mirror of https://github.com/scrapy/scrapy.git
Add typing to scrapy/utils/deprecate.py.
This commit is contained in:
parent
d400f1ac06
commit
9661a5c491
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
import inspect
|
||||
import warnings
|
||||
from typing import List, Tuple
|
||||
from typing import Any, List, Optional, Tuple, Type, overload
|
||||
|
||||
from scrapy.exceptions import ScrapyDeprecationWarning
|
||||
|
||||
|
||||
def attribute(obj, oldattr, newattr, version="0.12"):
|
||||
def attribute(obj: Any, oldattr: str, newattr: str, version: str = "0.12") -> None:
|
||||
cname = obj.__class__.__name__
|
||||
warnings.warn(
|
||||
f"{cname}.{oldattr} attribute is deprecated and will be no longer supported "
|
||||
|
|
@ -18,16 +18,16 @@ def attribute(obj, oldattr, newattr, version="0.12"):
|
|||
|
||||
|
||||
def create_deprecated_class(
|
||||
name,
|
||||
new_class,
|
||||
clsdict=None,
|
||||
warn_category=ScrapyDeprecationWarning,
|
||||
warn_once=True,
|
||||
old_class_path=None,
|
||||
new_class_path=None,
|
||||
subclass_warn_message="{cls} inherits from deprecated class {old}, please inherit from {new}.",
|
||||
instance_warn_message="{cls} is deprecated, instantiate {new} instead.",
|
||||
):
|
||||
name: str,
|
||||
new_class: type,
|
||||
clsdict: Optional[dict[str, Any]] = None,
|
||||
warn_category: Type[Warning] = ScrapyDeprecationWarning,
|
||||
warn_once: bool = True,
|
||||
old_class_path: Optional[str] = None,
|
||||
new_class_path: Optional[str] = None,
|
||||
subclass_warn_message: str = "{cls} inherits from deprecated class {old}, please inherit from {new}.",
|
||||
instance_warn_message: str = "{cls} is deprecated, instantiate {new} instead.",
|
||||
) -> type:
|
||||
"""
|
||||
Return a "deprecated" class that causes its subclasses to issue a warning.
|
||||
Subclasses of ``new_class`` are considered subclasses of this class.
|
||||
|
|
@ -53,17 +53,20 @@ def create_deprecated_class(
|
|||
OldName.
|
||||
"""
|
||||
|
||||
class DeprecatedClass(new_class.__class__):
|
||||
deprecated_class = None
|
||||
warned_on_subclass = False
|
||||
# https://github.com/python/mypy/issues/4177
|
||||
class DeprecatedClass(new_class.__class__): # type: ignore[misc, name-defined]
|
||||
deprecated_class: Optional[type] = None
|
||||
warned_on_subclass: bool = False
|
||||
|
||||
def __new__(metacls, name, bases, clsdict_):
|
||||
def __new__(
|
||||
metacls, name: str, bases: Tuple[type, ...], clsdict_: dict[str, Any]
|
||||
) -> type:
|
||||
cls = super().__new__(metacls, name, bases, clsdict_)
|
||||
if metacls.deprecated_class is None:
|
||||
metacls.deprecated_class = cls
|
||||
return cls
|
||||
|
||||
def __init__(cls, name, bases, clsdict_):
|
||||
def __init__(cls, name: str, bases: Tuple[type, ...], clsdict_: dict[str, Any]):
|
||||
meta = cls.__class__
|
||||
old = meta.deprecated_class
|
||||
if old in bases and not (warn_once and meta.warned_on_subclass):
|
||||
|
|
@ -81,10 +84,10 @@ def create_deprecated_class(
|
|||
# see https://www.python.org/dev/peps/pep-3119/#overloading-isinstance-and-issubclass
|
||||
# and https://docs.python.org/reference/datamodel.html#customizing-instance-and-subclass-checks
|
||||
# for implementation details
|
||||
def __instancecheck__(cls, inst):
|
||||
def __instancecheck__(cls, inst: Any) -> bool:
|
||||
return any(cls.__subclasscheck__(c) for c in (type(inst), inst.__class__))
|
||||
|
||||
def __subclasscheck__(cls, sub):
|
||||
def __subclasscheck__(cls, sub: type) -> bool:
|
||||
if cls is not DeprecatedClass.deprecated_class:
|
||||
# we should do the magic only if second `issubclass` argument
|
||||
# is the deprecated class itself - subclasses of the
|
||||
|
|
@ -98,7 +101,7 @@ def create_deprecated_class(
|
|||
mro = getattr(sub, "__mro__", ())
|
||||
return any(c in {cls, new_class} for c in mro)
|
||||
|
||||
def __call__(cls, *args, **kwargs):
|
||||
def __call__(cls, *args: Any, **kwargs: Any) -> Any:
|
||||
old = DeprecatedClass.deprecated_class
|
||||
if cls is old:
|
||||
msg = instance_warn_message.format(
|
||||
|
|
@ -125,7 +128,7 @@ def create_deprecated_class(
|
|||
return deprecated_cls
|
||||
|
||||
|
||||
def _clspath(cls, forced=None):
|
||||
def _clspath(cls: type, forced: Optional[str] = None) -> str:
|
||||
if forced is not None:
|
||||
return forced
|
||||
return f"{cls.__module__}.{cls.__name__}"
|
||||
|
|
@ -134,7 +137,17 @@ def _clspath(cls, forced=None):
|
|||
DEPRECATION_RULES: List[Tuple[str, str]] = []
|
||||
|
||||
|
||||
def update_classpath(path):
|
||||
@overload
|
||||
def update_classpath(path: str) -> str:
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def update_classpath(path: Any) -> Any:
|
||||
...
|
||||
|
||||
|
||||
def update_classpath(path: Any) -> Any:
|
||||
"""Update a deprecated path from an object with its new location"""
|
||||
for prefix, replacement in DEPRECATION_RULES:
|
||||
if isinstance(path, str) and path.startswith(prefix):
|
||||
|
|
@ -147,7 +160,7 @@ def update_classpath(path):
|
|||
return path
|
||||
|
||||
|
||||
def method_is_overridden(subclass, base_class, method_name):
|
||||
def method_is_overridden(subclass: type, base_class: type, method_name: str) -> bool:
|
||||
"""
|
||||
Return True if a method named ``method_name`` of a ``base_class``
|
||||
is overridden in a ``subclass``.
|
||||
|
|
|
|||
Loading…
Reference in New Issue