Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ exclude = []
"typing.Protocol".msg = "Use scikit_build_core._compat.typing.Protocol instead."
"typing.Self".msg = "Use scikit_build_core._compat.typing.Self instead."
"typing_extensions.Self".msg = "Use scikit_build_core._compat.typing.Self instead."
"typing.runtime_checkable".msg = "Use scikit_build_core._compat.typing.runtime_checkable instead."
"typing.runtime_checkable".msg = "Add and use scikit_build_core._compat.typing.runtime_checkable instead."
"typing.Final".msg = "Add scikit_build_core._compat.typing.Final instead."
"typing.NotRequired".msg = "Add scikit_build_core._compat.typing.NotRequired instead."
"typing.OrderedDict".msg = "Add scikit_build_core._compat.typing.OrderedDict instead."
Expand Down
11 changes: 8 additions & 3 deletions src/scikit_build_core/_compat/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@
import typing

if sys.version_info < (3, 8):
from typing_extensions import Literal, Protocol, runtime_checkable
from typing_extensions import (
Literal,
Protocol,
get_args,
get_origin,
)
else:
from typing import Literal, Protocol, runtime_checkable
from typing import Literal, Protocol, get_args, get_origin

if sys.version_info < (3, 11):
if typing.TYPE_CHECKING:
Expand All @@ -16,7 +21,7 @@
else:
from typing import Self

__all__ = ["Protocol", "runtime_checkable", "Literal", "Self"]
__all__ = ["Protocol", "Literal", "Self", "get_origin", "get_args"]


def __dir__() -> list[str]:
Expand Down
12 changes: 7 additions & 5 deletions src/scikit_build_core/file_api/reply.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import Any, Callable, Dict, List, Type, TypeVar, Union # noqa: TID251

from .._compat.builtins import ExceptionGroup
from .._compat.typing import get_args, get_origin
from .model.cache import Cache
from .model.cmakefiles import CMakeFiles
from .model.codemodel import CodeModel, Target
Expand Down Expand Up @@ -88,11 +89,12 @@ def _convert_any(self, item: Any, target: Type[T]) -> T:
if dataclasses.is_dataclass(target):
# We don't have DataclassInstance exposed in typing yet
return self.make_class(item, target) # type: ignore[return-value]
if hasattr(target, "__origin__"):
if target.__origin__ == list: # type: ignore[attr-defined]
return [self._convert_any(i, target.__args__[0]) for i in item] # type: ignore[return-value,attr-defined]
if target.__origin__ == Union: # type: ignore[attr-defined]
return self._convert_any(item, target.__args__[0]) # type: ignore[no-any-return,attr-defined]
origin = get_origin(target)
if origin is not None:
if origin == list:
return [self._convert_any(i, get_args(target)[0]) for i in item] # type: ignore[return-value]
if origin == Union:
return self._convert_any(item, get_args(target)[0]) # type: ignore[no-any-return]

return target(item) # type: ignore[call-arg]

Expand Down
38 changes: 11 additions & 27 deletions src/scikit_build_core/settings/sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
from typing import Any, TypeVar, Union

from .._compat.builtins import ExceptionGroup
from .._compat.typing import Protocol, runtime_checkable
from .._compat.typing import Protocol, get_args, get_origin

T = TypeVar("T")

Expand Down Expand Up @@ -72,32 +72,20 @@ def _dig_fields(__opt: Any, *names: str) -> Any:
return __opt


@runtime_checkable
class TypeLike(Protocol):
@property
def __origin__(self) -> Any:
...

@property
def __args__(self) -> list[Any]:
...


def _process_union(target: type[Any]) -> Any:
"""
Selects the non-None item in an Optional or Optional-like Union. Passes
through non-Unions.
"""

if (
not isinstance(target, TypeLike)
or not hasattr(target, "__origin__")
or target.__origin__ is not Union
):
origin = get_origin(target)

if origin is None or origin is not Union:
return target

if len(target.__args__) == 2:
items = list(target.__args__)
args = get_args(target)
if len(args) == 2:
items = list(args)
if type(None) not in items:
msg = f"None must be in union, got {items}"
raise AssertionError(msg)
Expand All @@ -115,10 +103,8 @@ def _get_target_raw_type(target: type[Any]) -> type[Any]:
"""

target = _process_union(target)
# The hasattr is required for Python 3.7, though not quite sure why
if isinstance(target, TypeLike) and hasattr(target, "__origin__"):
return target.__origin__
return target
origin = get_origin(target)
return origin or target


def _get_inner_type(__target: type[Any]) -> type[Any]:
Expand All @@ -130,11 +116,9 @@ def _get_inner_type(__target: type[Any]) -> type[Any]:
raw_target = _get_target_raw_type(__target)
target = _process_union(__target)
if raw_target == list:
assert isinstance(__target, TypeLike)
return target.__args__[0]
return get_args(target)[0] # type: ignore[no-any-return]
if raw_target == dict:
assert isinstance(__target, TypeLike)
return target.__args__[1]
return get_args(target)[1] # type: ignore[no-any-return]
msg = f"Expected a list or dict, got {target!r}"
raise AssertionError(msg)

Expand Down