This is an automated email from the ASF dual-hosted git repository.
sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
The following commit(s) were added to refs/heads/main by this push:
new af926e3 Add a lint to check imports in the models
af926e3 is described below
commit af926e3f0114acb07bd0d6bdae04bc8c9e357887
Author: Sean B. Palmer <[email protected]>
AuthorDate: Tue Jan 20 15:15:27 2026 +0000
Add a lint to check imports in the models
---
.pre-commit-config.yaml | 8 ++++
atr/models/attestable.py | 2 +-
scripts/check_models_imports.py | 82 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 91 insertions(+), 1 deletion(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 0c823fc..4a71a40 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -185,3 +185,11 @@ repos:
language: system
pass_filenames: false
always_run: true
+
+ - id: check-models-imports
+ name: check models imports
+ description: Ensure that the models only import from approved packages
+ entry: uv run --frozen python scripts/check_models_imports.py
+ language: system
+ pass_filenames: false
+ files: ^atr/models/.*\.py$
diff --git a/atr/models/attestable.py b/atr/models/attestable.py
index f49cc1f..3cff655 100644
--- a/atr/models/attestable.py
+++ b/atr/models/attestable.py
@@ -19,7 +19,7 @@ from typing import Annotated, Literal
import pydantic
-import atr.models.schema as schema
+from . import schema
class HashEntry(schema.Strict):
diff --git a/scripts/check_models_imports.py b/scripts/check_models_imports.py
new file mode 100755
index 0000000..80ae8e3
--- /dev/null
+++ b/scripts/check_models_imports.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python3
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import ast
+import pathlib
+import sys
+from typing import Final
+
+_ALLOWED_PACKAGES: Final = frozenset(
+ {
+ "pydantic",
+ "pydantic_core",
+ "sqlalchemy",
+ "sqlmodel",
+ }
+)
+
+
+def _check_file(path: pathlib.Path) -> list[str]:
+ errors = []
+ tree = ast.parse(path.read_text(), filename=str(path))
+
+ for node in ast.walk(tree):
+ if isinstance(node, ast.Import):
+ for alias in node.names:
+ root = alias.name.split(".")[0]
+ if not _is_stdlib(alias.name) and (root not in
_ALLOWED_PACKAGES):
+ errors.append(f"{path}:{node.lineno}: disallowed import
'{alias.name}'")
+
+ elif isinstance(node, ast.ImportFrom):
+ if node.level > 0:
+ # This uses "from ." or "from .name" syntax
+ continue
+ if node.module is None:
+ # This should be unreachable
+ continue
+ root = node.module.split(".")[0]
+ if not _is_stdlib(node.module) and (root not in _ALLOWED_PACKAGES):
+ errors.append(f"{path}:{node.lineno}: disallowed import from
'{node.module}'")
+
+ return errors
+
+
+def _is_stdlib(module: str) -> bool:
+ root = module.split(".")[0]
+ return root in sys.stdlib_module_names
+
+
+def _run() -> int:
+ models_dir = pathlib.Path(__file__).parent.parent / "atr" / "models"
+ errors = []
+
+ for path in models_dir.glob("*.py"):
+ errors.extend(_check_file(path))
+
+ for error in errors:
+ print(error, file=sys.stderr)
+
+ return 1 if errors else 0
+
+
+def main() -> None:
+ sys.exit(_run())
+
+
+if __name__ == "__main__":
+ main()
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]