diff options
author | Aarni Koskela <akx@iki.fi> | 2023-01-19 10:43:08 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-19 10:43:08 +0200 |
commit | cf405e2836bbcc32aaeaa6b7a7cc7bbabe873019 (patch) | |
tree | c75005ebf3ac8b79a6058da9823331f7d3d3765e | |
parent | 6e02940868a73cbcf3cc86077fc83c7cb21a4780 (diff) | |
parent | d14f9565c03ba10d493437784db439ca260ba69d (diff) | |
download | babel-cf405e2836bbcc32aaeaa6b7a7cc7bbabe873019.tar.gz |
Merge pull request #949 from python-babel/ruffify
Add ruff for linting
47 files changed, 785 insertions, 709 deletions
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b61dac4..4c3eb9c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,4 +1,11 @@ repos: + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.224 + hooks: + - id: ruff + args: + - --fix + - --force-exclude - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: diff --git a/babel/core.py b/babel/core.py index 5041c1b..ce564d7 100644 --- a/babel/core.py +++ b/babel/core.py @@ -46,6 +46,7 @@ if TYPE_CHECKING: _global_data = None _default_plural_rule = PluralRule({}) + def _raise_no_data_error(): raise RuntimeError('The babel data files are not available. ' 'This usually happens because you are using ' @@ -383,10 +384,12 @@ class Locale: for key in ('language', 'territory', 'script', 'variant'): if not hasattr(other, key): return False - return (self.language == getattr(other, 'language')) and \ - (self.territory == getattr(other, 'territory')) and \ - (self.script == getattr(other, 'script')) and \ - (self.variant == getattr(other, 'variant')) + return ( + self.language == getattr(other, 'language') and # noqa: B009 + self.territory == getattr(other, 'territory') and # noqa: B009 + self.script == getattr(other, 'script') and # noqa: B009 + self.variant == getattr(other, 'variant') # noqa: B009 + ) def __ne__(self, other: object) -> bool: return not self.__eq__(other) diff --git a/babel/dates.py b/babel/dates.py index 51bc7ff..e626df5 100644 --- a/babel/dates.py +++ b/babel/dates.py @@ -27,9 +27,9 @@ except ModuleNotFoundError: pytz = None import zoneinfo +import datetime from bisect import bisect_right from collections.abc import Iterable -import datetime from babel import localtime from babel.core import Locale, default_locale, get_global @@ -49,7 +49,7 @@ if TYPE_CHECKING: # empty set characters ( U+2205 )." # - https://www.unicode.org/reports/tr35/tr35-dates.html#Metazone_Names -NO_INHERITANCE_MARKER = u'\u2205\u2205\u2205' +NO_INHERITANCE_MARKER = '\u2205\u2205\u2205' if pytz: @@ -247,13 +247,13 @@ def get_timezone(zone: str | datetime.tzinfo | None = None) -> datetime.tzinfo: if pytz: try: return pytz.timezone(zone) - except pytz.UnknownTimeZoneError as exc: + except pytz.UnknownTimeZoneError as exc: # noqa: F841 pass else: assert zoneinfo try: return zoneinfo.ZoneInfo(zone) - except zoneinfo.ZoneInfoNotFoundError as exc: + except zoneinfo.ZoneInfoNotFoundError as exc: # noqa: F841 pass raise LookupError(f"Unknown timezone {zone}") from exc @@ -558,11 +558,11 @@ def get_timezone_gmt( if return_z and hours == 0 and seconds == 0: return 'Z' elif seconds == 0 and width == 'iso8601_short': - return u'%+03d' % hours + return '%+03d' % hours elif width == 'short' or width == 'iso8601_short': - pattern = u'%+03d%02d' + pattern = '%+03d%02d' elif width == 'iso8601': - pattern = u'%+03d:%02d' + pattern = '%+03d:%02d' else: pattern = locale.zone_formats['gmt'] % '%+03d:%02d' return pattern % (hours, seconds // 60) @@ -1083,10 +1083,10 @@ def format_timedelta( break # This really should not happen if pattern is None: - return u'' + return '' return pattern.replace('{0}', str(value)) - return u'' + return '' def _format_fallback_interval( @@ -1349,8 +1349,7 @@ def parse_date( month_idx = format_str.index('l') day_idx = format_str.index('d') - indexes = [(year_idx, 'Y'), (month_idx, 'M'), (day_idx, 'D')] - indexes.sort() + indexes = sorted([(year_idx, 'Y'), (month_idx, 'M'), (day_idx, 'D')]) indexes = {item[1]: idx for idx, item in enumerate(indexes)} # FIXME: this currently only supports numbers, but should also support month @@ -1399,8 +1398,7 @@ def parse_time( min_idx = format_str.index('m') sec_idx = format_str.index('s') - indexes = [(hour_idx, 'H'), (min_idx, 'M'), (sec_idx, 'S')] - indexes.sort() + indexes = sorted([(hour_idx, 'H'), (min_idx, 'M'), (sec_idx, 'S')]) indexes = {item[1]: idx for idx, item in enumerate(indexes)} # TODO: support time zones @@ -1436,7 +1434,7 @@ class DateTimePattern: return pat def __mod__(self, other: DateTimeFormat) -> str: - if type(other) is not DateTimeFormat: + if not isinstance(other, DateTimeFormat): return NotImplemented return self.format % other @@ -1829,7 +1827,7 @@ def parse_pattern(pattern: str) -> DateTimePattern: :param pattern: the formatting pattern to parse """ - if type(pattern) is DateTimePattern: + if isinstance(pattern, DateTimePattern): return pattern if pattern in _pattern_cache: @@ -1849,7 +1847,7 @@ def parse_pattern(pattern: str) -> DateTimePattern: else: raise NotImplementedError(f"Unknown token type: {tok_type}") - _pattern_cache[pattern] = pat = DateTimePattern(pattern, u''.join(result)) + _pattern_cache[pattern] = pat = DateTimePattern(pattern, ''.join(result)) return pat @@ -1884,7 +1882,7 @@ def tokenize_pattern(pattern: str) -> list[tuple[str, str | tuple[str, int]]]: fieldchar[0] = '' fieldnum[0] = 0 - for idx, char in enumerate(pattern.replace("''", '\0')): + for char in pattern.replace("''", '\0'): if quotebuf is None: if char == "'": # quote started if fieldchar[0]: diff --git a/babel/localtime/__init__.py b/babel/localtime/__init__.py index 9d227c7..1d65fb2 100644 --- a/babel/localtime/__init__.py +++ b/babel/localtime/__init__.py @@ -9,9 +9,9 @@ :license: BSD, see LICENSE for more details. """ +import datetime import sys import time -import datetime from threading import RLock if sys.platform == 'win32': diff --git a/babel/localtime/_helpers.py b/babel/localtime/_helpers.py index b7238f6..159f9a5 100644 --- a/babel/localtime/_helpers.py +++ b/babel/localtime/_helpers.py @@ -24,6 +24,7 @@ def _get_tzinfo(tzenv: str): return None + def _get_tzinfo_or_raise(tzenv: str): tzinfo = _get_tzinfo(tzenv) if tzinfo is None: diff --git a/babel/localtime/_unix.py b/babel/localtime/_unix.py index 89b461a..eb81beb 100644 --- a/babel/localtime/_unix.py +++ b/babel/localtime/_unix.py @@ -1,14 +1,14 @@ +import datetime import os import re -import datetime - from babel.localtime._helpers import ( + _get_tzinfo, _get_tzinfo_from_file, _get_tzinfo_or_raise, - _get_tzinfo, ) + def _tz_from_env(tzenv: str) -> datetime.tzinfo: if tzenv[0] == ':': tzenv = tzenv[1:] diff --git a/babel/localtime/_win32.py b/babel/localtime/_win32.py index 42f819a..1a52567 100644 --- a/babel/localtime/_win32.py +++ b/babel/localtime/_win32.py @@ -6,9 +6,10 @@ except ImportError: winreg = None import datetime +from typing import Any, Dict, cast + from babel.core import get_global from babel.localtime._helpers import _get_tzinfo_or_raise -from typing import Any, Dict, cast # When building the cldr data on windows this module gets imported. # Because at that point there is no global.dat yet this call will diff --git a/babel/messages/catalog.py b/babel/messages/catalog.py index 4486bec..dead4aa 100644 --- a/babel/messages/catalog.py +++ b/babel/messages/catalog.py @@ -9,21 +9,20 @@ """ from __future__ import annotations +import datetime import re - from collections import OrderedDict -from collections.abc import Generator, Iterable, Iterator -import datetime +from collections.abc import Iterable, Iterator +from copy import copy from difflib import get_close_matches from email import message_from_string -from copy import copy from typing import TYPE_CHECKING from babel import __version__ as VERSION from babel.core import Locale, UnknownLocaleError from babel.dates import format_datetime from babel.messages.plurals import get_plural -from babel.util import distinct, LOCALTZ, FixedOffsetTimezone, _cmp +from babel.util import LOCALTZ, FixedOffsetTimezone, _cmp, distinct if TYPE_CHECKING: from typing_extensions import TypeAlias @@ -81,7 +80,7 @@ class Message: def __init__( self, id: _MessageID, - string: _MessageID | None = u'', + string: _MessageID | None = '', locations: Iterable[tuple[str, int]] = (), flags: Iterable[str] = (), auto_comments: Iterable[str] = (), @@ -108,7 +107,7 @@ class Message: """ self.id = id if not string and self.pluralizable: - string = (u'', u'') + string = ('', '') self.string = string self.locations = list(distinct(locations)) self.flags = set(flags) @@ -234,13 +233,14 @@ class TranslationError(Exception): translations are encountered.""" -DEFAULT_HEADER = u"""\ +DEFAULT_HEADER = """\ # Translations template for PROJECT. # Copyright (C) YEAR ORGANIZATION # This file is distributed under the same license as the PROJECT project. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. #""" + def parse_separated_header(value: str) -> dict[str, str]: # Adapted from https://peps.python.org/pep-0594/#cgi from email.message import Message @@ -445,7 +445,7 @@ class Catalog: value = self._force_text(value, encoding=self.charset) if name == 'project-id-version': parts = value.split(' ') - self.project = u' '.join(parts[:-1]) + self.project = ' '.join(parts[:-1]) self.version = parts[-1] elif name == 'report-msgid-bugs-to': self.msgid_bugs_address = value @@ -592,7 +592,7 @@ class Catalog: flags = set() if self.fuzzy: flags |= {'fuzzy'} - yield Message(u'', '\n'.join(buf), flags=flags) + yield Message('', '\n'.join(buf), flags=flags) for key in self._messages: yield self._messages[key] @@ -737,7 +737,8 @@ class Catalog: if key in self._messages: del self._messages[key] - def update(self, + def update( + self, template: Catalog, no_fuzzy_matching: bool = False, update_header_comment: bool = False, @@ -832,7 +833,7 @@ class Catalog: if not isinstance(message.string, (list, tuple)): fuzzy = True message.string = tuple( - [message.string] + ([u''] * (len(message.id) - 1)) + [message.string] + ([''] * (len(message.id) - 1)) ) elif len(message.string) != self.num_plurals: fuzzy = True @@ -842,7 +843,7 @@ class Catalog: message.string = message.string[0] message.flags |= oldmsg.flags if fuzzy: - message.flags |= {u'fuzzy'} + message.flags |= {'fuzzy'} self[message.id] = message for message in template: diff --git a/babel/messages/checkers.py b/babel/messages/checkers.py index 00b84e5..38a26e8 100644 --- a/babel/messages/checkers.py +++ b/babel/messages/checkers.py @@ -13,8 +13,7 @@ from __future__ import annotations from collections.abc import Callable -from babel.messages.catalog import Catalog, Message, TranslationError, PYTHON_FORMAT - +from babel.messages.catalog import PYTHON_FORMAT, Catalog, Message, TranslationError #: list of format chars that are compatible to each other _string_format_compatibilities = [ @@ -111,7 +110,7 @@ def _validate_format(format: str, alternative: str) -> None: def _check_positional(results: list[tuple[str, str]]) -> bool: positional = None - for name, char in results: + for name, _char in results: if positional is None: positional = name is None else: diff --git a/babel/messages/extract.py b/babel/messages/extract.py index a426510..453742e 100644 --- a/babel/messages/extract.py +++ b/babel/messages/extract.py @@ -18,21 +18,29 @@ from __future__ import annotations import ast -from collections.abc import Callable, Collection, Generator, Iterable, Mapping, MutableSequence import io import os import sys +from collections.abc import ( + Callable, + Collection, + Generator, + Iterable, + Mapping, + MutableSequence, +) from os.path import relpath -from tokenize import generate_tokens, COMMENT, NAME, OP, STRING -from typing import Any, TYPE_CHECKING +from textwrap import dedent +from tokenize import COMMENT, NAME, OP, STRING, generate_tokens +from typing import TYPE_CHECKING, Any from babel.util import parse_encoding, parse_future_flags, pathmatch -from textwrap import dedent if TYPE_CHECKING: from typing import IO, Protocol - from typing_extensions import Final, TypeAlias, TypedDict + from _typeshed import SupportsItems, SupportsRead, SupportsReadline + from typing_extensions import Final, TypeAlias, TypedDict class _PyOptions(TypedDict, total=False): encoding: str @@ -82,7 +90,6 @@ DEFAULT_KEYWORDS: dict[str, _Keyword] = { DEFAULT_MAPPING: list[tuple[str, str]] = [('**.py', 'python')] - def _strip_comment_tags(comments: MutableSequence[str], tags: Iterable[str]): """Helper function for `extract` that strips comment tags from strings in a list of comment lines. This functions operates in-place. @@ -652,8 +659,7 @@ def extract_javascript( token = Token('operator', ')', token.lineno) if options.get('parse_template_string') and not funcname and token.type == 'template_string': - for item in parse_template_string(token.value, keywords, comment_tags, options, token.lineno): - yield item + yield from parse_template_string(token.value, keywords, comment_tags, options, token.lineno) elif token.type == 'operator' and token.value == '(': if funcname: @@ -786,8 +792,7 @@ def parse_template_string( if level == 0 and expression_contents: expression_contents = expression_contents[0:-1] fake_file_obj = io.BytesIO(expression_contents.encode()) - for item in extract_javascript(fake_file_obj, keywords, comment_tags, options, lineno): - yield item + yield from extract_javascript(fake_file_obj, keywords, comment_tags, options, lineno) lineno += len(line_re.findall(expression_contents)) expression_contents = '' prev_character = character diff --git a/babel/messages/frontend.py b/babel/messages/frontend.py index c7e921d..ab094ec 100644 --- a/babel/messages/frontend.py +++ b/babel/messages/frontend.py @@ -8,6 +8,7 @@ :license: BSD, see LICENSE for more details. """ +import datetime import fnmatch import logging import optparse @@ -18,14 +19,19 @@ import sys import tempfile from collections import OrderedDict from configparser import RawConfigParser -import datetime from io import StringIO +from typing import Iterable -from babel import __version__ as VERSION from babel import Locale, localedata +from babel import __version__ as VERSION from babel.core import UnknownLocaleError -from babel.messages.catalog import Catalog, DEFAULT_HEADER -from babel.messages.extract import DEFAULT_KEYWORDS, DEFAULT_MAPPING, check_and_call_extract_file, extract_from_dir +from babel.messages.catalog import DEFAULT_HEADER, Catalog +from babel.messages.extract import ( + DEFAULT_KEYWORDS, + DEFAULT_MAPPING, + check_and_call_extract_file, + extract_from_dir, +) from babel.messages.mofile import write_mo from babel.messages.pofile import read_po, write_po from babel.util import LOCALTZ @@ -38,15 +44,16 @@ try: distutils_log = log # "distutils.log → (no replacement yet)" try: - from setuptools.errors import OptionError, SetupError, BaseError + from setuptools.errors import BaseError, OptionError, SetupError except ImportError: # Error aliases only added in setuptools 59 (2021-11). OptionError = SetupError = BaseError = Exception except ImportError: from distutils import log as distutils_log from distutils.cmd import Command as _Command - from distutils.errors import DistutilsOptionError as OptionError, DistutilsSetupError as SetupError, DistutilsError as BaseError - + from distutils.errors import DistutilsError as BaseError + from distutils.errors import DistutilsOptionError as OptionError + from distutils.errors import DistutilsSetupError as SetupError def listify_value(arg, split=None): @@ -188,7 +195,7 @@ class compile_catalog(Command): def run(self): n_errors = 0 for domain in self.domain: - for catalog, errors in self._run_domain(domain).items(): + for errors in self._run_domain(domain).values(): n_errors += len(errors) if n_errors: self.log.error('%d errors encountered.', n_errors) @@ -472,6 +479,27 @@ class extract_messages(Command): else: self.directory_filter = None + def _build_callback(self, path: str): + def callback(filename: str, method: str, options: dict): + if method == 'ignore': + return + + # If we explicitly provide a full filepath, just use that. + # Otherwise, path will be the directory path and filename + # is the relative path from that dir to the file. + # So we can join those to get the full filepath. + if os.path.isfile(path): + filepath = path + else: + filepath = os.path.normpath(os.path.join(path, filename)) + + optstr = '' + if options: + opt_values = ", ".join(f'{k}="{v}"' for k, v in options.items()) + optstr = f" ({opt_values})" + self.log.info('extracting messages from %s%s', filepath, optstr) + return callback + def run(self): mappings = self._get_mappings() with open(self.output_file, 'wb') as outfile: @@ -483,25 +511,7 @@ class extract_messages(Command): header_comment=(self.header_comment or DEFAULT_HEADER)) for path, method_map, options_map in mappings: - def callback(filename, method, options): - if method == 'ignore': - return - - # If we explicitly provide a full filepath, just use that. - # Otherwise, path will be the directory path and filename - # is the relative path from that dir to the file. - # So we can join those to get the full filepath. - if os.path.isfile(path): - filepath = path - else: - filepath = os.path.normpath(os.path.join(path, filename)) - - optstr = '' - if options: - opt_values = ", ".join(f'{k}="{v}"' for k, v in options.items()) - optstr = f" ({opt_values})" - self.log.info('extracting messages from %s%s', filepath, optstr) - + callback = self._build_callback(path) if os.path.isfile(path): current_dir = os.getcwd() extracted = check_and_call_extract_file( @@ -842,7 +852,7 @@ class update_catalog(Command): omit_header=self.omit_header, ignore_obsolete=self.ignore_obsolete, include_previous=self.previous, width=self.width) - except: + except Exception: os.remove(tmpname) raise @@ -937,7 +947,7 @@ class CommandLineInterface: identifiers = localedata.locale_identifiers() longest = max(len(identifier) for identifier in identifiers) identifiers.sort() - format = u'%%-%ds %%s' % (longest + 1) + format = '%%-%ds %%s' % (longest + 1) for identifier in identifiers: locale = Locale.parse(identifier) print(format % (identifier, locale.english_name)) @@ -1105,7 +1115,7 @@ def parse_mapping(fileobj, filename=None): return method_map, options_map -def parse_keywords(strings=[]): +def parse_keywords(strings: Iterable[str] = ()): """Parse keywords specifications from the given list of strings. >>> kw = sorted(parse_keywords(['_', 'dgettext:2', 'dngettext:2,3', 'pgettext:1c,2']).items()) diff --git a/babel/messages/jslexer.py b/babel/messages/jslexer.py index 07fffde..0563f62 100644 --- a/babel/messages/jslexer.py +++ b/babel/messages/jslexer.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ babel.messages.jslexer ~~~~~~~~~~~~~~~~~~~~~~ @@ -11,9 +10,8 @@ """ from __future__ import annotations -from collections import namedtuple -from collections.abc import Generator, Iterator, Sequence import re +from collections.abc import Generator from typing import NamedTuple operators: list[str] = sorted([ @@ -34,11 +32,13 @@ line_join_re = re.compile(r'\\' + line_re.pattern) uni_escape_re = re.compile(r'[a-fA-F0-9]{1,4}') hex_escape_re = re.compile(r'[a-fA-F0-9]{1,2}') + class Token(NamedTuple): type: str value: str lineno: int + _rules: list[tuple[str | None, re.Pattern[str]]] = [ (None, re.compile(r'\s+', re.UNICODE)), (None, re.compile(r'<!--.*')), @@ -102,7 +102,7 @@ def unquote_string(string: str) -> str: add = result.append pos = 0 - while 1: + while True: # scan for the next escape escape_pos = string.find('\\', pos) if escape_pos < 0: @@ -155,7 +155,7 @@ def unquote_string(string: str) -> str: if pos < len(string): add(string[pos:]) - return u''.join(result) + return ''.join(result) def tokenize(source: str, jsx: bool = True, dotted: bool = True, template_string: bool = True, lineno: int = 1) -> Generator[Token, None, None]: @@ -174,7 +174,7 @@ def tokenize(source: str, jsx: bool = True, dotted: bool = True, template_string while pos < end: # handle regular rules first - for token_type, rule in rules: + for token_type, rule in rules: # noqa: B007 match = rule.match(source, pos) if match is not None: break diff --git a/babel/messages/mofile.py b/babel/messages/mofile.py index a96f059..0a432a7 100644 --- a/babel/messages/mofile.py +++ b/babel/messages/mofile.py @@ -55,7 +55,7 @@ def read_mo(fileobj: SupportsRead[bytes]) -> Catalog: # Now put all messages from the .mo file buffer into the catalog # dictionary - for i in range(0, msgcount): + for _i in range(msgcount): mlen, moff = unpack(ii, buf[origidx:origidx + 8]) mend = moff + mlen tlen, toff = unpack(ii, buf[transidx:transidx + 8]) diff --git a/babel/messages/plurals.py b/babel/messages/plurals.py index 0fdf53b..eb8de47 100644 --- a/babel/messages/plurals.py +++ b/babel/messages/plurals.py @@ -9,9 +9,9 @@ """ from __future__ import annotations -from babel.core import default_locale, Locale from operator import itemgetter +from babel.core import Locale, default_locale # XXX: remove this file, duplication with babel.plural diff --git a/babel/messages/pofile.py b/babel/messages/pofile.py index b6d0d6e..aef8cbf 100644 --- a/babel/messages/pofile.py +++ b/babel/messages/pofile.py @@ -14,14 +14,15 @@ import os import re from collections.abc import Iterable from typing import TYPE_CHECKING -from babel.core import Locale +from babel.core import Locale from babel.messages.catalog import Catalog, Message -from babel.util import wraptext, _cmp +from babel.util import _cmp, wraptext if TYPE_CHECKING: - from _typeshed import SupportsWrite from typing import IO, AnyStr + + from _typeshed import SupportsWrite from typing_extensions import Literal @@ -133,7 +134,6 @@ class _NormalizedString: return self.__cmp__(other) != 0 - class PoFileParser: """Support class to read messages from a ``gettext`` PO (portable object) file and add them to a `Catalog` @@ -183,7 +183,7 @@ class PoFileParser: string = ['' for _ in range(self.catalog.num_plurals)] for idx, translation in self.translations: if idx >= self.catalog.num_plurals: - self._invalid_pofile(u"", self.offset, "msg has more translations than num_plurals of catalog") + self._invalid_pofile("", self.offset, "msg has more translations than num_plurals of catalog") continue string[idx] = translation.denormalize() string = tuple(string) @@ -319,8 +319,8 @@ class PoFileParser: # No actual messages found, but there was some info in comments, from which # we'll construct an empty header message if not self.counter and (self.flags or self.user_comments or self.auto_comments): - self.messages.append(_NormalizedString(u'""')) - self.translations.append([0, _NormalizedString(u'""')]) + self.messages.append(_NormalizedString('""')) + self.translations.append([0, _NormalizedString('""')]) self._add_message() def _invalid_pofile(self, line, lineno, msg) -> None: @@ -451,17 +451,17 @@ def normalize(string: str, prefix: str = '', width: int = 76) -> str: buf = [] size = 2 while chunks: - l = len(escape(chunks[-1])) - 2 + prefixlen - if size + l < width: + length = len(escape(chunks[-1])) - 2 + prefixlen + if size + length < width: buf.append(chunks.pop()) - size += l + size += length else: if not buf: # handle long chunks by putting them on a # separate line buf.append(chunks.pop()) break - lines.append(u''.join(buf)) + lines.append(''.join(buf)) else: lines.append(line) else: @@ -474,7 +474,7 @@ def normalize(string: str, prefix: str = '', width: int = 76) -> str: if lines and not lines[-1]: del lines[-1] lines[-1] += '\n' - return u'""\n' + u'\n'.join([(prefix + escape(line)) for line in lines]) + return '""\n' + '\n'.join([(prefix + escape(line)) for line in lines]) def write_po( @@ -585,7 +585,7 @@ def write_po( for line in comment_header.splitlines(): lines += wraptext(line, width=width, subsequent_indent='# ') - comment_header = u'\n'.join(lines) + comment_header = '\n'.join(lines) _write(f"{comment_header}\n") for comment in message.user_comments: @@ -614,11 +614,13 @@ def write_po( locs.append(location) _write_comment(' '.join(locs), prefix=':') if message.flags: - _write('#%s\n' % ', '.join([''] + sorted(message.flags))) + _write(f"#{', '.join(['', *sorted(message.flags)])}\n") if message.previous_id and include_previous: - _write_comment('msgid %s' % _normalize(message.previous_id[0]), - prefix='|') + _write_comment( + f'msgid {_normalize(message.previous_id[0])}', + prefix='|', + ) if len(message.previous_id) > 1: _write_comment('msgid_plural %s' % _normalize( message.previous_id[1] diff --git a/babel/numbers.py b/babel/numbers.py index 5a05f91..399b70b 100644 --- a/babel/numbers.py +++ b/babel/numbers.py @@ -19,11 +19,11 @@ # - https://www.unicode.org/reports/tr35/ (Appendix G.6) from __future__ import annotations +import datetime import decimal import re -from typing import TYPE_CHECKING, Any, overload import warnings -import datetime +from typing import TYPE_CHECKING, Any, overload from babel.core import Locale, default_locale, get_global from babel.localedata import LocaleDataDict @@ -324,7 +324,7 @@ def get_decimal_symbol(locale: Locale | str | None = LC_NUMERIC) -> str: :param locale: the `Locale` object or locale identifier """ - return Locale.parse(locale).number_symbols.get('decimal', u'.') + return Locale.parse(locale).number_symbols.get('decimal', '.') def get_plus_sign_symbol(locale: Locale | str | None = LC_NUMERIC) -> str: @@ -335,7 +335,7 @@ def get_plus_sign_symbol(locale: Locale | str | None = LC_NUMERIC) -> str: :param locale: the `Locale` object or locale identifier """ - return Locale.parse(locale).number_symbols.get('plusSign', u'+') + return Locale.parse(locale).number_symbols.get('plusSign', '+') def get_minus_sign_symbol(locale: Locale | str | None = LC_NUMERIC) -> str: @@ -346,7 +346,7 @@ def get_minus_sign_symbol(locale: Locale | str | None = LC_NUMERIC) -> str: :param locale: the `Locale` object or locale identifier """ - return Locale.parse(locale).number_symbols.get('minusSign', u'-') + return Locale.parse(locale).number_symbols.get('minusSign', '-') def get_exponential_symbol(locale: Locale | str | None = LC_NUMERIC) -> str: @@ -357,7 +357,7 @@ def get_exponential_symbol(locale: Locale | str | None = LC_NUMERIC) -> str: :param locale: the `Locale` object or locale identifier """ - return Locale.parse(locale).number_symbols.get('exponential', u'E') + return Locale.parse(locale).number_symbols.get('exponential', 'E') def get_group_symbol(locale: Locale | str | None = LC_NUMERIC) -> str: @@ -368,11 +368,11 @@ def get_group_symbol(locale: Locale | str | None = LC_NUMERIC) -> str: :param locale: the `Locale` object or locale identifier """ - return Locale.parse(locale).number_symbols.get('group', u',') + return Locale.parse(locale).number_symbols.get('group', ',') def format_number(number: float | decimal.Decimal | str, locale: Locale | str | None = LC_NUMERIC) -> str: - u"""Return the given number formatted for a specific locale. + """Return the given number formatted for a specific locale. >>> format_number(1099, locale='en_US') # doctest: +SKIP u'1,099' @@ -418,7 +418,7 @@ def format_decimal( decimal_quantization: bool = True, group_separator: bool = True, ) -> str: - u"""Return the given decimal number formatted for a specific locale. + """Return the given decimal number formatted for a specific locale. >>> format_decimal(1.2345, locale='en_US') u'1.234' @@ -473,7 +473,7 @@ def format_compact_decimal( locale: Locale | str | None = LC_NUMERIC, fraction_digits: int = 0, ) -> str: - u"""Return the given decimal number formatted for a specific locale in compact form. + """Return the given decimal number formatted for a specific locale in compact form. >>> format_compact_decimal(12345, format_type="short", locale='en_US') u'12K' @@ -555,7 +555,7 @@ def format_currency( decimal_quantization: bool = True, group_separator: bool = True, ) -> str: - u"""Return formatted currency value. + """Return formatted currency value. >>> format_currency(1099.98, 'USD', locale='en_US') u'$1,099.98' @@ -653,7 +653,7 @@ def format_currency( try: pattern = locale.currency_formats[format_type] except KeyError: - raise UnknownCurrencyFormatError(f"{format_type!r} is not a known currency format type") + raise UnknownCurrencyFormatError(f"{format_type!r} is not a known currency format type") from None return pattern.apply( number, locale, currency=currency, currency_digits=currency_digits, @@ -711,7 +711,7 @@ def format_compact_currency( locale: Locale | str | None = LC_NUMERIC, fraction_digits: int = 0 ) -> str: - u"""Format a number as a currency value in compact form. + """Format a number as a currency value in compact form. >>> format_compact_currency(12345, 'USD', locale='en_US') u'$12K' @@ -870,8 +870,8 @@ def parse_number(string: str, locale: Locale | str | None = LC_NUMERIC) -> int: """ try: return int(string.replace(get_group_symbol(locale), '')) - except ValueError: - raise NumberFormatError(f"{string!r} is not a valid number") + except ValueError as ve: + raise NumberFormatError(f"{string!r} is not a valid number") from ve def parse_decimal(string: str, locale: Locale | str | None = LC_NUMERIC, strict: bool = False) -> decimal.Decimal: @@ -916,7 +916,7 @@ def parse_decimal(string: str, locale: Locale | str | None = LC_NUMERIC, strict: decimal_symbol = get_decimal_symbol(locale) if not strict and ( - group_symbol == u'\xa0' and # if the grouping symbol is U+00A0 NO-BREAK SPACE, + group_symbol == '\xa0' and # if the grouping symbol is U+00A0 NO-BREAK SPACE, group_symbol not in string and # and the string to be parsed does not contain it, ' ' in string # but it does contain a space instead, ): @@ -926,20 +926,20 @@ def parse_decimal(string: str, locale: Locale | str | None = LC_NUMERIC, strict: try: parsed = decimal.Decimal(string.replace(group_symbol, '') .replace(decimal_symbol, '.')) - except decimal.InvalidOperation: - raise NumberFormatError(f"{string!r} is not a valid decimal number") + except decimal.InvalidOperation as exc: + raise NumberFormatError(f"{string!r} is not a valid decimal number") from exc if strict and group_symbol in string: proper = format_decimal(parsed, locale=locale, decimal_quantization=False) if string != proper and string.rstrip('0') != (proper + decimal_symbol): try: parsed_alt = decimal.Decimal(string.replace(decimal_symbol, '') .replace(group_symbol, '.')) - except decimal.InvalidOperation: + except decimal.InvalidOperation as exc: raise NumberFormatError( f"{string!r} is not a properly formatted decimal number. " f"Did you mean {proper!r}?", suggestions=[proper], - ) + ) from exc else: proper_alt = format_decimal(parsed_alt, locale=locale, decimal_quantization=False) if proper_alt == proper: @@ -1095,7 +1095,7 @@ class NumberPattern: scale = 0 if '%' in ''.join(self.prefix + self.suffix): scale = 2 - elif u'‰' in ''.join(self.prefix + self.suffix): + elif '‰' in ''.join(self.prefix + self.suffix): scale = 3 return scale @@ -1222,11 +1222,11 @@ class NumberPattern: number if self.number_pattern != '' else '', self.suffix[is_negative]]) - if u'¤' in retval: - retval = retval.replace(u'¤¤¤', + if '¤' in retval: + retval = retval.replace('¤¤¤', get_currency_name(currency, value, locale)) - retval = retval.replace(u'¤¤', currency.upper()) - retval = retval.replace(u'¤', get_currency_symbol(currency, locale)) + retval = retval.replace('¤¤', currency.upper()) + retval = retval.replace('¤', get_currency_symbol(currency, locale)) # remove single quotes around text, except for doubled single quotes # which are replaced with a single quote diff --git a/babel/plural.py b/babel/plural.py index b4f54c0..26073ff 100644 --- a/babel/plural.py +++ b/babel/plural.py @@ -115,7 +115,7 @@ class PluralRule: rules = rules.items() found = set() self.abstract: list[tuple[str, Any]] = [] - for key, expr in sorted(list(rules)): + for key, expr in sorted(rules): if key not in _plural_tags: raise ValueError(f"unknown tag {key!r}") elif key in found: @@ -325,6 +325,7 @@ def cldr_modulo(a: float, b: float) -> float: class RuleError(Exception): """Raised if a rule is malformed.""" + _VARS = { 'n', # absolute value of the source number. 'i', # integer digits of n. @@ -363,6 +364,7 @@ def tokenize_rule(s: str) -> list[tuple[str, str]]: 'Got unexpected %r' % s[pos]) return result[::-1] + def test_next_token( tokens: list[tuple[str, str]], type_: str, @@ -519,7 +521,7 @@ class _Parser: def _binary_compiler(tmpl): """Compiler factory for the `_Compiler`.""" - return lambda self, l, r: tmpl % (self.compile(l), self.compile(r)) + return lambda self, left, right: tmpl % (self.compile(left), self.compile(right)) def _unary_compiler(tmpl): @@ -627,7 +629,7 @@ class _UnicodeCompiler(_Compiler): compile_mod = _binary_compiler('%s mod %s') def compile_not(self, relation): - return self.compile_relation(negated=True, *relation[1]) + return self.compile_relation(*relation[1], negated=True) def compile_relation(self, method, expr, range_list, negated=False): ranges = [] diff --git a/babel/support.py b/babel/support.py index a8dd230..242b492 100644 --- a/babel/support.py +++ b/babel/support.py @@ -16,23 +16,26 @@ import decimal import gettext import locale import os -import datetime from collections.abc import Iterator from typing import TYPE_CHECKING, Any, Callable from babel.core import Locale - -from babel.dates import (format_date, format_datetime, format_time, - format_timedelta, get_timezone) -from babel.numbers import (format_compact_currency, format_compact_decimal, - format_currency, format_decimal, format_percent, - format_scientific) +from babel.dates import format_date, format_datetime, format_time, format_timedelta +from babel.numbers import ( + format_compact_currency, + format_compact_decimal, + format_currency, + format_decimal, + format_percent, + format_scientific, +) if TYPE_CHECKING: from typing_extensions import Literal from babel.dates import _PredefinedTimeFormat + class Format: """Wrapper class providing the various date and number formatting functions bound to a specific locale and time-zone. @@ -77,6 +80,7 @@ class Format: """Return a date and time formatted according to the given pattern. >>> from datetime import datetime + >>> from babel.dates import get_timezone >>> fmt = Format('en_US', tzinfo=get_timezone('US/Eastern')) >>> fmt.datetime(datetime(2007, 4, 1, 15, 30)) u'Apr 1, 2007, 11:30:00 AM' @@ -91,6 +95,7 @@ class Format: """Return a time formatted according to the given pattern. >>> from datetime import datetime + >>> from babel.dates import get_timezone >>> fmt = Format('en_US', tzinfo=get_timezone('US/Eastern')) >>> fmt.time(datetime(2007, 4, 1, 15, 30)) u'11:30:00 AM' @@ -333,7 +338,7 @@ class LazyProxy: return LazyProxy( self._func, enable_cache=self._is_cache_enabled, - *self._args, + *self._args, # noqa: B026 **self._kwargs ) @@ -342,7 +347,7 @@ class LazyProxy: return LazyProxy( deepcopy(self._func, memo), enable_cache=deepcopy(self._is_cache_enabled, memo), - *deepcopy(self._args, memo), + *deepcopy(self._args, memo), # noqa: B026 **deepcopy(self._kwargs, memo) ) diff --git a/babel/units.py b/babel/units.py index 1180bd1..0c72ee9 100644 --- a/babel/units.py +++ b/babel/units.py @@ -9,6 +9,7 @@ from babel.numbers import LC_NUMERIC, format_decimal if TYPE_CHECKING: from typing_extensions import Literal + class UnknownUnitError(ValueError): def __init__(self, unit: str, locale: Locale) -> None: ValueError.__init__(self, f"{unit} is not a known unit in {locale}") diff --git a/babel/util.py b/babel/util.py index d25ec53..a5403e6 100644 --- a/babel/util.py +++ b/babel/util.py @@ -11,19 +11,20 @@ from __future__ import annotations import codecs import collections +import datetime import os import re import textwrap -from babel import localtime, dates - from collections.abc import Generator, Iterable -import datetime from typing import IO, Any, TypeVar +from babel import dates, localtime + missing = object() _T = TypeVar("_T") + def distinct(iterable: Iterable[_T]) -> Generator[_T, None, None]: """Yield all items in an iterable collection that are distinct. @@ -43,6 +44,7 @@ def distinct(iterable: Iterable[_T]) -> Generator[_T, None, None]: yield item seen.add(item) + # Regexp to match python magic encoding line PYTHON_MAGIC_COMMENT_re = re.compile( br'[ \t\f]* \# .* coding[=:][ \t]*([-\w.]+)', re.VERBOSE) diff --git a/docs/conf.py b/docs/conf.py index c0e2389..5118f72 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -10,7 +10,8 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os +import os +import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -42,8 +43,8 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'Babel' -copyright = u'2022, The Babel Team' +project = 'Babel' +copyright = '2022, The Babel Team' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -193,8 +194,8 @@ latex_elements = { # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'Babel.tex', u'Babel Documentation', - u'The Babel Team', 'manual'), + ('index', 'Babel.tex', 'Babel Documentation', + 'The Babel Team', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -223,7 +224,7 @@ latex_logo = '_static/logo.png' # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'babel', u'Babel Documentation', [u'The Babel Team'], 1), + ('index', 'babel', 'Babel Documentation', ['The Babel Team'], 1), ] # If true, show URL addresses after external links. @@ -236,8 +237,8 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index_', 'Babel', u'Babel Documentation', - u'The Babel Team', 'Babel', 'One line description of project.', + ('index_', 'Babel', 'Babel Documentation', + 'The Babel Team', 'Babel', 'One line description of project.', 'Miscellaneous'), ] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..dbd137c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,23 @@ +[tool.ruff] +target-version = "py37" +select = [ + "B", + "C", + "E", + "F", + "I", + "SIM300", + "UP", +] +ignore = [ + "C901", # Complexity + "E501", # Line length + "E731", # Do not assign a lambda expression (we use them on purpose) + "E741", # Ambiguous variable name + "UP012", # "utf-8" is on purpose +] +extend-exclude = [ + "tests/messages/data", +] +[tool.ruff.per-file-ignores] +"scripts/import_cldr.py" = ["E402"] diff --git a/scripts/download_import_cldr.py b/scripts/download_import_cldr.py index 57995b5..ab455ac 100755 --- a/scripts/download_import_cldr.py +++ b/scripts/download_import_cldr.py @@ -1,15 +1,14 @@ #!/usr/bin/env python3 import contextlib +import hashlib import os -import sys import shutil -import hashlib -import zipfile import subprocess +import sys +import zipfile from urllib.request import urlretrieve - URL = 'http://unicode.org/Public/cldr/41/cldr-common-41.0.zip' FILENAME = 'cldr-common-41.0.zip' # Via https://unicode.org/Public/cldr/41/hashes/SHASUM512 @@ -38,7 +37,7 @@ def is_good_file(filename): return False h = hashlib.sha512() with open(filename, 'rb') as f: - while 1: + while True: blk = f.read(BLKSIZE) if not blk: break diff --git a/scripts/dump_data.py b/scripts/dump_data.py index e419050..041a410 100755 --- a/scripts/dump_data.py +++ b/scripts/dump_data.py @@ -14,7 +14,7 @@ from optparse import OptionParser from pprint import pprint -from babel.localedata import load, LocaleDataDict +from babel.localedata import LocaleDataDict, load def main(): diff --git a/scripts/dump_global.py b/scripts/dump_global.py index 6696415..3fc95b6 100755 --- a/scripts/dump_global.py +++ b/scripts/dump_global.py @@ -11,10 +11,11 @@ # individuals. For the exact contribution history, see the revision # history and logs, available at http://babel.edgewall.org/log/. -import cPickle as pickle import os -from pprint import pprint import sys +from pprint import pprint + +import cPickle as pickle import babel diff --git a/scripts/generate_authors.py b/scripts/generate_authors.py index e2e3add..64c0af8 100644 --- a/scripts/generate_authors.py +++ b/scripts/generate_authors.py @@ -1,8 +1,7 @@ +import os from collections import Counter from subprocess import check_output -import os - root_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..')) diff --git a/scripts/import_cldr.py b/scripts/import_cldr.py index 5de707c..5630ba8 100755 --- a/scripts/import_cldr.py +++ b/scripts/import_cldr.py @@ -12,13 +12,12 @@ # history and logs, available at http://babel.edgewall.org/log/. import collections -from optparse import OptionParser +import logging import os import pickle import re import sys -import logging - +from optparse import OptionParser from xml.etree import ElementTree # Make sure we're using Babel source, and not some previously installed version @@ -44,7 +43,7 @@ def _text(elem): for child in elem: buf.append(_text(child)) buf.append(elem.tail or '') - return u''.join(filter(None, buf)).strip() + return ''.join(filter(None, buf)).strip() NAME_RE = re.compile(r"^\w+$") @@ -130,7 +129,7 @@ def _time_to_seconds_past_midnight(time_expr): return None if time_expr.count(":") == 1: time_expr += ":00" - hour, minute, second = [int(p, 10) for p in time_expr.split(":")] + hour, minute, second = (int(p, 10) for p in time_expr.split(":")) return hour * 60 * 60 + minute * 60 + second @@ -991,6 +990,5 @@ def parse_measurement_systems(data, tree): _import_type_text(measurement_systems, measurement_system, type=type) - if __name__ == '__main__': main() @@ -1,7 +1,7 @@ import subprocess import sys -from setuptools import setup, Command +from setuptools import Command, setup try: from babel import __version__ diff --git a/tests/conftest.py b/tests/conftest.py index 0506a83..67e3ce9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,5 @@ import os + import pytest try: diff --git a/tests/messages/test_catalog.py b/tests/messages/test_catalog.py index e9b15a8..273c83f 100644 --- a/tests/messages/test_catalog.py +++ b/tests/messages/test_catalog.py @@ -15,7 +15,7 @@ import datetime import unittest from io import StringIO -from babel.dates import format_datetime, UTC +from babel.dates import UTC, format_datetime from babel.messages import catalog, pofile from babel.util import FixedOffsetTimezone @@ -89,34 +89,34 @@ class CatalogTestCase(unittest.TestCase): def test_update_message_changed_to_plural(self): cat = catalog.Catalog() - cat.add(u'foo', u'Voh') + cat.add('foo', 'Voh') tmpl = catalog.Catalog() - tmpl.add((u'foo', u'foos')) + tmpl.add(('foo', 'foos')) cat.update(tmpl) assert cat['foo'].string == ('Voh', '') assert cat['foo'].fuzzy def test_update_message_changed_to_simple(self): cat = catalog.Catalog() - cat.add(u'foo' u'foos', (u'Voh', u'Vöhs')) + cat.add('foo' 'foos', ('Voh', 'Vöhs')) tmpl = catalog.Catalog() - tmpl.add(u'foo') + tmpl.add('foo') cat.update(tmpl) assert cat['foo'].string == 'Voh' assert cat['foo'].fuzzy def test_update_message_updates_comments(self): cat = catalog.Catalog() - cat[u'foo'] = catalog.Message('foo', locations=[('main.py', 5)]) + cat['foo'] = catalog.Message('foo', locations=[('main.py', 5)]) assert cat['foo'].auto_comments == [] assert cat['foo'].user_comments == [] # Update cat[u'foo'] with a new location and a comment - cat[u'foo'] = catalog.Message('foo', locations=[('main.py', 7)], - user_comments=['Foo Bar comment 1']) + cat['foo'] = catalog.Message('foo', locations=[('main.py', 7)], + user_comments=['Foo Bar comment 1']) assert cat['foo'].user_comments == ['Foo Bar comment 1'] # now add yet another location with another comment - cat[u'foo'] = catalog.Message('foo', locations=[('main.py', 9)], - auto_comments=['Foo Bar comment 2']) + cat['foo'] = catalog.Message('foo', locations=[('main.py', 9)], + auto_comments=['Foo Bar comment 2']) assert cat['foo'].auto_comments == ['Foo Bar comment 2'] def test_update_fuzzy_matching_with_case_change(self): @@ -404,21 +404,21 @@ def test_catalog_plural_forms(): def test_catalog_setitem(): cat = catalog.Catalog() - cat[u'foo'] = catalog.Message(u'foo') - assert cat[u'foo'].id == 'foo' + cat['foo'] = catalog.Message('foo') + assert cat['foo'].id == 'foo' cat = catalog.Catalog() - cat[u'foo'] = catalog.Message(u'foo', locations=[('main.py', 1)]) - assert cat[u'foo'].locations == [('main.py', 1)] - cat[u'foo'] = catalog.Message(u'foo', locations=[('utils.py', 5)]) - assert cat[u'foo'].locations == [('main.py', 1), ('utils.py', 5)] + cat['foo'] = catalog.Message('foo', locations=[('main.py', 1)]) + assert cat['foo'].locations == [('main.py', 1)] + cat['foo'] = catalog.Message('foo', locations=[('utils.py', 5)]) + assert cat['foo'].locations == [('main.py', 1), ('utils.py', 5)] def test_catalog_add(): cat = catalog.Catalog() - foo = cat.add(u'foo') + foo = cat.add('foo') assert foo.id == 'foo' - assert cat[u'foo'] is foo + assert cat['foo'] is foo def test_catalog_update(): @@ -427,9 +427,9 @@ def test_catalog_update(): template.add('blue', locations=[('main.py', 100)]) template.add(('salad', 'salads'), locations=[('util.py', 42)]) cat = catalog.Catalog(locale='de_DE') - cat.add('blue', u'blau', locations=[('main.py', 98)]) - cat.add('head', u'Kopf', locations=[('util.py', 33)]) - cat.add(('salad', 'salads'), (u'Salat', u'Salate'), + cat.add('blue', 'blau', locations=[('main.py', 98)]) + cat.add('head', 'Kopf', locations=[('util.py', 33)]) + cat.add(('salad', 'salads'), ('Salat', 'Salate'), locations=[('util.py', 38)]) cat.update(template) @@ -440,11 +440,11 @@ def test_catalog_update(): assert msg1.locations == [('main.py', 99)] msg2 = cat['blue'] - assert msg2.string == u'blau' + assert msg2.string == 'blau' assert msg2.locations == [('main.py', 100)] msg3 = cat['salad'] - assert msg3.string == (u'Salat', u'Salate') + assert msg3.string == ('Salat', 'Salate') assert msg3.locations == [('util.py', 42)] assert 'head' not in cat diff --git a/tests/messages/test_extract.py b/tests/messages/test_extract.py index 3873191..7a0df8e 100644 --- a/tests/messages/test_extract.py +++ b/tests/messages/test_extract.py @@ -41,14 +41,14 @@ msg10 = dngettext(getDomain(), 'Page', 'Pages', 3) assert messages == [ (1, '_', None, []), (2, 'ungettext', (None, None, None), []), - (3, 'ungettext', (u'Babel', None, None), []), - (4, 'ungettext', (None, u'Babels', None), []), - (5, 'ungettext', (u'bunny', u'bunnies', None), []), - (6, 'ungettext', (None, u'bunnies', None), []), + (3, 'ungettext', ('Babel', None, None), []), + (4, 'ungettext', (None, 'Babels', None), []), + (5, 'ungettext', ('bunny', 'bunnies', None), []), + (6, 'ungettext', (None, 'bunnies', None), []), (7, '_', None, []), - (8, 'gettext', u'Rabbit', []), - (9, 'dgettext', (u'wiki', None), []), - (10, 'dngettext', (None, u'Page', u'Pages', None), []), + (8, 'gettext', 'Rabbit', []), + (9, 'dgettext', ('wiki', None), []), + (10, 'dngettext', (None, 'Page', 'Pages', None), []), ] def test_extract_default_encoding_ascii(self): @@ -60,7 +60,7 @@ msg10 = dngettext(getDomain(), 'Page', 'Pages', 3) assert messages == [(1, '_', 'a', [])] def test_extract_default_encoding_utf8(self): - buf = BytesIO(u'_("☃")'.encode('UTF-8')) + buf = BytesIO('_("☃")'.encode('UTF-8')) messages = list(extract.extract_python( buf, list(extract.DEFAULT_KEYWORDS), [], {}, )) @@ -351,7 +351,7 @@ msg = _('Bonjour à tous') assert messages[0][3] == ['NOTE: hello'] def test_utf8_message_with_magic_comment(self): - buf = BytesIO(u"""# -*- coding: utf-8 -*- + buf = BytesIO("""# -*- coding: utf-8 -*- # NOTE: hello msg = _('Bonjour à tous') """.encode('utf-8')) @@ -360,7 +360,7 @@ msg = _('Bonjour à tous') assert messages[0][3] == ['NOTE: hello'] def test_utf8_message_with_utf8_bom(self): - buf = BytesIO(codecs.BOM_UTF8 + u""" + buf = BytesIO(codecs.BOM_UTF8 + """ # NOTE: hello msg = _('Bonjour à tous') """.encode('utf-8')) @@ -369,7 +369,7 @@ msg = _('Bonjour à tous') assert messages[0][3] == ['NOTE: hello'] def test_utf8_message_with_utf8_bom_and_magic_comment(self): - buf = BytesIO(codecs.BOM_UTF8 + u"""# -*- coding: utf-8 -*- + buf = BytesIO(codecs.BOM_UTF8 + """# -*- coding: utf-8 -*- # NOTE: hello msg = _('Bonjour à tous') """.encode('utf-8')) @@ -378,7 +378,7 @@ msg = _('Bonjour à tous') assert messages[0][3] == ['NOTE: hello'] def test_utf8_bom_with_latin_magic_comment_fails(self): - buf = BytesIO(codecs.BOM_UTF8 + u"""# -*- coding: latin-1 -*- + buf = BytesIO(codecs.BOM_UTF8 + """# -*- coding: latin-1 -*- # NOTE: hello msg = _('Bonjour à tous') """.encode('utf-8')) @@ -386,7 +386,7 @@ msg = _('Bonjour à tous') list(extract.extract_python(buf, ('_',), ['NOTE:'], {})) def test_utf8_raw_strings_match_unicode_strings(self): - buf = BytesIO(codecs.BOM_UTF8 + u""" + buf = BytesIO(codecs.BOM_UTF8 + """ msg = _('Bonjour à tous') msgu = _(u'Bonjour à tous') """.encode('utf-8')) @@ -527,7 +527,7 @@ nbsp = _('\xa0') """) messages = list(extract.extract('python', buf, extract.DEFAULT_KEYWORDS, [], {})) - assert messages[0][1] == u'\xa0' + assert messages[0][1] == '\xa0' def test_f_strings(self): buf = BytesIO(br""" @@ -542,10 +542,10 @@ t4 = _(f'spameggs {t1}') # should not be extracted """) messages = list(extract.extract('python', buf, extract.DEFAULT_KEYWORDS, [], {})) assert len(messages) == 4 - assert messages[0][1] == u'foobar' - assert messages[1][1] == u'spameggsfeast' - assert messages[2][1] == u'spameggskerroshampurilainen' - assert messages[3][1] == u'whoa! a flying shark... hello' + assert messages[0][1] == 'foobar' + assert messages[1][1] == 'spameggsfeast' + assert messages[2][1] == 'spameggskerroshampurilainen' + assert messages[3][1] == 'whoa! a flying shark... hello' def test_f_strings_non_utf8(self): buf = BytesIO(b""" @@ -554,4 +554,4 @@ t2 = _(f'\xe5\xe4\xf6' f'\xc5\xc4\xd6') """) messages = list(extract.extract('python', buf, extract.DEFAULT_KEYWORDS, [], {})) assert len(messages) == 1 - assert messages[0][1] == u'åäöÅÄÖ' + assert messages[0][1] == 'åäöÅÄÖ' diff --git a/tests/messages/test_frontend.py b/tests/messages/test_frontend.py index e91d02b..e540e71 100644 --- a/tests/messages/test_frontend.py +++ b/tests/messages/test_frontend.py @@ -9,26 +9,38 @@ # This software consists of voluntary contributions made by many # individuals. For the exact contribution history, see the revision # history and logs, available at http://babel.edgewall.org/log/. -import shlex -from datetime import datetime -from freezegun import freeze_time -from io import StringIO -from setuptools import Distribution import logging import os +import shlex import shutil import sys import time import unittest +from datetime import datetime +from io import StringIO import pytest +from freezegun import freeze_time +from setuptools import Distribution from babel import __version__ as VERSION from babel.dates import format_datetime -from babel.messages import frontend, Catalog -from babel.messages.frontend import CommandLineInterface, extract_messages, update_catalog, OptionError, BaseError -from babel.util import LOCALTZ +from babel.messages import Catalog, frontend +from babel.messages.frontend import ( + BaseError, + CommandLineInterface, + OptionError, + extract_messages, + update_catalog, +) from babel.messages.pofile import read_po, write_po +from babel.util import LOCALTZ + +TEST_PROJECT_DISTRIBUTION_DATA = { + "name": "TestProject", + "version": "0.1", + "packages": ["project"], +} this_dir = os.path.abspath(os.path.dirname(__file__)) data_dir = os.path.join(this_dir, 'data') @@ -47,11 +59,7 @@ class CompileCatalogTestCase(unittest.TestCase): self.olddir = os.getcwd() os.chdir(data_dir) - self.dist = Distribution(dict( - name='TestProject', - version='0.1', - packages=['project'] - )) + self.dist = Distribution(TEST_PROJECT_DISTRIBUTION_DATA) self.cmd = frontend.compile_catalog(self.dist) self.cmd.initialize_options() @@ -77,11 +85,7 @@ class ExtractMessagesTestCase(unittest.TestCase): self.olddir = os.getcwd() os.chdir(data_dir) - self.dist = Distribution(dict( - name='TestProject', - version='0.1', - packages=['project'] - )) + self.dist = Distribution(TEST_PROJECT_DISTRIBUTION_DATA) self.cmd = frontend.extract_messages(self.dist) self.cmd.initialize_options() @@ -350,11 +354,7 @@ class InitCatalogTestCase(unittest.TestCase): self.olddir = os.getcwd() os.chdir(data_dir) - self.dist = Distribution(dict( - name='TestProject', - version='0.1', - packages=['project'] - )) + self.dist = Distribution(TEST_PROJECT_DISTRIBUTION_DATA) self.cmd = frontend.init_catalog(self.dist) self.cmd.initialize_options() diff --git a/tests/messages/test_js_extract.py b/tests/messages/test_js_extract.py index 95985c0..82f5379 100644 --- a/tests/messages/test_js_extract.py +++ b/tests/messages/test_js_extract.py @@ -1,5 +1,7 @@ from io import BytesIO + import pytest + from babel.messages import extract @@ -35,32 +37,32 @@ msg10 = dngettext(domain, 'Page', 'Pages', 3) list(extract.extract('javascript', buf, extract.DEFAULT_KEYWORDS, [], {})) assert messages == [ - (5, (u'bunny', u'bunnies'), [], None), - (8, u'Rabbit', [], None), - (10, (u'Page', u'Pages'), [], None) + (5, ('bunny', 'bunnies'), [], None), + (8, 'Rabbit', [], None), + (10, ('Page', 'Pages'), [], None) ] def test_message_with_line_comment(): - buf = BytesIO(u"""\ + buf = BytesIO("""\ // NOTE: hello msg = _('Bonjour à tous') """.encode('utf-8')) messages = list(extract.extract_javascript(buf, ('_',), ['NOTE:'], {})) - assert messages[0][2] == u'Bonjour à tous' - assert messages[0][3] == [u'NOTE: hello'] + assert messages[0][2] == 'Bonjour à tous' + assert messages[0][3] == ['NOTE: hello'] def test_message_with_multiline_comment(): - buf = BytesIO(u"""\ + buf = BytesIO("""\ /* NOTE: hello and bonjour and servus */ msg = _('Bonjour à tous') """.encode('utf-8')) messages = list(extract.extract_javascript(buf, ('_',), ['NOTE:'], {})) - assert messages[0][2] == u'Bonjour à tous' - assert messages[0][3] == [u'NOTE: hello', 'and bonjour', ' and servus'] + assert messages[0][2] == 'Bonjour à tous' + assert messages[0][3] == ['NOTE: hello', 'and bonjour', ' and servus'] def test_ignore_function_definitions(): @@ -91,11 +93,11 @@ bar() _('no comment here') """) messages = list(extract.extract_javascript(buf, ('_',), ['NOTE:'], {})) - assert messages[0][2] == u'Something' - assert messages[0][3] == [u'NOTE: this will'] - assert messages[1][2] == u'Something else' - assert messages[1][3] == [u'NOTE: this will show up', 'too.'] - assert messages[2][2] == u'no comment here' + assert messages[0][2] == 'Something' + assert messages[0][3] == ['NOTE: this will'] + assert messages[1][2] == 'Something else' + assert messages[1][3] == ['NOTE: this will show up', 'too.'] + assert messages[2][2] == 'no comment here' assert messages[2][3] == [] diff --git a/tests/messages/test_jslexer.py b/tests/messages/test_jslexer.py index bd6322e..3889f0b 100644 --- a/tests/messages/test_jslexer.py +++ b/tests/messages/test_jslexer.py @@ -3,9 +3,9 @@ from babel.messages import jslexer def test_unquote(): assert jslexer.unquote_string('""') == '' - assert jslexer.unquote_string(r'"h\u00ebllo"') == u"hëllo" - assert jslexer.unquote_string(r'"h\xebllo"') == u"hëllo" - assert jslexer.unquote_string(r'"\xebb"') == u"ëb" + assert jslexer.unquote_string(r'"h\u00ebllo"') == "hëllo" + assert jslexer.unquote_string(r'"h\xebllo"') == "hëllo" + assert jslexer.unquote_string(r'"\xebb"') == "ëb" def test_dollar_in_identifier(): diff --git a/tests/messages/test_mofile.py b/tests/messages/test_mofile.py index 6e026a8..6a702ed 100644 --- a/tests/messages/test_mofile.py +++ b/tests/messages/test_mofile.py @@ -14,7 +14,7 @@ import os import unittest from io import BytesIO -from babel.messages import mofile, Catalog +from babel.messages import Catalog, mofile from babel.support import Translations @@ -42,12 +42,12 @@ class WriteMoTestCase(unittest.TestCase): # can be applied to all subsequent messages by GNUTranslations # (ensuring all messages are safely converted to unicode) catalog = Catalog(locale='en_US') - catalog.add(u'', '''\ + catalog.add('', '''\ "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n''') - catalog.add(u'foo', 'Voh') - catalog.add((u'There is', u'There are'), (u'Es gibt', u'Es gibt')) - catalog.add(u'Fizz', '') + catalog.add('foo', 'Voh') + catalog.add(('There is', 'There are'), ('Es gibt', 'Es gibt')) + catalog.add('Fizz', '') catalog.add(('Fuzz', 'Fuzzes'), ('', '')) buf = BytesIO() mofile.write_mo(buf, catalog) @@ -67,18 +67,18 @@ class WriteMoTestCase(unittest.TestCase): def test_empty_translation_with_fallback(self): catalog1 = Catalog(locale='fr_FR') - catalog1.add(u'', '''\ + catalog1.add('', '''\ "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n''') - catalog1.add(u'Fuzz', '') + catalog1.add('Fuzz', '') buf1 = BytesIO() mofile.write_mo(buf1, catalog1) buf1.seek(0) catalog2 = Catalog(locale='fr') - catalog2.add(u'', '''\ + catalog2.add('', '''\ "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n''') - catalog2.add(u'Fuzz', 'Flou') + catalog2.add('Fuzz', 'Flou') buf2 = BytesIO() mofile.write_mo(buf2, catalog2) buf2.seek(0) diff --git a/tests/messages/test_pofile.py b/tests/messages/test_pofile.py index a72368b..f668ea0 100644 --- a/tests/messages/test_pofile.py +++ b/tests/messages/test_pofile.py @@ -10,16 +10,18 @@ # individuals. For the exact contribution history, see the revision # history and logs, available at http://babel.edgewall.org/log/. -from datetime import datetime import unittest +from datetime import datetime from io import BytesIO, StringIO + import pytest from babel.core import Locale -from babel.messages.catalog import Catalog, Message from babel.messages import pofile +from babel.messages.catalog import Catalog, Message from babel.util import FixedOffsetTimezone + class ReadPoTestCase(unittest.TestCase): def test_preserve_locale(self): @@ -49,7 +51,7 @@ msgstr "Voh"''') assert catalog.domain == 'mydomain' def test_applies_specified_encoding_during_read(self): - buf = BytesIO(u''' + buf = BytesIO(''' msgid "" msgstr "" "Project-Id-Version: 3.15\\n" @@ -204,7 +206,7 @@ msgstr "Bahr" ''') catalog = pofile.read_po(buf) assert len(catalog.obsolete) == 1 - message = catalog.obsolete[u'foofoo'] + message = catalog.obsolete['foofoo'] assert message.id == 'foofoo' assert message.string == 'VohVooooh' assert message.user_comments == ['This is an obsolete message'] @@ -225,7 +227,7 @@ msgstr "Bahr" ''') catalog = pofile.read_po(buf) assert len(catalog) == 1 - message = catalog[u'bar'] + message = catalog['bar'] assert message.id == 'bar' assert message.string == 'Bahr' assert message.user_comments == ['This message is not obsolete'] @@ -247,7 +249,7 @@ msgstr "Bahr" ''') catalog = pofile.read_po(buf) assert len(catalog) == 1 - message = catalog[u'bar'] + message = catalog['bar'] assert message.id == 'bar' assert message.string == 'Bahr' assert message.user_comments == ['This message is not obsolete'] @@ -296,7 +298,7 @@ msgstr "Bahr" catalog = pofile.read_po(buf) assert len(catalog) == 2 assert len(catalog.obsolete) == 1 - message = catalog.obsolete[u"foo"] + message = catalog.obsolete["foo"] assert message.context == 'other' assert message.string == 'Voh' @@ -484,7 +486,7 @@ msgstr[2] "Vohs [text]" def test_invalid_pofile_with_abort_flag(self): parser = pofile.PoFileParser(None, abort_invalid=True) lineno = 10 - line = u'Algo esta mal' + line = 'Algo esta mal' msg = 'invalid file' with pytest.raises(pofile.PoFileError): parser._invalid_pofile(line, lineno, msg) @@ -494,8 +496,8 @@ class WritePoTestCase(unittest.TestCase): def test_join_locations(self): catalog = Catalog() - catalog.add(u'foo', locations=[('main.py', 1)]) - catalog.add(u'foo', locations=[('utils.py', 3)]) + catalog.add('foo', locations=[('main.py', 1)]) + catalog.add('foo', locations=[('utils.py', 3)]) buf = BytesIO() pofile.write_po(buf, catalog, omit_header=True) assert buf.getvalue().strip() == b'''#: main.py:1 utils.py:3 @@ -504,17 +506,17 @@ msgstr ""''' def test_write_po_file_with_specified_charset(self): catalog = Catalog(charset='iso-8859-1') - catalog.add('foo', u'äöü', locations=[('main.py', 1)]) + catalog.add('foo', 'äöü', locations=[('main.py', 1)]) buf = BytesIO() pofile.write_po(buf, catalog, omit_header=False) po_file = buf.getvalue().strip() assert b'"Content-Type: text/plain; charset=iso-8859-1\\n"' in po_file - assert u'msgstr "äöü"'.encode('iso-8859-1') in po_file + assert 'msgstr "äöü"'.encode('iso-8859-1') in po_file def test_duplicate_comments(self): catalog = Catalog() - catalog.add(u'foo', auto_comments=['A comment']) - catalog.add(u'foo', auto_comments=['A comment']) + catalog.add('foo', auto_comments=['A comment']) + catalog.add('foo', auto_comments=['A comment']) buf = BytesIO() pofile.write_po(buf, catalog, omit_header=True) assert buf.getvalue().strip() == b'''#. A comment @@ -577,10 +579,10 @@ msgstr ""''' def test_wrap_locations_with_hyphens(self): catalog = Catalog() - catalog.add(u'foo', locations=[ + catalog.add('foo', locations=[ ('doupy/templates/base/navmenu.inc.html.py', 60) ]) - catalog.add(u'foo', locations=[ + catalog.add('foo', locations=[ ('doupy/templates/job-offers/helpers.html', 22) ]) buf = BytesIO() @@ -623,9 +625,9 @@ msgstr "" def test_pot_with_translator_comments(self): catalog = Catalog() - catalog.add(u'foo', locations=[('main.py', 1)], + catalog.add('foo', locations=[('main.py', 1)], auto_comments=['Comment About `foo`']) - catalog.add(u'bar', locations=[('utils.py', 3)], + catalog.add('bar', locations=[('utils.py', 3)], user_comments=['Comment About `bar` with', 'multiple lines.']) buf = BytesIO() @@ -643,8 +645,8 @@ msgstr ""''' def test_po_with_obsolete_message(self): catalog = Catalog() - catalog.add(u'foo', u'Voh', locations=[('main.py', 1)]) - catalog.obsolete['bar'] = Message(u'bar', u'Bahr', + catalog.add('foo', 'Voh', locations=[('main.py', 1)]) + catalog.obsolete['bar'] = Message('bar', 'Bahr', locations=[('utils.py', 3)], user_comments=['User comment']) buf = BytesIO() @@ -659,7 +661,7 @@ msgstr "Voh" def test_po_with_multiline_obsolete_message(self): catalog = Catalog() - catalog.add(u'foo', u'Voh', locations=[('main.py', 1)]) + catalog.add('foo', 'Voh', locations=[('main.py', 1)]) msgid = r"""Here's a message that covers multiple lines, and should still be handled correctly. @@ -687,8 +689,8 @@ msgstr "Voh" def test_po_with_obsolete_message_ignored(self): catalog = Catalog() - catalog.add(u'foo', u'Voh', locations=[('main.py', 1)]) - catalog.obsolete['bar'] = Message(u'bar', u'Bahr', + catalog.add('foo', 'Voh', locations=[('main.py', 1)]) + catalog.obsolete['bar'] = Message('bar', 'Bahr', locations=[('utils.py', 3)], user_comments=['User comment']) buf = BytesIO() @@ -699,8 +701,8 @@ msgstr "Voh"''' def test_po_with_previous_msgid(self): catalog = Catalog() - catalog.add(u'foo', u'Voh', locations=[('main.py', 1)], - previous_id=u'fo') + catalog.add('foo', 'Voh', locations=[('main.py', 1)], + previous_id='fo') buf = BytesIO() pofile.write_po(buf, catalog, omit_header=True, include_previous=True) assert buf.getvalue().strip() == b'''#: main.py:1 @@ -710,8 +712,8 @@ msgstr "Voh"''' def test_po_with_previous_msgid_plural(self): catalog = Catalog() - catalog.add((u'foo', u'foos'), (u'Voh', u'Voeh'), - locations=[('main.py', 1)], previous_id=(u'fo', u'fos')) + catalog.add(('foo', 'foos'), ('Voh', 'Voeh'), + locations=[('main.py', 1)], previous_id=('fo', 'fos')) buf = BytesIO() pofile.write_po(buf, catalog, omit_header=True, include_previous=True) assert buf.getvalue().strip() == b'''#: main.py:1 @@ -724,10 +726,10 @@ msgstr[1] "Voeh"''' def test_sorted_po(self): catalog = Catalog() - catalog.add(u'bar', locations=[('utils.py', 3)], + catalog.add('bar', locations=[('utils.py', 3)], user_comments=['Comment About `bar` with', 'multiple lines.']) - catalog.add((u'foo', u'foos'), (u'Voh', u'Voeh'), + catalog.add(('foo', 'foos'), ('Voh', 'Voeh'), locations=[('main.py', 1)]) buf = BytesIO() pofile.write_po(buf, catalog, sort_output=True) @@ -748,12 +750,12 @@ msgstr[1] "Voeh"''' in value def test_sorted_po_context(self): catalog = Catalog() - catalog.add((u'foo', u'foos'), (u'Voh', u'Voeh'), + catalog.add(('foo', 'foos'), ('Voh', 'Voeh'), locations=[('main.py', 1)], context='there') - catalog.add((u'foo', u'foos'), (u'Voh', u'Voeh'), + catalog.add(('foo', 'foos'), ('Voh', 'Voeh'), locations=[('main.py', 1)]) - catalog.add((u'foo', u'foos'), (u'Voh', u'Voeh'), + catalog.add(('foo', 'foos'), ('Voh', 'Voeh'), locations=[('main.py', 1)], context='here') buf = BytesIO() @@ -783,8 +785,8 @@ msgstr[1] "Voeh"''' in value def test_file_sorted_po(self): catalog = Catalog() - catalog.add(u'bar', locations=[('utils.py', 3)]) - catalog.add((u'foo', u'foos'), (u'Voh', u'Voeh'), locations=[('main.py', 1)]) + catalog.add('bar', locations=[('utils.py', 3)]) + catalog.add(('foo', 'foos'), ('Voh', 'Voeh'), locations=[('main.py', 1)]) buf = BytesIO() pofile.write_po(buf, catalog, sort_by_file=True) value = buf.getvalue().strip() @@ -792,7 +794,7 @@ msgstr[1] "Voeh"''' in value def test_file_with_no_lineno(self): catalog = Catalog() - catalog.add(u'bar', locations=[('utils.py', None)], + catalog.add('bar', locations=[('utils.py', None)], user_comments=['Comment About `bar` with', 'multiple lines.']) buf = BytesIO() @@ -820,8 +822,8 @@ msgstr ""''') def test_include_lineno(self): catalog = Catalog() - catalog.add(u'foo', locations=[('main.py', 1)]) - catalog.add(u'foo', locations=[('utils.py', 3)]) + catalog.add('foo', locations=[('main.py', 1)]) + catalog.add('foo', locations=[('utils.py', 3)]) buf = BytesIO() pofile.write_po(buf, catalog, omit_header=True, include_lineno=True) assert buf.getvalue().strip() == b'''#: main.py:1 utils.py:3 @@ -830,9 +832,9 @@ msgstr ""''' def test_no_include_lineno(self): catalog = Catalog() - catalog.add(u'foo', locations=[('main.py', 1)]) - catalog.add(u'foo', locations=[('main.py', 2)]) - catalog.add(u'foo', locations=[('utils.py', 3)]) + catalog.add('foo', locations=[('main.py', 1)]) + catalog.add('foo', locations=[('main.py', 2)]) + catalog.add('foo', locations=[('utils.py', 3)]) buf = BytesIO() pofile.write_po(buf, catalog, omit_header=True, include_lineno=False) assert buf.getvalue().strip() == b'''#: main.py utils.py @@ -843,8 +845,8 @@ msgstr ""''' class PofileFunctionsTestCase(unittest.TestCase): def test_unescape(self): - escaped = u'"Say:\\n \\"hello, world!\\"\\n"' - unescaped = u'Say:\n "hello, world!"\n' + escaped = '"Say:\\n \\"hello, world!\\"\\n"' + unescaped = 'Say:\n "hello, world!"\n' assert unescaped != escaped assert unescaped == pofile.unescape(escaped) @@ -856,7 +858,7 @@ class PofileFunctionsTestCase(unittest.TestCase): # handle irregular multi-line msgstr (no "" as first line) # gracefully (#171) msgstr = '"multi-line\\n"\n" translation"' - expected_denormalized = u'multi-line\n translation' + expected_denormalized = 'multi-line\n translation' assert expected_denormalized == pofile.denormalize(msgstr) assert expected_denormalized == pofile.denormalize(f'""\n{msgstr}') diff --git a/tests/test_core.py b/tests/test_core.py index 605bf5c..d315018 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -13,20 +13,19 @@ import pytest from babel import core -from babel.core import default_locale, Locale +from babel.core import Locale, default_locale def test_locale_provides_access_to_cldr_locale_data(): locale = Locale('en', 'US') - assert u'English (United States)' == locale.display_name - assert u'.' == locale.number_symbols['decimal'] + assert locale.display_name == 'English (United States)' + assert locale.number_symbols['decimal'] == '.' def test_locale_repr(): assert repr(Locale('en', 'US')) == "Locale('en', territory='US')" - assert ("Locale('de', territory='DE')" == repr(Locale('de', 'DE'))) - assert ("Locale('zh', territory='CN', script='Hans')" == - repr(Locale('zh', 'CN', script='Hans'))) + assert (repr(Locale('de', 'DE')) == "Locale('de', territory='DE')") + assert (repr(Locale('zh', 'CN', script='Hans')) == "Locale('zh', territory='CN', script='Hans')") def test_locale_comparison(): @@ -97,36 +96,36 @@ class TestLocaleClass: assert (de_DE.language, de_DE.territory) == ('de', 'DE') def test_parse(self): - l = Locale.parse('de-DE', sep='-') - assert l.display_name == 'Deutsch (Deutschland)' + locale = Locale.parse('de-DE', sep='-') + assert locale.display_name == 'Deutsch (Deutschland)' - de_DE = Locale.parse(l) + de_DE = Locale.parse(locale) assert (de_DE.language, de_DE.territory) == ('de', 'DE') def test_parse_likely_subtags(self): - l = Locale.parse('zh-TW', sep='-') - assert l.language == 'zh' - assert l.territory == 'TW' - assert l.script == 'Hant' - - l = Locale.parse('zh_CN') - assert l.language == 'zh' - assert l.territory == 'CN' - assert l.script == 'Hans' - - l = Locale.parse('zh_SG') - assert l.language == 'zh' - assert l.territory == 'SG' - assert l.script == 'Hans' - - l = Locale.parse('und_AT') - assert l.language == 'de' - assert l.territory == 'AT' - - l = Locale.parse('und_UK') - assert l.language == 'en' - assert l.territory == 'GB' - assert l.script is None + locale = Locale.parse('zh-TW', sep='-') + assert locale.language == 'zh' + assert locale.territory == 'TW' + assert locale.script == 'Hant' + + locale = Locale.parse('zh_CN') + assert locale.language == 'zh' + assert locale.territory == 'CN' + assert locale.script == 'Hans' + + locale = Locale.parse('zh_SG') + assert locale.language == 'zh' + assert locale.territory == 'SG' + assert locale.script == 'Hans' + + locale = Locale.parse('und_AT') + assert locale.language == 'de' + assert locale.territory == 'AT' + + locale = Locale.parse('und_UK') + assert locale.language == 'en' + assert locale.territory == 'GB' + assert locale.script is None def test_get_display_name(self): zh_CN = Locale('zh', 'CN', script='Hans') @@ -170,9 +169,9 @@ class TestLocaleClass: def test_currency_formats_property(self): assert (Locale('en', 'US').currency_formats['standard'].pattern == - u'\xa4#,##0.00') + '\xa4#,##0.00') assert (Locale('en', 'US').currency_formats['accounting'].pattern == - u'\xa4#,##0.00;(\xa4#,##0.00)') + '\xa4#,##0.00;(\xa4#,##0.00)') def test_percent_formats_property(self): assert Locale('en', 'US').percent_formats[None].pattern == '#,##0%' @@ -200,7 +199,7 @@ class TestLocaleClass: time_zones = Locale('en', 'US').time_zones assert (time_zones['Europe/London']['long']['daylight'] == 'British Summer Time') - assert time_zones['America/St_Johns']['city'] == u'St. John\u2019s' + assert time_zones['America/St_Johns']['city'] == 'St. John\u2019s' def test_meta_zones_property(self): meta_zones = Locale('en', 'US').meta_zones @@ -209,7 +208,7 @@ class TestLocaleClass: def test_zone_formats_property(self): assert Locale('en', 'US').zone_formats['fallback'] == '%(1)s (%(0)s)' - assert Locale('pt', 'BR').zone_formats['region'] == u'Hor\xe1rio %s' + assert Locale('pt', 'BR').zone_formats['region'] == 'Hor\xe1rio %s' def test_first_week_day_property(self): assert Locale('de', 'DE').first_week_day == 0 @@ -233,12 +232,12 @@ class TestLocaleClass: assert Locale('fr', 'FR').time_formats['long'].pattern == 'HH:mm:ss z' def test_datetime_formats_property(self): - assert Locale('en').datetime_formats['full'] == u"{1} 'at' {0}" - assert Locale('th').datetime_formats['medium'] == u'{1} {0}' + assert Locale('en').datetime_formats['full'] == "{1} 'at' {0}" + assert Locale('th').datetime_formats['medium'] == '{1} {0}' def test_datetime_skeleton_property(self): - assert Locale('en').datetime_skeletons['Md'].pattern == u"M/d" - assert Locale('th').datetime_skeletons['Md'].pattern == u'd/M' + assert Locale('en').datetime_skeletons['Md'].pattern == "M/d" + assert Locale('th').datetime_skeletons['Md'].pattern == 'd/M' def test_plural_form_property(self): assert Locale('en').plural_form(1) == 'one' @@ -322,7 +321,7 @@ def test_issue_601_no_language_name_but_has_variant(): # Instead, it's better to return None altogether, as we can't reliably format # part of a language name. - assert Locale.parse('fi_FI').get_display_name('kw_GB') == None + assert Locale.parse('fi_FI').get_display_name('kw_GB') is None def test_issue_814(): diff --git a/tests/test_date_intervals.py b/tests/test_date_intervals.py index 8e84a9e..5565854 100644 --- a/tests/test_date_intervals.py +++ b/tests/test_date_intervals.py @@ -46,8 +46,8 @@ def test_format_interval_12_hour(): def test_format_interval_invalid_skeleton(): t1 = TEST_DATE t2 = TEST_DATE + datetime.timedelta(days=1) - assert dates.format_interval(t1, t2, "mumumu", fuzzy=False, locale="fi") == u"8.1.2016\u20139.1.2016" - assert dates.format_interval(t1, t2, fuzzy=False, locale="fi") == u"8.1.2016\u20139.1.2016" + assert dates.format_interval(t1, t2, "mumumu", fuzzy=False, locale="fi") == "8.1.2016\u20139.1.2016" + assert dates.format_interval(t1, t2, fuzzy=False, locale="fi") == "8.1.2016\u20139.1.2016" def test_issue_825(): diff --git a/tests/test_dates.py b/tests/test_dates.py index a4fb9c5..0c8bd17 100644 --- a/tests/test_dates.py +++ b/tests/test_dates.py @@ -16,7 +16,7 @@ from datetime import date, datetime, time, timedelta import freezegun import pytest -from babel import dates, Locale +from babel import Locale, dates from babel.dates import NO_INHERITANCE_MARKER, _localize from babel.util import FixedOffsetTimezone @@ -68,7 +68,7 @@ class DateTimeFormatTestCase: assert dates.DateTimeFormat(d, locale='en_US')['w'] == '53' def test_week_of_year_de_first_us_last_with_year(self): - d = date(2018,12,31) + d = date(2018, 12, 31) fmt = dates.DateTimeFormat(d, locale='de_DE') assert fmt['w'] == '1' assert fmt['YYYY'] == '2019' @@ -213,20 +213,20 @@ class DateTimeFormatTestCase: def test_timezone_walltime_long(self, timezone_getter): tz = timezone_getter('Europe/Paris') t = time(15, 30, tzinfo=tz) - assert dates.DateTimeFormat(t, locale='fr_FR')['vvvv'] == u'heure d’Europe centrale' + assert dates.DateTimeFormat(t, locale='fr_FR')['vvvv'] == 'heure d’Europe centrale' def test_hour_formatting(self): - l = 'en_US' + locale = 'en_US' t = time(0, 0, 0) - assert dates.format_time(t, 'h a', locale=l) == '12 AM' - assert dates.format_time(t, 'H', locale=l) == '0' - assert dates.format_time(t, 'k', locale=l) == '24' - assert dates.format_time(t, 'K a', locale=l) == '0 AM' + assert dates.format_time(t, 'h a', locale=locale) == '12 AM' + assert dates.format_time(t, 'H', locale=locale) == '0' + assert dates.format_time(t, 'k', locale=locale) == '24' + assert dates.format_time(t, 'K a', locale=locale) == '0 AM' t = time(12, 0, 0) - assert dates.format_time(t, 'h a', locale=l) == '12 PM' - assert dates.format_time(t, 'H', locale=l) == '12' - assert dates.format_time(t, 'k', locale=l) == '12' - assert dates.format_time(t, 'K a', locale=l) == '0 PM' + assert dates.format_time(t, 'h a', locale=locale) == '12 PM' + assert dates.format_time(t, 'H', locale=locale) == '12' + assert dates.format_time(t, 'k', locale=locale) == '12' + assert dates.format_time(t, 'K a', locale=locale) == '0 PM' class FormatDateTestCase: @@ -252,75 +252,75 @@ class FormatDatetimeTestCase: d = datetime(2012, 4, 1, 15, 30, 29, tzinfo=UTC) epoch = float(calendar.timegm(d.timetuple())) formatted_string = dates.format_datetime(epoch, format='long', locale='en_US') - assert formatted_string == u'April 1, 2012 at 3:30:29 PM UTC' + assert formatted_string == 'April 1, 2012 at 3:30:29 PM UTC' def test_timezone_formats_los_angeles(self, timezone_getter): tz = timezone_getter('America/Los_Angeles') dt = _localize(tz, datetime(2016, 1, 13, 7, 8, 35)) - assert dates.format_datetime(dt, 'z', locale='en') == u'PST' - assert dates.format_datetime(dt, 'zz', locale='en') == u'PST' - assert dates.format_datetime(dt, 'zzz', locale='en') == u'PST' - assert dates.format_datetime(dt, 'zzzz', locale='en') == u'Pacific Standard Time' - assert dates.format_datetime(dt, 'Z', locale='en') == u'-0800' - assert dates.format_datetime(dt, 'ZZ', locale='en') == u'-0800' - assert dates.format_datetime(dt, 'ZZZ', locale='en') == u'-0800' - assert dates.format_datetime(dt, 'ZZZZ', locale='en') == u'GMT-08:00' - assert dates.format_datetime(dt, 'ZZZZZ', locale='en') == u'-08:00' - assert dates.format_datetime(dt, 'OOOO', locale='en') == u'GMT-08:00' - assert dates.format_datetime(dt, 'VV', locale='en') == u'America/Los_Angeles' - assert dates.format_datetime(dt, 'VVV', locale='en') == u'Los Angeles' - assert dates.format_datetime(dt, 'X', locale='en') == u'-08' - assert dates.format_datetime(dt, 'XX', locale='en') == u'-0800' - assert dates.format_datetime(dt, 'XXX', locale='en') == u'-08:00' - assert dates.format_datetime(dt, 'XXXX', locale='en') == u'-0800' - assert dates.format_datetime(dt, 'XXXXX', locale='en') == u'-08:00' - assert dates.format_datetime(dt, 'x', locale='en') == u'-08' - assert dates.format_datetime(dt, 'xx', locale='en') == u'-0800' - assert dates.format_datetime(dt, 'xxx', locale='en') == u'-08:00' - assert dates.format_datetime(dt, 'xxxx', locale='en') == u'-0800' - assert dates.format_datetime(dt, 'xxxxx', locale='en') == u'-08:00' + assert dates.format_datetime(dt, 'z', locale='en') == 'PST' + assert dates.format_datetime(dt, 'zz', locale='en') == 'PST' + assert dates.format_datetime(dt, 'zzz', locale='en') == 'PST' + assert dates.format_datetime(dt, 'zzzz', locale='en') == 'Pacific Standard Time' + assert dates.format_datetime(dt, 'Z', locale='en') == '-0800' + assert dates.format_datetime(dt, 'ZZ', locale='en') == '-0800' + assert dates.format_datetime(dt, 'ZZZ', locale='en') == '-0800' + assert dates.format_datetime(dt, 'ZZZZ', locale='en') == 'GMT-08:00' + assert dates.format_datetime(dt, 'ZZZZZ', locale='en') == '-08:00' + assert dates.format_datetime(dt, 'OOOO', locale='en') == 'GMT-08:00' + assert dates.format_datetime(dt, 'VV', locale='en') == 'America/Los_Angeles' + assert dates.format_datetime(dt, 'VVV', locale='en') == 'Los Angeles' + assert dates.format_datetime(dt, 'X', locale='en') == '-08' + assert dates.format_datetime(dt, 'XX', locale='en') == '-0800' + assert dates.format_datetime(dt, 'XXX', locale='en') == '-08:00' + assert dates.format_datetime(dt, 'XXXX', locale='en') == '-0800' + assert dates.format_datetime(dt, 'XXXXX', locale='en') == '-08:00' + assert dates.format_datetime(dt, 'x', locale='en') == '-08' + assert dates.format_datetime(dt, 'xx', locale='en') == '-0800' + assert dates.format_datetime(dt, 'xxx', locale='en') == '-08:00' + assert dates.format_datetime(dt, 'xxxx', locale='en') == '-0800' + assert dates.format_datetime(dt, 'xxxxx', locale='en') == '-08:00' def test_timezone_formats_utc(self, timezone_getter): tz = timezone_getter('UTC') dt = _localize(tz, datetime(2016, 1, 13, 7, 8, 35)) - assert dates.format_datetime(dt, 'Z', locale='en') == u'+0000' - assert dates.format_datetime(dt, 'ZZ', locale='en') == u'+0000' - assert dates.format_datetime(dt, 'ZZZ', locale='en') == u'+0000' - assert dates.format_datetime(dt, 'ZZZZ', locale='en') == u'GMT+00:00' - assert dates.format_datetime(dt, 'ZZZZZ', locale='en') == u'Z' - assert dates.format_datetime(dt, 'OOOO', locale='en') == u'GMT+00:00' - assert dates.format_datetime(dt, 'VV', locale='en') == u'Etc/UTC' - assert dates.format_datetime(dt, 'VVV', locale='en') == u'UTC' - assert dates.format_datetime(dt, 'X', locale='en') == u'Z' - assert dates.format_datetime(dt, 'XX', locale='en') == u'Z' - assert dates.format_datetime(dt, 'XXX', locale='en') == u'Z' - assert dates.format_datetime(dt, 'XXXX', locale='en') == u'Z' - assert dates.format_datetime(dt, 'XXXXX', locale='en') == u'Z' - assert dates.format_datetime(dt, 'x', locale='en') == u'+00' - assert dates.format_datetime(dt, 'xx', locale='en') == u'+0000' - assert dates.format_datetime(dt, 'xxx', locale='en') == u'+00:00' - assert dates.format_datetime(dt, 'xxxx', locale='en') == u'+0000' - assert dates.format_datetime(dt, 'xxxxx', locale='en') == u'+00:00' + assert dates.format_datetime(dt, 'Z', locale='en') == '+0000' + assert dates.format_datetime(dt, 'ZZ', locale='en') == '+0000' + assert dates.format_datetime(dt, 'ZZZ', locale='en') == '+0000' + assert dates.format_datetime(dt, 'ZZZZ', locale='en') == 'GMT+00:00' + assert dates.format_datetime(dt, 'ZZZZZ', locale='en') == 'Z' + assert dates.format_datetime(dt, 'OOOO', locale='en') == 'GMT+00:00' + assert dates.format_datetime(dt, 'VV', locale='en') == 'Etc/UTC' + assert dates.format_datetime(dt, 'VVV', locale='en') == 'UTC' + assert dates.format_datetime(dt, 'X', locale='en') == 'Z' + assert dates.format_datetime(dt, 'XX', locale='en') == 'Z' + assert dates.format_datetime(dt, 'XXX', locale='en') == 'Z' + assert dates.format_datetime(dt, 'XXXX', locale='en') == 'Z' + assert dates.format_datetime(dt, 'XXXXX', locale='en') == 'Z' + assert dates.format_datetime(dt, 'x', locale='en') == '+00' + assert dates.format_datetime(dt, 'xx', locale='en') == '+0000' + assert dates.format_datetime(dt, 'xxx', locale='en') == '+00:00' + assert dates.format_datetime(dt, 'xxxx', locale='en') == '+0000' + assert dates.format_datetime(dt, 'xxxxx', locale='en') == '+00:00' def test_timezone_formats_kolkata(self, timezone_getter): tz = timezone_getter('Asia/Kolkata') dt = _localize(tz, datetime(2016, 1, 13, 7, 8, 35)) - assert dates.format_datetime(dt, 'zzzz', locale='en') == u'India Standard Time' - assert dates.format_datetime(dt, 'ZZZZ', locale='en') == u'GMT+05:30' - assert dates.format_datetime(dt, 'ZZZZZ', locale='en') == u'+05:30' - assert dates.format_datetime(dt, 'OOOO', locale='en') == u'GMT+05:30' - assert dates.format_datetime(dt, 'VV', locale='en') == u'Asia/Calcutta' - assert dates.format_datetime(dt, 'VVV', locale='en') == u'Kolkata' - assert dates.format_datetime(dt, 'X', locale='en') == u'+0530' - assert dates.format_datetime(dt, 'XX', locale='en') == u'+0530' - assert dates.format_datetime(dt, 'XXX', locale='en') == u'+05:30' - assert dates.format_datetime(dt, 'XXXX', locale='en') == u'+0530' - assert dates.format_datetime(dt, 'XXXXX', locale='en') == u'+05:30' - assert dates.format_datetime(dt, 'x', locale='en') == u'+0530' - assert dates.format_datetime(dt, 'xx', locale='en') == u'+0530' - assert dates.format_datetime(dt, 'xxx', locale='en') == u'+05:30' - assert dates.format_datetime(dt, 'xxxx', locale='en') == u'+0530' - assert dates.format_datetime(dt, 'xxxxx', locale='en') == u'+05:30' + assert dates.format_datetime(dt, 'zzzz', locale='en') == 'India Standard Time' + assert dates.format_datetime(dt, 'ZZZZ', locale='en') == 'GMT+05:30' + assert dates.format_datetime(dt, 'ZZZZZ', locale='en') == '+05:30' + assert dates.format_datetime(dt, 'OOOO', locale='en') == 'GMT+05:30' + assert dates.format_datetime(dt, 'VV', locale='en') == 'Asia/Calcutta' + assert dates.format_datetime(dt, 'VVV', locale='en') == 'Kolkata' + assert dates.format_datetime(dt, 'X', locale='en') == '+0530' + assert dates.format_datetime(dt, 'XX', locale='en') == '+0530' + assert dates.format_datetime(dt, 'XXX', locale='en') == '+05:30' + assert dates.format_datetime(dt, 'XXXX', locale='en') == '+0530' + assert dates.format_datetime(dt, 'XXXXX', locale='en') == '+05:30' + assert dates.format_datetime(dt, 'x', locale='en') == '+0530' + assert dates.format_datetime(dt, 'xx', locale='en') == '+0530' + assert dates.format_datetime(dt, 'xxx', locale='en') == '+05:30' + assert dates.format_datetime(dt, 'xxxx', locale='en') == '+0530' + assert dates.format_datetime(dt, 'xxxxx', locale='en') == '+05:30' class FormatTimeTestCase: @@ -337,7 +337,7 @@ class FormatTimeTestCase: tz = timezone_getter('UTC') d = _localize(tz, datetime(2012, 4, 1, 15, 30, 29)) epoch = float(calendar.timegm(d.timetuple())) - assert dates.format_time(epoch, format='long', locale='en_US') == u'3:30:29 PM UTC' + assert dates.format_time(epoch, format='long', locale='en_US') == '3:30:29 PM UTC' def test_with_date_fields_in_pattern(self): with pytest.raises(AttributeError): @@ -398,122 +398,122 @@ class TimeZoneAdjustTestCase: def test_get_period_names(): - assert dates.get_period_names(locale='en_US')['am'] == u'AM' + assert dates.get_period_names(locale='en_US')['am'] == 'AM' def test_get_day_names(): - assert dates.get_day_names('wide', locale='en_US')[1] == u'Tuesday' - assert dates.get_day_names('short', locale='en_US')[1] == u'Tu' - assert dates.get_day_names('abbreviated', locale='es')[1] == u'mar' + assert dates.get_day_names('wide', locale='en_US')[1] == 'Tuesday' + assert dates.get_day_names('short', locale='en_US')[1] == 'Tu' + assert dates.get_day_names('abbreviated', locale='es')[1] == 'mar' de = dates.get_day_names('narrow', context='stand-alone', locale='de_DE') - assert de[1] == u'D' + assert de[1] == 'D' def test_get_month_names(): - assert dates.get_month_names('wide', locale='en_US')[1] == u'January' - assert dates.get_month_names('abbreviated', locale='es')[1] == u'ene' + assert dates.get_month_names('wide', locale='en_US')[1] == 'January' + assert dates.get_month_names('abbreviated', locale='es')[1] == 'ene' de = dates.get_month_names('narrow', context='stand-alone', locale='de_DE') - assert de[1] == u'J' + assert de[1] == 'J' def test_get_quarter_names(): - assert dates.get_quarter_names('wide', locale='en_US')[1] == u'1st quarter' - assert dates.get_quarter_names('abbreviated', locale='de_DE')[1] == u'Q1' - assert dates.get_quarter_names('narrow', locale='de_DE')[1] == u'1' + assert dates.get_quarter_names('wide', locale='en_US')[1] == '1st quarter' + assert dates.get_quarter_names('abbreviated', locale='de_DE')[1] == 'Q1' + assert dates.get_quarter_names('narrow', locale='de_DE')[1] == '1' def test_get_era_names(): - assert dates.get_era_names('wide', locale='en_US')[1] == u'Anno Domini' - assert dates.get_era_names('abbreviated', locale='de_DE')[1] == u'n. Chr.' + assert dates.get_era_names('wide', locale='en_US')[1] == 'Anno Domini' + assert dates.get_era_names('abbreviated', locale='de_DE')[1] == 'n. Chr.' def test_get_date_format(): us = dates.get_date_format(locale='en_US') - assert us.pattern == u'MMM d, y' + assert us.pattern == 'MMM d, y' de = dates.get_date_format('full', locale='de_DE') - assert de.pattern == u'EEEE, d. MMMM y' + assert de.pattern == 'EEEE, d. MMMM y' def test_get_datetime_format(): - assert dates.get_datetime_format(locale='en_US') == u'{1}, {0}' + assert dates.get_datetime_format(locale='en_US') == '{1}, {0}' def test_get_time_format(): - assert dates.get_time_format(locale='en_US').pattern == u'h:mm:ss a' + assert dates.get_time_format(locale='en_US').pattern == 'h:mm:ss a' assert (dates.get_time_format('full', locale='de_DE').pattern == - u'HH:mm:ss zzzz') + 'HH:mm:ss zzzz') def test_get_timezone_gmt(timezone_getter): dt = datetime(2007, 4, 1, 15, 30) - assert dates.get_timezone_gmt(dt, locale='en') == u'GMT+00:00' + assert dates.get_timezone_gmt(dt, locale='en') == 'GMT+00:00' assert dates.get_timezone_gmt(dt, locale='en', return_z=True) == 'Z' - assert dates.get_timezone_gmt(dt, locale='en', width='iso8601_short') == u'+00' + assert dates.get_timezone_gmt(dt, locale='en', width='iso8601_short') == '+00' tz = timezone_getter('America/Los_Angeles') dt = _localize(tz, datetime(2007, 4, 1, 15, 30)) - assert dates.get_timezone_gmt(dt, locale='en') == u'GMT-07:00' - assert dates.get_timezone_gmt(dt, 'short', locale='en') == u'-0700' - assert dates.get_timezone_gmt(dt, locale='en', width='iso8601_short') == u'-07' - assert dates.get_timezone_gmt(dt, 'long', locale='fr_FR') == u'UTC-07:00' + assert dates.get_timezone_gmt(dt, locale='en') == 'GMT-07:00' + assert dates.get_timezone_gmt(dt, 'short', locale='en') == '-0700' + assert dates.get_timezone_gmt(dt, locale='en', width='iso8601_short') == '-07' + assert dates.get_timezone_gmt(dt, 'long', locale='fr_FR') == 'UTC-07:00' def test_get_timezone_location(timezone_getter): tz = timezone_getter('America/St_Johns') assert (dates.get_timezone_location(tz, locale='de_DE') == - u"Kanada (St. John\u2019s) Zeit") + "Kanada (St. John\u2019s) Zeit") assert (dates.get_timezone_location(tz, locale='en') == - u'Canada (St. John’s) Time') + 'Canada (St. John’s) Time') assert (dates.get_timezone_location(tz, locale='en', return_city=True) == - u'St. John’s') + 'St. John’s') tz = timezone_getter('America/Mexico_City') assert (dates.get_timezone_location(tz, locale='de_DE') == - u'Mexiko (Mexiko-Stadt) Zeit') + 'Mexiko (Mexiko-Stadt) Zeit') tz = timezone_getter('Europe/Berlin') assert (dates.get_timezone_location(tz, locale='de_DE') == - u'Deutschland (Berlin) Zeit') + 'Deutschland (Berlin) Zeit') @pytest.mark.parametrize( "tzname, params, expected", [ - ("America/Los_Angeles", {"locale": "en_US"}, u"Pacific Time"), - ("America/Los_Angeles", {"width": "short", "locale": "en_US"}, u"PT"), - ("Europe/Berlin", {"locale": "de_DE"}, u"Mitteleurop\xe4ische Zeit"), - ("Europe/Berlin", {"locale": "pt_BR"}, u"Hor\xe1rio da Europa Central"), - ("America/St_Johns", {"locale": "de_DE"}, u"Neufundland-Zeit"), + ("America/Los_Angeles", {"locale": "en_US"}, "Pacific Time"), + ("America/Los_Angeles", {"width": "short", "locale": "en_US"}, "PT"), + ("Europe/Berlin", {"locale": "de_DE"}, "Mitteleurop\xe4ische Zeit"), + ("Europe/Berlin", {"locale": "pt_BR"}, "Hor\xe1rio da Europa Central"), + ("America/St_Johns", {"locale": "de_DE"}, "Neufundland-Zeit"), ( "America/Los_Angeles", {"locale": "en", "width": "short", "zone_variant": "generic"}, - u"PT", + "PT", ), ( "America/Los_Angeles", {"locale": "en", "width": "short", "zone_variant": "standard"}, - u"PST", + "PST", ), ( "America/Los_Angeles", {"locale": "en", "width": "short", "zone_variant": "daylight"}, - u"PDT", + "PDT", ), ( "America/Los_Angeles", {"locale": "en", "width": "long", "zone_variant": "generic"}, - u"Pacific Time", + "Pacific Time", ), ( "America/Los_Angeles", {"locale": "en", "width": "long", "zone_variant": "standard"}, - u"Pacific Standard Time", + "Pacific Standard Time", ), ( "America/Los_Angeles", {"locale": "en", "width": "long", "zone_variant": "daylight"}, - u"Pacific Daylight Time", + "Pacific Daylight Time", ), - ("Europe/Berlin", {"locale": "en_US"}, u"Central European Time"), + ("Europe/Berlin", {"locale": "en_US"}, "Central European Time"), ], ) def test_get_timezone_name_tzinfo(timezone_getter, tzname, params, expected): @@ -525,13 +525,13 @@ def test_get_timezone_name_tzinfo(timezone_getter, tzname, params, expected): @pytest.mark.parametrize( "tzname, params, expected", [ - ("America/Los_Angeles", {"locale": "en_US"}, u"Pacific Standard Time"), + ("America/Los_Angeles", {"locale": "en_US"}, "Pacific Standard Time"), ( "America/Los_Angeles", {"locale": "en_US", "return_zone": True}, - u"America/Los_Angeles", + "America/Los_Angeles", ), - ("America/Los_Angeles", {"width": "short", "locale": "en_US"}, u"PST"), + ("America/Los_Angeles", {"width": "short", "locale": "en_US"}, "PST"), ], ) def test_get_timezone_name_time_pytz(timezone_getter, tzname, params, expected): @@ -554,40 +554,42 @@ def test_get_timezone_name_misc(timezone_getter): def test_format_date(): d = date(2007, 4, 1) - assert dates.format_date(d, locale='en_US') == u'Apr 1, 2007' + assert dates.format_date(d, locale='en_US') == 'Apr 1, 2007' assert (dates.format_date(d, format='full', locale='de_DE') == - u'Sonntag, 1. April 2007') + 'Sonntag, 1. April 2007') assert (dates.format_date(d, "EEE, MMM d, ''yy", locale='en') == - u"Sun, Apr 1, '07") + "Sun, Apr 1, '07") def test_format_datetime(timezone_getter): dt = datetime(2007, 4, 1, 15, 30) assert (dates.format_datetime(dt, locale='en_US') == - u'Apr 1, 2007, 3:30:00 PM') + 'Apr 1, 2007, 3:30:00 PM') full = dates.format_datetime( dt, 'full', tzinfo=timezone_getter('Europe/Paris'), locale='fr_FR' ) - assert full == (u'dimanche 1 avril 2007 à 17:30:00 heure ' - u'd\u2019\xe9t\xe9 d\u2019Europe centrale') + assert full == ( + 'dimanche 1 avril 2007 à 17:30:00 heure ' + 'd\u2019\xe9t\xe9 d\u2019Europe centrale' + ) custom = dates.format_datetime( dt, "yyyy.MM.dd G 'at' HH:mm:ss zzz", tzinfo=timezone_getter('US/Eastern'), locale='en' ) - assert custom == u'2007.04.01 AD at 11:30:00 EDT' + assert custom == '2007.04.01 AD at 11:30:00 EDT' def test_format_time(timezone_getter): t = time(15, 30) - assert dates.format_time(t, locale='en_US') == u'3:30:00 PM' - assert dates.format_time(t, format='short', locale='de_DE') == u'15:30' + assert dates.format_time(t, locale='en_US') == '3:30:00 PM' + assert dates.format_time(t, format='short', locale='de_DE') == '15:30' assert (dates.format_time(t, "hh 'o''clock' a", locale='en') == - u"03 o'clock PM") + "03 o'clock PM") paris = timezone_getter('Europe/Paris') eastern = timezone_getter('US/Eastern') @@ -597,41 +599,41 @@ def test_format_time(timezone_getter): assert fr == '15:30:00 heure d’été d’Europe centrale' custom = dates.format_time(t, "hh 'o''clock' a, zzzz", tzinfo=eastern, locale='en') - assert custom == u"09 o'clock AM, Eastern Daylight Time" + assert custom == "09 o'clock AM, Eastern Daylight Time" t = time(15, 30) paris = dates.format_time(t, format='full', tzinfo=paris, locale='fr_FR') assert paris == '15:30:00 heure normale d’Europe centrale' us_east = dates.format_time(t, format='full', tzinfo=eastern, locale='en_US') - assert us_east == u'3:30:00 PM Eastern Standard Time' + assert us_east == '3:30:00 PM Eastern Standard Time' def test_format_skeleton(timezone_getter): dt = datetime(2007, 4, 1, 15, 30) - assert (dates.format_skeleton('yMEd', dt, locale='en_US') == u'Sun, 4/1/2007') - assert (dates.format_skeleton('yMEd', dt, locale='th') == u'อา. 1/4/2007') + assert (dates.format_skeleton('yMEd', dt, locale='en_US') == 'Sun, 4/1/2007') + assert (dates.format_skeleton('yMEd', dt, locale='th') == 'อา. 1/4/2007') - assert (dates.format_skeleton('EHm', dt, locale='en') == u'Sun 15:30') - assert (dates.format_skeleton('EHm', dt, tzinfo=timezone_getter('Asia/Bangkok'), locale='th') == u'อา. 22:30 น.') + assert (dates.format_skeleton('EHm', dt, locale='en') == 'Sun 15:30') + assert (dates.format_skeleton('EHm', dt, tzinfo=timezone_getter('Asia/Bangkok'), locale='th') == 'อา. 22:30 น.') def test_format_timedelta(): assert (dates.format_timedelta(timedelta(weeks=12), locale='en_US') - == u'3 months') + == '3 months') assert (dates.format_timedelta(timedelta(seconds=1), locale='es') - == u'1 segundo') + == '1 segundo') assert (dates.format_timedelta(timedelta(hours=3), granularity='day', locale='en_US') - == u'1 day') + == '1 day') assert (dates.format_timedelta(timedelta(hours=23), threshold=0.9, locale='en_US') - == u'1 day') + == '1 day') assert (dates.format_timedelta(timedelta(hours=23), threshold=1.1, locale='en_US') - == u'23 hours') + == '23 hours') def test_parse_date(): @@ -679,24 +681,24 @@ def test_datetime_format_get_week_number(): def test_parse_pattern(): - assert dates.parse_pattern("MMMMd").format == u'%(MMMM)s%(d)s' + assert dates.parse_pattern("MMMMd").format == '%(MMMM)s%(d)s' assert (dates.parse_pattern("MMM d, yyyy").format == - u'%(MMM)s %(d)s, %(yyyy)s') + '%(MMM)s %(d)s, %(yyyy)s') assert (dates.parse_pattern("H:mm' Uhr 'z").format == - u'%(H)s:%(mm)s Uhr %(z)s') - assert dates.parse_pattern("hh' o''clock'").format == u"%(hh)s o'clock" + '%(H)s:%(mm)s Uhr %(z)s') + assert dates.parse_pattern("hh' o''clock'").format == "%(hh)s o'clock" def test_lithuanian_long_format(): assert ( dates.format_date(date(2015, 12, 10), locale='lt_LT', format='long') == - u'2015 m. gruodžio 10 d.' + '2015 m. gruodžio 10 d.' ) def test_zh_TW_format(): # Refs GitHub issue #378 - assert dates.format_time(datetime(2016, 4, 8, 12, 34, 56), locale='zh_TW') == u'中午12:34:56' + assert dates.format_time(datetime(2016, 4, 8, 12, 34, 56), locale='zh_TW') == '中午12:34:56' def test_format_current_moment(): @@ -727,8 +729,8 @@ def test_no_inherit_metazone_formatting(timezone_getter): def test_russian_week_numbering(): # See https://github.com/python-babel/babel/issues/485 v = date(2017, 1, 1) - assert dates.format_date(v, format='YYYY-ww',locale='ru_RU') == '2016-52' # This would have returned 2017-01 prior to CLDR 32 - assert dates.format_date(v, format='YYYY-ww',locale='de_DE') == '2016-52' + assert dates.format_date(v, format='YYYY-ww', locale='ru_RU') == '2016-52' # This would have returned 2017-01 prior to CLDR 32 + assert dates.format_date(v, format='YYYY-ww', locale='de_DE') == '2016-52' def test_en_gb_first_weekday(): diff --git a/tests/test_day_periods.py b/tests/test_day_periods.py index 414c0f6..9b51e1d 100644 --- a/tests/test_day_periods.py +++ b/tests/test_day_periods.py @@ -1,8 +1,9 @@ from datetime import time -import babel.dates as dates import pytest +import babel.dates as dates + @pytest.mark.parametrize("locale, time, expected_period_id", [ ("de", time(7, 42), "morning1"), # (from, before) diff --git a/tests/test_lists.py b/tests/test_lists.py index e51f18b..ca9c6ab 100644 --- a/tests/test_lists.py +++ b/tests/test_lists.py @@ -6,11 +6,11 @@ from babel import lists def test_format_list(): for list, locale, expected in [ ([], 'en', ''), - ([u'string'], 'en', u'string'), - (['string1', 'string2'], 'en', u'string1 and string2'), - (['string1', 'string2', 'string3'], 'en', u'string1, string2, and string3'), - (['string1', 'string2', 'string3'], 'zh', u'string1、string2和string3'), - (['string1', 'string2', 'string3', 'string4'], 'ne', u'string1,string2, string3 र string4'), + (['string'], 'en', 'string'), + (['string1', 'string2'], 'en', 'string1 and string2'), + (['string1', 'string2', 'string3'], 'en', 'string1, string2, and string3'), + (['string1', 'string2', 'string3'], 'zh', 'string1、string2和string3'), + (['string1', 'string2', 'string3', 'string4'], 'ne', 'string1,string2, string3 र string4'), ]: assert lists.format_list(list, locale=locale) == expected diff --git a/tests/test_localedata.py b/tests/test_localedata.py index 7bfe9c6..913922e 100644 --- a/tests/test_localedata.py +++ b/tests/test_localedata.py @@ -12,15 +12,15 @@ import os import pickle +import random import sys import tempfile import unittest -import random from operator import methodcaller import pytest -from babel import localedata, Locale, UnknownLocaleError +from babel import Locale, UnknownLocaleError, localedata class MergeResolveTestCase(unittest.TestCase): @@ -70,8 +70,8 @@ def test_merge(): def test_locale_identification(): - for l in localedata.locale_identifiers(): - assert localedata.exists(l) + for locale in localedata.locale_identifiers(): + assert localedata.exists(locale) def test_unique_ids(): @@ -84,9 +84,9 @@ def test_unique_ids(): def test_mixedcased_locale(): - for l in localedata.locale_identifiers(): + for locale in localedata.locale_identifiers(): locale_id = ''.join([ - methodcaller(random.choice(['lower', 'upper']))(c) for c in l]) + methodcaller(random.choice(['lower', 'upper']))(c) for c in locale]) assert localedata.exists(locale_id) @@ -94,19 +94,18 @@ def test_locale_argument_acceptance(): # Testing None input. normalized_locale = localedata.normalize_locale(None) assert normalized_locale is None - locale_exist = localedata.exists(None) - assert locale_exist == False + assert not localedata.exists(None) - # # Testing list input. + # Testing list input. normalized_locale = localedata.normalize_locale(['en_us', None]) assert normalized_locale is None - locale_exist = localedata.exists(['en_us', None]) - assert locale_exist == False + assert not localedata.exists(['en_us', None]) def test_locale_identifiers_cache(monkeypatch): original_listdir = localedata.os.listdir listdir_calls = [] + def listdir_spy(*args): rv = original_listdir(*args) listdir_calls.append((args, rv)) diff --git a/tests/test_numbers.py b/tests/test_numbers.py index 0939562..04a1865 100644 --- a/tests/test_numbers.py +++ b/tests/test_numbers.py @@ -12,14 +12,21 @@ import decimal import unittest -import pytest - from datetime import date +import pytest + from babel import localedata, numbers from babel.numbers import ( - list_currencies, validate_currency, UnknownCurrencyError, is_currency, normalize_currency, - get_currency_precision, get_decimal_precision, get_currency_unit_pattern) + UnknownCurrencyError, + get_currency_precision, + get_currency_unit_pattern, + get_decimal_precision, + is_currency, + list_currencies, + normalize_currency, + validate_currency, +) class FormatDecimalTestCase(unittest.TestCase): @@ -31,7 +38,7 @@ class FormatDecimalTestCase(unittest.TestCase): # regression test for #183, fraction digits were not correctly cut # if the input was a float value and the value had more than 7 # significant digits - assert numbers.format_decimal(12345678.051, '#,##0.00', locale='en_US') == u'12,345,678.05' + assert numbers.format_decimal(12345678.051, '#,##0.00', locale='en_US') == '12,345,678.05' def test_subpatterns(self): assert numbers.format_decimal((- 12345), '#,##0.##;-#', locale='en_US') == '-12,345' @@ -108,57 +115,58 @@ class FormatDecimalTestCase(unittest.TestCase): assert numbers.format_decimal(29567.12, locale='en_US', group_separator=False) == '29567.12' assert numbers.format_decimal(29567.12, locale='fr_CA', group_separator=False) == '29567,12' assert numbers.format_decimal(29567.12, locale='pt_BR', group_separator=False) == '29567,12' - assert numbers.format_currency(1099.98, 'USD', locale='en_US', group_separator=False) == u'$1099.98' - assert numbers.format_currency(101299.98, 'EUR', locale='fr_CA', group_separator=False) == u'101299,98\xa0€' + assert numbers.format_currency(1099.98, 'USD', locale='en_US', group_separator=False) == '$1099.98' + assert numbers.format_currency(101299.98, 'EUR', locale='fr_CA', group_separator=False) == '101299,98\xa0€' assert numbers.format_currency(101299.98, 'EUR', locale='en_US', group_separator=False, format_type='name') == '101299.98 euros' - assert numbers.format_percent(251234.1234, locale='sv_SE', group_separator=False) == u'25123412\xa0%' + assert numbers.format_percent(251234.1234, locale='sv_SE', group_separator=False) == '25123412\xa0%' - assert numbers.format_decimal(29567.12, locale='en_US', group_separator=True) == u'29,567.12' - assert numbers.format_decimal(29567.12, locale='fr_CA', group_separator=True) == u'29\xa0567,12' - assert numbers.format_decimal(29567.12, locale='pt_BR', group_separator=True) == u'29.567,12' - assert numbers.format_currency(1099.98, 'USD', locale='en_US', group_separator=True) == u'$1,099.98' - assert numbers.format_currency(101299.98, 'EUR', locale='fr_CA', group_separator=True) == u'101\xa0299,98\xa0€' - assert numbers.format_currency(101299.98, 'EUR', locale='en_US', group_separator=True, format_type='name') == u'101,299.98 euros' - assert numbers.format_percent(251234.1234, locale='sv_SE', group_separator=True) == u'25\xa0123\xa0412\xa0%' + assert numbers.format_decimal(29567.12, locale='en_US', group_separator=True) == '29,567.12' + assert numbers.format_decimal(29567.12, locale='fr_CA', group_separator=True) == '29\xa0567,12' + assert numbers.format_decimal(29567.12, locale='pt_BR', group_separator=True) == '29.567,12' + assert numbers.format_currency(1099.98, 'USD', locale='en_US', group_separator=True) == '$1,099.98' + assert numbers.format_currency(101299.98, 'EUR', locale='fr_CA', group_separator=True) == '101\xa0299,98\xa0€' + assert numbers.format_currency(101299.98, 'EUR', locale='en_US', group_separator=True, format_type='name') == '101,299.98 euros' + assert numbers.format_percent(251234.1234, locale='sv_SE', group_separator=True) == '25\xa0123\xa0412\xa0%' def test_compact(self): - assert numbers.format_compact_decimal(1, locale='en_US', format_type="short") == u'1' - assert numbers.format_compact_decimal(999, locale='en_US', format_type="short") == u'999' - assert numbers.format_compact_decimal(1000, locale='en_US', format_type="short") == u'1K' - assert numbers.format_compact_decimal(9000, locale='en_US', format_type="short") == u'9K' - assert numbers.format_compact_decimal(9123, locale='en_US', format_type="short", fraction_digits=2) == u'9.12K' - assert numbers.format_compact_decimal(10000, locale='en_US', format_type="short") == u'10K' - assert numbers.format_compact_decimal(10000, locale='en_US', format_type="short", fraction_digits=2) == u'10K' - assert numbers.format_compact_decimal(1000000, locale='en_US', format_type="short") == u'1M' - assert numbers.format_compact_decimal(9000999, locale='en_US', format_type="short") == u'9M' - assert numbers.format_compact_decimal(9000900099, locale='en_US', format_type="short", fraction_digits=5) == u'9.0009B' - assert numbers.format_compact_decimal(1, locale='en_US', format_type="long") == u'1' - assert numbers.format_compact_decimal(999, locale='en_US', format_type="long") == u'999' - assert numbers.format_compact_decimal(1000, locale='en_US', format_type="long") == u'1 thousand' - assert numbers.format_compact_decimal(9000, locale='en_US', format_type="long") == u'9 thousand' - assert numbers.format_compact_decimal(9000, locale='en_US', format_type="long", fraction_digits=2) == u'9 thousand' - assert numbers.format_compact_decimal(10000, locale='en_US', format_type="long") == u'10 thousand' - assert numbers.format_compact_decimal(10000, locale='en_US', format_type="long", fraction_digits=2) == u'10 thousand' - assert numbers.format_compact_decimal(1000000, locale='en_US', format_type="long") == u'1 million' - assert numbers.format_compact_decimal(9999999, locale='en_US', format_type="long") == u'10 million' - assert numbers.format_compact_decimal(9999999999, locale='en_US', format_type="long", fraction_digits=5) == u'10 billion' - assert numbers.format_compact_decimal(1, locale='ja_JP', format_type="short") == u'1' - assert numbers.format_compact_decimal(999, locale='ja_JP', format_type="short") == u'999' - assert numbers.format_compact_decimal(1000, locale='ja_JP', format_type="short") == u'1000' - assert numbers.format_compact_decimal(9123, locale='ja_JP', format_type="short") == u'9123' - assert numbers.format_compact_decimal(10000, locale='ja_JP', format_type="short") == u'1万' - assert numbers.format_compact_decimal(1234567, locale='ja_JP', format_type="long") == u'123万' - assert numbers.format_compact_decimal(-1, locale='en_US', format_type="short") == u'-1' - assert numbers.format_compact_decimal(-1234, locale='en_US', format_type="short", fraction_digits=2) == u'-1.23K' - assert numbers.format_compact_decimal(-123456789, format_type='short', locale='en_US') == u'-123M' - assert numbers.format_compact_decimal(-123456789, format_type='long', locale='en_US') == u'-123 million' - assert numbers.format_compact_decimal(2345678, locale='mk', format_type='long') == u'2 милиони' - assert numbers.format_compact_decimal(21000000, locale='mk', format_type='long') == u'21 милион' - assert numbers.format_compact_decimal(21345, locale="gv", format_type="short") == u'21K' - assert numbers.format_compact_decimal(1000, locale='it', format_type='long') == u'mille' - assert numbers.format_compact_decimal(1234, locale='it', format_type='long') == u'1 mila' - assert numbers.format_compact_decimal(1000, locale='fr', format_type='long') == u'mille' - assert numbers.format_compact_decimal(1234, locale='fr', format_type='long') == u'1 millier' + assert numbers.format_compact_decimal(1, locale='en_US', format_type="short") == '1' + assert numbers.format_compact_decimal(999, locale='en_US', format_type="short") == '999' + assert numbers.format_compact_decimal(1000, locale='en_US', format_type="short") == '1K' + assert numbers.format_compact_decimal(9000, locale='en_US', format_type="short") == '9K' + assert numbers.format_compact_decimal(9123, locale='en_US', format_type="short", fraction_digits=2) == '9.12K' + assert numbers.format_compact_decimal(10000, locale='en_US', format_type="short") == '10K' + assert numbers.format_compact_decimal(10000, locale='en_US', format_type="short", fraction_digits=2) == '10K' + assert numbers.format_compact_decimal(1000000, locale='en_US', format_type="short") == '1M' + assert numbers.format_compact_decimal(9000999, locale='en_US', format_type="short") == '9M' + assert numbers.format_compact_decimal(9000900099, locale='en_US', format_type="short", fraction_digits=5) == '9.0009B' + assert numbers.format_compact_decimal(1, locale='en_US', format_type="long") == '1' + assert numbers.format_compact_decimal(999, locale='en_US', format_type="long") == '999' + assert numbers.format_compact_decimal(1000, locale='en_US', format_type="long") == '1 thousand' + assert numbers.format_compact_decimal(9000, locale='en_US', format_type="long") == '9 thousand' + assert numbers.format_compact_decimal(9000, locale='en_US', format_type="long", fraction_digits=2) == '9 thousand' + assert numbers.format_compact_decimal(10000, locale='en_US', format_type="long") == '10 thousand' + assert numbers.format_compact_decimal(10000, locale='en_US', format_type="long", fraction_digits=2) == '10 thousand' + assert numbers.format_compact_decimal(1000000, locale='en_US', format_type="long") == '1 million' + assert numbers.format_compact_decimal(9999999, locale='en_US', format_type="long") == '10 million' + assert numbers.format_compact_decimal(9999999999, locale='en_US', format_type="long", fraction_digits=5) == '10 billion' + assert numbers.format_compact_decimal(1, locale='ja_JP', format_type="short") == '1' + assert numbers.format_compact_decimal(999, locale='ja_JP', format_type="short") == '999' + assert numbers.format_compact_decimal(1000, locale='ja_JP', format_type="short") == '1000' + assert numbers.format_compact_decimal(9123, locale='ja_JP', format_type="short") == '9123' + assert numbers.format_compact_decimal(10000, locale='ja_JP', format_type="short") == '1万' + assert numbers.format_compact_decimal(1234567, locale='ja_JP', format_type="long") == '123万' + assert numbers.format_compact_decimal(-1, locale='en_US', format_type="short") == '-1' + assert numbers.format_compact_decimal(-1234, locale='en_US', format_type="short", fraction_digits=2) == '-1.23K' + assert numbers.format_compact_decimal(-123456789, format_type='short', locale='en_US') == '-123M' + assert numbers.format_compact_decimal(-123456789, format_type='long', locale='en_US') == '-123 million' + assert numbers.format_compact_decimal(2345678, locale='mk', format_type='long') == '2 милиони' + assert numbers.format_compact_decimal(21000000, locale='mk', format_type='long') == '21 милион' + assert numbers.format_compact_decimal(21345, locale="gv", format_type="short") == '21K' + assert numbers.format_compact_decimal(1000, locale='it', format_type='long') == 'mille' + assert numbers.format_compact_decimal(1234, locale='it', format_type='long') == '1 mila' + assert numbers.format_compact_decimal(1000, locale='fr', format_type='long') == 'mille' + assert numbers.format_compact_decimal(1234, locale='fr', format_type='long') == '1 millier' + class NumberParsingTestCase(unittest.TestCase): @@ -224,15 +232,15 @@ def test_validate_currency(): def test_is_currency(): - assert is_currency('EUR') == True - assert is_currency('eUr') == False - assert is_currency('FUU') == False - assert is_currency('') == False - assert is_currency(None) == False - assert is_currency(' EUR ') == False - assert is_currency(' ') == False - assert is_currency([]) == False - assert is_currency(set()) == False + assert is_currency('EUR') + assert not is_currency('eUr') + assert not is_currency('FUU') + assert not is_currency('') + assert not is_currency(None) + assert not is_currency(' EUR ') + assert not is_currency(' ') + assert not is_currency([]) + assert not is_currency(set()) def test_normalize_currency(): @@ -248,12 +256,12 @@ def test_normalize_currency(): def test_get_currency_name(): - assert numbers.get_currency_name('USD', locale='en_US') == u'US Dollar' - assert numbers.get_currency_name('USD', count=2, locale='en_US') == u'US dollars' + assert numbers.get_currency_name('USD', locale='en_US') == 'US Dollar' + assert numbers.get_currency_name('USD', count=2, locale='en_US') == 'US dollars' def test_get_currency_symbol(): - assert numbers.get_currency_symbol('USD', 'en_US') == u'$' + assert numbers.get_currency_symbol('USD', 'en_US') == '$' def test_get_currency_precision(): @@ -294,24 +302,24 @@ def test_get_territory_currencies(): def test_get_decimal_symbol(): - assert numbers.get_decimal_symbol('en_US') == u'.' + assert numbers.get_decimal_symbol('en_US') == '.' def test_get_plus_sign_symbol(): - assert numbers.get_plus_sign_symbol('en_US') == u'+' + assert numbers.get_plus_sign_symbol('en_US') == '+' def test_get_minus_sign_symbol(): - assert numbers.get_minus_sign_symbol('en_US') == u'-' - assert numbers.get_minus_sign_symbol('nl_NL') == u'-' + assert numbers.get_minus_sign_symbol('en_US') == '-' + assert numbers.get_minus_sign_symbol('nl_NL') == '-' def test_get_exponential_symbol(): - assert numbers.get_exponential_symbol('en_US') == u'E' + assert numbers.get_exponential_symbol('en_US') == 'E' def test_get_group_symbol(): - assert numbers.get_group_symbol('en_US') == u',' + assert numbers.get_group_symbol('en_US') == ',' def test_decimal_precision(): @@ -321,18 +329,18 @@ def test_decimal_precision(): def test_format_decimal(): - assert numbers.format_decimal(1099, locale='en_US') == u'1,099' - assert numbers.format_decimal(1099, locale='de_DE') == u'1.099' - assert numbers.format_decimal(1.2345, locale='en_US') == u'1.234' - assert numbers.format_decimal(1.2346, locale='en_US') == u'1.235' - assert numbers.format_decimal(-1.2346, locale='en_US') == u'-1.235' - assert numbers.format_decimal(1.2345, locale='sv_SE') == u'1,234' - assert numbers.format_decimal(1.2345, locale='de') == u'1,234' - assert numbers.format_decimal(12345.5, locale='en_US') == u'12,345.5' - assert numbers.format_decimal(0001.2345000, locale='en_US') == u'1.234' - assert numbers.format_decimal(-0001.2346000, locale='en_US') == u'-1.235' - assert numbers.format_decimal(0000000.5, locale='en_US') == u'0.5' - assert numbers.format_decimal(000, locale='en_US') == u'0' + assert numbers.format_decimal(1099, locale='en_US') == '1,099' + assert numbers.format_decimal(1099, locale='de_DE') == '1.099' + assert numbers.format_decimal(1.2345, locale='en_US') == '1.234' + assert numbers.format_decimal(1.2346, locale='en_US') == '1.235' + assert numbers.format_decimal(-1.2346, locale='en_US') == '-1.235' + assert numbers.format_decimal(1.2345, locale='sv_SE') == '1,234' + assert numbers.format_decimal(1.2345, locale='de') == '1,234' + assert numbers.format_decimal(12345.5, locale='en_US') == '12,345.5' + assert numbers.format_decimal(0001.2345000, locale='en_US') == '1.234' + assert numbers.format_decimal(-0001.2346000, locale='en_US') == '-1.235' + assert numbers.format_decimal(0000000.5, locale='en_US') == '0.5' + assert numbers.format_decimal(000, locale='en_US') == '0' @pytest.mark.parametrize('input_value, expected_value', [ @@ -372,43 +380,43 @@ def test_format_decimal_quantization(): def test_format_currency(): assert (numbers.format_currency(1099.98, 'USD', locale='en_US') - == u'$1,099.98') + == '$1,099.98') assert (numbers.format_currency(0, 'USD', locale='en_US') - == u'$0.00') + == '$0.00') assert (numbers.format_currency(1099.98, 'USD', locale='es_CO') - == u'US$\xa01.099,98') + == 'US$\xa01.099,98') assert (numbers.format_currency(1099.98, 'EUR', locale='de_DE') - == u'1.099,98\xa0\u20ac') - assert (numbers.format_currency(1099.98, 'EUR', u'\xa4\xa4 #,##0.00', + == '1.099,98\xa0\u20ac') + assert (numbers.format_currency(1099.98, 'EUR', '\xa4\xa4 #,##0.00', locale='en_US') - == u'EUR 1,099.98') + == 'EUR 1,099.98') assert (numbers.format_currency(1099.98, 'EUR', locale='nl_NL') != numbers.format_currency(-1099.98, 'EUR', locale='nl_NL')) assert (numbers.format_currency(1099.98, 'USD', format=None, locale='en_US') - == u'$1,099.98') + == '$1,099.98') assert (numbers.format_currency(1, 'USD', locale='es_AR') - == u'US$\xa01,00') # one + == 'US$\xa01,00') # one assert (numbers.format_currency(1000000, 'USD', locale='es_AR') - == u'US$\xa01.000.000,00') # many + == 'US$\xa01.000.000,00') # many assert (numbers.format_currency(0, 'USD', locale='es_AR') - == u'US$\xa00,00') # other + == 'US$\xa00,00') # other def test_format_currency_format_type(): assert (numbers.format_currency(1099.98, 'USD', locale='en_US', format_type="standard") - == u'$1,099.98') + == '$1,099.98') assert (numbers.format_currency(0, 'USD', locale='en_US', format_type="standard") - == u'$0.00') + == '$0.00') assert (numbers.format_currency(1099.98, 'USD', locale='en_US', format_type="accounting") - == u'$1,099.98') + == '$1,099.98') assert (numbers.format_currency(0, 'USD', locale='en_US', format_type="accounting") - == u'$0.00') + == '$0.00') with pytest.raises(numbers.UnknownCurrencyFormatError) as excinfo: numbers.format_currency(1099.98, 'USD', locale='en_US', @@ -416,27 +424,27 @@ def test_format_currency_format_type(): assert excinfo.value.args[0] == "'unknown' is not a known currency format type" assert (numbers.format_currency(1099.98, 'JPY', locale='en_US') - == u'\xa51,100') - assert (numbers.format_currency(1099.98, 'COP', u'#,##0.00', locale='es_ES') - == u'1.099,98') + == '\xa51,100') + assert (numbers.format_currency(1099.98, 'COP', '#,##0.00', locale='es_ES') + == '1.099,98') assert (numbers.format_currency(1099.98, 'JPY', locale='en_US', currency_digits=False) - == u'\xa51,099.98') - assert (numbers.format_currency(1099.98, 'COP', u'#,##0.00', locale='es_ES', + == '\xa51,099.98') + assert (numbers.format_currency(1099.98, 'COP', '#,##0.00', locale='es_ES', currency_digits=False) - == u'1.099,98') + == '1.099,98') def test_format_compact_currency(): - assert numbers.format_compact_currency(1, 'USD', locale='en_US', format_type="short") == u'$1' - assert numbers.format_compact_currency(999, 'USD', locale='en_US', format_type="short") == u'$999' - assert numbers.format_compact_currency(123456789, 'USD', locale='en_US', format_type="short") == u'$123M' - assert numbers.format_compact_currency(123456789, 'USD', locale='en_US', fraction_digits=2, format_type="short") == u'$123.46M' - assert numbers.format_compact_currency(-123456789, 'USD', locale='en_US', fraction_digits=2, format_type="short") == u'-$123.46M' - assert numbers.format_compact_currency(1, 'JPY', locale='ja_JP', format_type="short") == u'¥1' - assert numbers.format_compact_currency(1234, 'JPY', locale='ja_JP', format_type="short") == u'¥1234' - assert numbers.format_compact_currency(123456, 'JPY', locale='ja_JP', format_type="short") == u'¥12万' - assert numbers.format_compact_currency(123456, 'JPY', locale='ja_JP', format_type="short", fraction_digits=2) == u'¥12.35万' + assert numbers.format_compact_currency(1, 'USD', locale='en_US', format_type="short") == '$1' + assert numbers.format_compact_currency(999, 'USD', locale='en_US', format_type="short") == '$999' + assert numbers.format_compact_currency(123456789, 'USD', locale='en_US', format_type="short") == '$123M' + assert numbers.format_compact_currency(123456789, 'USD', locale='en_US', fraction_digits=2, format_type="short") == '$123.46M' + assert numbers.format_compact_currency(-123456789, 'USD', locale='en_US', fraction_digits=2, format_type="short") == '-$123.46M' + assert numbers.format_compact_currency(1, 'JPY', locale='ja_JP', format_type="short") == '¥1' + assert numbers.format_compact_currency(1234, 'JPY', locale='ja_JP', format_type="short") == '¥1234' + assert numbers.format_compact_currency(123456, 'JPY', locale='ja_JP', format_type="short") == '¥12万' + assert numbers.format_compact_currency(123456, 'JPY', locale='ja_JP', format_type="short", fraction_digits=2) == '¥12.35万' assert numbers.format_compact_currency(123, 'EUR', locale='yav', format_type="short") == '123\xa0€' assert numbers.format_compact_currency(12345, 'EUR', locale='yav', format_type="short") == '12K\xa0€' assert numbers.format_compact_currency(123456789, 'EUR', locale='de_DE', fraction_digits=1) == '123,5\xa0Mio.\xa0€' @@ -444,8 +452,7 @@ def test_format_compact_currency(): def test_format_compact_currency_invalid_format_type(): with pytest.raises(numbers.UnknownCurrencyFormatError): - numbers.format_compact_currency(1099.98, 'USD', locale='en_US', - format_type='unknown') + numbers.format_compact_currency(1099.98, 'USD', locale='en_US', format_type='unknown') @pytest.mark.parametrize('input_value, expected_value', [ @@ -485,30 +492,30 @@ def test_format_currency_quantization(): def test_format_currency_long_display_name(): assert (numbers.format_currency(1099.98, 'USD', locale='en_US', format_type='name') - == u'1,099.98 US dollars') + == '1,099.98 US dollars') assert (numbers.format_currency(1.00, 'USD', locale='en_US', format_type='name') - == u'1.00 US dollar') + == '1.00 US dollar') assert (numbers.format_currency(1.00, 'EUR', locale='en_US', format_type='name') - == u'1.00 euro') + == '1.00 euro') assert (numbers.format_currency(2, 'EUR', locale='en_US', format_type='name') - == u'2.00 euros') + == '2.00 euros') # This tests that '{1} {0}' unitPatterns are found: assert (numbers.format_currency(1, 'USD', locale='sw', format_type='name') - == u'dola ya Marekani 1.00') + == 'dola ya Marekani 1.00') # This tests unicode chars: assert (numbers.format_currency(1099.98, 'USD', locale='es_GT', format_type='name') - == u'dólares estadounidenses 1,099.98') + == 'dólares estadounidenses 1,099.98') # Test for completely unknown currency, should fallback to currency code assert (numbers.format_currency(1099.98, 'XAB', locale='en_US', format_type='name') - == u'1,099.98 XAB') + == '1,099.98 XAB') # Test for finding different unit patterns depending on count assert (numbers.format_currency(1, 'USD', locale='ro', format_type='name') - == u'1,00 dolar american') + == '1,00 dolar american') assert (numbers.format_currency(2, 'USD', locale='ro', format_type='name') - == u'2,00 dolari americani') + == '2,00 dolari americani') assert (numbers.format_currency(100, 'USD', locale='ro', format_type='name') - == u'100,00 de dolari americani') + == '100,00 de dolari americani') def test_format_currency_long_display_name_all(): @@ -530,15 +537,15 @@ def test_format_currency_long_display_name_custom_format(): def test_format_percent(): - assert numbers.format_percent(0.34, locale='en_US') == u'34%' - assert numbers.format_percent(0, locale='en_US') == u'0%' - assert numbers.format_percent(0.34, u'##0%', locale='en_US') == u'34%' - assert numbers.format_percent(34, u'##0', locale='en_US') == u'34' - assert numbers.format_percent(25.1234, locale='en_US') == u'2,512%' + assert numbers.format_percent(0.34, locale='en_US') == '34%' + assert numbers.format_percent(0, locale='en_US') == '0%' + assert numbers.format_percent(0.34, '##0%', locale='en_US') == '34%' + assert numbers.format_percent(34, '##0', locale='en_US') == '34' + assert numbers.format_percent(25.1234, locale='en_US') == '2,512%' assert (numbers.format_percent(25.1234, locale='sv_SE') - == u'2\xa0512\xa0%') - assert (numbers.format_percent(25.1234, u'#,##0\u2030', locale='en_US') - == u'25,123\u2030') + == '2\xa0512\xa0%') + assert (numbers.format_percent(25.1234, '#,##0\u2030', locale='en_US') + == '25,123\u2030') @pytest.mark.parametrize('input_value, expected_value', [ @@ -576,25 +583,25 @@ def test_format_percent_quantization(): def test_format_scientific(): - assert numbers.format_scientific(10000, locale='en_US') == u'1E4' - assert numbers.format_scientific(4234567, u'#.#E0', locale='en_US') == u'4.2E6' - assert numbers.format_scientific(4234567, u'0E0000', locale='en_US') == u'4.234567E0006' - assert numbers.format_scientific(4234567, u'##0E00', locale='en_US') == u'4.234567E06' - assert numbers.format_scientific(4234567, u'##00E00', locale='en_US') == u'42.34567E05' - assert numbers.format_scientific(4234567, u'0,000E00', locale='en_US') == u'4,234.567E03' - assert numbers.format_scientific(4234567, u'##0.#####E00', locale='en_US') == u'4.23457E06' - assert numbers.format_scientific(4234567, u'##0.##E00', locale='en_US') == u'4.23E06' - assert numbers.format_scientific(42, u'00000.000000E0000', locale='en_US') == u'42000.000000E-0003' + assert numbers.format_scientific(10000, locale='en_US') == '1E4' + assert numbers.format_scientific(4234567, '#.#E0', locale='en_US') == '4.2E6' + assert numbers.format_scientific(4234567, '0E0000', locale='en_US') == '4.234567E0006' + assert numbers.format_scientific(4234567, '##0E00', locale='en_US') == '4.234567E06' + assert numbers.format_scientific(4234567, '##00E00', locale='en_US') == '42.34567E05' + assert numbers.format_scientific(4234567, '0,000E00', locale='en_US') == '4,234.567E03' + assert numbers.format_scientific(4234567, '##0.#####E00', locale='en_US') == '4.23457E06' + assert numbers.format_scientific(4234567, '##0.##E00', locale='en_US') == '4.23E06' + assert numbers.format_scientific(42, '00000.000000E0000', locale='en_US') == '42000.000000E-0003' def test_default_scientific_format(): """ Check the scientific format method auto-correct the rendering pattern in case of a missing fractional part. """ - assert numbers.format_scientific(12345, locale='en_US') == u'1.2345E4' - assert numbers.format_scientific(12345.678, locale='en_US') == u'1.2345678E4' - assert numbers.format_scientific(12345, u'#E0', locale='en_US') == u'1.2345E4' - assert numbers.format_scientific(12345.678, u'#E0', locale='en_US') == u'1.2345678E4' + assert numbers.format_scientific(12345, locale='en_US') == '1.2345E4' + assert numbers.format_scientific(12345.678, locale='en_US') == '1.2345678E4' + assert numbers.format_scientific(12345, '#E0', locale='en_US') == '1.2345E4' + assert numbers.format_scientific(12345.678, '#E0', locale='en_US') == '1.2345678E4' @pytest.mark.parametrize('input_value, expected_value', [ @@ -660,18 +667,18 @@ def test_parse_grouping(): def test_parse_pattern(): # Original pattern is preserved - np = numbers.parse_pattern(u'¤#,##0.00') - assert np.pattern == u'¤#,##0.00' + np = numbers.parse_pattern('¤#,##0.00') + assert np.pattern == '¤#,##0.00' - np = numbers.parse_pattern(u'¤#,##0.00;(¤#,##0.00)') - assert np.pattern == u'¤#,##0.00;(¤#,##0.00)' + np = numbers.parse_pattern('¤#,##0.00;(¤#,##0.00)') + assert np.pattern == '¤#,##0.00;(¤#,##0.00)' # Given a NumberPattern object, we don't return a new instance. # However, we don't cache NumberPattern objects, so calling # parse_pattern with the same format string will create new # instances - np1 = numbers.parse_pattern(u'¤ #,##0.00') - np2 = numbers.parse_pattern(u'¤ #,##0.00') + np1 = numbers.parse_pattern('¤ #,##0.00') + np2 = numbers.parse_pattern('¤ #,##0.00') assert np1 is not np2 assert np1 is numbers.parse_pattern(np1) @@ -679,19 +686,19 @@ def test_parse_pattern(): def test_parse_pattern_negative(): # No negative format specified - np = numbers.parse_pattern(u'¤#,##0.00') - assert np.prefix == (u'¤', u'-¤') - assert np.suffix == (u'', u'') + np = numbers.parse_pattern('¤#,##0.00') + assert np.prefix == ('¤', '-¤') + assert np.suffix == ('', '') # Negative format is specified - np = numbers.parse_pattern(u'¤#,##0.00;(¤#,##0.00)') - assert np.prefix == (u'¤', u'(¤') - assert np.suffix == (u'', u')') + np = numbers.parse_pattern('¤#,##0.00;(¤#,##0.00)') + assert np.prefix == ('¤', '(¤') + assert np.suffix == ('', ')') # Negative sign is a suffix - np = numbers.parse_pattern(u'¤ #,##0.00;¤ #,##0.00-') - assert np.prefix == (u'¤ ', u'¤ ') - assert np.suffix == (u'', u'-') + np = numbers.parse_pattern('¤ #,##0.00;¤ #,##0.00-') + assert np.prefix == ('¤ ', '¤ ') + assert np.suffix == ('', '-') def test_numberpattern_repr(): @@ -699,7 +706,7 @@ def test_numberpattern_repr(): # This implementation looks a bit funny, but that's cause strings are # repr'd differently in Python 2 vs 3 and this test runs under both. - format = u'¤#,##0.00;(¤#,##0.00)' + format = '¤#,##0.00;(¤#,##0.00)' np = numbers.parse_pattern(format) assert repr(format) in repr(np) diff --git a/tests/test_plural.py b/tests/test_plural.py index 16601cf..e1e5ead 100644 --- a/tests/test_plural.py +++ b/tests/test_plural.py @@ -11,9 +11,10 @@ # history and logs, available at http://babel.edgewall.org/log/. import decimal import unittest + import pytest -from babel import plural, localedata +from babel import localedata, plural EPSILON = decimal.Decimal("0.0001") diff --git a/tests/test_smoke.py b/tests/test_smoke.py index aed676a..c916845 100644 --- a/tests/test_smoke.py +++ b/tests/test_smoke.py @@ -4,11 +4,12 @@ looking at improving test coverage. They just verify that basic operations don't fail due to odd corner cases on any locale that we ship. """ -import decimal import datetime +import decimal + import pytest -from babel import Locale, units, dates, numbers +from babel import Locale, dates, numbers, units NUMBERS = ( decimal.Decimal("-33.76"), # Negative Decimal diff --git a/tests/test_support.py b/tests/test_support.py index 3ca0be3..0b7cba0 100644 --- a/tests/test_support.py +++ b/tests/test_support.py @@ -13,20 +13,21 @@ import inspect import os import shutil +import sys import tempfile import unittest -import pytest -import sys from datetime import date, datetime, timedelta from io import BytesIO +import pytest + from babel import support from babel.messages import Catalog from babel.messages.mofile import write_mo - SKIP_LGETTEXT = sys.version_info >= (3, 8) + @pytest.mark.usefixtures("os_environ") class TranslationsTestCase(unittest.TestCase): @@ -71,9 +72,9 @@ class TranslationsTestCase(unittest.TestCase): 'foo')) def test_upgettext(self): - self.assertEqualTypeToo(u'Voh', self.translations.ugettext('foo')) - self.assertEqualTypeToo(u'VohCTX', self.translations.upgettext('foo', - 'foo')) + self.assertEqualTypeToo('Voh', self.translations.ugettext('foo')) + self.assertEqualTypeToo('VohCTX', self.translations.upgettext('foo', + 'foo')) @pytest.mark.skipif(SKIP_LGETTEXT, reason="lgettext is deprecated") def test_lpgettext(self): @@ -94,14 +95,14 @@ class TranslationsTestCase(unittest.TestCase): 'foos1', 2)) def test_unpgettext(self): - self.assertEqualTypeToo(u'Voh1', + self.assertEqualTypeToo('Voh1', self.translations.ungettext('foo1', 'foos1', 1)) - self.assertEqualTypeToo(u'Vohs1', + self.assertEqualTypeToo('Vohs1', self.translations.ungettext('foo1', 'foos1', 2)) - self.assertEqualTypeToo(u'VohCTX1', + self.assertEqualTypeToo('VohCTX1', self.translations.unpgettext('foo', 'foo1', 'foos1', 1)) - self.assertEqualTypeToo(u'VohsCTX1', + self.assertEqualTypeToo('VohsCTX1', self.translations.unpgettext('foo', 'foo1', 'foos1', 2)) @@ -126,9 +127,9 @@ class TranslationsTestCase(unittest.TestCase): def test_dupgettext(self): self.assertEqualTypeToo( - u'VohD', self.translations.dugettext('messages1', 'foo')) + 'VohD', self.translations.dugettext('messages1', 'foo')) self.assertEqualTypeToo( - u'VohCTXD', self.translations.dupgettext('messages1', 'foo', 'foo')) + 'VohCTXD', self.translations.dupgettext('messages1', 'foo', 'foo')) @pytest.mark.skipif(SKIP_LGETTEXT, reason="lgettext is deprecated") def test_ldpgettext(self): @@ -151,15 +152,15 @@ class TranslationsTestCase(unittest.TestCase): def test_dunpgettext(self): self.assertEqualTypeToo( - u'VohD1', self.translations.dungettext('messages1', 'foo1', 'foos1', 1)) + 'VohD1', self.translations.dungettext('messages1', 'foo1', 'foos1', 1)) self.assertEqualTypeToo( - u'VohsD1', self.translations.dungettext('messages1', 'foo1', 'foos1', 2)) + 'VohsD1', self.translations.dungettext('messages1', 'foo1', 'foos1', 2)) self.assertEqualTypeToo( - u'VohCTXD1', self.translations.dunpgettext('messages1', 'foo', 'foo1', - 'foos1', 1)) + 'VohCTXD1', self.translations.dunpgettext('messages1', 'foo', 'foo1', + 'foos1', 1)) self.assertEqualTypeToo( - u'VohsCTXD1', self.translations.dunpgettext('messages1', 'foo', 'foo1', - 'foos1', 2)) + 'VohsCTXD1', self.translations.dunpgettext('messages1', 'foo', 'foo1', + 'foos1', 2)) @pytest.mark.skipif(SKIP_LGETTEXT, reason="lgettext is deprecated") def test_ldnpgettext(self): @@ -219,9 +220,9 @@ class NullTranslationsTestCase(unittest.TestCase): def test_same_return_values(self): data = { - 'message': u'foo', 'domain': u'domain', 'context': 'tests', - 'singular': u'bar', 'plural': u'baz', 'num': 1, - 'msgid1': u'bar', 'msgid2': u'baz', 'n': 1, + 'message': 'foo', 'domain': 'domain', 'context': 'tests', + 'singular': 'bar', 'plural': 'baz', 'num': 1, + 'msgid1': 'bar', 'msgid2': 'baz', 'n': 1, } for name in self.method_names(): method = getattr(self.translations, name) @@ -346,21 +347,20 @@ def test_lazy_proxy(): return f"Hello, {name}!" lazy_greeting = support.LazyProxy(greeting, name='Joe') - assert str(lazy_greeting) == u"Hello, Joe!" - assert u' ' + lazy_greeting == u' Hello, Joe!' - assert u'(%s)' % lazy_greeting == u'(Hello, Joe!)' + assert str(lazy_greeting) == "Hello, Joe!" + assert ' ' + lazy_greeting == ' Hello, Joe!' + assert '(%s)' % lazy_greeting == '(Hello, Joe!)' assert f"[{lazy_greeting}]" == "[Hello, Joe!]" - greetings = [ + greetings = sorted([ support.LazyProxy(greeting, 'world'), support.LazyProxy(greeting, 'Joe'), support.LazyProxy(greeting, 'universe'), - ] - greetings.sort() + ]) assert [str(g) for g in greetings] == [ - u"Hello, Joe!", - u"Hello, universe!", - u"Hello, world!", + "Hello, Joe!", + "Hello, universe!", + "Hello, world!", ] diff --git a/tests/test_util.py b/tests/test_util.py index d78aee7..ae861dd 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -11,6 +11,7 @@ # history and logs, available at http://babel.edgewall.org/log/. import __future__ + import unittest from io import BytesIO @@ -21,11 +22,12 @@ from babel.util import parse_future_flags class _FF: - division = __future__.division.compiler_flag - print_function = __future__.print_function.compiler_flag - with_statement = __future__.with_statement.compiler_flag + division = __future__.division.compiler_flag + print_function = __future__.print_function.compiler_flag + with_statement = __future__.with_statement.compiler_flag unicode_literals = __future__.unicode_literals.compiler_flag + def test_distinct(): assert list(util.distinct([1, 2, 1, 3, 4, 4])) == [1, 2, 3, 4] assert list(util.distinct('foobar')) == ['f', 'o', 'b', 'a', 'r'] @@ -47,7 +49,7 @@ def test_pathmatch(): class FixedOffsetTimezoneTestCase(unittest.TestCase): def test_zone_negative_offset(self): - assert util.FixedOffsetTimezone((-60)).zone == 'Etc/GMT-60' + assert util.FixedOffsetTimezone(-60).zone == 'Etc/GMT-60' def test_zone_zero_offset(self): assert util.FixedOffsetTimezone(0).zone == 'Etc/GMT+0' @@ -56,19 +58,20 @@ class FixedOffsetTimezoneTestCase(unittest.TestCase): assert util.FixedOffsetTimezone(330).zone == 'Etc/GMT+330' -parse_encoding = lambda s: util.parse_encoding(BytesIO(s.encode('utf-8'))) +def parse_encoding(s): + return util.parse_encoding(BytesIO(s.encode('utf-8'))) def test_parse_encoding_defined(): - assert parse_encoding(u'# coding: utf-8') == 'utf-8' + assert parse_encoding('# coding: utf-8') == 'utf-8' def test_parse_encoding_undefined(): - assert parse_encoding(u'') is None + assert parse_encoding('') is None def test_parse_encoding_non_ascii(): - assert parse_encoding(u'K\xf6ln') is None + assert parse_encoding('K\xf6ln') is None @pytest.mark.parametrize('source, result', [ |