diff --git a/.basedpyright/baseline.json b/.basedpyright/baseline.json index d28fde67..16b09c48 100644 --- a/.basedpyright/baseline.json +++ b/.basedpyright/baseline.json @@ -59,14 +59,6 @@ } ], "./pytools/__init__.py": [ - { - "code": "reportImportCycles", - "range": { - "startColumn": 0, - "endColumn": 0, - "lineCount": 1 - } - }, { "code": "reportInvalidTypeVarUse", "range": { @@ -627,14 +619,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 16, - "lineCount": 1 - } - }, { "code": "reportUnknownParameterType", "range": { @@ -699,14 +683,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 20, - "lineCount": 1 - } - }, { "code": "reportUnknownParameterType", "range": { @@ -787,14 +763,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 14, - "lineCount": 1 - } - }, { "code": "reportUnknownParameterType", "range": { @@ -835,14 +803,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 14, - "lineCount": 1 - } - }, { "code": "reportUnknownParameterType", "range": { @@ -923,30 +883,6 @@ "lineCount": 1 } }, - { - "code": "reportUnannotatedClassAttribute", - "range": { - "startColumn": 13, - "endColumn": 25, - "lineCount": 1 - } - }, - { - "code": "reportIncompatibleMethodOverride", - "range": { - "startColumn": 8, - "endColumn": 16, - "lineCount": 1 - } - }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 16, - "lineCount": 1 - } - }, { "code": "reportUnsafeMultipleInheritance", "range": { @@ -2059,14 +1995,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 32, - "lineCount": 1 - } - }, { "code": "reportUnknownParameterType", "range": { @@ -4827,14 +4755,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 15, - "lineCount": 1 - } - }, { "code": "reportUnknownMemberType", "range": { @@ -6723,14 +6643,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 15, - "lineCount": 1 - } - }, { "code": "reportUnknownVariableType", "range": { @@ -6747,14 +6659,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 16, - "lineCount": 1 - } - }, { "code": "reportUnknownParameterType", "range": { @@ -7886,8 +7790,8 @@ { "code": "reportUnreachable", "range": { - "startColumn": 16, - "endColumn": 83, + "startColumn": 12, + "endColumn": 58, "lineCount": 1 } } @@ -8677,14 +8581,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 15, - "lineCount": 1 - } - }, { "code": "reportUnknownArgumentType", "range": { @@ -9081,14 +8977,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 15, - "lineCount": 1 - } - }, { "code": "reportUnknownVariableType", "range": { @@ -9225,14 +9113,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 15, - "lineCount": 1 - } - }, { "code": "reportUnknownVariableType", "range": { @@ -9339,14 +9219,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 15, - "lineCount": 1 - } - }, { "code": "reportAny", "range": { @@ -10325,14 +10197,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 19, - "lineCount": 1 - } - }, { "code": "reportUnknownParameterType", "range": { @@ -10389,14 +10253,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 19, - "lineCount": 1 - } - }, { "code": "reportUnknownParameterType", "range": { @@ -10921,14 +10777,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 15, - "lineCount": 1 - } - }, { "code": "reportUnknownArgumentType", "range": { @@ -10985,14 +10833,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 15, - "lineCount": 1 - } - }, { "code": "reportUnknownArgumentType", "range": { @@ -11081,14 +10921,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 15, - "lineCount": 1 - } - }, { "code": "reportUnknownArgumentType", "range": { @@ -11153,14 +10985,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 16, - "lineCount": 1 - } - }, { "code": "reportUnknownParameterType", "range": { @@ -15217,6 +15041,22 @@ "lineCount": 1 } }, + { + "code": "reportUnknownMemberType", + "range": { + "startColumn": 28, + "endColumn": 46, + "lineCount": 1 + } + }, + { + "code": "reportAttributeAccessIssue", + "range": { + "startColumn": 30, + "endColumn": 46, + "lineCount": 1 + } + }, { "code": "reportUnknownMemberType", "range": { @@ -15273,22 +15113,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 19, - "lineCount": 1 - } - }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 15, - "lineCount": 1 - } - }, { "code": "reportAny", "range": { @@ -15297,14 +15121,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 16, - "lineCount": 1 - } - }, { "code": "reportIncompatibleMethodOverride", "range": { @@ -15313,14 +15129,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 12, - "lineCount": 1 - } - }, { "code": "reportAny", "range": { @@ -15345,14 +15153,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 14, - "lineCount": 1 - } - }, { "code": "reportAny", "range": { @@ -15377,14 +15177,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 13, - "lineCount": 1 - } - }, { "code": "reportAny", "range": { @@ -15409,14 +15201,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 16, - "lineCount": 1 - } - }, { "code": "reportUnknownMemberType", "range": { @@ -15434,10 +15218,18 @@ } }, { - "code": "reportImplicitOverride", + "code": "reportUnknownMemberType", "range": { - "startColumn": 8, - "endColumn": 13, + "startColumn": 23, + "endColumn": 41, + "lineCount": 1 + } + }, + { + "code": "reportAttributeAccessIssue", + "range": { + "startColumn": 25, + "endColumn": 41, "lineCount": 1 } }, @@ -15481,38 +15273,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 13, - "lineCount": 1 - } - }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 13, - "lineCount": 1 - } - }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 13, - "lineCount": 1 - } - }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 13, - "lineCount": 1 - } - }, { "code": "reportAny", "range": { @@ -15603,46 +15363,6 @@ } ], "./pytools/prefork.py": [ - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 12, - "lineCount": 1 - } - }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 18, - "lineCount": 1 - } - }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 27, - "lineCount": 1 - } - }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 12, - "lineCount": 1 - } - }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 15, - "lineCount": 1 - } - }, { "code": "reportUnknownVariableType", "range": { @@ -15755,30 +15475,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 12, - "lineCount": 1 - } - }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 18, - "lineCount": 1 - } - }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 27, - "lineCount": 1 - } - }, { "code": "reportReturnType", "range": { @@ -15787,22 +15483,6 @@ "lineCount": 2 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 12, - "lineCount": 1 - } - }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 15, - "lineCount": 1 - } - }, { "code": "reportUnknownVariableType", "range": { @@ -16101,14 +15781,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 20, - "lineCount": 1 - } - }, { "code": "reportUnknownVariableType", "range": { @@ -16573,14 +16245,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 20, - "lineCount": 1 - } - }, { "code": "reportUnknownVariableType", "range": { @@ -18059,22 +17723,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 16, - "lineCount": 1 - } - }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 14, - "lineCount": 1 - } - }, { "code": "reportUnusedParameter", "range": { @@ -18083,22 +17731,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 14, - "lineCount": 1 - } - }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 16, - "lineCount": 1 - } - }, { "code": "reportAny", "range": { @@ -18247,27 +17879,35 @@ "lineCount": 1 } }, + { + "code": "reportUnreachable", + "range": { + "startColumn": 4, + "endColumn": 18, + "lineCount": 16 + } + }, { "code": "reportUnreachable", "range": { "startColumn": 8, - "endColumn": 57, + "endColumn": 14, "lineCount": 1 } }, { - "code": "reportOptionalMemberAccess", + "code": "reportUnreachable", "range": { - "startColumn": 14, - "endColumn": 15, - "lineCount": 1 + "startColumn": 8, + "endColumn": 18, + "lineCount": 3 } }, { - "code": "reportUnusedClass", + "code": "reportUnreachable", "range": { - "startColumn": 14, - "endColumn": 22, + "startColumn": 12, + "endColumn": 18, "lineCount": 1 } } @@ -19189,14 +18829,6 @@ "lineCount": 1 } }, - { - "code": "reportImplicitOverride", - "range": { - "startColumn": 8, - "endColumn": 20, - "lineCount": 1 - } - }, { "code": "reportAny", "range": { @@ -21617,14 +21249,6 @@ "lineCount": 1 } }, - { - "code": "reportIncompatibleMethodOverride", - "range": { - "startColumn": 8, - "endColumn": 12, - "lineCount": 1 - } - }, { "code": "reportImplicitOverride", "range": { diff --git a/pyproject.toml b/pyproject.toml index bb8ca525..918f05a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,9 +43,6 @@ test = [ "pytest", "ruff", ] -siphash = [ - "siphash24>=1.6", -] [project.urls] Documentation = "https://documen.tician.de/pytools/" @@ -112,6 +109,12 @@ reportUnnecessaryIsInstance = "none" reportUnusedCallResult = "none" reportExplicitAny = "none" +# This reports even cycles that are qualified by 'if TYPE_CHECKING'. Not what +# we care about at this moment. +# https://github.com/microsoft/pyright/issues/746 +reportImportCycles = "none" +pythonVersion = "3.10" +pythonPlatform = "All" [tool.mypy] python_version = "3.10" diff --git a/pytools/__init__.py b/pytools/__init__.py index 5440d01d..44c7ad6e 100644 --- a/pytools/__init__.py +++ b/pytools/__init__.py @@ -57,7 +57,7 @@ cast, ) -from typing_extensions import Self, dataclass_transform +from typing_extensions import Self, dataclass_transform, override from pytools.version import VERSION_TEXT @@ -441,6 +441,7 @@ def get_copy_kwargs(self, **kwargs): def copy(self, **kwargs): return self.__class__(**self.get_copy_kwargs(**kwargs)) + @override def __repr__(self): return "{}({})".format( self.__class__.__name__, @@ -483,23 +484,28 @@ def __setstate__(self, valuedict): fields.add(key) setattr(self, key, value) + @override def __eq__(self, other): if self is other: return True return (self.__class__ == other.__class__ and self.__getstate__() == other.__getstate__()) + @override def __ne__(self, other): return not self.__eq__(other) class ImmutableRecordWithoutPickling(RecordWithoutPickling): """Hashable record. Does not explicitly enforce immutability.""" + _cached_hash: int | None + def __init__(self, *args, **kwargs): RecordWithoutPickling.__init__(self, *args, **kwargs) self._cached_hash = None - def __hash__(self): + @override + def __hash__(self) -> int: # This attribute may vanish during pickling. if getattr(self, "_cached_hash", None) is None: self._cached_hash = hash(( @@ -507,6 +513,7 @@ def __hash__(self): *(getattr(self, field) for field in self.__class__.fields) )) + assert self._cached_hash is not None return self._cached_hash @@ -876,6 +883,7 @@ class keyed_memoize_method(keyed_memoize_on_first_arg): # noqa: N801 Can memoize methods on classes that do not allow setting attributes (e.g. by overwriting ``__setattr__``), e.g. frozen :mod:`dataclasses`. """ + @override def _default_cache_dict_name(self, function): return intern(f"_memoize_dic_{function.__name__}") @@ -1631,6 +1639,7 @@ def _get_column_widths(self, rows) -> tuple[int, ...]: max(len(row[i]) for row in rows) for i in range(self.ncolumns) ) + @override def __str__(self) -> str: """ Returns a string representation of the table. @@ -2499,10 +2508,12 @@ def done(self): self.wall_elapsed = time.perf_counter() - self.perf_counter_start self.process_elapsed = time.process_time() - self.process_time_start + @override def __str__(self): cpu = self.process_elapsed / self.wall_elapsed return f"{self.wall_elapsed:.2f}s wall {cpu:.2f}x CPU" + @override def __repr__(self): wall = self.wall_elapsed process = self.process_elapsed diff --git a/pytools/batchjob.py b/pytools/batchjob.py index 84235a6c..a9790520 100644 --- a/pytools/batchjob.py +++ b/pytools/batchjob.py @@ -1,5 +1,7 @@ from __future__ import annotations +from typing_extensions import override + def _cp(src, dest): from pytools import assert_not_a_file @@ -134,6 +136,7 @@ def arg(self, i): def kwarg(self, name): return self.kwargs[name] + @override def __str__(self): return "{}({})".format(self.classname, ",".join( diff --git a/pytools/convergence.py b/pytools/convergence.py index 0b6ae0e7..56e1267d 100644 --- a/pytools/convergence.py +++ b/pytools/convergence.py @@ -10,6 +10,7 @@ import numbers import numpy as np +from typing_extensions import override # {{{ eoc estimation -------------------------------------------------------------- @@ -141,6 +142,7 @@ def pretty_print(self, *, return tbl.csv() raise ValueError(f"unknown table type: {table_type}") + @override def __str__(self): return self.pretty_print() @@ -211,6 +213,7 @@ def add_data_point(self, order, error): self.orders.append(order) self.errors.append(error) + @override def __str__(self): from pytools import Table tbl = Table() diff --git a/pytools/datatable.py b/pytools/datatable.py index 7f34e3e6..126ed4ba 100644 --- a/pytools/datatable.py +++ b/pytools/datatable.py @@ -1,20 +1,22 @@ +""" +An in-memory relational database table +====================================== + +.. autoclass:: DataTable +""" + from __future__ import annotations from typing import IO, TYPE_CHECKING, Any +from typing_extensions import override + from pytools import Record if TYPE_CHECKING: from collections.abc import Callable, Iterator, Sequence -__doc__ = """ -An in-memory relational database table -====================================== - -.. autoclass:: DataTable -""" - class Row(Record): pass @@ -58,6 +60,7 @@ def __len__(self) -> int: def __iter__(self) -> Iterator[list[Any]]: return self.data.__iter__() + @override def __str__(self) -> str: """Return a pretty-printed version of the table.""" diff --git a/pytools/debug.py b/pytools/debug.py index 0fc125c8..14f900dd 100644 --- a/pytools/debug.py +++ b/pytools/debug.py @@ -3,6 +3,8 @@ import contextlib import sys +from typing_extensions import override + from pytools import memoize @@ -177,10 +179,12 @@ def __init__(self, source_dicts, target_dict): self.target_dict = target_dict + @override def __setitem__(self, key, value): dict.__setitem__(self, key, value) self.target_dict[key] = value + @override def __delitem__(self, key): dict.__delitem__(self, key) del self.target_dict[key] diff --git a/pytools/lex.py b/pytools/lex.py index d6844243..f77c60b4 100644 --- a/pytools/lex.py +++ b/pytools/lex.py @@ -2,12 +2,15 @@ import re +from typing_extensions import override + class RuleError(RuntimeError): def __init__(self, rule): RuntimeError.__init__(self) self.Rule = rule + @override def __str__(self): return repr(self.Rule) @@ -18,6 +21,7 @@ def __init__(self, s, str_index): self.string = s self.index = str_index + @override def __str__(self): return "at index {}: ...{}...".format( self.index, self.string[self.index:self.index+20]) @@ -30,6 +34,7 @@ def __init__(self, msg, s, token): self.string = s self.Token = token + @override def __str__(self): if self.Token is None: return f"{self.message} at end of input" @@ -43,6 +48,7 @@ def __init__(self, s: str, flags: int = 0) -> None: self.Content = s self.RE = re.compile(s, flags) + @override def __repr__(self) -> str: return f"RE({self.Content})" diff --git a/pytools/persistent_dict.py b/pytools/persistent_dict.py index 3f62425e..0f24967c 100644 --- a/pytools/persistent_dict.py +++ b/pytools/persistent_dict.py @@ -1,5 +1,7 @@ from __future__ import annotations +from typing_extensions import override + """Generic persistent, concurrent dictionary-like facility.""" @@ -573,6 +575,7 @@ def _make_container_dir(self) -> None: """Create the container directory to store the dictionary.""" os.makedirs(self.container_dir, exist_ok=True) + @override def __getitem__(self, key: K) -> V: """Return the value associated with *key* in the dictionary.""" return self.fetch(key) @@ -581,26 +584,31 @@ def __setitem__(self, key: K, value: V) -> None: """Store (*key*, *value*) in the dictionary.""" self.store(key, value) + @override def __len__(self) -> int: """Return the number of entries in the dictionary.""" result, = next(self._exec_sql("SELECT COUNT(*) FROM dict")) assert isinstance(result, int) return result + @override def __iter__(self) -> Iterator[K]: """Return an iterator over the keys in the dictionary.""" return self.keys() + @override def keys(self) -> Iterator[K]: # type: ignore[override] """Return an iterator over the keys in the dictionary.""" for row in self._exec_sql("SELECT key_value FROM dict ORDER BY rowid"): yield pickle.loads(row[0])[0] + @override def values(self) -> Iterator[V]: # type: ignore[override] """Return an iterator over the values in the dictionary.""" for row in self._exec_sql("SELECT key_value FROM dict ORDER BY rowid"): yield pickle.loads(row[0])[1] + @override def items(self) -> Iterator[tuple[K, V]]: # type: ignore[override] """Return an iterator over the items in the dictionary.""" for row in self._exec_sql("SELECT key_value FROM dict ORDER BY rowid"): @@ -614,6 +622,7 @@ def nbytes(self) -> int: return result + @override def __repr__(self) -> str: """Return a string representation of the dictionary.""" return f"{type(self).__name__}({self.filename}, nitems={len(self)})" @@ -690,6 +699,7 @@ def clear_in_mem_cache(self) -> None: """ self._fetch.cache_clear() + @override def store(self, key: K, value: V, _skip_if_present: bool = False) -> None: keyhash = self.key_builder(key) v = pickle.dumps((key, value)) @@ -730,6 +740,7 @@ def fetch_inner() -> tuple[Any] | None: key, value = pickle.loads(row[0]) return key, value + @override def fetch(self, key: K) -> V: keyhash = self.key_builder(key) @@ -741,6 +752,7 @@ def fetch(self, key: K) -> V: self._collision_check(key, stored_key) return value + @override def clear(self) -> None: super().clear() self._fetch.cache_clear() @@ -796,6 +808,7 @@ def __init__(self, enable_wal=enable_wal, safe_sync=safe_sync) + @override def store(self, key: K, value: V, _skip_if_present: bool = False) -> None: keyhash = self.key_builder(key) v = pickle.dumps((key, value)) @@ -805,6 +818,7 @@ def store(self, key: K, value: V, _skip_if_present: bool = False) -> None: self._exec_sql(f"INSERT OR {mode} INTO dict VALUES (?, ?)", (keyhash, v)) + @override def fetch(self, key: K) -> V: keyhash = self.key_builder(key) diff --git a/pytools/prefork.py b/pytools/prefork.py index 14cca3f6..574d8ef7 100644 --- a/pytools/prefork.py +++ b/pytools/prefork.py @@ -26,6 +26,8 @@ from subprocess import Popen from typing import TYPE_CHECKING, Any +from typing_extensions import override + if TYPE_CHECKING: from collections.abc import Sequence @@ -65,6 +67,7 @@ def __init__(self) -> None: self.apids: dict[int, Popen[bytes]] = {} self.count: int = 0 + @override def call(self, cmdline: Sequence[str], cwd: str | None = None) -> int: from subprocess import call as spcall @@ -74,6 +77,7 @@ def call(self, cmdline: Sequence[str], cwd: str | None = None) -> int: raise ExecError( "error invoking '{}': {}".format(" ".join(cmdline), e)) from e + @override def call_async(self, cmdline: Sequence[str], cwd: str | None = None) -> int: try: self.count += 1 @@ -86,6 +90,7 @@ def call_async(self, cmdline: Sequence[str], cwd: str | None = None) -> int: raise ExecError( "error invoking '{}': {}".format(" ".join(cmdline), e)) from e + @override def call_capture_output(self, cmdline: Sequence[str], cwd: str | None = None, @@ -108,12 +113,14 @@ def call_capture_output(self, raise ExecError( "error invoking '{}': {}".format(" ".join(cmdline), e)) from e + @override def wait(self, aid: int) -> int: proc = self.apids.pop(aid) retc = proc.wait() return retc + @override def waitall(self) -> dict[int, int]: rets = {} @@ -225,18 +232,21 @@ def _quit(self) -> None: from os import waitpid waitpid(self.server_pid, 0) + @override def call(self, cmdline: Sequence[str], cwd: str | None = None) -> int: result = self._remote_invoke("call", cmdline, cwd) assert isinstance(result, int) return result + @override def call_async(self, cmdline: Sequence[str], cwd: str | None = None) -> int: result = self._remote_invoke("call_async", cmdline, cwd) assert isinstance(result, int) return result + @override def call_capture_output(self, cmdline: Sequence[str], cwd: str | None = None, @@ -245,12 +255,14 @@ def call_capture_output(self, return self._remote_invoke("call_capture_output", cmdline, cwd, # type: ignore[return-value] error_on_nonzero) + @override def wait(self, aid: int) -> int: result = self._remote_invoke("wait", aid) assert isinstance(result, int) return result + @override def waitall(self) -> dict[int, int]: result = self._remote_invoke("waitall") diff --git a/pytools/tag.py b/pytools/tag.py index 70d15515..d1b43ef4 100644 --- a/pytools/tag.py +++ b/pytools/tag.py @@ -30,7 +30,7 @@ from typing import TYPE_CHECKING, Any, TypeVar from warnings import warn -from typing_extensions import Self, dataclass_transform +from typing_extensions import Self, dataclass_transform, override from pytools import memoize, memoize_method @@ -101,9 +101,11 @@ def from_class(cls, argcls: Any) -> DottedName: "start with double underscores") return cls(name_parts) + @override def __repr__(self) -> str: return self.__class__.__name__ + repr(self.name_parts) + @override def __eq__(self, other: object) -> bool: if isinstance(other, DottedName): return self.name_parts == other.name_parts @@ -253,11 +255,10 @@ def __init__(self, tags: frozenset[Tag] = frozenset()): # ReST references in docstrings must be fully qualified, as docstrings may # be inherited and appear in different contexts. - # type-checking only so that self.tags = ... in subclasses still works - if TYPE_CHECKING: - @property - def tags(self) -> frozenset[Tag]: - ... + # Before https://peps.python.org/pep-0767/, there isn't a good way to declare + # an attribute read-only. Mypy accepts @property, but this is unsound: + # https://peps.python.org/pep-0767/#clarifying-interaction-of-property-and-protocols + tags: frozenset[Tag] # pyright: ignore[reportUninitializedInstanceVariable] def _with_new_tags(self, tags: frozenset[Tag]) -> Self: """ @@ -324,11 +325,13 @@ def tags_not_of_type(self, tag_t: type[TagT]) -> frozenset[Tag]: for tag in self.tags if not isinstance(tag, tag_t)}) + @override def __eq__(self, other: object) -> bool: if isinstance(other, Taggable): return self.tags == other.tags return super().__eq__(other) + @override def __hash__(self) -> int: return hash(self.tags)