File: country.py

package info (click to toggle)
python-sqlalchemy-utils 0.41.2-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,252 kB
  • sloc: python: 13,566; makefile: 141
file content (110 lines) | stat: -rw-r--r-- 2,740 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
from functools import total_ordering

from .. import i18n
from ..utils import str_coercible


@total_ordering
@str_coercible
class Country:
    """
    Country class wraps a 2 to 3 letter country code. It provides various
    convenience properties and methods.

    ::

        from babel import Locale
        from sqlalchemy_utils import Country, i18n


        # First lets add a locale getter for testing purposes
        i18n.get_locale = lambda: Locale('en')


        Country('FI').name  # Finland
        Country('FI').code  # FI

        Country(Country('FI')).code  # 'FI'

    Country always validates the given code if you use at least the optional
    dependency list 'babel', otherwise no validation are performed.

    ::

        Country(None)  # raises TypeError

        Country('UnknownCode')  # raises ValueError


    Country supports equality operators.

    ::

        Country('FI') == Country('FI')
        Country('FI') != Country('US')


    Country objects are hashable.


    ::

        assert hash(Country('FI')) == hash('FI')

    """
    def __init__(self, code_or_country):
        if isinstance(code_or_country, Country):
            self.code = code_or_country.code
        elif isinstance(code_or_country, str):
            self.validate(code_or_country)
            self.code = code_or_country
        else:
            raise TypeError(
                "Country() argument must be a string or a country, not '{}'"
                .format(
                    type(code_or_country).__name__
                )
            )

    @property
    def name(self):
        return i18n.get_locale().territories[self.code]

    @classmethod
    def validate(self, code):
        try:
            i18n.babel.Locale('en').territories[code]
        except KeyError:
            raise ValueError(
                f'Could not convert string to country code: {code}'
            )
        except AttributeError:
            # As babel is optional, we may raise an AttributeError accessing it
            pass

    def __eq__(self, other):
        if isinstance(other, Country):
            return self.code == other.code
        elif isinstance(other, str):
            return self.code == other
        else:
            return NotImplemented

    def __hash__(self):
        return hash(self.code)

    def __ne__(self, other):
        return not (self == other)

    def __lt__(self, other):
        if isinstance(other, Country):
            return self.code < other.code
        elif isinstance(other, str):
            return self.code < other
        return NotImplemented

    def __repr__(self):
        return f'{self.__class__.__name__}({self.code!r})'

    def __unicode__(self):
        return self.name