File: test_translation_hybrid.py

package info (click to toggle)
python-sqlalchemy-utils 0.41.2-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 1,252 kB
  • sloc: python: 13,566; makefile: 141
file content (138 lines) | stat: -rw-r--r-- 4,445 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import pytest
import sqlalchemy as sa
from flexmock import flexmock
from sqlalchemy.dialects.postgresql import HSTORE
from sqlalchemy.orm import aliased

from sqlalchemy_utils import i18n, TranslationHybrid  # noqa


@pytest.fixture
def translation_hybrid():
    return TranslationHybrid('fi', 'en')


@pytest.fixture
def City(Base, translation_hybrid):
    class City(Base):
        __tablename__ = 'city'
        id = sa.Column(sa.Integer, primary_key=True)
        name_translations = sa.Column(HSTORE)
        name = translation_hybrid(name_translations)
        locale = 'en'
    return City


@pytest.fixture
def init_models(City):
    pass


@pytest.mark.usefixtures('postgresql_dsn')
@pytest.mark.skipif('i18n.babel is None')
class TestTranslationHybrid:

    def test_using_hybrid_as_constructor(self, City):
        city = City(name='Helsinki')
        assert city.name_translations['fi'] == 'Helsinki'

    def test_if_no_translation_exists_returns_none(self, City):
        city = City()
        assert city.name is None

    def test_custom_default_value(self, City, translation_hybrid):
        translation_hybrid.default_value = 'Some value'
        city = City()
        assert city.name == 'Some value'

    def test_fall_back_to_default_translation(self, City, translation_hybrid):
        city = City(name_translations={'en': 'Helsinki'})
        translation_hybrid.current_locale = 'sv'
        assert city.name == 'Helsinki'

    def test_fallback_to_dynamic_locale(self, City, translation_hybrid):
        translation_hybrid.current_locale = 'en'
        translation_hybrid.default_locale = lambda self: self.locale
        city = City(name_translations={})
        city.locale = 'fi'
        city.name_translations['fi'] = 'Helsinki'

        assert city.name == 'Helsinki'

    def test_fallback_to_attr_dependent_locale(self, City, translation_hybrid):
        translation_hybrid.current_locale = 'en'
        translation_hybrid.default_locale = (
            lambda obj, attr: sorted(getattr(obj, attr).keys())[0]
        )
        city = City(name_translations={})
        city.name_translations['fi'] = 'Helsinki'
        assert city.name == 'Helsinki'
        city.name_translations['de'] = 'Stadt Helsinki'
        assert city.name == 'Stadt Helsinki'

    @pytest.mark.parametrize(
        ('name_translations', 'name'),
        (
            ({'fi': 'Helsinki', 'en': 'Helsing'}, 'Helsinki'),
            ({'en': 'Helsinki'}, 'Helsinki'),
            ({'fi': 'Helsinki'}, 'Helsinki'),
            ({}, None),
        )
    )
    def test_hybrid_as_an_expression(
        self,
        session,
        City,
        name_translations,
        name
    ):
        city = City(name_translations=name_translations)
        session.add(city)
        session.commit()

        assert session.query(City.name).scalar() == name

    def test_dynamic_locale(self, Base):
        translation_hybrid = TranslationHybrid(
            lambda obj: obj.locale,
            'fi'
        )

        class Article(Base):
            __tablename__ = 'article'
            id = sa.Column(sa.Integer, primary_key=True)
            name_translations = sa.Column(HSTORE)
            name = translation_hybrid(name_translations)
            locale = sa.Column(sa.String)

        assert (
            'coalesce(article.name_translations -> article.locale'
            in str(Article.name.expression)
        )

    def test_locales_casted_only_in_compilation_phase(self, Base):
        class LocaleGetter:
            def current_locale(self):
                return lambda obj: obj.locale

        flexmock(LocaleGetter).should_receive('current_locale').never()
        translation_hybrid = TranslationHybrid(
            LocaleGetter().current_locale,
            'fi'
        )

        class Article(Base):
            __tablename__ = 'article'
            id = sa.Column(sa.Integer, primary_key=True)
            name_translations = sa.Column(HSTORE)
            name = translation_hybrid(name_translations)
            locale = sa.Column(sa.String)

        Article.name

    def test_no_implicit_join_when_using_aliased_entities(self, session, City):
        # Ensure that queried entities are taken from the alias so that
        # there isn't an extra join to the original entity.
        CityAlias = aliased(City)
        query_str = str(session.query(CityAlias.name))
        assert query_str.endswith('FROM city AS city_1')