"tests/messages/data",
]
+[tool.ruff.format]
+quote-style = "preserve"
+
[tool.ruff.lint]
select = [
"B",
-import os
-
import pytest
try:
pytz = None
-@pytest.fixture
-def os_environ(monkeypatch):
- mock_environ = dict(os.environ)
- monkeypatch.setattr(os, 'environ', mock_environ)
- return mock_environ
-
-
def pytest_generate_tests(metafunc):
if hasattr(metafunc.function, "pytestmark"):
for mark in metafunc.function.pytestmark:
shutil.copytree(data_dir, dest)
monkeypatch.chdir(dest)
- env = os.environ.copy()
# When in Tox, we need to hack things a bit so as not to have the
# sub-interpreter `sys.executable` use the tox virtualenv's Babel
# installation, so the locale data is where we expect it to be.
- if "BABEL_TOX_INI_DIR" in env:
- env["PYTHONPATH"] = env["BABEL_TOX_INI_DIR"]
+ if "BABEL_TOX_INI_DIR" in os.environ:
+ monkeypatch.setenv("PYTHONPATH", os.environ["BABEL_TOX_INI_DIR"])
# Initialize an empty catalog
subprocess.check_call([
"-i", os.devnull,
"-l", "fi",
"-d", "inited",
- ], env=env)
+ ])
po_file = Path("inited/fi/LC_MESSAGES/messages.po")
orig_po_data = po_file.read_text()
subprocess.check_call([
"setup.py",
"extract_messages",
"-o", "extracted.pot",
- ], env=env)
+ ])
pot_file = Path("extracted.pot")
pot_data = pot_file.read_text()
assert "FooBar, TM" in pot_data # should be read from setup.cfg
"update_catalog",
"-i", "extracted.pot",
"-d", "inited",
- ], env=env)
+ ])
new_po_data = po_file.read_text()
assert new_po_data != orig_po_data # check we updated the file
subprocess.check_call([
"setup.py",
"compile_catalog",
"-d", "inited",
- ], env=env)
+ ])
assert po_file.with_suffix(".mo").exists()
assert fi_FI != bad_en_US
-def test_can_return_default_locale(os_environ):
- os_environ['LC_MESSAGES'] = 'fr_FR.UTF-8'
+def test_can_return_default_locale(monkeypatch):
+ monkeypatch.setenv('LC_MESSAGES', 'fr_FR.UTF-8')
assert Locale('fr', 'FR') == Locale.default('LC_MESSAGES')
-def test_ignore_invalid_locales_in_lc_ctype(os_environ):
+def test_ignore_invalid_locales_in_lc_ctype(monkeypatch):
# This is a regression test specifically for a bad LC_CTYPE setting on
# MacOS X 10.6 (#200)
- os_environ['LC_CTYPE'] = 'UTF-8'
+ monkeypatch.setenv('LC_CTYPE', 'UTF-8')
# must not throw an exception
default_locale('LC_CTYPE')
assert locale.language == 'en'
assert locale.territory == 'US'
- def test_default(self, os_environ):
+ def test_default(self, monkeypatch):
for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LC_MESSAGES']:
- os_environ[name] = ''
- os_environ['LANG'] = 'fr_FR.UTF-8'
+ monkeypatch.setenv(name, '')
+ monkeypatch.setenv('LANG', 'fr_FR.UTF-8')
default = Locale.default('LC_MESSAGES')
assert (default.language, default.territory) == ('fr', 'FR')
assert Locale('ru').plural_form(100) == 'many'
-def test_default_locale(os_environ):
+def test_default_locale(monkeypatch):
for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LC_MESSAGES']:
- os_environ[name] = ''
- os_environ['LANG'] = 'fr_FR.UTF-8'
+ monkeypatch.setenv(name, '')
+ monkeypatch.setenv('LANG', 'fr_FR.UTF-8')
assert default_locale('LC_MESSAGES') == 'fr_FR'
-
- os_environ['LC_MESSAGES'] = 'POSIX'
+ monkeypatch.setenv('LC_MESSAGES', 'POSIX')
assert default_locale('LC_MESSAGES') == 'en_US_POSIX'
for value in ['C', 'C.UTF-8', 'POSIX']:
- os_environ['LANGUAGE'] = value
+ monkeypatch.setenv('LANGUAGE', value)
assert default_locale() == 'en_US_POSIX'
+++ /dev/null
-#
-# Copyright (C) 2007-2011 Edgewall Software, 2013-2024 the Babel team
-# All rights reserved.
-#
-# This software is licensed as described in the file LICENSE, which
-# you should have received as part of this distribution. The terms
-# are also available at https://github.com/python-babel/babel/blob/master/LICENSE.
-#
-# This software consists of voluntary contributions made by many
-# individuals. For the exact contribution history, see the revision
-# history and logs, available at https://github.com/python-babel/babel/commits/master/.
-
-import datetime
-import inspect
-import os
-import shutil
-import sys
-import tempfile
-import unittest
-from decimal import Decimal
-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):
-
- def setUp(self):
- # Use a locale which won't fail to run the tests
- os.environ['LANG'] = 'en_US.UTF-8'
- messages1 = [
- ('foo', {'string': 'Voh'}),
- ('foo', {'string': 'VohCTX', 'context': 'foo'}),
- (('foo1', 'foos1'), {'string': ('Voh1', 'Vohs1')}),
- (('foo1', 'foos1'), {'string': ('VohCTX1', 'VohsCTX1'), 'context': 'foo'}),
- ]
- messages2 = [
- ('foo', {'string': 'VohD'}),
- ('foo', {'string': 'VohCTXD', 'context': 'foo'}),
- (('foo1', 'foos1'), {'string': ('VohD1', 'VohsD1')}),
- (('foo1', 'foos1'), {'string': ('VohCTXD1', 'VohsCTXD1'), 'context': 'foo'}),
- ]
- catalog1 = Catalog(locale='en_GB', domain='messages')
- catalog2 = Catalog(locale='en_GB', domain='messages1')
- for ids, kwargs in messages1:
- catalog1.add(ids, **kwargs)
- for ids, kwargs in messages2:
- catalog2.add(ids, **kwargs)
- catalog1_fp = BytesIO()
- catalog2_fp = BytesIO()
- write_mo(catalog1_fp, catalog1)
- catalog1_fp.seek(0)
- write_mo(catalog2_fp, catalog2)
- catalog2_fp.seek(0)
- translations1 = support.Translations(catalog1_fp)
- translations2 = support.Translations(catalog2_fp, domain='messages1')
- self.translations = translations1.add(translations2, merge=False)
-
- def assertEqualTypeToo(self, expected, result):
- assert expected == result
- assert type(expected) is type(result), f"instance types do not match: {type(expected)!r}!={type(result)!r}"
-
- def test_pgettext(self):
- self.assertEqualTypeToo('Voh', self.translations.gettext('foo'))
- self.assertEqualTypeToo('VohCTX', self.translations.pgettext('foo',
- 'foo'))
- self.assertEqualTypeToo('VohCTX1', self.translations.pgettext('foo',
- 'foo1'))
-
- def test_pgettext_fallback(self):
- fallback = self.translations._fallback
- self.translations._fallback = support.NullTranslations()
- assert self.translations.pgettext('foo', 'bar') == 'bar'
- self.translations._fallback = fallback
-
- def test_upgettext(self):
- 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):
- self.assertEqualTypeToo(b'Voh', self.translations.lgettext('foo'))
- self.assertEqualTypeToo(b'VohCTX', self.translations.lpgettext('foo',
- 'foo'))
-
- def test_npgettext(self):
- self.assertEqualTypeToo('Voh1',
- self.translations.ngettext('foo1', 'foos1', 1))
- self.assertEqualTypeToo('Vohs1',
- self.translations.ngettext('foo1', 'foos1', 2))
- self.assertEqualTypeToo('VohCTX1',
- self.translations.npgettext('foo', 'foo1',
- 'foos1', 1))
- self.assertEqualTypeToo('VohsCTX1',
- self.translations.npgettext('foo', 'foo1',
- 'foos1', 2))
-
- def test_unpgettext(self):
- self.assertEqualTypeToo('Voh1',
- self.translations.ungettext('foo1', 'foos1', 1))
- self.assertEqualTypeToo('Vohs1',
- self.translations.ungettext('foo1', 'foos1', 2))
- self.assertEqualTypeToo('VohCTX1',
- self.translations.unpgettext('foo', 'foo1',
- 'foos1', 1))
- self.assertEqualTypeToo('VohsCTX1',
- self.translations.unpgettext('foo', 'foo1',
- 'foos1', 2))
-
- @pytest.mark.skipif(SKIP_LGETTEXT, reason="lgettext is deprecated")
- def test_lnpgettext(self):
- self.assertEqualTypeToo(b'Voh1',
- self.translations.lngettext('foo1', 'foos1', 1))
- self.assertEqualTypeToo(b'Vohs1',
- self.translations.lngettext('foo1', 'foos1', 2))
- self.assertEqualTypeToo(b'VohCTX1',
- self.translations.lnpgettext('foo', 'foo1',
- 'foos1', 1))
- self.assertEqualTypeToo(b'VohsCTX1',
- self.translations.lnpgettext('foo', 'foo1',
- 'foos1', 2))
-
- def test_dpgettext(self):
- self.assertEqualTypeToo(
- 'VohD', self.translations.dgettext('messages1', 'foo'))
- self.assertEqualTypeToo(
- 'VohCTXD', self.translations.dpgettext('messages1', 'foo', 'foo'))
-
- def test_dupgettext(self):
- self.assertEqualTypeToo(
- 'VohD', self.translations.dugettext('messages1', 'foo'))
- self.assertEqualTypeToo(
- 'VohCTXD', self.translations.dupgettext('messages1', 'foo', 'foo'))
-
- @pytest.mark.skipif(SKIP_LGETTEXT, reason="lgettext is deprecated")
- def test_ldpgettext(self):
- self.assertEqualTypeToo(
- b'VohD', self.translations.ldgettext('messages1', 'foo'))
- self.assertEqualTypeToo(
- b'VohCTXD', self.translations.ldpgettext('messages1', 'foo', 'foo'))
-
- def test_dnpgettext(self):
- self.assertEqualTypeToo(
- 'VohD1', self.translations.dngettext('messages1', 'foo1', 'foos1', 1))
- self.assertEqualTypeToo(
- 'VohsD1', self.translations.dngettext('messages1', 'foo1', 'foos1', 2))
- self.assertEqualTypeToo(
- 'VohCTXD1', self.translations.dnpgettext('messages1', 'foo', 'foo1',
- 'foos1', 1))
- self.assertEqualTypeToo(
- 'VohsCTXD1', self.translations.dnpgettext('messages1', 'foo', 'foo1',
- 'foos1', 2))
-
- def test_dunpgettext(self):
- self.assertEqualTypeToo(
- 'VohD1', self.translations.dungettext('messages1', 'foo1', 'foos1', 1))
- self.assertEqualTypeToo(
- 'VohsD1', self.translations.dungettext('messages1', 'foo1', 'foos1', 2))
- self.assertEqualTypeToo(
- 'VohCTXD1', self.translations.dunpgettext('messages1', 'foo', 'foo1',
- 'foos1', 1))
- self.assertEqualTypeToo(
- 'VohsCTXD1', self.translations.dunpgettext('messages1', 'foo', 'foo1',
- 'foos1', 2))
-
- @pytest.mark.skipif(SKIP_LGETTEXT, reason="lgettext is deprecated")
- def test_ldnpgettext(self):
- self.assertEqualTypeToo(
- b'VohD1', self.translations.ldngettext('messages1', 'foo1', 'foos1', 1))
- self.assertEqualTypeToo(
- b'VohsD1', self.translations.ldngettext('messages1', 'foo1', 'foos1', 2))
- self.assertEqualTypeToo(
- b'VohCTXD1', self.translations.ldnpgettext('messages1', 'foo', 'foo1',
- 'foos1', 1))
- self.assertEqualTypeToo(
- b'VohsCTXD1', self.translations.ldnpgettext('messages1', 'foo', 'foo1',
- 'foos1', 2))
-
- def test_load(self):
- tempdir = tempfile.mkdtemp()
- try:
- messages_dir = os.path.join(tempdir, 'fr', 'LC_MESSAGES')
- os.makedirs(messages_dir)
- catalog = Catalog(locale='fr', domain='messages')
- catalog.add('foo', 'bar')
- with open(os.path.join(messages_dir, 'messages.mo'), 'wb') as f:
- write_mo(f, catalog)
-
- translations = support.Translations.load(tempdir, locales=('fr',), domain='messages')
- assert translations.gettext('foo') == 'bar'
- finally:
- shutil.rmtree(tempdir)
-
-
-class NullTranslationsTestCase(unittest.TestCase):
-
- def setUp(self):
- fp = BytesIO()
- write_mo(fp, Catalog(locale='de'))
- fp.seek(0)
- self.translations = support.Translations(fp=fp)
- self.null_translations = support.NullTranslations(fp=fp)
-
- def method_names(self):
- names = [name for name in dir(self.translations) if 'gettext' in name]
- if SKIP_LGETTEXT:
- # Remove deprecated l*gettext functions
- names = [name for name in names if not name.startswith('l')]
- return names
-
- def test_same_methods(self):
- for name in self.method_names():
- if not hasattr(self.null_translations, name):
- self.fail(f"NullTranslations does not provide method {name!r}")
-
- def test_method_signature_compatibility(self):
- for name in self.method_names():
- translations_method = getattr(self.translations, name)
- null_method = getattr(self.null_translations, name)
- assert inspect.getfullargspec(translations_method) == inspect.getfullargspec(null_method)
-
- def test_same_return_values(self):
- data = {
- '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)
- null_method = getattr(self.null_translations, name)
- signature = inspect.getfullargspec(method)
- parameter_names = [name for name in signature.args if name != 'self']
- values = [data[name] for name in parameter_names]
- assert method(*values) == null_method(*values)
-
-
-class LazyProxyTestCase(unittest.TestCase):
-
- def test_proxy_caches_result_of_function_call(self):
- self.counter = 0
-
- def add_one():
- self.counter += 1
- return self.counter
- proxy = support.LazyProxy(add_one)
- assert proxy.value == 1
- assert proxy.value == 1
-
- def test_can_disable_proxy_cache(self):
- self.counter = 0
-
- def add_one():
- self.counter += 1
- return self.counter
- proxy = support.LazyProxy(add_one, enable_cache=False)
- assert proxy.value == 1
- assert proxy.value == 2
-
- def test_can_copy_proxy(self):
- from copy import copy
-
- numbers = [1, 2]
-
- def first(xs):
- return xs[0]
-
- proxy = support.LazyProxy(first, numbers)
- proxy_copy = copy(proxy)
-
- numbers.pop(0)
- assert proxy.value == 2
- assert proxy_copy.value == 2
-
- def test_can_deepcopy_proxy(self):
- from copy import deepcopy
- numbers = [1, 2]
-
- def first(xs):
- return xs[0]
-
- proxy = support.LazyProxy(first, numbers)
- proxy_deepcopy = deepcopy(proxy)
-
- numbers.pop(0)
- assert proxy.value == 2
- assert proxy_deepcopy.value == 1
-
- def test_handle_attribute_error(self):
-
- def raise_attribute_error():
- raise AttributeError('message')
-
- proxy = support.LazyProxy(raise_attribute_error)
- with pytest.raises(AttributeError, match='message'):
- _ = proxy.value
-
-
-class TestFormat:
- def test_format_datetime(self, timezone_getter):
- when = datetime.datetime(2007, 4, 1, 15, 30)
- fmt = support.Format('en_US', tzinfo=timezone_getter('US/Eastern'))
- assert fmt.datetime(when) == 'Apr 1, 2007, 11:30:00\u202fAM'
-
- def test_format_time(self, timezone_getter):
- when = datetime.datetime(2007, 4, 1, 15, 30)
- fmt = support.Format('en_US', tzinfo=timezone_getter('US/Eastern'))
- assert fmt.time(when) == '11:30:00\u202fAM'
-
- def test_format_number(self):
- assert support.Format('en_US').number(1234) == '1,234'
- assert support.Format('ar_EG', numbering_system="default").number(1234) == '1٬234'
-
- def test_format_decimal(self):
- assert support.Format('en_US').decimal(1234.5) == '1,234.5'
- assert support.Format('en_US').decimal(Decimal("1234.5")) == '1,234.5'
- assert support.Format('ar_EG', numbering_system="default").decimal(1234.5) == '1٬234٫5'
- assert support.Format('ar_EG', numbering_system="default").decimal(Decimal("1234.5")) == '1٬234٫5'
-
- def test_format_compact_decimal(self):
- assert support.Format('en_US').compact_decimal(1234) == '1K'
- assert support.Format('ar_EG', numbering_system="default").compact_decimal(
- 1234, fraction_digits=1) == '1٫2\xa0ألف'
- assert support.Format('ar_EG', numbering_system="default").compact_decimal(
- Decimal("1234"), fraction_digits=1) == '1٫2\xa0ألف'
-
- def test_format_currency(self):
- assert support.Format('en_US').currency(1099.98, 'USD') == '$1,099.98'
- assert support.Format('en_US').currency(Decimal("1099.98"), 'USD') == '$1,099.98'
- assert support.Format('ar_EG', numbering_system="default").currency(
- 1099.98, 'EGP') == '\u200f1٬099٫98\xa0ج.م.\u200f'
-
- def test_format_compact_currency(self):
- assert support.Format('en_US').compact_currency(1099.98, 'USD') == '$1K'
- assert support.Format('en_US').compact_currency(Decimal("1099.98"), 'USD') == '$1K'
- assert support.Format('ar_EG', numbering_system="default").compact_currency(
- 1099.98, 'EGP') == '1\xa0ألف\xa0ج.م.\u200f'
-
- def test_format_percent(self):
- assert support.Format('en_US').percent(0.34) == '34%'
- assert support.Format('en_US').percent(Decimal("0.34")) == '34%'
- assert support.Format('ar_EG', numbering_system="default").percent(134.5) == '13٬450%'
-
- def test_format_scientific(self):
- assert support.Format('en_US').scientific(10000) == '1E4'
- assert support.Format('en_US').scientific(Decimal("10000")) == '1E4'
- assert support.Format('ar_EG', numbering_system="default").scientific(10000) == '1أس4'
-
-
-def test_lazy_proxy():
- def greeting(name='world'):
- return f"Hello, {name}!"
-
- lazy_greeting = support.LazyProxy(greeting, name='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 = sorted([
- support.LazyProxy(greeting, 'world'),
- support.LazyProxy(greeting, 'Joe'),
- support.LazyProxy(greeting, 'universe'),
- ])
- assert [str(g) for g in greetings] == [
- "Hello, Joe!",
- "Hello, universe!",
- "Hello, world!",
- ]
-
-
-def test_catalog_merge_files():
- # Refs issues #92, #162
- t1 = support.Translations()
- assert t1.files == []
- t1._catalog["foo"] = "bar"
- fp = BytesIO()
- write_mo(fp, Catalog())
- fp.seek(0)
- fp.name = "pro.mo"
- t2 = support.Translations(fp)
- assert t2.files == ["pro.mo"]
- t2._catalog["bar"] = "quux"
- t1.merge(t2)
- assert t1.files == ["pro.mo"]
- assert set(t1._catalog.keys()) == {'', 'foo', 'bar'}
--- /dev/null
+import datetime
+from decimal import Decimal
+
+import pytest
+
+from babel import support
+
+
+@pytest.fixture
+def ar_eg_format() -> support.Format:
+ return support.Format('ar_EG', numbering_system="default")
+
+
+@pytest.fixture
+def en_us_format(timezone_getter) -> support.Format:
+ return support.Format('en_US', tzinfo=timezone_getter('US/Eastern'))
+
+
+def test_format_datetime(en_us_format):
+ when = datetime.datetime(2007, 4, 1, 15, 30)
+ assert en_us_format.datetime(when) == 'Apr 1, 2007, 11:30:00\u202fAM'
+
+
+def test_format_time(en_us_format):
+ when = datetime.datetime(2007, 4, 1, 15, 30)
+ assert en_us_format.time(when) == '11:30:00\u202fAM'
+
+
+def test_format_number(ar_eg_format, en_us_format):
+ assert en_us_format.number(1234) == '1,234'
+ assert ar_eg_format.number(1234) == '1٬234'
+
+
+def test_format_decimal(ar_eg_format, en_us_format):
+ assert en_us_format.decimal(1234.5) == '1,234.5'
+ assert en_us_format.decimal(Decimal("1234.5")) == '1,234.5'
+ assert ar_eg_format.decimal(1234.5) == '1٬234٫5'
+ assert ar_eg_format.decimal(Decimal("1234.5")) == '1٬234٫5'
+
+
+def test_format_compact_decimal(ar_eg_format, en_us_format):
+ assert en_us_format.compact_decimal(1234) == '1K'
+ assert ar_eg_format.compact_decimal(1234, fraction_digits=1) == '1٫2\xa0ألف'
+ assert ar_eg_format.compact_decimal(Decimal("1234"), fraction_digits=1) == '1٫2\xa0ألف'
+
+
+def test_format_currency(ar_eg_format, en_us_format):
+ assert en_us_format.currency(1099.98, 'USD') == '$1,099.98'
+ assert en_us_format.currency(Decimal("1099.98"), 'USD') == '$1,099.98'
+ assert ar_eg_format.currency(1099.98, 'EGP') == '\u200f1٬099٫98\xa0ج.م.\u200f'
+
+
+def test_format_compact_currency(ar_eg_format, en_us_format):
+ assert en_us_format.compact_currency(1099.98, 'USD') == '$1K'
+ assert en_us_format.compact_currency(Decimal("1099.98"), 'USD') == '$1K'
+ assert ar_eg_format.compact_currency(1099.98, 'EGP') == '1\xa0ألف\xa0ج.م.\u200f'
+
+
+def test_format_percent(ar_eg_format, en_us_format):
+ assert en_us_format.percent(0.34) == '34%'
+ assert en_us_format.percent(Decimal("0.34")) == '34%'
+ assert ar_eg_format.percent(134.5) == '13٬450%'
+
+
+def test_format_scientific(ar_eg_format, en_us_format):
+ assert en_us_format.scientific(10000) == '1E4'
+ assert en_us_format.scientific(Decimal("10000")) == '1E4'
+ assert ar_eg_format.scientific(10000) == '1أس4'
--- /dev/null
+import copy
+
+import pytest
+
+from babel import support
+
+
+def test_proxy_caches_result_of_function_call():
+ counter = 0
+
+ def add_one():
+ nonlocal counter
+ counter += 1
+ return counter
+
+ proxy = support.LazyProxy(add_one)
+ assert proxy.value == 1
+ assert proxy.value == 1
+
+
+def test_can_disable_proxy_cache():
+ counter = 0
+
+ def add_one():
+ nonlocal counter
+ counter += 1
+ return counter
+
+ proxy = support.LazyProxy(add_one, enable_cache=False)
+ assert proxy.value == 1
+ assert proxy.value == 2
+
+
+@pytest.mark.parametrize(("copier", "expected_copy_value"), [
+ (copy.copy, 2),
+ (copy.deepcopy, 1),
+])
+def test_can_copy_proxy(copier, expected_copy_value):
+ numbers = [1, 2]
+
+ def first(xs):
+ return xs[0]
+
+ proxy = support.LazyProxy(first, numbers)
+ proxy_copy = copier(proxy)
+
+ numbers.pop(0)
+ assert proxy.value == 2
+ assert proxy_copy.value == expected_copy_value
+
+
+def test_handle_attribute_error():
+ def raise_attribute_error():
+ raise AttributeError('message')
+
+ proxy = support.LazyProxy(raise_attribute_error)
+ with pytest.raises(AttributeError, match='message'):
+ _ = proxy.value
+
+
+def test_lazy_proxy():
+ def greeting(name='world'):
+ return f"Hello, {name}!"
+
+ lazy_greeting = support.LazyProxy(greeting, name='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 = sorted([
+ support.LazyProxy(greeting, 'world'),
+ support.LazyProxy(greeting, 'Joe'),
+ support.LazyProxy(greeting, 'universe'),
+ ])
+ assert [str(g) for g in greetings] == [
+ "Hello, Joe!",
+ "Hello, universe!",
+ "Hello, world!",
+ ]
--- /dev/null
+import inspect
+import io
+import os
+import shutil
+import sys
+import tempfile
+
+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)
+
+messages1 = [
+ ('foo', {'string': 'Voh'}),
+ ('foo', {'string': 'VohCTX', 'context': 'foo'}),
+ (('foo1', 'foos1'), {'string': ('Voh1', 'Vohs1')}),
+ (('foo1', 'foos1'), {'string': ('VohCTX1', 'VohsCTX1'), 'context': 'foo'}),
+]
+
+messages2 = [
+ ('foo', {'string': 'VohD'}),
+ ('foo', {'string': 'VohCTXD', 'context': 'foo'}),
+ (('foo1', 'foos1'), {'string': ('VohD1', 'VohsD1')}),
+ (('foo1', 'foos1'), {'string': ('VohCTXD1', 'VohsCTXD1'), 'context': 'foo'}),
+]
+
+
+@pytest.fixture(autouse=True)
+def use_en_us_locale(monkeypatch):
+ # Use a locale which won't fail to run the tests
+ monkeypatch.setenv('LANG', 'en_US.UTF-8')
+
+
+@pytest.fixture()
+def translations() -> support.Translations:
+ catalog1 = Catalog(locale='en_GB', domain='messages')
+ catalog2 = Catalog(locale='en_GB', domain='messages1')
+ for ids, kwargs in messages1:
+ catalog1.add(ids, **kwargs)
+ for ids, kwargs in messages2:
+ catalog2.add(ids, **kwargs)
+ catalog1_fp = io.BytesIO()
+ catalog2_fp = io.BytesIO()
+ write_mo(catalog1_fp, catalog1)
+ catalog1_fp.seek(0)
+ write_mo(catalog2_fp, catalog2)
+ catalog2_fp.seek(0)
+ translations1 = support.Translations(catalog1_fp)
+ translations2 = support.Translations(catalog2_fp, domain='messages1')
+ return translations1.add(translations2, merge=False)
+
+
+@pytest.fixture(scope='module')
+def empty_translations() -> support.Translations:
+ fp = io.BytesIO()
+ write_mo(fp, Catalog(locale='de'))
+ fp.seek(0)
+ return support.Translations(fp=fp)
+
+
+@pytest.fixture(scope='module')
+def null_translations() -> support.NullTranslations:
+ fp = io.BytesIO()
+ write_mo(fp, Catalog(locale='de'))
+ fp.seek(0)
+ return support.NullTranslations(fp=fp)
+
+
+def assert_equal_type_too(expected, result) -> None:
+ assert expected == result
+ assert type(expected) is type(result), (
+ f'instance types do not match: {type(expected)!r}!={type(result)!r}'
+ )
+
+
+def test_pgettext(translations):
+ assert_equal_type_too('Voh', translations.gettext('foo'))
+ assert_equal_type_too('VohCTX', translations.pgettext('foo', 'foo'))
+ assert_equal_type_too('VohCTX1', translations.pgettext('foo', 'foo1'))
+
+
+def test_pgettext_fallback(translations):
+ fallback = translations._fallback
+ translations._fallback = support.NullTranslations()
+ assert translations.pgettext('foo', 'bar') == 'bar'
+ translations._fallback = fallback
+
+
+def test_upgettext(translations):
+ assert_equal_type_too('Voh', translations.ugettext('foo'))
+ assert_equal_type_too('VohCTX', translations.upgettext('foo', 'foo'))
+
+
+@pytest.mark.skipif(SKIP_LGETTEXT, reason='lgettext is deprecated')
+def test_lpgettext(translations):
+ assert_equal_type_too(b'Voh', translations.lgettext('foo'))
+ assert_equal_type_too(b'VohCTX', translations.lpgettext('foo', 'foo'))
+
+
+def test_npgettext(translations):
+ assert_equal_type_too('Voh1', translations.ngettext('foo1', 'foos1', 1))
+ assert_equal_type_too('Vohs1', translations.ngettext('foo1', 'foos1', 2))
+ assert_equal_type_too('VohCTX1', translations.npgettext('foo', 'foo1', 'foos1', 1))
+ assert_equal_type_too('VohsCTX1', translations.npgettext('foo', 'foo1', 'foos1', 2))
+
+
+def test_unpgettext(translations):
+ assert_equal_type_too('Voh1', translations.ungettext('foo1', 'foos1', 1))
+ assert_equal_type_too('Vohs1', translations.ungettext('foo1', 'foos1', 2))
+ assert_equal_type_too('VohCTX1', translations.unpgettext('foo', 'foo1', 'foos1', 1))
+ assert_equal_type_too('VohsCTX1', translations.unpgettext('foo', 'foo1', 'foos1', 2))
+
+
+@pytest.mark.skipif(SKIP_LGETTEXT, reason='lgettext is deprecated')
+def test_lnpgettext(translations):
+ assert_equal_type_too(b'Voh1', translations.lngettext('foo1', 'foos1', 1))
+ assert_equal_type_too(b'Vohs1', translations.lngettext('foo1', 'foos1', 2))
+ assert_equal_type_too(b'VohCTX1', translations.lnpgettext('foo', 'foo1', 'foos1', 1))
+ assert_equal_type_too(b'VohsCTX1', translations.lnpgettext('foo', 'foo1', 'foos1', 2))
+
+
+def test_dpgettext(translations):
+ assert_equal_type_too('VohD', translations.dgettext('messages1', 'foo'))
+ assert_equal_type_too('VohCTXD', translations.dpgettext('messages1', 'foo', 'foo'))
+
+
+def test_dupgettext(translations):
+ assert_equal_type_too('VohD', translations.dugettext('messages1', 'foo'))
+ assert_equal_type_too('VohCTXD', translations.dupgettext('messages1', 'foo', 'foo'))
+
+
+@pytest.mark.skipif(SKIP_LGETTEXT, reason='lgettext is deprecated')
+def test_ldpgettext(translations):
+ assert_equal_type_too(b'VohD', translations.ldgettext('messages1', 'foo'))
+ assert_equal_type_too(b'VohCTXD', translations.ldpgettext('messages1', 'foo', 'foo'))
+
+
+def test_dnpgettext(translations):
+ assert_equal_type_too('VohD1', translations.dngettext('messages1', 'foo1', 'foos1', 1))
+ assert_equal_type_too('VohsD1', translations.dngettext('messages1', 'foo1', 'foos1', 2))
+ assert_equal_type_too('VohCTXD1', translations.dnpgettext('messages1', 'foo', 'foo1', 'foos1', 1))
+ assert_equal_type_too('VohsCTXD1', translations.dnpgettext('messages1', 'foo', 'foo1', 'foos1', 2))
+
+
+def test_dunpgettext(translations):
+ assert_equal_type_too('VohD1', translations.dungettext('messages1', 'foo1', 'foos1', 1))
+ assert_equal_type_too('VohsD1', translations.dungettext('messages1', 'foo1', 'foos1', 2))
+ assert_equal_type_too('VohCTXD1', translations.dunpgettext('messages1', 'foo', 'foo1', 'foos1', 1))
+ assert_equal_type_too('VohsCTXD1', translations.dunpgettext('messages1', 'foo', 'foo1', 'foos1', 2))
+
+
+@pytest.mark.skipif(SKIP_LGETTEXT, reason='lgettext is deprecated')
+def test_ldnpgettext(translations):
+ assert_equal_type_too(b'VohD1', translations.ldngettext('messages1', 'foo1', 'foos1', 1))
+ assert_equal_type_too(b'VohsD1', translations.ldngettext('messages1', 'foo1', 'foos1', 2))
+ assert_equal_type_too(b'VohCTXD1', translations.ldnpgettext('messages1', 'foo', 'foo1', 'foos1', 1))
+ assert_equal_type_too(b'VohsCTXD1', translations.ldnpgettext('messages1', 'foo', 'foo1', 'foos1', 2))
+
+
+def test_load(translations):
+ tempdir = tempfile.mkdtemp()
+ try:
+ messages_dir = os.path.join(tempdir, 'fr', 'LC_MESSAGES')
+ os.makedirs(messages_dir)
+ catalog = Catalog(locale='fr', domain='messages')
+ catalog.add('foo', 'bar')
+ with open(os.path.join(messages_dir, 'messages.mo'), 'wb') as f:
+ write_mo(f, catalog)
+
+ translations = support.Translations.load(tempdir, locales=('fr',), domain='messages')
+ assert translations.gettext('foo') == 'bar'
+ finally:
+ shutil.rmtree(tempdir)
+
+
+def get_gettext_method_names(obj):
+ names = [name for name in dir(obj) if 'gettext' in name]
+ if SKIP_LGETTEXT:
+ # Remove deprecated l*gettext functions
+ names = [name for name in names if not name.startswith('l')]
+ return names
+
+
+def test_null_translations_have_same_methods(empty_translations, null_translations):
+ for name in get_gettext_method_names(empty_translations):
+ assert hasattr(null_translations, name), f'NullTranslations does not provide method {name!r}'
+
+
+def test_null_translations_method_signature_compatibility(empty_translations, null_translations):
+ for name in get_gettext_method_names(empty_translations):
+ assert (
+ inspect.getfullargspec(getattr(empty_translations, name)) ==
+ inspect.getfullargspec(getattr(null_translations, name))
+ )
+
+
+def test_null_translations_same_return_values(empty_translations, null_translations):
+ data = {
+ 'message': 'foo',
+ 'domain': 'domain',
+ 'context': 'tests',
+ 'singular': 'bar',
+ 'plural': 'baz',
+ 'num': 1,
+ 'msgid1': 'bar',
+ 'msgid2': 'baz',
+ 'n': 1,
+ }
+ for name in get_gettext_method_names(empty_translations):
+ method = getattr(empty_translations, name)
+ null_method = getattr(null_translations, name)
+ signature = inspect.getfullargspec(method)
+ parameter_names = [name for name in signature.args if name != 'self']
+ values = [data[name] for name in parameter_names]
+ assert method(*values) == null_method(*values)
+
+
+def test_catalog_merge_files():
+ # Refs issues #92, #162
+ t1 = support.Translations()
+ assert t1.files == []
+ t1._catalog['foo'] = 'bar'
+ fp = io.BytesIO()
+ write_mo(fp, Catalog())
+ fp.seek(0)
+ fp.name = 'pro.mo'
+ t2 = support.Translations(fp)
+ assert t2.files == ['pro.mo']
+ t2._catalog['bar'] = 'quux'
+ t1.merge(t2)
+ assert t1.files == ['pro.mo']
+ assert set(t1._catalog.keys()) == {'', 'foo', 'bar'}