From 3b08a47dcb9e0cdff5c80944a6d1a652b7005182 Mon Sep 17 00:00:00 2001 From: pavsoss Date: Mon, 13 Jul 2026 04:11:21 -0400 Subject: [PATCH] declare explicit __all__ for wildcard-re-exporting packages --- agentwatch/adapters/__init__.py | 14 ++++++++ agentwatch/alerting/__init__.py | 5 +++ agentwatch/core/__init__.py | 28 +++++++++++++++ agentwatch/cost/__init__.py | 6 ++++ agentwatch/governance/__init__.py | 12 +++++++ agentwatch/memory/__init__.py | 11 ++++++ agentwatch/orchestration/__init__.py | 10 ++++++ agentwatch/plugins/__init__.py | 5 +++ agentwatch/reasoning/__init__.py | 7 ++++ agentwatch/replay/__init__.py | 11 ++++++ agentwatch/rollback/__init__.py | 10 ++++++ agentwatch/scoring/__init__.py | 14 ++++++++ agentwatch/tracing/__init__.py | 6 ++++ pyproject.toml | 5 +-- tests/test_package_exports.py | 54 ++++++++++++++++++++++++++++ 15 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 tests/test_package_exports.py diff --git a/agentwatch/adapters/__init__.py b/agentwatch/adapters/__init__.py index c908910b..7aab4789 100644 --- a/agentwatch/adapters/__init__.py +++ b/agentwatch/adapters/__init__.py @@ -6,3 +6,17 @@ from agentwatch.adapters.openai_agents import * # noqa: F401, F403 from agentwatch.adapters.openclaw import * # noqa: F401, F403 from agentwatch.adapters.smolagents import * # noqa: F401, F403 + +__all__ = [ + "AutoGenAdapter", + "AutoGPTAdapter", + "ClaudeCodeEventParser", + "ClaudeCodeAdapter", + "watch_claude_code", + "AgentWatchCallbackHandler", + "create_langchain_handler", + "LangGraphAdapter", + "AgentWatchOpenAIAgentsAdapter", + "OpenClawAdapter", + "SmolagentsAdapter", +] diff --git a/agentwatch/alerting/__init__.py b/agentwatch/alerting/__init__.py index d2d0e309..13819ed7 100644 --- a/agentwatch/alerting/__init__.py +++ b/agentwatch/alerting/__init__.py @@ -1 +1,6 @@ from agentwatch.alerting.engine import * + +__all__ = [ + "AlertingConfig", + "AlertingEngine", +] diff --git a/agentwatch/core/__init__.py b/agentwatch/core/__init__.py index 6c31a798..8fb34189 100644 --- a/agentwatch/core/__init__.py +++ b/agentwatch/core/__init__.py @@ -7,3 +7,31 @@ SafetyPolicy, ) from agentwatch.core.schema import * + +__all__ = [ + "EventBus", + "EventFilter", + "get_event_bus", + "DEFAULT_POLICY", + "RiskPattern", + "RiskScorer", + "SafetyEngine", + "SafetyPolicy", + "EventType", + "RiskLevel", + "AgentFramework", + "ExecutionStatus", + "TokenUsage", + "ToolCallData", + "ToolResultData", + "SafetyCheckData", + "MemoryData", + "ConfidenceData", + "AgentMessageData", + "CheckpointData", + "AgentEvent", + "AgentSession", + "TaskNode", + "PluginPermissions", + "PluginManifest", +] diff --git a/agentwatch/cost/__init__.py b/agentwatch/cost/__init__.py index 88ff6865..3899f294 100644 --- a/agentwatch/cost/__init__.py +++ b/agentwatch/cost/__init__.py @@ -1,2 +1,8 @@ from agentwatch.cost.semantic_cache import SemanticCache from agentwatch.cost.tracker import * + +__all__ = [ + "SemanticCache", + "SessionBudget", + "CostTracker", +] diff --git a/agentwatch/governance/__init__.py b/agentwatch/governance/__init__.py index 8d208a7e..46027efa 100644 --- a/agentwatch/governance/__init__.py +++ b/agentwatch/governance/__init__.py @@ -1,2 +1,14 @@ from agentwatch.governance.compliance_reporter import * from agentwatch.governance.engine import * + +__all__ = [ + "ComplianceReport", + "ComplianceReporter", + "Permission", + "AuditEventType", + "Role", + "Principal", + "AuditEntry", + "BUILTIN_ROLES", + "GovernanceEngine", +] diff --git a/agentwatch/memory/__init__.py b/agentwatch/memory/__init__.py index 01c4ffcd..f265d871 100644 --- a/agentwatch/memory/__init__.py +++ b/agentwatch/memory/__init__.py @@ -1 +1,12 @@ from agentwatch.memory.engine import * + +__all__ = [ + "MemoryType", + "ImportanceLevel", + "MemoryEntry", + "MemorySearchResult", + "ContradictionReport", + "EmbeddingProvider", + "MemoryStore", + "MemoryEngine", +] diff --git a/agentwatch/orchestration/__init__.py b/agentwatch/orchestration/__init__.py index 564ba559..d1817dc4 100644 --- a/agentwatch/orchestration/__init__.py +++ b/agentwatch/orchestration/__init__.py @@ -1 +1,11 @@ from agentwatch.orchestration.engine import * + +__all__ = [ + "AgentRole", + "MessageType", + "AgentMessage", + "SubAgent", + "TaskGraph", + "SharedMemoryBus", + "OrchestrationEngine", +] diff --git a/agentwatch/plugins/__init__.py b/agentwatch/plugins/__init__.py index c82a8ca7..491926e1 100644 --- a/agentwatch/plugins/__init__.py +++ b/agentwatch/plugins/__init__.py @@ -1 +1,6 @@ from agentwatch.plugins.sandbox import * + +__all__ = [ + "SandboxViolationError", + "PermissionEnforcer", +] diff --git a/agentwatch/reasoning/__init__.py b/agentwatch/reasoning/__init__.py index e8895610..79dbe2f9 100644 --- a/agentwatch/reasoning/__init__.py +++ b/agentwatch/reasoning/__init__.py @@ -1 +1,8 @@ from agentwatch.reasoning.auditor import * + +__all__ = [ + "JudgeCallback", + "StepAudit", + "AuditSummary", + "ReasoningAuditor", +] diff --git a/agentwatch/replay/__init__.py b/agentwatch/replay/__init__.py index 589d5d84..6515329d 100644 --- a/agentwatch/replay/__init__.py +++ b/agentwatch/replay/__init__.py @@ -1 +1,12 @@ from agentwatch.replay.engine import * + +__all__ = [ + "ReplaySpeed", + "DivergenceType", + "FailureCause", + "ReplayStep", + "Divergence", + "FailureAnalysis", + "ReplaySession", + "ReplayEngine", +] diff --git a/agentwatch/rollback/__init__.py b/agentwatch/rollback/__init__.py index b21fefbe..03a00890 100644 --- a/agentwatch/rollback/__init__.py +++ b/agentwatch/rollback/__init__.py @@ -1 +1,11 @@ from agentwatch.rollback.engine import * + +__all__ = [ + "CheckpointType", + "RollbackStatus", + "Checkpoint", + "RollbackResult", + "FilesystemSnapshot", + "GitCheckpointer", + "RollbackEngine", +] diff --git a/agentwatch/scoring/__init__.py b/agentwatch/scoring/__init__.py index 3ced6a8a..7565f108 100644 --- a/agentwatch/scoring/__init__.py +++ b/agentwatch/scoring/__init__.py @@ -1 +1,15 @@ from agentwatch.scoring.confidence import * + +__all__ = [ + "ANOMALY_GOAL_DRIFT", + "ANOMALY_TOOL_LOOP", + "ANOMALY_REPEATED_FAILURES", + "ANOMALY_HALLUCINATED_SUCCESS", + "ANOMALY_NO_PROGRESS", + "ANOMALY_HIGH_RISK_ACTION", + "ANOMALY_MEMORY_CONTRADICTION", + "ANOMALY_IRRELEVANT_TOOLS", + "ANOMALY_CONTEXT_EXPLOSION", + "ScoringResult", + "ConfidenceScorer", +] diff --git a/agentwatch/tracing/__init__.py b/agentwatch/tracing/__init__.py index 83b366e7..531bedab 100644 --- a/agentwatch/tracing/__init__.py +++ b/agentwatch/tracing/__init__.py @@ -1,2 +1,8 @@ from agentwatch.tracing.collector import * from agentwatch.tracing.otel import * + +__all__ = [ + "TraceSpan", + "Trace", + "TraceCollector", +] diff --git a/pyproject.toml b/pyproject.toml index 80993f66..755677d6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -124,8 +124,9 @@ ignore = [ [tool.ruff.lint.per-file-ignores] # __init__.py re-exports: wildcard imports and implicit re-exports are intentional -"agentwatch/**/__init__.py" = ["F401", "F403"] -"agentwatch/*/__init__.py" = ["F401", "F403"] +# (F405: __all__ names resolve through those wildcards). +"agentwatch/**/__init__.py" = ["F401", "F403", "F405"] +"agentwatch/*/__init__.py" = ["F401", "F403", "F405"] [tool.mypy] python_version = "3.12" diff --git a/tests/test_package_exports.py b/tests/test_package_exports.py new file mode 100644 index 00000000..8c132bce --- /dev/null +++ b/tests/test_package_exports.py @@ -0,0 +1,54 @@ +"""Every wildcard-re-exporting package must declare a resolvable __all__.""" + +from __future__ import annotations + +import importlib + +import pytest + +# Packages whose __init__ uses `from .sub import *`; each must pin its public +# surface with an explicit __all__ so `import *` is honest and knowable. +WILDCARD_PACKAGES = [ + "adapters", + "alerting", + "core", + "cost", + "governance", + "memory", + "orchestration", + "plugins", + "reasoning", + "replay", + "rollback", + "scoring", + "tracing", +] + + +@pytest.mark.parametrize("pkg", WILDCARD_PACKAGES) +def test_package_defines_all(pkg): + module = importlib.import_module(f"agentwatch.{pkg}") + assert isinstance(getattr(module, "__all__", None), list) + assert module.__all__, "__all__ must not be empty" + + +@pytest.mark.parametrize("pkg", WILDCARD_PACKAGES) +def test_all_names_resolve(pkg): + module = importlib.import_module(f"agentwatch.{pkg}") + missing = [name for name in module.__all__ if not hasattr(module, name)] + assert not missing, f"agentwatch.{pkg}.__all__ lists undefined names: {missing}" + + +@pytest.mark.parametrize("pkg", WILDCARD_PACKAGES) +def test_all_has_no_duplicates(pkg): + names = importlib.import_module(f"agentwatch.{pkg}").__all__ + assert len(names) == len(set(names)) + + +@pytest.mark.parametrize("pkg", WILDCARD_PACKAGES) +def test_star_import_matches_all(pkg): + module = importlib.import_module(f"agentwatch.{pkg}") + ns: dict[str, object] = {} + exec(f"from agentwatch.{pkg} import *", ns) # noqa: S102 + exported = {k for k in ns if not k.startswith("__")} + assert exported == set(module.__all__)