jw.pkg: Massively tighten linter checks #53

Merged
Jan Lindemann merged 31 commits from jan/feature/20260809-pyrightconfig-json-mirror-strict-mypy-settings into master 2026-08-09 15:12:37 +02:00 AGit

This PR gradually tightens Mypy's linter rules in pypropject.toml. After every change, make check and make test fallout is fixed, and the fixes committed, to keep the project bisectable over the entire PR. After that, equivalent rules are also configured to Pyright in pyrightconfig.json, in this case with no additional fallout.

The fixes have to a large extent been made by AI.

pyrightconfig.json: Mirror strict mypy settings

Follow the changes in the mypy check profile by adding additional checks.

pyproject.toml: Simplify mypy config using strict mode

Remove 8 redundant mypy settings that are already enabled by strict mode: warn_redundant_casts, strict_equality, disallow_any_generics, warn_unused_ignores, disallow_untyped_calls, warn_return_any, disallow_incomplete_defs, disallow_untyped_defs.

Keep warn_unreachable explicitly since it's not part of strict mode. Also remove the duplicate exhaustive-match entry from enable_error_code.

pyproject.toml: Enable mypy.disallow_untyped_defs

Add disallow_untyped_defs = true to the mypy configuration. This requires all function definitions to have complete type annotations for both parameters and return types. Since disallow_incomplete_defs was already satisfied (all functions have partial annotations), this final rule validates that no function is left without any type hints.

pyproject.toml: Enable mypy.disallow_incomplete_defs

Add disallow_incomplete_defs = true to the mypy configuration. This requires all function definitions to have complete parameter and return type annotations, catching partially-annotated function signatures.

App, lib: Fix disallow_incomplete_defs fallout

Add missing type annotations to function parameters and return types to satisfy the disallow_incomplete_defs mypy rule.

Fixes applied across 28 files:

  • Added return type annotations (Result, str, None, etc.)

  • Added parameter type annotations (Any, int, str, Namespace, etc.)

  • Added *args: Any and **kwargs: Any where needed

  • Added from future import annotations to Package.py

  • util.py: annotate *args/**kwargs in run_cmd, run_curl_into

  • Result.py: annotate quote, verbose parameters in private methods

  • CopyContext.py: annotate chroot parameter

  • AsyncRunner.py: annotate exc_type, exc, tb in exit

  • ec/Curl.py: annotate *args/**kwargs in init, add Any import

  • ec/Local.py: fix __make_pty_reader return type and _read annotation

  • Types.py: annotate debug_level parameter, add return type

  • Distro.py: annotate **kwargs in instantiate

  • distros/suse/Distro.py: annotate *args/**kwargs, add Any import

  • distros/debian/Distro.py: annotate *args/**kwargs, add Any import

  • ec/ssh/Paramiko.py: annotate uri parameter, *args/**kwargs

  • ec/ssh/Exec.py: annotate uri parameter, *args/**kwargs, add Any import

  • pm/rpm.py: annotate **kwargs in run_rpm, add Any import

  • cmds/secrets/lib/FilesContext.py: annotate throw parameter

  • cmds/projects/lib/templates.py: annotate li_quote, li_delimiter parameters, fix search_path None handling

  • cmds/projects/lib/pkg_relations.py: annotate hide_self, hide_jw_pkg

  • cmds/projects/CmdCreateFile.py: annotate li_quote, li_delimiter

  • cmds/projects/CmdCanonicalizeRemotes.py: annotate ro, throw in git

  • cmds/posix/tar/Cmd.py: annotate **kwargs in ctx, add Any import

  • App.py: annotate __get_project_refs_cached return type, use cast

pyproject.toml: Enable mypy.warn_return_any

Add warn_return_any = true to the mypy configuration. This detects functions that return Any from contexts where a specific return type is declared, encouraging more precise type annotations.

App, cmds, lib: Fix Any returns from typed functions

Add type annotations and casts to functions that were returning Any where a specific type was declared, satisfying the new warn_return_any mypy rule.

Fixes:

  • log.py: get_caller_pos return type via cast
  • AsyncRunner.py: cast T for fut.result()
  • util.py: cast for getattr result, str() for args.username
  • FileContext.py: verbose_default bool annotation
  • SSHClient.py: cast SSHClient for dynamic import
  • lib/App.py: cast ArgumentParser, add return types to inner funcs
  • pm/rpm.py, dpkg.py: cast Iterable[Package]
  • App.py: cast for self.args.func(), add return types to inner funcs
  • BaseCmdPkgRelations.py: cast str for args.delimiter

pyproject.toml: Enable mypy.disallow_untyped_calls

Add disallow_untyped_calls = true to the mypy configuration. This requires all function calls from typed code to target typed functions, ensuring better type safety across the codebase.

App, lib: Add type annotations to untyped functions

Add missing type annotations to functions that are called from typed contexts, satisfying the new disallow_untyped_calls mypy rule.

Fixes:

  • Local.py: __log() with typed parameters
  • lib/App.py: _add_arguments(), add_cmd_to_parser(), add_cmds_to_parser()
  • pm/rpm.py, dpkg.py: meta_map() return type
  • Exec.py: __init_askpass() return type
  • App.py: strip_module_from_spec(), __get_project_refs_cached(), ResultCache.init and run(), _add_arguments()
  • Added Collection type for truthy-iterable compliance

pyproject.toml: Enable mypy.warn_unreachable

Add warn_unreachable = true to the mypy configuration. This detects statements that mypy proves are unreachable, such as code after an unconditional return or assertions that can never be true.

App, lib, cmds: Remove unreachable code

Remove dead code paths detected by the new warn_unreachable mypy rule. These include:

  • Removed always-false isinstance checks (ssh/util.py, templates.py)
  • Removed unreachable return statements after raise (FileContext.py)
  • Removed unreachable None checks for typed variables (Result.py, ExecContext.py, CmdGetAuthInfo.py)
  • Simplified __uri function by removing impossible None check (CopyContext.py)
  • Changed assert False to explicit error (Cmd.py)
  • Removed unreachable None case from match (App.py)
  • Removed redundant outer case _: pass (pkg_relations.py)
  • Restructured stdin write to avoid unreachable warning (AsyncSSH.py)

pyproject.toml: Enable mypy.exhaustive-match

Add the exhaustive-match error code to the mypy configuration. This requires all match statements to be exhaustive, handling all possible values of the matched expression.

The fix is to add 'case _: pass' to each match statement that is intended to be non-exhaustive, making the non-exhaustiveness explicit.

lib, cmds: Add exhaustive match cases

Add 'case _: pass' to match statements that are intentionally non-exhaustive, satisfying the new exhaustive-match mypy rule.

Also replaced 'case '_':' (a string literal) with 'case _: pass' in pkg_relations.py since it was an unreachable case (syntax is a VersionSyntax enum, not a str).

Added 'case VersionSyntax.names_only:' to the match in pkg_relations.py to handle the missing enum value.

Files modified:

  • util.py: Two match statements for askpass env vars
  • Distro.py: Three match statements for backend/os detection
  • pkg_relations.py: Match on VersionSyntax enum
  • CmdListRepos.py: Match on URL scheme

pyproject.toml: Enable mypy.truthy-iterable

Add the truthy-iterable error code to the mypy configuration. This detects Iterable parameters that are used in boolean contexts (if not names, etc.) since Iterable values are always truthy.

The fix is to change Iterable[str] parameters to Collection[str] when they are tested for emptiness, since Collection guarantees len.

lib: Change Iterable to Collection for truthy checks

Change parameter types from Iterable[str] to Collection[str] wherever the parameter is tested for emptiness (if not names). This satisfies the new truthy-iterable mypy rule, since bare Iterable values are always truthy even when empty.

Affected files:

  • Distro.py: install, delete, select, _select, _select_by_name
  • rpm.py: query_packages
  • suse/Distro.py: _select_by_name
  • Cmd.py (secrets): _match_files, _list_template_files, etc.
  • DistroContext.py: list_template_files, list_secret_paths, etc.

pyproject.toml: Enable mypy.warn_unused_ignores

Add warn_unused_ignores = true to the mypy configuration. This warns when a '# type: ignore' comment has no associated error code, ensuring all type ignores are explicit about which error they suppress.

App, AsyncSSH: Remove unused "type: ignore" comments

Remove '# type: ignore' comments that are no longer needed now that warn_unused_ignores is enabled in the mypy configuration. The errors they were suppressing (import-not-found, type-abstract) are no longer triggered, likely due to updated type stubs or changed code paths.

pyproject.toml: Enable mypy.disallow_any_generics

Add disallow_any_generics = true to the mypy configuration. This requires all generic types (dict, list, Iterable, Types, etc.) to have explicit type arguments instead of using bare generic aliases.

Distro, Cmd, AsyncSSH: Fix bare generic types

Add explicit type arguments to all generic type annotations that were previously bare, satisfying the new disallow_any_generics mypy rule.

Fixes:

  • Distro.py: Iterable[str] for expand_macros fmt parameter
  • Cmd.py: Types[Any] for add_subcommands cmds parameter
  • AsyncSSH.py: dict[str, Any] for _connect_kwargs return type

pyproject.toml: Enable mypy.strict_equality

Set mypy.strict_equality = true, forcing type-equal equality.

Distro._reboot_required(): Fix comparison

The comparison ret != 0 is comparing a Result object against the integer 0, which is always True since Result has no eq defined.

This commit fixes the bug by comparing ret.status instead, which is the actual exit code we care about. This satisfies the new strict_equality mypy rule which enables the comparison-overlap check.

pyproject.toml: Enable mypy.warn_redundant_casts

Add warn_redundant_casts = true to the mypy configuration template. This rule detects casts that mypy proves unnecessary, helping to clean up redundant type casts that clutter the codebase.

This is one of the boolean-flag rules being gradually adopted from the stricter mypy profile in /tmp/pyproject.toml. It produces just 1 error during initial rollout.

util: Remove redundant cast in run_curl_into

The cast to 'T' in run_curl_into was redundant: mypy already narrows the return value of json.loads() to type T after the isinstance(ret, expected_type) check (where expected_type: type[T]).

Remove the unnecessary cast and clean up the unused 'cast' import. This satisfies the new warn_redundant_casts mypy rule.

pyproject.toml: Enable mypy.truthy-bool

Add the truthy-bool error code to the mypy configuration. This detects conditions and expressions that are always truthy because the type has no bool or len method.

lib.Distro: Fix mypy.truthy-bool fallout

The _select() method in Distro.py has an assert on a PackageFilter parameter that doesn't define bool or len. Since the type signature already guarantees it is not None, the assertion is redundant and is now removed.

pyproject.toml: Enable mypy.possibly-undefined

Add the possibly-undefined error code to the mypy configuration. This detects variables that may not be defined on all execution paths, catching a class of NameError bugs at type-check time.

lib.log: Fix mypy.possibly-undefined fallout

The log_m() function has margs conditionally assigned inside an if block but used unconditionally afterwards. Initialize margs outside the if to guarantee it is always defined.

pyproject.toml: Enable mypy.ignore-without-code

Add the ignore-without-code error code to the mypy configuration. This requires all # type: ignore comments to include a specific error code, improving the precision and maintainability of type ignore annotations.

lib.AsyncRunner: Fix mypy.ignore-without-code fallout

Annotate the one existing bare "# type: ignore" in AsyncRunner.py with arg-type and var-annotated codes to prepare for mypy.ignore-without-code.

pyproject.toml, pyrightconfig.json: Require @override

Add mypy's explicit-override error code and pyrightconfig's reportImplicitOverride "error" directive. This requires all methods that override base class methods to be decorated with @override from typing. The change complements the previous commit, which added exactly that decorator to all relevant methods.

App, lib, cmds: Fix mypy.explicit-override fallout

This commit adds @override decorators to approximately 300 methods across 76 files that inherit from base classes such as AbstractCmd, FileContext, ExecContext, Distro, SSHClient, and others.

The decorator ensures the type checker can verify that overridden methods have compatible signatures and prevents accidental shadowing of inherited methods without intent.

Files modified include command classes, library modules, distro implementations, and SSH client implementations.

This PR gradually tightens Mypy's linter rules in `pypropject.toml`. After every change, `make check` and `make test` fallout is fixed, and the fixes committed, to keep the project bisectable over the entire PR. After that, equivalent rules are also configured to Pyright in `pyrightconfig.json`, in this case with no additional fallout. The fixes have to a large extent been made by AI. #### pyrightconfig.json: Mirror strict mypy settings Follow the changes in the mypy check profile by adding additional checks. #### pyproject.toml: Simplify mypy config using strict mode Remove 8 redundant mypy settings that are already enabled by strict mode: warn_redundant_casts, strict_equality, disallow_any_generics, warn_unused_ignores, disallow_untyped_calls, warn_return_any, disallow_incomplete_defs, disallow_untyped_defs. Keep warn_unreachable explicitly since it's not part of strict mode. Also remove the duplicate exhaustive-match entry from enable_error_code. #### pyproject.toml: Enable mypy.disallow_untyped_defs Add disallow_untyped_defs = true to the mypy configuration. This requires all function definitions to have complete type annotations for both parameters and return types. Since disallow_incomplete_defs was already satisfied (all functions have partial annotations), this final rule validates that no function is left without any type hints. #### pyproject.toml: Enable mypy.disallow_incomplete_defs Add disallow_incomplete_defs = true to the mypy configuration. This requires all function definitions to have complete parameter and return type annotations, catching partially-annotated function signatures. #### App, lib: Fix disallow_incomplete_defs fallout Add missing type annotations to function parameters and return types to satisfy the disallow_incomplete_defs mypy rule. Fixes applied across 28 files: - Added return type annotations (Result, str, None, etc.) - Added parameter type annotations (Any, int, str, Namespace, etc.) - Added *args: Any and **kwargs: Any where needed - Added from __future__ import annotations to Package.py - util.py: annotate *args/**kwargs in run_cmd, run_curl_into - Result.py: annotate quote, verbose parameters in private methods - CopyContext.py: annotate chroot parameter - AsyncRunner.py: annotate exc_type, exc, tb in __exit__ - ec/Curl.py: annotate *args/**kwargs in __init__, add Any import - ec/Local.py: fix __make_pty_reader return type and _read annotation - Types.py: annotate debug_level parameter, add return type - Distro.py: annotate **kwargs in instantiate - distros/suse/Distro.py: annotate *args/**kwargs, add Any import - distros/debian/Distro.py: annotate *args/**kwargs, add Any import - ec/ssh/Paramiko.py: annotate uri parameter, *args/**kwargs - ec/ssh/Exec.py: annotate uri parameter, *args/**kwargs, add Any import - pm/rpm.py: annotate **kwargs in run_rpm, add Any import - cmds/secrets/lib/FilesContext.py: annotate throw parameter - cmds/projects/lib/templates.py: annotate li_quote, li_delimiter parameters, fix search_path None handling - cmds/projects/lib/pkg_relations.py: annotate hide_self, hide_jw_pkg - cmds/projects/CmdCreateFile.py: annotate li_quote, li_delimiter - cmds/projects/CmdCanonicalizeRemotes.py: annotate ro, throw in git - cmds/posix/tar/Cmd.py: annotate **kwargs in ctx, add Any import - App.py: annotate __get_project_refs_cached return type, use cast #### pyproject.toml: Enable mypy.warn_return_any Add warn_return_any = true to the mypy configuration. This detects functions that return Any from contexts where a specific return type is declared, encouraging more precise type annotations. #### App, cmds, lib: Fix Any returns from typed functions Add type annotations and casts to functions that were returning Any where a specific type was declared, satisfying the new warn_return_any mypy rule. Fixes: - log.py: get_caller_pos return type via cast - AsyncRunner.py: cast T for fut.result() - util.py: cast for getattr result, str() for args.username - FileContext.py: verbose_default bool annotation - SSHClient.py: cast SSHClient for dynamic import - lib/App.py: cast ArgumentParser, add return types to inner funcs - pm/rpm.py, dpkg.py: cast Iterable[Package] - App.py: cast for self.args.func(), add return types to inner funcs - BaseCmdPkgRelations.py: cast str for args.delimiter #### pyproject.toml: Enable mypy.disallow_untyped_calls Add disallow_untyped_calls = true to the mypy configuration. This requires all function calls from typed code to target typed functions, ensuring better type safety across the codebase. #### App, lib: Add type annotations to untyped functions Add missing type annotations to functions that are called from typed contexts, satisfying the new disallow_untyped_calls mypy rule. Fixes: - Local.py: __log() with typed parameters - lib/App.py: _add_arguments(), add_cmd_to_parser(), add_cmds_to_parser() - pm/rpm.py, dpkg.py: meta_map() return type - Exec.py: __init_askpass() return type - App.py: strip_module_from_spec(), __get_project_refs_cached(), ResultCache.__init__ and run(), _add_arguments() - Added Collection type for truthy-iterable compliance #### pyproject.toml: Enable mypy.warn_unreachable Add warn_unreachable = true to the mypy configuration. This detects statements that mypy proves are unreachable, such as code after an unconditional return or assertions that can never be true. #### App, lib, cmds: Remove unreachable code Remove dead code paths detected by the new warn_unreachable mypy rule. These include: - Removed always-false isinstance checks (ssh/util.py, templates.py) - Removed unreachable return statements after raise (FileContext.py) - Removed unreachable None checks for typed variables (Result.py, ExecContext.py, CmdGetAuthInfo.py) - Simplified __uri function by removing impossible None check (CopyContext.py) - Changed assert False to explicit error (Cmd.py) - Removed unreachable None case from match (App.py) - Removed redundant outer case _: pass (pkg_relations.py) - Restructured stdin write to avoid unreachable warning (AsyncSSH.py) #### pyproject.toml: Enable mypy.exhaustive-match Add the exhaustive-match error code to the mypy configuration. This requires all match statements to be exhaustive, handling all possible values of the matched expression. The fix is to add 'case _: pass' to each match statement that is intended to be non-exhaustive, making the non-exhaustiveness explicit. #### lib, cmds: Add exhaustive match cases Add 'case _: pass' to match statements that are intentionally non-exhaustive, satisfying the new exhaustive-match mypy rule. Also replaced 'case '_':' (a string literal) with 'case _: pass' in pkg_relations.py since it was an unreachable case (syntax is a VersionSyntax enum, not a str). Added 'case VersionSyntax.names_only:' to the match in pkg_relations.py to handle the missing enum value. Files modified: - util.py: Two match statements for askpass env vars - Distro.py: Three match statements for backend/os detection - pkg_relations.py: Match on VersionSyntax enum - CmdListRepos.py: Match on URL scheme #### pyproject.toml: Enable mypy.truthy-iterable Add the truthy-iterable error code to the mypy configuration. This detects Iterable parameters that are used in boolean contexts (if not names, etc.) since Iterable values are always truthy. The fix is to change Iterable[str] parameters to Collection[str] when they are tested for emptiness, since Collection guarantees __len__. #### lib: Change Iterable to Collection for truthy checks Change parameter types from Iterable[str] to Collection[str] wherever the parameter is tested for emptiness (if not names). This satisfies the new truthy-iterable mypy rule, since bare Iterable values are always truthy even when empty. Affected files: - Distro.py: install, delete, select, _select, _select_by_name - rpm.py: query_packages - suse/Distro.py: _select_by_name - Cmd.py (secrets): _match_files, _list_template_files, etc. - DistroContext.py: list_template_files, list_secret_paths, etc. #### pyproject.toml: Enable mypy.warn_unused_ignores Add warn_unused_ignores = true to the mypy configuration. This warns when a '# type: ignore' comment has no associated error code, ensuring all type ignores are explicit about which error they suppress. #### App, AsyncSSH: Remove unused "type: ignore" comments Remove '# type: ignore' comments that are no longer needed now that warn_unused_ignores is enabled in the mypy configuration. The errors they were suppressing (import-not-found, type-abstract) are no longer triggered, likely due to updated type stubs or changed code paths. #### pyproject.toml: Enable mypy.disallow_any_generics Add disallow_any_generics = true to the mypy configuration. This requires all generic types (dict, list, Iterable, Types, etc.) to have explicit type arguments instead of using bare generic aliases. #### Distro, Cmd, AsyncSSH: Fix bare generic types Add explicit type arguments to all generic type annotations that were previously bare, satisfying the new disallow_any_generics mypy rule. Fixes: - Distro.py: Iterable[str] for expand_macros fmt parameter - Cmd.py: Types[Any] for add_subcommands cmds parameter - AsyncSSH.py: dict[str, Any] for _connect_kwargs return type #### pyproject.toml: Enable mypy.strict_equality Set mypy.strict_equality = true, forcing type-equal equality. #### Distro._reboot_required(): Fix comparison The comparison ret != 0 is comparing a Result object against the integer 0, which is always True since Result has no __eq__ defined. This commit fixes the bug by comparing ret.status instead, which is the actual exit code we care about. This satisfies the new strict_equality mypy rule which enables the comparison-overlap check. #### pyproject.toml: Enable mypy.warn_redundant_casts Add warn_redundant_casts = true to the mypy configuration template. This rule detects casts that mypy proves unnecessary, helping to clean up redundant type casts that clutter the codebase. This is one of the boolean-flag rules being gradually adopted from the stricter mypy profile in /tmp/pyproject.toml. It produces just 1 error during initial rollout. #### util: Remove redundant cast in run_curl_into The cast to 'T' in run_curl_into was redundant: mypy already narrows the return value of json.loads() to type T after the isinstance(ret, expected_type) check (where expected_type: type[T]). Remove the unnecessary cast and clean up the unused 'cast' import. This satisfies the new warn_redundant_casts mypy rule. #### pyproject.toml: Enable mypy.truthy-bool Add the truthy-bool error code to the mypy configuration. This detects conditions and expressions that are always truthy because the type has no __bool__ or __len__ method. #### lib.Distro: Fix mypy.truthy-bool fallout The _select() method in Distro.py has an assert on a PackageFilter parameter that doesn't define __bool__ or __len__. Since the type signature already guarantees it is not None, the assertion is redundant and is now removed. #### pyproject.toml: Enable mypy.possibly-undefined Add the possibly-undefined error code to the mypy configuration. This detects variables that may not be defined on all execution paths, catching a class of NameError bugs at type-check time. #### lib.log: Fix mypy.possibly-undefined fallout The log_m() function has margs conditionally assigned inside an if block but used unconditionally afterwards. Initialize margs outside the if to guarantee it is always defined. #### pyproject.toml: Enable mypy.ignore-without-code Add the ignore-without-code error code to the mypy configuration. This requires all # type: ignore comments to include a specific error code, improving the precision and maintainability of type ignore annotations. #### lib.AsyncRunner: Fix mypy.ignore-without-code fallout Annotate the one existing bare "# type: ignore" in AsyncRunner.py with arg-type and var-annotated codes to prepare for mypy.ignore-without-code. #### pyproject.toml, pyrightconfig.json: Require @override Add mypy's explicit-override error code and pyrightconfig's reportImplicitOverride "error" directive. This requires all methods that override base class methods to be decorated with @override from typing. The change complements the previous commit, which added exactly that decorator to all relevant methods. #### App, lib, cmds: Fix mypy.explicit-override fallout This commit adds @override decorators to approximately 300 methods across 76 files that inherit from base classes such as AbstractCmd, FileContext, ExecContext, Distro, SSHClient, and others. The decorator ensures the type checker can verify that overridden methods have compatible signatures and prevents accidental shadowing of inherited methods without intent. Files modified include command classes, library modules, distro implementations, and SSH client implementations.
This commit adds @override decorators to approximately 300 methods
across 76 files that inherit from base classes such as AbstractCmd,
FileContext, ExecContext, Distro, SSHClient, and others.

The decorator ensures the type checker can verify that overridden
methods have compatible signatures and prevents accidental shadowing
of inherited methods without intent.

Files modified include command classes, library modules, distro
implementations, and SSH client implementations.

Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL with pi.dev v
Signed-off-by: Jan Lindemann <jan@janware.com>
Add mypy's explicit-override error code and pyrightconfig's
reportImplicitOverride "error" directive. This requires all methods
that override base class methods to be decorated with @override from
typing. The change complements the previous commit, which added
exactly that decorator to all relevant methods.

Signed-off-by: Jan Lindemann <jan@janware.com>
Annotate the one existing bare "# type: ignore" in AsyncRunner.py
with arg-type and var-annotated codes to prepare for
mypy.ignore-without-code.

Signed-off-by: Jan Lindemann <jan@janware.com>
Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL and pi.dev 0.81.1
Add the ignore-without-code error code to the mypy configuration.
This requires all # type: ignore comments to include a specific error
code, improving the precision and maintainability of type ignore
annotations.

Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL and pi.dev 0.81.1
Signed-off-by: Jan Lindemann <jan@janware.com>
The log_m() function has margs conditionally assigned inside an if
block but used unconditionally afterwards. Initialize margs outside
the if to guarantee it is always defined.

Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL and pi.dev 0.81.1
Signed-off-by: Jan Lindemann <jan@janware.com>
Add the possibly-undefined error code to the mypy configuration.
This detects variables that may not be defined on all execution
paths, catching a class of NameError bugs at type-check time.

Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL and pi.dev 0.81.1
Signed-off-by: Jan Lindemann <jan@janware.com>
The _select() method in Distro.py has an assert on a PackageFilter
parameter that doesn't define __bool__ or __len__. Since the type
signature already guarantees it is not None, the assertion is
redundant and is now removed.

Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL and pi.dev 0.81.1
Signed-off-by: Jan Lindemann <jan@janware.com>
Add the truthy-bool error code to the mypy configuration. This
detects conditions and expressions that are always truthy because
the type has no __bool__ or __len__ method.

Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL and pi.dev 0.81.1
Signed-off-by: Jan Lindemann <jan@janware.com>
The cast to 'T' in run_curl_into was redundant: mypy already narrows
the return value of json.loads() to type T after the isinstance(ret,
expected_type) check (where expected_type: type[T]).

Remove the unnecessary cast and clean up the unused 'cast' import.
This satisfies the new warn_redundant_casts mypy rule.

Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL and pi.dev 0.81.1
Signed-off-by: Jan Lindemann <jan@janware.com>
Add warn_redundant_casts = true to the mypy configuration template.
This rule detects casts that mypy proves unnecessary, helping to
clean up redundant type casts that clutter the codebase.

This is one of the boolean-flag rules being gradually adopted from
the stricter mypy profile in /tmp/pyproject.toml. It produces just
1 error during initial rollout.

Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL and pi.dev 0.81.1
Signed-off-by: Jan Lindemann <jan@janware.com>
The comparison ret != 0 is comparing a Result object against the
integer 0, which is always True since Result has no __eq__ defined.

This commit fixes the bug by comparing ret.status instead, which is
the actual exit code we care about. This satisfies the new
strict_equality mypy rule which enables the comparison-overlap check.

Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL and pi.dev 0.81.1
Signed-off-by: Jan Lindemann <jan@janware.com>
Set mypy.strict_equality = true, forcing type-equal equality.

Signed-off-by: Jan Lindemann <jan@janware.com>
Add explicit type arguments to all generic type annotations that were
previously bare, satisfying the new disallow_any_generics mypy rule.

Fixes:
- Distro.py: Iterable[str] for expand_macros fmt parameter
- Cmd.py: Types[Any] for add_subcommands cmds parameter
- AsyncSSH.py: dict[str, Any] for _connect_kwargs return type

Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL and pi.dev 0.81.1
Signed-off-by: Jan Lindemann <jan@janware.com>
Add disallow_any_generics = true to the mypy configuration. This
requires all generic types (dict, list, Iterable, Types, etc.) to
have explicit type arguments instead of using bare generic aliases.

Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL and pi.dev 0.81.1
Signed-off-by: Jan Lindemann <jan@janware.com>
Jan Lindemann scheduled this pull request to auto merge when all checks succeed 2026-08-09 10:59:32 +02:00
Jan Lindemann changed title from pyrightconfig.json: Mirror strict mypy settings to jw.pkg: Massively tighten linter checks 2026-08-09 11:01:25 +02:00
Jan Lindemann force-pushed jan/feature/20260809-pyrightconfig-json-mirror-strict-mypy-settings from c1c1d82d76
Some checks failed
CI / Packaging - Kali Linux (pull_request) Failing after 2m11s
CI / Packaging - OpenSUSE Tumbleweed (pull_request) Failing after 2m43s
CI / Packaging test (pull_request) Failing after 0s
to 1f6da7ff3b
Some checks failed
CI / Packaging - Kali Linux (pull_request) Failing after 2m16s
CI / Packaging - OpenSUSE Tumbleweed (pull_request) Failing after 2m47s
CI / Packaging test (pull_request) Failing after 0s
2026-08-09 14:10:59 +02:00
Compare
Jan Lindemann force-pushed jan/feature/20260809-pyrightconfig-json-mirror-strict-mypy-settings from 1f6da7ff3b
Some checks failed
CI / Packaging - Kali Linux (pull_request) Failing after 2m16s
CI / Packaging - OpenSUSE Tumbleweed (pull_request) Failing after 2m47s
CI / Packaging test (pull_request) Failing after 0s
to be46a5ebcf
All checks were successful
CI / Packaging - Kali Linux (pull_request) Successful in 4m6s
CI / Packaging - OpenSUSE Tumbleweed (pull_request) Successful in 4m12s
CI / Packaging test (pull_request) Successful in 0s
CI / Packaging - Kali Linux (push) Successful in 4m9s
CI / Packaging - OpenSUSE Tumbleweed (push) Successful in 4m0s
CI / Packaging test (push) Successful in 0s
2026-08-09 15:04:15 +02:00
Compare
Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
janware/jw-pkg!53
No description provided.