forked from Raiza.dev/EliteBot
Cleaned up the directories
This commit is contained in:
parent
f708506d68
commit
a683fcffea
1340 changed files with 554582 additions and 6840 deletions
|
@ -0,0 +1,5 @@
|
|||
from .country import Country # noqa
|
||||
from .currency import Currency # noqa
|
||||
from .ltree import Ltree # noqa
|
||||
from .weekday import WeekDay # noqa
|
||||
from .weekdays import WeekDays # noqa
|
|
@ -0,0 +1,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
|
|
@ -0,0 +1,109 @@
|
|||
from .. import i18n, ImproperlyConfigured
|
||||
from ..utils import str_coercible
|
||||
|
||||
|
||||
@str_coercible
|
||||
class Currency:
|
||||
"""
|
||||
Currency class wraps a 3-letter currency code. It provides various
|
||||
convenience properties and methods.
|
||||
|
||||
::
|
||||
|
||||
from babel import Locale
|
||||
from sqlalchemy_utils import Currency, i18n
|
||||
|
||||
|
||||
# First lets add a locale getter for testing purposes
|
||||
i18n.get_locale = lambda: Locale('en')
|
||||
|
||||
|
||||
Currency('USD').name # US Dollar
|
||||
Currency('USD').symbol # $
|
||||
|
||||
Currency(Currency('USD')).code # 'USD'
|
||||
|
||||
Currency always validates the given code if you use at least the optional
|
||||
dependency list 'babel', otherwise no validation are performed.
|
||||
|
||||
::
|
||||
|
||||
Currency(None) # raises TypeError
|
||||
|
||||
Currency('UnknownCode') # raises ValueError
|
||||
|
||||
|
||||
Currency supports equality operators.
|
||||
|
||||
::
|
||||
|
||||
Currency('USD') == Currency('USD')
|
||||
Currency('USD') != Currency('EUR')
|
||||
|
||||
|
||||
Currencies are hashable.
|
||||
|
||||
|
||||
::
|
||||
|
||||
len(set([Currency('USD'), Currency('USD')])) # 1
|
||||
|
||||
|
||||
"""
|
||||
def __init__(self, code):
|
||||
if i18n.babel is None:
|
||||
raise ImproperlyConfigured(
|
||||
"'babel' package is required in order to use Currency class."
|
||||
)
|
||||
if isinstance(code, Currency):
|
||||
self.code = code
|
||||
elif isinstance(code, str):
|
||||
self.validate(code)
|
||||
self.code = code
|
||||
else:
|
||||
raise TypeError(
|
||||
'First argument given to Currency constructor should be '
|
||||
'either an instance of Currency or valid three letter '
|
||||
'currency code.'
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def validate(self, code):
|
||||
try:
|
||||
i18n.babel.Locale('en').currencies[code]
|
||||
except KeyError:
|
||||
raise ValueError(f"'{code}' is not valid currency code.")
|
||||
except AttributeError:
|
||||
# As babel is optional, we may raise an AttributeError accessing it
|
||||
pass
|
||||
|
||||
@property
|
||||
def symbol(self):
|
||||
return i18n.babel.numbers.get_currency_symbol(
|
||||
self.code,
|
||||
i18n.get_locale()
|
||||
)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return i18n.get_locale().currencies[self.code]
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Currency):
|
||||
return self.code == other.code
|
||||
elif isinstance(other, str):
|
||||
return self.code == other
|
||||
else:
|
||||
return NotImplemented
|
||||
|
||||
def __ne__(self, other):
|
||||
return not (self == other)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.code)
|
||||
|
||||
def __repr__(self):
|
||||
return f'{self.__class__.__name__}({self.code!r})'
|
||||
|
||||
def __unicode__(self):
|
||||
return self.code
|
|
@ -0,0 +1,220 @@
|
|||
import re
|
||||
|
||||
from ..utils import str_coercible
|
||||
|
||||
path_matcher = re.compile(r'^[A-Za-z0-9_]+(\.[A-Za-z0-9_]+)*$')
|
||||
|
||||
|
||||
@str_coercible
|
||||
class Ltree:
|
||||
"""
|
||||
Ltree class wraps a valid string label path. It provides various
|
||||
convenience properties and methods.
|
||||
|
||||
::
|
||||
|
||||
from sqlalchemy_utils import Ltree
|
||||
|
||||
Ltree('1.2.3').path # '1.2.3'
|
||||
|
||||
|
||||
Ltree always validates the given path.
|
||||
|
||||
::
|
||||
|
||||
Ltree(None) # raises TypeError
|
||||
|
||||
Ltree('..') # raises ValueError
|
||||
|
||||
|
||||
Validator is also available as class method.
|
||||
|
||||
::
|
||||
|
||||
Ltree.validate('1.2.3')
|
||||
Ltree.validate(None) # raises TypeError
|
||||
|
||||
|
||||
Ltree supports equality operators.
|
||||
|
||||
::
|
||||
|
||||
Ltree('Countries.Finland') == Ltree('Countries.Finland')
|
||||
Ltree('Countries.Germany') != Ltree('Countries.Finland')
|
||||
|
||||
|
||||
Ltree objects are hashable.
|
||||
|
||||
|
||||
::
|
||||
|
||||
assert hash(Ltree('Finland')) == hash('Finland')
|
||||
|
||||
|
||||
Ltree objects have length.
|
||||
|
||||
::
|
||||
|
||||
assert len(Ltree('1.2')) == 2
|
||||
assert len(Ltree('some.one.some.where')) # 4
|
||||
|
||||
|
||||
You can easily find subpath indexes.
|
||||
|
||||
::
|
||||
|
||||
assert Ltree('1.2.3').index('2.3') == 1
|
||||
assert Ltree('1.2.3.4.5').index('3.4') == 2
|
||||
|
||||
|
||||
Ltree objects can be sliced.
|
||||
|
||||
|
||||
::
|
||||
|
||||
assert Ltree('1.2.3')[0:2] == Ltree('1.2')
|
||||
assert Ltree('1.2.3')[1:] == Ltree('2.3')
|
||||
|
||||
|
||||
Finding longest common ancestor.
|
||||
|
||||
|
||||
::
|
||||
|
||||
assert Ltree('1.2.3.4.5').lca('1.2.3', '1.2.3.4', '1.2.3') == '1.2'
|
||||
assert Ltree('1.2.3.4.5').lca('1.2', '1.2.3') == '1'
|
||||
|
||||
|
||||
Ltree objects can be concatenated.
|
||||
|
||||
::
|
||||
|
||||
assert Ltree('1.2') + Ltree('1.2') == Ltree('1.2.1.2')
|
||||
"""
|
||||
|
||||
def __init__(self, path_or_ltree):
|
||||
if isinstance(path_or_ltree, Ltree):
|
||||
self.path = path_or_ltree.path
|
||||
elif isinstance(path_or_ltree, str):
|
||||
self.validate(path_or_ltree)
|
||||
self.path = path_or_ltree
|
||||
else:
|
||||
raise TypeError(
|
||||
"Ltree() argument must be a string or an Ltree, not '{}'"
|
||||
.format(
|
||||
type(path_or_ltree).__name__
|
||||
)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def validate(cls, path):
|
||||
if path_matcher.match(path) is None:
|
||||
raise ValueError(
|
||||
f"'{path}' is not a valid ltree path."
|
||||
)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.path.split('.'))
|
||||
|
||||
def index(self, other):
|
||||
subpath = Ltree(other).path.split('.')
|
||||
parts = self.path.split('.')
|
||||
for index, _ in enumerate(parts):
|
||||
if parts[index:len(subpath) + index] == subpath:
|
||||
return index
|
||||
raise ValueError('subpath not found')
|
||||
|
||||
def descendant_of(self, other):
|
||||
"""
|
||||
is left argument a descendant of right (or equal)?
|
||||
|
||||
::
|
||||
|
||||
assert Ltree('1.2.3.4.5').descendant_of('1.2.3')
|
||||
"""
|
||||
subpath = self[:len(Ltree(other))]
|
||||
return subpath == other
|
||||
|
||||
def ancestor_of(self, other):
|
||||
"""
|
||||
is left argument an ancestor of right (or equal)?
|
||||
|
||||
::
|
||||
|
||||
assert Ltree('1.2.3').ancestor_of('1.2.3.4.5')
|
||||
"""
|
||||
subpath = Ltree(other)[:len(self)]
|
||||
return subpath == self
|
||||
|
||||
def __getitem__(self, key):
|
||||
if isinstance(key, int):
|
||||
return Ltree(self.path.split('.')[key])
|
||||
elif isinstance(key, slice):
|
||||
return Ltree('.'.join(self.path.split('.')[key]))
|
||||
raise TypeError(
|
||||
'Ltree indices must be integers, not {}'.format(
|
||||
key.__class__.__name__
|
||||
)
|
||||
)
|
||||
|
||||
def lca(self, *others):
|
||||
"""
|
||||
Lowest common ancestor, i.e., longest common prefix of paths
|
||||
|
||||
::
|
||||
|
||||
assert Ltree('1.2.3.4.5').lca('1.2.3', '1.2.3.4', '1.2.3') == '1.2'
|
||||
"""
|
||||
other_parts = [Ltree(other).path.split('.') for other in others]
|
||||
parts = self.path.split('.')
|
||||
for index, element in enumerate(parts):
|
||||
if any(
|
||||
other[index] != element or
|
||||
len(other) <= index + 1 or
|
||||
len(parts) == index + 1
|
||||
for other in other_parts
|
||||
):
|
||||
if index == 0:
|
||||
return None
|
||||
return Ltree('.'.join(parts[0:index]))
|
||||
|
||||
def __add__(self, other):
|
||||
return Ltree(self.path + '.' + Ltree(other).path)
|
||||
|
||||
def __radd__(self, other):
|
||||
return Ltree(other) + self
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Ltree):
|
||||
return self.path == other.path
|
||||
elif isinstance(other, str):
|
||||
return self.path == other
|
||||
else:
|
||||
return NotImplemented
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.path)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not (self == other)
|
||||
|
||||
def __repr__(self):
|
||||
return f'{self.__class__.__name__}({self.path!r})'
|
||||
|
||||
def __unicode__(self):
|
||||
return self.path
|
||||
|
||||
def __contains__(self, label):
|
||||
return label in self.path.split('.')
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.path > other.path
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.path < other.path
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.path >= other.path
|
||||
|
||||
def __le__(self, other):
|
||||
return self.path <= other.path
|
|
@ -0,0 +1,54 @@
|
|||
from functools import total_ordering
|
||||
|
||||
from .. import i18n
|
||||
from ..utils import str_coercible
|
||||
|
||||
|
||||
@str_coercible
|
||||
@total_ordering
|
||||
class WeekDay:
|
||||
NUM_WEEK_DAYS = 7
|
||||
|
||||
def __init__(self, index):
|
||||
if not (0 <= index < self.NUM_WEEK_DAYS):
|
||||
raise ValueError(
|
||||
"index must be between 0 and %d" % self.NUM_WEEK_DAYS
|
||||
)
|
||||
self.index = index
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, WeekDay):
|
||||
return self.index == other.index
|
||||
else:
|
||||
return NotImplemented
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.index)
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.position < other.position
|
||||
|
||||
def __repr__(self):
|
||||
return f'{self.__class__.__name__}({self.index!r})'
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
def get_name(self, width='wide', context='format'):
|
||||
names = i18n.babel.dates.get_day_names(
|
||||
width,
|
||||
context,
|
||||
i18n.get_locale()
|
||||
)
|
||||
return names[self.index]
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.get_name()
|
||||
|
||||
@property
|
||||
def position(self):
|
||||
return (
|
||||
self.index -
|
||||
i18n.get_locale().first_week_day
|
||||
) % self.NUM_WEEK_DAYS
|
|
@ -0,0 +1,57 @@
|
|||
from ..utils import str_coercible
|
||||
from .weekday import WeekDay
|
||||
|
||||
|
||||
@str_coercible
|
||||
class WeekDays:
|
||||
def __init__(self, bit_string_or_week_days):
|
||||
if isinstance(bit_string_or_week_days, str):
|
||||
self._days = set()
|
||||
|
||||
if len(bit_string_or_week_days) != WeekDay.NUM_WEEK_DAYS:
|
||||
raise ValueError(
|
||||
'Bit string must be {} characters long.'.format(
|
||||
WeekDay.NUM_WEEK_DAYS
|
||||
)
|
||||
)
|
||||
|
||||
for index, bit in enumerate(bit_string_or_week_days):
|
||||
if bit not in '01':
|
||||
raise ValueError(
|
||||
'Bit string may only contain zeroes and ones.'
|
||||
)
|
||||
if bit == '1':
|
||||
self._days.add(WeekDay(index))
|
||||
elif isinstance(bit_string_or_week_days, WeekDays):
|
||||
self._days = bit_string_or_week_days._days
|
||||
else:
|
||||
self._days = set(bit_string_or_week_days)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, WeekDays):
|
||||
return self._days == other._days
|
||||
elif isinstance(other, str):
|
||||
return self.as_bit_string() == other
|
||||
else:
|
||||
return NotImplemented
|
||||
|
||||
def __iter__(self):
|
||||
yield from sorted(self._days)
|
||||
|
||||
def __contains__(self, value):
|
||||
return value in self._days
|
||||
|
||||
def __repr__(self):
|
||||
return '{}({!r})'.format(
|
||||
self.__class__.__name__,
|
||||
self.as_bit_string()
|
||||
)
|
||||
|
||||
def __unicode__(self):
|
||||
return ', '.join(str(day) for day in self)
|
||||
|
||||
def as_bit_string(self):
|
||||
return ''.join(
|
||||
'1' if WeekDay(index) in self._days else '0'
|
||||
for index in range(WeekDay.NUM_WEEK_DAYS)
|
||||
)
|
Loading…
Add table
Add a link
Reference in a new issue