Fix babel primitive types
- Make babel dependent primitive types to use Locale('en') for data
validation instead of current locale. Using current locale leads to
infinite recursion in cases where the loaded data has dependency to
the loaded object's locale.
This commit is contained in:
@@ -8,6 +8,7 @@ Here you can see the full list of changes between each SQLAlchemy-Utils release.
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Added better support for dynamic locales in translation_hybrid
|
||||
- Make babel dependent primitive types to use Locale('en') for data validation instead of current locale. Using current locale leads to infinite recursion in cases where the loaded data has dependency to the loaded object's locale.
|
||||
|
||||
|
||||
0.30.9 (2015-06-09)
|
||||
|
||||
@@ -92,4 +92,4 @@ from .types import ( # noqa
|
||||
WeekDaysType
|
||||
)
|
||||
|
||||
__version__ = '0.30.9'
|
||||
__version__ = '0.30.10'
|
||||
|
||||
@@ -3,18 +3,10 @@ from sqlalchemy.ext.hybrid import hybrid_property
|
||||
|
||||
from .exceptions import ImproperlyConfigured
|
||||
|
||||
from babel import Locale
|
||||
|
||||
|
||||
try:
|
||||
from babel.dates import get_day_names
|
||||
import babel
|
||||
except ImportError:
|
||||
def get_day_names():
|
||||
raise ImproperlyConfigured(
|
||||
'Could not load get_day_names function from babel. Either install '
|
||||
' babel or make a similar function and override it in this '
|
||||
'module.'
|
||||
)
|
||||
babel = None
|
||||
|
||||
try:
|
||||
from flask.ext.babel import get_locale
|
||||
@@ -29,6 +21,10 @@ except ImportError:
|
||||
|
||||
class TranslationHybrid(object):
|
||||
def __init__(self, current_locale, default_locale, default_value=None):
|
||||
if babel is None:
|
||||
raise ImproperlyConfigured(
|
||||
'You need to install babel in order to use TranslationHybrid.'
|
||||
)
|
||||
self.current_locale = current_locale
|
||||
self.default_locale = default_locale
|
||||
self.default_value = default_value
|
||||
@@ -43,8 +39,9 @@ class TranslationHybrid(object):
|
||||
locale = locale()
|
||||
except TypeError:
|
||||
locale = locale(obj)
|
||||
if isinstance(locale, Locale):
|
||||
if isinstance(locale, babel.Locale):
|
||||
return str(locale)
|
||||
|
||||
return locale
|
||||
|
||||
def getter_factory(self, attr):
|
||||
|
||||
@@ -71,7 +71,7 @@ class Country(object):
|
||||
@classmethod
|
||||
def validate(self, code):
|
||||
try:
|
||||
i18n.get_locale().territories[code]
|
||||
i18n.babel.Locale('en').territories[code]
|
||||
except KeyError:
|
||||
raise ValueError(
|
||||
'Could not convert string to country code: {0}'.format(code)
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
babel = None
|
||||
try:
|
||||
import babel
|
||||
except ImportError:
|
||||
pass
|
||||
import six
|
||||
|
||||
from sqlalchemy_utils import i18n, ImproperlyConfigured
|
||||
@@ -58,7 +53,7 @@ class Currency(object):
|
||||
|
||||
"""
|
||||
def __init__(self, code):
|
||||
if babel is None:
|
||||
if i18n.babel is None:
|
||||
raise ImproperlyConfigured(
|
||||
"'babel' package is required in order to use Currency class."
|
||||
)
|
||||
@@ -77,13 +72,16 @@ class Currency(object):
|
||||
@classmethod
|
||||
def validate(self, code):
|
||||
try:
|
||||
i18n.get_locale().currencies[code]
|
||||
i18n.babel.Locale('en').currencies[code]
|
||||
except KeyError:
|
||||
raise ValueError("{0}' is not valid currency code.")
|
||||
|
||||
@property
|
||||
def symbol(self):
|
||||
return babel.numbers.get_currency_symbol(self.code, i18n.get_locale())
|
||||
return i18n.babel.numbers.get_currency_symbol(
|
||||
self.code,
|
||||
i18n.get_locale()
|
||||
)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
||||
@@ -39,7 +39,7 @@ class WeekDay(object):
|
||||
return self.name
|
||||
|
||||
def get_name(self, width='wide', context='format'):
|
||||
names = i18n.get_day_names(
|
||||
names = i18n.babel.dates.get_day_names(
|
||||
width,
|
||||
context,
|
||||
i18n.get_locale()
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
babel = None
|
||||
try:
|
||||
import babel
|
||||
except ImportError:
|
||||
pass
|
||||
import six
|
||||
from sqlalchemy import types
|
||||
|
||||
from sqlalchemy_utils import ImproperlyConfigured
|
||||
from sqlalchemy_utils import i18n, ImproperlyConfigured
|
||||
from sqlalchemy_utils.primitives import Currency
|
||||
|
||||
from .scalar_coercible import ScalarCoercible
|
||||
@@ -57,7 +52,7 @@ class CurrencyType(types.TypeDecorator, ScalarCoercible):
|
||||
python_type = Currency
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if babel is None:
|
||||
if i18n.babel is None:
|
||||
raise ImproperlyConfigured(
|
||||
"'babel' package is required in order to use CurrencyType."
|
||||
)
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
babel = None
|
||||
try:
|
||||
import babel
|
||||
except ImportError:
|
||||
pass
|
||||
import six
|
||||
from sqlalchemy import types
|
||||
|
||||
from sqlalchemy_utils import i18n
|
||||
from sqlalchemy_utils.exceptions import ImproperlyConfigured
|
||||
from sqlalchemy_utils.primitives import WeekDay, WeekDays
|
||||
|
||||
@@ -57,7 +53,7 @@ class WeekDaysType(types.TypeDecorator, ScalarCoercible):
|
||||
impl = BitType(WeekDay.NUM_WEEK_DAYS)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if babel is None:
|
||||
if i18n.babel is None:
|
||||
raise ImproperlyConfigured(
|
||||
"'babel' package is required to use 'WeekDaysType'"
|
||||
)
|
||||
|
||||
@@ -31,7 +31,7 @@ sa.event.listen(sa.orm.mapper, 'mapper_configured', coercion_listener)
|
||||
|
||||
def get_locale():
|
||||
class Locale():
|
||||
territories = {'fi': 'Finland'}
|
||||
territories = {'FI': 'Finland'}
|
||||
|
||||
return Locale()
|
||||
|
||||
|
||||
@@ -2,13 +2,12 @@ import six
|
||||
from pytest import mark, raises
|
||||
|
||||
from sqlalchemy_utils import Country, i18n
|
||||
from sqlalchemy_utils.primitives.currency import babel # noqa
|
||||
|
||||
|
||||
@mark.skipif('babel is None')
|
||||
@mark.skipif('i18n.babel is None')
|
||||
class TestCountry(object):
|
||||
def setup_method(self, method):
|
||||
i18n.get_locale = lambda: babel.Locale('en')
|
||||
i18n.get_locale = lambda: i18n.babel.Locale('en')
|
||||
|
||||
def test_init(self):
|
||||
assert Country(u'FI') == Country(Country(u'FI'))
|
||||
|
||||
@@ -3,13 +3,12 @@ import six
|
||||
from pytest import mark, raises
|
||||
|
||||
from sqlalchemy_utils import Currency, i18n
|
||||
from sqlalchemy_utils.primitives.currency import babel # noqa
|
||||
|
||||
|
||||
@mark.skipif('babel is None')
|
||||
@mark.skipif('i18n.babel is None')
|
||||
class TestCurrency(object):
|
||||
def setup_method(self, method):
|
||||
i18n.get_locale = lambda: babel.Locale('en')
|
||||
i18n.get_locale = lambda: i18n.babel.Locale('en')
|
||||
|
||||
def test_init(self):
|
||||
assert Currency('USD') == Currency(Currency('USD'))
|
||||
|
||||
@@ -5,17 +5,11 @@ from flexmock import flexmock
|
||||
from sqlalchemy_utils import i18n
|
||||
from sqlalchemy_utils.primitives import WeekDay, WeekDays
|
||||
|
||||
Locale = None
|
||||
try:
|
||||
from babel import Locale
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.skipif('Locale is None')
|
||||
@pytest.mark.skipif('i18n.babel is None')
|
||||
class TestWeekDay(object):
|
||||
def setup_method(self, method):
|
||||
i18n.get_locale = lambda: Locale('fi')
|
||||
i18n.get_locale = lambda: i18n.babel.Locale('fi')
|
||||
|
||||
def test_constructor_with_valid_index(self):
|
||||
day = WeekDay(1)
|
||||
@@ -88,7 +82,7 @@ class TestWeekDay(object):
|
||||
assert str(day) == 'maanantaina'
|
||||
|
||||
|
||||
@pytest.mark.skipif('Locale is None')
|
||||
@pytest.mark.skipif('i18n.babel is None')
|
||||
class TestWeekDays(object):
|
||||
def test_constructor_with_valid_bit_string(self):
|
||||
days = WeekDays('1000100')
|
||||
@@ -161,11 +155,11 @@ class TestWeekDays(object):
|
||||
assert indices == [1, 2, 3, 4, 5, 6, 0]
|
||||
|
||||
def test_unicode(self):
|
||||
i18n.get_locale = lambda: Locale('fi')
|
||||
i18n.get_locale = lambda: i18n.babel.Locale('fi')
|
||||
days = WeekDays('1000100')
|
||||
assert six.text_type(days) == u'maanantaina, perjantaina'
|
||||
|
||||
def test_str(self):
|
||||
i18n.get_locale = lambda: Locale('fi')
|
||||
i18n.get_locale = lambda: i18n.babel.Locale('fi')
|
||||
days = WeekDays('1000100')
|
||||
assert str(days) == 'maanantaina, perjantaina'
|
||||
|
||||
@@ -2,10 +2,11 @@ import sqlalchemy as sa
|
||||
from pytest import mark
|
||||
from sqlalchemy.dialects.postgresql import HSTORE
|
||||
|
||||
from sqlalchemy_utils import TranslationHybrid
|
||||
from sqlalchemy_utils import i18n, TranslationHybrid # noqa
|
||||
from tests import TestCase
|
||||
|
||||
|
||||
@mark.skipif('i18n.babel is None')
|
||||
class TestTranslationHybrid(TestCase):
|
||||
dns = 'postgres://postgres@localhost/sqlalchemy_utils_test'
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ from sqlalchemy_utils import (
|
||||
remove_composite_listeners
|
||||
)
|
||||
from sqlalchemy_utils.types import pg_composite
|
||||
from sqlalchemy_utils.types.currency import babel
|
||||
from sqlalchemy_utils.types.range import intervals
|
||||
from tests import TestCase
|
||||
|
||||
@@ -52,13 +51,13 @@ class TestCompositeTypeWithRegularTypes(TestCase):
|
||||
assert account.balance.amount == 15
|
||||
|
||||
|
||||
@mark.skipif('babel is None')
|
||||
@mark.skipif('i18n.babel is None')
|
||||
class TestCompositeTypeWithTypeDecorators(TestCase):
|
||||
dns = 'postgres://postgres@localhost/sqlalchemy_utils_test'
|
||||
|
||||
def setup_method(self, method):
|
||||
TestCase.setup_method(self, method)
|
||||
i18n.get_locale = lambda: babel.Locale('en')
|
||||
i18n.get_locale = lambda: i18n.babel.Locale('en')
|
||||
|
||||
def create_models(self):
|
||||
class Account(self.Base):
|
||||
@@ -101,7 +100,7 @@ class TestCompositeTypeWithTypeDecorators(TestCase):
|
||||
assert account.balance.amount == 15
|
||||
|
||||
|
||||
@mark.skipif('babel is None')
|
||||
@mark.skipif('i18n.babel is None')
|
||||
class TestCompositeTypeInsideArray(TestCase):
|
||||
dns = 'postgres://postgres@localhost/sqlalchemy_utils_test'
|
||||
|
||||
@@ -115,7 +114,7 @@ class TestCompositeTypeInsideArray(TestCase):
|
||||
)
|
||||
|
||||
TestCase.setup_method(self, method)
|
||||
i18n.get_locale = lambda: babel.Locale('en')
|
||||
i18n.get_locale = lambda: i18n.babel.Locale('en')
|
||||
|
||||
def create_models(self):
|
||||
class Account(self.Base):
|
||||
@@ -159,7 +158,6 @@ class TestCompositeTypeWithRangeTypeInsideArray(TestCase):
|
||||
)
|
||||
|
||||
TestCase.setup_method(self, method)
|
||||
i18n.get_locale = lambda: babel.Locale('en')
|
||||
|
||||
def create_models(self):
|
||||
class Account(self.Base):
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import sqlalchemy as sa
|
||||
from pytest import mark
|
||||
|
||||
from sqlalchemy_utils import Country, CountryType
|
||||
from sqlalchemy_utils import Country, CountryType, i18n # noqa
|
||||
from tests import TestCase
|
||||
|
||||
|
||||
@mark.skipif('i18n.babel is None')
|
||||
class TestCountryType(TestCase):
|
||||
def create_models(self):
|
||||
class User(self.Base):
|
||||
@@ -18,7 +20,7 @@ class TestCountryType(TestCase):
|
||||
|
||||
def test_parameter_processing(self):
|
||||
user = self.User(
|
||||
country=Country(u'fi')
|
||||
country=Country(u'FI')
|
||||
)
|
||||
|
||||
self.session.add(user)
|
||||
@@ -28,6 +30,5 @@ class TestCountryType(TestCase):
|
||||
assert user.country.name == u'Finland'
|
||||
|
||||
def test_scalar_attributes_get_coerced_to_objects(self):
|
||||
user = self.User(country='fi')
|
||||
|
||||
user = self.User(country='FI')
|
||||
assert isinstance(user.country, Country)
|
||||
|
||||
@@ -3,15 +3,14 @@ import sqlalchemy as sa
|
||||
from pytest import mark
|
||||
|
||||
from sqlalchemy_utils import Currency, CurrencyType, i18n
|
||||
from sqlalchemy_utils.types.currency import babel
|
||||
from tests import TestCase
|
||||
|
||||
|
||||
@mark.skipif('babel is None')
|
||||
@mark.skipif('i18n.babel is None')
|
||||
class TestCurrencyType(TestCase):
|
||||
def setup_method(self, method):
|
||||
TestCase.setup_method(self, method)
|
||||
i18n.get_locale = lambda: babel.Locale('en')
|
||||
i18n.get_locale = lambda: i18n.babel.Locale('en')
|
||||
|
||||
def create_models(self):
|
||||
class User(self.Base):
|
||||
|
||||
@@ -4,15 +4,14 @@ import sqlalchemy as sa
|
||||
from sqlalchemy_utils import i18n
|
||||
from sqlalchemy_utils.primitives import WeekDays
|
||||
from sqlalchemy_utils.types import WeekDaysType
|
||||
from sqlalchemy_utils.types.weekdays import babel
|
||||
from tests import TestCase
|
||||
|
||||
|
||||
@pytest.mark.skipif('babel is None')
|
||||
@pytest.mark.skipif('i18n.babel is None')
|
||||
class WeekDaysTypeTestCase(TestCase):
|
||||
def setup_method(self, method):
|
||||
TestCase.setup_method(self, method)
|
||||
i18n.get_locale = lambda: babel.Locale('en')
|
||||
i18n.get_locale = lambda: i18n.babel.Locale('en')
|
||||
|
||||
def create_models(self):
|
||||
class Schedule(self.Base):
|
||||
|
||||
Reference in New Issue
Block a user