Skip to main content

flask-unirate

PyPI Python License

Flask extension for the UniRate currency-exchange API:

  • Drop-in UniRate(app) extension — follows the standard init_app factory pattern, registers itself on app.extensions["unirate"].
  • Jinja filters — {{ amount|to_currency('EUR') }}, {{ amount|convert_currency('USD', 'JPY') }}, {{ price|format_money('USD') }}, plus to_usd / to_eur / to_gbp shortcuts.
  • Optional Flask-Caching integration — set UNIRATE_CACHE_TIMEOUT and the extension caches latest-rate / supported-currency lookups through whatever Flask-Caching backend you already have.
  • Wraps the official unirate-api Python client; full method surface is reachable through unirate.client if you need historical rates / VAT / time series.

UniRate covers 593+ fiat, crypto, and commodity codes. Latest rates and conversion are on the free tier; historical endpoints (get_historical_rate, convert_historical) require Pro.

Install

pip install flask-unirate

With Flask-Caching support:

pip install "flask-unirate[caching]"

Quick start

import os

from flask import Flask, render_template_string

from flask_unirate import UniRate

app = Flask(__name__)
app.config["UNIRATE_API_KEY"] = os.environ["UNIRATE_API_KEY"]
unirate = UniRate(app)


@app.route("/rate/<base>/<quote>")
def rate(base: str, quote: str):
    return {"rate": unirate.get_rate(base, quote)}


@app.route("/checkout/<int:amount_usd>")
def checkout(amount_usd: int):
    return render_template_string(
        """
        <p>USD: {{ amount|format_money('USD') }}</p>
        <p>EUR: {{ amount|to_eur|format_money('EUR') }}</p>
        <p>JPY: {{ amount|to_currency('JPY')|format_money('JPY', decimals=0) }}</p>
        """,
        amount=amount_usd,
    )

Configuration

Key Default Notes
UNIRATE_API_KEY — Required. Falls back to the UNIRATE_API_KEY env var.
UNIRATE_TIMEOUT 30 (s) HTTP timeout passed to UnirateClient.
UNIRATE_BASE_URL https://api.unirateapi.com Override only if you proxy the API.
UNIRATE_DEFAULT_BASE_CURRENCY USD Default base for the to_currency Jinja filter.
UNIRATE_CACHE_TIMEOUT unset If set and Flask-Caching is initialised on the app, latest-rate / supported-currency lookups are cached for this many seconds.

Factory pattern

from flask import Flask
from flask_unirate import UniRate

unirate = UniRate()


def create_app() -> Flask:
    app = Flask(__name__)
    app.config.from_pyfile("config.py")
    unirate.init_app(app)
    return app

Inside any view (or template) you can also reach the extension through current_app:

from flask import current_app

current_app.extensions["unirate"].get_rate("USD", "EUR")

…or through the convenience helper:

from flask_unirate import get_unirate

get_unirate().get_rate("USD", "EUR")

Jinja filters

Every filter is registered automatically when you call UniRate(app) / init_app(app):

Filter Example Result
to_currency(target, base=None) `{{ 100 to_currency('EUR') }}`
convert_currency(base, target) `{{ 100 convert_currency('USD', 'JPY') }}`
format_money(currency, decimals=2) `{{ 1234.5 format_money('USD') }}`
to_usd / to_eur / to_gbp `{{ 100 to_eur }}`

Chain them: {{ amount|to_eur|format_money('EUR') }}.

Flask-Caching integration

from flask import Flask
from flask_caching import Cache

from flask_unirate import UniRate

app = Flask(__name__)
app.config.update(
    UNIRATE_API_KEY="...",
    UNIRATE_CACHE_TIMEOUT=300,         # 5 minutes
    CACHE_TYPE="RedisCache",
    CACHE_REDIS_URL="redis://localhost",
)
Cache(app)
UniRate(app)

The extension auto-discovers the Cache instance off app.extensions['cache'] — so all of Flask-Caching's backends (SimpleCache, RedisCache, MemcachedCache, FileSystemCache, …) work with no extra wiring. Failures fall through to a fresh API call rather than raising.

Errors

Errors come from the underlying unirate-api client and propagate unchanged:

HTTP Exception class Meaning
401 unirate.exceptions.AuthenticationError Missing or invalid API key
404 unirate.exceptions.InvalidCurrencyError Currency not found
429 unirate.exceptions.RateLimitError Rate limit exceeded
503 unirate.exceptions.APIError Service unavailable
403 (raised as requests.HTTPError by raise_for_status) Pro plan required (historical, commodities)

Wrap the call site in try / except UnirateError to catch the whole family.

Compatibility

  • Python 3.9 – 3.13
  • Flask ≥ 2.0
  • unirate-api ≥ 1.0
  • (Optional) flask-caching ≥ 2.0

Related

License

MIT

Metadata

Release files for flask-unirate 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for flask-unirate 0.1.0
File Size Uploaded
flask_unirate-0.1.0.tar.gz 12.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for flask-unirate 0.1.0
File Interpreter ABI Platform
flask_unirate-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 21.1 kB

Release files / flask_unirate-0.1.0.tar.gz

Download URL flask_unirate-0.1.0.tar.gz
Size 12.0 kB
Tags Source
SHA-256 checksum
How to use checksums
ea085b4dd6e0a2b7b0b1a6891d9d00a82851de032c7b46524e5cb9c985a7eed7
BLAKE2b-256 checksum
How to use checksums
c6dadaa2fa1a5d793a93ca98841d365427431501f3d4351ed14651a90efdac30
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 9, 2026.

Transparency log

Release files / flask_unirate-0.1.0-py3-none-any.whl

Download URL flask_unirate-0.1.0-py3-none-any.whl
Size 9.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9430622b176008595cf422b7bff09adfb04bdba3894d0cc88ec07a7a07acb79d
BLAKE2b-256 checksum
How to use checksums
076ec46bb8f507f4b2ff4e5df7495334c126fb2349da0e536d29683075273f71
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 9, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page