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

Python 3.5.1 + Django 1.9, возвращает пустую строку для дат #32

Open
KhodeN opened this issue Jun 6, 2016 · 15 comments
Assignees

Comments

@KhodeN
Copy link

KhodeN commented Jun 6, 2016

u_res = date.strftime(format) (это конец функции ru_strftime)

Какой-то странный глюк. Если format='%Y мая', то возвращается пустая строка. Удивительно, ведь метод-то встроенный в python.

Если просто в python сделать в консоли datetime(2016,5,23).strftime('%Y мая'), то все нормально. Если же то же самое в дебаге (вотчером) в этом месте функции ru_strftime, то та же проблема.

@last-partizan
Copy link
Owner

Честно говоря не представляю, проблема еще актуальна?

@KhodeN
Copy link
Author

KhodeN commented Apr 18, 2018

Я уж и забыл) Проверю на днях

@wswld
Copy link

wswld commented Oct 22, 2018

Честно говоря не представляю, проблема еще актуальна?

Для Python 3.6 все еще актуально

Но я пытаюсь получить чисто месяц "%B" и получаю пустую строку

PS: чтобы не быть голословным:

>>> pytils.dt.ru_strftime('%B', inflected=False, date=datetime.datetime.fromtimestamp(1540209256))
''

@last-partizan
Copy link
Owner

Очень странно, у меня не воспроизводится на python 3.6.6.

Попробуйте воткнуть ipdb в функцию ru_strftime и понять на каком моменте все ломается.
И если удастся починить, буду рад пулл-реквесту.

@wswld
Copy link

wswld commented Oct 26, 2018

Наткнулся на интересное поведение:

>>> dt.strftime('october')
'october'
>>> dt.strftime('октябрь')
''

Похоже что на маке работает только после:

locale.setlocale(locale.LC_ALL, 'ru_RU.UTF-8')

Но при этом на Linux если я буквально ставлю LC_ALL=C - баг не воспроизводится.

PS: Подозреваю ноги могут отсюда расти.

@kilgoretrout1985
Copy link

kilgoretrout1985 commented Feb 28, 2019

Столкнулся с такой же проблемой пустой даты.
С 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'

@last-partizan
Copy link
Owner

О, интересно.

Решение конечно костыльное, но если ничего лучше не придет в голову сделаем такой фикс.

@kilgoretrout1985
Copy link

Мой костыль лишь частично работоспособен оказался.
Он не проходит pytils.test.test_dt, например.
Любая строка форматирования с не ascii его сломает в окружении без локали, вроде варианта:
pytils.dt2.ru_strftime('когда-то было %d %B %Y', inflected=True, date=datetime.datetime.fromtimestamp(1540209256))

@last-partizan
Copy link
Owner

Ага, это конечно ожидаемо.

Наверное тогда самый нормальный вариант - предупреждать что локаль не установлена при импорте.
Это всё-таки проблема окружения а не pytils.

@kilgoretrout1985
Copy link

Есть еще вариант на уме:
сначала обычный запуск как сейчас, если вернулась пустая строка или UnicodeError, то вторая попытка в режиме совместимости, так сказать.
В этом режиме совместимости надо выдирать из полученной в ru_strftime строки format макросы по одному и по одному же их скармливать в питоновский strftime.
Да, это будет медленно, но 1) должно сработать надежно, 2) плохая производительность только для тех, у кого проблемы с настройками сервера.

Постараюсь сделать pull request.

@last-partizan
Copy link
Owner

Мне кажется, это плохой вариант. Он конечно будет работать, но сделает код сложнее чем он должен быть :)

А один warning при импорте - предупредит людей о проблемах, они починят настройки сервера, и всё будет хорошо.
Потому что с этим вариантом - pytils отработает как будто всё хорошо, а на самом деле всё не хорошо, и при ручном использовании strftime проблемы будут такие же.

@kilgoretrout1985
Copy link

ок, звучит разумно )

@last-partizan last-partizan self-assigned this Mar 1, 2019
@last-partizan
Copy link
Owner

@kilgoretrout1985 а посмотри, пожалуйста, что там будет на ненастроенном сервере в

import locale
locale.getlocale()

или может есть ещё какие идеи как нам это определить

@kilgoretrout1985
Copy link

import locale; locale.getlocale()
(None, None)

@kilgoretrout1985
Copy link

kilgoretrout1985 commented Mar 1, 2019

Но вот так надежнее наверное
Text-6.txt

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

No branches or pull requests

4 participants