diff --git a/nisystemlink/clients/alarm/__init__.py b/nisystemlink/clients/alarm/__init__.py index daa177e9..bfbfcaa8 100644 --- a/nisystemlink/clients/alarm/__init__.py +++ b/nisystemlink/clients/alarm/__init__.py @@ -1,3 +1,5 @@ +"""Start here with AlarmClient for alarm management.""" + from nisystemlink.clients.alarm._alarm_client import AlarmClient -# flake8: noqa +__all__ = ["AlarmClient"] diff --git a/nisystemlink/clients/artifact/__init__.py b/nisystemlink/clients/artifact/__init__.py index 2f507a2f..d7dcebae 100644 --- a/nisystemlink/clients/artifact/__init__.py +++ b/nisystemlink/clients/artifact/__init__.py @@ -1,3 +1,5 @@ -from ._artifact_client import ArtifactClient - -# flake8: noqa +"""Start here with ArtifactClient for artifact management.""" + +from ._artifact_client import ArtifactClient + +__all__ = ["ArtifactClient"] diff --git a/nisystemlink/clients/assetmanagement/__init__.py b/nisystemlink/clients/assetmanagement/__init__.py index 3b415a1b..ac53c7b7 100644 --- a/nisystemlink/clients/assetmanagement/__init__.py +++ b/nisystemlink/clients/assetmanagement/__init__.py @@ -1,5 +1,7 @@ +"""Start here with AssetManagementClient for asset management.""" + from nisystemlink.clients.assetmanagement._asset_management_client import ( AssetManagementClient, ) -# flake8: noqa +__all__ = ["AssetManagementClient"] diff --git a/nisystemlink/clients/dataframe/__init__.py b/nisystemlink/clients/dataframe/__init__.py index cf553adb..5aef89b9 100644 --- a/nisystemlink/clients/dataframe/__init__.py +++ b/nisystemlink/clients/dataframe/__init__.py @@ -1,3 +1,5 @@ +"""Start here with DataFrameClient for dataframe operations.""" + from ._data_frame_client import DataFrameClient -# flake8: noqa +__all__ = ["DataFrameClient"] diff --git a/nisystemlink/clients/feeds/__init__.py b/nisystemlink/clients/feeds/__init__.py index c5da55bd..cc5561b9 100644 --- a/nisystemlink/clients/feeds/__init__.py +++ b/nisystemlink/clients/feeds/__init__.py @@ -1,3 +1,5 @@ +"""Start here with FeedsClient for feed management.""" + from ._feeds_client import FeedsClient -# flake8: noqa +__all__ = ["FeedsClient"] diff --git a/nisystemlink/clients/file/__init__.py b/nisystemlink/clients/file/__init__.py index 6398a061..7c2f29ba 100644 --- a/nisystemlink/clients/file/__init__.py +++ b/nisystemlink/clients/file/__init__.py @@ -1,3 +1,5 @@ +"""Start here with FileClient for file operations.""" + from ._file_client import FileClient -# flake8: noqa +__all__ = ["FileClient"] diff --git a/nisystemlink/clients/notebook/__init__.py b/nisystemlink/clients/notebook/__init__.py index ee625b42..15e53082 100644 --- a/nisystemlink/clients/notebook/__init__.py +++ b/nisystemlink/clients/notebook/__init__.py @@ -1,3 +1,5 @@ +"""Start here with NotebookClient for notebook management.""" + from ._notebook_client import NotebookClient -# flake8: noqa +__all__ = ["NotebookClient"] diff --git a/nisystemlink/clients/notification/__init__.py b/nisystemlink/clients/notification/__init__.py index 93aa4ea6..62d482bc 100644 --- a/nisystemlink/clients/notification/__init__.py +++ b/nisystemlink/clients/notification/__init__.py @@ -1,3 +1,5 @@ +"""Start here with NotificationClient for notification management.""" + from ._notification_client import NotificationClient -# flake8: noqa +__all__ = ["NotificationClient"] diff --git a/nisystemlink/clients/product/__init__.py b/nisystemlink/clients/product/__init__.py index 7b357f5d..469999f4 100644 --- a/nisystemlink/clients/product/__init__.py +++ b/nisystemlink/clients/product/__init__.py @@ -1,3 +1,5 @@ +"""Start here with ProductClient for product management.""" + from ._product_client import ProductClient -# flake8: noqa +__all__ = ["ProductClient"] diff --git a/nisystemlink/clients/spec/__init__.py b/nisystemlink/clients/spec/__init__.py index 3f1f0074..16a9d4e8 100644 --- a/nisystemlink/clients/spec/__init__.py +++ b/nisystemlink/clients/spec/__init__.py @@ -1,3 +1,5 @@ +"""Start here with SpecClient for specification management.""" + from ._spec_client import SpecClient -# flake8: noqa +__all__ = ["SpecClient"] diff --git a/nisystemlink/clients/systems/__init__.py b/nisystemlink/clients/systems/__init__.py index 0e88f3ca..12e9108a 100644 --- a/nisystemlink/clients/systems/__init__.py +++ b/nisystemlink/clients/systems/__init__.py @@ -1,3 +1,5 @@ +"""Start here with SystemsClient for system management.""" + from nisystemlink.clients.systems._systems_client import SystemsClient -# flake8: noqa +__all__ = ["SystemsClient"] diff --git a/nisystemlink/clients/tag/__init__.py b/nisystemlink/clients/tag/__init__.py index f3b2b112..56bd4ef8 100644 --- a/nisystemlink/clients/tag/__init__.py +++ b/nisystemlink/clients/tag/__init__.py @@ -1,21 +1,43 @@ # -*- coding: utf-8 -*- +"""Start here with TagManager for tag operations and helper types.""" + from ._data_type import DataType from ._retention_type import RetentionType from ._tag_data import TagData -from ._tag_with_aggregates import TagWithAggregates -from ._async_tag_query_result_collection import AsyncTagQueryResultCollection +from ._tag_with_aggregates import TagWithAggregates # noqa: I100 +from ._async_tag_query_result_collection import ( # noqa: I100 + AsyncTagQueryResultCollection, +) from ._itag_reader import ITagReader from ._itag_writer import ITagWriter -from ._buffered_tag_writer import BufferedTagWriter +from ._buffered_tag_writer import BufferedTagWriter # noqa: I100 from ._tag_value_reader import TagValueReader from ._tag_value_writer import TagValueWriter -from ._tag_update_fields import TagUpdateFields -from ._tag_data_update import TagDataUpdate +from ._tag_update_fields import TagUpdateFields # noqa: I100 +from ._tag_data_update import TagDataUpdate # noqa: I100 from ._tag_path_utilities import TagPathUtilities from ._tag_query_result_collection import TagQueryResultCollection from ._tag_subscription import TagSubscription -from ._tag_selection import TagSelection -from ._tag_manager import TagManager +from ._tag_selection import TagSelection # noqa: I100 +from ._tag_manager import TagManager # noqa: I100 -# flake8: noqa +__all__ = [ + "DataType", + "RetentionType", + "TagData", + "TagWithAggregates", + "AsyncTagQueryResultCollection", + "ITagReader", + "ITagWriter", + "BufferedTagWriter", + "TagValueReader", + "TagValueWriter", + "TagUpdateFields", + "TagDataUpdate", + "TagPathUtilities", + "TagQueryResultCollection", + "TagSubscription", + "TagSelection", + "TagManager", +] diff --git a/nisystemlink/clients/test_plan/__init__.py b/nisystemlink/clients/test_plan/__init__.py index 013b65cb..f51497c9 100644 --- a/nisystemlink/clients/test_plan/__init__.py +++ b/nisystemlink/clients/test_plan/__init__.py @@ -1,3 +1,5 @@ +"""Start here with TestPlanClient for test plan management.""" + from ._test_plan_client import TestPlanClient -# flake8: noqa +__all__ = ["TestPlanClient"] diff --git a/nisystemlink/clients/testmonitor/__init__.py b/nisystemlink/clients/testmonitor/__init__.py index 827fc6a4..078062a6 100644 --- a/nisystemlink/clients/testmonitor/__init__.py +++ b/nisystemlink/clients/testmonitor/__init__.py @@ -1,3 +1,5 @@ +"""Start here with TestMonitorClient for test monitor operations.""" + from ._test_monitor_client import TestMonitorClient -# flake8: noqa +__all__ = ["TestMonitorClient"] diff --git a/nisystemlink/clients/work_item/__init__.py b/nisystemlink/clients/work_item/__init__.py index d190f619..850d74e0 100644 --- a/nisystemlink/clients/work_item/__init__.py +++ b/nisystemlink/clients/work_item/__init__.py @@ -1,3 +1,5 @@ +"""Start here with WorkItemClient for work item operations.""" + from ._work_item_client import WorkItemClient, WorkItemExecuteApiException -# flake8: noqa +__all__ = ["WorkItemClient", "WorkItemExecuteApiException"] diff --git a/tests/test_service_package_exports.py b/tests/test_service_package_exports.py new file mode 100644 index 00000000..7d36a041 --- /dev/null +++ b/tests/test_service_package_exports.py @@ -0,0 +1,73 @@ +"""Validate the public surface declared by each service package.""" + +import ast +import unittest +from pathlib import Path + +PACKAGE_EXPORTS = { + "alarm": ["AlarmClient"], + "artifact": ["ArtifactClient"], + "assetmanagement": ["AssetManagementClient"], + "dataframe": ["DataFrameClient"], + "feeds": ["FeedsClient"], + "file": ["FileClient"], + "notebook": ["NotebookClient"], + "notification": ["NotificationClient"], + "product": ["ProductClient"], + "spec": ["SpecClient"], + "systems": ["SystemsClient"], + "tag": [ + "DataType", + "RetentionType", + "TagData", + "TagWithAggregates", + "AsyncTagQueryResultCollection", + "ITagReader", + "ITagWriter", + "BufferedTagWriter", + "TagValueReader", + "TagValueWriter", + "TagUpdateFields", + "TagDataUpdate", + "TagPathUtilities", + "TagQueryResultCollection", + "TagSubscription", + "TagSelection", + "TagManager", + ], + "test_plan": ["TestPlanClient"], + "testmonitor": ["TestMonitorClient"], + "work_item": ["WorkItemClient", "WorkItemExecuteApiException"], +} + + +class TestServicePackageExports(unittest.TestCase): + """Verify service package docstrings and explicit export lists.""" + + def test_service_package_exports_are_explicit(self): + """Each service package should document and declare its public exports.""" + package_root = Path(__file__).resolve().parents[1] / "nisystemlink" / "clients" + + for package_name, exported_names in PACKAGE_EXPORTS.items(): + with self.subTest(package_name=package_name): + module_path = package_root / package_name / "__init__.py" + module = ast.parse(module_path.read_text(encoding="utf-8")) + imported_names = [] + declared_exports = None + module_docstring = ast.get_docstring(module) + + self.assertIsNotNone(module_docstring) + if module_docstring is None: + self.fail(f"Missing module docstring in {module_path}") + self.assertTrue(module_docstring.startswith("Start here with ")) + + for node in module.body: + if isinstance(node, ast.ImportFrom): + imported_names.extend(alias.name for alias in node.names) + elif isinstance(node, ast.Assign): + for target in node.targets: + if isinstance(target, ast.Name) and target.id == "__all__": + declared_exports = ast.literal_eval(node.value) + + self.assertEqual(declared_exports, exported_names) + self.assertCountEqual(imported_names, exported_names)