Skip to main content

Currency utilities for the kiarina namespace

Project description

kiarina-currency

PyPI Python License

English | 日本語

[!NOTE] Provides system currency detection and exchange rate retrieval through pluggable providers.

Dependencies

Package Version License
HTTPX >=0.28.1 BSD-3-Clause
kiarina-utils-common >=1.11.0 MIT
Pydantic >=2.10.6 MIT
pydantic-settings >=2.7.1 MIT
pydantic-settings-manager >=3.2.0 MIT

Installation

pip install kiarina-currency

Features

  • Detect the system currency Resolve an ISO 4217 currency code from locale settings and environment variables.
  • Get exchange rates Retrieve rates from configured static data or the Frankfurter API.
  • Extend rate providers Select an implementation by provider instance, registered name, or import path.

Detecting the System Currency

from kiarina.currency import get_system_currency

currency = get_system_currency()

Detection checks locale.localeconv(), the locale name, LC_ALL, LC_MONETARY, and LANG. It returns "USD" when detection fails.

Getting Exchange Rates

The static provider is used by default.

from kiarina.currency import get_exchange_rate

rate = await get_exchange_rate("USD", "JPY")

The static provider resolves direct rates, inverted rates, and indirect rates through the base currency, in that order. A fallback value can be provided when a rate is unavailable.

rate = await get_exchange_rate("USD", "XXX", default=1.0)

The Frankfurter provider retrieves rates from the Frankfurter API.

rate = await get_exchange_rate(
    "USD",
    "EUR",
    rate_options={"rate_provider": "frankfurter"},
)

Configuring Providers

Settings are managed by pydantic-settings-manager. For example, static rates can be configured at runtime.

from kiarina.currency import get_exchange_rate
from kiarina.currency.rate_provider_impl.static import settings_manager

settings_manager.cli_args = {
    "base_currency": "USD",
    "rates": {
        "USD": {
            "EUR": 0.85,
            "JPY": 150.0,
        },
    },
}

rate = await get_exchange_rate("JPY", "EUR")

Environment variable names combine each settings class prefix with its field name.

Setting Environment Variable
Default provider KIARINA_CURRENCY_RATE_PROVIDER_DEFAULT
Static provider base currency KIARINA_CURRENCY_RATE_PROVIDER_IMPL_STATIC_BASE_CURRENCY
Frankfurter API base URL KIARINA_CURRENCY_RATE_PROVIDER_IMPL_FRANKFURTER_BASE_URL
Frankfurter API timeout KIARINA_CURRENCY_RATE_PROVIDER_IMPL_FRANKFURTER_TIMEOUT

Creating a Custom Provider

An instance implementing the RateProvider protocol can be passed directly.

from kiarina.currency import CurrencyCode, get_exchange_rate
from kiarina.currency.rate_provider import BaseRateProvider


class CustomRateProvider(BaseRateProvider):
    async def get_rate(
        self,
        from_currency: CurrencyCode,
        to_currency: CurrencyCode,
        *,
        default: float | None = None,
    ) -> float:
        return 1.5


rate = await get_exchange_rate(
    "USD",
    "EUR",
    rate_options={"rate_provider": CustomRateProvider()},
)

A provider can also be created from a registered name or import path.

from kiarina.currency import create_rate_provider

provider = create_rate_provider("my_package.providers:CustomRateProvider")

When an import path omits the class name, :RateProvider is appended.

API Reference

kiarina.currency

from kiarina.currency import (
    CurrencyCode,
    CurrencyError,
    ExchangeRateNotFoundError,
    RateOptions,
    RateProvider,
    RateProviderName,
    RateProviderSettings,
    create_rate_provider,
    get_exchange_rate,
    get_system_currency,
    rate_provider_settings_manager,
)

Functions

def get_system_currency() -> CurrencyCode: ...

async def get_exchange_rate(
    from_currency: CurrencyCode,
    to_currency: CurrencyCode,
    *,
    default: float | None = None,
    rate_options: RateOptions | None = None,
) -> float: ...

def create_rate_provider(
    provider_name: RateProviderName | ImportPath | None = None,
    **kwargs: Any,
) -> RateProvider: ...

get_system_currency returns the system currency and falls back to "USD" when detection fails.

get_exchange_rate retrieves a rate from the selected provider. It raises ExchangeRateNotFoundError when the rate is unavailable and no default is provided.

create_rate_provider creates a provider from a registered name or import path. It raises TypeError when the resulting object does not implement RateProvider.

RateProvider

@runtime_checkable
class RateProvider(Protocol):
    async def get_rate(
        self,
        from_currency: CurrencyCode,
        to_currency: CurrencyCode,
        *,
        default: float | None = None,
    ) -> float: ...

Settings

class RateProviderSettings(BaseSettings):
    default: RateProviderName = "static"
    providers: dict[RateProviderName, ImportPath] = {
        "frankfurter": "kiarina.currency.rate_provider_impl.frankfurter:FrankfurterRateProvider",
        "static": "kiarina.currency.rate_provider_impl.static:StaticRateProvider",
    }

rate_provider_settings_manager: SettingsManager[RateProviderSettings]

rate_provider_settings_manager is an alias for kiarina.currency.rate_provider.settings_manager.

Types

CurrencyCode: TypeAlias = str
RateProviderName: TypeAlias = str

class RateOptions(TypedDict, total=False):
    rate_provider: RateProvider | RateProviderName | ImportPath | None

CurrencyCode represents an ISO 4217 currency code. RateOptions.rate_provider accepts a provider instance, registered name, import path, or None.

Exceptions

class CurrencyError(Exception): ...

class ExchangeRateNotFoundError(CurrencyError): ...

kiarina.currency.rate_provider

from kiarina.currency.rate_provider import (
    BaseRateProvider,
    RateProvider,
    RateProviderName,
    RateProviderSettings,
    create_rate_provider,
    settings_manager,
)

BaseRateProvider

class BaseRateProvider(RateProvider, ABC):
    def __init__(self, **kwargs: Any) -> None: ...

    @abstractmethod
    async def get_rate(
        self,
        from_currency: CurrencyCode,
        to_currency: CurrencyCode,
        *,
        default: float | None = None,
    ) -> float: ...

Use this base class for custom providers and implement get_rate.

settings_manager: SettingsManager[RateProviderSettings]

kiarina.currency.rate_provider_impl.static

from kiarina.currency.rate_provider_impl.static import (
    StaticRateProvider,
    StaticRateProviderSettings,
    settings_manager,
)

StaticRateProvider

class StaticRateProvider(BaseRateProvider):
    async def get_rate(
        self,
        from_currency: CurrencyCode,
        to_currency: CurrencyCode,
        *,
        default: float | None = None,
    ) -> float: ...

Settings

class StaticRateProviderSettings(BaseSettings):
    base_currency: CurrencyCode = "USD"
    rates: dict[CurrencyCode, dict[CurrencyCode, float]]

settings_manager: SettingsManager[StaticRateProviderSettings]

rates is nested by source currency, target currency, and rate.

kiarina.currency.rate_provider_impl.frankfurter

from kiarina.currency.rate_provider_impl.frankfurter import (
    FrankfurterRateProvider,
    FrankfurterRateProviderSettings,
    settings_manager,
)

FrankfurterRateProvider

class FrankfurterRateProvider(BaseRateProvider):
    async def get_rate(
        self,
        from_currency: CurrencyCode,
        to_currency: CurrencyCode,
        *,
        default: float | None = None,
    ) -> float: ...

When an HTTP error, network error, timeout, or missing rate occurs, the provider returns default when supplied. Otherwise, it raises ExchangeRateNotFoundError.

Settings

class FrankfurterRateProviderSettings(BaseSettings):
    base_url: str = "https://api.frankfurter.app"
    timeout: float = 10.0

settings_manager: SettingsManager[FrankfurterRateProviderSettings]

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kiarina_currency-2.3.1.tar.gz (12.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kiarina_currency-2.3.1-py3-none-any.whl (16.3 kB view details)

Uploaded Python 3

File details

Details for the file kiarina_currency-2.3.1.tar.gz.

File metadata

  • Download URL: kiarina_currency-2.3.1.tar.gz
  • Upload date:
  • Size: 12.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for kiarina_currency-2.3.1.tar.gz
Algorithm Hash digest
SHA256 39f462407be82ed266c94ee1c3251fbe93160656b0b27b74b07fc095dbbff41b
MD5 6c8ad2164f76db4b6a3b4a299882e924
BLAKE2b-256 bb7206a22448c8351f47dc798add0225905562682b1d768685cadb340000781f

See more details on using hashes here.

Provenance

The following attestation bundles were made for kiarina_currency-2.3.1.tar.gz:

Publisher: release-pypi.yml on kiarina/kiarina-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kiarina_currency-2.3.1-py3-none-any.whl.

File metadata

File hashes

Hashes for kiarina_currency-2.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 cd568a67615125469e467c59bd1ed6f662b387cfe0b27391c3e73b571da55e49
MD5 28703c95214c5923c8a42ee47da2362a
BLAKE2b-256 7d8c59197c3184d46b7dffaf44ca769db1b59b2f9ba30ae6ca4664d82ba65689

See more details on using hashes here.

Provenance

The following attestation bundles were made for kiarina_currency-2.3.1-py3-none-any.whl:

Publisher: release-pypi.yml on kiarina/kiarina-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page