Rhino 8 - Importing Python 3 Libraries

@Thomas_Dowse

In case of en-US, the problem is that it is an invalid locale identifier reported by Windows (en_US being the valid id). In Rhino, when editor is launched I check against this case and a few others and correct them automatically:

import locale

default_locale, default_codepage = locale.getdefaultlocale()
current_locale, current_codepage = locale.getlocale()

if default_locale == "en-US" \
    or current_locale == "en-US":
    locale.setlocale(locale.LC_ALL, "en_US")

elif '-' in default_locale:
    fixed_locale = default_locale.replace('-', '_')
    locale.setlocale(locale.LC_ALL, fixed_locale)

elif '-' in current_locale:
    fixed_locale = current_locale.replace('-', '_')
    locale.setlocale(locale.LC_ALL, fixed_locale)

After launching Rhino, run RhinoCodeLogs command and look for messages like this:

Info 18/3/2024 20:42:26 [RhinoCode] Python default locale is 'en_ZW.cp1252'
Info 18/3/2024 20:42:26 [RhinoCode] Python current locale is 'English_Zimbabwe.1252'

or

Info 18/3/2024 20:42:26 [RhinoCode] updated local from 'en-US' to 'en_US'

Q: Would you mind confirming this correction is happening on your machine and is reported in the logs?

Here is how importing pandas look like on my machine:

Rhino_reF38MRuwS

I ran the above and am now getting the following error. I have also copied in the code logs underneath.

ScriptEditor.log (28.9 KB)

@Thomas_Dowse

Try checking or resetting the Regional Settings on Windows.

The logs get the current locale from python locale module on startup and it is reported as (Line 56):

Info 3/18/2024 9:54:58 PM [RhinoCode] Python locale is (‘English_Australia’, ‘1252’)

But when pandas is being loaded, it throws an error on bad locale (Line 256):

ValueError: unknown locale: en-US

Windows has two different places for this. Regional settings in legacy control panel, and Regional settings in the new more modern Settings:

Please make sure these two match.

More info on locales here

I think I have got it working, need to run the following at the top of the script prior to installing/running pandas.

import locale
locale.setlocale(locale.LC_ALL, 'en_US')

Thanks for your help @eirannejad , will let you know if we run into anymore issues.

Ehsan that’s an excellent spot - well done. In most Pythons this can be verified via:

Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import locale
>>> for code in ('en_US', 'en-US.UTF8', 'en-US'):
...   print(locale._parse_localename(code))
...
('en_US', 'ISO8859-1')
('en-US', 'UTF8')
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "C:\Users\...\AppData\Local\Programs\Python\Python39\lib\locale.py", line 501, in _parse_localename
    raise ValueError('unknown locale: %s' % localename)
ValueError: unknown locale: en-US

However I’m not sure it’s the full story. The question is what’s setting the locale "en-US" to contain a hyphen in the first place. I haven’t been able to find this hyphenated locale name in any other application in Windows, other than Rhino 8’s CPython, and even then only within Grasshopper. So perhaps the root cause is, that something, either in Rhino, or in the integration of Python 3.9 within Rhino 8, is setting that locale code to "en-US". I can’t reproduce the error in Python 2.7 components within Grasshopper, so I suspect it’s not Rhino.

From the command line (both a standard 3.9 from python.org and Rhino 8’s own Python 3.9):

>py -3.9 -c "import _strptime; print(_strptime._getlang())"
(None, None)

>.\.rhinocode\py39-rh8\python.exe -c "import _strptime; print(_strptime._getlang())"
(None, None)


_strptime._getlang.gh (5.9 KB)

1 Like

The error even occurs on first import of _strptime, without pandas or even pip doing anything:

During pandas rather complicated initial import, it imports _strptime, a core library of Python’s (even though it starts with an underscore):

Within Python 3.9’s _strptime.py, a default instance of TimeRE is created.
If TimeRE.__init__ is called with no args, an instance of LocaleTime is created.
LocaleTime.__init__ calls _getlang, (which I’ve used in the tests above, now realise I didn’t actually need to, as importing the module calls it anyway).

1 Like

The rogue hyphenated “en-US” comes from the _locale module. Without that, Python defaults to the C locale. The user facing locale imports setlocale from _locale. This _locale module (I can’t find its source as it’s probably compiled or even buried in a dll) behaves differently in Rhino 8’s Python 3 from the command line, as it does within Rhino 8.

>.\python.exe -c "import _locale; print(_locale.setlocale(5))"
C

The 5 is local.LC_TIME

>py -3.9 -c "import _locale; print(_locale.setlocale(5))"

_locale.setlocale is defined in Python 3.9 's C code base:

It calls the C func of the same name (setlocale - cppreference.com)

I don’t know if it’s relevant but Windows only code defined getdefaultlocale to call GetLocaleInfo from MSVC

but in Python 3.12 this was changed to GetLocaleInfoA (as MS recommend in their docs).

So, Microsoft and Rhino have done this right in the modern way! I wonder if Python 3.9 followed Posix and C idioms (as well as its own historical ones), and contained a bug that crops up in this edge case.

ISO_3166-1 doesn’t care, but to be compliant with RFC1766 Lang/ Country/ lang codes should be separated by hyphens:

EBNF is:

    Language-Tag = Primary-tag *( "-" Subtag )
    Primary-tag = 1*8ALPHA
    Subtag = 1*8ALPHA

https://www.ietf.org/rfc/rfc1766.txt

Python does normalize the language/country tags in locale.setlocale:

but only crudely by testing the string against a huge hardcoded dict of lang codes, in which all the entries are separated by underscores, not hyphens:

1 Like

Exactly the same issue when trying to implement Google App following this tutorial.

The solution mentioned above leads to another error:
image

1 Like

Type the line in correctly as:

locale.setlocale(locale.LC_ALL, 'en_US')
2 Likes

RH-81130 is fixed in Rhino 8 Service Release 15 Release Candidate