Skip to main content

A Python library for fetching hanta virus info from hantavirus osint.

Project description

hantaviruspy

A typed async Python library for fetching and querying hantavirus outbreak data from the hantaosint.com API.

Publishing is handled manually (custom settings), so there's no publish workflow here, just a release.sh that bumps the version, regenerates the changelog, and tags.

What's inside

  • HTTP client: async httpx-based client targeting https://hantaosint.com/api/v1, with built-in rate limiter integration.
  • Rate limiter: token-bucket RateLimiter (60 req/min, 120 burst by default). Raises RateLimiterError with a retryAfterMs value when the bucket is empty.
  • Cache: CachedFetcher wraps the public-JSON fetch with a configurable TTL (default 5 min). Call invalidate() to bust it early.
  • Types: frozen dataclasses for the full API surface — PublicJsonResponse, Country, Outbreak, MapMarker, Brief, Stats, Meta, and GenericRequestError.
  • Service helpers: filter/search functions for countries and outbreaks (by status, trend, strain, origin, ISO code, slug, and name).
  • Packaging: hatchling build backend, a src-less layout (hantaviruspy/), a py.typed marker, and a thin __init__.py barrel that re-exports the public API.
  • Type checking: mypy in strict mode, configured in pyproject.toml.
  • Linting & formatting: ruff for both lint and format (tab indentation, 88-col, E/F/I/UP/ANN/B/SIM rule sets, with type-hint enforcement relaxed for tests).
  • Testing: the standard library's unittest runner. Test modules live under tests/ and are named after the area they cover.
  • Conventional Commits: a commit-msg hook validates the Conventional Commits format with a regex (no Node toolchain), and git-cliff turns that history into a CHANGELOG.md.
  • Git hooks: lefthook runs ruff + mypy on staged files before commit and lints the commit message.
  • CI: .github/workflows/ runs lint + type-check on one job and the test suite across Linux/macOS/Windows on Python 3.12 & 3.13.
  • Editor config: .vscode/ recommends the Ruff + Python + mypy extensions and wires up format-on-save and import sorting via Ruff.
  • Dependabot: daily pip + GitHub Actions update PRs.

Getting started

  1. Create a virtual environment and install the dev dependencies:
    python -m venv .venv
    source .venv/bin/activate        # Windows: .venv\Scripts\activate
    pip install -e ".[dev]"
    
  2. Install the git hooks: lefthook install.

Usage

import asyncio
from hantaviruspy.cache import create_cached_fetcher
from hantaviruspy.service.filterCountries import getCountriesByStatus, searchCountriesByName
from hantaviruspy.service.filterOutbreak import getOutbreaksByStatus

fetcher = create_cached_fetcher(ttl_s=300)

async def main() -> None:
    data = await fetcher()

    active = getCountriesByStatus(data, "active")
    print(f"{len(active)} countries with active cases")

    results = searchCountriesByName(data, "germany")
    print(results)

    outbreaks = getOutbreaksByStatus(data, "active")
    print(outbreaks)

asyncio.run(main())

API reference

hanta_virus_client(endpoint, path=None, request_type="GET")

Low-level async client. Consumes one rate-limiter token per call and raises GenericRequestError on any failure.

RateLimiter(max_per_minute=60, burst=120)

Token-bucket rate limiter. The module-level rateLimiter instance is used automatically by the client.

Method / property Description
consume() Deduct one token; raises RateLimiterError if empty
canRequest() True if at least one token is available
retryAfterMs Milliseconds until the next token is available

CachedFetcher(ttl_s=300)

Callable that returns a cached PublicJsonResponse, re-fetching when the TTL expires.

Method Description
await fetcher() Return cached data (or fetch if stale)
fetcher.invalidate() Clear the cache immediately

Use create_cached_fetcher(ttl_s=...) to construct one with a custom TTL.

Service helpers — countries (hantaviruspy.service.filterCountries)

Function Description
getCountryByCode(data, code) Look up a country by its 2-letter code
getCountryByIso(data, iso) Look up a country by ISO A3 code
getCountriesByStatus(data, status) Filter by status ("active", "suspected", "lockdown", "historical")
getCountriesByTrend(data, trend) Filter by trend ("up", "down", "flat")
searchCountriesByName(data, name) Case-insensitive substring search on country name

Service helpers — outbreaks (hantaviruspy.service.filterOutbreak)

Function Description
getOutbreakBySlug(data, slug) Look up an outbreak by its slug
getOutbreaksByStatus(data, status) Filter by status ("active", "resolved")
getOutbreaksByStrain(data, strain) Case-insensitive substring match on strain
searchOutbreaksByName(data, name) Case-insensitive substring search on outbreak name
getOutbreaksByOrigin(data, origin) Case-insensitive substring match on origin

Types (hantaviruspy._types)

Type Description
PublicJsonResponse Full API response (meta, stats, countries, map_markers, briefs, outbreaks)
Country Per-country data (code, iso_a3, status, cases, trend, …)
Outbreak Outbreak record (slug, strain, origin, cases, deaths, …)
MapMarker Geographic marker (lat/lng, city, category, strain, …)
Brief News brief (tag, source, title, url, …)
Meta Response metadata (tier, delay, generated_at, license, docs)
Stats Global aggregate counts
GenericRequestError Raised on any API or HTTP failure

Commands

Command What it does
python -m unittest discover -s tests -p "*.py" Run the test suite
python -m unittest tests.cache Run a single test module
mypy Type-check the package (strict)
ruff check . Lint
ruff check . --fix Lint and auto-fix what it can
ruff format . Format with tabs
git-cliff -o CHANGELOG.md Regenerate the changelog from commit history
./release.sh v[X.Y.Z] Bump version, regenerate changelog, commit, tag

Test files are named after the area they cover (e.g. cache.py) rather than test_*.py, so discovery needs the explicit -p "*.py" pattern.

Conventional commits & git hooks

Commits follow Conventional Commits (feat:, fix:, chore:, etc.). After installing the dev dependencies, run lefthook install once to wire up the hooks:

  • pre-commit: runs ruff check, ruff format --check on staged Python files and mypy on the package.
  • commit-msg: validates the message format with a regex (the rule lives in lefthook.yml; no Node/commitlint dependency).

Because the history is conventional, git-cliff can regenerate CHANGELOG.md automatically.

Project layout

.
├── hantaviruspy/               # implementation
│   ├── __init__.py             # public barrel — re-exports the full API
│   ├── _types.py               # dataclasses and literal types
│   ├── client.py               # async httpx client
│   ├── rateLimiter.py          # token-bucket rate limiter
│   ├── cache.py                # TTL-based cached fetcher
│   ├── py.typed                # ships type information to consumers
│   └── service/
│       ├── getPublicJsonData.py
│       ├── filterCountries.py
│       └── filterOutbreak.py
├── tests/                      # unittest modules, run via discovery
│   ├── __init__.py
│   ├── cache.py
│   ├── filterCountries.py
│   ├── filterOutbreaks.py
│   ├── getPublicJsonData.py
│   └── rateLimit.py
├── pyproject.toml              # packaging + mypy + ruff config
├── cliff.toml                  # git-cliff changelog config
├── lefthook.yml                # git hooks (ruff + mypy + commit-msg check)
├── release.sh                  # version bump + changelog + annotated tag
├── LICENSE
├── .vscode/                    # recommended extensions + editor settings
└── .github/
    ├── ISSUE_TEMPLATE/         # bug report + feature request
    ├── workflows/              # lint.yml + test.yml
    └── dependabot.yml

Releasing

./release.sh v[X.Y.Z] bumps the version in pyproject.toml, regenerates CHANGELOG.md, commits the result as chore(release): prepare for v[X.Y.Z], and creates an annotated tag whose message is the changelog for the new version. Then push with git push && git push --tags.

Publishing is intentionally left manual. Build with python -m build (or hatch build) and upload with whatever registry/auth settings you use.

License

ISC

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

hantaviruspy-0.1.1.tar.gz (13.5 kB view details)

Uploaded Source

Built Distribution

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

hantaviruspy-0.1.1-py3-none-any.whl (10.4 kB view details)

Uploaded Python 3

File details

Details for the file hantaviruspy-0.1.1.tar.gz.

File metadata

  • Download URL: hantaviruspy-0.1.1.tar.gz
  • Upload date:
  • Size: 13.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for hantaviruspy-0.1.1.tar.gz
Algorithm Hash digest
SHA256 5210ed7a801854d313b99d5189656c09f4168542e4f62d1cbf733d1e5ad90856
MD5 c579e8b6df692d5d7d0a7f4c52805c84
BLAKE2b-256 d20c7345fb30c190067766ba6874f5e123feef23bf430df1e02d2ab944ba44d8

See more details on using hashes here.

File details

Details for the file hantaviruspy-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: hantaviruspy-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 10.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for hantaviruspy-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 75c5ed3c54960953050f17a784c7b1c18880980ef5b811783d11c52ad6c76fbe
MD5 3a9b410a284ec6afd8a95c4221a455c4
BLAKE2b-256 7b73ed7d89a3a12b4da6fc3181792c5e953d396af331d4b17822b8a46d4e6d3a

See more details on using hashes here.

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