Enable check_untyped_defs and make mypy hook blocking
Fix the 13 errors that surfaced under mypy --check-untyped-defs so the flag can be turned on permanently in pyproject.toml, and drop the advisory exit-0 wrapper on the mypy pre-commit hook now that the tree is clean. - _plugin_manager: rename colliding loop vars (module/name were reused with conflicting types) and guard spec/spec.loader from spec_from_file_location; call __init__ via the class in __setstate__. - __main__: pass Verbosity(options.verbose), not a bare int. - subprocess/_check: widen package to str | Mapping[str, str] to match _error_trailer's existing per-platform handling. - optimize.main: annotate the standalone PdfContext(..., None, None) that only ever reads context.options.
This commit is contained in:
@@ -56,11 +56,9 @@ require_serial = true
|
|||||||
|
|
||||||
[[repos.hooks]]
|
[[repos.hooks]]
|
||||||
id = "mypy"
|
id = "mypy"
|
||||||
name = "mypy (advisory — reports errors, does not fail)"
|
name = "mypy"
|
||||||
language = "system"
|
language = "system"
|
||||||
# Errors are pre-existing debt (87 across 22 files as of 2026-07); reports but
|
entry = "uv run mypy src/ocrmypdf"
|
||||||
# never fails the hook until that debt is fixed and this can be made blocking.
|
|
||||||
entry = "bash -c 'uv run mypy src/ocrmypdf; exit 0'"
|
|
||||||
types = ["python"]
|
types = ["python"]
|
||||||
pass_filenames = false
|
pass_filenames = false
|
||||||
require_serial = true
|
require_serial = true
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ filterwarnings = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[tool.mypy]
|
[tool.mypy]
|
||||||
|
check_untyped_defs = true
|
||||||
|
|
||||||
[[tool.mypy.overrides]]
|
[[tool.mypy.overrides]]
|
||||||
module = [
|
module = [
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ def run(args=None):
|
|||||||
with suppress(AttributeError, PermissionError):
|
with suppress(AttributeError, PermissionError):
|
||||||
os.nice(5)
|
os.nice(5)
|
||||||
|
|
||||||
verbosity = options.verbose
|
verbosity = Verbosity(options.verbose)
|
||||||
if not os.isatty(sys.stderr.fileno()):
|
if not os.isatty(sys.stderr.fileno()):
|
||||||
options.progress_bar = False
|
options.progress_bar = False
|
||||||
if options.quiet:
|
if options.quiet:
|
||||||
|
|||||||
@@ -76,7 +76,8 @@ class OcrmypdfPluginManager:
|
|||||||
return state
|
return state
|
||||||
|
|
||||||
def __setstate__(self, state):
|
def __setstate__(self, state):
|
||||||
self.__init__(
|
OcrmypdfPluginManager.__init__(
|
||||||
|
self,
|
||||||
*state['init_args'],
|
*state['init_args'],
|
||||||
plugins=state['plugins'],
|
plugins=state['plugins'],
|
||||||
builtins=state['builtins'],
|
builtins=state['builtins'],
|
||||||
@@ -88,10 +89,10 @@ class OcrmypdfPluginManager:
|
|||||||
|
|
||||||
# 1. Register builtins
|
# 1. Register builtins
|
||||||
if self._builtins:
|
if self._builtins:
|
||||||
for module in sorted(
|
for module_info in sorted(
|
||||||
pkgutil.iter_modules(ocrmypdf.builtin_plugins.__path__)
|
pkgutil.iter_modules(ocrmypdf.builtin_plugins.__path__)
|
||||||
):
|
):
|
||||||
name = f'ocrmypdf.builtin_plugins.{module.name}'
|
name = f'ocrmypdf.builtin_plugins.{module_info.name}'
|
||||||
module = importlib.import_module(name)
|
module = importlib.import_module(name)
|
||||||
self._pm.register(module)
|
self._pm.register(module)
|
||||||
|
|
||||||
@@ -99,17 +100,20 @@ class OcrmypdfPluginManager:
|
|||||||
self._pm.load_setuptools_entrypoints('ocrmypdf')
|
self._pm.load_setuptools_entrypoints('ocrmypdf')
|
||||||
|
|
||||||
# 3. Register plugins specified on command line
|
# 3. Register plugins specified on command line
|
||||||
for name in self._plugins:
|
for plugin in self._plugins:
|
||||||
if isinstance(name, Path) or name.endswith('.py'):
|
if isinstance(plugin, Path) or plugin.endswith('.py'):
|
||||||
# Import by filename
|
# Import by filename
|
||||||
module_name = Path(name).stem
|
plugin_path = Path(plugin)
|
||||||
spec = importlib.util.spec_from_file_location(module_name, name)
|
module_name = plugin_path.stem
|
||||||
|
spec = importlib.util.spec_from_file_location(module_name, plugin_path)
|
||||||
|
if spec is None or spec.loader is None:
|
||||||
|
raise ImportError(f'Could not load plugin from {plugin_path}')
|
||||||
module = importlib.util.module_from_spec(spec)
|
module = importlib.util.module_from_spec(spec)
|
||||||
sys.modules[module_name] = module
|
sys.modules[module_name] = module
|
||||||
spec.loader.exec_module(module)
|
spec.loader.exec_module(module)
|
||||||
else:
|
else:
|
||||||
# Import by dotted module name
|
# Import by dotted module name
|
||||||
module = importlib.import_module(name)
|
module = importlib.import_module(plugin)
|
||||||
self._pm.register(module)
|
self._pm.register(module)
|
||||||
|
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
|
|||||||
@@ -774,7 +774,9 @@ def main(infile, outfile, level, jobs=1):
|
|||||||
)
|
)
|
||||||
|
|
||||||
with TemporaryDirectory() as tmpdir:
|
with TemporaryDirectory() as tmpdir:
|
||||||
context = PdfContext(options, Path(tmpdir), infile, None, None)
|
# optimize() only reads context.options on this standalone path, so
|
||||||
|
# pdfinfo and plugin_manager are not needed.
|
||||||
|
context = PdfContext(options, Path(tmpdir), infile, None, None) # type: ignore[arg-type]
|
||||||
tmpout = Path(tmpdir) / 'out.pdf'
|
tmpout = Path(tmpdir) / 'out.pdf'
|
||||||
optimize(
|
optimize(
|
||||||
infile,
|
infile,
|
||||||
|
|||||||
@@ -94,7 +94,10 @@ def _error_trailer(program: str, package: str | Mapping[str, str], **kwargs) ->
|
|||||||
|
|
||||||
|
|
||||||
def _error_missing_program(
|
def _error_missing_program(
|
||||||
program: str, package: str, required_for: str | None, recommended: bool
|
program: str,
|
||||||
|
package: str | Mapping[str, str],
|
||||||
|
required_for: str | None,
|
||||||
|
recommended: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
if recommended:
|
if recommended:
|
||||||
@@ -108,7 +111,7 @@ def _error_missing_program(
|
|||||||
|
|
||||||
def _error_old_version(
|
def _error_old_version(
|
||||||
program: str,
|
program: str,
|
||||||
package: str,
|
package: str | Mapping[str, str],
|
||||||
need_version: str,
|
need_version: str,
|
||||||
found_version: str,
|
found_version: str,
|
||||||
required_for: str | None,
|
required_for: str | None,
|
||||||
@@ -124,7 +127,7 @@ def _error_old_version(
|
|||||||
def check_external_program(
|
def check_external_program(
|
||||||
*,
|
*,
|
||||||
program: str,
|
program: str,
|
||||||
package: str,
|
package: str | Mapping[str, str],
|
||||||
version_checker: Callable[[], Version],
|
version_checker: Callable[[], Version],
|
||||||
need_version: str | Version,
|
need_version: str | Version,
|
||||||
required_for: str | None = None,
|
required_for: str | None = None,
|
||||||
|
|||||||
Reference in New Issue
Block a user