mdlaw
Blazing-fast unofficial API for MyDramaList, powered by the official MDL Android app API (app-api.mydramalist.com/v1).
Built from reverse-engineering com.mydramalist.app v2.3.18 (Flutter/Dio): the app's request header scheme, auth flow, and endpoint inventory were recovered and live-validated before this wrapper was written.
⚠️ Unofficial. Not affiliated with MyDramaList. For research & personal use. Stop using if an official API ships.
✨ Why mdlaw?
| Web scrapers | mdlaw | |
|---|---|---|
| Data source | HTML scraping (mydramalist.com) |
Official app JSON API |
| Speed | Slow — parses HTML per request | ~1 ms after cache warm-up |
| Fragility | Breaks when site markup changes | Stable — same API the app uses |
| WAF risk | High | Throttled + cached outbound |
The Android app talks to a JSON API behind Cloudflare. mdlaw replicates the exact request headers the app sends, so it gets real structured data — not scraped HTML.
📊 Real-world benchmark (measured, not estimated)
Same machine, same network, live hits (median of 3 runs):
| Test | Latency | Payload |
|---|---|---|
mdlaw GET /api/v1/genres (cached) |
2.9 ms | 35 genres · 1.7 KB JSON |
mdlaw GET /api/v1/titles/1/reviews (cold — hits upstream) |
298 ms | 5 reviews JSON |
Web scraper fetch mydramalist.com/ + parse HTML |
395 ms | 112 KB HTML |
Result: mdlaw (cached) is ~136× faster than a typical web scraper, and even a cold mdlaw hit (real upstream call) beats HTML scraping. On top of that, scrapers return HTML that you still have to parse, while mdlaw hands you clean JSON.
Benchmark: 2026-09-01,
python3+urllibon localhost → mydramalist.com. Your numbers will vary with network, but the order of magnitude is the point.
🤖 AI-agent instructions
AGENTS.md is a purpose-built instruction file for AI coding agents (and new
developers): how to install, verify, extend, and deploy mdlaw without
tripping on the WAF/throttle/cache rules.
- File:
AGENTS.md - It covers: quick start, verification commands, env var reference, how the throttling/cache/auth works, conventions & pitfalls (never remove the throttle, keep tests offline, don't leak credentials), and deploy steps.
Point any agent (or your future self) at AGENTS.md first — it's the fastest
path to a working setup.
🚀 Quickstart
Option 1 — pip (PyPI):
pip install mdlaw
mdlaw # serves http://0.0.0.0:8000 (Swagger at /docs)
mdlaw self # offline self-check
mdlaw genres # one-shot JSON data commands (see below)
mdl-api-keyis not a secret — it's a client nonce the MDL app generates per launch, and the server never validates it (verified live).mdlawgenerates one for you; setMDL_API_KEYonly to pin a value for reproducible requests.
Option 2 — from source:
# 1. Clone & enter
git clone <your-repo-url> mdlaw && cd mdlaw
# 2. Create venv & install
python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
# 3. Run
uvicorn mdlaw:app --port 8000
Verify:
curl http://localhost:8000/api/v1/health
# {"status":"ok","service":"mdlaw"}
curl http://localhost:8000/api/v1/genres | python3 -m json.tool
Interactive docs (Swagger UI): http://localhost:8000/docs
🖥 CLI
mdlaw is also a one-shot CLI — print JSON directly to the terminal (no
server needed). Works after pip install mdlaw:
mdlaw genres # all genres
mdlaw search "crash landing" # search titles (requires credentials)
mdlaw search-people "lee minho" # search people (requires credentials)
mdlaw title 686 # title detail (requires credentials)
mdlaw people 12345 # actor/crew profile
mdlaw watchlist completed # your watchlist (requires credentials)
mdlaw watchlist # full watchlist (requires credentials)
mdlaw me # your profile (requires credentials)
mdlaw leaderboard weekly # period: alltime | weekly | monthly
mdlaw languages # supported languages
mdlaw calendar # upcoming episodes
Output is pretty-printed JSON. Auth-gated commands use the same credentials
as the library: MDL_USERNAME/MDL_PASSWORD env vars, or pass them inline:
MDL_USERNAME=you@example.com MDL_PASSWORD=hunter2 mdlaw search "crash landing"
Errors print a clean error: ... message to stderr with exit code 1 — no
tracebacks.
🐍 Use as a Python package
mdlaw works as a library too — no server needed. All methods are async and
share the same cache, throttle, auth and transport as the HTTP API:
import asyncio
from mdlaw import MDL
async def main():
mdl = MDL() # optional: MDL(transport="curl_cffi")
genres = await mdl.genres() # list of genres
title = await mdl.title(686) # title detail (requires account credentials)
results = await mdl.search("crash landing") # search titles
watch = await mdl.watchlist("completed") # your watchlist (requires credentials)
me = await mdl.me() # your profile (requires credentials)
print(mdl.stats()) # {'backend': 'TTLCache', 'hits': ..., ...}
await mdl.close() # close the HTTP session
asyncio.run(main())
Authenticating as a package
Account endpoints (title(), search(), watchlist(), me(), …) need
credentials. Two ways — same auto-login + auto-refresh behavior:
1. Constructor (recommended for library use):
mdl = MDL(username="you@example.com", password="hunter2")
me = await mdl.me() # logs in automatically on first auth-gated call
2. Env vars (set before import mdlaw, or in your process manager):
MDL_USERNAME=you@example.com MDL_PASSWORD=hunter2 python app.py
⚠️ Env vars are read at import time. Setting
os.environ[...]afterimport mdlawhas no effect — use the constructor instead for dynamic credentials. Both paths share the token cache, so callingme()twice logs in once. 2FA accounts are not supported (428).
Every MDL method maps to a route: genres(), languages(), calendar(),
articles_featured(), lists_featured(), lists_popular(), leaderboard(),
people(), payment_plans(), payment_coins(), title(),
title_reviews(), title_recommendations(), title_comments(),
title_credits(), search(), search_people(), watchlist(), me().
Prefer await mdl.get(path, ttl=..., auth=...) / post(...) for ad-hoc calls
to endpoints that aren't wrapped yet. Account endpoints require
MDL_USERNAME + MDL_PASSWORD env vars, exactly like the HTTP server.
📚 API docs & playground
mdlaw ships with the industry-standard docs out of the box (FastAPI built-ins — no extra setup):
| URL | What it is |
|---|---|
/ |
Redirects to Swagger UI |
/docs |
Swagger UI — interactive playground. "Try it out" on any endpoint, fill params, execute live, see the JSON response + latency. |
/redoc |
ReDoc — clean, readable reference docs |
/openapi.json |
Machine-readable OpenAPI 3.1 spec (for codegen / clients) |
The Swagger playground is pre-configured for quick use: Try it out is open by default, request duration is displayed, and the schemas section is collapsed so endpoints are front and center.
🖥 Deploy locally
Three options, same code.
Option 1 — Run directly (dev)
python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
uvicorn mdlaw:app --host 0.0.0.0 --port 8000
# → http://localhost:8000/docs
Option 2 — Docker
docker build -t mdlaw .
docker run -p 8000:8000 mdlaw
Option 3 — Docker Compose (production-ish)
# docker-compose.yml
services:
mdlaw:
build: .
ports:
- "8000:8000"
environment:
- MDL_USERNAME=${MDL_USERNAME} # optional
- MDL_PASSWORD=${MDL_PASSWORD} # optional
restart: unless-stopped
docker compose up -d
📡 Endpoints
All responses are the raw upstream JSON (fastest path, zero transformation).
| Method | Route | Upstream | Cache TTL | Auth |
|---|---|---|---|---|
| GET | /api/v1/health |
— | — | — |
| GET | /api/v1/dashboard |
— (local) | — | — |
| GET | /api/v1/status |
— (alias dashboard) | — | — |
| GET | /api/v1/auth/status |
— (local) | — | — |
| GET | /api/v1/cache/stats |
— (local) | — | — |
| POST | /api/v1/auth/login |
POST /auth/login (force re-login) |
— | env |
| POST | /api/v1/auth/refresh |
POST /auth/refresh (force refresh) |
— | env |
| GET | /api/v1/genres |
GET /genres |
1h | — |
| GET | /api/v1/languages |
GET /languages/supported?v=2 |
1h | — |
| GET | /api/v1/titles/{id} |
GET /titles/{id}?expand=1 |
5m | ✅ |
| GET | /api/v1/titles/{id}/reviews |
GET /titles/{id}/reviews |
5m | — |
| GET | /api/v1/titles/{id}/comments |
GET /titles/{id}/comments |
5m | — |
| GET | /api/v1/titles/{id}/credits |
GET /titles/{id}/credits |
5m | — |
| GET | /api/v1/titles/{id}/recommendations |
GET /titles/{id}/recommendations |
10m | ✅ |
| POST | /api/v1/search?q={q} |
POST /search (body {"q", "synopsis"}) |
5m | ✅ |
| POST | /api/v1/search/people?q={q} |
POST /search/people (body {"q"}) |
5m | ✅ |
| GET | /api/v1/watchlist |
GET /sync/mylist/watchlist |
1m | ✅ |
| GET | /api/v1/watchlist/{status} |
GET /sync/mylist/{status} |
1m | ✅ |
| GET | /api/v1/me |
GET /users/me |
1m | ✅ |
| GET | /api/v1/calendar |
POST /calendar/episodes |
1h | — |
| GET | /api/v1/articles/featured?page={page} |
GET /articles/featured |
10m | — |
| GET | /api/v1/lists/featured?limit={limit} |
GET /lists/featured |
10m | — |
| GET | /api/v1/lists/popular?limit={limit} |
GET /lists/popular_voting_lists |
10m | — |
| GET | /api/v1/people/leaderboard?period={alltime|weekly|monthly} |
GET /people/leaderboard |
10m | — |
| GET | /api/v1/people/{id} |
GET /people/{id} |
24h | — |
| GET | /api/v1/payment/plans |
GET /payment/plans |
1h | — |
| GET | /api/v1/payment/coins |
GET /payment/coins |
1h | — |
Auth ✅ = needs
MDL_USERNAME+MDL_PASSWORD(see 🔐 Account). Without them these return400with a clear message.
Example responses (captured live)
GET /api/v1/genres → 200 · Cache-Control: public, max-age=3600
[
{ "id": 1, "name": "Action", "slug": "action" },
{ "id": 5, "name": "Adventure", "slug": "adventure" },
{ "id": 13, "name": "Business", "slug": "business" }
]
GET /api/v1/people/6997 → 200
{
"id": 6997,
"name": "Shin Myung Jin",
"first_name": "Myung Jin",
"family_name": "Shin",
"biography": "A South Korean actor. Starred in the movie December (2014).",
"permalink": "https://mydramalist.com/people/6997-shin-myung-jin",
"nationality": "South Korean",
"ranked": 99999,
"images": {
"thumb": "https://i.mydramalist.com/QDldg_5t.jpg",
"medium": "https://i.mydramalist.com/QDldg_5m.jpg",
"poster": "https://i.mydramalist.com/QDldg_5c.jpg"
}
}
GET /api/v1/titles/1/reviews → 200
[
{
"id": 3561,
"ratings": { "story": 10, "acting": 10, "music": 10, "rewatch": 10, "overall": 10 },
"headline": "As I watched through the whole...",
"upvotes": 0,
"total_votes": 0,
"spoiler": false,
"lang_iso": "en"
}
]
GET /api/v1/calendar → 200 — airing calendar
{
"items": [
{
"id": 4349807, "rid": 695673, "episode_number": 19,
"released_at": 1788141600, "duration": 19,
"permalink": "/695673-wu-zuo-nu-fu-ma/episode/19"
}
],
"relationships": []
}
Errors
| Case | Status | Body |
|---|---|---|
| Upstream 4xx (e.g. auth-gated) | 400/401/403 |
{"error": true, "code": <status>, "detail": <upstream body>} |
| Upstream timeout | 504 |
{"error": true, "code": 504, "detail": "upstream timeout"} |
| Upstream unreachable | 502 |
{"error": true, "code": 502, "detail": "upstream error: ..."} |
| Invalid query param | 400 |
{"error": true, "code": 400, "detail": "period must be alltime|weekly|monthly"} |
| Bad path / type | 404 / 422 |
FastAPI default |
⚡ Performance
- Async + connection pooling — one
httpx.AsyncClientreuses TCP/TLS connections. - TTL cache in-memory — repeat requests never hit upstream. Measured:
- Cold (first hit): ~0.5 s
- Warm (cached): ~1 ms
Cache-Controlheader on every response → CDN/proxy caching works too.- Outbound throttle (2 concurrent, 0.5 s min interval) — keeps us under MDL's WAF rate limit.
Note: the in-memory cache is single-process. Swap to a SQL backend or Redis if you run more than one instance.
💾 Response cache (DB)
By default mdlaw caches responses in memory (TTL). For persistence across restarts / multiple instances, switch to a SQL database:
| Env | Value | Notes |
|---|---|---|
MDL_CACHE_BACKEND |
memory (default) · sqlite · mysql · postgres |
memory needs no setup |
MDL_CACHE_DB_URL |
e.g. sqlite:///mdlaw_cache.db · mysql://user:pass@host/db · postgresql://user:pass@host/db |
required when backend ≠ memory |
# SQLite (zero setup — stdlib driver)
export MDL_CACHE_BACKEND=sqlite
export MDL_CACHE_DB_URL=sqlite:///mdlaw_cache.db
uvicorn mdlaw:app --port 8000
# MySQL
pip install pymysql
export MDL_CACHE_BACKEND=mysql MDL_CACHE_DB_URL=mysql://user:pass@localhost:3306/mdlaw
uvicorn mdlaw:app --port 8000
# PostgreSQL
pip install "psycopg[binary]"
export MDL_CACHE_BACKEND=postgres MDL_CACHE_DB_URL=postgresql://user:pass@localhost:5432/mdlaw
uvicorn mdlaw:app --port 8000
The cache table (mdlaw_cache) stores each response as JSON + a sha256 hash.
🔄 How response changes are detected
MDL doesn't push changes — so mdlaw uses the standard TTL + hash comparison pattern:
- Response is stored with its sha256 hash.
- When the TTL expires, the upstream is re-fetched.
- The new hash is compared to the stored one:
- Different → the row is updated and flagged
changed=1(withupdated_at). - Same → the row is refreshed (TTL extended),
changed=0.
- Different → the row is updated and flagged
- So you always know when a response actually changed — not just when it was re-fetched.
Inspect live:
curl http://localhost:8000/api/v1/cache/stats
# {"backend": "sqlite", "hits": 1, "misses": 1, "hit_rate": 0.5, "entries": 1}
Note: change detection is only meaningful for a persistent backend (sqlite/mysql/postgres). In-memory cache resets on restart, so nothing to compare against.
⚙️ Configuration requirements
Everything mdlaw needs is set via environment variables. Here's the full picture at a glance:
| Variable | Required? | What it does | Default |
|---|---|---|---|
MDL_API_KEY |
No | Pin a fixed mdl-api-key (client nonce; optional, no security meaning) |
generated nonce |
MDL_TRANSPORT |
No | httpx (plain TLS) or curl_cffi (TLS impersonation, passes Cloudflare challenge) |
httpx |
MDL_USERNAME |
No | Enables auth-gated endpoints (title detail, search, watchlist, /me) |
disabled |
MDL_PASSWORD |
No | Password for the account above (paired with MDL_USERNAME) |
disabled |
MDL_CACHE_BACKEND |
No | memory · sqlite · mysql · postgres |
memory |
MDL_CACHE_DB_URL |
Only if backend ≠ memory | DSN, e.g. sqlite:///mdlaw_cache.db |
— |
🔐 API key (optional)
mdl-api-key looks like a secret but isn't one: it's a 20-character client
nonce that the MDL Android app generates on every launch
(Utils.getRandomString() in main.dart), and the server never validates
it — verified live: requests with no header, with the "real" key, and with a
random value all return 200 OK. The actual access gate is Cloudflare bot
protection (TLS/JA3 fingerprint), not this header.
So there is nothing to configure: mdlaw generates a valid nonce for you
and just works. Set MDL_API_KEY only if you want reproducible requests.
uvicorn mdlaw:app --port 8000 # no env needed — works out of the box
🔀 Transport (optional)
From most residential IPs, plain httpx with the app's header scheme passes.
If Cloudflare serves you a 403 "Just a moment..." challenge (common on
datacenter/flagged IPs), switch to the curl_cffi transport, which
impersonates a real browser/mobile TLS fingerprint:
pip install curl_cffi
MDL_TRANSPORT=curl_cffi uvicorn mdlaw:app --port 8000
👤 Account (optional)
Set both to unlock auth-gated endpoints:
export MDL_USERNAME=your_username
export MDL_PASSWORD=your_password
uvicorn mdlaw:app --port 8000
Without them, auth-gated endpoints return a clear 400 ("requires MDL_USERNAME and MDL_PASSWORD env vars").
💾 Cache (optional)
# default (in-memory) — no setup
uvicorn mdlaw:app --port 8000
# persistent (SQLite, zero dependencies)
export MDL_CACHE_BACKEND=sqlite MDL_CACHE_DB_URL=sqlite:///mdlaw_cache.db
uvicorn mdlaw:app --port 8000
🔐 Account (auth) — how it works
POST /auth/login?device_id=<uuid>with{username, password: md5(password)}→{token, refresh_token, user}.- Token is a JWT;
expis decoded to know when to refresh. - On
401(orinvalid_grant),POST /auth/refreshis called; if that fails, it re-logs in.
Check status:
curl http://localhost:8000/api/v1/auth/status
# {"configured": true, "logged_in": true, "user": {...}, "expires_at": ..., "refreshes": 0, ...}
⚠️ 2FA is not supported. If your account has 2FA enabled, either disable it or use an app password. The wrapper will return
428("2FA required") instead of hanging.
🚢 Deploy
All options below. This is the public build: mdlaw works with zero
configuration — the API key is an optional client nonce, so there is no
required env var.
| Env | Public build |
|---|---|
MDL_API_KEY |
optional (pin a nonce for reproducible requests) |
MDL_TRANSPORT |
optional (curl_cffi for Cloudflare-challenged IPs) |
MDL_USERNAME + MDL_PASSWORD |
optional (auth-gated endpoints) |
MDL_CACHE_BACKEND + MDL_CACHE_DB_URL |
optional (persistent cache) |
Option A — Fly.io (recommended)
# 1. One-time: create the app (reads fly.toml)
fly launch --no-deploy
# 2. Set secrets (all optional)
fly secrets set MDL_USERNAME=<your-user> MDL_PASSWORD=<your-pass> # optional
fly secrets set MDL_CACHE_BACKEND=sqlite MDL_CACHE_DB_URL=sqlite:////data/mdlaw_cache.db # optional
# 3. Deploy
fly deploy
fly.toml is preconfigured: port 8000, region sin, 1 machine always
running (no cold starts), HTTPS forced.
Persistent cache on Fly.io: the default in-memory cache resets on every deploy/restart. Use the SQLite backend with a volume if you want it to survive restarts:
fly volumes create mdlaw_data --size 1 fly secrets set MDL_CACHE_BACKEND=sqlite MDL_CACHE_DB_URL=sqlite:////data/mdlaw_cache.db # then add to fly.toml: # [mounts] # source = "mdlaw_data" # destination = "/data" fly deploy
Option B — Vercel (serverless)
Works, but know the trade-offs:
npx vercel
# when prompted, set env vars in the Vercel dashboard:
# Settings → Environment Variables → add MDL_USERNAME, MDL_PASSWORD,
# MDL_CACHE_BACKEND, MDL_CACHE_DB_URL (all optional; MDL_API_KEY not needed)
Two files are already included (api/index.py + vercel.json). Caveats:
- Cold starts: Python serverless functions boot per request — first hit after idle is slow (~2–5 s).
- Cache is per-instance & ephemeral: the TTL cache resets between cold starts, so MDL's WAF sees more upstream traffic than on a persistent host. Still throttled (2 concurrent, 0.5 s interval), so it holds up, but it's not "blazing" on first hits.
- SQL cache not recommended on Vercel: serverless has no persistent filesystem — use an external MySQL/Postgres if you want persistence.
- Fine for a demo / low-traffic personal API. For consistent speed, use Fly.io (persistent instance, warm cache).
Option C — Docker
docker build -t mdlaw .
# all env vars optional — no API key needed
docker run -p 8000:8000 \
-e MDL_USERNAME=<your-user> -e MDL_PASSWORD=<your-pass> \
-e MDL_CACHE_BACKEND=sqlite -e MDL_CACHE_DB_URL=sqlite:////data/mdlaw_cache.db \
-v mdlaw_data:/data \
mdlaw
Option D — Docker Compose (production)
# docker-compose.yml
services:
mdlaw:
build: .
ports:
- "8000:8000"
environment:
MDL_USERNAME: ${MDL_USERNAME} # optional
MDL_PASSWORD: ${MDL_PASSWORD} # optional
MDL_CACHE_BACKEND: ${MDL_CACHE_BACKEND:-memory}
MDL_CACHE_DB_URL: ${MDL_CACHE_DB_URL:-}
volumes:
- mdlaw_data:/data
restart: unless-stopped
volumes:
mdlaw_data:
# .env (same folder, gitignored)
MDL_USERNAME=your-user
MDL_PASSWORD=your-pass
MDL_CACHE_BACKEND=sqlite
MDL_CACHE_DB_URL=sqlite:////data/mdlaw_cache.db
docker compose up -d
Option E — VPS / systemd
Any host that can run Python 3.12.
# /etc/systemd/system/mdlaw.service
[Unit]
Description=mdlaw API
After=network.target
[Service]
WorkingDirectory=/opt/mdlaw
ExecStart=/opt/mdlaw/.venv/bin/uvicorn mdlaw:app --host 0.0.0.0 --port 8000
EnvironmentFile=/opt/mdlaw/.env
Restart=always
User=mdlaw
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now mdlaw
# logs: journalctl -u mdlaw -f
🧪 Tests
Offline — no network needed:
python -m pytest tests/ -q
# 8 passed
Covers: key decode, md5 formula, header scheme, TTL cache expiry, SQL cache change detection, route count, auth-offline, and leaderboard validation.
📦 Project layout
mdlaw/
├── mdlaw.py # the whole API: config, client, cache (memory/SQL), auth, 27 routes
├── pyproject.toml # PyPI packaging (pip install mdlaw → console script)
├── LICENSE # MIT
├── AGENTS.md # AI-agent / dev instructions (install, verify, extend, pitfalls)
├── CHANGELOG.md # version history (Keep a Changelog convention)
├── api/index.py # Vercel serverless entrypoint
├── vercel.json # Vercel config (rewrites, function limits)
├── requirements.txt # fastapi, uvicorn[standard], httpx
├── Dockerfile # python:3.12-slim, non-root
├── docker-compose.yml # one-command production deploy (with healthcheck)
├── fly.toml # Fly.io config (port 8000, region sin, always-on)
├── pytest.ini # pythonpath for tests
├── .env.example # API key + account + cache backend placeholders
├── tests/
│ └── test_mdlaw.py # 8 offline checks
└── README.md
⚠️ Known limits
- 2FA accounts are not supported by the auto-login (returns
428). Disable 2FA or use an app password. - Anonymous guest mode does not exist — MDL's Firebase project has anonymous auth disabled. Account features need
MDL_USERNAME/MDL_PASSWORD. - One account per instance — the wrapper holds a single token for all requests.
- Rate limits: the MDL WAF soft-blocks bursts.
mdlawthrottles outbound, but don't point heavy crawlers at it. - Version drift: if MDL updates the app's header scheme / key, endpoints may start returning 403. Update
mdlaw.pyconstants (single place).
🛠 Development
# self-check (offline)
python mdlaw.py self
# run dev server with auto-reload
uvicorn mdlaw:app --reload --port 8000
📜 License & disclaimer
Unofficial, for research/education. Not affiliated with MyDramaList. All data © MyDramaList. Use at your own risk; stop if an official API ships.
Metadata
Release files for mdlaw 1.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mdlaw-1.3.0.tar.gz | 24.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mdlaw-1.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 46.1 kB
Release files / mdlaw-1.3.0.tar.gz
| Download URL | mdlaw-1.3.0.tar.gz |
|---|---|
| Size | 24.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
503486fab921f7a2e81b165203a0349a49c8ad4647e0bcd3c913fc25a389fe9c
|
|
BLAKE2b-256 checksum How to use checksums |
38881bd69535df6e338a118c0456f9c6efe6db44d4e034446cf7ead49cb6f650
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.5
|
Release files / mdlaw-1.3.0-py3-none-any.whl
| Download URL | mdlaw-1.3.0-py3-none-any.whl |
|---|---|
| Size | 22.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bf12b2177371cbf8a615f035d5e21194caed3af9ada71db9c341a1e1fd523f54
|
|
BLAKE2b-256 checksum How to use checksums |
c92638fac7f6bee69cff519d0d2de6ade37500b03f747c0ad6a2d2504f37bfe8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.5
|