Source code for valuta.base

from decimal import Decimal
import operator
from typing import Optional, Dict, Union, List, Set, Tuple, ItemsView
from babel.numbers import (
    get_currency_name,
    get_currency_symbol,
    format_currency,
)

from .constants import DEFAULT_DISPLAY_FORMAT
from .exceptions import ImproperlyConfigured
from .helpers import classproperty

__author__ = "Artur Barseghyan"
__copyright__ = "2021 Artur Barseghyan"
__license__ = "GPL-2.0-only OR LGPL-2.1-or-later"
__all__ = (
    "BaseCurrency",
    "Registry",
)


[docs]class Registry(type): REGISTRY: Dict[str, "BaseCurrency"] = {} def __new__(mcs, name, bases, attrs): new_cls = type.__new__(mcs, name, bases, attrs) # Here the name of the class is used as key but it could be any class # parameter. if getattr(new_cls, "_uid", None): mcs.REGISTRY[new_cls._uid] = new_cls if new_cls.__name__ != "BaseCurrency": new_cls.validate() return new_cls @property def _uid(cls) -> str: return getattr(cls, "uid", cls.__name__)
[docs] @classmethod def reset(mcs) -> None: mcs.REGISTRY = {}
[docs] @classmethod def get( mcs, key: str, default: "BaseCurrency" = None ) -> Union["BaseCurrency", None]: return mcs.REGISTRY.get(key, default)
[docs] @classmethod def items(mcs) -> ItemsView[str, "BaseCurrency"]: return mcs.REGISTRY.items()
[docs] @classmethod def values( mcs, limit_choices_to: Union[Tuple[str, ...], List[str], Set[str]] = None, sort_by_key: bool = False, ) -> List[Tuple[str, str]]: if limit_choices_to is None: values = [ (__key, __value.name) for __key, __value in mcs.REGISTRY.items() ] else: values = [ (__key, __value.name) for __key, __value in mcs.REGISTRY.items() if __key in limit_choices_to ] if sort_by_key: values.sort(key=operator.itemgetter(0)) else: values.sort(key=operator.itemgetter(1)) return values
[docs] @classmethod def values_with_code( mcs, limit_choices_to: Union[Tuple[str, ...], List[str], Set[str]] = None, sort_by_key: bool = False, ) -> List[Tuple[str, str]]: if limit_choices_to is None: values = [ (__key, f"{__value.name} ({__key})") for __key, __value in mcs.REGISTRY.items() ] else: values = [ (__key, f"{__value.name} ({__key})") for __key, __value in mcs.REGISTRY.items() if __key in limit_choices_to ] if sort_by_key: values.sort(key=operator.itemgetter(0)) else: values.sort(key=operator.itemgetter(1)) return values
[docs]class BaseCurrency(metaclass=Registry): """Base currency. Each currency typically has a main currency unit (the dollar, for example, or the euro) and a fractional unit, often defined as 1⁄100 of the main unit: 100 cents = 1 dollar, 100 centimes = 1 franc, 100 pence = 1 pound, although units of 1⁄10 or 1⁄1000 occasionally also occur. Some currencies do not have any smaller units at all, such as the Icelandic krona. https://en.wikipedia.org/wiki/Currency """ uid: Optional[str] = None rate: Union[int, float, Decimal]
[docs] @classmethod def validate(cls): """Constructor.""" if not hasattr(cls, "rate"): raise ImproperlyConfigured( "The `rate` property of the currency shall be defined." )
[docs] @classmethod def convert_to_currency_units( cls, value: int ) -> Union[int, float, Decimal]: """Convert to amount in currency units.""" return value / cls.rate
[docs] @classmethod def display_in_currency_units( cls, value: int, format: Optional[str] = DEFAULT_DISPLAY_FORMAT, locale: Optional[str] = None, decimal_quantization: bool = True, ) -> str: """Convert to amount in currency units.""" kwargs = {} if locale is not None: kwargs = {"locale": locale} return format_currency( value / cls.rate, cls.uid, format, decimal_quantization=decimal_quantization, **kwargs, )
@classproperty def name(cls) -> str: """Automatic currency name. Example:: from babel.numbers import get_currency_name In: get_currency_name('AMD') Out: 'Armenian Dram' In: get_currency_name('AMD', locale='hy_AM') Out: 'հայկական դրամ' In: get_currency_name('AMD', locale='nl_NL') Out: 'Armeense dram' :return: """ return get_currency_name(cls.uid) @classproperty def symbol(cls) -> str: """Automatic currency symbol. Example:: from babel.numbers import get_currency_symbol In: get_currency_symbol('AMD') Out: 'AMD' In: get_currency_symbol('AMD', locale='hy_AM') Out: '֏' In: get_currency_symbol('AMD', locale='nl_NL') Out: 'AMD' :return: """ return get_currency_symbol(cls.uid)