Metadata-Version: 2.4
Name: get-args-and-origin
Version: 0.1.0a0
Summary: Compatibility helpers for typing.get_origin() and typing.get_args() on Python < 3.8.
Author-email: Jifeng Wu <jifengwu2k@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/jifengwu2k/get-args-and-origin
Project-URL: Bug Tracker, https://github.com/jifengwu2k/get-args-and-origin/issues
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Requires-Python: >=2
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: typing; python_version < "3.5"
Requires-Dist: typing-extensions
Dynamic: license-file

# get_args_and_origin

`get_args_and_origin` provides `get_origin()` and `get_args()` on Python `< 3.8`.

- On Python `>= 3.8`, it simply re-exports the stdlib implementations.
- On Python `< 3.8`, it backports equivalent behavior for the older `typing`
  constructs, plus `typing_extensions.Annotated`, `typing_extensions.Final`,
  and `typing_extensions.Literal`.

## Installation

```bash
pip install get-args-and-origin
```

## Usage

```python
from get_args_and_origin import get_origin, get_args
```

## Supported on Python < 3.8

Core `typing` constructs:

- `List[T]`
- `Dict[K, V]`
- `Set[T]`
- `FrozenSet[T]`
- `Tuple[...]`
- `Callable[..., T]`
- `Callable[[A, B], R]`
- `Union[...]`
- `Optional[T]`
- `Type[T]`
- nested generic aliases
- unsubscripted `Generic`

`typing_extensions` constructs:

- `typing_extensions.Final[T]`
- `typing_extensions.Literal[...]`
- `typing_extensions.Annotated[T, ...]`

## Notes

- On Python `< 3.8`, `Final`, `Literal`, and `Annotated` should be used from
  `typing_extensions`, and `get_origin()` normalizes them to those
  `typing_extensions` objects.
- On Python `>= 3.8`, behavior is exactly whatever `typing.get_origin()` and
  `typing.get_args()` do in the standard library.
- Union argument ordering can vary slightly across old `typing` backports.

## Quick assert-style smoke tests

These assert-style checks are meant to double as a compact, high-coverage
compatibility suite for Python 2.7, 3.4, 3.5, 3.6, and 3.7.

```python
from typing import (
    Callable,
    Dict,
    FrozenSet,
    Generic,
    List,
    Optional,
    Set,
    Tuple,
    Type,
    TypeVar,
    Union,
)
import typing_extensions
from get_args_and_origin import get_origin, get_args

T = TypeVar('T')
S = TypeVar('S')

assert get_origin(int) is None
assert get_origin(str) is None
assert get_args(int) == ()
assert get_args(str) == ()

assert get_origin(T) is None
assert get_args(T) == ()

assert get_origin(List[int]) is list
assert get_args(List[int]) == (int,)

assert get_origin(Dict[int, str]) is dict
assert get_args(Dict[int, str]) == (int, str)

assert get_origin(Set[int]) is set
assert get_args(Set[int]) == (int,)

assert get_origin(FrozenSet[int]) is frozenset
assert get_args(FrozenSet[int]) == (int,)

assert get_origin(Tuple[int, str]) is tuple
assert get_args(Tuple[int, str]) == (int, str)

assert get_origin(Tuple[int, ...]) is tuple
assert get_args(Tuple[int, ...]) == (int, Ellipsis)

assert get_origin(Union[int, str]) is Union
assert get_args(Union[int, str]) == (int, str)

assert get_origin(Optional[int]) is Union
assert get_args(Optional[int]) == (int, type(None))

assert get_origin(Callable[[int, str], bool]).__name__ == 'Callable'
assert get_args(Callable[[int, str], bool]) == ([int, str], bool)

assert get_origin(Callable[..., bool]).__name__ == 'Callable'
assert get_args(Callable[..., bool]) == (Ellipsis, bool)

assert get_origin(Type[int]) is type
assert get_args(Type[int]) == (int,)

assert get_origin(Generic) is Generic
assert get_args(Generic) == ()

assert get_origin(List) is list
assert get_origin(Dict) is dict
assert get_origin(Set) is set
assert get_origin(FrozenSet) is frozenset
assert get_origin(Tuple) is tuple
assert get_args(List) == ()
assert get_args(Dict) == ()
assert get_args(Set) == ()
assert get_args(FrozenSet) == ()

assert get_origin(Dict[str, List[Tuple[int, str]]]) is dict
assert get_args(Dict[str, List[Tuple[int, str]]]) == (str, List[Tuple[int, str]])

assert get_origin(List[Union[int, str]]) is list
assert get_args(List[Union[int, str]]) == (Union[int, str],)

assert get_origin(Dict[str, Optional[int]]) is dict
assert get_args(Dict[str, Optional[int]]) == (str, Optional[int])

assert get_origin(Tuple[List[int], Dict[str, bool]]) is tuple
assert get_args(Tuple[List[int], Dict[str, bool]]) == (List[int], Dict[str, bool])

assert get_origin(Tuple[List[T], Dict[str, S]]) is tuple
assert get_args(Tuple[List[T], Dict[str, S]]) == (List[T], Dict[str, S])

assert get_origin(Tuple[Union[int, str], Optional[bool]]) is tuple
assert get_args(Tuple[Union[int, str], Optional[bool]]) == (Union[int, str], Optional[bool])

Literal = typing_extensions.Literal
Final = typing_extensions.Final
Annotated = typing_extensions.Annotated

assert get_origin(Literal[1, 'x', True]) is Literal
assert get_args(Literal[1, 'x', True]) == (1, 'x', True)
assert get_origin(Literal[1]) is Literal
assert get_origin(Literal) is None
assert get_args(Literal) == ()

assert get_origin(Final[int]) is Final
assert get_args(Final[int]) == (int,)
assert get_origin(Final) is None
assert get_args(Final) == ()

assert get_origin(Annotated[int, 'm1', 'm2']) is Annotated
assert get_args(Annotated[int, 'm1', 'm2']) == (int, 'm1', 'm2')
assert get_origin(Annotated[int, 'm']) is Annotated
assert get_origin(Annotated[List[int], 'tag']) is Annotated
assert get_args(Annotated[List[int], 'tag']) == (List[int], 'tag')
assert get_origin(Annotated[Union[int, str], 'u']) is Annotated
assert get_args(Annotated[Union[int, str], 'u']) == (Union[int, str], 'u')

nested = Dict[
    str,
    Tuple[
        List[Optional[int]],
        Annotated[Literal[1, 2], 'meta'],
    ],
]
assert get_origin(nested) is dict
assert get_args(nested) == (
    str,
    Tuple[
        List[Optional[int]],
        Annotated[Literal[1, 2], 'meta'],
    ],
)
```

## Contributing

Contributions are welcome! Please submit pull requests or open issues on the GitHub repository.

## License

This project is licensed under the [MIT License](LICENSE).
