What is wxPython doing to the locale to makes pandas crash?

I suspect that any module that parses dates/time will have a similar issue. I experienced it importing datetime as well.

When I tried your sample app, I got the same error. After I moved the import pandas statement out of the class and just under the import wx statement the problem seemed to go away. I’m not saying that’s the issue, but it might fix the problem for you.

Robin, I’m having this issue with locale mismatch on Windows 10, Python 3.8, and wxPython 4.1.0. Whenever I run a strptime() function I get an error “unknown locale: en-US”
What is the best way to work around this so that I can use the strptime function in my program? I can’t seem to find any info on this anywhere except in your mention here. Any ideas would be greatly appreciated.

This really should be en_US.

Windows has got some strange ideas with regard to locale
names. Somewhere in the PostgreSQL mailing list archives
there should be in-depth discussions of that.

Eryk Syn on the python mailing list may know more, too.

Karsten

I tried adding some entries to alias and the windows locale dictionaries in locale.py, but that didn’t help. I don’t understand enough about how “locale” is used and by which pieces of code, so if anyone can suggest a workaround I would really appreciate it. As it stands right now, I cannot make a “strptime” call in wxPython, so I can’t pass a string into a datetime field. Kind of stuck.

It looks like the hyphenated “en-US” is coming from the Windows API GetLocaleInfo function. Leave it to Microsoft to do their own thing in an incompatible manner…

I haven’t been able to duplicate whatever it was that prompted me to setup the default locale settings when the wx.App is initialized. So try this: derive a new class from wx.App and override the InitLocale method, like this:

    class MyApp(wx.App):
        def InitLocale(self):
            self.ResetLocale()

Let me know if you run into any locale- or translations-related problems. I have some ideas for an alternate approach that will avoid the ‘en-US’ problem, but if it is no longer needed I can just rip out that chunk of code entirely.

For those who are interested, in Python 3.7 and earlier, on my Windows machine, locale.getlocale() returns (None, None), so it seems that the process’ locale is left in its default state. But in Python 3.8 on Windows it returns ('English_United States', '1252') indicating that Python or something is now setting the locale to the system default. If I remember correctly, the problem I was trying to workaround was that by default wxWidgets would assume that the locale is set to the default “C” locale, and there was something that failed due to that difference. But now I don’t remember what it was that caused the problem back then…

1 Like

Thanks, Robin. Unfortunately I tried your code snippet in a variety of places in my code and it never seemed to make a difference. I eventually found a workaround…right after the wx.App is instantiated, I added this to nail me down to “en_US” and my strptime functions work now.

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

I don’t know if that is some sort of taboo to hard set this, but after a few hours of reading and trying to understand what is going on here, it was the best I could do to get my code working.

Preferably:

import locale
hyphenated_locale = wx.WhateverGivesTheStrangeLocale()
locale.setlocale(locale.LC_ALL, hyphenated_locale.replace('-', '_'))

or some such.

Best,
Karsten

1 Like

Just a note about this :
I’m facing this issue on a Windows 8.1 platform.
It’s not happening on Windows 10 exclusively.

Does it make any difference ?

Other than that, it sorta defeats the whole purpose of I18N :smiley:

But maybe that was symbolic code only.

Karsten

Thanks for that. If I’m reading the documentation correctly (https://wxpython.org/Phoenix/docs/html/wx.Locale.html), it looks like “wx.Locale.GetName()” might be the function to get the short name. Will test that tonight.

Okay. Please try this wx.App implementation:

class MyApp(wx.App):
    def InitLocale(self):
        self.ResetLocale()
        import locale
        lang, enc = locale.getdefaultlocale()
        self._initial_locale = wx.Locale(lang, lang[:2], lang)
        locale.setlocale(locale.LC_ALL, lang)
1 Like

From the looks of it this should work (barring typos etc)
and goes to the core of the issue rather than kluding around
the symptom.

It also fixes Stuart’s issue of “None does not have
replace()” by unpacking the tuple (gotten from
getdefaultlocale() in this case).

Except that it is not recommended by the Python manual to
use

locale.setlocale(locale.LC_ALL, lang)

in libraries:

It is generally a bad idea to call setlocale() in some
library routine, since as a side effect it affects the
entire program. Saving and restoring it is almost as bad:
it is expensive and affects other threads that happen to
run before the settings have been restored.

It might be safer like so:

 class MyApp(wx.App):
     def InitLocale(self):
         self.ResetLocale()
         import locale
         lang, enc = locale.getdefaultlocale()
         self._initial_locale = wx.Locale(lang, lang[:2], lang)
         curr_lang, curr_enc = locale.getlocale()
         if curr_lang is None:
             try:
                 locale.setlocale(locale.LC_ALL, lang)
             except locale.Error:
                 whatever_log_is_available('cannot set LC_ALL to %' % lang)

meaning that

- it only tries to set the locale if it hasn't been set before
- or the locale cannot currently be determined
- and wxPython GUI apps always initialize the locale system
- which makes sense for GUI apps

Best,
Karsten

Unfortunately doing a locale.getlocale() after wx.Locale(...) will trigger the exception due to the ‘en-US’ being set as the system locale. It happens when the wx.Locale is created, in some MSW-specific code. (It was something like, check the requested language/locale is valid, get the info with GetLocaleInfo API, and then set the locale using the name returned from GetLocalInfo, which is the ‘en-US’ name.)

I still need to check with wx-dev if what is going on currently is actually correct, and check if they have any ideas for Python’s locale restrictions. But in the meantime, it looks like we will need to call locale.setlocale to make the wx and Python locale settings to be equivalent. I will likely add a conditional so the code is only run on Windows however.

As to the warning about setlocale in a library, I would argue that wxPython is more of an application framework than a library, and so the warning doesn’t apply, (at least not as strongly) as it would for something like numpy, some database adapter, or whatever. The warning implies that it is up to the application to worry about setting the locale, and that is exactly what wx.App is. If the developer wants to do something differently they are free to override InitLocale themselves.

Unfortunately doing a locale.getlocale() after
wx.Locale(...) will trigger the exception due to the
‘en-US’ being set as the system locale. It happens when the
wx.Locale is created, in some MSW-specific code. (It was
something like, check the requested language/locale is valid,
get the info with GetLocaleInfo API, and then set the
locale using the name returned from GetLocalInfo, which is
the ‘en-US’ name.)

I don’t fully parse (but then even the Python manual warns
that locale implementations tend to be strange and wondrous
beasts) but I smell the problem.

I still need to check with wx-dev if what is going on
currently is actually correct, and check if they have any
ideas for Python’s locale restrictions. But in the meantime,
likely add a conditional so the code is only run on Windows
however.

Sounds good.

As to the warning about setlocale in a library, I would
argue that wxPython is more of an application framework than
a library, and so the warning doesn’t apply, (at least not as
strongly) as it would for something like numpy, some database
adapter, or whatever.

Agree.

The warning implies that it is up to
the application to worry about setting the locale, and that
is exactly what wx.App is. If the developer wants to do
something differently they are free to override InitLocale
themselves.

There’s this issue, however, unless I am mistaken:

  • python application starts up and sets up environment,
    including activating a desired, but non-default, locale
    (say, user selection from a config file)

  • application the proceeds to import wxPython and generates
    the GUI

  • wx.App() will re-set the locale to whatever the default
    locale for the user is

This means applications need to be adapted to re-activate the
desired locale init()ing wx.App, or overwrite
App.InitLocale() as you say. Both ways warrant a note in the
4.0/4.1 gotcha notes.

Also, would re-activating the desired locale require using wx
facilities rather than stdlib locale.* ones ?

On yet another level, will this entanglement prevent
decoupling string translation from GUI toolkit use ?

(currently, one can use gettext.gettext() without ever
touching wx.Translation() ?

Regards,
Karsten

Robin,

This won’t work in linux:

        lang, enc = locale.getdefaultlocale()
        self._initial_locale = wx.Locale(lang, lang[:2], lang)
        locale.setlocale(locale.LC_ALL, lang)

locale.setlocale would raise

locale.Error: unsupported locale setting

What would work is:

locale.setlocale(locale.LC_ALL, (lang, enc))

Of course, this does not work in windows, so you might want to try one, and if a locale.Error is raised try the other.

Is there a bug report for this issue somewhere?

it works in my code following this :

In main page I have :
(self.locale = wx.Locale(wx.LANGUAGE_ENGLISH) for example)

      elif langue == "english" :
          self.locale = wx.Locale(wx.LANGUAGE_ENGLISH)
          presLan = gettext.translation("en", "./locale", languages=['en'])
          self.langage_utilisateur = "english"
          langue_par_defaut = "en_GB"
      elif langue == "french" :
          self.locale = wx.Locale(wx.LANGUAGE_FRENCH)
          presLan = gettext.translation("fr", "./locale", languages=['fr'])
          self.langage_utilisateur = "francais"
          langue_par_defaut = "fr_FR"
      elif langue == "spanish" :
          self.locale = wx.Locale(wx.LANGUAGE_SPANISH)
          presLan  = gettext.translation("es", "./locale", languages=['es'])
          self.langage_utilisateur = "espanol"
          langue_par_defaut = "es_ES"
presLan.install()

and before a call who used to crash in windows (strptime for example) :
(locale.setlocale(locale.LC_ALL, ‘en’) for example)

            if ( parent.parent.systeme_version == "WINDOWS" ) :
                if ( parent.parent.langage_utilisateur == "english" ) :
                    locale.setlocale(locale.LC_ALL, 'en')
                if ( parent.parent.langage_utilisateur == "francais" ) :
                    locale.setlocale(locale.LC_ALL, 'fr')
                if ( parent.parent.langage_utilisateur == "espanol" ) :
                    locale.setlocale(locale.LC_ALL, 'es')
                    
            date_formate_en_float = date2num(datetime.datetime.strptime(date_heure_formatee, '%Y%m%d%H%M'))

Hope it will be usefull, not clean method for sure …

    class MyApp(wx.App):
        def InitLocale(self):
            self.ResetLocale()

This works for me!

OS Windows 10, wxpython 4.1.0 and python 3.8.3

Thanks you!

1 Like

Install wxPython version 4.0.7 and it works great

1 Like

Yep, this works for me as well.