Skip to content

maint(types): annotate codebase and enable mypy strict#150

Merged
stanislavlevin merged 3 commits into
mainfrom
issue_149
May 7, 2026
Merged

maint(types): annotate codebase and enable mypy strict#150
stanislavlevin merged 3 commits into
mainfrom
issue_149

Conversation

@stanislavlevin
Copy link
Copy Markdown
Owner

@stanislavlevin stanislavlevin commented May 7, 2026

  • type annotations across src/, backend/, tests/
  • enable mypy strict; drop allowlist (whole tree type-checks)
  • mark package as PEP 561 typed (py.typed)
  • ci: mypy step with pretty-output flags

Fixes: #149

Summary by Sourcery

Add comprehensive type annotations across core library, backend, CLI, dependency collection, and tests, and enforce strict static typing in development and CI.

Enhancements:

  • Introduce precise TypedDicts, Protocols, Literals, and overloads for build backends, wheels, metadata parsing, dependency config, and collectors to improve type safety and clarity.
  • Refine public and internal APIs (including CLI helpers, virtualenv management, RPM filelist generation, and installer logic) to use explicit, typed arguments and return values.
  • Allow packaging of the PEP 561 typing marker (py.typed) in wheels and sdists so the library is recognized as typed by consumers.
  • Tighten coverage configuration to require 100% coverage and extend linting guidance to include mypy in contributor docs.

Build:

  • Mark the distribution as typed via classifiers and packaging metadata, and add strict mypy configuration to pyproject.toml for the source tree.
  • Wire mypy into the CI pipeline with pretty error reporting flags alongside existing linting steps.

Tests:

  • Extend and adjust unit and integration tests to cover new typed behaviors, error paths, and helper utilities (e.g., wheel extraction safety, venv context handling, backend-path enforcement).

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="backend/metadata.py" line_range="60-69" />
<code_context>
+)
+
+
+Pep621SupportedFieldsType = Literal[
+    "name",
+    "version",
+    "description",
+    "readme",
+    "requires-python",
+    "license",
+    "authors",
+    "keywords",
+    "classifiers",
+    "dynamic",
+    "urls",
+]
+
</code_context>
<issue_to_address>
**issue (bug_risk):** The PEP 621 supported fields omit `maintainers`, which will now be rejected as an unexpected field.

In the previous implementation, `maintainers` was part of `supported_fields`, but it’s now missing from `Pep621SupportedFieldsType`/`PEP621_SUPPORTED_FIELDS`. This will cause existing `project.maintainers` entries in `pyproject.toml` to raise `ValueError("Unexpected fields in project table: maintainers")`. Please add `"maintainers"` to `Pep621SupportedFieldsType` so it remains accepted and passed through to `Pep621MetadataType` as before, avoiding a regression for current users.
</issue_to_address>

### Comment 2
<location path="src/pyproject_installer/deps_cmd/deps_config.py" line_range="160-170" />
<code_context>
+        return sources

-    def add(self, srcname, srctype, srcargs=()):
+    def add(
+        self,
+        srcname: str,
+        srctype: str,
+        srcargs: tuple[str, ...] = (),
+    ) -> None:
         if not self.file.is_file():
             # allow new file
             self.set_default()
-        srcargs = tuple(srcargs)
+        # srcargs = list(srcargs)
         self.validate_collector(srctype, srcargs)

</code_context>
<issue_to_address>
**suggestion (bug_risk):** Inconsistent handling of `srcargs` and leftover commented-out conversion may cause type/shape drift over time.

Previously `srcargs` was normalized with `srcargs = tuple(srcargs)` so its shape was consistent regardless of the caller. Removing that and leaving a commented `# srcargs = list(srcargs)` introduces dead code and the risk of mixed tuple/list representations, diverging from `DepsConfigSourceSpec`. Please either reintroduce explicit normalization (e.g. `srcargs = tuple(srcargs)`) or remove the comment and clearly rely on the JSON/schema to define the runtime type.

```suggestion
    def add(
        self,
        srcname: str,
        srctype: str,
        srcargs: tuple[str, ...] = (),
    ) -> None:
         if not self.file.is_file():
             # allow new file
             self.set_default()
+        # Normalize to a tuple to keep consistent with DepsConfigSourceSpec
+        srcargs = tuple(srcargs)
         self.validate_collector(srctype, srcargs)
```
</issue_to_address>

### Comment 3
<location path="src/pyproject_installer/install_cmd/_install.py" line_range="243-246" />
<code_context>
             installed_paths=installed_paths,
         )

-    if installed_paths is not None:
+    if rpm_filelist is not None and installed_paths:
         write_rpm_filelist(
             rpm_filelist,
</code_context>
<issue_to_address>
**question (bug_risk):** RPM filelist is skipped when requested but no files were installed, which may not be the intended behavior.

With the new condition, providing `rpm_filelist` but ending up with an empty `installed_paths` means `write_rpm_filelist` is never called and the file is not created/updated. If the contract is "emit a filelist whenever `rpm_filelist` is set", consider checking only `rpm_filelist is not None` and letting `write_rpm_filelist` handle an empty `installed_paths` set (e.g., by writing an empty file).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread backend/metadata.py
Comment thread src/pyproject_installer/deps_cmd/deps_config.py
Comment thread src/pyproject_installer/install_cmd/_install.py
stanislavlevin and others added 2 commits May 7, 2026 13:17
- type annotations across src/, backend/, tests/
- enable mypy strict; drop allowlist (whole tree type-checks)
- mark package as PEP 561 typed (py.typed)
- ci: mypy step with pretty-output flags

Fixes: #149

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Exercise the 4 raise-on-None guards added during the mypy strict
pass: backend_caller's __file__ check, PyprojectVenv.context in
both create() and venv_environ(), and WheelFile._zipfile in
extract().

Fixes: #149

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Cover WheelFile.extract default-members branch. Exclude
version-gated <3.11 shims (vendored tomli import, get_identifiers
backport) via # pragma: no cover. Set fail_under = 100 in
[tool.coverage.report] so any drop fails CI.

Fixes: #149

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Stanislav Levin <slev@altlinux.org>
@stanislavlevin stanislavlevin merged commit cf0354a into main May 7, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

annotate codebase

1 participant