mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
Fix mypy not picking up on missing attributes
Behaviour changed in recent releases: https://github.com/python/mypy/issues/13319
This commit is contained in:
parent
3973f27ee4
commit
2504ad0b99
7 changed files with 70 additions and 62 deletions
|
@ -7,7 +7,7 @@ import functools
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import traceback
|
import traceback
|
||||||
from typing import Any, Callable, Union, no_type_check
|
from typing import TYPE_CHECKING, Any, Callable, Union
|
||||||
|
|
||||||
from anki._vendor import stringcase
|
from anki._vendor import stringcase
|
||||||
|
|
||||||
|
@ -66,21 +66,20 @@ class DeprecatedNamesMixin:
|
||||||
# deprecated name -> [new internal name, new name shown to user]
|
# deprecated name -> [new internal name, new name shown to user]
|
||||||
_deprecated_attributes: dict[str, tuple[str, str | None]] = {}
|
_deprecated_attributes: dict[str, tuple[str, str | None]] = {}
|
||||||
|
|
||||||
# the @no_type_check lines are required to prevent mypy allowing arbitrary
|
# TYPE_CHECKING check is required for https://github.com/python/mypy/issues/13319
|
||||||
# attributes on the consuming class
|
if not TYPE_CHECKING:
|
||||||
|
|
||||||
@no_type_check
|
def __getattr__(self, name: str) -> Any:
|
||||||
def __getattr__(self, name: str) -> Any:
|
try:
|
||||||
try:
|
remapped, replacement = _get_remapped_and_replacement(self, name)
|
||||||
remapped, replacement = _get_remapped_and_replacement(self, name)
|
out = getattr(self, remapped)
|
||||||
out = getattr(self, remapped)
|
except AttributeError:
|
||||||
except AttributeError:
|
raise AttributeError(
|
||||||
raise AttributeError(
|
f"'{self.__class__.__name__}' object has no attribute '{name}'"
|
||||||
f"'{self.__class__.__name__}' object has no attribute '{name}'"
|
) from None
|
||||||
) from None
|
|
||||||
|
|
||||||
_print_replacement_warning(name, replacement)
|
_print_replacement_warning(name, replacement)
|
||||||
return out
|
return out
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def register_deprecated_aliases(cls, **kwargs: DeprecatedAliasTarget) -> None:
|
def register_deprecated_aliases(cls, **kwargs: DeprecatedAliasTarget) -> None:
|
||||||
|
@ -123,9 +122,9 @@ class DeprecatedNamesMixinForModule:
|
||||||
_deprecated_names.register_deprecated_aliases(...
|
_deprecated_names.register_deprecated_aliases(...
|
||||||
_deprecated_names.register_deprecated_attributes(...
|
_deprecated_names.register_deprecated_attributes(...
|
||||||
|
|
||||||
@no_type_check
|
if not TYPE_CHECKING:
|
||||||
def __getattr__(name: str) -> Any:
|
def __getattr__(name: str) -> Any:
|
||||||
return _deprecated_names.__getattr__(name)
|
return _deprecated_names.__getattr__(name)
|
||||||
```
|
```
|
||||||
See DeprecatedNamesMixin for more documentation.
|
See DeprecatedNamesMixin for more documentation.
|
||||||
"""
|
"""
|
||||||
|
@ -135,19 +134,20 @@ class DeprecatedNamesMixinForModule:
|
||||||
self._deprecated_aliases: dict[str, str] = {}
|
self._deprecated_aliases: dict[str, str] = {}
|
||||||
self._deprecated_attributes: dict[str, tuple[str, str | None]] = {}
|
self._deprecated_attributes: dict[str, tuple[str, str | None]] = {}
|
||||||
|
|
||||||
@no_type_check
|
if not TYPE_CHECKING:
|
||||||
def __getattr__(self, name: str) -> Any:
|
|
||||||
try:
|
|
||||||
remapped, replacement = _get_remapped_and_replacement(self, name)
|
|
||||||
out = self.module_globals[remapped]
|
|
||||||
except (AttributeError, KeyError):
|
|
||||||
raise AttributeError(
|
|
||||||
f"Module '{self.module_globals['__name__']}' has no attribute '{name}'"
|
|
||||||
) from None
|
|
||||||
|
|
||||||
# skip an additional frame as we are called from the module `__getattr__`
|
def __getattr__(self, name: str) -> Any:
|
||||||
_print_replacement_warning(name, replacement, frame=2)
|
try:
|
||||||
return out
|
remapped, replacement = _get_remapped_and_replacement(self, name)
|
||||||
|
out = self.module_globals[remapped]
|
||||||
|
except (AttributeError, KeyError):
|
||||||
|
raise AttributeError(
|
||||||
|
f"Module '{self.module_globals['__name__']}' has no attribute '{name}'"
|
||||||
|
) from None
|
||||||
|
|
||||||
|
# skip an additional frame as we are called from the module `__getattr__`
|
||||||
|
_print_replacement_warning(name, replacement, frame=2)
|
||||||
|
return out
|
||||||
|
|
||||||
def register_deprecated_aliases(self, **kwargs: DeprecatedAliasTarget) -> None:
|
def register_deprecated_aliases(self, **kwargs: DeprecatedAliasTarget) -> None:
|
||||||
self._deprecated_aliases = {k: _target_to_string(v) for k, v in kwargs.items()}
|
self._deprecated_aliases = {k: _target_to_string(v) for k, v in kwargs.items()}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
from typing import Any, NewType, no_type_check
|
from typing import TYPE_CHECKING, Any, NewType
|
||||||
|
|
||||||
from anki._legacy import DeprecatedNamesMixinForModule
|
from anki._legacy import DeprecatedNamesMixinForModule
|
||||||
|
|
||||||
|
@ -132,6 +132,7 @@ def new_card_scheduling_labels(
|
||||||
_deprecated_names = DeprecatedNamesMixinForModule(globals())
|
_deprecated_names = DeprecatedNamesMixinForModule(globals())
|
||||||
|
|
||||||
|
|
||||||
@no_type_check
|
if not TYPE_CHECKING:
|
||||||
def __getattr__(name: str) -> Any:
|
|
||||||
return _deprecated_names.__getattr__(name)
|
def __getattr__(name: str) -> Any:
|
||||||
|
return _deprecated_names.__getattr__(name)
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
from typing import TYPE_CHECKING, Any, Iterable, NewType, Sequence, no_type_check
|
from typing import TYPE_CHECKING, Any, Iterable, NewType, Sequence
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import anki
|
import anki
|
||||||
|
@ -590,15 +590,18 @@ DeckManager.register_deprecated_aliases(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@no_type_check
|
if not TYPE_CHECKING:
|
||||||
def __getattr__(name):
|
|
||||||
if name == "defaultDeck":
|
def __getattr__(name):
|
||||||
print_deprecation_warning(
|
if name == "defaultDeck":
|
||||||
"defaultDeck is deprecated; call decks.id() without it"
|
print_deprecation_warning(
|
||||||
)
|
"defaultDeck is deprecated; call decks.id() without it"
|
||||||
return 0
|
)
|
||||||
elif name == "defaultDynamicDeck":
|
return 0
|
||||||
print_deprecation_warning("defaultDynamicDeck is replaced with new_filtered()")
|
elif name == "defaultDynamicDeck":
|
||||||
return 1
|
print_deprecation_warning(
|
||||||
else:
|
"defaultDynamicDeck is replaced with new_filtered()"
|
||||||
raise AttributeError(f"module {__name__} has no attribute {name}")
|
)
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
raise AttributeError(f"module {__name__} has no attribute {name}")
|
||||||
|
|
|
@ -6,7 +6,7 @@ from __future__ import annotations
|
||||||
import locale
|
import locale
|
||||||
import re
|
import re
|
||||||
import weakref
|
import weakref
|
||||||
from typing import Any, no_type_check
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
import anki
|
import anki
|
||||||
import anki._backend
|
import anki._backend
|
||||||
|
@ -224,6 +224,7 @@ def with_collapsed_whitespace(string: str) -> str:
|
||||||
_deprecated_names = DeprecatedNamesMixinForModule(globals())
|
_deprecated_names = DeprecatedNamesMixinForModule(globals())
|
||||||
|
|
||||||
|
|
||||||
@no_type_check
|
if not TYPE_CHECKING:
|
||||||
def __getattr__(name: str) -> Any:
|
|
||||||
return _deprecated_names.__getattr__(name)
|
def __getattr__(name: str) -> Any:
|
||||||
|
return _deprecated_names.__getattr__(name)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any, Callable, no_type_check
|
from typing import TYPE_CHECKING, Any, Callable
|
||||||
|
|
||||||
import anki.collection
|
import anki.collection
|
||||||
import anki.models
|
import anki.models
|
||||||
|
@ -115,6 +115,7 @@ _deprecated_names.register_deprecated_attributes(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@no_type_check
|
if not TYPE_CHECKING:
|
||||||
def __getattr__(name: str) -> Any:
|
|
||||||
return _deprecated_names.__getattr__(name)
|
def __getattr__(name: str) -> Any:
|
||||||
|
return _deprecated_names.__getattr__(name)
|
||||||
|
|
|
@ -16,7 +16,7 @@ import tempfile
|
||||||
import time
|
import time
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
from typing import Any, Callable, Iterable, Iterator, no_type_check
|
from typing import TYPE_CHECKING, Any, Callable, Iterable, Iterator
|
||||||
|
|
||||||
from anki._legacy import DeprecatedNamesMixinForModule
|
from anki._legacy import DeprecatedNamesMixinForModule
|
||||||
from anki.dbproxy import DBProxy
|
from anki.dbproxy import DBProxy
|
||||||
|
@ -324,6 +324,7 @@ _deprecated_names.register_deprecated_aliases(
|
||||||
_deprecated_names.register_deprecated_attributes(json=((_json, "_json"), None))
|
_deprecated_names.register_deprecated_attributes(json=((_json, "_json"), None))
|
||||||
|
|
||||||
|
|
||||||
@no_type_check
|
if not TYPE_CHECKING:
|
||||||
def __getattr__(name: str) -> Any:
|
|
||||||
return _deprecated_names.__getattr__(name)
|
def __getattr__(name: str) -> Any:
|
||||||
|
return _deprecated_names.__getattr__(name)
|
||||||
|
|
|
@ -9,7 +9,7 @@ import subprocess
|
||||||
import sys
|
import sys
|
||||||
from functools import partial, wraps
|
from functools import partial, wraps
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING, Any, Callable, Literal, Sequence, Union, no_type_check
|
from typing import TYPE_CHECKING, Any, Callable, Literal, Sequence, Union
|
||||||
|
|
||||||
from send2trash import send2trash
|
from send2trash import send2trash
|
||||||
|
|
||||||
|
@ -1243,6 +1243,7 @@ class KeyboardModifiersPressed:
|
||||||
_deprecated_names = DeprecatedNamesMixinForModule(globals())
|
_deprecated_names = DeprecatedNamesMixinForModule(globals())
|
||||||
|
|
||||||
|
|
||||||
@no_type_check
|
if not TYPE_CHECKING:
|
||||||
def __getattr__(name: str) -> Any:
|
|
||||||
return _deprecated_names.__getattr__(name)
|
def __getattr__(name: str) -> Any:
|
||||||
|
return _deprecated_names.__getattr__(name)
|
||||||
|
|
Loading…
Reference in a new issue