Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Datetime.strptime error in wxPython why #1637

Closed
wstates opened this issue May 14, 2020 · 19 comments · Fixed by #1912
Closed

Datetime.strptime error in wxPython why #1637

wstates opened this issue May 14, 2020 · 19 comments · Fixed by #1912

Comments

@wstates
Copy link

wstates commented May 14, 2020

# coding=utf-8
import wx
import sys
import datetime

if __name__ == "__main__":
    print("wxpython version:", wx.version())
    print("Python version:", sys.version)
    print("Run before wx:", datetime.datetime.strptime("02/02/2020", '%d/%m/%Y'), "normal")
    app = wx.App()
    print("Run after wx:", datetime.datetime.strptime("02/02/2020", '%d/%m/%Y'), "error")

    # frame = MainFrame()
    # frame.SetSize(0, 0, 1200, 750)
    # frame.Center()
    # frame.Show()
    app.MainLoop()
wxpython version: 4.1.0 msw (phoenix) wxWidgets 3.1.4
Python version: 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)]
Run before wx: 2020-02-02 00:00:00 normal
Traceback (most recent call last):
  File "K:/test/a.py", line 14, in <module>
    print("Run after wx:", datetime.datetime.strptime("02/02/2020", '%d/%m/%Y'), "error")
  File "C:\Program Files\Python36\lib\_strptime.py", line 565, in _strptime_datetime
    tt, fraction = _strptime(data_string, format)
  File "C:\Program Files\Python36\lib\_strptime.py", line 334, in _strptime
    if (_getlang() != locale_time.lang or
  File "C:\Program Files\Python36\lib\_strptime.py", line 31, in _getlang
    return locale.getlocale(locale.LC_TIME)
  File "C:\Program Files\Python36\lib\locale.py", line 581, in getlocale
    return _parse_localename(localename)
  File "C:\Program Files\Python36\lib\locale.py", line 490, in _parse_localename
    raise ValueError('unknown locale: %s' % localename)
ValueError: unknown locale: zh-CN
@cwassert
Copy link

See also pyinstaller/pyinstaller#4874

@AndersMunch
Copy link

AndersMunch commented May 14, 2020

I'm seeing this too with wxPython 4.1.0 (and Python 3.8.1 MSW 64 bit, for the record).
The same traceback occurs even if the locale is set explicitly through wx:

import wx
import datetime
app = wx.App()
loc = wx.Locale(wx.LANGUAGE_ENGLISH_UK)
print(datetime.datetime.strptime('2020', "%Y"))

However, if the locale is set using the Python locale module, it doesn't:

import wx
import datetime, locale
app = wx.App()
locale.setlocale(locale.LC_ALL, 'en_GB')
print(datetime.datetime.strptime('2020', "%Y"))

No traceback in this case. It seems to be a usable workaround.

Note that some older 4.0.x wxPython's insisted on the opposite, requiring wx.Locale instead of Python locale, as seen in this assertion failure from 4.0.4 wx.Image.ConvertToBitmap:
wx._core.wxAssertionError: C++ assertion "strcmp(setlocale(LC_ALL, NULL), "C") == 0" failed at ..\..\src\common\intl.cpp(1579) in wxLocale::GetInfo(): You probably called setlocale() directly instead of using wxLocale and now there is a mismatch between C/C++ and Windows locale.

Edited to add:
Apparently not just older wxPythons: 4.1.0 wx.Image gave me this:

wx._core.wxAssertionError: C++ assertion "wxString::Format("%.3f", 1.23).find(str) != wxString::npos" failed at ..\..\src\common\intl.cpp(1638) in `anonymous-namespace'::GetInfoFromLCID(): Decimal separator mismatch -- did you use setlocale()?If so, use wxLocale to change the locale instead.

It seems locale.setlocale is not a usable workaround after all.

@swt2c
Copy link
Collaborator

swt2c commented May 15, 2020

For those seeing this, what does locale.getlocale() return before and after calling wx.App()?

@wstates
Copy link
Author

wstates commented May 16, 2020

对于那些看到此消息的人,在_致电_之前_和_之后locale.getlocale()返回什么?____wx.App()

# coding=utf-8

import wx
import sys
import datetime, locale

if __name__ == "__main__":
    print("wxpython version:", wx.version())
    print("Python version:", sys.version)
    print("Run before wx:", locale.getlocale())
    app = wx.App()
    print("Run after wx:", locale.getlocale())
    

    # Use this locale.setlocale(locale.LC_ALL, "") to return to normal.
    locale.setlocale(locale.LC_ALL, "") 
    print("Run after wx:", locale.getlocale())

    app.MainLoop()
wxpython version: 4.1.0 msw (phoenix) wxWidgets 3.1.4
Python version: 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)]
Run before wx: (None, None)
Traceback (most recent call last):
  File "K:/test/a.py", line 14, in <module>
    print("Run after wx:", locale.getlocale())
  File "C:\Program Files\Python36\lib\locale.py", line 581, in getlocale
    return _parse_localename(localename)
  File "C:\Program Files\Python36\lib\locale.py", line 490, in _parse_localename
    raise ValueError('unknown locale: %s' % localename)
ValueError: unknown locale: zh-CN
    def InitLocale(self):
        """
        Try to ensure that the C and Python locale is in sync with wxWidgets locale.
        """
        import locale
        print("BugTest1", locale.getlocale())

        self.ResetLocale()
        print("BugTest2", locale.getlocale())

        import locale
        print("BugTest3", locale.getlocale())

        try:
            loc, enc = locale.getlocale()
        except ValueError:
            loc = enc = None
            print("BugTest4", locale.getlocale())
        print("BugTest5", locale.getlocale())

        # Try to set it to the same language as what is already set in the C locale
        info = wx.Locale.FindLanguageInfo(loc) if loc else None
        if info:
            self._initial_locale = wx.Locale(info.Language)
            print("BugTest6", locale.getlocale())

        else:
            # otherwise fall back to the system default
            print("BugTest7", locale.getlocale())
            self._initial_locale = wx.Locale(wx.LANGUAGE_DEFAULT)
            print("BugTest8", locale.getlocale())
wxpython version: 4.1.0 msw (phoenix) wxWidgets 3.1.4
Python version: 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)]
Run before wx: (None, None)
BugTest1 (None, None)
BugTest2 (None, None)
BugTest3 (None, None)
BugTest5 (None, None)
BugTest7 (None, None)
Traceback (most recent call last):
  File "i:\python\lib\site-packages\wx\core.py", line 2204, in OnPreInit
    self.InitLocale()
  File "i:\python\lib\site-packages\wx\core.py", line 2287, in InitLocale
    print("BugTest8", locale.getlocale())
  File "C:\Program Files\Python36\lib\locale.py", line 581, in getlocale
    return _parse_localename(localename)
  File "C:\Program Files\Python36\lib\locale.py", line 490, in _parse_localename
    raise ValueError('unknown locale: %s' % localename)
ValueError: unknown locale: zh-CN

@wstates
Copy link
Author

wstates commented May 16, 2020

self._initial_locale = wx.Locale(wx.LANGUAGE_DEFAULT)
changed to

self._initial_locale = wx.Locale(wx.LANGUAGE_UNKNOWN)
No traceback in this case

@swt2c
Copy link
Collaborator

swt2c commented May 17, 2020

@RobinD42 perhaps in the case where Python's locale.getlocale() returns None, wxPython should NOT be calling wx.Locale(wx.LANGUAGE_DEFAULT)? It seems like in that case you are setting a locale where none is currently set.

@AndersMunch
Copy link

For those seeing this, what does locale.getlocale() return before and after calling wx.App()?

Python 3.8.1 (tags/v3.8.1:1b293b6, Dec 18 2019, 23:11:46) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import locale
>>> locale.getlocale()
('Danish_Denmark', '1252')
>>> import wx
>>> wx.version()
'4.1.0 msw (phoenix) wxWidgets 3.1.4'
>>> locale.getlocale()
('Danish_Denmark', '1252')
>>> app = wx.App()
>>> locale.getlocale()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\flonidan\env\Python38-64\lib\locale.py", line 591, in getlocale
    return _parse_localename(localename)
  File "C:\flonidan\env\Python38-64\lib\locale.py", line 499, in _parse_localename
    raise ValueError('unknown locale: %s' % localename)
ValueError: unknown locale: da-DK

@cwassert
Copy link

cwassert commented May 18, 2020

What confuses me about the error message is the hyphen. Because the usual notation uses an underscore.

>>> locale.setlocale(locale.LC_ALL, ('en-US', 'UTF-8'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.8/locale.py", line 608, in setlocale
    return _setlocale(category, locale)
locale.Error: unsupported locale setting
>>> locale.setlocale(locale.LC_ALL, ('en_US', 'UTF-8'))
'en_US.UTF-8'
>>> 

See also locale.locale_alias.keys().

@swt2c
Copy link
Collaborator

swt2c commented Jul 15, 2020

There will be a new version of InitLocale() in wxPython 4.1.1. Can you try the snapshot builds and see if this issue is resolved with one of the latest snapshots? https://wxpython.org/Phoenix/snapshot-builds/

@AndersMunch
Copy link

4.1.1a1 is an improvement, so long as you stick with default locale everything seems fine:

Python 3.8.3 (tags/v3.8.3:6f8c832, May 13 2020, 22:37:02) [MSC v.1924 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import locale
>>> locale.getlocale()
('Danish_Denmark', '1252')
>>> import wx
>>> wx.version()
'4.1.1a1.dev4861+961dda67 msw (phoenix) wxWidgets 3.1.4'
>>> locale.getlocale()
('Danish_Denmark', '1252')
>>> app = wx.App()
>>> locale.getlocale()
('da_DK', 'ISO8859-1')

But setting a different locale does not work:

Python 3.8.3 (tags/v3.8.3:6f8c832, May 13 2020, 22:37:02) [MSC v.1924 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import wx
>>> app = wx.App()
>>> loc = wx.Locale(wx.LANGUAGE_ENGLISH_UK)
>>> import locale
>>> locale.getlocale()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\flonidan\env\Python38-64\lib\locale.py", line 591, in getlocale
    return _parse_localename(localename)
  File "C:\flonidan\env\Python38-64\lib\locale.py", line 499, in _parse_localename
    raise ValueError('unknown locale: %s' % localename)
ValueError: unknown locale: en-GB

@AndersMunch
Copy link

Update: wxPython 4.1.1/wxWidgets 3.1.5 is out, and it works exactly like 4.1.1a1. It's a showstopper, so I remain stuck on 4.0.7/3.0.5.

@RobinD42
Copy link
Member

This issue has been mentioned on Discuss wxPython. There might be relevant details there:

https://discuss.wxpython.org/t/wxpython4-1-1-python3-8-locale-wxassertionerror/35168/2

@RobinD42
Copy link
Member

For those still having issues with this and are using non-US locales, please try this experiment. The root of the problem started when Python 3.8+ on Windows started changing the locale to something other than the default unset value, so perhaps the simplest thing that can be done is to just change it back to "C" instead of overdoing things to try and bring the C runtime and wxWIdgets into sync with what the system thinks should be the default.

So try adding the following method to your wx.App-derived class.

    def InitLocale(self):
        import sys
        if sys.platform.startswith('win') and sys.version_info > (3,8):
            import locale
            locale.setlocale(locale.LC_ALL, "C")

If you also need to set an explicit wx.Locale then do so after the code above, and remember to hold on to the reference to the wx.Local object.

Please reply with how it works for you, and if it doesn't help then also reply with any clues you may have discovered.

@AndersMunch
Copy link

Tried the InitLocale override, and yes, it works to set the "C" locale. You can't subsequently set a different locale; any other locale than the C locale (specifically, wx.LANGUAGE_ENGLISH) or the default locale results in this error message from wx.Locale:

wx._core.wxAssertionError: C++ assertion ""!szLocale.empty()"" failed at ..\..\src\common\intl.cpp(304) in wxLocale::Init(): no locale to set in wxLocale::Init()

@AndersMunch
Copy link

If I'm understanding 040c59f correctly, isn't it just the workaround above, which means that in order to choose the default locale, you now have to override InitLocale back to the old code? And no locales other than the default and the C locale can be set?

I guess this is really a CPython bug in locale.getlocale. Opened issue https://bugs.python.org/issue43115.

@AndersMunch
Copy link

@RobinD42, please revert 040c59f. If doesn't solve the problem but merely shuffles it around, then it will only lead to more version-dependent workarounds.

@swt2c
Copy link
Collaborator

swt2c commented Feb 5, 2021

@RobinD42 is it worth taking this locale issue to upstream Python (perhaps to the person who implemented the change on Windows) and ask for advice on how to resolve it?

@AndersMunch
Copy link

I came across a PC where it goes wrong even if you don't set the locale at all:

Python 3.8.7 (tags/v3.8.7:6503f05, Dec 21 2020, 17:59:51) [MSC v.1928 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import wx,locale
>>> locale._setlocale(locale.LC_ALL, None)
'LC_COLLATE=C;LC_CTYPE=English_Germany.1252;LC_MONETARY=C;LC_NUMERIC=C;LC_TIME=C'
>>> app = wx.App()
>>> locale._setlocale(locale.LC_ALL, None)
'en_DE'
>>> locale.getlocale()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Flonidan\env\Python38-64\lib\locale.py", line 591, in getlocale
    return _parse_localename(localename)
  File "C:\Flonidan\env\Python38-64\lib\locale.py", line 499, in _parse_localename
    raise ValueError('unknown locale: %s' % localename)
ValueError: unknown locale: en_DE

I added the two locale._setlocale just to show what's going on, to report on what the locale is at the C level. They don't actually set anything and removing those statements changes nothing.

At this point I'm struggling to find any way to write a wxPython program that will run on computers with varying locales. I'm beginning to think monkeypatching locale.getlocale is the only thing that will work.

@RobinD42
Copy link
Member

This issue has been mentioned on Discuss wxPython. There might be relevant details there:

https://discuss.wxpython.org/t/questions-on-the-locale-issue/36084/1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants