Python 3.5.1 + Django 1.9, возвращает пустую строку для дат
Opened this issue · 15 comments
u_res = date.strftime(format)
(это конец функции ru_strftime
)
Какой-то странный глюк. Если format='%Y мая'
, то возвращается пустая строка. Удивительно, ведь метод-то встроенный в python.
Если просто в python сделать в консоли datetime(2016,5,23).strftime('%Y мая')
, то все нормально. Если же то же самое в дебаге (вотчером) в этом месте функции ru_strftime
, то та же проблема.
Честно говоря не представляю, проблема еще актуальна?
Я уж и забыл) Проверю на днях
Честно говоря не представляю, проблема еще актуальна?
Для Python 3.6 все еще актуально
Но я пытаюсь получить чисто месяц "%B"
и получаю пустую строку
PS: чтобы не быть голословным:
>>> pytils.dt.ru_strftime('%B', inflected=False, date=datetime.datetime.fromtimestamp(1540209256))
''
Очень странно, у меня не воспроизводится на python 3.6.6.
Попробуйте воткнуть ipdb в функцию ru_strftime и понять на каком моменте все ломается.
И если удастся починить, буду рад пулл-реквесту.
Наткнулся на интересное поведение:
>>> dt.strftime('october')
'october'
>>> dt.strftime('октябрь')
''
Похоже что на маке работает только после:
locale.setlocale(locale.LC_ALL, 'ru_RU.UTF-8')
Но при этом на Linux если я буквально ставлю LC_ALL=C
- баг не воспроизводится.
PS: Подозреваю ноги могут отсюда расти.
Столкнулся с такой же проблемой пустой даты.
С python 2.7 всё работало и на ноуте и на сервере.
С python 3.6/3.7 на ноуте у меня, где нормальные локали из коробки, всё ок. На сервере, где ничего не настроено с локалями - пустая строка.
Это проблема не pytils. Пустая строка возвращается уже из вызова
u_res = date.strftime(format) # dt.py, строка 229
Причина вот в чем скорее всего: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior
For the same reason, handling of format strings containing Unicode code points that can’t be represented in the charset of the current locale is also platform-dependent. On some platforms such code points are preserved intact in the output, while on others strftime may raise UnicodeError or return an empty string instead.
Но это можно обойти и в pytils, насколько я понимаю, путем некоторых извращений. Надо сначала передать ascii-строку через u_res = date.strftime(format), а потом уже делать локальные замены, которые делает pytils.
Сделал копию dt.py -> dt2.py и поменял там строки 215:230
`
# save custom codes to work on them later
format = format.replace(u'%a', u'--PYTILS--a--')
format = format.replace(u'%A', u'--PYTILS--A--')
format = format.replace(u'%b', u'--PYTILS--b--')
format = format.replace(u'%B', u'--PYTILS--B--')
# Python 2: strftime's argument must be str
# Python 3: strftime's argument str, not a bitestring
if six.PY2:
# strftime must be str, so encode it to utf8:
s_format = format.encode("utf-8")
s_res = date.strftime(s_format)
# and back to unicode
u_res = s_res.decode("utf-8")
else:
u_res = date.strftime(format)
u_res = u_res.replace(u'--PYTILS--a--', prepos+DAY_NAMES[weekday][0])
u_res = u_res.replace(u'--PYTILS--A--', prepos+DAY_NAMES[weekday][day_idx])
u_res = u_res.replace(u'--PYTILS--b--', MONTH_NAMES[date.month-1][0])
u_res = u_res.replace(u'--PYTILS--B--', MONTH_NAMES[date.month-1][month_idx])
return u_res
`
Вывод на сервере,где есть проблема, такой:
(dt.ru_strftime - дефолтный код, dt2.ru_strftime с костылями)
import pytils
import datetime
pytils.dt.ru_strftime('%d %B %Y', inflected=True, date=datetime.datetime.fromtimestamp(1540209256))
''
pytils.dt2.ru_strftime('%d %B %Y', inflected=True, date=datetime.datetime.fromtimestamp(1540209256))
'22 октября 2018'
О, интересно.
Решение конечно костыльное, но если ничего лучше не придет в голову сделаем такой фикс.
Мой костыль лишь частично работоспособен оказался.
Он не проходит pytils.test.test_dt, например.
Любая строка форматирования с не ascii его сломает в окружении без локали, вроде варианта:
pytils.dt2.ru_strftime('когда-то было %d %B %Y', inflected=True, date=datetime.datetime.fromtimestamp(1540209256))
Ага, это конечно ожидаемо.
Наверное тогда самый нормальный вариант - предупреждать что локаль не установлена при импорте.
Это всё-таки проблема окружения а не pytils.
Есть еще вариант на уме:
сначала обычный запуск как сейчас, если вернулась пустая строка или UnicodeError, то вторая попытка в режиме совместимости, так сказать.
В этом режиме совместимости надо выдирать из полученной в ru_strftime строки format макросы по одному и по одному же их скармливать в питоновский strftime.
Да, это будет медленно, но 1) должно сработать надежно, 2) плохая производительность только для тех, у кого проблемы с настройками сервера.
Постараюсь сделать pull request.
Мне кажется, это плохой вариант. Он конечно будет работать, но сделает код сложнее чем он должен быть :)
А один warning при импорте - предупредит людей о проблемах, они починят настройки сервера, и всё будет хорошо.
Потому что с этим вариантом - pytils отработает как будто всё хорошо, а на самом деле всё не хорошо, и при ручном использовании strftime проблемы будут такие же.
ок, звучит разумно )
@kilgoretrout1985 а посмотри, пожалуйста, что там будет на ненастроенном сервере в
import locale
locale.getlocale()
или может есть ещё какие идеи как нам это определить
import locale; locale.getlocale()
(None, None)
Но вот так надежнее наверное
Text-6.txt