-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(internal): minor utils restructuring (#992)
- Loading branch information
1 parent
3d6ca3e
commit 052e611
Showing
8 changed files
with
183 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from typing import Any | ||
from typing_extensions import Iterator, AsyncIterator | ||
|
||
|
||
def consume_sync_iterator(iterator: Iterator[Any]) -> None: | ||
for _ in iterator: | ||
... | ||
|
||
|
||
async def consume_async_iterator(iterator: AsyncIterator[Any]) -> None: | ||
async for _ in iterator: | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
from __future__ import annotations | ||
|
||
from typing import Any, cast | ||
from typing_extensions import Required, Annotated, get_args, get_origin | ||
|
||
from .._types import InheritsGeneric | ||
from .._compat import is_union as _is_union | ||
|
||
|
||
def is_annotated_type(typ: type) -> bool: | ||
return get_origin(typ) == Annotated | ||
|
||
|
||
def is_list_type(typ: type) -> bool: | ||
return (get_origin(typ) or typ) == list | ||
|
||
|
||
def is_union_type(typ: type) -> bool: | ||
return _is_union(get_origin(typ)) | ||
|
||
|
||
def is_required_type(typ: type) -> bool: | ||
return get_origin(typ) == Required | ||
|
||
|
||
# Extracts T from Annotated[T, ...] or from Required[Annotated[T, ...]] | ||
def strip_annotated_type(typ: type) -> type: | ||
if is_required_type(typ) or is_annotated_type(typ): | ||
return strip_annotated_type(cast(type, get_args(typ)[0])) | ||
|
||
return typ | ||
|
||
|
||
def extract_type_arg(typ: type, index: int) -> type: | ||
args = get_args(typ) | ||
try: | ||
return cast(type, args[index]) | ||
except IndexError as err: | ||
raise RuntimeError(f"Expected type {typ} to have a type argument at index {index} but it did not") from err | ||
|
||
|
||
def extract_type_var_from_base(typ: type, *, generic_bases: tuple[type, ...], index: int) -> type: | ||
"""Given a type like `Foo[T]`, returns the generic type variable `T`. | ||
This also handles the case where a concrete subclass is given, e.g. | ||
```py | ||
class MyResponse(Foo[bytes]): | ||
... | ||
extract_type_var(MyResponse, bases=(Foo,), index=0) -> bytes | ||
``` | ||
""" | ||
cls = cast(object, get_origin(typ) or typ) | ||
if cls in generic_bases: | ||
# we're given the class directly | ||
return extract_type_arg(typ, index) | ||
|
||
# if a subclass is given | ||
# --- | ||
# this is needed as __orig_bases__ is not present in the typeshed stubs | ||
# because it is intended to be for internal use only, however there does | ||
# not seem to be a way to resolve generic TypeVars for inherited subclasses | ||
# without using it. | ||
if isinstance(cls, InheritsGeneric): | ||
target_base_class: Any | None = None | ||
for base in cls.__orig_bases__: | ||
if base.__origin__ in generic_bases: | ||
target_base_class = base | ||
break | ||
|
||
if target_base_class is None: | ||
raise RuntimeError( | ||
"Could not find the generic base class;\n" | ||
"This should never happen;\n" | ||
f"Does {cls} inherit from one of {generic_bases} ?" | ||
) | ||
|
||
return extract_type_arg(target_base_class, index) | ||
|
||
raise RuntimeError(f"Could not resolve inner type variable at index {index} for {typ}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters