Skip to content

Commit

Permalink
Bump typing_extensions; remove GenericAlias dep
Browse files Browse the repository at this point in the history
  • Loading branch information
brentyi committed Nov 18, 2021
1 parent 03257fb commit 0646766
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 27 deletions.
4 changes: 1 addition & 3 deletions dcargs/_construction.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
import enum
from typing import Any, Callable, Dict, Set, Tuple, Type, TypeVar, Union

from typing_extensions import _GenericAlias # type: ignore

from . import _resolver, _strings

DataclassType = TypeVar("DataclassType", bound=Union[Type, _GenericAlias])
DataclassType = TypeVar("DataclassType")


# Each dataclass field is assigned a role, which is either taken from an enum or a
Expand Down
9 changes: 4 additions & 5 deletions dcargs/_docstrings.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
import tokenize
from typing import Dict, List, Optional, Type

from typing_extensions import _GenericAlias # type: ignore

from . import _strings
from . import _resolver, _strings


@dataclasses.dataclass
Expand Down Expand Up @@ -76,8 +74,9 @@ def make(cls) -> "_Tokenization":
def get_field_docstring(cls: Type, field_name: str) -> Optional[str]:
"""Get docstring for a field in a class."""

if isinstance(cls, _GenericAlias):
cls = cls.__origin__
origin_cls = _resolver.unwrap_generic(cls)
if origin_cls is not None:
cls = origin_cls

assert dataclasses.is_dataclass(cls)
try:
Expand Down
4 changes: 1 addition & 3 deletions dcargs/_parse.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import argparse
from typing import Optional, Sequence, Type, TypeVar, Union

from typing_extensions import _GenericAlias # type: ignore

from . import _construction, _parsers, _strings

DataclassType = TypeVar("DataclassType", bound=Union[Type, _GenericAlias])
DataclassType = TypeVar("DataclassType")


def parse(
Expand Down
4 changes: 1 addition & 3 deletions dcargs/_parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
import dataclasses
from typing import Any, Dict, List, Optional, Set, Tuple, Type, TypeVar, Union

from typing_extensions import _GenericAlias # type: ignore

from . import _arguments, _construction, _docstrings, _resolver, _strings

T = TypeVar("T")
Expand Down Expand Up @@ -43,7 +41,7 @@ def apply(self, parser: argparse.ArgumentParser) -> None:

@staticmethod
def from_dataclass(
cls: Union[Type[T], _GenericAlias],
cls: Type[T],
parent_dataclasses: Optional[Set[Type]],
parent_type_from_typevar: Optional[Dict[TypeVar, Type]],
default_instance: Optional[T],
Expand Down
29 changes: 17 additions & 12 deletions dcargs/_resolver.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,41 @@
import copy
import dataclasses
import functools
from typing import Dict, List, Tuple, Type, TypeVar, Union
from typing import Dict, List, Optional, Tuple, Type, TypeVar, Union

from typing_extensions import _GenericAlias, get_type_hints # type: ignore
from typing_extensions import get_type_hints


def is_dataclass(cls: Union[Type, _GenericAlias]) -> bool:
def unwrap_generic(cls: Type) -> Optional[Type]:
"""Returns the origin of a generic type; or None if not a generic."""
# Note that isinstance(cls, GenericAlias) breaks in Python >= 3.9
return cls.__origin__ if hasattr(cls, "__origin__") else None


def is_dataclass(cls: Type) -> bool:
"""Same as `dataclasses.is_dataclass`, but also handles generic aliases."""
return dataclasses.is_dataclass(cls) or (
isinstance(cls, _GenericAlias) and dataclasses.is_dataclass(cls.__origin__)
)
origin_cls = unwrap_generic(cls)
return dataclasses.is_dataclass(cls if origin_cls is None else origin_cls)


def resolve_generic_dataclasses(
cls: Union[Type, _GenericAlias],
cls: Type,
) -> Tuple[Type, Dict[TypeVar, Type]]:
"""If the input is a dataclass: no-op. If it's a generic alias: returns the root
dataclass, and a mapping from typevars to concrete types."""

if isinstance(cls, _GenericAlias):
typevars = cls.__origin__.__parameters__
origin_cls = unwrap_generic(cls)
if origin_cls is not None:
typevars = origin_cls.__parameters__
typevar_values = cls.__args__
assert len(typevars) == len(typevar_values)
cls = cls.__origin__
return cls, dict(zip(typevars, typevar_values))
return origin_cls, dict(zip(typevars, typevar_values))
else:
return cls, {}


@functools.lru_cache(maxsize=16)
def resolved_fields(cls: Union[Type, _GenericAlias]) -> List[dataclasses.Field]:
def resolved_fields(cls: Type) -> List[dataclasses.Field]:
"""Similar to dataclasses.fields, but resolves forward references."""

assert dataclasses.is_dataclass(cls)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
packages=find_packages(),
package_data={"dcargs": ["py.typed"]},
python_requires=">=3.7",
install_requires=["typing_extensions"],
install_requires=["typing_extensions>=4.0.0"],
extras_require={
"testing": [
"pytest",
Expand Down

0 comments on commit 0646766

Please sign in to comment.