cleanup and rename provider to plugin

This commit is contained in:
2026-05-21 16:19:17 -07:00
parent 02d84f423e
commit e8913d1344
62 changed files with 553 additions and 165 deletions
+3 -3
View File
@@ -2,8 +2,8 @@
## Unreleased (2026-01-05)
- **docs:** Add `docs/provider_authoring.md` as a plugin authoring Quick Start for the strict `ResultTable` API (ResultModel/ColumnSpec/selection_fn). The file keeps its legacy name for compatibility.
- **docs:** Add `docs/plugin_authoring.md` as a plugin authoring Quick Start for the strict `ResultTable` API (ResultModel/ColumnSpec/selection_fn).
- **docs:** Add a link from `docs/result_table.md` to the plugin authoring guide.
- **tests:** Add `tests/test_provider_author_examples.py` validating example plugin registration and adapter behavior. The test file keeps its legacy name for compatibility.
- **notes:** Existing example plugins (`plugins/example_provider.py`, `plugins/vimm/__init__.py`) are referenced as canonical patterns.
- **tests:** Add plugin-author example coverage validating example plugin registration and adapter behavior.
- **notes:** Existing example plugins (`plugins/example_plugin.py`, `plugins/vimm/__init__.py`) are referenced as canonical patterns.
@@ -1,9 +1,9 @@
PR Title: docs: Add plugin authoring doc, examples, and tests
Summary:
- Add `docs/provider_authoring.md` describing the strict `ResultModel`-based plugin adapter pattern, `ColumnSpec` usage, `selection_fn`, and `TableProviderMixin` for HTML table scraping.
- Add `docs/plugin_authoring.md` describing the strict `ResultModel`-based plugin adapter pattern, `ColumnSpec` usage, `selection_fn`, and `TablePluginMixin` for HTML table scraping.
- Link the new doc from `docs/result_table.md`.
- Add `tests/test_provider_author_examples.py` to validate the example plugin integration with the registry.
- Add plugin-author example coverage to validate the example plugin integration with the registry.
Why:
- Provide a short, focused Quick Start to help contributors author plugins that integrate with the strict ResultTable API.
@@ -5,16 +5,15 @@ ResultTable API: adapters yield `ResultModel` instances, and plugins register
via `SYS.result_table_adapters.register_plugin` with columns and a
`selection_fn`.
Note: this file keeps its historical `provider_authoring` name, but the public
terminology is plugin-first. Some internal classes and metadata fields still use
`Provider` naming.
The public terminology is plugin-first, even though some internal classes and
metadata fields still use `Provider` naming.
---
## Quick summary
- Plugins register a plugin adapter, a `columns` definition, and a `selection_fn`.
- `selection_fn` returns CLI args for a selected row.
- For HTML table or list scraping, prefer `TableProviderMixin` from `SYS.provider_helpers`.
- For HTML table or list scraping, prefer `TablePluginMixin` from `SYS.plugin_helpers`.
## Runtime dependency policy
- Treat required runtime dependencies such as Playwright as mandatory: import them unconditionally and let missing dependencies fail fast.
@@ -74,16 +73,16 @@ register_plugin("myplugin", adapter, columns=columns_factory, selection_fn=selec
---
## Table scraping with `TableProviderMixin`
## Table scraping with `TablePluginMixin`
If your plugin scrapes HTML tables or list-like results, use `TableProviderMixin`:
If your plugin scrapes HTML tables or list-like results, use `TablePluginMixin`:
```py
from ProviderCore.base import Provider
from SYS.provider_helpers import TableProviderMixin
from PluginCore.base import Provider
from SYS.plugin_helpers import TablePluginMixin
class MyTablePlugin(TableProviderMixin, Provider):
class MyTablePlugin(TablePluginMixin, Provider):
URL = ("https://example.org/search",)
def validate(self) -> bool:
@@ -94,8 +93,8 @@ class MyTablePlugin(TableProviderMixin, Provider):
return self.search_table_from_url(url, limit=limit)
```
`TableProviderMixin.search_table_from_url` returns
`ProviderCore.base.SearchResult` entries. If you want to integrate the plugin
`TablePluginMixin.search_table_from_url` returns
`PluginCore.base.SearchResult` entries. If you want to integrate the plugin
with the strict `ResultTable` registry, add a small adapter that converts
`SearchResult` to `ResultModel` and register it using `register_plugin`.
@@ -128,22 +127,22 @@ Example test skeleton:
```py
from SYS.result_table_adapters import get_plugin
from plugins import example_provider
from plugins import example_plugin
def test_example_plugin_registration():
plugin = get_plugin("example")
rows = list(plugin.adapter(example_provider.SAMPLE_ITEMS))
rows = list(plugin.adapter(example_plugin.SAMPLE_ITEMS))
assert rows and rows[0].title
cols = plugin.get_columns(rows)
assert any(col.name == "title" for col in cols)
table = plugin.build_table(example_provider.SAMPLE_ITEMS)
table = plugin.build_table(example_plugin.SAMPLE_ITEMS)
assert table.provider == "example" and table.rows
```
---
## References and examples
- Read `plugins/example_provider.py` for a compact example of a strict adapter and dynamic columns.
- Read `plugins/vimm/__init__.py` for a table-oriented plugin that uses `TableProviderMixin` and converts `SearchResult` to `ResultModel` for registration.
- See `docs/provider_guide.md` for a broader plugin development checklist.
- Read `plugins/example_plugin.py` for a compact example of a strict adapter and dynamic columns.
- Read `plugins/vimm/__init__.py` for a table-oriented plugin that uses `TablePluginMixin` and converts `SearchResult` to `ResultModel` for registration.
- See `docs/plugin_guide.md` for a broader plugin development checklist.
@@ -4,9 +4,8 @@
This guide describes how to write, test, and register a plugin so the
application can discover and use it as a pluggable component.
Note: this file keeps its historical `provider_guide` name, but the public
model is plugin-first. Some runtime classes still use `Provider` naming
internally.
The public model is plugin-first, even though the internal base class still
uses `Provider` naming.
Keep plugin code small, focused, and well-tested. Bundled plugins and drop-in
plugins share the same `plugins/` layout.
@@ -15,7 +14,7 @@ plugins share the same `plugins/` layout.
## Anatomy of a plugin
A plugin is a Python class that currently extends the internal base class
`ProviderCore.base.Provider` and implements a few key methods and attributes.
`PluginCore.base.Provider` and implements a few key methods and attributes.
Minimum expectations:
- `class MyPlugin(Provider):` subclasses the current internal base plugin class.
@@ -31,7 +30,7 @@ Optional but common:
---
## SearchResult
Use `ProviderCore.base.SearchResult` to describe results returned by `search()`.
Use `PluginCore.base.SearchResult` to describe results returned by `search()`.
Important fields:
- `table` (str): plugin table name
@@ -55,7 +54,7 @@ Return a list of `SearchResult(...)` objects or simple dicts convertible with `.
Example:
```python
from ProviderCore.base import Provider, SearchResult
from PluginCore.base import Provider, SearchResult
class HelloPlugin(Provider):
@@ -132,7 +131,7 @@ pytest -q
- Bundled plugins live under `plugins/` and are auto-discovered from that package.
- External plugins can be dropped into `plugins/` or any directory listed in `MM_PLUGIN_PATH` or `MEDEIA_PLUGIN_PATH`.
- Package directories are preferred so plugin-specific files travel with the plugin.
- Plugin authors should import from `ProviderCore.*`.
- Plugin authors should import from `PluginCore.*`.
If a plugin supports multiple configured endpoints or accounts, the user-facing
concept is a plugin instance. Some stored config still lives under legacy key
+1 -1
View File
@@ -181,4 +181,4 @@ another, such as artist to discography drill-in.
- ResultTable implementation: `SYS/result_table.py`
- Pipeline helpers: `SYS/pipeline.py`
- Row replay and selection flow: `SYS/pipeline.py`
- Plugin authoring guide: `docs/provider_authoring.md`
- Plugin authoring guide: `docs/plugin_authoring.md`