Enforce plugin contract purity: single import surface via shopdb.api
Plugins were reaching into internal core paths (shopdb.core.models.*, shopdb.extensions, shopdb.utils.*), coupling them to core's file layout and violating the ADR-001 contract. Consolidate onto one versioned surface. - shopdb.api: expand from 2 helpers to the full plugin import surface - db, cache; BaseModel, AuditMixin; core models (Asset, AssetType, AssetStatus, Vendor, Model, Communication, CommunicationType, Location, Setting, AuditLog, Application, AppVersion, OperatingSystem); response + pagination helpers; employee_connection. Documented in PLUGIN-HOOKS.md. - Migrate all 22 plugin source files to import only from shopdb.api (plus shopdb.plugins.base for the ABC). - Drop the printers plugin's legacy MachineType dependency: remove _ensure_legacy_machine_types and the seed_supplies machinetypeid lookup (Model.machinetypeid is nullable; printers carry type via PrinterType). - Guard test test_plugins_only_import_contract_surface scans plugin source and fails on any core import outside shopdb.api / shopdb.plugins.base. - Scaffold templates updated so generated plugins are contract-pure. - Bump __contract_version__ 0.2.0 -> 0.3.0 (additive surface expansion; manifests pin <1.0.0 so they still satisfy). 145 tests pass, naming/style green, app factory boots all 6 plugins. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,47 @@ Setting helpers are exposed via BasePlugin instance methods
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from shopdb.core.models import AuditLog
|
||||
# -- Plugin contract surface (ADR-001, versioned per ADR-002) ----------------
|
||||
# Everything a plugin is allowed to import from the core lives here. Plugins
|
||||
# import these from `shopdb.api`, never from internal paths like
|
||||
# `shopdb.core.models.*` or `shopdb.extensions`. The contract test
|
||||
# (tests/test_plugin_contract.py) enforces this. Adding a name here is an
|
||||
# additive (minor) contract change; removing one is breaking (major).
|
||||
|
||||
# Infrastructure
|
||||
from shopdb.extensions import db, cache
|
||||
|
||||
# Model base classes for declaring plugin tables
|
||||
from shopdb.core.models.base import BaseModel, AuditMixin
|
||||
|
||||
# Core domain models plugins legitimately reference (the asset contract)
|
||||
from shopdb.core.models import (
|
||||
Asset,
|
||||
AssetType,
|
||||
AssetStatus,
|
||||
Vendor,
|
||||
Model,
|
||||
Communication,
|
||||
CommunicationType,
|
||||
Location,
|
||||
Setting,
|
||||
AuditLog,
|
||||
Application,
|
||||
AppVersion,
|
||||
OperatingSystem,
|
||||
)
|
||||
|
||||
# Response + pagination helpers for plugin API blueprints
|
||||
from shopdb.utils.responses import (
|
||||
success_response,
|
||||
error_response,
|
||||
paginated_response,
|
||||
ErrorCodes,
|
||||
)
|
||||
from shopdb.utils.pagination import get_pagination_params, paginate_query
|
||||
|
||||
# Legacy employee directory lookup (read-only) used by notifications
|
||||
from shopdb.utils.employee_db import employee_connection
|
||||
|
||||
|
||||
def audit_log(
|
||||
@@ -155,4 +195,37 @@ def resolve_asset_position(asset) -> Optional[Dict[str, Any]]:
|
||||
return None
|
||||
|
||||
|
||||
__all__ = ['audit_log', 'resolve_asset_position']
|
||||
__all__ = [
|
||||
# Helpers
|
||||
'audit_log',
|
||||
'resolve_asset_position',
|
||||
# Infrastructure
|
||||
'db',
|
||||
'cache',
|
||||
# Model bases
|
||||
'BaseModel',
|
||||
'AuditMixin',
|
||||
# Core models
|
||||
'Asset',
|
||||
'AssetType',
|
||||
'AssetStatus',
|
||||
'Vendor',
|
||||
'Model',
|
||||
'Communication',
|
||||
'CommunicationType',
|
||||
'Location',
|
||||
'Setting',
|
||||
'AuditLog',
|
||||
'Application',
|
||||
'AppVersion',
|
||||
'OperatingSystem',
|
||||
# Response + pagination helpers
|
||||
'success_response',
|
||||
'error_response',
|
||||
'paginated_response',
|
||||
'ErrorCodes',
|
||||
'get_pagination_params',
|
||||
'paginate_query',
|
||||
# Legacy employee directory
|
||||
'employee_connection',
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user