refactor: remove per-type module.py and simplify plugin wiring

This commit is contained in:
Jage9
2026-02-24 18:56:42 -05:00
parent fcb5e85b13
commit 3c52d35983
27 changed files with 75 additions and 366 deletions

View File

@@ -7,7 +7,6 @@ This is a reference layout for adding a new server item type plugin.
- `definition.py`: static metadata/defaults/schema constants. - `definition.py`: static metadata/defaults/schema constants.
- `validator.py`: `validate_update(item, next_params)` normalization and validation. - `validator.py`: `validate_update(item, next_params)` normalization and validation.
- `actions.py`: `use_item(item, nickname, clock_formatter)` runtime behavior. - `actions.py`: `use_item(item, nickname, clock_formatter)` runtime behavior.
- `module.py`: thin exported surface combining the three files.
- `plugin.py`: registration payload consumed by plugin auto-discovery. - `plugin.py`: registration payload consumed by plugin auto-discovery.
Use this folder as a copy template when creating a real item under: Use this folder as a copy template when creating a real item under:

View File

@@ -1,20 +0,0 @@
"""Counter item plugin module surface."""
from __future__ import annotations
from .actions import use_item
from .definition import (
CAPABILITIES,
DEFAULT_PARAMS,
DEFAULT_TITLE,
DIRECTIONAL,
EDITABLE_PROPERTIES,
EMIT_RANGE,
EMIT_SOUND,
LABEL,
PROPERTY_METADATA,
TOOLTIP,
USE_COOLDOWN_MS,
USE_SOUND,
)
from .validator import validate_update

View File

@@ -2,10 +2,11 @@
from __future__ import annotations from __future__ import annotations
from . import module from ..plugin_helpers import build_item_module
from . import actions, definition, validator
ITEM_TYPE_PLUGIN = { ITEM_TYPE_PLUGIN = {
"type": "counter", "type": "counter",
"order": 25, "order": 25,
"module": module, "module": build_item_module(definition, validate_update=validator.validate_update, use_item=actions.use_item),
} }

View File

@@ -49,7 +49,7 @@
- Persisted state stores only instance data. - Persisted state stores only instance data.
- Global/type-level properties are loaded from server registry in `server/app/item_catalog.py`. - Global/type-level properties are loaded from server registry in `server/app/item_catalog.py`.
- Per-type use/update validation and message behavior are implemented in per-item modules under `server/app/items/types/*/module.py`, discovered via plugins in `server/app/items/types/*/plugin.py`. - Per-type use/update validation and message behavior are implemented in per-item modules under `server/app/items/types/*/definition.py`, `validator.py`, and `actions.py`, discovered via plugins in `server/app/items/types/*/plugin.py`.
- Client-side add/edit metadata is consumed from `welcome.uiDefinitions` via `client/src/items/itemRegistry.ts` (no local fallback definitions). - Client-side add/edit metadata is consumed from `welcome.uiDefinitions` via `client/src/items/itemRegistry.ts` (no local fallback definitions).
- End-to-end add-item template: `docs/item-type-template.md`. - End-to-end add-item template: `docs/item-type-template.md`.

View File

@@ -11,7 +11,6 @@ When adding a new item type:
- `definition.py` for metadata/constants - `definition.py` for metadata/constants
- `validator.py` for `validate_update(item, next_params)` - `validator.py` for `validate_update(item, next_params)`
- `actions.py` for `use_item(item, nickname, clock_formatter)` - `actions.py` for `use_item(item, nickname, clock_formatter)`
- `module.py` as thin exported surface
- `plugin.py` for registration - `plugin.py` for registration
2. Server plugin file 2. Server plugin file
@@ -20,11 +19,9 @@ When adding a new item type:
- `order` - `order`
- `module` - `module`
3. Shared item-type unions 3. Shared type acceptance
- Add the type in: - Item type ids are string-based in protocol/state models.
- `server/app/models.py` - For generic new types, no enum/union list updates are required.
- `client/src/network/protocol.ts`
- `client/src/state/gameState.ts`
4. Client runtime behavior (optional) 4. Client runtime behavior (optional)
- Default: no item-specific client module needed. - Default: no item-specific client module needed.
@@ -34,14 +31,19 @@ That is enough for a first working item type.
## Reference Sample Folder ## Reference Sample Folder
See `docs/examples/item-type-sample/` for a complete copyable folder with all five files. See `docs/examples/item-type-sample/` for a complete copyable folder.
## Minimal `module.py` Example ## Minimal `plugin.py` Example
```py ```py
from .actions import use_item from ..plugin_helpers import build_item_module
from .definition import LABEL, TOOLTIP, EDITABLE_PROPERTIES, CAPABILITIES, USE_SOUND, EMIT_SOUND, USE_COOLDOWN_MS, EMIT_RANGE, DIRECTIONAL, DEFAULT_TITLE, DEFAULT_PARAMS, PROPERTY_METADATA from . import actions, definition, validator
from .validator import validate_update
ITEM_TYPE_PLUGIN = {
"type": "counter",
"order": 25,
"module": build_item_module(definition, validate_update=validator.validate_update, use_item=actions.use_item),
}
``` ```
## Checklist Before Commit ## Checklist Before Commit

View File

@@ -197,14 +197,12 @@ For a full copy/paste example with plain-English explanation, see `docs/item-typ
- `definition.py` (defaults/capabilities/metadata/options) - `definition.py` (defaults/capabilities/metadata/options)
- `validator.py` (`validate_update`) - `validator.py` (`validate_update`)
- `actions.py` (`use_item`) - `actions.py` (`use_item`)
- `module.py` (thin exported surface)
2. Server plugin: add `server/app/items/types/<item_type>/plugin.py` exporting `ITEM_TYPE_PLUGIN` with: 2. Server plugin: add `server/app/items/types/<item_type>/plugin.py` exporting `ITEM_TYPE_PLUGIN` with:
- `type` - `type`
- `order` - `order`
- `module` - `module`
The server auto-discovers plugins at boot, so no central registry edit is needed. The server auto-discovers plugins at boot, so no central registry edit is needed.
3. Server models: extend `ItemType` literals in `server/app/models.py` and any packet enums that list item types. 3. Server/client protocol/state models are now string-based for item type ids; for generic types no enum/union list updates are required.
4. Client protocol/state types: update item-type unions in `client/src/network/protocol.ts` and `client/src/state/gameState.ts`.
5. Client runtime behavior: add `client/src/items/types/<item_type>/behavior.ts` only if custom client runtime is needed (for example piano mode). 5. Client runtime behavior: add `client/src/items/types/<item_type>/behavior.ts` only if custom client runtime is needed (for example piano mode).
6. Tests: add or update server tests under `server/tests/` for use/update validation, unknown-key stripping, and `uiDefinitions` completeness. 6. Tests: add or update server tests under `server/tests/` for use/update validation, unknown-key stripping, and `uiDefinitions` completeness.

View File

@@ -285,7 +285,8 @@ When adding a new item type:
- Missing/invalid schema now disables item menus with explicit status. - Missing/invalid schema now disables item menus with explicit status.
- Phase 4: - Phase 4:
- Property editor behavior is metadata-driven by `valueType/range/options/maxLength`. - Property editor behavior is metadata-driven by `valueType/range/options/maxLength`.
- `visibleWhen` is supported and item property rows recompute live after updates. - `visibleWhen` now survives protocol parsing and item property rows recompute live after updates.
- List options are now carried in `propertyMetadata[key].options` (no separate `propertyOptions` map).
- Phase 5: - Phase 5:
- Client runtime behavior remains modular per item via behavior registry; `main.ts` orchestration no longer carries item-specific business branches. - Client runtime behavior remains modular per item via behavior registry; `main.ts` orchestration no longer carries item-specific business branches.
- Phase 6: - Phase 6:
@@ -294,11 +295,16 @@ When adding a new item type:
- Save timing now configurable via: - Save timing now configurable via:
- `storage.state_save_debounce_ms` - `storage.state_save_debounce_ms`
- `storage.state_save_max_delay_ms` - `storage.state_save_max_delay_ms`
- Additional:
- Added plugin contract tests to validate required item package files/exports.
- Added unknown-item-type rejection for `item_add`.
- Added `capabilities` in `welcome.uiDefinitions.itemTypes`.
- Removed hardcoded client/server item-type enum restrictions (string-based ids + runtime known-type checks).
### Notes ### Notes
- Client item-specific runtime is now reduced to only `piano`; simple items (`dice`, `wheel`, `clock`, `radio_station`, `widget`) run through generic client flows with no custom behavior module. - Client item-specific runtime is now reduced to only `piano`; simple items (`dice`, `wheel`, `clock`, `radio_station`, `widget`) run through generic client flows with no custom behavior module.
- Server item implementations now live inside per-type folders (`server/app/items/types/*/module.py`) and plugins point directly to those modules. - Server item implementations now live inside per-type folders (`server/app/items/types/*/definition.py`, `validator.py`, `actions.py`).
- Server type packages are now split into `definition.py` / `validator.py` / `actions.py` plus a thin `module.py` export surface. - Plugins now compose module surfaces via a shared helper (`server/app/items/types/plugin_helpers.py`), so per-type `module.py` is no longer required.
- Added docs sample folder at `docs/examples/item-type-sample/` and updated template docs to reflect the package layout. - Added docs sample folder at `docs/examples/item-type-sample/` and updated template docs to reflect the package layout.
## Completion Review (2026-02-24) ## Completion Review (2026-02-24)
@@ -306,64 +312,11 @@ When adding a new item type:
- **Phase 0 (docs + guardrails):** ✅ Complete. `docs/item-schema.md` exists and server tests cover UI schema completeness + unknown-key stripping behavior. - **Phase 0 (docs + guardrails):** ✅ Complete. `docs/item-schema.md` exists and server tests cover UI schema completeness + unknown-key stripping behavior.
- **Phase 1 (server package standardization + auto-discovery):** ✅ Complete. Item types are standardized under `server/app/items/types/*` with `plugin.py` entrypoints and discovered by `server/app/items/registry.py`. - **Phase 1 (server package standardization + auto-discovery):** ✅ Complete. Item types are standardized under `server/app/items/types/*` with `plugin.py` entrypoints and discovered by `server/app/items/registry.py`.
- **Phase 2 (strict validation + unknown-key stripping):** ✅ Complete. Type validators enforce allowed keys and normalize values; tests verify unknown params are stripped. - **Phase 2 (strict validation + unknown-key stripping):** ✅ Complete. Type validators enforce allowed keys and normalize values; tests verify unknown params are stripped.
- **Phase 3 (client removes fallback authority):** ✅ Mostly complete. Client consumes `welcome.uiDefinitions` and disables item menus when schema is missing. - **Phase 3 (client removes fallback authority):** ✅ Complete. Client consumes `welcome.uiDefinitions` and disables item menus when schema is missing.
- **Phase 4 (metadata-driven editor + visibility dependencies):** ⚠️ Partially complete. Generic metadata-driven editing is in place, but `visibleWhen` is not included in the client protocol schema, so dependency visibility rules from server metadata are dropped during message validation. - **Phase 4 (metadata-driven editor + visibility dependencies):** ✅ Complete. Generic metadata-driven editing is in place and `visibleWhen` survives client protocol parsing.
- **Phase 5 (behavior registry completion):** ✅ Complete. Runtime behavior is registry-driven with generic path + optional piano module. - **Phase 5 (behavior registry completion):** ✅ Complete. Runtime behavior is registry-driven with generic path + optional piano module.
- **Phase 6 (coalesced persistence):** ✅ Complete. Debounced/max-delay state save and flush-on-shutdown are implemented in server lifecycle. - **Phase 6 (coalesced persistence):** ✅ Complete. Debounced/max-delay state save and flush-on-shutdown are implemented in server lifecycle.
### Recommendations / Cleanup (for simplest new-item creation) ### Recommendations / Cleanup (remaining)
1. **Unblock `visibleWhen` end-to-end (high priority).** 1. **Eliminate manual property label mapping in client (medium):** either include labels for all properties in server metadata or auto-humanize keys so new properties are readable without code changes.
Scope: 2. **Strengthen new-item completeness checks (low):** extend the plugin contract tests to optionally assert docs coverage and richer protocol examples per discovered type.
- Carry `visibleWhen` from server metadata through client protocol validation into `itemRegistry`.
Problem today:
- Server emits `visibleWhen`, but client protocol schema drops unknown metadata fields, so dependency visibility can silently fail.
Implementation:
- Update `client/src/network/protocol.ts` `welcome.uiDefinitions.itemTypes[].propertyMetadata` schema to allow `visibleWhen` object values of `string | number | boolean`.
- Keep `client/src/items/itemRegistry.ts` normalization strict (ignore invalid `visibleWhen` entries).
- Add a client test/fixture (or lightweight runtime assertion) that confirms `visibleWhen` survives parse.
Acceptance criteria:
- For a property like `facing` with `visibleWhen: { directional: true }`, toggling `directional` updates property visibility without hardcoded client logic.
2. **Remove hardcoded item-type literals (high priority).**
Scope:
- Reduce manual edits needed when adding a new item type.
Problem today:
- Type additions still touch multiple literal lists (`Literal[...]`, unions, enums) across server/client protocol/state models.
Implementation:
- Server:
- Keep runtime source of truth in plugin registry.
- Limit literal usage to protocol boundary where needed; validate item type membership against discovered registry set.
- Client:
- Replace rigid item-type enums in parse paths with string + runtime membership checks from server-provided definitions where feasible.
- Keep compile-time unions only where they materially improve safety and can be generated/centralized.
Acceptance criteria:
- Adding a new item plugin does not require editing multiple type-literal lists in unrelated files.
- New type appears in add/edit flows after server metadata update with minimal client changes.
3. **Include `capabilities` in `welcome.uiDefinitions.itemTypes` (medium).**
Scope:
- Complete server metadata contract for item UI/runtime decisions.
Problem today:
- `capabilities` exist on `WorldItem`, but not consistently in type definition metadata payload for menu/rules decisions.
Implementation:
- Add `capabilities` per item type in server `uiDefinitions.itemTypes[]` payload.
- Parse/store on client registry model.
- Use this metadata for UI gating where applicable (for example, show/hide unsupported actions for a type).
Acceptance criteria:
- Client can decide type-level action affordances from `uiDefinitions` alone, without extra hardcoded assumptions.
4. **Move list options into per-property metadata (medium).**
Scope:
- Consolidate split item property config sources.
Problem today:
- Options are split between `propertyOptions` and `propertyMetadata`, causing parallel maintenance.
Implementation:
- Server emits list options at `propertyMetadata[key].options`.
- Client reads options from metadata first.
- Remove separate `propertyOptions` map.
Acceptance criteria:
- One canonical place (`propertyMetadata`) defines type, range, tooltip, options, and visibility for each property.
- New list property requires server-only metadata changes for options.
5. **Eliminate manual property label mapping in client (medium):** either include labels in server metadata or auto-humanize keys so new properties are readable without code changes.
6. **Add a script/check for “new item completeness” (low):** one CI check that verifies plugin discovery, protocol acceptance, docs presence, and test coverage for each discovered type.

View File

@@ -1,3 +1 @@
"""Item type package exposing plugin module surface.""" """Clock item type plugin package."""
from .module import * # noqa: F401,F403

View File

@@ -1,41 +0,0 @@
"""Clock item plugin module surface."""
from __future__ import annotations
from .actions import use_item
from .definition import (
CAPABILITIES,
DEFAULT_PARAMS,
DEFAULT_TIME_ZONE,
DEFAULT_TITLE,
DIRECTIONAL,
EDITABLE_PROPERTIES,
EMIT_RANGE,
EMIT_SOUND,
LABEL,
PROPERTY_METADATA,
TIME_ZONE_OPTIONS,
TOOLTIP,
USE_COOLDOWN_MS,
USE_SOUND,
)
from .validator import validate_update
__all__ = [
"LABEL",
"TOOLTIP",
"EDITABLE_PROPERTIES",
"CAPABILITIES",
"USE_SOUND",
"EMIT_SOUND",
"USE_COOLDOWN_MS",
"EMIT_RANGE",
"DIRECTIONAL",
"DEFAULT_TITLE",
"DEFAULT_TIME_ZONE",
"TIME_ZONE_OPTIONS",
"DEFAULT_PARAMS",
"PROPERTY_METADATA",
"validate_update",
"use_item",
]

View File

@@ -2,10 +2,11 @@
from __future__ import annotations from __future__ import annotations
from . import module from ..plugin_helpers import build_item_module
from . import actions, definition, validator
ITEM_TYPE_PLUGIN = { ITEM_TYPE_PLUGIN = {
"type": "clock", "type": "clock",
"order": 10, "order": 10,
"module": module, "module": build_item_module(definition, validate_update=validator.validate_update, use_item=actions.use_item),
} }

View File

@@ -1,3 +1 @@
"""Item type package exposing plugin module surface.""" """Dice item type plugin package."""
from .module import * # noqa: F401,F403

View File

@@ -1,37 +0,0 @@
"""Dice item plugin module surface."""
from __future__ import annotations
from .actions import use_item
from .definition import (
CAPABILITIES,
DEFAULT_PARAMS,
DEFAULT_TITLE,
DIRECTIONAL,
EDITABLE_PROPERTIES,
EMIT_RANGE,
EMIT_SOUND,
LABEL,
PROPERTY_METADATA,
TOOLTIP,
USE_COOLDOWN_MS,
USE_SOUND,
)
from .validator import validate_update
__all__ = [
"LABEL",
"TOOLTIP",
"EDITABLE_PROPERTIES",
"CAPABILITIES",
"USE_SOUND",
"EMIT_SOUND",
"USE_COOLDOWN_MS",
"EMIT_RANGE",
"DIRECTIONAL",
"DEFAULT_TITLE",
"DEFAULT_PARAMS",
"PROPERTY_METADATA",
"validate_update",
"use_item",
]

View File

@@ -2,10 +2,11 @@
from __future__ import annotations from __future__ import annotations
from . import module from ..plugin_helpers import build_item_module
from . import actions, definition, validator
ITEM_TYPE_PLUGIN = { ITEM_TYPE_PLUGIN = {
"type": "dice", "type": "dice",
"order": 20, "order": 20,
"module": module, "module": build_item_module(definition, validate_update=validator.validate_update, use_item=actions.use_item),
} }

View File

@@ -1,3 +1 @@
"""Item type package exposing plugin module surface.""" """Piano item type plugin package."""
from .module import * # noqa: F401,F403

View File

@@ -1,41 +0,0 @@
"""Piano item plugin module surface."""
from __future__ import annotations
from .actions import use_item
from .definition import (
CAPABILITIES,
DEFAULT_PARAMS,
DEFAULT_TITLE,
DIRECTIONAL,
EDITABLE_PROPERTIES,
EMIT_RANGE,
EMIT_SOUND,
INSTRUMENT_OPTIONS,
LABEL,
PROPERTY_METADATA,
TOOLTIP,
USE_COOLDOWN_MS,
USE_SOUND,
VOICE_MODE_OPTIONS,
)
from .validator import validate_update
__all__ = [
"LABEL",
"TOOLTIP",
"EDITABLE_PROPERTIES",
"CAPABILITIES",
"USE_SOUND",
"EMIT_SOUND",
"USE_COOLDOWN_MS",
"EMIT_RANGE",
"DIRECTIONAL",
"DEFAULT_TITLE",
"DEFAULT_PARAMS",
"PROPERTY_METADATA",
"INSTRUMENT_OPTIONS",
"VOICE_MODE_OPTIONS",
"validate_update",
"use_item",
]

View File

@@ -2,10 +2,11 @@
from __future__ import annotations from __future__ import annotations
from . import module from ..plugin_helpers import build_item_module
from . import actions, definition, validator
ITEM_TYPE_PLUGIN = { ITEM_TYPE_PLUGIN = {
"type": "piano", "type": "piano",
"order": 30, "order": 30,
"module": module, "module": build_item_module(definition, validate_update=validator.validate_update, use_item=actions.use_item),
} }

View File

@@ -0,0 +1,19 @@
"""Helpers for composing item plugin module surfaces."""
from __future__ import annotations
from types import SimpleNamespace
from typing import Any
def build_item_module(definition: Any, *, validate_update: Any, use_item: Any) -> Any:
"""Compose a plugin module-like object from split definition/validator/actions files."""
exports: dict[str, Any] = {
name: getattr(definition, name)
for name in dir(definition)
if name.isupper()
}
exports["validate_update"] = validate_update
exports["use_item"] = use_item
return SimpleNamespace(**exports)

View File

@@ -1,3 +1 @@
"""Item type package exposing plugin module surface.""" """Radio station item type plugin package."""
from .module import * # noqa: F401,F403

View File

@@ -1,41 +0,0 @@
"""Radio item plugin module surface."""
from __future__ import annotations
from .actions import use_item
from .definition import (
CAPABILITIES,
CHANNEL_OPTIONS,
DEFAULT_PARAMS,
DEFAULT_TITLE,
DIRECTIONAL,
EDITABLE_PROPERTIES,
EFFECT_OPTIONS,
EMIT_RANGE,
EMIT_SOUND,
LABEL,
PROPERTY_METADATA,
TOOLTIP,
USE_COOLDOWN_MS,
USE_SOUND,
)
from .validator import validate_update
__all__ = [
"LABEL",
"TOOLTIP",
"EDITABLE_PROPERTIES",
"CAPABILITIES",
"USE_SOUND",
"EMIT_SOUND",
"USE_COOLDOWN_MS",
"EMIT_RANGE",
"DIRECTIONAL",
"DEFAULT_TITLE",
"DEFAULT_PARAMS",
"PROPERTY_METADATA",
"CHANNEL_OPTIONS",
"EFFECT_OPTIONS",
"validate_update",
"use_item",
]

View File

@@ -2,10 +2,11 @@
from __future__ import annotations from __future__ import annotations
from . import module from ..plugin_helpers import build_item_module
from . import actions, definition, validator
ITEM_TYPE_PLUGIN = { ITEM_TYPE_PLUGIN = {
"type": "radio_station", "type": "radio_station",
"order": 40, "order": 40,
"module": module, "module": build_item_module(definition, validate_update=validator.validate_update, use_item=actions.use_item),
} }

View File

@@ -1,3 +1 @@
"""Item type package exposing plugin module surface.""" """Wheel item type plugin package."""
from .module import * # noqa: F401,F403

View File

@@ -1,37 +0,0 @@
"""Wheel item plugin module surface."""
from __future__ import annotations
from .actions import use_item
from .definition import (
CAPABILITIES,
DEFAULT_PARAMS,
DEFAULT_TITLE,
DIRECTIONAL,
EDITABLE_PROPERTIES,
EMIT_RANGE,
EMIT_SOUND,
LABEL,
PROPERTY_METADATA,
TOOLTIP,
USE_COOLDOWN_MS,
USE_SOUND,
)
from .validator import validate_update
__all__ = [
"LABEL",
"TOOLTIP",
"EDITABLE_PROPERTIES",
"CAPABILITIES",
"USE_SOUND",
"EMIT_SOUND",
"USE_COOLDOWN_MS",
"EMIT_RANGE",
"DIRECTIONAL",
"DEFAULT_TITLE",
"DEFAULT_PARAMS",
"PROPERTY_METADATA",
"validate_update",
"use_item",
]

View File

@@ -2,10 +2,11 @@
from __future__ import annotations from __future__ import annotations
from . import module from ..plugin_helpers import build_item_module
from . import actions, definition, validator
ITEM_TYPE_PLUGIN = { ITEM_TYPE_PLUGIN = {
"type": "wheel", "type": "wheel",
"order": 50, "order": 50,
"module": module, "module": build_item_module(definition, validate_update=validator.validate_update, use_item=actions.use_item),
} }

View File

@@ -1,3 +1 @@
"""Item type package exposing plugin module surface.""" """Widget item type plugin package."""
from .module import * # noqa: F401,F403

View File

@@ -1,39 +0,0 @@
"""Widget item plugin module surface."""
from __future__ import annotations
from .actions import use_item
from .definition import (
CAPABILITIES,
DEFAULT_PARAMS,
DEFAULT_TITLE,
DIRECTIONAL,
EDITABLE_PROPERTIES,
EFFECT_OPTIONS,
EMIT_RANGE,
EMIT_SOUND,
LABEL,
PROPERTY_METADATA,
TOOLTIP,
USE_COOLDOWN_MS,
USE_SOUND,
)
from .validator import validate_update
__all__ = [
"LABEL",
"TOOLTIP",
"EDITABLE_PROPERTIES",
"CAPABILITIES",
"USE_SOUND",
"EMIT_SOUND",
"USE_COOLDOWN_MS",
"EMIT_RANGE",
"DIRECTIONAL",
"DEFAULT_TITLE",
"DEFAULT_PARAMS",
"PROPERTY_METADATA",
"EFFECT_OPTIONS",
"validate_update",
"use_item",
]

View File

@@ -2,10 +2,11 @@
from __future__ import annotations from __future__ import annotations
from . import module from ..plugin_helpers import build_item_module
from . import actions, definition, validator
ITEM_TYPE_PLUGIN = { ITEM_TYPE_PLUGIN = {
"type": "widget", "type": "widget",
"order": 60, "order": 60,
"module": module, "module": build_item_module(definition, validate_update=validator.validate_update, use_item=actions.use_item),
} }

View File

@@ -28,5 +28,4 @@ def test_item_plugin_folders_have_required_files() -> None:
assert (type_dir / "definition.py").is_file() assert (type_dir / "definition.py").is_file()
assert (type_dir / "validator.py").is_file() assert (type_dir / "validator.py").is_file()
assert (type_dir / "actions.py").is_file() assert (type_dir / "actions.py").is_file()
assert (type_dir / "module.py").is_file()
assert (type_dir / "plugin.py").is_file() assert (type_dir / "plugin.py").is_file()