From 8f61bcc21202523ff82cff498c59930bf81bfd0e Mon Sep 17 00:00:00 2001 From: lampslave Date: Sat, 13 Apr 2019 22:09:37 +0300 Subject: [PATCH 1/2] python3, django>=1.11<=2.2 --- .travis.yml | 31 +- doc/examples-django/pytilsex/manage.py | 20 +- doc/examples-django/pytilsex/settings.py | 7 +- doc/examples-django/pytilsex/tests.py | 20 +- doc/examples/dt.ru_strftime.py | 18 +- doc/examples/numeral.choose_plural.py | 18 +- doc/examples/numeral.sum_string.py | 8 +- doc/examples/test.py | 6 +- doc/examples/translit.py | 8 +- pytils/dt.py | 101 +++--- pytils/numeral.py | 135 ++++---- pytils/templatetags/__init__.py | 7 +- pytils/test/templatetags/helpers.py | 3 +- pytils/test/templatetags/test_common.py | 9 +- pytils/test/templatetags/test_dt.py | 27 +- pytils/test/templatetags/test_numeral.py | 43 +-- pytils/test/templatetags/test_translit.py | 15 +- pytils/test/test_dt.py | 293 ++++++++--------- pytils/test/test_numeral.py | 371 +++++++++++----------- pytils/test/test_translit.py | 63 ++-- pytils/test/test_typo.py | 233 +++++++------- pytils/test/test_utils.py | 31 +- pytils/translit.py | 218 ++++++------- pytils/typo.py | 74 +++-- pytils/utils.py | 8 +- tox.ini | 12 +- 26 files changed, 921 insertions(+), 858 deletions(-) diff --git a/.travis.yml b/.travis.yml index ed20ee5..4e7a5ac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,29 @@ language: python -python: - - "2.7" - - "3.6" -env: - - TOXENV="py27-django11" - - TOXENV="py36-django11" - - TOXENV="py36-django20" +sudo: false +dist: xenial matrix: - exclude: + include: - python: "2.7" + env: TOXENV="py27-django11" + - python: "3.4" + env: TOXENV="py34-django11" + - python: "3.4" + env: TOXENV="py34-django20" + - python: "3.5" + env: TOXENV="py35-django11" + - python: "3.5" + env: TOXENV="py35-django20" + - python: "3.5" + env: TOXENV="py35-django21" + - python: "3.5" + env: TOXENV="py35-django22" + - python: "3.6" env: TOXENV="py36-django11" - - python: "2.7" + - python: "3.6" env: TOXENV="py36-django20" - python: "3.6" - env: TOXENV="py27-django11" + env: TOXENV="py36-django21" + - python: "3.6" + env: TOXENV="py36-django22" install: pip install tox script: tox -e $TOXENV diff --git a/doc/examples-django/pytilsex/manage.py b/doc/examples-django/pytilsex/manage.py index d0ea2fa..7646e46 100755 --- a/doc/examples-django/pytilsex/manage.py +++ b/doc/examples-django/pytilsex/manage.py @@ -4,7 +4,19 @@ if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") - - from django.core.management import execute_from_command_line - - execute_from_command_line(sys.argv) \ No newline at end of file + try: + from django.core.management import execute_from_command_line + except ImportError: + # The above import may fail for some other reason. Ensure that the + # issue is really that Django is missing to avoid masking other + # exceptions on Python 2. + try: + import django + except ImportError: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) + raise + execute_from_command_line(sys.argv) diff --git a/doc/examples-django/pytilsex/settings.py b/doc/examples-django/pytilsex/settings.py index 7bba286..aff4d13 100644 --- a/doc/examples-django/pytilsex/settings.py +++ b/doc/examples-django/pytilsex/settings.py @@ -1,3 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + # Django settings for pytilsex project. # find current path @@ -55,9 +58,9 @@ SECRET_KEY = '-)^ay7gz76#9!j=ssycphb7*(gg74zhx9h-(j_1k7!wfr7j(o^' -MIDDLEWARE_CLASSES = ( +MIDDLEWARE = [ 'django.middleware.common.CommonMiddleware', -) +] ROOT_URLCONF = 'urls' diff --git a/doc/examples-django/pytilsex/tests.py b/doc/examples-django/pytilsex/tests.py index 8727f0b..d2ab956 100644 --- a/doc/examples-django/pytilsex/tests.py +++ b/doc/examples-django/pytilsex/tests.py @@ -1,4 +1,6 @@ # -*- encoding: utf-8 -*- + +from __future__ import unicode_literals from django.urls import reverse from django.test import TestCase from django.test.client import Client @@ -27,8 +29,8 @@ def testDt(self): self.assertTrue('ru_strftime' in body) self.assertTrue('ru_strftime_inflected' in body) self.assertTrue('ru_strftime_preposition' in body) - self.assertTrue(u'вчера' in body) - self.assertTrue(u'завтра' in body) + self.assertTrue('вчера' in body) + self.assertTrue('завтра' in body) def testNumeral(self): resp = self.c.get(reverse('pytils_numeral_example')) @@ -39,13 +41,13 @@ def testNumeral(self): self.assertTrue('rubles' in body) self.assertTrue('in_words' in body) self.assertTrue('sum_string' in body) - self.assertTrue(u'комментарий' in body) - self.assertTrue(u'без примеров' in body) - self.assertTrue(u'двадцать три рубля пятнадцать копеек' in body) - self.assertTrue(u'двенадцать рублей' in body) - self.assertTrue(u'двадцать один' in body) - self.assertTrue(u'тридцать одна целая триста восемьдесят пять тысячных' in body) - self.assertTrue(u'двадцать один комментарий' in body) + self.assertTrue('комментарий' in body) + self.assertTrue('без примеров' in body) + self.assertTrue('двадцать три рубля пятнадцать копеек' in body) + self.assertTrue('двенадцать рублей' in body) + self.assertTrue('двадцать один' in body) + self.assertTrue('тридцать одна целая триста восемьдесят пять тысячных' in body) + self.assertTrue('двадцать один комментарий' in body) def testTranslit(self): resp = self.c.get(reverse('pytils_translit_example')) diff --git a/doc/examples/dt.ru_strftime.py b/doc/examples/dt.ru_strftime.py index 9a4ce6e..4359e34 100755 --- a/doc/examples/dt.ru_strftime.py +++ b/doc/examples/dt.ru_strftime.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from __future__ import unicode_literals + import datetime from pytils import dt @@ -30,29 +32,29 @@ def print_(s): # теперь на русском # (единственно, что нужно формат строки передавать в unicode # в то время, как в оригинальном strftime это обязательно str) -print_(dt.ru_strftime(u"%d.%m.%Y (%a)", d)) +print_(dt.ru_strftime("%d.%m.%Y (%a)", d)) # -> 15.09.2006 (пт) # %A дает полное название дня недели -print_(dt.ru_strftime(u"%d.%m.%Y (%A)", d)) +print_(dt.ru_strftime("%d.%m.%Y (%A)", d)) # -> 15.09.2006 (пятница) # %B -- название месяца -print_(dt.ru_strftime(u"%d %B %Y", d)) +print_(dt.ru_strftime("%d %B %Y", d)) # -> 15 сентябрь 2006 # ru_strftime умеет правильно склонять месяц (опция inflected) -print_(dt.ru_strftime(u"%d %B %Y", d, inflected=True)) +print_(dt.ru_strftime("%d %B %Y", d, inflected=True)) # -> 15 сентября 2006 # ... и день (опция inflected_day) -print_(dt.ru_strftime(u"%d.%m.%Y, в %A", d, inflected_day=True)) +print_(dt.ru_strftime("%d.%m.%Y, в %A", d, inflected_day=True)) # -> 15.09.2006, в пятницу # ... и добавлять правильный предлог (опция preposition) -print_(dt.ru_strftime(u"%d.%m.%Y, %A", d, preposition=True)) +print_(dt.ru_strftime("%d.%m.%Y, %A", d, preposition=True)) # -> 15.09.2006, в пятницу # второй параметр можно не передавать, будет использована текущая дата -print_(dt.ru_strftime(u"%d %B %Y", inflected=True)) -# ->> 1 декабря 2013 \ No newline at end of file +print_(dt.ru_strftime("%d %B %Y", inflected=True)) +# ->> 1 декабря 2013 diff --git a/doc/examples/numeral.choose_plural.py b/doc/examples/numeral.choose_plural.py index 815085b..7bc3428 100755 --- a/doc/examples/numeral.choose_plural.py +++ b/doc/examples/numeral.choose_plural.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from __future__ import unicode_literals + from pytils import numeral def print_(s): @@ -28,28 +30,28 @@ def print_(s): # (один, два, пять) # т.е. для 1, 2 и 5 объектов, например для слова "пример" # (пример, примера, примеров) -print_(numeral.choose_plural(21, (u"пример", u"примера", u"примеров"))) +print_(numeral.choose_plural(21, ("пример", "примера", "примеров"))) #-> пример -print_(numeral.choose_plural(12, (u"пример", u"примера", u"примеров"))) +print_(numeral.choose_plural(12, ("пример", "примера", "примеров"))) #-> примеров -print_(numeral.choose_plural(32, (u"пример", u"примера", u"примеров"))) +print_(numeral.choose_plural(32, ("пример", "примера", "примеров"))) #-> примера # также можно задавать варианты в одну строку, разделенные запятой -print_(numeral.choose_plural(32, u"пример,примера, примеров")) +print_(numeral.choose_plural(32, "пример,примера, примеров")) #-> примера # если в варианте используется запятая, она экранируется слешем -print_(numeral.choose_plural(35, u"гвоздь, гвоздя, гвоздей\, шпунтов")) +print_(numeral.choose_plural(35, "гвоздь, гвоздя, гвоздей\, шпунтов")) #-> гвоздей, шпунтов # зачастую требуется не просто вариант, а вместе с числительным # в этом случае следует использовать get_plural -print_(numeral.get_plural(32, u"пример,примера, примеров")) +print_(numeral.get_plural(32, "пример,примера, примеров")) #-> 32 примера # часто хочется, чтобы в случае отсутсвия значения (т.е. количество равно нулю) # выводилось не "0 примеров", а "примеров нет" # в этом случае используйте третий параметр get_plural: -print_(numeral.get_plural(0, u"пример,примера, примеров", u"без примеров")) -# -> без примеров \ No newline at end of file +print_(numeral.get_plural(0, "пример,примера, примеров", "без примеров")) +# -> без примеров diff --git a/doc/examples/numeral.sum_string.py b/doc/examples/numeral.sum_string.py index e88a0ec..5933e99 100755 --- a/doc/examples/numeral.sum_string.py +++ b/doc/examples/numeral.sum_string.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from __future__ import unicode_literals + from pytils import numeral def print_(s): @@ -27,13 +29,13 @@ def print_(s): # 3) items, варианты названий объекта (необязательно), # правила аналогичны таковым у choose_plural -print_(numeral.sum_string(3, numeral.MALE, (u"носок", u"носка", u"носков"))) +print_(numeral.sum_string(3, numeral.MALE, ("носок", "носка", "носков"))) #-> три носка -print_(numeral.sum_string(5, numeral.FEMALE, (u"коробка", u"коробки", u"коробок"))) +print_(numeral.sum_string(5, numeral.FEMALE, ("коробка", "коробки", "коробок"))) #-> пять коробок -print_(numeral.sum_string(21, numeral.NEUTER, (u"очко", u"очка", u"очков"))) +print_(numeral.sum_string(21, numeral.NEUTER, ("очко", "очка", "очков"))) #-> двадцать одно очко # если варианты не указывать, то действие функции аналогично дейтсвию in_words diff --git a/doc/examples/test.py b/doc/examples/test.py index faa6827..4188a46 100644 --- a/doc/examples/test.py +++ b/doc/examples/test.py @@ -1,5 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- + +from __future__ import unicode_literals import subprocess import sys import os @@ -57,7 +59,7 @@ def __init__(self, name): "%r is not text type (not a unicode for Py2.x, not a str for Py3.x" % self.expected_output[0] def test_cases(self): - return range(len(self.real_output)) + return list(range(len(self.real_output))) def run_test(self, name, i): assert name == self.name @@ -96,4 +98,4 @@ def test_python_version(): if __name__ == '__main__': import nose, sys if not nose.runmodule(): - sys.exit(1) \ No newline at end of file + sys.exit(1) diff --git a/doc/examples/translit.py b/doc/examples/translit.py index f053160..a1526a9 100755 --- a/doc/examples/translit.py +++ b/doc/examples/translit.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from __future__ import unicode_literals + from pytils import translit def print_(s): @@ -21,10 +23,10 @@ def print_(s): # выход - str, а в детранслитерации -- наоборот # -print_(translit.translify(u"Это тест и ничего более")) +print_(translit.translify("Это тест и ничего более")) #-> Eto test i nichego bolee -print_(translit.translify(u"Традиционно сложные для транслитерации буквы - подъезд, щука")) +print_(translit.translify("Традиционно сложные для транслитерации буквы - подъезд, щука")) #-> Traditsionno slozhnyie dlya transliteratsii bukvyi - pod`ezd, schuka # и теперь пытаемся вернуть назад... (понятно, что Э и Е получаются одинаково) @@ -37,7 +39,7 @@ def print_(s): # и пригодные для url и названий каталогов/файлов транслиты # dirify и slugify -- синонимы, действия абсолютно идентичны -print_(translit.slugify(u"Традиционно сложные для транслитерации буквы - подъезд, щука")) +print_(translit.slugify("Традиционно сложные для транслитерации буквы - подъезд, щука")) #-> traditsionno-slozhnyie-dlya-transliteratsii-bukvyi-podezd-schuka # обратного преобразования, понятно, нет :) diff --git a/pytils/dt.py b/pytils/dt.py index dece505..cd6205b 100644 --- a/pytils/dt.py +++ b/pytils/dt.py @@ -4,6 +4,7 @@ Russian dates without locales """ +from __future__ import unicode_literals import datetime from pytils import numeral @@ -11,54 +12,54 @@ from pytils.third import six DAY_ALTERNATIVES = { - 1: (u"вчера", u"завтра"), - 2: (u"позавчера", u"послезавтра") + 1: ("вчера", "завтра"), + 2: ("позавчера", "послезавтра") } #: Day alternatives (i.e. one day ago -> yesterday) DAY_VARIANTS = ( - u"день", - u"дня", - u"дней", + "день", + "дня", + "дней", ) #: Forms (1, 2, 5) for noun 'day' HOUR_VARIANTS = ( - u"час", - u"часа", - u"часов", + "час", + "часа", + "часов", ) #: Forms (1, 2, 5) for noun 'hour' MINUTE_VARIANTS = ( - u"минуту", - u"минуты", - u"минут", + "минуту", + "минуты", + "минут", ) #: Forms (1, 2, 5) for noun 'minute' -PREFIX_IN = u"через" #: Prefix 'in' (i.e. B{in} three hours) -SUFFIX_AGO = u"назад" #: Prefix 'ago' (i.e. three hours B{ago}) +PREFIX_IN = "через" #: Prefix 'in' (i.e. B{in} three hours) +SUFFIX_AGO = "назад" #: Prefix 'ago' (i.e. three hours B{ago}) MONTH_NAMES = ( - (u"янв", u"январь", u"января"), - (u"фев", u"февраль", u"февраля"), - (u"мар", u"март", u"марта"), - (u"апр", u"апрель", u"апреля"), - (u"май", u"май", u"мая"), - (u"июн", u"июнь", u"июня"), - (u"июл", u"июль", u"июля"), - (u"авг", u"август", u"августа"), - (u"сен", u"сентябрь", u"сентября"), - (u"окт", u"октябрь", u"октября"), - (u"ноя", u"ноябрь", u"ноября"), - (u"дек", u"декабрь", u"декабря"), + ("янв", "январь", "января"), + ("фев", "февраль", "февраля"), + ("мар", "март", "марта"), + ("апр", "апрель", "апреля"), + ("май", "май", "мая"), + ("июн", "июнь", "июня"), + ("июл", "июль", "июля"), + ("авг", "август", "августа"), + ("сен", "сентябрь", "сентября"), + ("окт", "октябрь", "октября"), + ("ноя", "ноябрь", "ноября"), + ("дек", "декабрь", "декабря"), ) #: Month names (abbreviated, full, inflected) DAY_NAMES = ( - (u"пн", u"понедельник", u"понедельник", u"в\xa0"), - (u"вт", u"вторник", u"вторник", u"во\xa0"), - (u"ср", u"среда", u"среду", u"в\xa0"), - (u"чт", u"четверг", u"четверг", u"в\xa0"), - (u"пт", u"пятница", u"пятницу", u"в\xa0"), - (u"сб", u"суббота", u"субботу", u"в\xa0"), - (u"вск", u"воскресенье", u"воскресенье", u"в\xa0") + ("пн", "понедельник", "понедельник", "в\xa0"), + ("вт", "вторник", "вторник", "во\xa0"), + ("ср", "среда", "среду", "в\xa0"), + ("чт", "четверг", "четверг", "в\xa0"), + ("пт", "пятница", "пятницу", "в\xa0"), + ("сб", "суббота", "субботу", "в\xa0"), + ("вск", "воскресенье", "воскресенье", "в\xa0") ) #: Day names (abbreviated, full, inflected, preposition) @@ -113,23 +114,23 @@ def distance_of_time_in_words(from_time, accuracy=1, to_time=None): days = days_orig hours = hours_orig - days_orig*24 - words.append(u"%d %s" % (days, numeral.choose_plural(days, DAY_VARIANTS))) + words.append("%d %s" % (days, numeral.choose_plural(days, DAY_VARIANTS))) values.append(days) - words.append(u"%d %s" % + words.append("%d %s" % (hours, numeral.choose_plural(hours, HOUR_VARIANTS))) values.append(hours) - days == 0 and hours == 1 and current and alternatives.append(u"час") + days == 0 and hours == 1 and current and alternatives.append("час") minutes = minutes_orig - hours_orig*60 - words.append(u"%d %s" % (minutes, + words.append("%d %s" % (minutes, numeral.choose_plural(minutes, MINUTE_VARIANTS))) values.append(minutes) days == 0 and hours == 0 and minutes == 1 and current and \ - alternatives.append(u"минуту") + alternatives.append("минуту") # убираем из values и words конечные нули while values and not values[-1]: @@ -148,21 +149,21 @@ def distance_of_time_in_words(from_time, accuracy=1, to_time=None): real_words.pop() limit -= 1 - real_str = u" ".join(real_words) + real_str = " ".join(real_words) # альтернативные варианты нужны только если в real_words одно значение # и, вдобавок, если используется текущее время alter_str = limit == 1 and current and alternatives and \ alternatives[0] _result_str = alter_str or real_str - result_str = in_future and u"%s %s" % (PREFIX_IN, _result_str) \ - or u"%s %s" % (_result_str, SUFFIX_AGO) + result_str = in_future and "%s %s" % (PREFIX_IN, _result_str) \ + or "%s %s" % (_result_str, SUFFIX_AGO) # если же прошло менее минуты, то real_words -- пустой, и поэтому # нужно брать alternatives[0], а не result_str zero_str = minutes == 0 and not real_words and \ - (in_future and u"менее чем через минуту" - or u"менее минуты назад") + (in_future and "менее чем через минуту" + or "менее минуты назад") # нужно использовать вчера/позавчера/завтра/послезавтра # если days 1..2 и в real_words одно значение @@ -176,7 +177,7 @@ def distance_of_time_in_words(from_time, accuracy=1, to_time=None): return final_str -def ru_strftime(format=u"%d.%m.%Y", date=None, inflected=False, +def ru_strftime(format="%d.%m.%Y", date=None, inflected=False, inflected_day=False, preposition=False): """ Russian strftime without locale @@ -205,20 +206,20 @@ def ru_strftime(format=u"%d.%m.%Y", date=None, inflected=False, weekday = date.weekday() - prepos = preposition and DAY_NAMES[weekday][3] or u"" + prepos = preposition and DAY_NAMES[weekday][3] or "" month_idx = inflected and 2 or 1 day_idx = (inflected_day or preposition) and 2 or 1 # for russian typography standard, # 1 April 2007, but 01.04.2007 - if u'%b' in format or u'%B' in format: - format = format.replace(u'%d', six.text_type(date.day)) + if '%b' in format or '%B' in format: + format = format.replace('%d', six.text_type(date.day)) - format = format.replace(u'%a', prepos+DAY_NAMES[weekday][0]) - format = format.replace(u'%A', prepos+DAY_NAMES[weekday][day_idx]) - format = format.replace(u'%b', MONTH_NAMES[date.month-1][0]) - format = format.replace(u'%B', MONTH_NAMES[date.month-1][month_idx]) + format = format.replace('%a', prepos+DAY_NAMES[weekday][0]) + format = format.replace('%A', prepos+DAY_NAMES[weekday][day_idx]) + format = format.replace('%b', MONTH_NAMES[date.month-1][0]) + format = format.replace('%B', MONTH_NAMES[date.month-1][month_idx]) # Python 2: strftime's argument must be str # Python 3: strftime's argument str, not a bitestring diff --git a/pytils/numeral.py b/pytils/numeral.py index 922b441..58b9ca3 100644 --- a/pytils/numeral.py +++ b/pytils/numeral.py @@ -3,70 +3,71 @@ """ Plural forms and in-word representation for numerals. """ -from __future__ import division + +from __future__ import unicode_literals, division from decimal import Decimal from pytils.utils import check_positive, check_length, split_values from pytils.third import six FRACTIONS = ( - (u"десятая", u"десятых", u"десятых"), - (u"сотая", u"сотых", u"сотых"), - (u"тысячная", u"тысячных", u"тысячных"), - (u"десятитысячная", u"десятитысячных", u"десятитысячных"), - (u"стотысячная", u"стотысячных", u"стотысячных"), - (u"миллионная", u"милллионных", u"милллионных"), - (u"десятимиллионная", u"десятимилллионных", u"десятимиллионных"), - (u"стомиллионная", u"стомилллионных", u"стомиллионных"), - (u"миллиардная", u"миллиардных", u"миллиардных"), + ("десятая", "десятых", "десятых"), + ("сотая", "сотых", "сотых"), + ("тысячная", "тысячных", "тысячных"), + ("десятитысячная", "десятитысячных", "десятитысячных"), + ("стотысячная", "стотысячных", "стотысячных"), + ("миллионная", "милллионных", "милллионных"), + ("десятимиллионная", "десятимилллионных", "десятимиллионных"), + ("стомиллионная", "стомилллионных", "стомиллионных"), + ("миллиардная", "миллиардных", "миллиардных"), ) #: Forms (1, 2, 5) for fractions ONES = { - 0: (u"", u"", u""), - 1: (u"один", u"одна", u"одно"), - 2: (u"два", u"две", u"два"), - 3: (u"три", u"три", u"три"), - 4: (u"четыре", u"четыре", u"четыре"), - 5: (u"пять", u"пять", u"пять"), - 6: (u"шесть", u"шесть", u"шесть"), - 7: (u"семь", u"семь", u"семь"), - 8: (u"восемь", u"восемь", u"восемь"), - 9: (u"девять", u"девять", u"девять"), + 0: ("", "", ""), + 1: ("один", "одна", "одно"), + 2: ("два", "две", "два"), + 3: ("три", "три", "три"), + 4: ("четыре", "четыре", "четыре"), + 5: ("пять", "пять", "пять"), + 6: ("шесть", "шесть", "шесть"), + 7: ("семь", "семь", "семь"), + 8: ("восемь", "восемь", "восемь"), + 9: ("девять", "девять", "девять"), } #: Forms (MALE, FEMALE, NEUTER) for ones TENS = { - 0: u"", + 0: "", # 1 - особый случай - 10: u"десять", - 11: u"одиннадцать", - 12: u"двенадцать", - 13: u"тринадцать", - 14: u"четырнадцать", - 15: u"пятнадцать", - 16: u"шестнадцать", - 17: u"семнадцать", - 18: u"восемнадцать", - 19: u"девятнадцать", - 2: u"двадцать", - 3: u"тридцать", - 4: u"сорок", - 5: u"пятьдесят", - 6: u"шестьдесят", - 7: u"семьдесят", - 8: u"восемьдесят", - 9: u"девяносто", + 10: "десять", + 11: "одиннадцать", + 12: "двенадцать", + 13: "тринадцать", + 14: "четырнадцать", + 15: "пятнадцать", + 16: "шестнадцать", + 17: "семнадцать", + 18: "восемнадцать", + 19: "девятнадцать", + 2: "двадцать", + 3: "тридцать", + 4: "сорок", + 5: "пятьдесят", + 6: "шестьдесят", + 7: "семьдесят", + 8: "восемьдесят", + 9: "девяносто", } #: Tens HUNDREDS = { - 0: u"", - 1: u"сто", - 2: u"двести", - 3: u"триста", - 4: u"четыреста", - 5: u"пятьсот", - 6: u"шестьсот", - 7: u"семьсот", - 8: u"восемьсот", - 9: u"девятьсот", + 0: "", + 1: "сто", + 2: "двести", + 3: "триста", + 4: "четыреста", + 5: "пятьсот", + 6: "шестьсот", + 7: "семьсот", + 8: "восемьсот", + 9: "девятьсот", } #: Hundreds MALE = 1 #: sex - male @@ -176,7 +177,7 @@ def get_plural(amount, variants, absence=None): @rtype: C{unicode} """ if amount or absence is None: - return u"%d %s" % (amount, choose_plural(amount, variants)) + return "%d %s" % (amount, choose_plural(amount, variants)) else: return absence @@ -227,7 +228,7 @@ def rubles(amount, zero_for_kopeck=False): pts = [] amount = round(amount, 2) - pts.append(sum_string(int(amount), 1, (u"рубль", u"рубля", u"рублей"))) + pts.append(sum_string(int(amount), 1, ("рубль", "рубля", "рублей"))) remainder = _get_float_remainder(amount, 2) iremainder = int(remainder) @@ -236,9 +237,9 @@ def rubles(amount, zero_for_kopeck=False): if iremainder < 10 and len(remainder) == 1: iremainder *= 10 pts.append(sum_string(iremainder, 2, - (u"копейка", u"копейки", u"копеек"))) + ("копейка", "копейки", "копеек"))) - return u" ".join(pts) + return " ".join(pts) def in_words_int(amount, gender=MALE): @@ -277,13 +278,13 @@ def in_words_float(amount, _gender=FEMALE): pts = [] # преобразуем целую часть pts.append(sum_string(int(amount), 2, - (u"целая", u"целых", u"целых"))) + ("целая", "целых", "целых"))) # теперь то, что после запятой remainder = _get_float_remainder(amount) signs = len(str(remainder)) - 1 pts.append(sum_string(int(remainder), 2, FRACTIONS[signs])) - return u" ".join(pts) + return " ".join(pts) def in_words(amount, gender=None): @@ -350,7 +351,7 @@ def sum_string(amount, gender, items=None): if isinstance(items, six.text_type): items = split_values(items) if items is None: - items = (u"", u"", u"") + items = ("", "", "") try: one_item, two_items, five_items = items @@ -361,24 +362,24 @@ def sum_string(amount, gender, items=None): if amount == 0: if five_items: - return u"ноль %s" % five_items + return "ноль %s" % five_items else: - return u"ноль" + return "ноль" - into = u'' + into = '' tmp_val = amount # единицы into, tmp_val = _sum_string_fn(into, tmp_val, gender, items) # тысячи into, tmp_val = _sum_string_fn(into, tmp_val, FEMALE, - (u"тысяча", u"тысячи", u"тысяч")) + ("тысяча", "тысячи", "тысяч")) # миллионы into, tmp_val = _sum_string_fn(into, tmp_val, MALE, - (u"миллион", u"миллиона", u"миллионов")) + ("миллион", "миллиона", "миллионов")) # миллиарды into, tmp_val = _sum_string_fn(into, tmp_val, MALE, - (u"миллиард", u"миллиарда", u"миллиардов")) + ("миллиард", "миллиарда", "миллиардов")) if tmp_val == 0: return into else: @@ -407,7 +408,7 @@ def _sum_string_fn(into, tmp_val, gender, items=None): @raise ValueError: tmp_val is negative """ if items is None: - items = (u"", u"", u"") + items = ("", "", "") one_item, two_items, five_items = items check_positive(tmp_val) @@ -421,8 +422,8 @@ def _sum_string_fn(into, tmp_val, gender, items=None): tmp_val = tmp_val // 1000 if rest == 0: # последние три знака нулевые - if into == u"": - into = u"%s " % five_items + if into == "": + into = "%s " % five_items return into, tmp_val # начинаем подсчет с rest @@ -449,7 +450,7 @@ def _sum_string_fn(into, tmp_val, gender, items=None): words.append(into) # убираем пустые подстроки - words = filter(lambda x: len(x) > 0, words) + words = [x for x in words if len(x) > 0] # склеиваем и отдаем - return u" ".join(words).strip(), tmp_val + return " ".join(words).strip(), tmp_val diff --git a/pytils/templatetags/__init__.py b/pytils/templatetags/__init__.py index edd4f95..1dfc804 100644 --- a/pytils/templatetags/__init__.py +++ b/pytils/templatetags/__init__.py @@ -2,6 +2,7 @@ """ Pytils templatetags for Django web-framework """ +from __future__ import unicode_literals # Если отладка, то показываем 'unknown+сообщение об ошибке'. # Если отладка выключена, то можно чтобы при ошибках показывалось @@ -10,11 +11,11 @@ def init_defaults(debug, show_value): if debug: default_value = "unknown: %(error)s" - default_uvalue = u"unknown: %(error)s" + default_uvalue = "unknown: %(error)s" elif show_value: default_value = "%(value)s" - default_uvalue = u"%(value)s" + default_uvalue = "%(value)s" else: default_value = "" - default_uvalue = u"" + default_uvalue = "" return default_value, default_uvalue diff --git a/pytils/test/templatetags/helpers.py b/pytils/test/templatetags/helpers.py index 891b299..4886920 100644 --- a/pytils/test/templatetags/helpers.py +++ b/pytils/test/templatetags/helpers.py @@ -3,6 +3,7 @@ Helpers for templatetags' unit tests in Django webframework """ +from __future__ import unicode_literals from django.conf import settings from django.utils.encoding import smart_str @@ -51,5 +52,5 @@ def test_template_loader(template_name, template_dirs=None): loader.template_source_loaders = [test_template_loader,] output = loader.get_template(template_name).render(template.Context(context)) - self.assertEquals(output, result_string) + self.assertEqual(output, result_string) diff --git a/pytils/test/templatetags/test_common.py b/pytils/test/templatetags/test_common.py index fc7571f..8d8e2f3 100644 --- a/pytils/test/templatetags/test_common.py +++ b/pytils/test/templatetags/test_common.py @@ -3,6 +3,7 @@ Unit tests for pytils' templatetags common things """ +from __future__ import unicode_literals import unittest from pytils import templatetags as tt @@ -13,10 +14,10 @@ def testInitDefaults(self): """ Unit-tests for pytils.templatetags.init_defaults """ - self.assertEquals(tt.init_defaults(debug=False, show_value=False), ('', u'')) - self.assertEquals(tt.init_defaults(debug=False, show_value=True), ('%(value)s', u'%(value)s')) - self.assertEquals(tt.init_defaults(debug=True, show_value=False), ('unknown: %(error)s', u'unknown: %(error)s')) - self.assertEquals(tt.init_defaults(debug=True, show_value=True), ('unknown: %(error)s', u'unknown: %(error)s')) + self.assertEqual(tt.init_defaults(debug=False, show_value=False), ('', '')) + self.assertEqual(tt.init_defaults(debug=False, show_value=True), ('%(value)s', '%(value)s')) + self.assertEqual(tt.init_defaults(debug=True, show_value=False), ('unknown: %(error)s', 'unknown: %(error)s')) + self.assertEqual(tt.init_defaults(debug=True, show_value=True), ('unknown: %(error)s', 'unknown: %(error)s')) if __name__ == '__main__': diff --git a/pytils/test/templatetags/test_dt.py b/pytils/test/templatetags/test_dt.py index 2fe7fd4..e34bc68 100644 --- a/pytils/test/templatetags/test_dt.py +++ b/pytils/test/templatetags/test_dt.py @@ -3,6 +3,7 @@ Unit tests for pytils' dt templatetags for Django web framework """ +from __future__ import unicode_literals import datetime from pytils.test.templatetags import helpers @@ -13,43 +14,43 @@ def setUp(self): self.date_before = datetime.datetime.now() - datetime.timedelta(1, 2000) def testLoad(self): - self.check_template_tag('load_tag', u'{% load pytils_dt %}', {}, u'') + self.check_template_tag('load_tag', '{% load pytils_dt %}', {}, '') def testRuStrftimeFilter(self): self.check_template_tag('ru_strftime_filter', - u'{% load pytils_dt %}{{ val|ru_strftime:"%d %B %Y, %A" }}', + '{% load pytils_dt %}{{ val|ru_strftime:"%d %B %Y, %A" }}', {'val': self.date}, - u'26 января 2007, пятница') + '26 января 2007, пятница') def testRuStrftimeInflectedFilter(self): self.check_template_tag('ru_strftime_inflected_filter', - u'{% load pytils_dt %}{{ val|ru_strftime_inflected:"в %A, %d %B %Y" }}', + '{% load pytils_dt %}{{ val|ru_strftime_inflected:"в %A, %d %B %Y" }}', {'val': self.date}, - u'в пятницу, 26 января 2007') + 'в пятницу, 26 января 2007') def testRuStrftimePrepositionFilter(self): self.check_template_tag('ru_strftime_preposition_filter', - u'{% load pytils_dt %}{{ val|ru_strftime_preposition:"%A, %d %B %Y" }}', + '{% load pytils_dt %}{{ val|ru_strftime_preposition:"%A, %d %B %Y" }}', {'val': self.date}, - u'в\xa0пятницу, 26 января 2007') + 'в\xa0пятницу, 26 января 2007') def testDistanceFilter(self): self.check_template_tag('distance_filter', - u'{% load pytils_dt %}{{ val|distance_of_time }}', + '{% load pytils_dt %}{{ val|distance_of_time }}', {'val': self.date_before}, - u'вчера') + 'вчера') self.check_template_tag('distance_filter', - u'{% load pytils_dt %}{{ val|distance_of_time:3 }}', + '{% load pytils_dt %}{{ val|distance_of_time:3 }}', {'val': self.date_before}, - u'1 день 0 часов 33 минуты назад') + '1 день 0 часов 33 минуты назад') # без отладки, если ошибка -- по умолчанию пустая строка def testRuStrftimeError(self): self.check_template_tag('ru_strftime_error', - u'{% load pytils_dt %}{{ val|ru_strftime:"%d %B %Y" }}', + '{% load pytils_dt %}{{ val|ru_strftime:"%d %B %Y" }}', {'val': 1}, - u'') + '') if __name__ == '__main__': import unittest diff --git a/pytils/test/templatetags/test_numeral.py b/pytils/test/templatetags/test_numeral.py index cdb4b67..89a6622 100644 --- a/pytils/test/templatetags/test_numeral.py +++ b/pytils/test/templatetags/test_numeral.py @@ -3,72 +3,73 @@ Unit tests for pytils' numeral templatetags for Django web framework """ +from __future__ import unicode_literals from pytils.test.templatetags import helpers class NumeralDefaultTestCase(helpers.TemplateTagTestCase): def testLoad(self): - self.check_template_tag('load_tag', u'{% load pytils_numeral %}', {}, u'') + self.check_template_tag('load_tag', '{% load pytils_numeral %}', {}, '') def testChoosePluralFilter(self): self.check_template_tag('choose_plural', - u'{% load pytils_numeral %}{{ val|choose_plural:"гвоздь,гвоздя,гвоздей" }}', + '{% load pytils_numeral %}{{ val|choose_plural:"гвоздь,гвоздя,гвоздей" }}', {'val': 10}, - u'гвоздей') + 'гвоздей') def testGetPluralFilter(self): self.check_template_tag('get_plural', - u'{% load pytils_numeral %}{{ val|get_plural:"гвоздь,гвоздя,гвоздей" }}', + '{% load pytils_numeral %}{{ val|get_plural:"гвоздь,гвоздя,гвоздей" }}', {'val': 10}, - u'10 гвоздей') + '10 гвоздей') self.check_template_tag('get_plural', - u'{% load pytils_numeral %}{{ val|get_plural:"гвоздь,гвоздя,гвоздей" }}', + '{% load pytils_numeral %}{{ val|get_plural:"гвоздь,гвоздя,гвоздей" }}', {'val': 0}, - u'0 гвоздей') + '0 гвоздей') self.check_template_tag('get_plural', - u'{% load pytils_numeral %}{{ val|get_plural:"гвоздь,гвоздя,гвоздей,нет гвоздей" }}', + '{% load pytils_numeral %}{{ val|get_plural:"гвоздь,гвоздя,гвоздей,нет гвоздей" }}', {'val': 0}, - u'нет гвоздей') + 'нет гвоздей') def testRublesFilter(self): self.check_template_tag('rubles', - u'{% load pytils_numeral %}{{ val|rubles }}', + '{% load pytils_numeral %}{{ val|rubles }}', {'val': 10.1}, - u'десять рублей десять копеек') + 'десять рублей десять копеек') def testInWordsFilter(self): self.check_template_tag('in_words', - u'{% load pytils_numeral %}{{ val|in_words }}', + '{% load pytils_numeral %}{{ val|in_words }}', {'val': 21}, - u'двадцать один') + 'двадцать один') self.check_template_tag('in_words', - u'{% load pytils_numeral %}{{ val|in_words:"NEUTER" }}', + '{% load pytils_numeral %}{{ val|in_words:"NEUTER" }}', {'val': 21}, - u'двадцать одно') + 'двадцать одно') def testSumStringTag(self): self.check_template_tag('sum_string', - u'{% load pytils_numeral %}{% sum_string val "MALE" "пример,пример,примеров" %}', + '{% load pytils_numeral %}{% sum_string val "MALE" "пример,пример,примеров" %}', {'val': 21}, - u'двадцать один пример') + 'двадцать один пример') self.check_template_tag('sum_string_w_gender', - u'{% load pytils_numeral %}{% sum_string val male variants %}', + '{% load pytils_numeral %}{% sum_string val male variants %}', { 'val': 21, 'male':'MALE', 'variants': ('пример','пример','примеров') }, - u'двадцать один пример') + 'двадцать один пример') # без отладки, если ошибка -- по умолчанию пустая строка def testChoosePluralError(self): self.check_template_tag('choose_plural_error', - u'{% load pytils_numeral %}{{ val|choose_plural:"вариант" }}', + '{% load pytils_numeral %}{{ val|choose_plural:"вариант" }}', {'val': 1}, - u'') + '') if __name__ == '__main__': diff --git a/pytils/test/templatetags/test_translit.py b/pytils/test/templatetags/test_translit.py index 80aa148..e0ecbbb 100644 --- a/pytils/test/templatetags/test_translit.py +++ b/pytils/test/templatetags/test_translit.py @@ -3,30 +3,31 @@ Unit tests for pytils' translit templatetags for Django web framework """ +from __future__ import unicode_literals from pytils.test.templatetags import helpers class TranslitDefaultTestCase(helpers.TemplateTagTestCase): def testLoad(self): - self.check_template_tag('load_tag', u'{% load pytils_translit %}', {}, u'') + self.check_template_tag('load_tag', '{% load pytils_translit %}', {}, '') def testTranslifyFilter(self): self.check_template_tag('translify_filter', - u'{% load pytils_translit %}{{ val|translify }}', + '{% load pytils_translit %}{{ val|translify }}', {'val': 'проверка'}, - u'proverka') + 'proverka') def testDetranslifyFilter(self): self.check_template_tag('detranslify_filter', - u'{% load pytils_translit %}{{ val|detranslify }}', + '{% load pytils_translit %}{{ val|detranslify }}', {'val': 'proverka'}, - u'проверка') + 'проверка') def testSlugifyFilter(self): self.check_template_tag('slugify_filter', - u'{% load pytils_translit %}{{ val|slugify }}', + '{% load pytils_translit %}{{ val|slugify }}', {'val': 'Проверка связи'}, - u'proverka-svyazi') + 'proverka-svyazi') if __name__ == '__main__': diff --git a/pytils/test/test_dt.py b/pytils/test/test_dt.py index f00a5ee..c3a81d2 100644 --- a/pytils/test/test_dt.py +++ b/pytils/test/test_dt.py @@ -3,6 +3,7 @@ Unit-tests for pytils.dt """ +from __future__ import unicode_literals import datetime import time import unittest @@ -62,7 +63,7 @@ def ckDefaultAccuracy(self, typ, estimated): # --- revert state to original value self.updateTime(self.time) # --- - self.assertEquals(res, estimated) + self.assertEqual(res, estimated) def ckDefaultTimeAndAccuracy(self, typ, estimated): """ @@ -77,7 +78,7 @@ def ckDefaultTimeAndAccuracy(self, typ, estimated): # --- revert state to original value self.updateTime(self.time) # --- - self.assertEquals(res, estimated) + self.assertEqual(res, estimated) def ckDefaultToTime(self, typ, accuracy, estimated): """ @@ -92,73 +93,73 @@ def ckDefaultToTime(self, typ, accuracy, estimated): # --- revert state to original value self.updateTime(self.time) # --- - self.assertEquals(res, estimated) + self.assertEqual(res, estimated) def testDOTIWDefaultAccuracy(self): """ Unit-test for distance_of_time_in_words with default accuracy """ - self.ckDefaultAccuracy("10sec_ago", u"менее минуты назад") - self.ckDefaultAccuracy("1min_ago", u"1 минуту назад") - self.ckDefaultAccuracy("10min_ago", u"10 минут назад") - self.ckDefaultAccuracy("59min_ago", u"59 минут назад") - self.ckDefaultAccuracy("59min59sec_ago", u"59 минут назад") - self.ckDefaultAccuracy("1hr_ago", u"1 час назад") - self.ckDefaultAccuracy("1hr1sec_ago", u"1 час назад") - self.ckDefaultAccuracy("1hr59sec_ago", u"1 час назад") - self.ckDefaultAccuracy("1hr1min_ago", u"1 час назад") - self.ckDefaultAccuracy("1hr2min_ago", u"1 час назад") - self.ckDefaultAccuracy("10hr_ago", u"10 часов назад") - self.ckDefaultAccuracy("1day_ago", u"1 день назад") - self.ckDefaultAccuracy("1day1hr_ago", u"1 день назад") - self.ckDefaultAccuracy("2day_ago", u"2 дня назад") - - self.ckDefaultAccuracy("in_10sec", u"менее чем через минуту") - self.ckDefaultAccuracy("in_1min", u"через 1 минуту") - self.ckDefaultAccuracy("in_10min", u"через 10 минут") - self.ckDefaultAccuracy("in_1hr", u"через 1 час") - self.ckDefaultAccuracy("in_10hr", u"через 10 часов") - self.ckDefaultAccuracy("in_1day", u"через 1 день") - self.ckDefaultAccuracy("in_1day1hr", u"через 1 день") - self.ckDefaultAccuracy("in_2day", u"через 2 дня") + self.ckDefaultAccuracy("10sec_ago", "менее минуты назад") + self.ckDefaultAccuracy("1min_ago", "1 минуту назад") + self.ckDefaultAccuracy("10min_ago", "10 минут назад") + self.ckDefaultAccuracy("59min_ago", "59 минут назад") + self.ckDefaultAccuracy("59min59sec_ago", "59 минут назад") + self.ckDefaultAccuracy("1hr_ago", "1 час назад") + self.ckDefaultAccuracy("1hr1sec_ago", "1 час назад") + self.ckDefaultAccuracy("1hr59sec_ago", "1 час назад") + self.ckDefaultAccuracy("1hr1min_ago", "1 час назад") + self.ckDefaultAccuracy("1hr2min_ago", "1 час назад") + self.ckDefaultAccuracy("10hr_ago", "10 часов назад") + self.ckDefaultAccuracy("1day_ago", "1 день назад") + self.ckDefaultAccuracy("1day1hr_ago", "1 день назад") + self.ckDefaultAccuracy("2day_ago", "2 дня назад") + + self.ckDefaultAccuracy("in_10sec", "менее чем через минуту") + self.ckDefaultAccuracy("in_1min", "через 1 минуту") + self.ckDefaultAccuracy("in_10min", "через 10 минут") + self.ckDefaultAccuracy("in_1hr", "через 1 час") + self.ckDefaultAccuracy("in_10hr", "через 10 часов") + self.ckDefaultAccuracy("in_1day", "через 1 день") + self.ckDefaultAccuracy("in_1day1hr", "через 1 день") + self.ckDefaultAccuracy("in_2day", "через 2 дня") def testDOTIWDefaultAccuracyDayAndMinute(self): """ Unit-tests for distance_of_time_in_words with default accuracy and to_time """ - self.ckDefaultTimeAndAccuracy("4day1min_ago", u"4 дня назад") - - self.ckDefaultTimeAndAccuracy("10sec_ago", u"менее минуты назад") - self.ckDefaultTimeAndAccuracy("1min_ago", u"минуту назад") - self.ckDefaultTimeAndAccuracy("10min_ago", u"10 минут назад") - self.ckDefaultTimeAndAccuracy("59min_ago", u"59 минут назад") - self.ckDefaultTimeAndAccuracy("59min59sec_ago", u"59 минут назад") - self.ckDefaultTimeAndAccuracy("1hr_ago", u"час назад") - self.ckDefaultTimeAndAccuracy("1hr1sec_ago", u"час назад") - self.ckDefaultTimeAndAccuracy("1hr59sec_ago", u"час назад") - self.ckDefaultTimeAndAccuracy("1hr1min_ago", u"час назад") - self.ckDefaultTimeAndAccuracy("1hr2min_ago", u"час назад") - self.ckDefaultTimeAndAccuracy("10hr_ago", u"10 часов назад") - self.ckDefaultTimeAndAccuracy("1day_ago", u"вчера") - self.ckDefaultTimeAndAccuracy("1day1hr_ago", u"вчера") - self.ckDefaultTimeAndAccuracy("2day_ago", u"позавчера") - - self.ckDefaultTimeAndAccuracy("in_10sec", u"менее чем через минуту") - self.ckDefaultTimeAndAccuracy("in_1min", u"через минуту") - self.ckDefaultTimeAndAccuracy("in_10min", u"через 10 минут") - self.ckDefaultTimeAndAccuracy("in_1hr", u"через час") - self.ckDefaultTimeAndAccuracy("in_10hr", u"через 10 часов") - self.ckDefaultTimeAndAccuracy("in_1day", u"завтра") - self.ckDefaultTimeAndAccuracy("in_1day1hr", u"завтра") - self.ckDefaultTimeAndAccuracy("in_2day", u"послезавтра") + self.ckDefaultTimeAndAccuracy("4day1min_ago", "4 дня назад") + + self.ckDefaultTimeAndAccuracy("10sec_ago", "менее минуты назад") + self.ckDefaultTimeAndAccuracy("1min_ago", "минуту назад") + self.ckDefaultTimeAndAccuracy("10min_ago", "10 минут назад") + self.ckDefaultTimeAndAccuracy("59min_ago", "59 минут назад") + self.ckDefaultTimeAndAccuracy("59min59sec_ago", "59 минут назад") + self.ckDefaultTimeAndAccuracy("1hr_ago", "час назад") + self.ckDefaultTimeAndAccuracy("1hr1sec_ago", "час назад") + self.ckDefaultTimeAndAccuracy("1hr59sec_ago", "час назад") + self.ckDefaultTimeAndAccuracy("1hr1min_ago", "час назад") + self.ckDefaultTimeAndAccuracy("1hr2min_ago", "час назад") + self.ckDefaultTimeAndAccuracy("10hr_ago", "10 часов назад") + self.ckDefaultTimeAndAccuracy("1day_ago", "вчера") + self.ckDefaultTimeAndAccuracy("1day1hr_ago", "вчера") + self.ckDefaultTimeAndAccuracy("2day_ago", "позавчера") + + self.ckDefaultTimeAndAccuracy("in_10sec", "менее чем через минуту") + self.ckDefaultTimeAndAccuracy("in_1min", "через минуту") + self.ckDefaultTimeAndAccuracy("in_10min", "через 10 минут") + self.ckDefaultTimeAndAccuracy("in_1hr", "через час") + self.ckDefaultTimeAndAccuracy("in_10hr", "через 10 часов") + self.ckDefaultTimeAndAccuracy("in_1day", "завтра") + self.ckDefaultTimeAndAccuracy("in_1day1hr", "завтра") + self.ckDefaultTimeAndAccuracy("in_2day", "послезавтра") def test4Days1MinuteDaytimeBug2(self): from_time = datetime.datetime.now() - \ datetime.timedelta(days=4, minutes=1) res = pytils.dt.distance_of_time_in_words(from_time) - self.assertEquals( + self.assertEqual( res, - u"4 дня назад") + "4 дня назад") def testDOTIWDefaultToTimeAcc1(self): @@ -166,93 +167,93 @@ def testDOTIWDefaultToTimeAcc1(self): Unit-tests for distance_of_time_in_words with default to_time and accuracy=1 """ # accuracy = 1 - self.ckDefaultToTime("10sec_ago", 1, u"менее минуты назад") - self.ckDefaultToTime("1min_ago", 1, u"минуту назад") - self.ckDefaultToTime("10min_ago", 1, u"10 минут назад") - self.ckDefaultToTime("59min_ago", 1, u"59 минут назад") - self.ckDefaultToTime("59min59sec_ago", 1, u"59 минут назад") - self.ckDefaultToTime("1hr_ago", 1, u"час назад") - self.ckDefaultToTime("1hr1sec_ago", 1, u"час назад") - self.ckDefaultToTime("1hr59sec_ago", 1, u"час назад") - self.ckDefaultToTime("1hr1min_ago", 1, u"час назад") - self.ckDefaultToTime("1hr2min_ago", 1, u"час назад") - self.ckDefaultToTime("10hr_ago", 1, u"10 часов назад") - self.ckDefaultToTime("1day_ago", 1, u"вчера") - self.ckDefaultToTime("1day1hr_ago", 1, u"вчера") - self.ckDefaultToTime("2day_ago", 1, u"позавчера") - - self.ckDefaultToTime("in_10sec", 1, u"менее чем через минуту") - self.ckDefaultToTime("in_1min", 1, u"через минуту") - self.ckDefaultToTime("in_10min", 1, u"через 10 минут") - self.ckDefaultToTime("in_1hr", 1, u"через час") - self.ckDefaultToTime("in_10hr", 1, u"через 10 часов") - self.ckDefaultToTime("in_1day", 1, u"завтра") - self.ckDefaultToTime("in_1day1hr", 1, u"завтра") - self.ckDefaultToTime("in_2day", 1, u"послезавтра") + self.ckDefaultToTime("10sec_ago", 1, "менее минуты назад") + self.ckDefaultToTime("1min_ago", 1, "минуту назад") + self.ckDefaultToTime("10min_ago", 1, "10 минут назад") + self.ckDefaultToTime("59min_ago", 1, "59 минут назад") + self.ckDefaultToTime("59min59sec_ago", 1, "59 минут назад") + self.ckDefaultToTime("1hr_ago", 1, "час назад") + self.ckDefaultToTime("1hr1sec_ago", 1, "час назад") + self.ckDefaultToTime("1hr59sec_ago", 1, "час назад") + self.ckDefaultToTime("1hr1min_ago", 1, "час назад") + self.ckDefaultToTime("1hr2min_ago", 1, "час назад") + self.ckDefaultToTime("10hr_ago", 1, "10 часов назад") + self.ckDefaultToTime("1day_ago", 1, "вчера") + self.ckDefaultToTime("1day1hr_ago", 1, "вчера") + self.ckDefaultToTime("2day_ago", 1, "позавчера") + + self.ckDefaultToTime("in_10sec", 1, "менее чем через минуту") + self.ckDefaultToTime("in_1min", 1, "через минуту") + self.ckDefaultToTime("in_10min", 1, "через 10 минут") + self.ckDefaultToTime("in_1hr", 1, "через час") + self.ckDefaultToTime("in_10hr", 1, "через 10 часов") + self.ckDefaultToTime("in_1day", 1, "завтра") + self.ckDefaultToTime("in_1day1hr", 1, "завтра") + self.ckDefaultToTime("in_2day", 1, "послезавтра") def testDOTIWDefaultToTimeAcc2(self): """ Unit-tests for distance_of_time_in_words with default to_time and accuracy=2 """ # accuracy = 2 - self.ckDefaultToTime("10sec_ago", 2, u"менее минуты назад") - self.ckDefaultToTime("1min_ago", 2, u"минуту назад") - self.ckDefaultToTime("10min_ago", 2, u"10 минут назад") - self.ckDefaultToTime("59min_ago", 2, u"59 минут назад") - self.ckDefaultToTime("59min59sec_ago", 2, u"59 минут назад") - self.ckDefaultToTime("1hr_ago", 2, u"час назад") - self.ckDefaultToTime("1hr1sec_ago", 2, u"час назад") - self.ckDefaultToTime("1hr59sec_ago", 2, u"час назад") - self.ckDefaultToTime("1hr1min_ago", 2, u"1 час 1 минуту назад") - self.ckDefaultToTime("1hr2min_ago", 2, u"1 час 2 минуты назад") - self.ckDefaultToTime("10hr_ago", 2, u"10 часов 10 минут назад") - self.ckDefaultToTime("1day_ago", 2, u"вчера") - self.ckDefaultToTime("1day1hr_ago", 2, u"1 день 1 час назад") - self.ckDefaultToTime("2day_ago", 2, u"позавчера") - - self.ckDefaultToTime("in_10sec", 2, u"менее чем через минуту") - self.ckDefaultToTime("in_1min", 2, u"через минуту") - self.ckDefaultToTime("in_10min", 2, u"через 10 минут") - self.ckDefaultToTime("in_1hr", 2, u"через 1 час 2 минуты") - self.ckDefaultToTime("in_10hr", 2, u"через 10 часов 10 минут") - self.ckDefaultToTime("in_1day", 2, u"завтра") - self.ckDefaultToTime("in_1day1hr", 2, u"через 1 день 1 час") - self.ckDefaultToTime("in_2day", 2, u"послезавтра") + self.ckDefaultToTime("10sec_ago", 2, "менее минуты назад") + self.ckDefaultToTime("1min_ago", 2, "минуту назад") + self.ckDefaultToTime("10min_ago", 2, "10 минут назад") + self.ckDefaultToTime("59min_ago", 2, "59 минут назад") + self.ckDefaultToTime("59min59sec_ago", 2, "59 минут назад") + self.ckDefaultToTime("1hr_ago", 2, "час назад") + self.ckDefaultToTime("1hr1sec_ago", 2, "час назад") + self.ckDefaultToTime("1hr59sec_ago", 2, "час назад") + self.ckDefaultToTime("1hr1min_ago", 2, "1 час 1 минуту назад") + self.ckDefaultToTime("1hr2min_ago", 2, "1 час 2 минуты назад") + self.ckDefaultToTime("10hr_ago", 2, "10 часов 10 минут назад") + self.ckDefaultToTime("1day_ago", 2, "вчера") + self.ckDefaultToTime("1day1hr_ago", 2, "1 день 1 час назад") + self.ckDefaultToTime("2day_ago", 2, "позавчера") + + self.ckDefaultToTime("in_10sec", 2, "менее чем через минуту") + self.ckDefaultToTime("in_1min", 2, "через минуту") + self.ckDefaultToTime("in_10min", 2, "через 10 минут") + self.ckDefaultToTime("in_1hr", 2, "через 1 час 2 минуты") + self.ckDefaultToTime("in_10hr", 2, "через 10 часов 10 минут") + self.ckDefaultToTime("in_1day", 2, "завтра") + self.ckDefaultToTime("in_1day1hr", 2, "через 1 день 1 час") + self.ckDefaultToTime("in_2day", 2, "послезавтра") def testDOTIWDefaultToTimeAcc3(self): """ Unit-tests for distance_of_time_in_words with default to_time and accuracy=3 """ # accuracy = 3 - self.ckDefaultToTime("10sec_ago", 3, u"менее минуты назад") - self.ckDefaultToTime("1min_ago", 3, u"минуту назад") - self.ckDefaultToTime("10min_ago", 3, u"10 минут назад") - self.ckDefaultToTime("59min_ago", 3, u"59 минут назад") - self.ckDefaultToTime("59min59sec_ago", 3, u"59 минут назад") - self.ckDefaultToTime("1hr_ago", 3, u"час назад") - self.ckDefaultToTime("1hr1sec_ago", 3, u"час назад") - self.ckDefaultToTime("1hr59sec_ago", 3, u"час назад") - self.ckDefaultToTime("1hr1min_ago", 3, u"1 час 1 минуту назад") - self.ckDefaultToTime("1hr2min_ago", 3, u"1 час 2 минуты назад") - self.ckDefaultToTime("10hr_ago", 3, u"10 часов 10 минут назад") + self.ckDefaultToTime("10sec_ago", 3, "менее минуты назад") + self.ckDefaultToTime("1min_ago", 3, "минуту назад") + self.ckDefaultToTime("10min_ago", 3, "10 минут назад") + self.ckDefaultToTime("59min_ago", 3, "59 минут назад") + self.ckDefaultToTime("59min59sec_ago", 3, "59 минут назад") + self.ckDefaultToTime("1hr_ago", 3, "час назад") + self.ckDefaultToTime("1hr1sec_ago", 3, "час назад") + self.ckDefaultToTime("1hr59sec_ago", 3, "час назад") + self.ckDefaultToTime("1hr1min_ago", 3, "1 час 1 минуту назад") + self.ckDefaultToTime("1hr2min_ago", 3, "1 час 2 минуты назад") + self.ckDefaultToTime("10hr_ago", 3, "10 часов 10 минут назад") self.ckDefaultToTime("1day_ago", 3, - u"1 день 0 часов 20 минут назад") + "1 день 0 часов 20 минут назад") self.ckDefaultToTime("1day1hr_ago", 3, - u"1 день 1 час 10 минут назад") + "1 день 1 час 10 минут назад") self.ckDefaultToTime("2day_ago", 3, - u"2 дня 0 часов 40 минут назад") + "2 дня 0 часов 40 минут назад") - self.ckDefaultToTime("in_10sec", 3, u"менее чем через минуту") - self.ckDefaultToTime("in_1min", 3, u"через минуту") - self.ckDefaultToTime("in_10min", 3, u"через 10 минут") - self.ckDefaultToTime("in_1hr", 3, u"через 1 час 2 минуты") - self.ckDefaultToTime("in_10hr", 3, u"через 10 часов 10 минут") + self.ckDefaultToTime("in_10sec", 3, "менее чем через минуту") + self.ckDefaultToTime("in_1min", 3, "через минуту") + self.ckDefaultToTime("in_10min", 3, "через 10 минут") + self.ckDefaultToTime("in_1hr", 3, "через 1 час 2 минуты") + self.ckDefaultToTime("in_10hr", 3, "через 10 часов 10 минут") self.ckDefaultToTime("in_1day", 3, - u"через 1 день 0 часов 20 минут") + "через 1 день 0 часов 20 минут") self.ckDefaultToTime("in_1day1hr", 3, - u"через 1 день 1 час 10 минут") + "через 1 день 1 час 10 минут") self.ckDefaultToTime("in_2day", 3, - u"через 2 дня 0 часов 40 минут") + "через 2 дня 0 часов 40 минут") def testDOTWDatetimeType(self): """ @@ -260,11 +261,11 @@ def testDOTWDatetimeType(self): """ first_time = datetime.datetime.now() second_time = first_time + datetime.timedelta(0, 1000) - self.assertEquals(pytils.dt.distance_of_time_in_words( + self.assertEqual(pytils.dt.distance_of_time_in_words( from_time=first_time, accuracy=1, to_time=second_time), - u"16 минут назад") + "16 минут назад") def testDOTIWExceptions(self): """ @@ -277,16 +278,16 @@ def testIssue25DaysFixed(self): Unit-test for testing that Issue#25 is fixed (err when accuracy==1, days<>0, hours==1) """ d_days = datetime.datetime.now() - datetime.timedelta(13, 3620) - self.assertEquals(pytils.dt.distance_of_time_in_words(d_days), - u"13 дней назад") + self.assertEqual(pytils.dt.distance_of_time_in_words(d_days), + "13 дней назад") def testIssue25HoursFixed(self): """ Unit-test for testing that Issue#25 is fixed (err when accuracy==1, hours<>0, minutes==1) """ d_hours = datetime.datetime.now() - datetime.timedelta(0, 46865) - self.assertEquals(pytils.dt.distance_of_time_in_words(d_hours), - u"13 часов назад") + self.assertEqual(pytils.dt.distance_of_time_in_words(d_hours), + "13 часов назад") class RuStrftimeTestCase(unittest.TestCase): @@ -307,7 +308,7 @@ def ck(self, format, estimates, date=None): if date is None: date = self.date res = pytils.dt.ru_strftime(format, date) - self.assertEquals(res, estimates) + self.assertEqual(res, estimates) def ckInflected(self, format, estimates, date=None): """ @@ -316,7 +317,7 @@ def ckInflected(self, format, estimates, date=None): if date is None: date = self.date res = pytils.dt.ru_strftime(format, date, True) - self.assertEquals(res, estimates) + self.assertEqual(res, estimates) def ckInflectedDay(self, format, estimates, date=None): """ @@ -325,7 +326,7 @@ def ckInflectedDay(self, format, estimates, date=None): if date is None: date = self.date res = pytils.dt.ru_strftime(format, date, inflected_day=True) - self.assertEquals(res, estimates) + self.assertEqual(res, estimates) def ckPreposition(self, format, estimates, date=None): """ @@ -334,28 +335,28 @@ def ckPreposition(self, format, estimates, date=None): if date is None: date = self.date res = pytils.dt.ru_strftime(format, date, preposition=True) - self.assertEquals(res, estimates) + self.assertEqual(res, estimates) def testRuStrftime(self): """ Unit-tests for pytils.dt.ru_strftime """ - self.ck(u"тест %a", u"тест пт") - self.ck(u"тест %A", u"тест пятница") - self.ck(u"тест %b", u"тест авг") - self.ck(u"тест %B", u"тест август") - self.ckInflected(u"тест %B", u"тест августа") - self.ckInflected(u"тест выполнен %d %B %Y года", - u"тест выполнен 25 августа 2006 года") - self.ckInflectedDay(u"тест выполнен в %A", u"тест выполнен в пятницу") + self.ck("тест %a", "тест пт") + self.ck("тест %A", "тест пятница") + self.ck("тест %b", "тест авг") + self.ck("тест %B", "тест август") + self.ckInflected("тест %B", "тест августа") + self.ckInflected("тест выполнен %d %B %Y года", + "тест выполнен 25 августа 2006 года") + self.ckInflectedDay("тест выполнен в %A", "тест выполнен в пятницу") def testRuStrftimeWithPreposition(self): """ Unit-tests for pytils.dt.ru_strftime with preposition option """ - self.ckPreposition(u"тест %a", u"тест в\xa0пт") - self.ckPreposition(u"тест %A", u"тест в\xa0пятницу") - self.ckPreposition(u"тест %A", u"тест во\xa0вторник", datetime.date(2007, 6, 5)) + self.ckPreposition("тест %a", "тест в\xa0пт") + self.ckPreposition("тест %A", "тест в\xa0пятницу") + self.ckPreposition("тест %A", "тест во\xa0вторник", datetime.date(2007, 6, 5)) def testRuStrftimeZeros(self): """ @@ -363,17 +364,17 @@ def testRuStrftimeZeros(self): It means, 1 April 2007, but 01.04.2007 """ - self.ck(u"%d.%m.%Y", u"01.04.2007", datetime.date(2007, 4, 1)) - self.ckInflected(u"%d %B %Y", u"1 апреля 2007", datetime.date(2007, 4, 1)) + self.ck("%d.%m.%Y", "01.04.2007", datetime.date(2007, 4, 1)) + self.ckInflected("%d %B %Y", "1 апреля 2007", datetime.date(2007, 4, 1)) def testIssue20Fixed(self): """ Unit-test for testing that Issue#20 is fixed (typo) """ - self.assertEquals(u"воскресенье", + self.assertEqual("воскресенье", pytils.dt.ru_strftime( - u"%A", + "%A", datetime.date(2007,3,18), inflected_day=True) ) diff --git a/pytils/test/test_numeral.py b/pytils/test/test_numeral.py index 67f471b..6d522f0 100644 --- a/pytils/test/test_numeral.py +++ b/pytils/test/test_numeral.py @@ -3,6 +3,7 @@ Unit-tests for pytils.numeral """ +from __future__ import unicode_literals import unittest import decimal import pytils @@ -24,51 +25,51 @@ def setUp(self): """ Setting up environment for tests """ - self.variants = (u"гвоздь", u"гвоздя", u"гвоздей") + self.variants = ("гвоздь", "гвоздя", "гвоздей") def checkChoosePlural(self, amount, estimated): """ Checks choose_plural """ - self.assertEquals(pytils.numeral.choose_plural(amount, self.variants), + self.assertEqual(pytils.numeral.choose_plural(amount, self.variants), estimated) def testChoosePlural(self): """ Unit-test for choose_plural """ - self.checkChoosePlural(1, u"гвоздь") - self.checkChoosePlural(2, u"гвоздя") - self.checkChoosePlural(3, u"гвоздя") - self.checkChoosePlural(5, u"гвоздей") - self.checkChoosePlural(11, u"гвоздей") - self.checkChoosePlural(109, u"гвоздей") - self.checkChoosePlural(long(109), u"гвоздей") + self.checkChoosePlural(1, "гвоздь") + self.checkChoosePlural(2, "гвоздя") + self.checkChoosePlural(3, "гвоздя") + self.checkChoosePlural(5, "гвоздей") + self.checkChoosePlural(11, "гвоздей") + self.checkChoosePlural(109, "гвоздей") + self.checkChoosePlural(long(109), "гвоздей") def testChoosePluralNegativeBug9(self): """ Test handling of negative numbers """ - self.checkChoosePlural(-5, u"гвоздей") - self.checkChoosePlural(-2, u"гвоздя") + self.checkChoosePlural(-5, "гвоздей") + self.checkChoosePlural(-2, "гвоздя") def testChoosePluralExceptions(self): """ Unit-test for testing choos_plural's exceptions """ self.assertRaises(ValueError, pytils.numeral.choose_plural, - 25, u"any,bene") + 25, "any,bene") def testChoosePluralVariantsInStr(self): """ Tests new-style variants """ - self.assertEquals( - pytils.numeral.choose_plural(1,u"гвоздь,гвоздя, гвоздей"), - u"гвоздь") - self.assertEquals( - pytils.numeral.choose_plural(5,u"гвоздь, гвоздя, гвоздей\, шпунтов"), - u"гвоздей, шпунтов") + self.assertEqual( + pytils.numeral.choose_plural(1,"гвоздь,гвоздя, гвоздей"), + "гвоздь") + self.assertEqual( + pytils.numeral.choose_plural(5,"гвоздь, гвоздя, гвоздей\, шпунтов"), + "гвоздей, шпунтов") class GetPluralTestCase(unittest.TestCase): """ @@ -78,42 +79,42 @@ def testGetPlural(self): """ Test regular get_plural """ - self.assertEquals( - pytils.numeral.get_plural(1, u"комментарий, комментария, комментариев"), - u"1 комментарий") - self.assertEquals( - pytils.numeral.get_plural(0, u"комментарий, комментария, комментариев"), - u"0 комментариев") + self.assertEqual( + pytils.numeral.get_plural(1, "комментарий, комментария, комментариев"), + "1 комментарий") + self.assertEqual( + pytils.numeral.get_plural(0, "комментарий, комментария, комментариев"), + "0 комментариев") def testGetPluralAbsence(self): """ Test get_plural with absence """ - self.assertEquals( - pytils.numeral.get_plural(1, u"комментарий, комментария, комментариев", - u"без комментариев"), - u"1 комментарий") - self.assertEquals( - pytils.numeral.get_plural(0, u"комментарий, комментария, комментариев", - u"без комментариев"), - u"без комментариев") + self.assertEqual( + pytils.numeral.get_plural(1, "комментарий, комментария, комментариев", + "без комментариев"), + "1 комментарий") + self.assertEqual( + pytils.numeral.get_plural(0, "комментарий, комментария, комментариев", + "без комментариев"), + "без комментариев") def testGetPluralLegacy(self): """ Test _get_plural_legacy """ - self.assertEquals( - pytils.numeral._get_plural_legacy(1, u"комментарий, комментария, комментариев"), - u"1 комментарий") - self.assertEquals( - pytils.numeral._get_plural_legacy(0, u"комментарий, комментария, комментариев"), - u"0 комментариев") - self.assertEquals( - pytils.numeral._get_plural_legacy(1, u"комментарий, комментария, комментариев, без комментариев"), - u"1 комментарий") - self.assertEquals( - pytils.numeral._get_plural_legacy(0, u"комментарий, комментария, комментариев, без комментариев"), - u"без комментариев") + self.assertEqual( + pytils.numeral._get_plural_legacy(1, "комментарий, комментария, комментариев"), + "1 комментарий") + self.assertEqual( + pytils.numeral._get_plural_legacy(0, "комментарий, комментария, комментариев"), + "0 комментариев") + self.assertEqual( + pytils.numeral._get_plural_legacy(1, "комментарий, комментария, комментариев, без комментариев"), + "1 комментарий") + self.assertEqual( + pytils.numeral._get_plural_legacy(0, "комментарий, комментария, комментариев, без комментариев"), + "без комментариев") class GetFloatRemainderTestCase(unittest.TestCase): @@ -125,17 +126,17 @@ def testFloatRemainder(self): """ Unit-test for _get_float_remainder """ - self.assertEquals(pytils.numeral._get_float_remainder(1.3), + self.assertEqual(pytils.numeral._get_float_remainder(1.3), '3') - self.assertEquals(pytils.numeral._get_float_remainder(2.35, 1), + self.assertEqual(pytils.numeral._get_float_remainder(2.35, 1), '4') - self.assertEquals(pytils.numeral._get_float_remainder(123.1234567891), + self.assertEqual(pytils.numeral._get_float_remainder(123.1234567891), '123456789') - self.assertEquals(pytils.numeral._get_float_remainder(2.353, 2), + self.assertEqual(pytils.numeral._get_float_remainder(2.353, 2), '35') - self.assertEquals(pytils.numeral._get_float_remainder(0.01), + self.assertEqual(pytils.numeral._get_float_remainder(0.01), '01') - self.assertEquals(pytils.numeral._get_float_remainder(5), + self.assertEqual(pytils.numeral._get_float_remainder(5), '0') def testFloatRemainderDecimal(self): @@ -143,17 +144,17 @@ def testFloatRemainderDecimal(self): Unit-test for _get_float_remainder with decimal type """ D = decimal.Decimal - self.assertEquals(pytils.numeral._get_float_remainder(D("1.3")), + self.assertEqual(pytils.numeral._get_float_remainder(D("1.3")), '3') - self.assertEquals(pytils.numeral._get_float_remainder(D("2.35"), 1), + self.assertEqual(pytils.numeral._get_float_remainder(D("2.35"), 1), '4') - self.assertEquals(pytils.numeral._get_float_remainder(D("123.1234567891")), + self.assertEqual(pytils.numeral._get_float_remainder(D("123.1234567891")), '123456789') - self.assertEquals(pytils.numeral._get_float_remainder(D("2.353"), 2), + self.assertEqual(pytils.numeral._get_float_remainder(D("2.353"), 2), '35') - self.assertEquals(pytils.numeral._get_float_remainder(D("0.01")), + self.assertEqual(pytils.numeral._get_float_remainder(D("0.01")), '01') - self.assertEquals(pytils.numeral._get_float_remainder(D("5")), + self.assertEqual(pytils.numeral._get_float_remainder(D("5")), '0') def testFloatRemainderExceptions(self): @@ -173,36 +174,36 @@ def testRubles(self): """ Unit-test for rubles """ - self.assertEquals(pytils.numeral.rubles(10.01), - u"десять рублей одна копейка") - self.assertEquals(pytils.numeral.rubles(10.10), - u"десять рублей десять копеек") - self.assertEquals(pytils.numeral.rubles(2.353), - u"два рубля тридцать пять копеек") - self.assertEquals(pytils.numeral.rubles(2.998), - u"три рубля") - self.assertEquals(pytils.numeral.rubles(3), - u"три рубля") - self.assertEquals(pytils.numeral.rubles(3, True), - u"три рубля ноль копеек") - self.assertEquals(pytils.numeral.rubles(long(3)), - u"три рубля") + self.assertEqual(pytils.numeral.rubles(10.01), + "десять рублей одна копейка") + self.assertEqual(pytils.numeral.rubles(10.10), + "десять рублей десять копеек") + self.assertEqual(pytils.numeral.rubles(2.353), + "два рубля тридцать пять копеек") + self.assertEqual(pytils.numeral.rubles(2.998), + "три рубля") + self.assertEqual(pytils.numeral.rubles(3), + "три рубля") + self.assertEqual(pytils.numeral.rubles(3, True), + "три рубля ноль копеек") + self.assertEqual(pytils.numeral.rubles(long(3)), + "три рубля") def testRublesDecimal(self): """ Test for rubles with decimal instead of float/integer """ D = decimal.Decimal - self.assertEquals(pytils.numeral.rubles(D("10.01")), - u"десять рублей одна копейка") - self.assertEquals(pytils.numeral.rubles(D("10.10")), - u"десять рублей десять копеек") - self.assertEquals(pytils.numeral.rubles(D("2.35")), - u"два рубля тридцать пять копеек") - self.assertEquals(pytils.numeral.rubles(D(3)), - u"три рубля") - self.assertEquals(pytils.numeral.rubles(D(3), True), - u"три рубля ноль копеек") + self.assertEqual(pytils.numeral.rubles(D("10.01")), + "десять рублей одна копейка") + self.assertEqual(pytils.numeral.rubles(D("10.10")), + "десять рублей десять копеек") + self.assertEqual(pytils.numeral.rubles(D("2.35")), + "два рубля тридцать пять копеек") + self.assertEqual(pytils.numeral.rubles(D(3)), + "три рубля") + self.assertEqual(pytils.numeral.rubles(D(3), True), + "три рубля ноль копеек") def testRublesExceptions(self): """ @@ -220,17 +221,17 @@ def testInt(self): """ Unit-test for in_words_int """ - self.assertEquals(pytils.numeral.in_words_int(0), u"ноль") - self.assertEquals(pytils.numeral.in_words_int(10), u"десять") - self.assertEquals(pytils.numeral.in_words_int(5), u"пять") - self.assertEquals(pytils.numeral.in_words_int(102), u"сто два") - self.assertEquals(pytils.numeral.in_words_int(3521), - u"три тысячи пятьсот двадцать один") - self.assertEquals(pytils.numeral.in_words_int(3500), - u"три тысячи пятьсот") - self.assertEquals(pytils.numeral.in_words_int(5231000), - u"пять миллионов двести тридцать одна тысяча") - self.assertEquals(pytils.numeral.in_words_int(long(10)), u"десять") + self.assertEqual(pytils.numeral.in_words_int(0), "ноль") + self.assertEqual(pytils.numeral.in_words_int(10), "десять") + self.assertEqual(pytils.numeral.in_words_int(5), "пять") + self.assertEqual(pytils.numeral.in_words_int(102), "сто два") + self.assertEqual(pytils.numeral.in_words_int(3521), + "три тысячи пятьсот двадцать один") + self.assertEqual(pytils.numeral.in_words_int(3500), + "три тысячи пятьсот") + self.assertEqual(pytils.numeral.in_words_int(5231000), + "пять миллионов двести тридцать одна тысяча") + self.assertEqual(pytils.numeral.in_words_int(long(10)), "десять") def testIntExceptions(self): """ @@ -242,31 +243,31 @@ def testFloat(self): """ Unit-test for in_words_float """ - self.assertEquals(pytils.numeral.in_words_float(10.0), - u"десять целых ноль десятых") - self.assertEquals(pytils.numeral.in_words_float(2.25), - u"две целых двадцать пять сотых") - self.assertEquals(pytils.numeral.in_words_float(0.01), - u"ноль целых одна сотая") - self.assertEquals(pytils.numeral.in_words_float(0.10), - u"ноль целых одна десятая") + self.assertEqual(pytils.numeral.in_words_float(10.0), + "десять целых ноль десятых") + self.assertEqual(pytils.numeral.in_words_float(2.25), + "две целых двадцать пять сотых") + self.assertEqual(pytils.numeral.in_words_float(0.01), + "ноль целых одна сотая") + self.assertEqual(pytils.numeral.in_words_float(0.10), + "ноль целых одна десятая") def testDecimal(self): """ Unit-test for in_words_float with decimal type """ D = decimal.Decimal - self.assertEquals(pytils.numeral.in_words_float(D("10.0")), - u"десять целых ноль десятых") - self.assertEquals(pytils.numeral.in_words_float(D("2.25")), - u"две целых двадцать пять сотых") - self.assertEquals(pytils.numeral.in_words_float(D("0.01")), - u"ноль целых одна сотая") + self.assertEqual(pytils.numeral.in_words_float(D("10.0")), + "десять целых ноль десятых") + self.assertEqual(pytils.numeral.in_words_float(D("2.25")), + "две целых двадцать пять сотых") + self.assertEqual(pytils.numeral.in_words_float(D("0.01")), + "ноль целых одна сотая") # поскольку это Decimal, то здесь нет незначащих нулей # т.е. нули определяют точность, поэтому десять сотых, # а не одна десятая - self.assertEquals(pytils.numeral.in_words_float(D("0.10")), - u"ноль целых десять сотых") + self.assertEqual(pytils.numeral.in_words_float(D("0.10")), + "ноль целых десять сотых") def testFloatExceptions(self): """ @@ -278,41 +279,41 @@ def testWithGenderOldStyle(self): """ Unit-test for in_words_float with gender (old-style, i.e. ints) """ - self.assertEquals(pytils.numeral.in_words(21, 1), - u"двадцать один") - self.assertEquals(pytils.numeral.in_words(21, 2), - u"двадцать одна") - self.assertEquals(pytils.numeral.in_words(21, 3), - u"двадцать одно") + self.assertEqual(pytils.numeral.in_words(21, 1), + "двадцать один") + self.assertEqual(pytils.numeral.in_words(21, 2), + "двадцать одна") + self.assertEqual(pytils.numeral.in_words(21, 3), + "двадцать одно") # на дробные пол не должен влиять - всегда в женском роде - self.assertEquals(pytils.numeral.in_words(21.0, 1), - u"двадцать одна целая ноль десятых") - self.assertEquals(pytils.numeral.in_words(21.0, 2), - u"двадцать одна целая ноль десятых") - self.assertEquals(pytils.numeral.in_words(21.0, 3), - u"двадцать одна целая ноль десятых") - self.assertEquals(pytils.numeral.in_words(long(21), 1), - u"двадцать один") + self.assertEqual(pytils.numeral.in_words(21.0, 1), + "двадцать одна целая ноль десятых") + self.assertEqual(pytils.numeral.in_words(21.0, 2), + "двадцать одна целая ноль десятых") + self.assertEqual(pytils.numeral.in_words(21.0, 3), + "двадцать одна целая ноль десятых") + self.assertEqual(pytils.numeral.in_words(long(21), 1), + "двадцать один") def testWithGender(self): """ Unit-test for in_words_float with gender (old-style, i.e. ints) """ - self.assertEquals(pytils.numeral.in_words(21, pytils.numeral.MALE), - u"двадцать один") - self.assertEquals(pytils.numeral.in_words(21, pytils.numeral.FEMALE), - u"двадцать одна") - self.assertEquals(pytils.numeral.in_words(21, pytils.numeral.NEUTER), - u"двадцать одно") + self.assertEqual(pytils.numeral.in_words(21, pytils.numeral.MALE), + "двадцать один") + self.assertEqual(pytils.numeral.in_words(21, pytils.numeral.FEMALE), + "двадцать одна") + self.assertEqual(pytils.numeral.in_words(21, pytils.numeral.NEUTER), + "двадцать одно") # на дробные пол не должен влиять - всегда в женском роде - self.assertEquals(pytils.numeral.in_words(21.0, pytils.numeral.MALE), - u"двадцать одна целая ноль десятых") - self.assertEquals(pytils.numeral.in_words(21.0, pytils.numeral.FEMALE), - u"двадцать одна целая ноль десятых") - self.assertEquals(pytils.numeral.in_words(21.0, pytils.numeral.NEUTER), - u"двадцать одна целая ноль десятых") - self.assertEquals(pytils.numeral.in_words(long(21), pytils.numeral.MALE), - u"двадцать один") + self.assertEqual(pytils.numeral.in_words(21.0, pytils.numeral.MALE), + "двадцать одна целая ноль десятых") + self.assertEqual(pytils.numeral.in_words(21.0, pytils.numeral.FEMALE), + "двадцать одна целая ноль десятых") + self.assertEqual(pytils.numeral.in_words(21.0, pytils.numeral.NEUTER), + "двадцать одна целая ноль десятых") + self.assertEqual(pytils.numeral.in_words(long(21), pytils.numeral.MALE), + "двадцать один") def testCommon(self): @@ -320,31 +321,31 @@ def testCommon(self): Unit-test for general in_words """ D = decimal.Decimal - self.assertEquals(pytils.numeral.in_words(10), u"десять") - self.assertEquals(pytils.numeral.in_words(5), u"пять") - self.assertEquals(pytils.numeral.in_words(102), u"сто два") - self.assertEquals(pytils.numeral.in_words(3521), - u"три тысячи пятьсот двадцать один") - self.assertEquals(pytils.numeral.in_words(3500), - u"три тысячи пятьсот") - self.assertEquals(pytils.numeral.in_words(5231000), - u"пять миллионов двести тридцать одна тысяча") - self.assertEquals(pytils.numeral.in_words(10.0), - u"десять целых ноль десятых") - self.assertEquals(pytils.numeral.in_words(2.25), - u"две целых двадцать пять сотых") - self.assertEquals(pytils.numeral.in_words(0.01), - u"ноль целых одна сотая") - self.assertEquals(pytils.numeral.in_words(0.10), - u"ноль целых одна десятая") - self.assertEquals(pytils.numeral.in_words(long(10)), u"десять") - self.assertEquals(pytils.numeral.in_words(D("2.25")), - u"две целых двадцать пять сотых") - self.assertEquals(pytils.numeral.in_words(D("0.01")), - u"ноль целых одна сотая") - self.assertEquals(pytils.numeral.in_words(D("0.10")), - u"ноль целых десять сотых") - self.assertEquals(pytils.numeral.in_words(D("10")), u"десять") + self.assertEqual(pytils.numeral.in_words(10), "десять") + self.assertEqual(pytils.numeral.in_words(5), "пять") + self.assertEqual(pytils.numeral.in_words(102), "сто два") + self.assertEqual(pytils.numeral.in_words(3521), + "три тысячи пятьсот двадцать один") + self.assertEqual(pytils.numeral.in_words(3500), + "три тысячи пятьсот") + self.assertEqual(pytils.numeral.in_words(5231000), + "пять миллионов двести тридцать одна тысяча") + self.assertEqual(pytils.numeral.in_words(10.0), + "десять целых ноль десятых") + self.assertEqual(pytils.numeral.in_words(2.25), + "две целых двадцать пять сотых") + self.assertEqual(pytils.numeral.in_words(0.01), + "ноль целых одна сотая") + self.assertEqual(pytils.numeral.in_words(0.10), + "ноль целых одна десятая") + self.assertEqual(pytils.numeral.in_words(long(10)), "десять") + self.assertEqual(pytils.numeral.in_words(D("2.25")), + "две целых двадцать пять сотых") + self.assertEqual(pytils.numeral.in_words(D("0.01")), + "ноль целых одна сотая") + self.assertEqual(pytils.numeral.in_words(D("0.10")), + "ноль целых десять сотых") + self.assertEqual(pytils.numeral.in_words(D("10")), "десять") def testCommonExceptions(self): """ @@ -363,14 +364,14 @@ def setUp(self): """ Setting up environment for tests """ - self.variants_male = (u"гвоздь", u"гвоздя", u"гвоздей") - self.variants_female = (u"шляпка", u"шляпки", u"шляпок") + self.variants_male = ("гвоздь", "гвоздя", "гвоздей") + self.variants_female = ("шляпка", "шляпки", "шляпок") def ckMaleOldStyle(self, amount, estimated): """ Checks sum_string with male gender with old-style genders (i.e. ints) """ - self.assertEquals(pytils.numeral.sum_string(amount, + self.assertEqual(pytils.numeral.sum_string(amount, 1, self.variants_male), estimated) @@ -379,7 +380,7 @@ def ckMale(self, amount, estimated): """ Checks sum_string with male gender """ - self.assertEquals(pytils.numeral.sum_string(amount, + self.assertEqual(pytils.numeral.sum_string(amount, pytils.numeral.MALE, self.variants_male), estimated) @@ -389,7 +390,7 @@ def ckFemaleOldStyle(self, amount, estimated): """ Checks sum_string with female gender wuth old-style genders (i.e. ints) """ - self.assertEquals(pytils.numeral.sum_string(amount, + self.assertEqual(pytils.numeral.sum_string(amount, 2, self.variants_female), estimated) @@ -398,7 +399,7 @@ def ckFemale(self, amount, estimated): """ Checks sum_string with female gender """ - self.assertEquals(pytils.numeral.sum_string(amount, + self.assertEqual(pytils.numeral.sum_string(amount, pytils.numeral.FEMALE, self.variants_female), estimated) @@ -407,40 +408,40 @@ def testSumStringOldStyleGender(self): """ Unit-test for sum_string with old-style genders """ - self.ckMaleOldStyle(10, u"десять гвоздей") - self.ckMaleOldStyle(2, u"два гвоздя") - self.ckMaleOldStyle(31, u"тридцать один гвоздь") - self.ckFemaleOldStyle(10, u"десять шляпок") - self.ckFemaleOldStyle(2, u"две шляпки") - self.ckFemaleOldStyle(31, u"тридцать одна шляпка") + self.ckMaleOldStyle(10, "десять гвоздей") + self.ckMaleOldStyle(2, "два гвоздя") + self.ckMaleOldStyle(31, "тридцать один гвоздь") + self.ckFemaleOldStyle(10, "десять шляпок") + self.ckFemaleOldStyle(2, "две шляпки") + self.ckFemaleOldStyle(31, "тридцать одна шляпка") - self.ckFemaleOldStyle(long(31), u"тридцать одна шляпка") + self.ckFemaleOldStyle(long(31), "тридцать одна шляпка") - self.assertEquals(u"одиннадцать негритят", + self.assertEqual("одиннадцать негритят", pytils.numeral.sum_string( 11, 1, - u"негритенок,негритенка,негритят" + "негритенок,негритенка,негритят" )) def testSumString(self): """ Unit-test for sum_string """ - self.ckMale(10, u"десять гвоздей") - self.ckMale(2, u"два гвоздя") - self.ckMale(31, u"тридцать один гвоздь") - self.ckFemale(10, u"десять шляпок") - self.ckFemale(2, u"две шляпки") - self.ckFemale(31, u"тридцать одна шляпка") + self.ckMale(10, "десять гвоздей") + self.ckMale(2, "два гвоздя") + self.ckMale(31, "тридцать один гвоздь") + self.ckFemale(10, "десять шляпок") + self.ckFemale(2, "две шляпки") + self.ckFemale(31, "тридцать одна шляпка") - self.ckFemale(long(31), u"тридцать одна шляпка") + self.ckFemale(long(31), "тридцать одна шляпка") - self.assertEquals(u"одиннадцать негритят", + self.assertEqual("одиннадцать негритят", pytils.numeral.sum_string( 11, pytils.numeral.MALE, - u"негритенок,негритенка,негритят" + "негритенок,негритенка,негритят" )) def testSumStringExceptions(self): @@ -448,7 +449,7 @@ def testSumStringExceptions(self): Unit-test for testing sum_string's exceptions """ self.assertRaises(ValueError, pytils.numeral.sum_string, - -1, pytils.numeral.MALE, u"any,bene,raba") + -1, pytils.numeral.MALE, "any,bene,raba") if __name__ == '__main__': unittest.main() diff --git a/pytils/test/test_translit.py b/pytils/test/test_translit.py index b83d7b0..0f9cbc2 100644 --- a/pytils/test/test_translit.py +++ b/pytils/test/test_translit.py @@ -3,6 +3,7 @@ Unit-tests for pytils.translit """ +from __future__ import unicode_literals import unittest import pytils from pytils.third import six @@ -16,45 +17,45 @@ def ckTransl(self, in_, out_): """ Checks translify """ - self.assertEquals(pytils.translit.translify(in_), out_) + self.assertEqual(pytils.translit.translify(in_), out_) def ckDetransl(self, in_, out_): """ Checks detranslify """ - self.assertEquals(pytils.translit.detranslify(in_), out_) + self.assertEqual(pytils.translit.detranslify(in_), out_) def ckSlug(self, in_, out_): """ Checks slugify """ - self.assertEquals(pytils.translit.slugify(in_), out_) + self.assertEqual(pytils.translit.slugify(in_), out_) def testTransliteration(self): """ Unit-test for transliterations """ - self.ckTransl(u"тест", 'test') - self.ckTransl(u"проверка", 'proverka') - self.ckTransl(u"транслит", 'translit') - self.ckTransl(u"правда ли это", 'pravda li eto') - self.ckTransl(u"Щука", 'Schuka') + self.ckTransl("тест", 'test') + self.ckTransl("проверка", 'proverka') + self.ckTransl("транслит", 'translit') + self.ckTransl("правда ли это", 'pravda li eto') + self.ckTransl("Щука", 'Schuka') def testTransliterationExceptions(self): """ Unit-test for testing translify's exceptions """ - self.assertRaises(ValueError, pytils.translit.translify, u'\u00bfHabla espa\u00f1ol?') + self.assertRaises(ValueError, pytils.translit.translify, '\u00bfHabla espa\u00f1ol?') def testDetransliteration(self): """ Unit-test for detransliterations """ - self.ckDetransl('test', u"тест") - self.ckDetransl('proverka', u"проверка") - self.ckDetransl('translit', u"транслит") - self.ckDetransl('SCHuka', u"Щука") - self.ckDetransl('Schuka', u"Щука") + self.ckDetransl('test', "тест") + self.ckDetransl('proverka', "проверка") + self.ckDetransl('translit', "транслит") + self.ckDetransl('SCHuka', "Щука") + self.ckDetransl('Schuka', "Щука") def testDetransliterationExceptions(self): """ @@ -62,16 +63,16 @@ def testDetransliterationExceptions(self): """ # for Python 2.x non-unicode detranslify should raise exception if six.PY2: - self.assertRaises(ValueError, pytils.translit.detranslify, "тест") + self.assertRaises(ValueError, pytils.translit.detranslify, "тест".encode('utf8')) def testSlug(self): """ Unit-test for slugs """ - self.ckSlug(u"ТеСт", 'test') - self.ckSlug(u"Проверка связи", 'proverka-svyazi') - self.ckSlug(u"me&you", 'me-and-you') - self.ckSlug(u"и еще один тест", 'i-esche-odin-test') + self.ckSlug("ТеСт", 'test') + self.ckSlug("Проверка связи", 'proverka-svyazi') + self.ckSlug("me&you", 'me-and-you') + self.ckSlug("и еще один тест", 'i-esche-odin-test') def testSlugExceptions(self): """ @@ -79,39 +80,39 @@ def testSlugExceptions(self): """ # for Python 2.x non-unicode slugify should raise exception if six.PY2: - self.assertRaises(ValueError, pytils.translit.slugify, "тест") + self.assertRaises(ValueError, pytils.translit.slugify, "тест".encode('utf8')) def testTranslifyAdditionalUnicodeSymbols(self): """ Unit-test for testing additional unicode symbols """ - self.ckTransl(u"«Вот так вот»", '"Vot tak vot"') - self.ckTransl(u"‘Или вот так’", "'Ili vot tak'") - self.ckTransl(u"– Да…", "- Da...") + self.ckTransl("«Вот так вот»", '"Vot tak vot"') + self.ckTransl("‘Или вот так’", "'Ili vot tak'") + self.ckTransl("– Да…", "- Da...") def testSlugifyIssue10(self): """ Unit-test for testing that bug#10 fixed """ - self.ckSlug(u"Проверка связи…", 'proverka-svyazi') - self.ckSlug(u"Проверка\x0aсвязи 2", 'proverka-svyazi-2') - self.ckSlug(u"Проверка\201связи 3", 'proverkasvyazi-3') + self.ckSlug("Проверка связи…", 'proverka-svyazi') + self.ckSlug("Проверка\x0aсвязи 2", 'proverka-svyazi-2') + self.ckSlug("Проверка\201связи 3", 'proverkasvyazi-3') def testSlugifyIssue15(self): """ Unit-test for testing that bug#15 fixed """ - self.ckSlug(u"World of Warcraft", "world-of-warcraft") + self.ckSlug("World of Warcraft", "world-of-warcraft") def testAdditionalDashesAndQuotes(self): """ Unit-test for testing additional dashes (figure and em-dash) and quotes """ - self.ckSlug(u"Юнит-тесты — наше всё", 'yunit-testyi---nashe-vsyo') - self.ckSlug(u"Юнит-тесты ‒ наше всё", 'yunit-testyi---nashe-vsyo') - self.ckSlug(u"95−34", '95-34') - self.ckTransl(u"Двигатель “Pratt&Whitney”", 'Dvigatel\' "Pratt&Whitney"') + self.ckSlug("Юнит-тесты — наше всё", 'yunit-testyi---nashe-vsyo') + self.ckSlug("Юнит-тесты ‒ наше всё", 'yunit-testyi---nashe-vsyo') + self.ckSlug("95−34", '95-34') + self.ckTransl("Двигатель “Pratt&Whitney”", 'Dvigatel\' "Pratt&Whitney"') if __name__ == '__main__': unittest.main() diff --git a/pytils/test/test_typo.py b/pytils/test/test_typo.py index 0235b42..7650f0c 100644 --- a/pytils/test/test_typo.py +++ b/pytils/test/test_typo.py @@ -3,13 +3,17 @@ Unit-tests for pytils.typo """ +from __future__ import unicode_literals import unittest import os from pytils import typo +import collections + def cb_testrule(x): return x + class HelpersTestCase(unittest.TestCase): """ Test case for pytils.typo helpers @@ -18,11 +22,10 @@ def testGetRuleByName(self): """ unit-test for pytils.typo._get_rule_by_name """ - self.assert_( - callable( - typo._get_rule_by_name('testrule') - )) - self.assertEquals( + self.assertTrue( + isinstance( + typo._get_rule_by_name('testrule'), collections.Callable)) + self.assertEqual( 'rl_testrule', typo._get_rule_by_name('testrule').__name__ ) @@ -31,19 +34,17 @@ def testResolveRule(self): """ unit-test for pytils.typo._resolve_rule """ - self.assert_( - callable( - typo._resolve_rule_name('testrule')[1] - )) - self.assert_( - callable( - typo._resolve_rule_name(cb_testrule)[1] - )) - self.assertEquals( + self.assertTrue( + isinstance( + typo._resolve_rule_name('testrule')[1], collections.Callable)) + self.assertTrue( + isinstance( + typo._resolve_rule_name(cb_testrule)[1], collections.Callable)) + self.assertEqual( 'testrule', typo._resolve_rule_name('testrule')[0] ) - self.assertEquals( + self.assertEqual( 'cb_testrule', typo._resolve_rule_name(cb_testrule)[0] ) @@ -52,17 +53,15 @@ def testResolveRuleWithForcedName(self): """ unit-test for pytils.typo._resolve_rule with forced_name arg """ - self.assert_( - callable(typo._resolve_rule_name('testrule', 'newrule')[1] - )) - self.assert_( - callable(typo._resolve_rule_name(cb_testrule, 'newrule')[1] - )) - self.assertEquals( + self.assertTrue( + isinstance(typo._resolve_rule_name('testrule', 'newrule')[1], collections.Callable)) + self.assertTrue( + isinstance(typo._resolve_rule_name(cb_testrule, 'newrule')[1], collections.Callable)) + self.assertEqual( 'newrule', typo._resolve_rule_name('testrule', 'newrule')[0] ) - self.assertEquals( + self.assertEqual( 'newrule', typo._resolve_rule_name(cb_testrule, 'newrule')[0] ) @@ -72,88 +71,88 @@ class TypographyApplierTestCase(unittest.TestCase): Test case for typography rule applier pytils.typo.Typography """ def testExpandEmptyArgs(self): - self.assertEquals( + self.assertEqual( {}, typo.Typography().rules ) - self.assertEquals( + self.assertEqual( [], typo.Typography().rules_names ) def testExpandSimpleStrArgs(self): - self.assertEquals( + self.assertEqual( {'testrule': typo.rl_testrule}, typo.Typography('testrule').rules ) - self.assertEquals( + self.assertEqual( ['testrule'], typo.Typography('testrule').rules_names ) def testExpandDictStrArgs(self): - self.assertEquals( + self.assertEqual( { 'testrule': typo.rl_testrule, 'newrule': typo.rl_testrule }, typo.Typography('testrule', {'newrule': 'testrule'}).rules ) - self.assertEquals( + self.assertEqual( ['testrule', 'newrule'], typo.Typography('testrule', {'newrule': 'testrule'}).rules_names ) def testExpandSimpleCallableArgs(self): - self.assertEquals( + self.assertEqual( {'cb_testrule': cb_testrule}, typo.Typography(cb_testrule).rules ) - self.assertEquals( + self.assertEqual( ['cb_testrule'], typo.Typography(cb_testrule).rules_names ) def testExpandDictCallableArgs(self): - self.assertEquals( + self.assertEqual( { 'cb_testrule': cb_testrule, 'newrule': cb_testrule }, typo.Typography(cb_testrule, {'newrule': cb_testrule}).rules ) - self.assertEquals( + self.assertEqual( ['cb_testrule', 'newrule'], typo.Typography(cb_testrule, {'newrule': cb_testrule}).rules_names ) def testExpandMixedArgs(self): - self.assertEquals( + self.assertEqual( { 'cb_testrule': cb_testrule, 'newrule': typo.rl_testrule }, typo.Typography(cb_testrule, newrule='testrule').rules ) - self.assertEquals( + self.assertEqual( ['cb_testrule', 'newrule'], typo.Typography(cb_testrule, newrule='testrule').rules_names ) - self.assertEquals( + self.assertEqual( { 'cb_testrule': cb_testrule, 'testrule': typo.rl_testrule }, typo.Typography(cb_testrule, 'testrule').rules ) - self.assertEquals( + self.assertEqual( ['cb_testrule', 'testrule'], typo.Typography(cb_testrule, 'testrule').rules_names ) def testRecommendedArgsStyle(self): lambdarule = lambda x: x - self.assertEquals( + self.assertEqual( { 'cb_testrule': cb_testrule, 'testrule': typo.rl_testrule, @@ -161,7 +160,7 @@ def testRecommendedArgsStyle(self): }, typo.Typography([cb_testrule], ['testrule'], {'newrule': lambdarule}).rules ) - self.assertEquals( + self.assertEqual( ['cb_testrule', 'testrule', 'newrule'], typo.Typography([cb_testrule], ['testrule'], {'newrule': lambdarule}).rules_names ) @@ -172,7 +171,7 @@ def checkRule(self, name, input_value, expected_result): """ Check how rule is acted on input_value with expected_result """ - self.assertEquals( + self.assertEqual( expected_result, typo._get_rule_by_name(name)(input_value) ) @@ -183,28 +182,28 @@ def testCleanspaces(self): """ self.checkRule( 'cleanspaces', - u" Точка ,точка , запятая, вышла рожица кривая . ", - u"Точка, точка, запятая, вышла рожица кривая." + " Точка ,точка , запятая, вышла рожица кривая . ", + "Точка, точка, запятая, вышла рожица кривая." ) self.checkRule( 'cleanspaces', - u" Точка ,точка , %(n)sзапятая,%(n)s вышла рожица кривая . " % {'n': os.linesep}, - u"Точка, точка,%(n)sзапятая,%(n)sвышла рожица кривая." % {'n': os.linesep} + " Точка ,точка , %(n)sзапятая,%(n)s вышла рожица кривая . " % {'n': os.linesep}, + "Точка, точка,%(n)sзапятая,%(n)sвышла рожица кривая." % {'n': os.linesep} ) self.checkRule( 'cleanspaces', - u"Газета ( ее принес мальчишка утром ) всё еще лежала на столе.", - u"Газета (ее принес мальчишка утром) всё еще лежала на столе.", + "Газета ( ее принес мальчишка утром ) всё еще лежала на столе.", + "Газета (ее принес мальчишка утром) всё еще лежала на столе.", ) self.checkRule( 'cleanspaces', - u"Газета, утром принесенная мальчишкой ( это был сосед, подзарабатывающий летом ) , всё еще лежала на столе.", - u"Газета, утром принесенная мальчишкой (это был сосед, подзарабатывающий летом), всё еще лежала на столе.", + "Газета, утром принесенная мальчишкой ( это был сосед, подзарабатывающий летом ) , всё еще лежала на столе.", + "Газета, утром принесенная мальчишкой (это был сосед, подзарабатывающий летом), всё еще лежала на столе.", ) self.checkRule( 'cleanspaces', - u"Что это?!?!", - u"Что это?!?!", + "Что это?!?!", + "Что это?!?!", ) def testEllipsis(self): @@ -213,23 +212,23 @@ def testEllipsis(self): """ self.checkRule( 'ellipsis', - u"Быть или не быть, вот в чем вопрос...%(n)s%(n)sШекспир" % {'n': os.linesep}, - u"Быть или не быть, вот в чем вопрос…%(n)s%(n)sШекспир" % {'n': os.linesep} + "Быть или не быть, вот в чем вопрос...%(n)s%(n)sШекспир" % {'n': os.linesep}, + "Быть или не быть, вот в чем вопрос…%(n)s%(n)sШекспир" % {'n': os.linesep} ) self.checkRule( 'ellipsis', - u"Мдя..... могло быть лучше", - u"Мдя..... могло быть лучше" + "Мдя..... могло быть лучше", + "Мдя..... могло быть лучше" ) self.checkRule( 'ellipsis', - u"...Дааааа", - u"…Дааааа" + "...Дааааа", + "…Дааааа" ) self.checkRule( 'ellipsis', - u"... Дааааа", - u"…Дааааа" + "... Дааааа", + "…Дааааа" ) @@ -239,23 +238,23 @@ def testInitials(self): """ self.checkRule( 'initials', - u'Председатель В.И.Иванов выступил на собрании', - u'Председатель В.И.\u2009Иванов выступил на собрании', + 'Председатель В.И.Иванов выступил на собрании', + 'Председатель В.И.\u2009Иванов выступил на собрании', ) self.checkRule( 'initials', - u'Председатель В.И. Иванов выступил на собрании', - u'Председатель В.И.\u2009Иванов выступил на собрании', + 'Председатель В.И. Иванов выступил на собрании', + 'Председатель В.И.\u2009Иванов выступил на собрании', ) self.checkRule( 'initials', - u'1. В.И.Иванов%(n)s2. С.П.Васечкин'% {'n': os.linesep}, - u'1. В.И.\u2009Иванов%(n)s2. С.П.\u2009Васечкин' % {'n': os.linesep} + '1. В.И.Иванов%(n)s2. С.П.Васечкин'% {'n': os.linesep}, + '1. В.И.\u2009Иванов%(n)s2. С.П.\u2009Васечкин' % {'n': os.linesep} ) self.checkRule( 'initials', - u'Комиссия в составе директора В.И.Иванова и главного бухгалтера С.П.Васечкина постановила', - u'Комиссия в составе директора В.И.\u2009Иванова и главного бухгалтера С.П.\u2009Васечкина постановила' + 'Комиссия в составе директора В.И.Иванова и главного бухгалтера С.П.Васечкина постановила', + 'Комиссия в составе директора В.И.\u2009Иванова и главного бухгалтера С.П.\u2009Васечкина постановила' ) def testDashes(self): @@ -264,28 +263,28 @@ def testDashes(self): """ self.checkRule( 'dashes', - u'- Я пошел домой... - Может останешься? - Нет, ухожу.', - u'\u2014 Я пошел домой... \u2014 Может останешься? \u2014 Нет, ухожу.' + '- Я пошел домой... - Может останешься? - Нет, ухожу.', + '\u2014 Я пошел домой... \u2014 Может останешься? \u2014 Нет, ухожу.' ) self.checkRule( 'dashes', - u'-- Я пошел домой... -- Может останешься? -- Нет, ухожу.', - u'\u2014 Я пошел домой... \u2014 Может останешься? \u2014 Нет, ухожу.' + '-- Я пошел домой... -- Может останешься? -- Нет, ухожу.', + '\u2014 Я пошел домой... \u2014 Может останешься? \u2014 Нет, ухожу.' ) self.checkRule( 'dashes', - u'-- Я\u202fпошел домой…\u202f-- Может останешься?\u202f-- Нет,\u202fухожу.', - u'\u2014 Я\u202fпошел домой…\u202f\u2014 Может останешься?\u202f\u2014 Нет,\u202fухожу.' + '-- Я\u202fпошел домой…\u202f-- Может останешься?\u202f-- Нет,\u202fухожу.', + '\u2014 Я\u202fпошел домой…\u202f\u2014 Может останешься?\u202f\u2014 Нет,\u202fухожу.' ) self.checkRule( 'dashes', - u'Ползать по-пластунски', - u'Ползать по-пластунски', + 'Ползать по-пластунски', + 'Ползать по-пластунски', ) self.checkRule( 'dashes', - u'Диапазон: 9-15', - u'Диапазон: 9\u201315', + 'Диапазон: 9-15', + 'Диапазон: 9\u201315', ) def testWordglue(self): @@ -294,33 +293,33 @@ def testWordglue(self): """ self.checkRule( 'wordglue', - u'Вроде бы он согласен', - u'Вроде\u202fбы\u202fон\u202fсогласен', + 'Вроде бы он согласен', + 'Вроде\u202fбы\u202fон\u202fсогласен', ) self.checkRule( 'wordglue', - u'Он не поверил своим глазам', - u'Он\u202fне\u202fповерил своим\u202fглазам', + 'Он не поверил своим глазам', + 'Он\u202fне\u202fповерил своим\u202fглазам', ) self.checkRule( 'wordglue', - u'Это - великий и ужасный Гудвин', - u'Это\u202f- великий и\u202fужасный\u202fГудвин', + 'Это - великий и ужасный Гудвин', + 'Это\u202f- великий и\u202fужасный\u202fГудвин', ) self.checkRule( 'wordglue', - u'Это \u2014 великий и ужасный Гудвин', - u'Это\u202f\u2014 великий и\u202fужасный\u202fГудвин', + 'Это \u2014 великий и ужасный Гудвин', + 'Это\u202f\u2014 великий и\u202fужасный\u202fГудвин', ) self.checkRule( 'wordglue', - u'-- Я пошел домой… -- Может останешься? -- Нет, ухожу.', - u'-- Я\u202fпошел домой…\u202f-- Может останешься?\u202f-- Нет,\u202fухожу.' + '-- Я пошел домой… -- Может останешься? -- Нет, ухожу.', + '-- Я\u202fпошел домой…\u202f-- Может останешься?\u202f-- Нет,\u202fухожу.' ) self.checkRule( 'wordglue', - u'увидел в газете (это была "Сермяжная правда" № 45) рубрику Weather Forecast', - u'увидел в\u202fгазете (это\u202fбыла "Сермяжная правда" № 45) рубрику Weather\u202fForecast', + 'увидел в газете (это была "Сермяжная правда" № 45) рубрику Weather Forecast', + 'увидел в\u202fгазете (это\u202fбыла "Сермяжная правда" № 45) рубрику Weather\u202fForecast', ) @@ -330,43 +329,43 @@ def testMarks(self): """ self.checkRule( 'marks', - u"Когда В. И. Пупкин увидел в газете рубрику Weather Forecast(r), он не поверил своим глазам \u2014 температуру обещали +-451F.", - u"Когда В. И. Пупкин увидел в газете рубрику Weather Forecast®, он не поверил своим глазам \u2014 температуру обещали ±451\u202f°F." + "Когда В. И. Пупкин увидел в газете рубрику Weather Forecast(r), он не поверил своим глазам \u2014 температуру обещали +-451F.", + "Когда В. И. Пупкин увидел в газете рубрику Weather Forecast®, он не поверил своим глазам \u2014 температуру обещали ±451\u202f°F." ) self.checkRule( 'marks', - u"14 Foo", - u"14 Foo" + "14 Foo", + "14 Foo" ) self.checkRule( 'marks', - u"Coca-cola(tm)", - u"Coca-cola™" + "Coca-cola(tm)", + "Coca-cola™" ) self.checkRule( 'marks', - u'(c) 2008 Юрий Юревич', - u'©\u202f2008 Юрий Юревич' + '(c) 2008 Юрий Юревич', + '©\u202f2008 Юрий Юревич' ) self.checkRule( 'marks', - u"Microsoft (R) Windows (tm)", - u"Microsoft® Windows™" + "Microsoft (R) Windows (tm)", + "Microsoft® Windows™" ) self.checkRule( 'marks', - u"Школа-гимназия No 3", - u"Школа-гимназия №\u20093", + "Школа-гимназия No 3", + "Школа-гимназия №\u20093", ) self.checkRule( 'marks', - u"Школа-гимназия No3", - u"Школа-гимназия №\u20093", + "Школа-гимназия No3", + "Школа-гимназия №\u20093", ) self.checkRule( 'marks', - u"Школа-гимназия №3", - u"Школа-гимназия №\u20093", + "Школа-гимназия №3", + "Школа-гимназия №\u20093", ) def testQuotes(self): @@ -375,28 +374,28 @@ def testQuotes(self): """ self.checkRule( 'quotes', - u"ООО \"МСК \"Аско-Забота\"", - u"ООО «МСК «Аско-Забота»" + "ООО \"МСК \"Аско-Забота\"", + "ООО «МСК «Аско-Забота»" ) self.checkRule( 'quotes', - u"ООО\u202f\"МСК\u202f\"Аско-Забота\"", - u"ООО\u202f«МСК\u202f«Аско-Забота»" + "ООО\u202f\"МСК\u202f\"Аско-Забота\"", + "ООО\u202f«МСК\u202f«Аско-Забота»" ) self.checkRule( 'quotes', - u"Двигатели 'Pratt&Whitney'", - u"Двигатели “Pratt&Whitney”" + "Двигатели 'Pratt&Whitney'", + "Двигатели “Pratt&Whitney”" ) self.checkRule( 'quotes', - u"\"Вложенные \"кавычки\" - бич всех типографик\", не правда ли", - u"«Вложенные «кавычки» - бич всех типографик», не правда ли", + "\"Вложенные \"кавычки\" - бич всех типографик\", не правда ли", + "«Вложенные «кавычки» - бич всех типографик», не правда ли", ) self.checkRule( 'quotes', - u"Двигатели 'Pratt&Whitney' никогда не использовались на самолетах \"Аэрофлота\"", - u"Двигатели “Pratt&Whitney” никогда не использовались на самолетах «Аэрофлота»" + "Двигатели 'Pratt&Whitney' никогда не использовались на самолетах \"Аэрофлота\"", + "Двигатели “Pratt&Whitney” никогда не использовались на самолетах «Аэрофлота»" ) class TypographyTestCase(unittest.TestCase): @@ -407,15 +406,15 @@ def checkTypo(self, input_value, expected_value): """ Helper for checking typo.typography """ - self.assertEquals(expected_value, typo.typography(input_value)) + self.assertEqual(expected_value, typo.typography(input_value)) def testPupkin(self): """ Unit-test on pupkin-text """ self.checkTypo( - u"""...Когда В. И. Пупкин увидел в газете ( это была "Сермяжная правда" № 45) рубрику Weather Forecast(r), он не поверил своим глазам - температуру обещали +-451F.""", - u"""…Когда В.И.\u2009Пупкин увидел в\u202fгазете (это\u202fбыла «Сермяжная правда» №\u200945) рубрику Weather Forecast®, он\u202fне\u202fповерил своим глазам\u202f\u2014 температуру обещали ±451\u202f°F.""") + """...Когда В. И. Пупкин увидел в газете ( это была "Сермяжная правда" № 45) рубрику Weather Forecast(r), он не поверил своим глазам - температуру обещали +-451F.""", + """…Когда В.И.\u2009Пупкин увидел в\u202fгазете (это\u202fбыла «Сермяжная правда» №\u200945) рубрику Weather Forecast®, он\u202fне\u202fповерил своим глазам\u202f\u2014 температуру обещали ±451\u202f°F.""") if __name__ == '__main__': unittest.main() diff --git a/pytils/test/test_utils.py b/pytils/test/test_utils.py index 8efb9c6..253b56a 100644 --- a/pytils/test/test_utils.py +++ b/pytils/test/test_utils.py @@ -3,6 +3,7 @@ Unit-tests for pytils.utils """ +from __future__ import unicode_literals import unittest import pytils import decimal @@ -18,7 +19,7 @@ def testCheckLength(self): """ Unit-test for pytils.utils.check_length """ - self.assertEquals(pytils.utils.check_length("var", 3), None) + self.assertEqual(pytils.utils.check_length("var", 3), None) self.assertRaises(ValueError, pytils.utils.check_length, "var", 4) self.assertRaises(ValueError, pytils.utils.check_length, "var", 2) @@ -28,14 +29,14 @@ def testCheckPositive(self): """ Unit-test for pytils.utils.check_positive """ - self.assertEquals(pytils.utils.check_positive(0), None) - self.assertEquals(pytils.utils.check_positive(1), None) - self.assertEquals(pytils.utils.check_positive(1, False), None) - self.assertEquals(pytils.utils.check_positive(1, strict=False), None) - self.assertEquals(pytils.utils.check_positive(1, True), None) - self.assertEquals(pytils.utils.check_positive(1, strict=True), None) - self.assertEquals(pytils.utils.check_positive(decimal.Decimal("2.0")), None) - self.assertEquals(pytils.utils.check_positive(2.0), None) + self.assertEqual(pytils.utils.check_positive(0), None) + self.assertEqual(pytils.utils.check_positive(1), None) + self.assertEqual(pytils.utils.check_positive(1, False), None) + self.assertEqual(pytils.utils.check_positive(1, strict=False), None) + self.assertEqual(pytils.utils.check_positive(1, True), None) + self.assertEqual(pytils.utils.check_positive(1, strict=True), None) + self.assertEqual(pytils.utils.check_positive(decimal.Decimal("2.0")), None) + self.assertEqual(pytils.utils.check_positive(2.0), None) self.assertRaises(ValueError, pytils.utils.check_positive, -2) self.assertRaises(ValueError, pytils.utils.check_positive, -2.0) @@ -49,17 +50,17 @@ def testClassicSplit(self): """ Unit-test for pytils.utils.split_values, classic split """ - self.assertEquals((u"Раз", u"Два", u"Три"), pytils.utils.split_values(u"Раз,Два,Три")) - self.assertEquals((u"Раз", u"Два", u"Три"), pytils.utils.split_values(u"Раз, Два,Три")) - self.assertEquals((u"Раз", u"Два", u"Три"), pytils.utils.split_values(u" Раз, Два, Три ")) - self.assertEquals((u"Раз", u"Два", u"Три"), pytils.utils.split_values(u" Раз, \nДва,\n Три ")) + self.assertEqual(("Раз", "Два", "Три"), pytils.utils.split_values("Раз,Два,Три")) + self.assertEqual(("Раз", "Два", "Три"), pytils.utils.split_values("Раз, Два,Три")) + self.assertEqual(("Раз", "Два", "Три"), pytils.utils.split_values(" Раз, Два, Три ")) + self.assertEqual(("Раз", "Два", "Три"), pytils.utils.split_values(" Раз, \nДва,\n Три ")) def testEscapedSplit(self): """ Unit-test for pytils.utils.split_values, split with escaping """ - self.assertEquals((u"Раз,Два", u"Три,Четыре", u"Пять,Шесть"), pytils.utils.split_values(u"Раз\,Два,Три\,Четыре,Пять\,Шесть")) - self.assertEquals((u"Раз, Два", u"Три", u"Четыре"), pytils.utils.split_values(u"Раз\, Два, Три, Четыре")) + self.assertEqual(("Раз,Два", "Три,Четыре", "Пять,Шесть"), pytils.utils.split_values("Раз\,Два,Три\,Четыре,Пять\,Шесть")) + self.assertEqual(("Раз, Два", "Три", "Четыре"), pytils.utils.split_values("Раз\, Два, Три, Четыре")) if __name__ == '__main__': unittest.main() diff --git a/pytils/translit.py b/pytils/translit.py index a71962e..7424b04 100644 --- a/pytils/translit.py +++ b/pytils/translit.py @@ -4,128 +4,130 @@ Simple transliteration """ +from __future__ import unicode_literals + import re from pytils.third import six TRANSTABLE = ( - (u"'", u"'"), - (u'"', u'"'), - (u"‘", u"'"), - (u"’", u"'"), - (u"«", u'"'), - (u"»", u'"'), - (u"“", u'"'), - (u"”", u'"'), - (u"–", u"-"), # en dash - (u"—", u"-"), # em dash - (u"‒", u"-"), # figure dash - (u"−", u"-"), # minus - (u"…", u"..."), - (u"№", u"#"), + ("'", "'"), + ('"', '"'), + ("‘", "'"), + ("’", "'"), + ("«", '"'), + ("»", '"'), + ("“", '"'), + ("”", '"'), + ("–", "-"), # en dash + ("—", "-"), # em dash + ("‒", "-"), # figure dash + ("−", "-"), # minus + ("…", "..."), + ("№", "#"), ## upper # three-symbols replacements - (u"Щ", u"Sch"), + ("Щ", "Sch"), # on russian->english translation only first replacement will be done # i.e. Sch # but on english->russian translation both variants (Sch and SCH) will play - (u"Щ", u"SCH"), + ("Щ", "SCH"), # two-symbol replacements - (u"Ё", u"Yo"), - (u"Ё", u"YO"), - (u"Ж", u"Zh"), - (u"Ж", u"ZH"), - (u"Ц", u"Ts"), - (u"Ц", u"TS"), - (u"Ч", u"Ch"), - (u"Ч", u"CH"), - (u"Ш", u"Sh"), - (u"Ш", u"SH"), - (u"Ы", u"Yi"), - (u"Ы", u"YI"), - (u"Ю", u"Yu"), - (u"Ю", u"YU"), - (u"Я", u"Ya"), - (u"Я", u"YA"), + ("Ё", "Yo"), + ("Ё", "YO"), + ("Ж", "Zh"), + ("Ж", "ZH"), + ("Ц", "Ts"), + ("Ц", "TS"), + ("Ч", "Ch"), + ("Ч", "CH"), + ("Ш", "Sh"), + ("Ш", "SH"), + ("Ы", "Yi"), + ("Ы", "YI"), + ("Ю", "Yu"), + ("Ю", "YU"), + ("Я", "Ya"), + ("Я", "YA"), # one-symbol replacements - (u"А", u"A"), - (u"Б", u"B"), - (u"В", u"V"), - (u"Г", u"G"), - (u"Д", u"D"), - (u"Е", u"E"), - (u"З", u"Z"), - (u"И", u"I"), - (u"Й", u"J"), - (u"К", u"K"), - (u"Л", u"L"), - (u"М", u"M"), - (u"Н", u"N"), - (u"О", u"O"), - (u"П", u"P"), - (u"Р", u"R"), - (u"С", u"S"), - (u"Т", u"T"), - (u"У", u"U"), - (u"Ф", u"F"), - (u"Х", u"H"), - (u"Э", u"E"), - (u"Ъ", u"`"), - (u"Ь", u"'"), + ("А", "A"), + ("Б", "B"), + ("В", "V"), + ("Г", "G"), + ("Д", "D"), + ("Е", "E"), + ("З", "Z"), + ("И", "I"), + ("Й", "J"), + ("К", "K"), + ("Л", "L"), + ("М", "M"), + ("Н", "N"), + ("О", "O"), + ("П", "P"), + ("Р", "R"), + ("С", "S"), + ("Т", "T"), + ("У", "U"), + ("Ф", "F"), + ("Х", "H"), + ("Э", "E"), + ("Ъ", "`"), + ("Ь", "'"), ## lower # three-symbols replacements - (u"щ", u"sch"), + ("щ", "sch"), # two-symbols replacements - (u"ё", u"yo"), - (u"ж", u"zh"), - (u"ц", u"ts"), - (u"ч", u"ch"), - (u"ш", u"sh"), - (u"ы", u"yi"), - (u"ю", u"yu"), - (u"я", u"ya"), + ("ё", "yo"), + ("ж", "zh"), + ("ц", "ts"), + ("ч", "ch"), + ("ш", "sh"), + ("ы", "yi"), + ("ю", "yu"), + ("я", "ya"), # one-symbol replacements - (u"а", u"a"), - (u"б", u"b"), - (u"в", u"v"), - (u"г", u"g"), - (u"д", u"d"), - (u"е", u"e"), - (u"з", u"z"), - (u"и", u"i"), - (u"й", u"j"), - (u"к", u"k"), - (u"л", u"l"), - (u"м", u"m"), - (u"н", u"n"), - (u"о", u"o"), - (u"п", u"p"), - (u"р", u"r"), - (u"с", u"s"), - (u"т", u"t"), - (u"у", u"u"), - (u"ф", u"f"), - (u"х", u"h"), - (u"э", u"e"), - (u"ъ", u"`"), - (u"ь", u"'"), + ("а", "a"), + ("б", "b"), + ("в", "v"), + ("г", "g"), + ("д", "d"), + ("е", "e"), + ("з", "z"), + ("и", "i"), + ("й", "j"), + ("к", "k"), + ("л", "l"), + ("м", "m"), + ("н", "n"), + ("о", "o"), + ("п", "p"), + ("р", "r"), + ("с", "s"), + ("т", "t"), + ("у", "u"), + ("ф", "f"), + ("х", "h"), + ("э", "e"), + ("ъ", "`"), + ("ь", "'"), # Make english alphabet full: append english-english pairs # for symbols which is not used in russian-english # translations. Used in slugify. - (u"c", u"c"), - (u"q", u"q"), - (u"y", u"y"), - (u"x", u"x"), - (u"w", u"w"), - (u"1", u"1"), - (u"2", u"2"), - (u"3", u"3"), - (u"4", u"4"), - (u"5", u"5"), - (u"6", u"6"), - (u"7", u"7"), - (u"8", u"8"), - (u"9", u"9"), - (u"0", u"0"), + ("c", "c"), + ("q", "q"), + ("y", "y"), + ("x", "x"), + ("w", "w"), + ("1", "1"), + ("2", "2"), + ("3", "3"), + ("4", "4"), + ("5", "5"), + ("6", "6"), + ("7", "7"), + ("8", "8"), + ("9", "9"), + ("0", "0"), ) #: Translation table RU_ALPHABET = [x[0] for x in TRANSTABLE] #: Russian alphabet that we can translate @@ -206,15 +208,15 @@ def slugify(in_string): "it is an ascii, but now it isn't. Use unicode " + \ "in this case.") # convert & to "and" - u_in_string = re.sub('\&\;|\&', ' and ', u_in_string) + u_in_string = re.sub(r'\&\;|\&', ' and ', u_in_string) # replace spaces by hyphen - u_in_string = re.sub('[-\s]+', '-', u_in_string) + u_in_string = re.sub(r'[-\s]+', '-', u_in_string) # remove symbols that not in alphabet - u_in_string = u''.join([symb for symb in u_in_string if symb in ALPHABET]) + u_in_string = ''.join([symb for symb in u_in_string if symb in ALPHABET]) # translify it out_string = translify(u_in_string) # remove non-alpha - return re.sub('[^\w\s-]', '', out_string).strip().lower() + return re.sub(r'[^\w\s-]', '', out_string).strip().lower() def dirify(in_string): diff --git a/pytils/typo.py b/pytils/typo.py index fa3028d..346dd49 100644 --- a/pytils/typo.py +++ b/pytils/typo.py @@ -3,8 +3,14 @@ """ Russian typography """ + +from __future__ import unicode_literals import re import os +import collections + +from pytils.third import six + def _sub_patterns(patterns, text): """ @@ -51,11 +57,11 @@ def rl_ellipsis(x): patterns = ( # если больше трех точек, то не заменяем на троеточие # чтобы не было глупых .....->….. - (r'([^\.]|^)\.\.\.([^\.]|$)', u'\\1\u2026\\2'), + (r'([^\.]|^)\.\.\.([^\.]|$)', '\\1\u2026\\2'), # если троеточие в начале строки или возле кавычки -- # это цитата, пробел между троеточием и первым # словом нужно убрать - (re.compile(u'(^|\\"|\u201c|\xab)\\s*\u2026\\s*([А-Яа-яA-Za-z])', re.UNICODE), u'\\1\u2026\\2'), + (re.compile(r'(^|\"|\u201c|\xab)\s*\u2026\s*([А-Яа-яA-Za-z])', re.UNICODE), '\\1\u2026\\2'), ) return _sub_patterns(patterns, x) @@ -65,8 +71,8 @@ def rl_initials(x): Replace space between initials and surname by thin space """ return re.sub( - re.compile(u'([А-Я])\\.\\s*([А-Я])\\.\\s*([А-Я][а-я]+)', re.UNICODE), - u'\\1.\\2.\u2009\\3', + re.compile(r'([А-Я])\.\s*([А-Я])\.\s*([А-Я][а-я]+)', re.UNICODE), + '\\1.\\2.\u2009\\3', x ) @@ -76,9 +82,9 @@ def rl_dashes(x): """ patterns = ( # тире - (re.compile(u'(^|(.\\s))\\-\\-?(([\\s\u202f].)|$)', re.MULTILINE|re.UNICODE), u'\\1\u2014\\3'), + (re.compile(r'(^|(.\s))--?(([\s\u202f].)|$)', re.MULTILINE|re.UNICODE), '\\1\u2014\\3'), # диапазоны между цифрами - en dash - (re.compile(u'(\\d[\\s\u2009]*)\\-([\\s\u2009]*\d)', re.MULTILINE|re.UNICODE), u'\\1\u2013\\2'), + (re.compile(r'(\d[\s\u2009]*)\-([\s\u2009]*\d)', re.MULTILINE|re.UNICODE), '\\1\u2013\\2'), # TODO: а что с минусом? ) return _sub_patterns(patterns, x) @@ -89,14 +95,14 @@ def rl_wordglue(x): """ patterns = ( # частицы склеиваем с предыдущим словом - (re.compile(u'(\\s+)(же|ли|ль|бы|б|ж|ка)([\\.,!\\?:;]?\\s+)', re.UNICODE), u'\u202f\\2\\3'), + (re.compile(r'(\s+)(же|ли|ль|бы|б|ж|ка)([\.,!\?:;]?\s+)', re.UNICODE), '\u202f\\2\\3'), # склеиваем короткие слова со следующим словом - (re.compile(u'\\b([a-zA-ZА-Яа-я]{1,3})(\\s+)', re.UNICODE), u'\\1\u202f'), + (re.compile(r'\b([a-zA-ZА-Яа-я]{1,3})(\s+)', re.UNICODE), '\\1\u202f'), # склеиваем тире с предыдущим словом - (re.compile(u'(\\s+)([\u2014\\-]+)(\\s+)', re.UNICODE), u'\u202f\\2\\3'), + (re.compile(r'(\s+)([\u2014\-]+)(\s+)', re.UNICODE), '\u202f\\2\\3'), # склеиваем два последних слова в абзаце между собой # полагается, что абзацы будут передаваться отдельной строкой - (re.compile(u'([^\\s]+)\\s+([^\\s]+)$', re.UNICODE), u'\\1\u202f\\2'), + (re.compile(r'([^\s]+)\s+([^\s]+)$', re.UNICODE), '\\1\u202f\\2'), ) return _sub_patterns(patterns, x) @@ -106,25 +112,25 @@ def rl_marks(x): """ # простые замены, можно без регулярок replacements = ( - (u'(r)', u'\u00ae'), # ® - (u'(R)', u'\u00ae'), # ® - (u'(p)', u'\u00a7'), # § - (u'(P)', u'\u00a7'), # § - (u'(tm)', u'\u2122'), # ™ - (u'(TM)', u'\u2122'), # ™ + ('(r)', '\u00ae'), # ® + ('(R)', '\u00ae'), # ® + ('(p)', '\u00a7'), # § + ('(P)', '\u00a7'), # § + ('(tm)', '\u2122'), # ™ + ('(TM)', '\u2122'), # ™ ) patterns = ( # копирайт ставится до года: © 2008 Юрий Юревич - (re.compile(u'\\([cCсС]\\)\\s*(\\d+)', re.UNICODE), u'\u00a9\u202f\\1'), - (r'([^+])(\+\-|\-\+)', u'\\1\u00b1'), # ± + (re.compile(r'\([cCсС]\)\s*(\d+)', re.UNICODE), '\u00a9\u202f\\1'), + (r'([^+])(\+\-|\-\+)', '\\1\u00b1'), # ± # градусы с минусом - (u'\\-(\\d+)[\\s]*([FCС][^\\w])', u'\u2212\\1\202f\u00b0\\2'), # −12 °C, −53 °F + (r'\-(\d+)[\s]*([FCС][^\w])', '\u2212\\1\202f\u00b0\\2'), # −12 °C, −53 °F # градусы без минуса - (u'(\\d+)[\\s]*([FCС][^\\w])', u'\\1\u202f\u00b0\\2'), # 12 °C, 53 °F + (r'(\d+)[\s]*([FCС][^\w])', '\\1\u202f\u00b0\\2'), # 12 °C, 53 °F # ® и ™ приклеиваются к предыдущему слову, без пробела - (re.compile(u'([A-Za-zА-Яа-я\\!\\?])\\s*(\xae|\u2122)', re.UNICODE), u'\\1\\2'), + (re.compile(r'([A-Za-zА-Яа-я\!\?])\s*(\xae|\u2122)', re.UNICODE), '\\1\\2'), # No5 -> № 5 - (re.compile(u'(\\s)(No|no|NO|\u2116)[\\s\u2009]*(\\d+)', re.UNICODE), u'\\1\u2116\u2009\\3'), + (re.compile(r'(\s)(No|no|NO|\u2116)[\s\u2009]*(\d+)', re.UNICODE), '\\1\u2116\u2009\\3'), ) for what, to in replacements: @@ -140,13 +146,13 @@ def rl_quotes(x): # открывающие кавычки ставятся обычно вплотную к слову слева # а закрывающие -- вплотную справа # открывающие русские кавычки-ёлочки - (re.compile(r'((?:^|\s))(")((?u))', re.UNICODE), u'\\1\xab\\3'), + (re.compile(r'((?:^|\s))(")((?u))', re.UNICODE), '\\1\xab\\3'), # закрывающие русские кавычки-ёлочки - (re.compile(r'(\S)(")((?u))', re.UNICODE), u'\\1\xbb\\3'), + (re.compile(r'(\S)(")((?u))', re.UNICODE), '\\1\xbb\\3'), # открывающие кавычки-лапки, вместо одинарных кавычек - (re.compile(r'((?:^|\s))(\')((?u))', re.UNICODE), u'\\1\u201c\\3'), + (re.compile(r'((?:^|\s))(\')((?u))', re.UNICODE), '\\1\u201c\\3'), # закрывающие кавычки-лапки - (re.compile(r'(\S)(\')((?u))', re.UNICODE), u'\\1\u201d\\3'), + (re.compile(r'(\S)(\')((?u))', re.UNICODE), '\\1\u201d\\3'), ) return _sub_patterns(patterns, x) @@ -159,16 +165,16 @@ def _get_rule_by_name(name): rule = globals().get('rl_%s' % name) if rule is None: raise ValueError("Rule %s is not found" % name) - if not callable(rule): + if not isinstance(rule, collections.Callable): raise ValueError("Rule with name %s is not callable" % name) return rule def _resolve_rule_name(rule_or_name, forced_name=None): - if isinstance(rule_or_name, str): + if isinstance(rule_or_name, six.string_types): # got name name = rule_or_name rule = _get_rule_by_name(name) - elif callable(rule_or_name): + elif isinstance(rule_or_name, collections.Callable): # got rule name = rule_or_name.__name__ if name.startswith('rl_'): @@ -235,20 +241,20 @@ def __init__(self, *args, **kwargs): expanded_args += list(arg) elif isinstance(arg, dict): expanded_kwargs.update(arg) - elif isinstance(arg, str) or callable(arg): + elif isinstance(arg, six.string_types) or isinstance(arg, collections.Callable): expanded_args.append(arg) else: raise TypeError( "Cannot expand arg %r, must be tuple, list,"\ - " dict, str or callable, not" % + " dict, str or callable, not %s" % (arg, type(arg).__name__)) - for kw, arg in kwargs.items(): - if isinstance(arg, str) or callable(arg): + for kw, arg in list(kwargs.items()): + if isinstance(arg, six.string_types) or isinstance(arg, collections.Callable): expanded_kwargs[kw] = arg else: raise TypeError( "Cannot expand kwarg %r, must be str or "\ - "callable, not" % (arg, type(arg).__name__)) + "callable, not %s" % (arg, type(arg).__name__)) # next, resolve rule names to callables for name, rule in (_resolve_rule_name(a) for a in expanded_args): self.rules[name] = rule diff --git a/pytils/utils.py b/pytils/utils.py index a11065e..c10d209 100644 --- a/pytils/utils.py +++ b/pytils/utils.py @@ -4,6 +4,8 @@ Misc utils for internal use """ +from __future__ import unicode_literals + from pytils.third import six @@ -44,7 +46,7 @@ def check_positive(value, strict=False): raise ValueError("Value must be positive, not %s" % str(value)) -def split_values(ustring, sep=u','): +def split_values(ustring, sep=','): """ Splits unicode string with separator C{sep}, but skips escaped separator. @@ -60,6 +62,6 @@ def split_values(ustring, sep=u','): assert isinstance(ustring, six.text_type), "uvalue must be unicode, not %s" % type(ustring) # unicode have special mark symbol 0xffff which cannot be used in a regular text, # so we use it to mark a place where escaped column was - ustring_marked = ustring.replace(u'\,', u'\uffff') - items = tuple([i.strip().replace(u'\uffff', u',') for i in ustring_marked.split(sep)]) + ustring_marked = ustring.replace('\,', '\uffff') + items = tuple([i.strip().replace('\uffff', ',') for i in ustring_marked.split(sep)]) return items diff --git a/tox.ini b/tox.ini index 9f33f81..853e3d3 100644 --- a/tox.ini +++ b/tox.ini @@ -1,18 +1,22 @@ [tox] -envlist = py27-django11,py36-django{11,20} +envlist = py{27,34,35,36,37}-django11,py{34,35,36,37}-django20,py{35,36,37}-django2{1,2} [testenv] -setenv= +setenv = DJANGO_SETTINGS_MODULE = settings -commands= +commands = {envpython} pytils/test/__init__.py {envpython} doc/examples-django/pytilsex/manage.py test --where=doc/examples-django/pytilsex/ --verbosity=2 {envpython} doc/examples/test.py --verbosity=2 -d - basepython = py27: python2.7 + py34: python3.4 + py35: python3.5 py36: python3.6 + py37: python3.7 deps = django-nose django11: Django>=1.11,<2.0 django20: Django>=2.0,<2.1 + django21: Django>=2.1,<2.2 + django22: Django>=2.2,<3.0 From 4cc32fcf505ea58f81b579d3e5ac0132bf20021f Mon Sep 17 00:00:00 2001 From: Eugene Morozov Date: Fri, 15 May 2020 16:57:38 +0300 Subject: [PATCH 2/2] python3, django>=1.11<=3.0 --- .travis.yml | 28 +- doc/examples-django/pytilsex/settings.py | 1 - doc/examples-django/pytilsex/tests.py | 1 - doc/examples/dt.distance_of_time_in_words.py | 30 +- doc/examples/dt.ru_strftime.py | 31 +- doc/examples/numeral.choose_plural.py | 29 +- doc/examples/numeral.in_words.py | 28 +- doc/examples/numeral.rubles.py | 22 +- doc/examples/numeral.sum_string.py | 24 +- doc/examples/test.py | 20 +- doc/examples/translit.py | 24 +- pytils/dt.py | 16 +- pytils/numeral.py | 12 +- pytils/templatetags/__init__.py | 1 - pytils/templatetags/pytils_numeral.py | 14 +- pytils/test/templatetags/helpers.py | 1 - pytils/test/templatetags/test_common.py | 1 - pytils/test/templatetags/test_dt.py | 1 - pytils/test/templatetags/test_numeral.py | 1 - pytils/test/templatetags/test_translit.py | 1 - pytils/test/test_dt.py | 1 - pytils/test/test_numeral.py | 21 - pytils/test/test_translit.py | 19 +- pytils/test/test_typo.py | 1 - pytils/test/test_utils.py | 2 - pytils/third/__init__.py | 3 - pytils/third/six.py | 577 ------------------- pytils/translit.py | 19 +- pytils/typo.py | 9 +- pytils/utils.py | 11 +- setup.py | 8 +- tox.ini | 6 +- 32 files changed, 106 insertions(+), 857 deletions(-) delete mode 100644 pytils/third/__init__.py delete mode 100644 pytils/third/six.py diff --git a/.travis.yml b/.travis.yml index 4e7a5ac..f597449 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,12 +3,6 @@ sudo: false dist: xenial matrix: include: - - python: "2.7" - env: TOXENV="py27-django11" - - python: "3.4" - env: TOXENV="py34-django11" - - python: "3.4" - env: TOXENV="py34-django20" - python: "3.5" env: TOXENV="py35-django11" - python: "3.5" @@ -25,5 +19,27 @@ matrix: env: TOXENV="py36-django21" - python: "3.6" env: TOXENV="py36-django22" + - python: "3.6" + env: TOXENV="py36-django30" + - python: "3.7" + env: TOXENV="py37-django11" + - python: "3.7" + env: TOXENV="py37-django20" + - python: "3.7" + env: TOXENV="py37-django21" + - python: "3.7" + env: TOXENV="py37-django22" + - python: "3.7" + env: TOXENV="py37-django30" + - python: "3.8" + env: TOXENV="py38-django11" + - python: "3.8" + env: TOXENV="py38-django20" + - python: "3.8" + env: TOXENV="py38-django21" + - python: "3.8" + env: TOXENV="py38-django22" + - python: "3.8" + env: TOXENV="py38-django30" install: pip install tox script: tox -e $TOXENV diff --git a/doc/examples-django/pytilsex/settings.py b/doc/examples-django/pytilsex/settings.py index aff4d13..1476f02 100644 --- a/doc/examples-django/pytilsex/settings.py +++ b/doc/examples-django/pytilsex/settings.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals # Django settings for pytilsex project. diff --git a/doc/examples-django/pytilsex/tests.py b/doc/examples-django/pytilsex/tests.py index d2ab956..b5481f0 100644 --- a/doc/examples-django/pytilsex/tests.py +++ b/doc/examples-django/pytilsex/tests.py @@ -1,6 +1,5 @@ # -*- encoding: utf-8 -*- -from __future__ import unicode_literals from django.urls import reverse from django.test import TestCase from django.test.client import Client diff --git a/doc/examples/dt.distance_of_time_in_words.py b/doc/examples/dt.distance_of_time_in_words.py index 94364ec..8486b8c 100755 --- a/doc/examples/dt.distance_of_time_in_words.py +++ b/doc/examples/dt.distance_of_time_in_words.py @@ -5,18 +5,6 @@ import time from pytils import dt -def print_(s): - # pytils всегда возвращает юникод (строка в Py3.x) - # обычно это ОК выводить юникод в терминал - # но если это неинтерактивный вывод - # (например, использования модуля subprocess) - # то для Py2.x нужно использовать перекодировку в utf-8 - from pytils.third import six - if six.PY3: - out = s - else: - out = s.encode('UTF-8') - print(out) # поддерживаются оба модуля работы со временем: # time @@ -37,30 +25,30 @@ def print_(s): # если to_time не передано, считается от "сейчас", # и тогда -1 день -> "вчера", а +1 день -> "завтра" -print_(dt.distance_of_time_in_words(in_past)) +print(dt.distance_of_time_in_words(in_past)) #-> вчера -print_(dt.distance_of_time_in_words(dt_in_future)) +print(dt.distance_of_time_in_words(dt_in_future)) #-> завтра # а вот если передано to_time, то нельзя говорить "вчера", # потому что to_time не обязательно "сейчас", # поэтому -1 день -> "1 день назад" -print_(dt.distance_of_time_in_words(in_past, to_time=current_time)) +print(dt.distance_of_time_in_words(in_past, to_time=current_time)) #-> 1 день назад # увеличение точности отражается на результате -print_(dt.distance_of_time_in_words(in_past, accuracy=2)) +print(dt.distance_of_time_in_words(in_past, accuracy=2)) #-> 1 день 3 часа назад -print_(dt.distance_of_time_in_words(in_past, accuracy=3)) +print(dt.distance_of_time_in_words(in_past, accuracy=3)) #-> 1 день 3 часа 46 минут назад # аналогично и с будущим временем: -print_(dt.distance_of_time_in_words(in_future)) +print(dt.distance_of_time_in_words(in_future)) #-> завтра -print_(dt.distance_of_time_in_words(in_future, to_time=current_time)) +print(dt.distance_of_time_in_words(in_future, to_time=current_time)) #-> через 1 день -print_(dt.distance_of_time_in_words(in_future, accuracy=2)) +print(dt.distance_of_time_in_words(in_future, accuracy=2)) #-> через 1 день 3 часа -print_(dt.distance_of_time_in_words(in_future, accuracy=3)) +print(dt.distance_of_time_in_words(in_future, accuracy=3)) #-> через 1 день 3 часа 46 минут diff --git a/doc/examples/dt.ru_strftime.py b/doc/examples/dt.ru_strftime.py index 4359e34..639bf0a 100755 --- a/doc/examples/dt.ru_strftime.py +++ b/doc/examples/dt.ru_strftime.py @@ -1,24 +1,9 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from __future__ import unicode_literals - import datetime from pytils import dt -def print_(s): - # pytils всегда возвращает юникод (строка в Py3.x) - # обычно это ОК выводить юникод в терминал - # но если это неинтерактивный вывод - # (например, использования модуля subprocess) - # то для Py2.x нужно использовать перекодировку в utf-8 - from pytils.third import six - if six.PY3: - out = s - else: - out = s.encode('UTF-8') - print(out) - # действие ru_strftime аналогично оригинальному strftime # только в %a, %A, %b и %B вместо английских названий будут русские @@ -26,35 +11,35 @@ def print_(s): d = datetime.date(2006, 9, 15) # оригинал -print_(d.strftime("%d.%m.%Y (%a)")) +print(d.strftime("%d.%m.%Y (%a)")) # -> 15.09.2006 (Fri) # теперь на русском # (единственно, что нужно формат строки передавать в unicode # в то время, как в оригинальном strftime это обязательно str) -print_(dt.ru_strftime("%d.%m.%Y (%a)", d)) +print(dt.ru_strftime("%d.%m.%Y (%a)", d)) # -> 15.09.2006 (пт) # %A дает полное название дня недели -print_(dt.ru_strftime("%d.%m.%Y (%A)", d)) +print(dt.ru_strftime("%d.%m.%Y (%A)", d)) # -> 15.09.2006 (пятница) # %B -- название месяца -print_(dt.ru_strftime("%d %B %Y", d)) +print(dt.ru_strftime("%d %B %Y", d)) # -> 15 сентябрь 2006 # ru_strftime умеет правильно склонять месяц (опция inflected) -print_(dt.ru_strftime("%d %B %Y", d, inflected=True)) +print(dt.ru_strftime("%d %B %Y", d, inflected=True)) # -> 15 сентября 2006 # ... и день (опция inflected_day) -print_(dt.ru_strftime("%d.%m.%Y, в %A", d, inflected_day=True)) +print(dt.ru_strftime("%d.%m.%Y, в %A", d, inflected_day=True)) # -> 15.09.2006, в пятницу # ... и добавлять правильный предлог (опция preposition) -print_(dt.ru_strftime("%d.%m.%Y, %A", d, preposition=True)) +print(dt.ru_strftime("%d.%m.%Y, %A", d, preposition=True)) # -> 15.09.2006, в пятницу # второй параметр можно не передавать, будет использована текущая дата -print_(dt.ru_strftime("%d %B %Y", inflected=True)) +print(dt.ru_strftime("%d %B %Y", inflected=True)) # ->> 1 декабря 2013 diff --git a/doc/examples/numeral.choose_plural.py b/doc/examples/numeral.choose_plural.py index 7bc3428..b47a252 100755 --- a/doc/examples/numeral.choose_plural.py +++ b/doc/examples/numeral.choose_plural.py @@ -1,23 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from __future__ import unicode_literals - from pytils import numeral -def print_(s): - # pytils всегда возвращает юникод (строка в Py3.x) - # обычно это ОК выводить юникод в терминал - # но если это неинтерактивный вывод - # (например, использования модуля subprocess) - # то для Py2.x нужно использовать перекодировку в utf-8 - from pytils.third import six - if six.PY3: - out = s - else: - out = s.encode('UTF-8') - print(out) - # choose_plural нужен для выбора правильной формы # существительного @@ -30,28 +15,28 @@ def print_(s): # (один, два, пять) # т.е. для 1, 2 и 5 объектов, например для слова "пример" # (пример, примера, примеров) -print_(numeral.choose_plural(21, ("пример", "примера", "примеров"))) +print(numeral.choose_plural(21, ("пример", "примера", "примеров"))) #-> пример -print_(numeral.choose_plural(12, ("пример", "примера", "примеров"))) +print(numeral.choose_plural(12, ("пример", "примера", "примеров"))) #-> примеров -print_(numeral.choose_plural(32, ("пример", "примера", "примеров"))) +print(numeral.choose_plural(32, ("пример", "примера", "примеров"))) #-> примера # также можно задавать варианты в одну строку, разделенные запятой -print_(numeral.choose_plural(32, "пример,примера, примеров")) +print(numeral.choose_plural(32, "пример,примера, примеров")) #-> примера # если в варианте используется запятая, она экранируется слешем -print_(numeral.choose_plural(35, "гвоздь, гвоздя, гвоздей\, шпунтов")) +print(numeral.choose_plural(35, "гвоздь, гвоздя, гвоздей\, шпунтов")) #-> гвоздей, шпунтов # зачастую требуется не просто вариант, а вместе с числительным # в этом случае следует использовать get_plural -print_(numeral.get_plural(32, "пример,примера, примеров")) +print(numeral.get_plural(32, "пример,примера, примеров")) #-> 32 примера # часто хочется, чтобы в случае отсутсвия значения (т.е. количество равно нулю) # выводилось не "0 примеров", а "примеров нет" # в этом случае используйте третий параметр get_plural: -print_(numeral.get_plural(0, "пример,примера, примеров", "без примеров")) +print(numeral.get_plural(0, "пример,примера, примеров", "без примеров")) # -> без примеров diff --git a/doc/examples/numeral.in_words.py b/doc/examples/numeral.in_words.py index 0844930..d84cee5 100755 --- a/doc/examples/numeral.in_words.py +++ b/doc/examples/numeral.in_words.py @@ -3,44 +3,30 @@ from pytils import numeral -def print_(s): - # pytils всегда возвращает юникод (строка в Py3.x) - # обычно это ОК выводить юникод в терминал - # но если это неинтерактивный вывод - # (например, использования модуля subprocess) - # то для Py2.x нужно использовать перекодировку в utf-8 - from pytils.third import six - if six.PY3: - out = s - else: - out = s.encode('UTF-8') - print(out) - - # in_words нужен для представления цифр словами -print_(numeral.in_words(12)) +print(numeral.in_words(12)) #-> двенадцать # вторым параметром можно задать пол: # мужской=numeral.MALE, женский=numeral.FEMALE, срелний=numeral.NEUTER (по умолчанию -- мужской) -print_(numeral.in_words(21)) +print(numeral.in_words(21)) #-> двадцать один # можно передавать неименованным параметром: -print_(numeral.in_words(21, numeral.FEMALE)) +print(numeral.in_words(21, numeral.FEMALE)) #-> двадцать одна # можно именованным -print_(numeral.in_words(21, gender=numeral.FEMALE)) +print(numeral.in_words(21, gender=numeral.FEMALE)) #-> двадцать одна -print_(numeral.in_words(21, gender=numeral.NEUTER)) +print(numeral.in_words(21, gender=numeral.NEUTER)) #-> двадцать одно # можно и дробные -print_(numeral.in_words(12.5)) +print(numeral.in_words(12.5)) #-> двенадцать целых пять десятых # причем "пишутся" только значимые цифры -print_(numeral.in_words(5.30000)) +print(numeral.in_words(5.30000)) #-> пять целых три десятых diff --git a/doc/examples/numeral.rubles.py b/doc/examples/numeral.rubles.py index 95fa18a..fc8113f 100755 --- a/doc/examples/numeral.rubles.py +++ b/doc/examples/numeral.rubles.py @@ -3,32 +3,18 @@ from pytils import numeral -def print_(s): - # pytils всегда возвращает юникод (строка в Py3.x) - # обычно это ОК выводить юникод в терминал - # но если это неинтерактивный вывод - # (например, использования модуля subprocess) - # то для Py2.x нужно использовать перекодировку в utf-8 - from pytils.third import six - if six.PY3: - out = s - else: - out = s.encode('UTF-8') - print(out) - - # rubles служит для формирования строк с деньгами -print_(numeral.rubles(10)) +print(numeral.rubles(10)) #-> десять рублей # если нужно, то даже 0 копеек можно записать словами -print_(numeral.rubles(10, zero_for_kopeck=True)) +print(numeral.rubles(10, zero_for_kopeck=True)) #-> десять рублей ноль копеек -print_(numeral.rubles(2.35)) +print(numeral.rubles(2.35)) #-> два рубля тридцать пять копеек # в случае чего, копейки округляются -print_(numeral.rubles(3.95754)) +print(numeral.rubles(3.95754)) #-> три рубля девяносто шесть копеек diff --git a/doc/examples/numeral.sum_string.py b/doc/examples/numeral.sum_string.py index 5933e99..d292eeb 100755 --- a/doc/examples/numeral.sum_string.py +++ b/doc/examples/numeral.sum_string.py @@ -1,24 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from __future__ import unicode_literals - from pytils import numeral -def print_(s): - # pytils всегда возвращает юникод (строка в Py3.x) - # обычно это ОК выводить юникод в терминал - # но если это неинтерактивный вывод - # (например, использования модуля subprocess) - # то для Py2.x нужно использовать перекодировку в utf-8 - from pytils.third import six - if six.PY3: - out = s - else: - out = s.encode('UTF-8') - print(out) - - # sum_string объединяет в себе choose_plural и in_words # т.е. передаются и количество, и варианты названия объекта # а на выходе получаем количество объектов в правильной форме @@ -29,17 +13,17 @@ def print_(s): # 3) items, варианты названий объекта (необязательно), # правила аналогичны таковым у choose_plural -print_(numeral.sum_string(3, numeral.MALE, ("носок", "носка", "носков"))) +print(numeral.sum_string(3, numeral.MALE, ("носок", "носка", "носков"))) #-> три носка -print_(numeral.sum_string(5, numeral.FEMALE, ("коробка", "коробки", "коробок"))) +print(numeral.sum_string(5, numeral.FEMALE, ("коробка", "коробки", "коробок"))) #-> пять коробок -print_(numeral.sum_string(21, numeral.NEUTER, ("очко", "очка", "очков"))) +print(numeral.sum_string(21, numeral.NEUTER, ("очко", "очка", "очков"))) #-> двадцать одно очко # если варианты не указывать, то действие функции аналогично дейтсвию in_words -print_(numeral.sum_string(21, gender=numeral.NEUTER)) +print(numeral.sum_string(21, gender=numeral.NEUTER)) #-> двадцать одно diff --git a/doc/examples/test.py b/doc/examples/test.py index 4188a46..2fb1960 100644 --- a/doc/examples/test.py +++ b/doc/examples/test.py @@ -1,11 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from __future__ import unicode_literals import subprocess -import sys import os -from pytils.third import six EXAMPLES = [ 'dt.distance_of_time_in_words.py', @@ -25,10 +22,7 @@ def safe_file_iterator(fh, encoding='UTF-8'): # Py3 file iterator returns not a bytestrings but string # therefore we should decode for Py2.x and leave as is for Py3 for line in fh: - if six.PY3: - yield line - else: - yield line.decode(encoding) + yield line def grab_expected_output(name): @@ -53,18 +47,18 @@ def __init__(self, name): assert len(self.real_output) == len(self.expected_output), \ "Mismatch in number of real (%s) and expected (%s) strings" % (len(self.real_output), len(self.expected_output)) assert len(self.real_output) > 0 - assert isinstance(self.real_output[0], six.text_type), \ - "%r is not text type (not a unicode for Py2.x, not a str for Py3.x" % self.real_output[0] - assert isinstance(self.expected_output[0], six.text_type), \ - "%r is not text type (not a unicode for Py2.x, not a str for Py3.x" % self.expected_output[0] + assert isinstance(self.real_output[0], str), \ + "%r is not a str" % self.real_output[0] + assert isinstance(self.expected_output[0], str), \ + "%r is not a str" % self.expected_output[0] def test_cases(self): return list(range(len(self.real_output))) def run_test(self, name, i): assert name == self.name - assert isinstance(self.real_output[i], six.text_type) - assert isinstance(self.expected_output[i], six.text_type) + assert isinstance(self.real_output[i], str) + assert isinstance(self.expected_output[i], str) # ignore real output if in example line marked with ->> if self.expected_output[i].startswith('>'): return diff --git a/doc/examples/translit.py b/doc/examples/translit.py index a1526a9..dedc47b 100755 --- a/doc/examples/translit.py +++ b/doc/examples/translit.py @@ -1,45 +1,31 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from __future__ import unicode_literals - from pytils import translit -def print_(s): - # pytils всегда возвращает юникод (строка в Py3.x) - # обычно это ОК выводить юникод в терминал - # но если это неинтерактивный вывод - # (например, использования модуля subprocess) - # то для Py2.x нужно использовать перекодировку в utf-8 - from pytils.third import six - if six.PY3: - out = s - else: - out = s.encode('UTF-8') - print(out) # простая траслитерация/детранслитерация # обратите внимание на то, что при транслитерации вход - unicode, # выход - str, а в детранслитерации -- наоборот # -print_(translit.translify("Это тест и ничего более")) +print(translit.translify("Это тест и ничего более")) #-> Eto test i nichego bolee -print_(translit.translify("Традиционно сложные для транслитерации буквы - подъезд, щука")) +print(translit.translify("Традиционно сложные для транслитерации буквы - подъезд, щука")) #-> Traditsionno slozhnyie dlya transliteratsii bukvyi - pod`ezd, schuka # и теперь пытаемся вернуть назад... (понятно, что Э и Е получаются одинаково) -print_(translit.detranslify("Eto test i nichego bolee")) +print(translit.detranslify("Eto test i nichego bolee")) #-> Ето тест и ничего более -print_(translit.detranslify("Traditsionno slozhnyie dlya transliteratsii bukvyi - pod`ezd, schuka")) +print(translit.detranslify("Traditsionno slozhnyie dlya transliteratsii bukvyi - pod`ezd, schuka")) #-> Традиционно сложные для транслитерации буквы – подЪезд, щука # и пригодные для url и названий каталогов/файлов транслиты # dirify и slugify -- синонимы, действия абсолютно идентичны -print_(translit.slugify("Традиционно сложные для транслитерации буквы - подъезд, щука")) +print(translit.slugify("Традиционно сложные для транслитерации буквы - подъезд, щука")) #-> traditsionno-slozhnyie-dlya-transliteratsii-bukvyi-podezd-schuka # обратного преобразования, понятно, нет :) diff --git a/pytils/dt.py b/pytils/dt.py index cd6205b..4142398 100644 --- a/pytils/dt.py +++ b/pytils/dt.py @@ -4,12 +4,10 @@ Russian dates without locales """ -from __future__ import unicode_literals import datetime from pytils import numeral from pytils.utils import check_positive -from pytils.third import six DAY_ALTERNATIVES = { 1: ("вчера", "завтра"), @@ -214,21 +212,11 @@ def ru_strftime(format="%d.%m.%Y", date=None, inflected=False, # for russian typography standard, # 1 April 2007, but 01.04.2007 if '%b' in format or '%B' in format: - format = format.replace('%d', six.text_type(date.day)) + format = format.replace('%d', str(date.day)) format = format.replace('%a', prepos+DAY_NAMES[weekday][0]) format = format.replace('%A', prepos+DAY_NAMES[weekday][day_idx]) format = format.replace('%b', MONTH_NAMES[date.month-1][0]) format = format.replace('%B', MONTH_NAMES[date.month-1][month_idx]) - # 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) - return u_res + return date.strftime(format) diff --git a/pytils/numeral.py b/pytils/numeral.py index 58b9ca3..1208a1b 100644 --- a/pytils/numeral.py +++ b/pytils/numeral.py @@ -4,10 +4,8 @@ Plural forms and in-word representation for numerals. """ -from __future__ import unicode_literals, division from decimal import Decimal from pytils.utils import check_positive, check_length, split_values -from pytils.third import six FRACTIONS = ( ("десятая", "десятых", "десятых"), @@ -92,7 +90,7 @@ def _get_float_remainder(fvalue, signs=9): @raise ValueError: signs overflow """ check_positive(fvalue) - if isinstance(fvalue, six.integer_types): + if isinstance(fvalue, int): return "0" if isinstance(fvalue, Decimal) and fvalue.as_tuple()[2] == 0: # Decimal.as_tuple() -> (sign, digit_tuple, exponent) @@ -142,7 +140,7 @@ def choose_plural(amount, variants): @raise ValueError: variants' length lesser than 3 """ - if isinstance(variants, six.text_type): + if isinstance(variants, str): variants = split_values(variants) check_length(variants, 3) amount = abs(amount) @@ -199,7 +197,7 @@ def _get_plural_legacy(amount, extra_variants): @rtype: C{unicode} """ absence = None - if isinstance(extra_variants, six.text_type): + if isinstance(extra_variants, str): extra_variants = split_values(extra_variants) if len(extra_variants) == 4: variants = extra_variants[:3] @@ -313,7 +311,7 @@ def in_words(amount, gender=None): else: args = (amount, gender) # если целое - if isinstance(amount, six.integer_types): + if isinstance(amount, int): return in_words_int(*args) # если дробное elif isinstance(amount, (float, Decimal)): @@ -348,7 +346,7 @@ def sum_string(amount, gender, items=None): @raise ValueError: amount bigger than 10**11 @raise ValueError: amount is negative """ - if isinstance(items, six.text_type): + if isinstance(items, str): items = split_values(items) if items is None: items = ("", "", "") diff --git a/pytils/templatetags/__init__.py b/pytils/templatetags/__init__.py index 1dfc804..dc56192 100644 --- a/pytils/templatetags/__init__.py +++ b/pytils/templatetags/__init__.py @@ -2,7 +2,6 @@ """ Pytils templatetags for Django web-framework """ -from __future__ import unicode_literals # Если отладка, то показываем 'unknown+сообщение об ошибке'. # Если отладка выключена, то можно чтобы при ошибках показывалось diff --git a/pytils/templatetags/pytils_numeral.py b/pytils/templatetags/pytils_numeral.py index 4393571..48b0b0a 100644 --- a/pytils/templatetags/pytils_numeral.py +++ b/pytils/templatetags/pytils_numeral.py @@ -8,14 +8,8 @@ from pytils import numeral from pytils.templatetags import init_defaults -from pytils.third import six -try: - # Django 1.4+ - from django.utils.encoding import smart_text -except ImportError: - from django.utils.encoding import smart_unicode - smart_text = smart_unicode +from django.utils.encoding import smart_text register = template.Library() #: Django template tag/filter registrator encoding = conf.settings.DEFAULT_CHARSET #: Current charset (sets in Django project's settings) @@ -39,7 +33,7 @@ def choose_plural(amount, variants): {{ some_int|choose_plural:"пример,примера,примеров" }} """ try: - if isinstance(variants, six.string_types): + if isinstance(variants, str): uvariants = smart_text(variants, encoding) else: uvariants = [smart_text(v, encoding) for v in variants] @@ -66,7 +60,7 @@ def get_plural(amount, variants): {{ some_int|get_plural:"пример,примера,примеров,нет примеров" }} """ try: - if isinstance(variants, six.string_types): + if isinstance(variants, str): uvariants = smart_text(variants, encoding) else: uvariants = [smart_text(v, encoding) for v in variants] @@ -130,7 +124,7 @@ def sum_string(amount, gender, items): {% sum_string some_other_int FEMALE "задача,задачи,задач" %} """ try: - if isinstance(items, six.string_types): + if isinstance(items, str): uitems = smart_text(items, encoding, default_uvalue) else: uitems = [smart_text(i, encoding) for i in items] diff --git a/pytils/test/templatetags/helpers.py b/pytils/test/templatetags/helpers.py index 4886920..72a4875 100644 --- a/pytils/test/templatetags/helpers.py +++ b/pytils/test/templatetags/helpers.py @@ -3,7 +3,6 @@ Helpers for templatetags' unit tests in Django webframework """ -from __future__ import unicode_literals from django.conf import settings from django.utils.encoding import smart_str diff --git a/pytils/test/templatetags/test_common.py b/pytils/test/templatetags/test_common.py index 8d8e2f3..fe48d09 100644 --- a/pytils/test/templatetags/test_common.py +++ b/pytils/test/templatetags/test_common.py @@ -3,7 +3,6 @@ Unit tests for pytils' templatetags common things """ -from __future__ import unicode_literals import unittest from pytils import templatetags as tt diff --git a/pytils/test/templatetags/test_dt.py b/pytils/test/templatetags/test_dt.py index e34bc68..d56df11 100644 --- a/pytils/test/templatetags/test_dt.py +++ b/pytils/test/templatetags/test_dt.py @@ -3,7 +3,6 @@ Unit tests for pytils' dt templatetags for Django web framework """ -from __future__ import unicode_literals import datetime from pytils.test.templatetags import helpers diff --git a/pytils/test/templatetags/test_numeral.py b/pytils/test/templatetags/test_numeral.py index 89a6622..159d8b8 100644 --- a/pytils/test/templatetags/test_numeral.py +++ b/pytils/test/templatetags/test_numeral.py @@ -3,7 +3,6 @@ Unit tests for pytils' numeral templatetags for Django web framework """ -from __future__ import unicode_literals from pytils.test.templatetags import helpers diff --git a/pytils/test/templatetags/test_translit.py b/pytils/test/templatetags/test_translit.py index e0ecbbb..1b785ba 100644 --- a/pytils/test/templatetags/test_translit.py +++ b/pytils/test/templatetags/test_translit.py @@ -3,7 +3,6 @@ Unit tests for pytils' translit templatetags for Django web framework """ -from __future__ import unicode_literals from pytils.test.templatetags import helpers class TranslitDefaultTestCase(helpers.TemplateTagTestCase): diff --git a/pytils/test/test_dt.py b/pytils/test/test_dt.py index c3a81d2..1db9c9d 100644 --- a/pytils/test/test_dt.py +++ b/pytils/test/test_dt.py @@ -3,7 +3,6 @@ Unit-tests for pytils.dt """ -from __future__ import unicode_literals import datetime import time import unittest diff --git a/pytils/test/test_numeral.py b/pytils/test/test_numeral.py index 6d522f0..bdd70c8 100644 --- a/pytils/test/test_numeral.py +++ b/pytils/test/test_numeral.py @@ -3,18 +3,10 @@ Unit-tests for pytils.numeral """ -from __future__ import unicode_literals import unittest import decimal import pytils -# Python3 doesn't have long type -# it has only int -from pytils.third import six - -if six.PY3: - long = int - class ChoosePluralTestCase(unittest.TestCase): """ @@ -44,7 +36,6 @@ def testChoosePlural(self): self.checkChoosePlural(5, "гвоздей") self.checkChoosePlural(11, "гвоздей") self.checkChoosePlural(109, "гвоздей") - self.checkChoosePlural(long(109), "гвоздей") def testChoosePluralNegativeBug9(self): """ @@ -186,8 +177,6 @@ def testRubles(self): "три рубля") self.assertEqual(pytils.numeral.rubles(3, True), "три рубля ноль копеек") - self.assertEqual(pytils.numeral.rubles(long(3)), - "три рубля") def testRublesDecimal(self): """ @@ -231,7 +220,6 @@ def testInt(self): "три тысячи пятьсот") self.assertEqual(pytils.numeral.in_words_int(5231000), "пять миллионов двести тридцать одна тысяча") - self.assertEqual(pytils.numeral.in_words_int(long(10)), "десять") def testIntExceptions(self): """ @@ -292,8 +280,6 @@ def testWithGenderOldStyle(self): "двадцать одна целая ноль десятых") self.assertEqual(pytils.numeral.in_words(21.0, 3), "двадцать одна целая ноль десятых") - self.assertEqual(pytils.numeral.in_words(long(21), 1), - "двадцать один") def testWithGender(self): """ @@ -312,8 +298,6 @@ def testWithGender(self): "двадцать одна целая ноль десятых") self.assertEqual(pytils.numeral.in_words(21.0, pytils.numeral.NEUTER), "двадцать одна целая ноль десятых") - self.assertEqual(pytils.numeral.in_words(long(21), pytils.numeral.MALE), - "двадцать один") def testCommon(self): @@ -338,7 +322,6 @@ def testCommon(self): "ноль целых одна сотая") self.assertEqual(pytils.numeral.in_words(0.10), "ноль целых одна десятая") - self.assertEqual(pytils.numeral.in_words(long(10)), "десять") self.assertEqual(pytils.numeral.in_words(D("2.25")), "две целых двадцать пять сотых") self.assertEqual(pytils.numeral.in_words(D("0.01")), @@ -415,8 +398,6 @@ def testSumStringOldStyleGender(self): self.ckFemaleOldStyle(2, "две шляпки") self.ckFemaleOldStyle(31, "тридцать одна шляпка") - self.ckFemaleOldStyle(long(31), "тридцать одна шляпка") - self.assertEqual("одиннадцать негритят", pytils.numeral.sum_string( 11, @@ -434,8 +415,6 @@ def testSumString(self): self.ckFemale(10, "десять шляпок") self.ckFemale(2, "две шляпки") self.ckFemale(31, "тридцать одна шляпка") - - self.ckFemale(long(31), "тридцать одна шляпка") self.assertEqual("одиннадцать негритят", pytils.numeral.sum_string( diff --git a/pytils/test/test_translit.py b/pytils/test/test_translit.py index 0f9cbc2..9114a10 100644 --- a/pytils/test/test_translit.py +++ b/pytils/test/test_translit.py @@ -3,10 +3,9 @@ Unit-tests for pytils.translit """ -from __future__ import unicode_literals import unittest import pytils -from pytils.third import six + class TranslitTestCase(unittest.TestCase): """ @@ -57,14 +56,6 @@ def testDetransliteration(self): self.ckDetransl('SCHuka', "Щука") self.ckDetransl('Schuka', "Щука") - def testDetransliterationExceptions(self): - """ - Unit-test for testing detranslify's exceptions - """ - # for Python 2.x non-unicode detranslify should raise exception - if six.PY2: - self.assertRaises(ValueError, pytils.translit.detranslify, "тест".encode('utf8')) - def testSlug(self): """ Unit-test for slugs @@ -74,14 +65,6 @@ def testSlug(self): self.ckSlug("me&you", 'me-and-you') self.ckSlug("и еще один тест", 'i-esche-odin-test') - def testSlugExceptions(self): - """ - Unit-test for testing slugify's exceptions - """ - # for Python 2.x non-unicode slugify should raise exception - if six.PY2: - self.assertRaises(ValueError, pytils.translit.slugify, "тест".encode('utf8')) - def testTranslifyAdditionalUnicodeSymbols(self): """ Unit-test for testing additional unicode symbols diff --git a/pytils/test/test_typo.py b/pytils/test/test_typo.py index 7650f0c..55b6a31 100644 --- a/pytils/test/test_typo.py +++ b/pytils/test/test_typo.py @@ -3,7 +3,6 @@ Unit-tests for pytils.typo """ -from __future__ import unicode_literals import unittest import os from pytils import typo diff --git a/pytils/test/test_utils.py b/pytils/test/test_utils.py index 253b56a..321a38a 100644 --- a/pytils/test/test_utils.py +++ b/pytils/test/test_utils.py @@ -3,13 +3,11 @@ Unit-tests for pytils.utils """ -from __future__ import unicode_literals import unittest import pytils import decimal - class ChecksTestCase(unittest.TestCase): """ Test case for check_* utils diff --git a/pytils/third/__init__.py b/pytils/third/__init__.py deleted file mode 100644 index c38a492..0000000 --- a/pytils/third/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -Third-party modules -""" diff --git a/pytils/third/six.py b/pytils/third/six.py deleted file mode 100644 index 85898ec..0000000 --- a/pytils/third/six.py +++ /dev/null @@ -1,577 +0,0 @@ -"""Utilities for writing code that runs on Python 2 and 3""" - -# Copyright (c) 2010-2013 Benjamin Peterson -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -import operator -import sys -import types - -__author__ = "Benjamin Peterson " -__version__ = "1.4.1" - - -# Useful for very coarse version differentiation. -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 - -if PY3: - string_types = str, - integer_types = int, - class_types = type, - text_type = str - binary_type = bytes - - MAXSIZE = sys.maxsize -else: - string_types = basestring, - integer_types = (int, long) - class_types = (type, types.ClassType) - text_type = unicode - binary_type = str - - if sys.platform.startswith("java"): - # Jython always uses 32 bits. - MAXSIZE = int((1 << 31) - 1) - else: - # It's possible to have sizeof(long) != sizeof(Py_ssize_t). - class X(object): - def __len__(self): - return 1 << 31 - try: - len(X()) - except OverflowError: - # 32-bit - MAXSIZE = int((1 << 31) - 1) - else: - # 64-bit - MAXSIZE = int((1 << 63) - 1) - del X - - -def _add_doc(func, doc): - """Add documentation to a function.""" - func.__doc__ = doc - - -def _import_module(name): - """Import module, returning the module after the last dot.""" - __import__(name) - return sys.modules[name] - - -class _LazyDescr(object): - - def __init__(self, name): - self.name = name - - def __get__(self, obj, tp): - result = self._resolve() - setattr(obj, self.name, result) - # This is a bit ugly, but it avoids running this again. - delattr(tp, self.name) - return result - - -class MovedModule(_LazyDescr): - - def __init__(self, name, old, new=None): - super(MovedModule, self).__init__(name) - if PY3: - if new is None: - new = name - self.mod = new - else: - self.mod = old - - def _resolve(self): - return _import_module(self.mod) - - -class MovedAttribute(_LazyDescr): - - def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): - super(MovedAttribute, self).__init__(name) - if PY3: - if new_mod is None: - new_mod = name - self.mod = new_mod - if new_attr is None: - if old_attr is None: - new_attr = name - else: - new_attr = old_attr - self.attr = new_attr - else: - self.mod = old_mod - if old_attr is None: - old_attr = name - self.attr = old_attr - - def _resolve(self): - module = _import_module(self.mod) - return getattr(module, self.attr) - - - -class _MovedItems(types.ModuleType): - """Lazy loading of moved objects""" - - -_moved_attributes = [ - MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), - MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), - MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), - MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), - MovedAttribute("map", "itertools", "builtins", "imap", "map"), - MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("reload_module", "__builtin__", "imp", "reload"), - MovedAttribute("reduce", "__builtin__", "functools"), - MovedAttribute("StringIO", "StringIO", "io"), - MovedAttribute("UserString", "UserString", "collections"), - MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), - MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), - - MovedModule("builtins", "__builtin__"), - MovedModule("configparser", "ConfigParser"), - MovedModule("copyreg", "copy_reg"), - MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), - MovedModule("http_cookies", "Cookie", "http.cookies"), - MovedModule("html_entities", "htmlentitydefs", "html.entities"), - MovedModule("html_parser", "HTMLParser", "html.parser"), - MovedModule("http_client", "httplib", "http.client"), - MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), - MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), - MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), - MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), - MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), - MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), - MovedModule("cPickle", "cPickle", "pickle"), - MovedModule("queue", "Queue"), - MovedModule("reprlib", "repr"), - MovedModule("socketserver", "SocketServer"), - MovedModule("tkinter", "Tkinter"), - MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), - MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), - MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), - MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), - MovedModule("tkinter_tix", "Tix", "tkinter.tix"), - MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), - MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), - MovedModule("tkinter_colorchooser", "tkColorChooser", - "tkinter.colorchooser"), - MovedModule("tkinter_commondialog", "tkCommonDialog", - "tkinter.commondialog"), - MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), - MovedModule("tkinter_font", "tkFont", "tkinter.font"), - MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), - MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", - "tkinter.simpledialog"), - MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), - MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), - MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), - MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), - MovedModule("winreg", "_winreg"), -] -for attr in _moved_attributes: - setattr(_MovedItems, attr.name, attr) -del attr - -moves = sys.modules[__name__ + ".moves"] = _MovedItems(__name__ + ".moves") - - - -class Module_six_moves_urllib_parse(types.ModuleType): - """Lazy loading of moved objects in six.moves.urllib_parse""" - - -_urllib_parse_moved_attributes = [ - MovedAttribute("ParseResult", "urlparse", "urllib.parse"), - MovedAttribute("parse_qs", "urlparse", "urllib.parse"), - MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), - MovedAttribute("urldefrag", "urlparse", "urllib.parse"), - MovedAttribute("urljoin", "urlparse", "urllib.parse"), - MovedAttribute("urlparse", "urlparse", "urllib.parse"), - MovedAttribute("urlsplit", "urlparse", "urllib.parse"), - MovedAttribute("urlunparse", "urlparse", "urllib.parse"), - MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), - MovedAttribute("quote", "urllib", "urllib.parse"), - MovedAttribute("quote_plus", "urllib", "urllib.parse"), - MovedAttribute("unquote", "urllib", "urllib.parse"), - MovedAttribute("unquote_plus", "urllib", "urllib.parse"), - MovedAttribute("urlencode", "urllib", "urllib.parse"), -] -for attr in _urllib_parse_moved_attributes: - setattr(Module_six_moves_urllib_parse, attr.name, attr) -del attr - -sys.modules[__name__ + ".moves.urllib_parse"] = Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse") -sys.modules[__name__ + ".moves.urllib.parse"] = Module_six_moves_urllib_parse(__name__ + ".moves.urllib.parse") - - -class Module_six_moves_urllib_error(types.ModuleType): - """Lazy loading of moved objects in six.moves.urllib_error""" - - -_urllib_error_moved_attributes = [ - MovedAttribute("URLError", "urllib2", "urllib.error"), - MovedAttribute("HTTPError", "urllib2", "urllib.error"), - MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), -] -for attr in _urllib_error_moved_attributes: - setattr(Module_six_moves_urllib_error, attr.name, attr) -del attr - -sys.modules[__name__ + ".moves.urllib_error"] = Module_six_moves_urllib_error(__name__ + ".moves.urllib_error") -sys.modules[__name__ + ".moves.urllib.error"] = Module_six_moves_urllib_error(__name__ + ".moves.urllib.error") - - -class Module_six_moves_urllib_request(types.ModuleType): - """Lazy loading of moved objects in six.moves.urllib_request""" - - -_urllib_request_moved_attributes = [ - MovedAttribute("urlopen", "urllib2", "urllib.request"), - MovedAttribute("install_opener", "urllib2", "urllib.request"), - MovedAttribute("build_opener", "urllib2", "urllib.request"), - MovedAttribute("pathname2url", "urllib", "urllib.request"), - MovedAttribute("url2pathname", "urllib", "urllib.request"), - MovedAttribute("getproxies", "urllib", "urllib.request"), - MovedAttribute("Request", "urllib2", "urllib.request"), - MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), - MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), - MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), - MovedAttribute("BaseHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), - MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), - MovedAttribute("FileHandler", "urllib2", "urllib.request"), - MovedAttribute("FTPHandler", "urllib2", "urllib.request"), - MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), - MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), - MovedAttribute("urlretrieve", "urllib", "urllib.request"), - MovedAttribute("urlcleanup", "urllib", "urllib.request"), - MovedAttribute("URLopener", "urllib", "urllib.request"), - MovedAttribute("FancyURLopener", "urllib", "urllib.request"), -] -for attr in _urllib_request_moved_attributes: - setattr(Module_six_moves_urllib_request, attr.name, attr) -del attr - -sys.modules[__name__ + ".moves.urllib_request"] = Module_six_moves_urllib_request(__name__ + ".moves.urllib_request") -sys.modules[__name__ + ".moves.urllib.request"] = Module_six_moves_urllib_request(__name__ + ".moves.urllib.request") - - -class Module_six_moves_urllib_response(types.ModuleType): - """Lazy loading of moved objects in six.moves.urllib_response""" - - -_urllib_response_moved_attributes = [ - MovedAttribute("addbase", "urllib", "urllib.response"), - MovedAttribute("addclosehook", "urllib", "urllib.response"), - MovedAttribute("addinfo", "urllib", "urllib.response"), - MovedAttribute("addinfourl", "urllib", "urllib.response"), -] -for attr in _urllib_response_moved_attributes: - setattr(Module_six_moves_urllib_response, attr.name, attr) -del attr - -sys.modules[__name__ + ".moves.urllib_response"] = Module_six_moves_urllib_response(__name__ + ".moves.urllib_response") -sys.modules[__name__ + ".moves.urllib.response"] = Module_six_moves_urllib_response(__name__ + ".moves.urllib.response") - - -class Module_six_moves_urllib_robotparser(types.ModuleType): - """Lazy loading of moved objects in six.moves.urllib_robotparser""" - - -_urllib_robotparser_moved_attributes = [ - MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), -] -for attr in _urllib_robotparser_moved_attributes: - setattr(Module_six_moves_urllib_robotparser, attr.name, attr) -del attr - -sys.modules[__name__ + ".moves.urllib_robotparser"] = Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib_robotparser") -sys.modules[__name__ + ".moves.urllib.robotparser"] = Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser") - - -class Module_six_moves_urllib(types.ModuleType): - """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" - parse = sys.modules[__name__ + ".moves.urllib_parse"] - error = sys.modules[__name__ + ".moves.urllib_error"] - request = sys.modules[__name__ + ".moves.urllib_request"] - response = sys.modules[__name__ + ".moves.urllib_response"] - robotparser = sys.modules[__name__ + ".moves.urllib_robotparser"] - - -sys.modules[__name__ + ".moves.urllib"] = Module_six_moves_urllib(__name__ + ".moves.urllib") - - -def add_move(move): - """Add an item to six.moves.""" - setattr(_MovedItems, move.name, move) - - -def remove_move(name): - """Remove item from six.moves.""" - try: - delattr(_MovedItems, name) - except AttributeError: - try: - del moves.__dict__[name] - except KeyError: - raise AttributeError("no such move, %r" % (name,)) - - -if PY3: - _meth_func = "__func__" - _meth_self = "__self__" - - _func_closure = "__closure__" - _func_code = "__code__" - _func_defaults = "__defaults__" - _func_globals = "__globals__" - - _iterkeys = "keys" - _itervalues = "values" - _iteritems = "items" - _iterlists = "lists" -else: - _meth_func = "im_func" - _meth_self = "im_self" - - _func_closure = "func_closure" - _func_code = "func_code" - _func_defaults = "func_defaults" - _func_globals = "func_globals" - - _iterkeys = "iterkeys" - _itervalues = "itervalues" - _iteritems = "iteritems" - _iterlists = "iterlists" - - -try: - advance_iterator = next -except NameError: - def advance_iterator(it): - return it.next() -next = advance_iterator - - -try: - callable = callable -except NameError: - def callable(obj): - return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) - - -if PY3: - def get_unbound_function(unbound): - return unbound - - create_bound_method = types.MethodType - - Iterator = object -else: - def get_unbound_function(unbound): - return unbound.im_func - - def create_bound_method(func, obj): - return types.MethodType(func, obj, obj.__class__) - - class Iterator(object): - - def next(self): - return type(self).__next__(self) - - callable = callable -_add_doc(get_unbound_function, - """Get the function out of a possibly unbound function""") - - -get_method_function = operator.attrgetter(_meth_func) -get_method_self = operator.attrgetter(_meth_self) -get_function_closure = operator.attrgetter(_func_closure) -get_function_code = operator.attrgetter(_func_code) -get_function_defaults = operator.attrgetter(_func_defaults) -get_function_globals = operator.attrgetter(_func_globals) - - -def iterkeys(d, **kw): - """Return an iterator over the keys of a dictionary.""" - return iter(getattr(d, _iterkeys)(**kw)) - -def itervalues(d, **kw): - """Return an iterator over the values of a dictionary.""" - return iter(getattr(d, _itervalues)(**kw)) - -def iteritems(d, **kw): - """Return an iterator over the (key, value) pairs of a dictionary.""" - return iter(getattr(d, _iteritems)(**kw)) - -def iterlists(d, **kw): - """Return an iterator over the (key, [values]) pairs of a dictionary.""" - return iter(getattr(d, _iterlists)(**kw)) - - -if PY3: - def b(s): - return s.encode("latin-1") - def u(s): - return s - unichr = chr - if sys.version_info[1] <= 1: - def int2byte(i): - return bytes((i,)) - else: - # This is about 2x faster than the implementation above on 3.2+ - int2byte = operator.methodcaller("to_bytes", 1, "big") - byte2int = operator.itemgetter(0) - indexbytes = operator.getitem - iterbytes = iter - import io - StringIO = io.StringIO - BytesIO = io.BytesIO -else: - def b(s): - return s - def u(s): - return unicode(s, "unicode_escape") - unichr = unichr - int2byte = chr - def byte2int(bs): - return ord(bs[0]) - def indexbytes(buf, i): - return ord(buf[i]) - def iterbytes(buf): - return (ord(byte) for byte in buf) - import StringIO - StringIO = BytesIO = StringIO.StringIO -_add_doc(b, """Byte literal""") -_add_doc(u, """Text literal""") - - -if PY3: - import builtins - exec_ = getattr(builtins, "exec") - - - def reraise(tp, value, tb=None): - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - - - print_ = getattr(builtins, "print") - del builtins - -else: - def exec_(_code_, _globs_=None, _locs_=None): - """Execute code in a namespace.""" - if _globs_ is None: - frame = sys._getframe(1) - _globs_ = frame.f_globals - if _locs_ is None: - _locs_ = frame.f_locals - del frame - elif _locs_ is None: - _locs_ = _globs_ - exec("""exec _code_ in _globs_, _locs_""") - - - exec_("""def reraise(tp, value, tb=None): - raise tp, value, tb -""") - - - def print_(*args, **kwargs): - """The new-style print function.""" - fp = kwargs.pop("file", sys.stdout) - if fp is None: - return - def write(data): - if not isinstance(data, basestring): - data = str(data) - fp.write(data) - want_unicode = False - sep = kwargs.pop("sep", None) - if sep is not None: - if isinstance(sep, unicode): - want_unicode = True - elif not isinstance(sep, str): - raise TypeError("sep must be None or a string") - end = kwargs.pop("end", None) - if end is not None: - if isinstance(end, unicode): - want_unicode = True - elif not isinstance(end, str): - raise TypeError("end must be None or a string") - if kwargs: - raise TypeError("invalid keyword arguments to print()") - if not want_unicode: - for arg in args: - if isinstance(arg, unicode): - want_unicode = True - break - if want_unicode: - newline = unicode("\n") - space = unicode(" ") - else: - newline = "\n" - space = " " - if sep is None: - sep = space - if end is None: - end = newline - for i, arg in enumerate(args): - if i: - write(sep) - write(arg) - write(end) - -_add_doc(reraise, """Reraise an exception.""") - - -def with_metaclass(meta, *bases): - """Create a base class with a metaclass.""" - return meta("NewBase", bases, {}) - -def add_metaclass(metaclass): - """Class decorator for creating a class with a metaclass.""" - def wrapper(cls): - orig_vars = cls.__dict__.copy() - orig_vars.pop('__dict__', None) - orig_vars.pop('__weakref__', None) - for slots_var in orig_vars.get('__slots__', ()): - orig_vars.pop(slots_var) - return metaclass(cls.__name__, cls.__bases__, orig_vars) - return wrapper diff --git a/pytils/translit.py b/pytils/translit.py index 7424b04..96d57ef 100644 --- a/pytils/translit.py +++ b/pytils/translit.py @@ -4,10 +4,7 @@ Simple transliteration """ -from __future__ import unicode_literals - import re -from pytils.third import six TRANSTABLE = ( ("'", "'"), @@ -175,10 +172,10 @@ def detranslify(in_string): @raise ValueError: if in_string is C{str}, but it isn't ascii """ try: - russian = six.text_type(in_string) + russian = str(in_string) except UnicodeDecodeError: - raise ValueError("We expects if in_string is 8-bit string," + \ - "then it consists only ASCII chars, but now it doesn't. " + \ + raise ValueError("We expects if in_string is 8-bit string," + + "then it consists only ASCII chars, but now it doesn't. " + "Use unicode in this case.") for symb_out, symb_in in TRANSTABLE: @@ -202,17 +199,17 @@ def slugify(in_string): @raise ValueError: if in_string is C{str}, but it isn't ascii """ try: - u_in_string = six.text_type(in_string).lower() + u_in_string = str(in_string).lower() except UnicodeDecodeError: - raise ValueError("We expects when in_string is str type," + \ - "it is an ascii, but now it isn't. Use unicode " + \ + raise ValueError("We expects when in_string is str type," + + "it is an ascii, but now it isn't. Use unicode " + "in this case.") # convert & to "and" - u_in_string = re.sub(r'\&\;|\&', ' and ', u_in_string) + u_in_string = re.sub(r'&|&', ' and ', u_in_string) # replace spaces by hyphen u_in_string = re.sub(r'[-\s]+', '-', u_in_string) # remove symbols that not in alphabet - u_in_string = ''.join([symb for symb in u_in_string if symb in ALPHABET]) + u_in_string = ''.join(symb for symb in u_in_string if symb in ALPHABET) # translify it out_string = translify(u_in_string) # remove non-alpha diff --git a/pytils/typo.py b/pytils/typo.py index 346dd49..88f7d41 100644 --- a/pytils/typo.py +++ b/pytils/typo.py @@ -4,13 +4,10 @@ Russian typography """ -from __future__ import unicode_literals import re import os import collections -from pytils.third import six - def _sub_patterns(patterns, text): """ @@ -170,7 +167,7 @@ def _get_rule_by_name(name): return rule def _resolve_rule_name(rule_or_name, forced_name=None): - if isinstance(rule_or_name, six.string_types): + if isinstance(rule_or_name, str): # got name name = rule_or_name rule = _get_rule_by_name(name) @@ -241,7 +238,7 @@ def __init__(self, *args, **kwargs): expanded_args += list(arg) elif isinstance(arg, dict): expanded_kwargs.update(arg) - elif isinstance(arg, six.string_types) or isinstance(arg, collections.Callable): + elif isinstance(arg, str) or isinstance(arg, collections.Callable): expanded_args.append(arg) else: raise TypeError( @@ -249,7 +246,7 @@ def __init__(self, *args, **kwargs): " dict, str or callable, not %s" % (arg, type(arg).__name__)) for kw, arg in list(kwargs.items()): - if isinstance(arg, six.string_types) or isinstance(arg, collections.Callable): + if isinstance(arg, str) or isinstance(arg, collections.Callable): expanded_kwargs[kw] = arg else: raise TypeError( diff --git a/pytils/utils.py b/pytils/utils.py index c10d209..02a3d1e 100644 --- a/pytils/utils.py +++ b/pytils/utils.py @@ -4,10 +4,6 @@ Misc utils for internal use """ -from __future__ import unicode_literals - -from pytils.third import six - def check_length(value, length): """ @@ -59,9 +55,8 @@ def split_values(ustring, sep=','): @return: tuple of splitted elements """ - assert isinstance(ustring, six.text_type), "uvalue must be unicode, not %s" % type(ustring) + assert isinstance(ustring, str), "uvalue must be str, not %s" % type(ustring) # unicode have special mark symbol 0xffff which cannot be used in a regular text, # so we use it to mark a place where escaped column was - ustring_marked = ustring.replace('\,', '\uffff') - items = tuple([i.strip().replace('\uffff', ',') for i in ustring_marked.split(sep)]) - return items + ustring_marked = ustring.replace(r'\,', '\uffff') + return tuple(i.strip().replace('\uffff', ',') for i in ustring_marked.split(sep)) diff --git a/setup.py b/setup.py index 15588a7..a5c0ea2 100755 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ else: from distutils.core import setup -version = "0.3.1" +version = "0.3.2" setup_data = { 'name': 'pytils', @@ -24,7 +24,7 @@ 'long_description': """Simple tools for processing strings in russian (choose proper form for plurals, in-words representation of numerals, dates in russian without locales, transliteration, etc)""", - 'packages': ['pytils', 'pytils.templatetags', 'pytils.test', 'pytils.test.templatetags', 'pytils.third'], + 'packages': ['pytils', 'pytils.templatetags', 'pytils.test', 'pytils.test.templatetags'], 'license': "MIT", 'platforms': "All", 'classifiers': [ @@ -33,10 +33,10 @@ 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', 'Natural Language :: Russian', 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', diff --git a/tox.ini b/tox.ini index 853e3d3..1f05c1e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py{27,34,35,36,37}-django11,py{34,35,36,37}-django20,py{35,36,37}-django2{1,2} +envlist = py{35,36,37,38}-django11,py{35,36,37,38}-django20,py{35,36,37,38}-django2{1,2},py{36,37,38}-django30 [testenv] setenv = @@ -9,14 +9,14 @@ commands = {envpython} doc/examples-django/pytilsex/manage.py test --where=doc/examples-django/pytilsex/ --verbosity=2 {envpython} doc/examples/test.py --verbosity=2 -d basepython = - py27: python2.7 - py34: python3.4 py35: python3.5 py36: python3.6 py37: python3.7 + py38: python3.8 deps = django-nose django11: Django>=1.11,<2.0 django20: Django>=2.0,<2.1 django21: Django>=2.1,<2.2 django22: Django>=2.2,<3.0 + django30: Django>=3.0,<3.1