Resolve the documentation URL for any Python module or PyPI distribution name.
Project description
pymanual
Given a Python module name (import name) or a distribution name (the string you'd type in pip install …), deterministically return the best available documentation URL — or a status token explaining why one isn't available.
Install
End users:
pipx install pymanual
# or
uv tool install pymanual
This puts pymanual on your PATH.
Developing on the project itself instead:
git clone https://github.com/gkarpo/pymanual && cd pymanual
uv sync
CLI
pymanual <module> [--no-network] [--no-cache]
pymanual --clear-cache
Exit code is 0 when a URL is returned, 1 when a status token is returned.
$ pymanual json
https://docs.python.org/3/library/json.html
$ pymanual email.mime.text
https://docs.python.org/3/library/email.html
$ pymanual pytest
https://docs.pytest.org/en/latest/
$ pymanual pytest-cov # distribution name with a dash
https://pytest-cov.readthedocs.io/
$ pymanual python-dateutil # not installed; PyPI lookup
https://dateutil.readthedocs.io/en/stable/
$ pymanual definitely_no_such_xyz
module_not_found
If you're working inside the project source, prefix every command with uv run (e.g. uv run pymanual json).
Flags
--no-network— skip the PyPI HTTP fallback (step 4.ii below for installed third-party modules, and the second half of step 5 for the distribution-name fallback). Resolution stays fully offline.--no-cache— bypass the local cache for that one call (no read, no write).--clear-cache— delete the cache file and exit.
Library
from pymanual import (
resolve_doc_url,
STATUS_NOT_FOUND,
STATUS_UNRESOLVABLE_PATH,
STATUS_LOCAL,
)
resolve_doc_url("json") # 'https://docs.python.org/3/library/json.html'
resolve_doc_url("pytest") # URL from installed distribution metadata
resolve_doc_url("pytest-cov") # distribution-name fallback
resolve_doc_url("python-dateutil") # not installed → PyPI lookup
resolve_doc_url("nope_xyz") # 'module_not_found'
# Same options as the CLI flags:
resolve_doc_url("pytest", network=False) # offline-only
resolve_doc_url("json", use_cache=False) # bypass the on-disk cache
Resolution strategy
Strict order — the first step that yields a result wins.
- Import the module with
importlib.import_module.- On success → continue at step 2.
- On
ImportError/ValueError→ try the distribution-name fallback (step 5).
- Get the file path with
inspect.getfile. If unavailable (e.g. namespace packages with no__file__), returnunresolvable_module_path. Builtins (sys,builtins, …) are short-circuited as stdlib before this step. - Classify by file path only (not
sys.path):- inside
sysconfig.get_paths()["stdlib"]→ stdlib - inside
site-packages/dist-packages/ a venv directory → third_party - otherwise → local
- inside
- Resolve URL by classification:
- stdlib →
https://docs.python.org/3/library/<top-level>.html - third_party:
importlib.metadata.metadata(...)→ preferProject-URLkeys matchingdocumentation/docs/doc, thenhomepage, thenHome-page- PyPI JSON (
https://pypi.org/pypi/<name>/json) — same key precedence; skipped whennetwork=False - Heuristic last resort:
https://pypi.org/project/<name>/
- local →
local_module_no_external_docs
- stdlib →
- Distribution-name fallback (when
import_modulefound nothing):- Try
importlib.metadata.metadata(<input>)— catches cases likepytest-cov,PyYAML,scikit-learnwhose import names don't match their distribution names. If installed → return URL from its metadata (falling back tohttps://pypi.org/project/<input>/). - Else, if
network=True, query PyPI directly for<input>. If the package exists there → return its documentation URL. - Otherwise →
module_not_found.
- Try
Import-name vs distribution-name mismatches (e.g. yaml → PyYAML) from step 4 are handled via importlib.metadata.packages_distributions().
Local cache
Successful URL resolutions are cached at $XDG_CACHE_HOME/pymanual/cache.json (defaults to ~/.cache/pymanual/cache.json). Subsequent lookups for the same input string return instantly without hitting importlib.import_module, importlib.metadata, or PyPI.
- Status tokens (
module_not_found, etc.) are not cached, so installing a previously-missing module just works on the next call. - Cache key is the verbatim input string —
pytest-covandpytest_covare independent entries. - LRU-bounded at 100 entries; the oldest entry is evicted when the cap is exceeded.
- No TTL; entries live until eviction, until you run
pymanual --clear-cache, or until you delete the file. - Override location for tests/sandboxing via the
PYMANUAL_CACHE_DIRenv var.
Output contract
A single string — either a URL or one of:
module_not_foundunresolvable_module_pathlocal_module_no_external_docs
Development
uv run pytest -q # run tests
uv run pytest --cov=pymanual # with coverage
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 pymanual-1.0.0.tar.gz.
File metadata
- Download URL: pymanual-1.0.0.tar.gz
- Upload date:
- Size: 9.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
425a659e6ed854dd270747cc076267b62058cf440933f02cdbd6110670167060
|
|
| MD5 |
257c5375962d869e7340acd6c750b8c5
|
|
| BLAKE2b-256 |
96fb99c51de4ef7cea5346d4247643ec4f5cca8192e94171c021f3cd385ac603
|
File details
Details for the file pymanual-1.0.0-py3-none-any.whl.
File metadata
- Download URL: pymanual-1.0.0-py3-none-any.whl
- Upload date:
- Size: 12.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
82b1bde0feb83b316cba3e502999ecca370b0201b12b5a9bc5ff37f0911971c4
|
|
| MD5 |
a6790363f3b7ed919ea92fef231079cc
|
|
| BLAKE2b-256 |
fe602bf22b2baf0b8091fe22c81f8902bd0e6105b44d0b8f789174ea1d7dc451
|