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.shthat bumps the version, regenerates the changelog, and tags.
What's inside
- HTTP client: async
httpx-based client targetinghttps://hantaosint.com/api/v1, with built-in rate limiter integration. - Rate limiter: token-bucket
RateLimiter(60 req/min, 120 burst by default). RaisesRateLimiterErrorwith aretryAfterMsvalue when the bucket is empty. - Cache:
CachedFetcherwraps the public-JSON fetch with a configurable TTL (default 5 min). Callinvalidate()to bust it early. - Types: frozen dataclasses for the full API surface —
PublicJsonResponse,Country,Outbreak,MapMarker,Brief,Stats,Meta, andGenericRequestError. - 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/), apy.typedmarker, and a thin__init__.pybarrel that re-exports the public API. - Type checking: mypy in
strictmode, configured inpyproject.toml. - Linting & formatting: ruff for both lint and format (tab indentation, 88-col,
E/F/I/UP/ANN/B/SIMrule sets, with type-hint enforcement relaxed for tests). - Testing: the standard library's
unittestrunner. Test modules live undertests/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
- 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]"
- 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 thantest_*.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 --checkon staged Python files andmypyon 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5210ed7a801854d313b99d5189656c09f4168542e4f62d1cbf733d1e5ad90856
|
|
| MD5 |
c579e8b6df692d5d7d0a7f4c52805c84
|
|
| BLAKE2b-256 |
d20c7345fb30c190067766ba6874f5e123feef23bf430df1e02d2ab944ba44d8
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
75c5ed3c54960953050f17a784c7b1c18880980ef5b811783d11c52ad6c76fbe
|
|
| MD5 |
3a9b410a284ec6afd8a95c4221a455c4
|
|
| BLAKE2b-256 |
7b73ed7d89a3a12b4da6fc3181792c5e953d396af331d4b17822b8a46d4e6d3a
|