feat: entry-point provider discovery with inline-table local form#74
Merged
Conversation
Add a `dynamic_metadata.provider` entry-point group so providers are
referenced by a registered name rather than an import path. The bundled
plugins register there under `dynamic_metadata.`-prefixed names
(`dynamic_metadata.regex`, ...); third-party plugins register their own,
conventionally prefixed with their package to avoid collisions in the
shared group.
`provider` now takes one of two shapes:
- a string: a registered entry-point name (installed plugins);
- an inline table `{ path, module }`: a local plugin imported from a
directory, replacing the old top-level `provider-path` key.
The raw module-path form is only accepted via the inline table; without
it there is no bare-import fallback. Duplicate names across distributions
are a hard error, and an unknown name suggests close matches.
Also adds `list_providers()` and a `dynamic-metadata providers` CLI
subcommand, plus a dependency-free `_compat.metadata.entry_points` shim
for the 3.8/3.9-vs-3.10+ API split.
Assisted-by: ClaudeCode:claude-opus-4.8
Assisted-by: ClaudeCode:claude-opus-4.8
henryiii
marked this pull request as ready for review
July 1, 2026 14:18
Drop the DMProtocols union in favor of the base DynamicMetadataProtocol (callers isinstance-narrow to the optional-hook protocols anyway), inline the single-element RESERVED_KEYS check, and fix a stale docstring in _load_entry_point that referred to a removed module-import fallback. Assisted-by: ClaudeCode:claude-opus-4.8
Move list_providers() into a new discovery.py so loader.py holds only what a backend needs to resolve dynamic metadata; the unknown-provider error now enumerates entry-point names inline instead of via list_providers. Update the CLI, tests, and docs to the new location. Assisted-by: ClaudeCode:claude-opus-4.8
The provider_path=None branch was a vestige of the removed bare-import fallback; the sole caller only invokes it with a real directory. Make provider_path required and validate it up front. Assisted-by: ClaudeCode:claude-opus-4.8
Collapse the provider loading pipeline: load_provider now accepts the
raw provider value (entry-point name string or {path, module} table) and
dispatches internally, instead of a (provider, provider_path) pair with a
separate _provider_location parser. The unknown-provider hint moves into
_load_entry_point (resolve-or-raise, no None handshake) and _instantiate
is inlined.
Type the parameter as object so the isinstance validation is required,
and reword _import_provider around the {path, module} vocabulary.
Assisted-by: ClaudeCode:claude-opus-4-8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 AI text below 🤖
Adds an entry-point discovery mechanism for dynamic-metadata providers, replacing the import-path +
provider-pathscheme with a two-shapeproviderconfig. Follows up on the "could we provide an entry point system?" design discussion.What changed
providernow takes one of two shapes:dynamic_metadata.providerentry-point group. Bundled plugins register underdynamic_metadata.-prefixed names; third-party plugins are encouraged to prefix with their own package (the group is shared, and a name registered by two distributions is a hard error).{ path, module }table. The raw module-path form is only accepted this way — there is no bare-import fallback.did you mean …?suggestion.For each audience
[project.entry-points."dynamic_metadata.provider"]table to your ownpyproject.toml. Loose in-project scripts still need no packaging (inline table). No runtime dependency on this package either way.process_dynamic_metadata/load_dynamic_metadatasignatures are unchanged. New optionallist_providers()for diagnostics.provideris now aoneOf(string, or{path, module}object).Notable bits
_compat.metadata.entry_pointsshim handles the 3.8/3.9-vs-3.10+ API split without trippingfilterwarnings = error.list_providers()+dynamic-metadata providersCLI subcommand.RESERVED_KEYSshrank to just{provider}.Testing
uv run pytest(80 passed),mypy --strict, andprek -aall green. New tests cover entry-point resolution (module/class/singleton/import-failure/duplicate), the inline-table form and its validation, rejection of the raw-import form without a path, and the discovery helper + CLI.Open questions
modulekey,dynamic_metadata.-prefixed provider names) and the drop ofprovider-pathwere chosen in discussion but are easy to revisit.