Modules#
An overview of the packages that make up peta.
The API reference below is generated automatically from the source docstrings.
Core (peta.core)#
Core data models for peta.
- peta.core.models.VULNERABILITY_FIELD = 'result.vulnerabilities'#
The
resultpath advisory evidence is written to.Declared here rather than in
peta.core.providersso a package can be asked whether its advisory lookup failed without importing the provider layer.
- class peta.core.models.DependencyNode(name, version_spec, installed_version=None, children=None, circular=None, source=None, retrieved_at=None, freshness=None, resolution_failure=None, *, selected_version=None, state='satisfied', conflict_reason=None)[source]#
Bases:
objectA node in a package’s recursive dependency tree.
Initialize a DependencyNode.
Explicit
statetakes precedence over the deprecatedcircularconstructor argument.- Parameters:
name (str)
version_spec (str)
installed_version (str | None)
children (list[DependencyNode] | None)
circular (bool | None)
source (str | None)
retrieved_at (str | None)
freshness (Freshness | None)
resolution_failure (DependencyResolutionFailure | None)
selected_version (str | None)
state (Literal['satisfied', 'conflicting', 'unresolved', 'circular', 'depth_limited'])
conflict_reason (Literal['version', 'target'] | None)
- class peta.core.models.DependencyResolutionFailure(source, state, reason, retrieved_at, freshness=None)[source]#
Bases:
objectA failed or unavailable transitive dependency lookup.
- Parameters:
- retrieved_at: str | None#
When the source answered, or
Noneif it was never contacted.Required but nullable, so a failure always states whether a retrieval happened at all rather than leaving it to a forgotten default. An offline miss deliberately makes no request, and claiming a retrieval time for one would make the provenance misleading.
- class peta.core.models.EnrichmentFailure(source, reason, field)[source]#
Bases:
objectA non-fatal failure from an optional metadata source.
- class peta.core.models.PackageInfo(name, version, source, summary=None, author=None, author_email=None, maintainer=None, license=None, python_requires=None, homepage=None, project_urls=<factory>, dependencies=<factory>, classifiers=<factory>, keywords=<factory>, files=None, vulnerabilities=<factory>, download_count=None, dependent_count=None, license_source=None, enrichment_failures=<factory>, enrichment_conflicts=<factory>, provider_warnings=<factory>, retrieved_at=None, freshness=None, enrichment_sources=<factory>)[source]#
Bases:
objectPackage metadata from a local installation or PyPI.
- Parameters:
name (str)
version (str)
source (str)
summary (str | None)
author (str | None)
author_email (str | None)
maintainer (str | None)
license (str | None)
python_requires (str | None)
homepage (str | None)
vulnerabilities (list[Vulnerability])
download_count (int | None)
dependent_count (int | None)
license_source (Literal['expression', 'legacy'] | None)
enrichment_failures (list[EnrichmentFailure])
enrichment_conflicts (list[ProviderConflict])
provider_warnings (list[ProviderWarning])
retrieved_at (str | None)
freshness (Freshness | None)
enrichment_sources (list[SourceRecord])
- class peta.core.models.ProviderConflict(field, kept, discarded)[source]#
Bases:
objectTwo providers offered different evidence for the same field.
Both sources are named so the disagreement stays visible;
keptrecords which one the deterministic merge order selected.
- class peta.core.models.ProviderWarning(source, code, message)[source]#
Bases:
objectAn advisory message a provider returned alongside its evidence.
- class peta.core.models.Vulnerability(id, aliases, summary, fixed_in, severity=None)[source]#
Bases:
objectA known security vulnerability for a package.
Typed models for peta’s versioned output contract.
- peta.core.output.SOURCE_STATES: frozenset[SourceState] = frozenset({'empty', 'failed', 'skipped', 'success', 'unavailable', 'unsupported'})#
Every documented source state, as a runtime-checkable set.
Lets a runtime-supplied state be checked against the schema before it reaches the envelope, since an annotation alone does not stop one. Kept in step with
SourceStatebytest_source_states_match_the_alias.
- peta.core.output.TARGET_ENVIRONMENT_KEY = 'target_environment'#
How a command hands
make_envelope()its resolved target.Transport only. It travels in the
argumentsmapping because that is the one channel every command already threads through to the envelope, andmake_envelope()removes it again before serialization:argumentsis the contract’s record of the CLI invocation, so publishing the environment there as well would both duplicatequery.target_environmentand put an undocumented nested object in front of exact consumers.
- class peta.core.output.OutputEnvelope(query, status, result, generated_at, sources=<factory>, warnings=<factory>, errors=<factory>, schema_version='2', peta_version='0.3.0')[source]#
Bases:
objectStable top-level shape for machine-readable output.
- Parameters:
query (OutputQuery)
status (EnvelopeStatus)
result (object)
generated_at (str)
sources (list[SourceRecord])
warnings (list[OutputMessage])
errors (list[OutputMessage])
schema_version (str)
peta_version (str)
- class peta.core.output.OutputMessage(code, message, source=None)[source]#
Bases:
objectA structured warning or error.
Credentials are stripped from the message on construction. This is the one channel every diagnostic reaches the user through — fatal errors and per-source warnings alike — so redacting here covers the ones peta builds today and the ones added later, which redacting at each call site would not. Result fields are deliberately left alone: a query string a package declared is metadata to report, not a secret to hide.
- class peta.core.output.OutputQuery(command, arguments, target_environment)[source]#
Bases:
objectThe command invocation represented by an output envelope.
- Parameters:
command (CommandName)
target_environment (TargetEnvironment)
- class peta.core.output.SourceRecord(name, state, target=None, retrieved_at=None, reason=None, freshness=None, fields=<factory>)[source]#
Bases:
objectRetrieval state for one metadata source.
- Parameters:
- class peta.core.output.TargetEnvironment(implementation, python_version, platform, interpreter=None, paths=(), markers=<factory>)[source]#
Bases:
objectInterpreter and platform used to evaluate the query.
- Parameters:
- classmethod current()[source]#
Describe the current runtime.
markersis populated even though no target was named: an untargeted run still evaluates dependency markers against the running interpreter, and leaving the field empty would hide from consumers which values actually decided what the result contains.- Returns:
The active interpreter and operating-system platform.
- Return type:
- peta.core.output.make_envelope(command, *, arguments, status, result, sources=None, warnings=None, errors=None, generated_at=None)[source]#
Build an output envelope using the current runtime as the target.
- Returns:
A populated, typed output envelope.
- Parameters:
command (CommandName)
status (EnvelopeStatus)
result (object)
sources (list[SourceRecord] | None)
warnings (list[OutputMessage] | None)
errors (list[OutputMessage] | None)
generated_at (str | None)
- Return type:
- peta.core.output.utc_from(timestamp)[source]#
Format a Unix timestamp in the same RFC 3339 form as
utc_now().Lets a response served from cache report when it was actually retrieved rather than when it was replayed.
- peta.core.output.utc_now()[source]#
Return the current UTC time in RFC 3339 form.
- Returns:
A second-precision UTC timestamp ending in
Z.- Return type:
The one outbound HTTP client every peta source shares.
Each source used to call the top-level httpx.get/httpx.post helpers,
which build a throwaway client per call. A dependency tree or a comparison
therefore paid for a fresh connection and TLS handshake on every request to the
same host. Routing every request through a single pooled client lets them reuse
connections, and leaves one place for the caching and concurrency layers to wrap
instead of four call sites in three modules.
Only transport lives here. Status handling, decoding, and validation stay with
each source, because they map failures onto different error types: a PyPI
lookup is fatal (NetworkError) while an enrichment
lookup is not (EnrichmentError).
Caching also lives here rather than in each source, so one implementation of
“is the stored copy still good, and if not can the source just confirm it”
serves every URL peta fetches. Whether a given URL is cacheable at all, and
for how long, stays with the caller: see peta.core.cache.
- peta.core.http.DEFAULT_TIMEOUT = 10.0#
Per-request timeout, in seconds, applied to every outbound request.
- peta.core.http.MAX_RESPONSE_BYTES = 67108864#
Largest response accepted from an untrusted source, in bytes.
Sized against real PyPI data, not a round guess:
grpcio’s JSON document is already 9 MiB and its Simple API page 6.7 MiB, and both grow with every release. A 10 MiB cap was 87% used by one popular package. This one leaves room for years of growth while still bounding what a hostile index can make peta hold in memory.
- peta.core.http.USER_AGENT = 'peta/0.3.0'#
Identifies peta to the APIs it queries, as their usage guidelines ask.
- class peta.core.http.Fetched(response, provenance, cache_key=None)[source]#
Bases:
objectA response, where it came from, and whether it may still be cached.
- Parameters:
response (Response)
provenance (Provenance)
cache_key (str | None)
- exception peta.core.http.OfflineError(url)[source]#
Bases:
ExceptionRaised when offline mode is on and the cache cannot answer.
Distinct from
NetworkError: nothing went wrong, peta was told not to use the network and does not hold the answer. Conflating the two would tell a user to check their connection when the fix is to drop--offlineor warm the cache.Name the request that could not be served offline.
The URL is redacted here rather than at each raise site, so no future caller can leak a credential by forgetting to. Libraries.io takes its API key in the query string, and this message is surfaced to users: for a fatal lookup it becomes the
offline_unavailableerror in the envelope, and for an optional one it survives as the__cause__of the source failure, where any traceback would print it.- Parameters:
url (str)
- Return type:
None
- exception peta.core.http.ResponseTooLargeError(message, *, request=None)[source]#
Bases:
TransportPolicyErrorRaised when an untrusted source exceeds the response-size limit.
- Parameters:
message (str)
request (Request | None)
- Return type:
None
- exception peta.core.http.TransportPolicyError(message, *, request=None)[source]#
Bases:
RequestErrorA request peta refused, or could not start, before any reply existed.
Derived from
httpx.RequestErrorso that these checks join the contract every source already handles. Each one maps a failed request onto its own error type by catchinghttpx.RequestError; an exception outside that hierarchy reaches the CLI unhandled, which prints a traceback and no message at all. A request peta declined to send has failed in exactly the sense those handlers already describe.- Parameters:
message (str)
request (Request | None)
- Return type:
None
- exception peta.core.http.UnsafeURLError(message, *, request=None)[source]#
Bases:
TransportPolicyErrorRaised before a request to a non-HTTPS URL can be sent.
- Parameters:
message (str)
request (Request | None)
- Return type:
None
- exception peta.core.http.UnsupportedEncodingError(message, *, request=None)[source]#
Bases:
TransportPolicyErrorRaised when a response uses a content encoding peta did not ask for.
- Parameters:
message (str)
request (Request | None)
- Return type:
None
- peta.core.http.client()[source]#
Return the process-wide pooled client, building it on first use.
Built on demand rather than at import time because constructing a client loads the system CA bundle, which costs tens of milliseconds — a price
peta filesandpeta info --localshould not pay to import a module they never send a request through.- Returns:
The shared
httpx.Client.- Return type:
Client
- peta.core.http.get(url, *, params=None, headers=None, ttl=None, scope='')[source]#
Send a GET request, using the cache when the caller allows it.
A transport-level
httpx.RequestErrorpropagates untouched, and anOfflineErrorpropagates when offline mode is on and the cache cannot answer; each source maps them onto its own error type.A live result is not cached until the caller confirms the body was usable by passing it to
keep().- Parameters:
url¶ – The absolute URL to request.
params¶ – Optional query-string parameters.
headers¶ – Extra request headers merged onto the shared client’s defaults, for content negotiation or similar per-source needs.
ttl¶ – How long a stored response stays usable, in seconds.
Nonebypasses the cache entirely, for a URL whose answer should never be reused.scope¶ – Distinguishes consumers that fetch the same URL but validate different parts of it, so neither replays a body the other accepted. See
peta.core.cache.key_for().url (str)
ttl (int | None)
scope (str)
- Returns:
The response and where it came from.
- Return type:
- peta.core.http.keep(fetched)[source]#
Store a live response the caller has confirmed it could actually use.
Storing on arrival would cache a body the source-specific decoder then rejects — a
200carrying an error page, or truncated JSON — and every later request would replay that same unusable response until the TTL expired, up to a month for pinned metadata. A transient upstream fault would become a persistent one.So nothing is written until the caller has decoded and validated the body and says so by calling this. Failing to call it means the response is simply not cached, which costs a refetch; the opposite default would poison the cache.
- peta.core.http.post(url, *, json)[source]#
Send a JSON POST request over the shared client.
Never cached: a POST body carries the question, and peta’s only POST source is an advisory query whose request shape is about to change with batching. Offline mode still refuses it rather than pretending.
A transport-level
httpx.RequestErrorpropagates untouched, and anOfflineErrorpropagates when offline mode is on.
On-disk cache for successful responses, and the settings that govern it.
Peta re-asks the same questions constantly: a dependency tree resolves the same transitive packages, and a pinned release’s metadata cannot change once it is published. Caching those answers turns a repeat query into a local read, and makes working without a network possible rather than merely degraded.
Only 200 responses are stored. An error is a fact about right now, not
about the package, so caching one would turn a transient outage into a
persistent wrong answer.
How long an entry stays usable is the caller’s decision, not this module’s:
the code building a URL is the only code that knows what kind of answer it
asked for. This module supplies the vocabulary — LATEST, DAILY
— and each source picks from it.
- peta.core.cache.DAILY = 21600#
Download and dependent counts are recomputed about once a day.
Shorter than a day so a query late in the cycle does not serve a count from two refreshes ago.
- peta.core.cache.FRESHNESS_VALUES: frozenset[Freshness] = frozenset({'cached', 'live', 'revalidated'})#
Every documented freshness value, as a runtime-checkable set.
Kept in step with
Freshnessbytest_freshness_values_match_the_alias.
- peta.core.cache.LATEST = 3600#
A package’s metadata response, whether a version was pinned or not.
It is tempting to keep a pinned release for far longer, since its metadata is settled once published. The response is not: PyPI’s package payload also carries a
vulnerabilitiesarray, and advisories are published against releases long after they ship. A month-long entry would letinfo name==version --no-osvreport a package as clear after PyPI had already published an advisory against it, so the whole response expires on the advisory data’s schedule rather than the metadata’s.
- peta.core.cache.MAX_AGE = 2592000#
How long any entry may sit on disk, however long its TTL.
A TTL decides whether an entry may still be served; without a separate bound nothing would ever delete one, so querying many packages — a dependency tree especially — would leave every file behind for good. Comfortably longer than any TTL, so pruning never discards an entry that could still have been served, and short enough that an abandoned cache does not grow without limit.
- peta.core.cache.MAX_ENTRY_BYTES = 167772160#
Largest entry file read back, in bytes; anything bigger is a miss.
Replayed entries never pass through the transport, so its response-size limit does not apply to them, and
loadreads and decodes a whole file at once. Entries written by earlier versions — which had no transport limit at all — and entries tampered with on disk would otherwise be read in full whatever their size. Set at two and a half timeshttp.MAX_RESPONSE_BYTESbecause an entry stores its body as an escaped JSON string inside an envelope, so an entry for the largest accepted body is bigger than the body. Too small a value only costs a refetch, never a failure.
- class peta.core.cache.CacheSettings(directory, offline=False, refresh=False, enabled=True)[source]#
Bases:
objectHow the cache behaves for this invocation.
- class peta.core.cache.CachedResponse(status, body, headers, stored_at)[source]#
Bases:
objectA stored response and the moment it was stored.
- type peta.core.cache.Freshness = Literal['live', 'cached', 'revalidated']#
Where a response came from.
livemeans the source answered,cachedmeans the entry was read from disk without contacting the source, andrevalidatedmeans the source confirmed a stored entry was still current without resending its body.
- class peta.core.cache.Provenance(freshness, retrieved_at)[source]#
Bases:
objectWhere a source’s answer came from, and when it was retrieved.
Carried separately from the answer so a caller can report accurate provenance without knowing whether the cache was involved.
retrieved_atis the moment the source answered, not the moment it was replayed: a response stored days ago and served from disk must not claim it was retrieved just now, or the provenance is worse than useless.
- peta.core.cache.configure(*, directory=None, offline=False, refresh=False, enabled=True)[source]#
Install the settings for this process.
Held in module state rather than threaded through every signature: these are one decision made once at startup, and passing them down would mean adding parameters to every source, to the resolver, to the dependency walker, and to the provider protocol — all of which would then carry transport configuration they have no use for.
- Parameters:
- Return type:
None
- peta.core.cache.default_directory()[source]#
Locate the cache directory for the current platform.
Resolved by hand rather than through
platformdirs: it is four branches, and peta’s runtime dependencies are deliberately few.- Returns:
The per-user cache directory for peta.
- Return type:
- peta.core.cache.entries_directory()[source]#
Locate the directory the entries themselves live in.
- Returns:
The subdirectory of the configured location that peta owns.
- Return type:
- peta.core.cache.key_for(method, url, scope='')[source]#
Derive the cache key for one request.
scopeseparates consumers that fetch the same URL but validate different parts of it. Nothing is stored until its caller confirms the body was usable, and “usable” means usable to that caller: one command accepting a payload whose other half is malformed must not hand it to a command that reads that other half.
- peta.core.cache.load(key)[source]#
Read one entry, treating any unreadable entry as absent.
A cache is disposable, so a truncated write, a partial disk, or a file from a future format must degrade to a miss. Raising here would make a corrupt byte on disk fatal to a command that could simply refetch.
- Parameters:
- Returns:
The stored entry, or
Noneon a miss or a damaged entry.- Return type:
CachedResponse | None
- peta.core.cache.now()[source]#
Return the current wall-clock time as a Unix timestamp.
Indirected through a function so tests can drive expiry from a fixed clock instead of sleeping.
- Returns:
Seconds since the epoch.
- Return type:
- peta.core.cache.redacted(url)[source]#
Rewrite a URL with credential-bearing query parameters removed.
Public because the cache is not the only place a request URL is retained: an error that names the URL it could not answer would otherwise carry the credential into a message, a log, or a traceback.
- peta.core.cache.redacted_text(value)[source]#
Redact credentials from every URL embedded in an arbitrary string.
- peta.core.cache.reset()[source]#
Discard configured settings, restoring the defaults.
- Return type:
None
- peta.core.cache.settings()[source]#
Return the active settings, defaulting until
configure()runs.Defaults apply so importing a source module and making a request works without the CLI having wired anything up, which is what the unit tests and any library use rely on.
- Returns:
The active cache settings.
- Return type:
- peta.core.cache.store(key, *, url, status, body, headers)[source]#
Store one successful response.
- Parameters:
- Return type:
None
Running independent lookups at the same time, without losing their order.
Peta’s slow work is waiting on other people’s servers. A package’s three enrichment sources have no dependency on each other, and neither do the two packages of a comparison, yet each waited for the last: measured against the live services, roughly 44% of a package’s enrichment latency was one source idling while another was queried.
Order is not incidental here. The enrichment merge is first-writer-wins by provider order, so a conflict between two sources is resolved by which was consulted first. Results must therefore come back in the order the caller asked for them, whatever order they actually complete in.
- peta.core.concurrency.MAX_WORKERS = 8#
How many lookups may be in flight from one
gather()call.Threads are not the scarce resource — sockets are — so the real bound on concurrent requests is the connection limit on the shared client in
peta.core.http, which applies however many callers are running. This number keeps any single fan-out from creating threads without limit, and is set above peta’s widest fan-out (three enrichment sources, two compared packages) so the bound never shapes ordinary work.
- peta.core.concurrency.gather(tasks)[source]#
Run independent tasks concurrently and return results in input order.
Nothing is threaded for a single task, so the common case — one package, one source — costs no pool, no threads, and no change to a traceback.
A task that raises propagates, and because results are consumed in input order the exception surfaced is the first task’s, not the first to fail. That keeps error reporting identical to running them one after another. Tasks after a failing one still run, since they were already started; peta’s callers treat that as a wasted request rather than a problem.
Local package metadata fetcher using importlib.metadata.
- peta.core.local.METADATA_READ_ERRORS: tuple[type[Exception], ...] = (<class 'OSError'>, <class 'RuntimeError'>, <class 'ValueError'>, <class 'zipfile.BadZipFile'>, <class 'zipfile.LargeZipFile'>, <class '_lzma.LZMAError'>, <class 'zlib.error'>, <class 'compression.zstd.ZstdError'>)#
What reading an unreadable metadata file or archive member can raise.
A zipped member can also fail to decompress:
RuntimeErrorwhen it is encrypted,NotImplementedError(aRuntimeError) for a compression methodzipfilelacks, andLZMAError,zlib.errororZstdErrorfor a corrupt stream.
- exception peta.core.local.InvalidTargetError[source]#
Bases:
ValueErrorRaised when an explicit local-environment target cannot be used.
- class peta.core.local.LocalTarget(paths, interpreter, marker_environment, prefix=None)[source]#
Bases:
objectMetadata paths and marker values used for a local inspection.
- Parameters:
- prefix: str | None = None#
The environment’s installation prefix, when it is known.
Bounds which files origin inspection may read: a
RECORDlegitimately lists console scripts outsidesite-packagesbut inside the prefix. Unknown for a--path-only target, which names metadata directories rather than an environment.
- classmethod create(python=None, paths=(), python_version=None, platform=None)[source]#
Build a target without implicitly discovering a virtual environment.
- Returns:
The selected metadata paths and marker environment.
- Raises:
InvalidTargetError – If a path or interpreter cannot be inspected.
- Parameters:
- Return type:
- describe()[source]#
Return a concise human-readable target description.
Includes the marker values that decide which dependencies a tree contains, since with
--pathalone they come from the running interpreter rather than from anything named on the command line.- Returns:
A one-line target summary.
- Return type:
- exception peta.core.local.PackageNotFoundError(name)[source]#
Bases:
ExceptionRaised when a package is not installed locally.
Store the missing package name.
- Parameters:
name (str)
- Return type:
None
- peta.core.local.find_distribution(name, *, target=None, name_of=None)[source]#
Find an installed distribution in the selected environment.
- Parameters:
name¶ – Package name to look up.
target¶ – The environment to search; the running one when
None.name_of¶ – How to read each candidate’s
Namewhen the target’s search path is enumerated; the stdlib parser whenNone. A caller that vets metadata files before reading them passes its own, so no candidate is read unvetted.name (str)
target (LocalTarget | None)
name_of (Callable[[importlib_metadata.Distribution], str | None] | None)
- Returns:
The first matching distribution on the target’s search path.
- Raises:
PackageNotFoundError – If the package is not installed there.
- Return type:
importlib_metadata.Distribution
- peta.core.local.get_package(name, *, target=None)[source]#
Get metadata for a locally installed package.
- Parameters:
name¶ – Package name to look up.
name (str)
target (LocalTarget | None)
- Returns:
A
PackageInfowithsource="local".- Return type:
- peta.core.local.legacy_installed_files(dist, *, skip_missing=True, listing=None)[source]#
Read a legacy
.egg-info’sinstalled-files.txt, as Python 3.12 does.Python 3.11’s importlib.metadata never reads this file and falls back to
SOURCES.txt, which lists the project’s source tree rather than what was installed. Reading it here, relative to the search-path root and skipping files that are gone, keepsfilesthe same on every supported version.A non-empty
RECORDstill wins, as it does in the stdlib, so a.dist-infothat also carries a strayinstalled-files.txtkeeps its authoritative listing.skip_missing=Falsekeeps entries whose file is gone, for callers that report a missing file rather than hide it.listingis the file’s text for a caller that has already read and vetted it, and has found noRECORD: nothing is read a second time, so nothing swapped in meanwhile is read unchecked.- Returns:
The installed files, or
Nonewhendisthas no such listing.- Parameters:
dist (Distribution)
skip_missing (bool)
listing (str | None)
- Return type:
PyPI JSON API client for remote package metadata.
- exception peta.core.remote.NetworkError(message)[source]#
Bases:
ExceptionRaised when a network request fails.
Wrap a network failure message.
- Parameters:
message (str)
- Return type:
None
- exception peta.core.remote.PackageNotFoundError(name, version=None)[source]#
Bases:
ExceptionRaised when a package is not found on PyPI.
Store the missing package name and optional version.
- class peta.core.remote.PyPIInfo[source]#
Bases:
TypedDictThe
infoobject of a PyPI package payload.
- class peta.core.remote.PyPIReleaseFile[source]#
Bases:
TypedDictA single distribution file within a release entry.
- class peta.core.remote.PyPIResponse[source]#
Bases:
TypedDictThe top-level PyPI JSON payload for a package.
- class peta.core.remote.PyPIVulnerability[source]#
Bases:
TypedDictA single entry of the
vulnerabilitiesarray.
- peta.core.remote.get_package(name, version=None)[source]#
Get metadata for a package from PyPI.
- Parameters:
- Returns:
A
PackageInfowithsource="remote". Not-found and network failures propagate from_fetch().- Return type:
- peta.core.remote.get_package_matching(name, specifier, marker_environment)[source]#
Get the newest PyPI release satisfying a dependency requirement.
The project endpoint lists releases but only a version endpoint supplies historical
Requires-Pythonand dependency metadata, so candidates are checked newest-first until one also supports the requested target.- Returns:
The newest compatible package, or the current release when no release satisfies the requirement so callers can surface a conflict.
- Raises:
PackageNotFoundError – If a matching current release has no usable files.
- Parameters:
- Return type:
Shared package-resolution logic for the info and compare commands.
- peta.core.resolve.not_found_source(exc)[source]#
Name the provider that reported a package as missing.
- Returns:
"local"for the installed environment, otherwise"pypi".- Parameters:
exc (BaseException)
- Return type:
- peta.core.resolve.resolve_package(package, *, local, remote, target=None, specifier=None, select_compatible=False)[source]#
Resolve a package argument to its metadata.
Checks the local environment first and falls back to PyPI, unless
--local/--remoteforce a source or aname==versionspecifier is given (which always queries PyPI and rejects--local).- Returns:
The resolved package metadata.
- Raises:
typer.BadParameter – If source-selection options conflict.
- Parameters:
package (str)
local (bool)
remote (bool)
target (LocalTarget | None)
specifier (SpecifierSet | None)
select_compatible (bool)
- Return type:
Recursive dependency-tree construction and deps --why path lookup.
- peta.core.deptree.build_tree(name, *, local, remote, target=None, max_depth=10, extras=())[source]#
Recursively resolve
nameand its dependency tree.Only the root resolution can raise (propagated from
peta.core.resolve.resolve_package()); unresolvable transitive dependencies become leaf nodes withselected_version=Noneinstead.- Returns:
The root
DependencyNode, with children expanded recursively.- Parameters:
- Return type:
- peta.core.deptree.find_why(root, target)[source]#
Find every root-to-
targetpath in the dependency tree.- Returns:
A list of name paths (each starting with
root.name); empty iftargetis not present anywhere in the tree.- Parameters:
root (DependencyNode)
target (str)
- Return type:
Best-effort enrichment orchestration over peta.core.providers.
Providers are consulted independently and merged deterministically, so one source failing can never discard another’s evidence, and two sources answering the same field disagree loudly rather than silently overwriting each other.
- peta.core.enrich.enrich(pkg, *, no_osv, no_stats, providers=None)[source]#
Best-effort enrich a package from every configured provider.
Never raises: providers report failure as a result state, so an enrichment problem stays visible in the output without affecting exit codes.
- Parameters:
pkg¶ – The resolved package to enrich.
no_osv¶ – Skip the vulnerability provider group.
no_stats¶ – Skip the usage-statistics provider group.
providers¶ – The providers to consult, in conflict-priority order. Injectable so callers and tests can substitute sources; defaults to
DEFAULT_PROVIDERS. Resolved at call time rather than bound as a default argument, so the registry stays swappable.pkg (PackageInfo)
no_osv (bool)
no_stats (bool)
providers (Sequence[EnrichmentProvider] | None)
- Returns:
The enriched package metadata.
- Return type:
The internal seam between enrichment orchestration and concrete sources.
A provider answers exactly one Capability for one package and reports
the outcome as a ProviderResult, so orchestration never needs to know
which HTTP service produced the evidence, how it failed, or how it is
configured.
This seam is deliberately internal. It is not a third-party plugin API, and it carries no compatibility guarantees outside this package.
- peta.core.providers.base.CAPABILITY_FIELDS: dict[Capability, str] = {'dependent_count': 'result.dependent_count', 'download_count': 'result.download_count', 'vulnerabilities': 'result.vulnerabilities'}#
The output-contract
fieldspath each capability writes to.
- peta.core.providers.base.CAPABILITY_GROUPS: dict[Capability, ProviderGroup] = {'dependent_count': 'stats', 'download_count': 'stats', 'vulnerabilities': 'vulnerabilities'}#
The opt-out family each capability falls under.
Derived from the capability rather than declared per provider: the CLI’s opt-out flags select kinds of data, so a provider cannot place itself in a group that does not match what it supplies and thereby escape its own flag.
- type peta.core.providers.base.Capability = Literal['vulnerabilities', 'download_count', 'dependent_count']#
The single
resultfield a provider contributes evidence for.
- class peta.core.providers.base.CountEvidence(count)[source]#
Bases:
objectA single scalar count, such as downloads or dependents.
- Parameters:
count (int)
- class peta.core.providers.base.EnrichmentProvider(*args, **kwargs)[source]#
Bases:
ProtocolAn optional metadata source that enriches one package.
Implementations expose their identity as
nameand the single result field they contribute ascapability; the opt-out family follows from the capability viaCAPABILITY_GROUPS.Implementations must not raise: every outcome, including failure and missing configuration, is reported as a
ProviderResultso one source can never abort another.The member bodies below raise rather than using a bare
...: a protocol body is never executed, and an explicit raise says so without leaving a statement that has no effect.- property name: str#
Identify the source in provenance and warnings.
- Returns:
The provider’s stable source name.
- Raises:
NotImplementedError – Always; implementations supply the value.
- property capability: Capability#
Name the single result field this provider contributes.
- Returns:
The provider’s capability.
- Raises:
NotImplementedError – Always; implementations supply the value.
- fetch(pkg)[source]#
Look up this provider’s capability for
pkg.- Parameters:
pkg¶ – The resolved package to look up.
pkg (PackageInfo)
- Returns:
The outcome, whether evidence, an empty answer, or a failure.
- Raises:
NotImplementedError – Always; implementations perform the lookup.
- Return type:
- type peta.core.providers.base.Evidence = VulnerabilityEvidence | CountEvidence#
Typed payload a provider returns, carried separately from its provenance.
- type peta.core.providers.base.ProviderGroup = Literal['vulnerabilities', 'stats']#
The
--no-osv/--no-statsfamily a capability belongs to.
- class peta.core.providers.base.ProviderResult(provider, capability, state, subject, retrieved_at=None, freshness=None, upstream_id=None, evidence=None, reason=None, warnings=<factory>)[source]#
Bases:
objectOne provider’s answer for one package, evidence and provenance together.
statereuses the output contract’sSourceStateso a result maps onto a source record without a translation table.- Parameters:
provider (str)
capability (Capability)
state (SourceState)
subject (str)
retrieved_at (str | None)
freshness (Freshness | None)
upstream_id (str | None)
evidence (Evidence | None)
reason (str | None)
warnings (list[ProviderWarning])
- property field: str | None#
Name the
resultpath this provider contributes to.Nonewhen the capability is not one peta knows, which an injected provider can declare at runtime despite the annotation. Such a result has no attributable field rather than an invented one.- Returns:
The output-contract field path, or
Noneif unattributable.
- class peta.core.providers.base.VulnerabilityEvidence(vulnerabilities)[source]#
Bases:
objectAdvisories a provider found for the subject.
- Parameters:
vulnerabilities (list[Vulnerability])
Adapters wrapping peta’s built-in enrichment sources as providers.
Each adapter owns its own failure and configuration handling, so orchestration neither catches source-specific exceptions nor reads source-specific settings.
- peta.core.providers.builtin.DEFAULT_PROVIDERS: tuple[EnrichmentProvider, ...] = (OsvProvider(name='osv', capability='vulnerabilities'), PypiStatsProvider(name='pypistats', capability='download_count'), LibrariesIoProvider(name='libraries.io', capability='dependent_count'))#
The built-in providers, in the order orchestration consults them.
Order is the conflict tie-breaker: for a given capability the first provider to return evidence wins.
- class peta.core.providers.builtin.LibrariesIoProvider(name='libraries.io', capability='dependent_count')[source]#
Bases:
objectLook up a package’s dependent count on libraries.io.
- Parameters:
name (str)
capability (Capability)
- fetch(pkg)[source]#
Query libraries.io for the package’s dependent count.
Reports
unavailablewithout making a request when no API key is configured, keeping “not set up” distinct from “returned nothing”.- Returns:
The dependent count, an empty or unavailable answer, or the lookup failure.
- Parameters:
pkg (PackageInfo)
- Return type:
- class peta.core.providers.builtin.OsvProvider(name='osv', capability='vulnerabilities')[source]#
Bases:
objectLook up advisories for a package on OSV.dev.
- Parameters:
name (str)
capability (Capability)
- fetch(pkg)[source]#
Query OSV for the package’s known vulnerabilities.
- Returns:
The advisories found, an empty answer, or the lookup failure.
- Parameters:
pkg (PackageInfo)
- Return type:
- class peta.core.providers.builtin.PypiStatsProvider(name='pypistats', capability='download_count')[source]#
Bases:
objectLook up a package’s last-month download count on pypistats.org.
- Parameters:
name (str)
capability (Capability)
- fetch(pkg)[source]#
Query pypistats.org for the package’s recent downloads.
- Returns:
The download count, an empty answer, or the lookup failure.
- Parameters:
pkg (PackageInfo)
- Return type:
OSV.dev vulnerability lookups (best-effort enrichment).
- class peta.core.osv.OsvAffected[source]#
Bases:
TypedDictA single
affectedentry of an OSV vulnerability.
- class peta.core.osv.OsvEvent[source]#
Bases:
TypedDictA single event within an affected range (only
fixedis read).
- class peta.core.osv.OsvResponse[source]#
Bases:
TypedDictThe top-level OSV JSON payload for a query.
- class peta.core.osv.OsvSeverity[source]#
Bases:
TypedDictA single
severityentry of an OSV vulnerability (onlyscoreis read).
- peta.core.osv.get_vulnerabilities(name, version=None)[source]#
Look up known vulnerabilities for a package on OSV.dev.
The caller may treat this as best-effort by catching
EnrichmentErrorand retaining its source and reason.
Download and dependent count lookups (best-effort enrichment).
- class peta.core.stats.LibrariesIoResponse[source]#
Bases:
TypedDictThe fields peta reads from a libraries.io project JSON payload.
- class peta.core.stats.PypiStatsData[source]#
Bases:
TypedDictThe
dataobject of a pypistats.org “recent” response.
- class peta.core.stats.PypiStatsResponse[source]#
Bases:
TypedDictThe top-level pypistats.org “recent” JSON payload.
- peta.core.stats.get_dependent_count(name, *, api_key)[source]#
Look up a package’s dependent count on libraries.io.
The enrichment coordinator catches source-specific failures so they remain non-fatal while still being visible to users.
A key is required rather than optional. Deciding what “not configured” means is the provider’s job — it reports
unavailablewithout making a request — and the previous no-key branch here had to invent a provenance for a request that never happened, which is exactly the fabricationProvenanceexists to prevent.
- peta.core.stats.get_download_count(name)[source]#
Look up a package’s last-month download count on pypistats.org.
The enrichment coordinator catches source-specific failures so they remain non-fatal while still being visible to users.
- Parameters:
- Returns:
The last-month download count, and where it came from.
- Return type:
tuple[int | None, Provenance]
- peta.core.stats.libraries_io_api_key()[source]#
Read the libraries.io API key from the environment.
- Returns:
The
LIBRARIES_IO_API_KEYvalue, orNoneif unset or empty.- Return type:
str | None
Dedup/merge of vulnerabilities from multiple sources.
- peta.core.vulns.merge_vulnerabilities(existing, extra)[source]#
Merge two vulnerability lists, deduping by identity.
Two vulnerabilities are the same if they share their
idor any overlapping alias. When a candidate’s identity bridges several existing entries (e.g. it carries aliases of two otherwise-unrelated entries), ALL of them are folded into one cumulative entry rather than merging into only the first match. The result prefers a non-Noneseverityand unionsaliasesandfixed_in.- Parameters:
existing¶ – Vulnerabilities already known (e.g. from PyPI).
extra¶ – Additional vulnerabilities to merge in (e.g. from OSV).
existing (list[Vulnerability])
extra (list[Vulnerability])
- Returns:
A deduped list, with
existingentries first, in order.- Return type:
Small runtime validators for decoded external API responses.
- exception peta.core.validation.EnrichmentError(source, reason, *, contacted=True)[source]#
Bases:
ExceptionA source-specific failure from an optional external API.
Store the failed source, safe diagnostic reason, and whether it ran.
- Parameters:
source (str) – The source that failed.
reason (str) – A diagnostic to show a user. Credentials are stripped from any URL it names, here rather than at each call site: most of these reasons are
str(exc)on a transport error, which quotes the request URL, and Libraries.io carries its API key in the query string.contacted (bool) – Whether a request was actually made.
Falsefor a refusal that never reached the network — being offline — so the resulting record can omit a retrieval time instead of claiming one for a source nothing was sent to.
- Return type:
None
- exception peta.core.validation.ResponseLimitError(source, path, limit)[source]#
Bases:
ResponseValidationErrorRaised when a response is well formed but past one of peta’s limits.
Separate from its parent so that a refusal on size does not claim the value had the wrong type. An array of 10,001 items is an array, and reporting it as “must be an array” sends whoever debugs it to check the response shape, find it correct, and lose the trail.
Describe the source, JSON path, and the limit that was exceeded.
- exception peta.core.validation.ResponseValidationError(source, path, expected)[source]#
Bases:
ValueErrorRaised when an external response does not match its consumed contract.
Describe the source, JSON path, and expected value type.
- peta.core.validation.expect_int(value, *, source, path)[source]#
Require an integer while rejecting JSON booleans.
- Returns:
The validated integer.
- Raises:
ResponseValidationError – If the value is not a genuine integer.
- Parameters:
- Return type:
- peta.core.validation.expect_list(value, *, source, path)[source]#
Require a JSON array.
- Returns:
The validated list.
- Raises:
ResponseValidationError – If the value is not a list.
ResponseLimitError – If the array holds more than the item limit.
- Parameters:
- Return type:
- peta.core.validation.expect_mapping(value, *, source, path)[source]#
Require a JSON object with string keys.
- Returns:
The validated mapping.
- Raises:
ResponseValidationError – If the value is not a string-keyed mapping.
ResponseLimitError – If the object holds more than the item limit.
- Parameters:
- Return type:
- peta.core.validation.expect_string(value, *, source, path)[source]#
Require a string value.
- Returns:
The validated string.
- Raises:
ResponseValidationError – If the value is not a string.
ResponseLimitError – If the string is longer than the length limit.
- Parameters:
- Return type:
- peta.core.validation.json_body(response, *, source)[source]#
Decode a JSON response, refusing one shaped to exhaust the process.
- Returns:
The decoded body.
- Raises:
ResponseLimitError – If the body nests past
MAX_JSON_DEPTH, holds more thanMAX_JSON_VALUESvalues orMAX_JSON_CONTAINERSobjects and arrays, has any array or object with more thanMAX_COLLECTION_ITEMSitems, or any string longer thanMAX_STRING_LENGTH.- Parameters:
response (httpx.Response)
source (str)
- Return type:
- peta.core.validation.optional_string(mapping, key, *, source, path)[source]#
Validate an optional nullable string field.
- peta.core.validation.optional_string_list(mapping, key, *, source, path)[source]#
Validate an optional nullable array of strings.
CLI (peta.cli)#
Typer application and command registration.
- peta.cli.app.artifacts(ctx, package, use_json=False, output_format=OutputFormat.RICH, python=None, detailed=False, provenance=False)[source]#
Show a release’s distribution files, compatibility, and provenance.
- Parameters:
ctx (Context)
package (Annotated[str, <typer.models.ArgumentInfo object at 0x7f49bb0f1e50>])
use_json (Annotated[bool, <typer.models.OptionInfo object at 0x7f49bb0f1f90>])
output_format (Annotated[OutputFormat, <typer.models.OptionInfo object at 0x7f49bb0f20d0>])
python (Annotated[str | None, <typer.models.OptionInfo object at 0x7f49bb0f2210>])
detailed (Annotated[bool, <typer.models.OptionInfo object at 0x7f49bb0f2350>])
provenance (Annotated[bool, <typer.models.OptionInfo object at 0x7f49bb0f2490>])
- Return type:
None
- peta.cli.app.compare(ctx, a, b, use_json=False, output_format=OutputFormat.RICH, local=False, remote=False, no_osv=False, no_stats=False, python=None, path=None, changes_only=False, artifacts=False)[source]#
Compare two packages, or two releases of one, and explain what changed.
- Parameters:
ctx (Context)
a (Annotated[str, <typer.models.ArgumentInfo object at 0x7f49bb0f34d0>])
b (Annotated[str, <typer.models.ArgumentInfo object at 0x7f49bb0f3610>])
use_json (Annotated[bool, <typer.models.OptionInfo object at 0x7f49bb0f3750>])
output_format (Annotated[OutputFormat, <typer.models.OptionInfo object at 0x7f49bb0f3890>])
local (Annotated[bool, <typer.models.OptionInfo object at 0x7f49bb0f39d0>])
remote (Annotated[bool, <typer.models.OptionInfo object at 0x7f49bb0f3b10>])
no_osv (Annotated[bool, <typer.models.OptionInfo object at 0x7f49bb0f3c50>])
no_stats (Annotated[bool, <typer.models.OptionInfo object at 0x7f49bb0f3d90>])
python (Annotated[str | None, <typer.models.OptionInfo object at 0x7f49bb0f3ed0>])
path (Annotated[list[str] | None, <typer.models.OptionInfo object at 0x7f49ba594050>])
changes_only (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba594190>])
artifacts (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba5942d0>])
- Return type:
None
- peta.cli.app.deps(ctx, package, use_json=False, output_format=OutputFormat.RICH, local=False, remote=False, why=None, depth=10, python=None, python_version=None, platform=None, extra=None, path=None)[source]#
Show a package’s recursive dependency tree.
- Parameters:
ctx (Context)
package (Annotated[str, <typer.models.ArgumentInfo object at 0x7f49ba595310>])
use_json (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba595450>])
output_format (Annotated[OutputFormat, <typer.models.OptionInfo object at 0x7f49ba595590>])
local (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba5956d0>])
remote (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba595810>])
why (Annotated[str | None, <typer.models.OptionInfo object at 0x7f49ba595950>])
depth (Annotated[int, <typer.models.OptionInfo object at 0x7f49ba595a90>])
python (Annotated[str | None, <typer.models.OptionInfo object at 0x7f49ba595bd0>])
python_version (Annotated[str | None, <typer.models.OptionInfo object at 0x7f49ba595d10>])
platform (Annotated[str | None, <typer.models.OptionInfo object at 0x7f49ba595e50>])
extra (Annotated[list[str] | None, <typer.models.OptionInfo object at 0x7f49ba595f90>])
path (Annotated[list[str] | None, <typer.models.OptionInfo object at 0x7f49ba5960d0>])
- Return type:
None
- peta.cli.app.files(ctx, package, use_json=False, output_format=OutputFormat.RICH, python=None, path=None)[source]#
List files installed by a local package.
- Parameters:
ctx (Context)
package (Annotated[str, <typer.models.ArgumentInfo object at 0x7f49ba596850>])
use_json (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba596990>])
output_format (Annotated[OutputFormat, <typer.models.OptionInfo object at 0x7f49ba596ad0>])
python (Annotated[str | None, <typer.models.OptionInfo object at 0x7f49ba596c10>])
path (Annotated[list[str] | None, <typer.models.OptionInfo object at 0x7f49ba596d50>])
- Return type:
None
- peta.cli.app.info(ctx, package, use_json=False, output_format=OutputFormat.RICH, local=False, remote=False, no_osv=False, no_stats=False, python=None, path=None)[source]#
Show detailed package metadata.
- Parameters:
ctx (Context)
package (Annotated[str, <typer.models.ArgumentInfo object at 0x7f49ba5979d0>])
use_json (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba597b10>])
output_format (Annotated[OutputFormat, <typer.models.OptionInfo object at 0x7f49ba597c50>])
local (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba597d90>])
remote (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba597ed0>])
no_osv (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba5dc050>])
no_stats (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba5dc190>])
python (Annotated[str | None, <typer.models.OptionInfo object at 0x7f49ba5dc2d0>])
path (Annotated[list[str] | None, <typer.models.OptionInfo object at 0x7f49ba5dc410>])
- Return type:
None
- peta.cli.app.main(ctx, _version=False, no_color=False, offline=False, refresh=False, cache_dir=None)[source]#
Human-friendly Python package metadata viewer.
- Parameters:
ctx (Context)
_version (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba5dcb90>])
no_color (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba5dccd0>])
offline (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba5dce10>])
refresh (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba5dcf50>])
cache_dir (Annotated[Path | None, <typer.models.OptionInfo object at 0x7f49ba5dd090>])
- Return type:
None
- peta.cli.app.origin(ctx, package, use_json=False, output_format=OutputFormat.RICH, python=None, path=None, verify=False)[source]#
Show how a local package was installed and whether its files match.
- Parameters:
ctx (Context)
package (Annotated[str, <typer.models.ArgumentInfo object at 0x7f49ba5dd950>])
use_json (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba5dda90>])
output_format (Annotated[OutputFormat, <typer.models.OptionInfo object at 0x7f49ba5ddbd0>])
python (Annotated[str | None, <typer.models.OptionInfo object at 0x7f49ba5ddd10>])
path (Annotated[list[str] | None, <typer.models.OptionInfo object at 0x7f49ba5dde50>])
verify (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba5ddf90>])
- Return type:
None
- peta.cli.app.run()[source]#
Entry point;
peta <package>is shorthand forpeta info <package>.- Return type:
None
- peta.cli.app.versions(ctx, package, use_json=False, output_format=OutputFormat.RICH, limit=20)[source]#
Show published versions of a package from PyPI.
- Parameters:
ctx (Context)
package (Annotated[str, <typer.models.ArgumentInfo object at 0x7f49ba5de5d0>])
use_json (Annotated[bool, <typer.models.OptionInfo object at 0x7f49ba5de710>])
output_format (Annotated[OutputFormat, <typer.models.OptionInfo object at 0x7f49ba5de850>])
limit (Annotated[int, <typer.models.OptionInfo object at 0x7f49ba5de990>])
- Return type:
None
Shared CLI state resolved once by the root callback.
- class peta.cli.state.CliState(color)[source]#
Bases:
objectOptions resolved once at the root callback and shared by commands.
- Parameters:
color (bool)
Color resolution and Rich console rendering.
- peta.cli.output.console.inline(value)[source]#
Make one untrusted value safe to place on a line of terminal output.
sanitize_terminal()keeps newlines and tabs because formatters build their layout from them, so a value inserted into that layout has to give up its own: folded to spaces, they can neither start a forged line nor shift a column.
- peta.cli.output.console.render(renderable, *, color, width=100)[source]#
Render a Rich renderable to a string, with or without ANSI color.
Rendering happens in two steps so that untrusted metadata can be made inert after Rich has laid it out but before Rich turns styles into escape sequences. Sanitizing the finished string instead would have to tell peta’s own color codes from an attacker’s, which it cannot; sanitizing every renderer’s inputs instead would leave each new call site free to forget.
Markup and emoji substitution are disabled because both let metadata change which characters are printed: a
[bold]or a:pile_of_poo:in a package summary is data, not an instruction. Highlighting stays on — it only colors what is already there, and peta’s output has always had it.
- peta.cli.output.console.resolve_color(*, no_color)[source]#
Decide whether Rich output should include color.
Precedence: an explicit
--no-colorflag always wins; otherwise theNO_COLORenvironment variable (any non-empty value) disables color; otherwise color follows whether stdout is a terminal.
- peta.cli.output.console.sanitize_terminal(value)[source]#
Make untrusted text inert when it is written to a terminal.
Newlines and tabs stay, because the formatters use them; every other C0 or C1 control character is dropped, which is what stops ANSI escape and OSC-8 hyperlink injection from package metadata. Dropping rather than escaping them is deliberate: Rich measures a control character as occupying no cells, so a visible stand-in would be one cell wider than the space Rich reserved and would push a table’s border out of line. Nothing is lost that a reader needs — the JSON output still carries the original bytes.
Rich text output formatters.
- peta.cli.output.tables.render_artifacts(release, *, color, detailed=False)[source]#
Render a release’s artifacts as a Rich summary, optionally per file.
- peta.cli.output.tables.render_compare(a, b, diff=None, *, color, changes_only=False)[source]#
Render two
PackageInfoobjects as a side-by-side Rich table.The grouped semantic changes follow the table;
changes_onlydrops the table and shows only them.- Returns:
The comparison rendered as text.
- Parameters:
a (PackageInfo)
b (PackageInfo)
diff (ChangeSet | None)
color (bool)
changes_only (bool)
- Return type:
- peta.cli.output.tables.render_dep_tree(node, *, color)[source]#
Render a recursive dependency tree as a Rich tree string.
- Returns:
The dependency tree rendered as text.
- Parameters:
node (DependencyNode)
color (bool)
- Return type:
- peta.cli.output.tables.render_files(pkg, *, color)[source]#
Render a package’s file listing as a string.
coloris accepted for signature parity with the other renderers but unused: this output is plain lines, not a Rich renderable.- Returns:
The file listing rendered as text.
- Parameters:
pkg (PackageInfo)
color (bool)
- Return type:
- peta.cli.output.tables.render_info(pkg, *, color)[source]#
Render
PackageInfoas a Rich panel string.- Returns:
The formatted panel text, with any vulnerability block appended.
- Parameters:
pkg (PackageInfo)
color (bool)
- Return type:
- peta.cli.output.tables.render_origin(installation, *, color)[source]#
Render how a distribution was installed as a Rich summary.
- peta.cli.output.tables.render_versions(name, versions, *, color)[source]#
Render a version list as a Rich table string.
- peta.cli.output.tables.render_why(target, paths, *, color)[source]#
Render root-to-target dependency chains as arrow-joined lines.
coloris accepted for signature parity with the other renderers but unused: this output is plain lines, not a Rich renderable.
Versioned JSON output formatters.
- peta.cli.output.json.format_artifacts(release, *, arguments=None, generated_at=None, retrieved_at=None, freshness=None, publishers=False)[source]#
Format a release’s artifacts in the versioned JSON envelope.
- peta.cli.output.json.format_compare(a, b, *, diff=None, releases=None, arguments=None, generated_at=None)[source]#
Format two packages and their semantic diff in the versioned envelope.
result.diff.changeslists only what changed, each record with a stablekindand itsbefore/aftervalues;result.diff.unknownnames the groups a side had no evidence for. Withreleases, each side’s artifact listing is recorded as apypisource, and a failed listing makes the envelopepartialrather than failing the comparison.- Returns:
An indented JSON string.
- Parameters:
a (PackageInfo)
b (PackageInfo)
diff (ChangeSet | None)
releases (tuple[ReleaseEvidence, ReleaseEvidence] | None)
generated_at (str | None)
- Return type:
- peta.cli.output.json.format_dep_tree(node, *, arguments=None, generated_at=None)[source]#
Format a dependency tree in the versioned JSON envelope.
- peta.cli.output.json.format_error(command, *, arguments, code, message, source=None, generated_at=None)[source]#
Format a fatal command error in the versioned JSON envelope.
- peta.cli.output.json.format_files(pkg, *, arguments=None, generated_at=None)[source]#
Format an installed file list in the versioned JSON envelope.
- peta.cli.output.json.format_info(pkg, *, arguments=None, generated_at=None)[source]#
Format package metadata in the versioned JSON envelope.
- peta.cli.output.json.format_origin(installation, *, arguments=None, generated_at=None)[source]#
Format a distribution’s origin and file integrity in the JSON envelope.
File states are data, not diagnostics: a changed file is what the command was asked to find, so it never makes the envelope
partial.
- peta.cli.output.json.format_versions(name, versions, *, arguments=None, generated_at=None, retrieved_at=None, freshness=None)[source]#
Format published versions in the versioned JSON envelope.
- peta.cli.output.json.format_why(target, paths, *, arguments=None, generated_at=None, tree=None)[source]#
Format dependency paths in the versioned JSON envelope.
Markdown output formatters.
- peta.cli.output.markdown.format_artifacts(release, *, detailed=False)[source]#
Format a release’s artifacts as Markdown.
- peta.cli.output.markdown.format_banner(text)[source]#
Escape a line printed above a Markdown document for inertness.
Public for the target-environment banner, which the CLI prepends to the document rather than building through a formatter here, and which names paths that may carry link or image syntax.
- peta.cli.output.markdown.format_compare(a, b, diff=None, *, changes_only=False)[source]#
Format a package comparison as Markdown.
- Returns:
A Markdown comparison table followed by the grouped semantic changes; only the changes with
changes_only.- Parameters:
a (PackageInfo)
b (PackageInfo)
diff (ChangeSet | None)
changes_only (bool)
- Return type:
- peta.cli.output.markdown.format_dep_tree(node)[source]#
Format a dependency tree as Markdown.
- Returns:
A heading and nested Markdown list.
- Parameters:
node (DependencyNode)
- Return type:
- peta.cli.output.markdown.format_files(pkg)[source]#
Format an installed file list as Markdown.
- Returns:
A heading and Markdown list.
- Parameters:
pkg (PackageInfo)
- Return type:
- peta.cli.output.markdown.format_info(pkg)[source]#
Format package metadata as Markdown.
- Returns:
A Markdown heading and field table.
- Parameters:
pkg (PackageInfo)
- Return type:
- peta.cli.output.markdown.format_origin(installation)[source]#
Format how a distribution was installed as Markdown.
- Returns:
A summary table, a table of flagged files, and any notes.
- Parameters:
installation (Installation)
- Return type:
- peta.cli.output.markdown.format_versions(name, versions)[source]#
Format published versions as Markdown.
Plain-text output formatters.
- peta.cli.output.text.format_artifacts(release, *, detailed=False)[source]#
Format a release’s artifacts as plain text.
Unlike the Rich view this carries the full SHA-256 of every file, since plain text is what a script or a reviewer pipes somewhere else.
- peta.cli.output.text.format_compare(a, b, diff=None, *, changes_only=False)[source]#
Format a package comparison as tab-separated text.
- Returns:
A header and one tab-separated row per field, then the grouped semantic changes; only the changes with
changes_only.- Parameters:
a (PackageInfo)
b (PackageInfo)
diff (ChangeSet | None)
changes_only (bool)
- Return type:
- peta.cli.output.text.format_dep_tree(node)[source]#
Format a dependency tree as indented plain text.
- Returns:
One dependency per line.
- Parameters:
node (DependencyNode)
- Return type:
- peta.cli.output.text.format_files(pkg)[source]#
Format installed files as plain text.
- Returns:
A heading and one path per line.
- Parameters:
pkg (PackageInfo)
- Return type:
- peta.cli.output.text.format_info(pkg)[source]#
Format package metadata as plain text.
- Returns:
One labeled field per line.
- Parameters:
pkg (PackageInfo)
- Return type:
- peta.cli.output.text.format_origin(installation)[source]#
Format how a distribution was installed as plain text.
- Returns:
A heading, one
label: valueline per row, flagged files as tab-separatedstate/pathpairs, and any notes.- Parameters:
installation (Installation)
- Return type:
- peta.cli.output.text.format_versions(name, versions)[source]#
Format published versions as tab-separated text.
Central dispatch for CLI output representations.
- peta.cli.output.render.render_artifacts(output_format, release, *, arguments, color, detailed, retrieved_at, freshness=None, publishers=False)[source]#
Render a release’s artifacts in the selected format.
- peta.cli.output.render.render_compare(output_format, a, b, *, arguments, color, diff=None, releases=None, changes_only=False)[source]#
Render a package comparison in the selected format.
changes_onlyaffects the human formats only: JSON always carries both packages and the change list, which is already changed-only.- Returns:
The rendered output.
- Parameters:
output_format (OutputFormat)
a (PackageInfo)
b (PackageInfo)
color (bool)
diff (ChangeSet | None)
releases (tuple[ReleaseEvidence, ReleaseEvidence] | None)
changes_only (bool)
- Return type:
- peta.cli.output.render.render_dep_tree(output_format, tree, *, arguments, color)[source]#
Render a dependency tree in the selected format.
- Returns:
The rendered output.
- Parameters:
output_format (OutputFormat)
tree (DependencyNode)
color (bool)
- Return type:
- peta.cli.output.render.render_files(output_format, pkg, *, arguments, color)[source]#
Render installed files in the selected format.
- Returns:
The rendered output.
- Parameters:
output_format (OutputFormat)
pkg (PackageInfo)
color (bool)
- Return type:
- peta.cli.output.render.render_info(output_format, pkg, *, arguments, color)[source]#
Render package information in the selected format.
- Returns:
The rendered output.
- Parameters:
output_format (OutputFormat)
pkg (PackageInfo)
color (bool)
- Return type:
- peta.cli.output.render.render_origin(output_format, installation, *, arguments, color)[source]#
Render a distribution’s origin and file integrity in the selected format.
- peta.cli.output.render.render_target(output_format, target)[source]#
Render the target-environment banner shown above human output.
Printed outside the formatters, so it would otherwise skip the boundary every other human string passes through. It names paths from
--pathand from the target interpreter’s ownsys.path, and a directory name can carry an escape sequence like any other untrusted text.Line breaks are escaped visibly first.
sanitize_terminal()keeps\\nbecause the multi-line formatters need it, but the banner is one line, and a directory named with a newline would otherwise add lines of its own choosing to the output. Above a Markdown document it is also escaped as Markdown: a directory namedwould otherwise become an image that loads wherever the output is rendered.- Returns:
The banner on one line, inert in the selected format.
- Parameters:
output_format (OutputFormat)
target (LocalTarget)
- Return type:
- peta.cli.output.render.render_versions(output_format, package, versions, *, arguments, color, retrieved_at, freshness=None)[source]#
Render published versions in the selected format.
- peta.cli.output.render.render_why(output_format, target, paths, tree, *, arguments, color)[source]#
Render dependency paths in the selected format.
Application-boundary formatting for parser validation failures.
- class peta.cli.output.errors.StructuredErrorGroup(*, name=None, commands=None, rich_markup_mode='rich', rich_help_panel=None, suggest_commands=True, invoke_without_command=False, no_args_is_help=False, subcommand_metavar=None, result_callback=None, **attrs)[source]#
Bases:
TyperGroupTyper group that preserves the JSON contract for parser errors.
- Parameters:
- main(args=None, prog_name=None, complete_var=None, standalone_mode=True, windows_expand_args=True, **extra)[source]#
Run the CLI and envelope pre-handler failures when JSON was requested.
- Returns:
The command callback result when standalone mode is disabled.
- Raises:
SystemExit – When a standalone JSON invocation exits.
TyperException – When validation fails outside standalone mode.
- Parameters:
- Return type:
Output-format selection and fatal error rendering.
- class peta.cli.output.selection.OutputFormat(*values)[source]#
Bases:
StrEnumSupported CLI output representations.
- peta.cli.output.selection.fail(command, *, arguments, code, message, output_format, exit_code, source=None)[source]#
Render a fatal error consistently and exit.
- peta.cli.output.selection.resolve_or_fail(command, arguments, output_format, *, use_json)[source]#
Resolve output selection, using a JSON envelope for JSON conflicts.
- Returns:
The selected output format.
- Parameters:
command (CommandName)
output_format (OutputFormat | None)
use_json (bool)
- Return type:
- peta.cli.output.selection.resolve_output_format(output_format, *, use_json)[source]#
Resolve the deprecated JSON flag against the unified format option.
output_formatisNonewhen--formatwas left at its default, so--jsonalone selects JSON while any explicit non-JSON--formatconflicts with it.- Returns:
The selected output format.
- Raises:
BadParameter – If
--jsonconflicts with an explicit non-JSON format.- Parameters:
output_format (OutputFormat | None)
use_json (bool)
- Return type:
The peta info command.
- peta.cli.commands.info.info(package, *, use_json=False, output_format=None, local=False, remote=False, color=False, no_osv=False, no_stats=False, python=None, paths=())[source]#
Show detailed package metadata.
The peta compare command.
- peta.cli.commands.compare.compare(a, b, *, use_json=False, output_format=None, local=False, remote=False, color=False, no_osv=False, no_stats=False, python=None, paths=(), changes_only=False, artifacts=False)[source]#
Compare two packages, or two releases of one, and explain what changed.
The peta deps command.
- peta.cli.commands.deps.deps(package, *, use_json=False, output_format=None, local=False, remote=False, color=False, why=None, depth=10, python=None, python_version=None, platform=None, extras=(), paths=())[source]#
Show a package’s recursive dependency tree, or why a target is pulled in.
The peta files command.
- peta.cli.commands.files.files(package, *, use_json=False, output_format=None, color=False, python=None, paths=())[source]#
List files installed by a local package.
The peta versions command.