Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Support lists #37

Open
USSX-Hares opened this issue Jun 21, 2019 · 7 comments
Open

Feature Request: Support lists #37

USSX-Hares opened this issue Jun 21, 2019 · 7 comments

Comments

@USSX-Hares
Copy link

Could you support lists in your api?
In example, have such functions:

def is_list_type(tp) -> bool:
    pass

is_list_type(List[int]) # True
is_list_type(Tuple[int, str]) # False
@JelleZijlstra
Copy link

You can just write

def is_list_type(tp) -> bool:
    return typing_inspect.get_origin(tp) is list

@Stewori
Copy link

Stewori commented Jun 21, 2019

@JelleZijlstra is that backwards compatible, even to Python 3.6?
I suspect one might better write

typing_inspect.get_origin(tp) in {list, List}

@USSX-Hares
Copy link
Author

Works in both python3.6 and python3.7

def is_list_type(tp) -> bool:
    """
    Test if the type is a generic list type, including subclasses excluding
    non-generic classes.
    Examples::
    
    is_list_type(int) == False
    is_list_type(list) == False
    is_list_type(List) == True
    is_list_type(List[str, int]) == True
    class MyClass(List[str]):
        ...
    is_list_type(MyClass) == True
    """
    
    return is_generic_type(tp) and issubclass(get_origin(tp) or tp, List)

And from tests:

        params: List[Tuple[str, type, bool]] = \
        [
            ("int",                         int,                         False),
            ("list",                        list,                        False),
            ("List",                        List,                        True),
            ("List[int]",                   List[int],                   True),
            ("ListChild",                   ListChild,                   True),
            ("List[ListChild]",             List[ListChild],             True),
            ("List[CustomJsonDataclass]",   List[CustomJsonDataclass],   True),
            ("CustomJsonDataclass",         CustomJsonDataclass,         False),
            ("GenericListChild",            GenericListChild,            True),
            ("GenericListChild[int, bool]", GenericListChild[int, bool], True),
        ]
        for name, tp, expected in params:
            with self.subTest(name, expected=expected):
                self.assertEqual(expected, is_list_type(tp))

@opk12
Copy link

opk12 commented Mar 29, 2020

See also typing.get_origin, typing.get_args added in Python 3.8.

@DanCardin
Copy link

Fwiw, I arrived here looking for something like is_sequence_type, to return True for all of list, tuple, set, etc

The above solutions did not work for me given that I dont know the incoming annotation, which are not always issubclass-able. It's also perhaps not obvious to me why one would want to exclude list in the most recent is_generic_type(tp) and issubclass(get_origin(tp) or tp, List) solution.

is_generic_type(tp) and issubclass(get_origin(tp) or tp, List) returns False for list, and issubclass raises TypeError for various typing types like Literal["s"].

I ended up with (although i may be misinformed and this fails in ways I dont yet understand):

def is_subclass(typ, superclass):
    if not isinstance(typ, type):
        return False

    return issubclass(typ, superclass)

def is_sequence_type(typ):
    return is_subclass(get_origin(typ) or typ, SUPPORTED_SEQUENCE_TYPES)

SUPPORTED_SEQUENCE_TYPES = (typing.List, typing.Tuple, typing.Set)

In my humble, uneducated opinion it'd be ideal if this library were able to include runtime equivalents for these sorts of things that have corresponding values-apis in stdlib, even if (as the comments towards the top imply) it's "easy" to compose them from other apis already exposed from this library.

@USSX-Hares
Copy link
Author

What is sequence in your definition? Is it any iterable, or collection of finite size? One thing you can do is to check if the class matches the protocol via magic Merida methods — __iter__ for iterables and __len__ (iirc) for collections

@DanCardin
Copy link

For my purposes, i'm talking about equivalency to Sequence, although now that i'm looking at it, i was is_sequence_type(tp) and not is_mapping_type(tp). I probably should be using the literal magic method interface rather than explicitly calling out the types as i am.

But I wouldn't be surprised if there were some weird false positives in the context of the type system, given that any generic type is going implement __getitem__(?).

mostly posted to suggest that i think there's value in a library like this one implementing these "easily" derivable runtime checks for common use, which the earlier comments seemed to be advocating against.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants