huge refactor of the entire codebase, with the goal of improving maintainability, readability, and extensibility. This commit includes changes to almost every file in the project, including:
This commit is contained in:
+12
-12
@@ -1,13 +1,13 @@
|
||||
# Provider authoring: ResultTable & provider adapters ✅
|
||||
# Plugin authoring: ResultTable & plugin adapters
|
||||
|
||||
This short guide explains how to write providers that integrate with the *strict* ResultTable API: adapters must yield `ResultModel` instances and providers register via `SYS.result_table_adapters.register_provider` with a column specification and a `selection_fn`.
|
||||
This short guide explains how to write plugins that integrate with the *strict* ResultTable API: adapters must yield `ResultModel` instances and plugins register via `SYS.result_table_adapters.register_plugin` with a column specification and a `selection_fn`.
|
||||
|
||||
---
|
||||
|
||||
## Quick summary
|
||||
|
||||
- Providers register a *provider adapter* (callable that yields `ResultModel`).
|
||||
- Providers must also provide `columns` (static list or factory) and a `selection_fn` that returns CLI args for a selected row.
|
||||
- Plugins register a *plugin adapter* (callable that yields `ResultModel`).
|
||||
- Plugins must also provide `columns` (static list or factory) and a `selection_fn` that returns CLI args for a selected row.
|
||||
- For simple HTML table/list scraping, prefer `TableProviderMixin` from `SYS.provider_helpers` to fetch and extract rows using `SYS.html_table.extract_records`.
|
||||
|
||||
## Runtime dependency policy
|
||||
@@ -21,11 +21,11 @@ This short guide explains how to write providers that integrate with the *strict
|
||||
## Minimal provider template (copy/paste)
|
||||
|
||||
```py
|
||||
# Provider/my_provider.py
|
||||
# plugins/my_plugin.py
|
||||
from typing import Any, Dict, Iterable, List
|
||||
|
||||
from SYS.result_table_api import ResultModel, ColumnSpec, title_column, metadata_column
|
||||
from SYS.result_table_adapters import register_provider
|
||||
from SYS.result_table_adapters import register_plugin
|
||||
|
||||
# Example adapter: convert provider-specific items into ResultModel instances
|
||||
SAMPLE_ITEMS = [
|
||||
@@ -59,8 +59,8 @@ def selection_fn(row: ResultModel) -> List[str]:
|
||||
return ["-path", row.path]
|
||||
return ["-title", row.title or ""]
|
||||
|
||||
# Register provider (done at import time)
|
||||
register_provider("myprovider", adapter, columns=columns_factory, selection_fn=selection_fn)
|
||||
# Register plugin (done at import time)
|
||||
register_plugin("myprovider", adapter, columns=columns_factory, selection_fn=selection_fn)
|
||||
```
|
||||
|
||||
---
|
||||
@@ -84,7 +84,7 @@ class MyTableProvider(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 this provider with the strict `ResultTable` registry, add a small adapter that converts `SearchResult` -> `ResultModel` and register it using `register_provider` (see `Provider/vimm.py` for a real example).
|
||||
`TableProviderMixin.search_table_from_url` returns `ProviderCore.base.SearchResult` entries. If you want to integrate this plugin with the strict `ResultTable` registry, add a small adapter that converts `SearchResult` -> `ResultModel` and register it using `register_plugin` (see `Provider/vimm.py` for a real example).
|
||||
|
||||
---
|
||||
|
||||
@@ -93,7 +93,7 @@ class MyTableProvider(TableProviderMixin, Provider):
|
||||
- `columns` may be a static `List[ColumnSpec]` or a factory `def cols(rows: List[ResultModel]) -> List[ColumnSpec]` that inspects sample rows.
|
||||
- `selection_fn` must accept a `ResultModel` and return a `List[str]` representing CLI args (e.g., `['-path', row.path]`). These args are used by `select` and `@N` expansion.
|
||||
|
||||
**Tip:** for providers that produce downloadable file rows prefer returning explicit URL args (e.g., `['-url', row.path]`) so the selected URL is clearly identified by downstream downloaders and to avoid ambiguous parsing when provider hints (like `-provider`) are present.
|
||||
**Tip:** for plugins that produce downloadable file rows prefer returning explicit URL args (e.g., `['-url', row.path]`) so the selected URL is clearly identified by downstream downloaders and to avoid ambiguous parsing when plugin hints (like `-plugin`) are present.
|
||||
- Ensure your `ResultModel.source` is set (either in the model or rely on the provider name set by `serialize_row`).
|
||||
|
||||
---
|
||||
@@ -107,7 +107,7 @@ class MyTableProvider(TableProviderMixin, Provider):
|
||||
## Testing & examples
|
||||
|
||||
- Write `tests/test_provider_<name>.py` that imports your provider and verifies `provider.build_table(...)` produces a `ResultTable` (has `.rows` and `.columns`) and that `serialize_rows()` yields dicts with `_selection_args`, `_selection_action` when applicable, and `source`.
|
||||
- When you need to guarantee a specific CLI stage sequence (e.g., `download-file -url <path> -provider <name>`), call `table.set_row_selection_action(row_index, tokens)` so the serialized payload emits `_selection_action` and the CLI can run the row exactly as intended.
|
||||
- When you need to guarantee a specific CLI stage sequence (e.g., `download-file -url <path> -plugin <name>`), call `table.set_row_selection_action(row_index, tokens)` so the serialized payload emits `_selection_action` and the CLI can run the row exactly as intended.
|
||||
- For table providers you can test `search_table_from_url` using a local HTML fixture or by mocking `HTTPClient` to return a small sample page.
|
||||
- If you rely on pandas, add a test that monkeypatches `sys.modules['pandas']` to a simple shim to validate the pandas path.
|
||||
|
||||
@@ -119,7 +119,7 @@ from Provider import example_provider
|
||||
|
||||
|
||||
def test_example_provider_registration():
|
||||
provider = get_provider("example")
|
||||
plugin = get_plugin("example")
|
||||
rows = list(provider.adapter(example_provider.SAMPLE_ITEMS))
|
||||
assert rows and rows[0].title
|
||||
cols = provider.get_columns(rows)
|
||||
|
||||
Reference in New Issue
Block a user