stewori / pytypes Goto Github PK
View Code? Open in Web Editor NEWTyping-toolbox for Python 3 _and_ 2.7 w.r.t. PEP 484.
License: Apache License 2.0
Typing-toolbox for Python 3 _and_ 2.7 w.r.t. PEP 484.
License: Apache License 2.0
This library looks quite useful; it would be awesome to have it pip-installable!
The following trivial script fails with TypeError: 'TypeChecker' object does not support indexing
:
from pytypes import TypeChecker
with TypeChecker():
pass
Python 3.5.5.
Surely some kind of basic testing would've been nice? This works in typeguard btw.
import typing
from pytypes import type_util
T = typing.TypeVar('T', covariant=True)
class L(typing.List[T]):
pass
C = typing.TypeVar('T', bound=L)
type_util._issubclass(L[float], C) # False
type_util._issubclass(L[float], C, bound_typevars={}) # True
Why does bound_typevar
change result from False
to True
?
Also, why code never checks if superclass
is in bound_typevars
? I think it just relays on catch-all except
. I think such approach might hide some bugs?
The following code:
import re
from pytypes import TypeChecker
with TypeChecker():
re.compile('a')
fails as follows:
$ python3 Test.py
/usr/local/lib/python3.6/dist-packages/pytypes-1.0b5.post20-py3.6.egg/pytypes/type_util.py:2532: UserWarning: the system profiling hook has changed unexpectedly
warn('the system profiling hook has changed unexpectedly')
Traceback (most recent call last):
File "/usr/local/lib/python3.6/dist-packages/pytypes-1.0b5.post20-py3.6.egg/pytypes/typecomment_parser.py", line 52, in _get_typestrings
srclines = inspect.getsourcelines(obj)[0]
File "/usr/lib/python3.6/inspect.py", line 955, in getsourcelines
lines, lnum = findsource(object)
File "/usr/lib/python3.6/inspect.py", line 768, in findsource
file = getsourcefile(object)
File "/usr/lib/python3.6/inspect.py", line 684, in getsourcefile
filename = getfile(object)
File "/usr/lib/python3.6/inspect.py", line 666, in getfile
'function, traceback, frame, or code object'.format(object))
TypeError: <slot wrapper '__and__' of 'int' objects> is not a module, class, method, function, traceback, frame, or code object
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "Test.py", line 5, in <module>
re.compile('a')
File "/usr/lib/python3.6/re.py", line 233, in compile
return _compile(pattern, flags)
File "/usr/lib/python3.6/re.py", line 302, in _compile
if not (flags & DEBUG):
File "/usr/lib/python3.6/enum.py", line 803, in __and__
def __and__(self, other):
File "/usr/local/lib/python3.6/dist-packages/pytypes-1.0b5.post20-py3.6.egg/pytypes/type_util.py", line 2563, in __call__
_check_caller_type(False, caller_level=self._caller_level_shift+1)
File "/usr/local/lib/python3.6/dist-packages/pytypes-1.0b5.post20-py3.6.egg/pytypes/type_util.py", line 2416, in _check_caller_type
cllable, clss = _find_typed_base_method(cllable, clss)
File "/usr/local/lib/python3.6/dist-packages/pytypes-1.0b5.post20-py3.6.egg/pytypes/type_util.py", line 2131, in _find_typed_base_method
if has_type_hints(util._actualfunc(fmeth)):
File "/usr/local/lib/python3.6/dist-packages/pytypes-1.0b5.post20-py3.6.egg/pytypes/type_util.py", line 657, in has_type_hints
return _has_type_hints(func0)
File "/usr/local/lib/python3.6/dist-packages/pytypes-1.0b5.post20-py3.6.egg/pytypes/type_util.py", line 686, in _has_type_hints
tpStr = _get_typestrings(func, False)
File "/usr/local/lib/python3.6/dist-packages/pytypes-1.0b5.post20-py3.6.egg/pytypes/typecomment_parser.py", line 54, in _get_typestrings
srclines = inspect.getsourcelines(getattr(obj.__class__, obj.__name__))[0]
AttributeError: type object 'wrapper_descriptor' has no attribute '__and__'
Is this intended behavior?
#Python 3.6.2 | packaged by conda-forge | (default, Jul 23 2017, 23:01:38)
#Type 'copyright', 'credits' or 'license' for more information
#IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import pytypes
In [2]: issubclass(int, float)
Out[2]: False
In [3]: pytypes.is_subtype(int, float)
Out[3]: True
Just noticed that with CPyhton 3.6.3 tests related to check_argument_types started to fail.
I lastly tested with CPython 3.6.1, so not sure about CPython 3.6.2. Will test that one as soon as I find time...
The following code:
from typing import Iterator
from pytypes import TypeChecker
def f() -> Iterator[str]:
yield 'abc'
with TypeChecker():
x = tuple(c for c in f())
print("OK")
fails as follows:
$ python3 Test.py
Traceback (most recent call last):
File "Test.py", line 9, in <module>
x = tuple(c for c in f())
File "Test.py", line 9, in <genexpr>
x = tuple(c for c in f())
File "Test.py", line 6, in f
yield 'abc'
pytypes.exceptions.ReturnTypeError:
__main__.f
returned incompatible type:
Expected: Iterator[str]
Received: str
Also a simple call to f()
, not wrapped in generator expression and tuple
, fails in a slightly different manner:
$ python3 Test.py
Exception ignored in: <generator object f at 0x7fe74e4b7db0>
Traceback (most recent call last):
File "Test.py", line 5, in f
def f() -> Iterator[str]:
File "/usr/local/lib/python3.6/dist-packages/pytypes-1.0b5.post23-py3.6.egg/pytypes/type_util.py", line 2580, in __call__
_check_caller_type(True, None, arg, caller_level=self._caller_level_shift+1)
File "/usr/local/lib/python3.6/dist-packages/pytypes-1.0b5.post23-py3.6.egg/pytypes/type_util.py", line 2431, in _check_caller_type
prop_getter, force_exception=True)
File "/usr/local/lib/python3.6/dist-packages/pytypes-1.0b5.post23-py3.6.egg/pytypes/typechecker.py", line 718, in _checkfuncresult
_raise_typecheck_error(msg, True, check_val, tpch, resSig, func)
File "/usr/local/lib/python3.6/dist-packages/pytypes-1.0b5.post23-py3.6.egg/pytypes/type_util.py", line 2336, in _raise_typecheck_error
raise pytypes.ReturnTypeError(msg)
pytypes.exceptions.ReturnTypeError:
__main__.f
returned incompatible type:
Expected: Iterator[str]
Received: NoneType
OK
Similar stacks occur if Iterator[str]
is replaced with Generator[str, None, None]
.
Having a type comment like Tuple[(int, ...)]
cannot be parsed on Python 2.7:
.../pytypes/typecomment_parser.py", line 225, in _funcsigtypesfromstring
argTp = eval(argString, globals)
File "<string>", line 1
(Tuple[(int, ...)])
Using pytypes-1.0b5
I get:
$ python
Python 3.6.5 (default, Mar 31 2018, 05:34:57)
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pytypes
>>> import typing
>>> T = typing.TypeVar('T')
>>> pytypes.is_subtype(T, typing.Any)
True
>>> pytypes.is_subtype(typing.Any, T)
False
Does pytypes support gradual typing? Is there a way to do verify an is-consistent-with relationship with its API?
Background: I'm trying to replace this method with a call to pytypes.is_subtype
(using Python typing types):
https://github.com/apache/beam/blob/a843a08439eddcf10f140767761f8e8c1f88d715/sdks/python/apache_beam/typehints/typehints.py#L1112-L1120
Reproduction:
import typing
import pytypes
from pytypes import type_util
type_util._issubclass(typing.List[typing.Dict[str, str]], typing.List[dict])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".../pytypes/type_util.py", line 1769, in _issubclass
bound_typevars_readonly, follow_fwd_refs, _recursion_check)
File ".../pytypes/type_util.py", line 1799, in _issubclass_2
bound_typevars_readonly, follow_fwd_refs, _recursion_check)
File ".../pytypes/type_util.py", line 1345, in _issubclass_Generic
_recursion_check):
File ".../pytypes/type_util.py", line 1769, in _issubclass
bound_typevars_readonly, follow_fwd_refs, _recursion_check)
File ".../pytypes/type_util.py", line 1796, in _issubclass_2
_recursion_check)
File ".../pytypes/type_util.py", line 1140, in _issubclass_Mapping_covariant
return issubclass(subclass, superclass)
File "/usr/lib/python3.6/typing.py", line 1148, in __subclasscheck__
raise TypeError("Parameterized generics cannot be used with class "
TypeError: Parameterized generics cannot be used with class or instance checks
Using pytypes-1.0b5.
It seems like enable_clean_traceback
is automatically called in __init__
?
Running Usage example with decorator in readme gave following error for me.
Traceback (most recent call last):
File "/tmp/tmp.py", line 31, in <module>
pytypes.dump_cache()
NameError: name 'pytypes' is not defined
Error in atexit._run_exitfuncs:
Traceback (most recent call last):
File "/Users/qria/.venvs/jupyter2/lib/python3.6/site-packages/pytypes/typelogger.py", line 316, in _dump_module
assumed_glbls, implicit_globals, assumed_typevars)
File "/Users/qria/.venvs/jupyter2/lib/python3.6/site-packages/pytypes/typelogger.py", line 755, in dump
assumed_globals, implicit_globals, assumed_typevars)
File "/Users/qria/.venvs/jupyter2/lib/python3.6/site-packages/pytypes/typelogger.py", line 680, in dump
assumed_globals, implicit_globals))
File "/Users/qria/.venvs/jupyter2/lib/python3.6/site-packages/pytypes/typelogger.py", line 653, in _stub_src_annotations
assumed_globals, implicit_globals), ' ...']
File "/Users/qria/.venvs/jupyter2/lib/python3.6/site-packages/pytypes/typelogger.py", line 625, in _declaration
if annotated else self._signature(), ':'))
File "/Users/qria/.venvs/jupyter2/lib/python3.6/site-packages/pytypes/typelogger.py", line 597, in _annotated_signature
tp_lst = _prepare_arg_types_list(combine_argtype(self.arg_type_observations),
File "/Users/qria/.venvs/jupyter2/lib/python3.6/site-packages/pytypes/typelogger.py", line 149, in combine_argtype
assert isinstance(is_Tuple(observations[0]))
TypeError: isinstance expected 2 arguments, got 1
I don't know much about this codebase but maybe you've intended assert is_Tuple(observations[0])
?
versions:
pytypes==1.0b4
So this means package cannot be installed on systems which do not have current local set to utf-8. In Python 3, you get an error like:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 8634: ordinal not in range(128)
One option would be to do open(readme_path, encoding='utf8').read()
, but this would not work on Python 2, where you will have to use io.open
.
Other is that you remove all unicode characters from the README.
I would like to provide an example showing how pytypes can be used with autoclass.
However the following code fails with a strange error:
from autoclass import autoclass, Boolean
from pytypes import typechecked
from numbers import Real, Integral
from typing import Optional
@typechecked
@autoclass
class HouseConfiguration(object):
def __init__(self,
name: str,
surface: Real,
nb_floors: Optional[Integral] = 1,
with_windows: Boolean = False):
pass
# -- overriden setter for surface for custom validation
@setter_override
def surface(self, surface):
assert surface > 0
self._surface = surface
t = HouseConfiguration('test', 12, 2) # error
The error received is :
Expected: Tuple[str, Real, Union[Integral, NoneType], Boolean]
Received: Tuple[str, int, int, int]
While this works:
t = HouseConfiguration('test', 12, nb_floors=2)
So it seems that this does not have anything to do with autoclass: somehow positional arguments / default values in the constructor signature are not handled properly.
Why the following returns false?
import typing
from pytypes import type_util
type_util._issubclass(typing.List[float], typing.List)
Isn't this the same as type_util._issubclass(typing.List[float], typing.List[typing.Any])
? And then float
is an instance of typing.Any
? But this is false as well:
type_util._issubclass(typing.List[float], typing.List[typing.Any])
from pytypes import typechecked
from inspect import signature
class Foo:
def __init__(self, foo: str = 'hello'):
self.foo = foo
s = signature(Foo.__init__)
print(s.parameters)
# > OrderedDict([('self', <Parameter "self">), ('foo', <Parameter "foo:str='hello'">)])
# parameter names, type hints and default values are preserved
Whereas
@typechecked
class Foo:
def __init__(self, foo: str):
self.foo = foo
s = signature(Foo.__init__)
print(s.parameters)
# > OrderedDict([('args', <Parameter "*args">), ('kw', <Parameter "**kw">)])
# everything has been removed !
This is annoying as it does not allow other libraries to automatically discover what is required to build an object. For example with parsyfiles.
The solution is to use a signature-preserving decorator library in pytypes
, I personally use decorator but you can also use wrapt
I think.
from pytypes import typechecked
@typechecked
class Class1():
def __init__(self, arg1: str) -> None:
pass
class Class2(Class1):
def __init__(self, arg1: str, arg2: str) -> None:
Class1.__init__(self, arg1)
Class2("arg1", "arg2")
Calling Class1.__init__(self, arg1)
causes the following exception:
pytypes.exceptions.InputTypeError:
__main__.Class2.__init__
called with incompatible types:
Expected: Tuple[str, str]
Received: Tuple[str]
There is a lot of code in pytypes.type_utils
. It would be great to see some tests to help understand it better, along with some docstrings (and type annotations!) on important functions. I was really surprised to see that there are no tests for pytypes.is_subtype
.
The following trivial code:
from configparser import ConfigParser
from pytypes import TypeChecker
with TypeChecker():
ConfigParser()
fails as follows:
$ python3 Test.py
/usr/local/lib/python3.6/dist-packages/pytypes/type_util.py:2399: UserWarning: the system profiling hook has changed unexpectedly
warn('the system profiling hook has changed unexpectedly')
Traceback (most recent call last):
File "Test.py", line 5, in <module>
ConfigParser()
File "/usr/lib/python3.6/configparser.py", line 612, in __init__
self._proxies[default_section] = SectionProxy(self, default_section)
File "/usr/lib/python3.6/configparser.py", line 1223, in __init__
for conv in parser.converters:
File "/usr/lib/python3.6/configparser.py", line 1181, in converters
return self._converters
File "/usr/local/lib/python3.6/dist-packages/pytypes/type_util.py", line 2446, in __call__
_check_caller_type(True, None, arg, caller_level=self._caller_level_shift+1)
File "/usr/local/lib/python3.6/dist-packages/pytypes/type_util.py", line 2247, in _check_caller_type
orig_clss = call_args[0].__orig_class__
File "/usr/lib/python3.6/configparser.py", line 1306, in __getitem__
return self._data[key]
KeyError: 0
Example:
import typing
from pytypes import type_util
Container = typing.Union[
typing.List['Data'],
]
Data = typing.Union[
Container,
str, bytes, bool, float, int, dict,
]
type_util._issubclass(typing.List[float], Container)
Traceback (most recent call last):
File "<redacted>/lib/python3.6/site-packages/pytypes/type_util.py", line 1387, in _issubclass_2
return issubclass(subclass, superclass)
TypeError: Forward references cannot be used with issubclass().
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test.py", line 14, in <module>
type_util._issubclass(typing.List[float], Container)
TypeError: Invalid type declaration: float, _ForwardRef('Data')
The following code:
from typing import cast, List
from pytypes import TypeChecker
def f() -> List[float]:
return cast(List[float], [2])
with TypeChecker():
f()
print("OK")
fails as follows:
$ python3 Test.py
Traceback (most recent call last):
File "Test.py", line 9, in <module>
f()
File "Test.py", line 6, in f
return cast(List[float], [2])
pytypes.exceptions.ReturnTypeError:
__main__.f
returned incompatible type:
Expected: List[float]
Received: List[int]
Union
types are equivalent (but not identical) when they differ in the order of arguments. Currently, type_str
prints out Union
type with arguments in the same order as it is stored in the type. But I think it might be better (or at least optional with argument) to output it in a canonical and reproducible way (probably just sort it). This would allow one to output descriptions of strings without being surprised by random replacements of types with equivalent types. See here for more information: python/typing#559
So, my suggestion would be to add to type_str
an argument canonical
which would always output description with everything in the same order, no matter if you are outputting for equivalent but not identical types.
The following code causes deep_type to throw a ValueError:
import pytypes
import numpy as np
pytypes.deep_type([np.int64(1), np.int64(1)])
>>> from pytypes import type_util
>>> import typing
>>> type_util._isinstance((), typing.List)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: issubclass() arg 2 must be a class or tuple of classes
>>> type_util._isinstance((), typing.List[typing.Any])
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import typing
>>> import pytypes
>>> pytypes.is_of_type([], typing.List[int])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "D:\.virtualenvs\pytypes\lib\site-packages\pytypes\type_util.py", line 1904, in _isinstance
bound_typevars_readonly, follow_fwd_refs, _recursion_check)
File "D:\.virtualenvs\pytypes\lib\site-packages\pytypes\type_util.py", line 1769, in _issubclass
bound_typevars_readonly, follow_fwd_refs, _recursion_check)
File "D:\.virtualenvs\pytypes\lib\site-packages\pytypes\type_util.py", line 1799, in _issubclass_2
bound_typevars_readonly, follow_fwd_refs, _recursion_check)
File "D:\.virtualenvs\pytypes\lib\site-packages\pytypes\type_util.py", line 1310, in _issubclass_Generic
bound_typevars_readonly, follow_fwd_refs, _recursion_check):
File "D:\.virtualenvs\pytypes\lib\site-packages\pytypes\type_util.py", line 1769, in _issubclass
bound_typevars_readonly, follow_fwd_refs, _recursion_check)
File "D:\.virtualenvs\pytypes\lib\site-packages\pytypes\type_util.py", line 1799, in _issubclass_2
bound_typevars_readonly, follow_fwd_refs, _recursion_check)
File "D:\.virtualenvs\pytypes\lib\site-packages\pytypes\type_util.py", line 1293, in _issubclass_Generic
if subclass.__origin__ is None:
AttributeError: type object 'Empty' has no attribute '__origin__'
This seems to be related to #32. I tested the above in python 3.6.5 and it worked fine, so it's only an issue in python 3.7.
>>> import typing
>>> import collections
>>> import pytypes
>>> pytypes.is_of_type(collections.defaultdict(list), typing.Dict[str, typing.List])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Parameterized generics cannot be used with class or instance checks
I would hope to get True
instead.
The following code:
from typing import List, Mapping
from pytypes import TypeChecker
def f() -> List[Mapping[int, str]]:
return [{}]
with TypeChecker():
f()
print("OK")
fails as follows:
$ python3 Test.py
Traceback (most recent call last):
File "Test.py", line 9, in <module>
f()
File "Test.py", line 6, in f
return [{}]
pytypes.exceptions.ReturnTypeError:
__main__.f
returned incompatible type:
Expected: List[Mapping[int, str]]
Received: List[Empty[Dict]]
from pytypes import type_util
value = (i for i in range(10))
type_util._isinstance(value, int)
I would just assume it would be False
, but it is:
TypeError: <code object <genexpr> at 0x7f5bc05418a0, file "test.py", line 2> is not a module, class, method, or function.
This one is even trickier:
from pytypes import type_util
class Foo:
def bar(self):
value = (i for i in range(10))
type_util._isinstance(value, int)
Foo().bar()
If I understand correctly, the following class Bar
has all parameters set to Any
:
from typing import *
A = TypeVar('A')
class Foo(Generic[A]):
pass
class Bar(Foo):
pass
But pytypes.type_util.get_Generic_parameters(Bar, Foo)
fails with:
TypeError: Bar has no proper parameters defined by Foo.
But it should return:
(typing.Any,)
From documentation:
Using a generic class without specifying type parameters assumes
Any
for each position. In the following example,MyIterable
is not generic but implicitly inherits fromIterable[Any]
:
from typing import Iterable
class MyIterable(Iterable): # Same as Iterable[Any]
Per your comment ilevkivskyi/typing_inspect#35 (comment)
Using the latest master of pytypes
(1449eff)
import typing as tp
import pytypes
T = tp.TypeVar("T")
T1 = tp.TypeVar("T1")
T2 = tp.TypeVar("T2")
class D0(tp.Dict[T1, T2]):
def show_types(self) -> None:
gt = pytypes.get_Generic_type(self)
print(gt, pytypes.get_Generic_parameters(gt, D0))
class D1(D0[int, T]):
pass
class D2(D1[str]):
pass
D0[int, str]().show_types()
D1[str]().show_types()
D2().show_types()
works as expected on Python 3.6, producing:
__main__.D0[int, str] (<class 'int'>, <class 'str'>)
__main__.D1[str] (<class 'int'>, <class 'str'>)
__main__.D2 (<class 'int'>, <class 'str'>)
but crashes on Python 3.7:
__main__.D0[int, str] (<class 'int'>, <class 'str'>)
Traceback (most recent call last):
File "pytypes10.py", line 26, in <module>
D1[str]().show_types()
File "pytypes10.py", line 14, in show_types
print(gt, pytypes.get_Generic_parameters(gt, D0))
File "venv-pytypes/lib/python3.7/site-packages/pytypes/type_util.py", line 327, in get_Generic_parameters
res = _select_Generic_superclass_parameters(tp, generic_supertype)
File "venv-pytypes/lib/python3.7/site-packages/pytypes/type_util.py", line 1319, in _select_Generic_superclass_parameters
prms = _find_Generic_super_origin(subclass, superclass_origin)
File "venv-pytypes/lib/python3.7/site-packages/pytypes/type_util.py", line 1256, in _find_Generic_super_origin
if not bs.__origin__ is None:
AttributeError: type object 'D0' has no attribute '__origin__'
Maybe deserving a separate bug:
Changing
-class D1(D0[int, T]):
+class D1(D0[int, T1]):
pass
causes the following erroneous output (running on Python 3.6):
__main__.D0[int, str] (<class 'int'>, <class 'str'>)
__main__.D1[str] (<class 'str'>, <class 'str'>)
__main__.D2 (<class 'str'>, <class 'str'>)
TypeVars should definitely be independent between classes (verified using reveal_type
and mypy
).
The following code:
from collections import OrderedDict
from typing import Mapping
from pytypes import TypeChecker
def f() -> Mapping[int, str]:
return OrderedDict()
with TypeChecker():
f()
fails as follows:
$ python3 Test.py
Traceback (most recent call last):
File "Test.py", line 11, in <module>
f()
File "Test.py", line 8, in f
return OrderedDict()
pytypes.exceptions.ReturnTypeError:
__main__.f
returned incompatible type:
Expected: Mapping[int, str]
Received: OrderedDict
Compatibility with the new upcoming typing module is not yet established. I'm working on this as far as time allows, help welcome.
928fd62 was the first milestone of this process, enabling the test suite to complete without a crash (not speaking of failing tests). Now, still most tests are failing. Work to do...
The following code:
from pytypes import TypeChecker
class A:
def __init__(self) -> None:
pass
with TypeChecker():
A()
fails as follows:
$ python3 Test.py
Traceback (most recent call last):
File "Test.py", line 8, in <module>
A()
File "Test.py", line 5, in __init__
pass
pytypes.exceptions.ReturnTypeError:
__main__.A.__init__
returned incompatible type:
Expected: NoneType
Received: Tuple[A]
If None
annotation to A.__init_()
is removed, the fail disappears.
In one part of my code, where I am deciding how to convert a value to JSON, I do:
any(is_subclass(structural_type, typ) for typ in (str, int, float, bool))
What I realized is that I would be OK with all possible Union
combinations of these as well. So if structural_type
is Union[str, int]
that should also pass this check. Do you have a suggestion how to do so, or a helper function which would already do this? So I wonder about complicated case like Union[str, Union[int, bool]]
or something like that.
The following code:
from typing import Callable, List
from pytypes import TypeChecker
def n() -> None:
pass
def f() -> List[Callable[[], None]]:
return [n]
with TypeChecker():
f()
print("OK")
fails as follows:
$ python3 Test.py
Traceback (most recent call last):
File "Test.py", line 12, in <module>
f()
File "Test.py", line 9, in f
return [n]
pytypes.exceptions.ReturnTypeError:
__main__.f
returned incompatible type:
Expected: List[Callable[[], NoneType]]
Received: List[function]
Noting this down as a reminder to follow up on agronholm/typeguard#56 (comment)...
>>> import typing
>>> from pytypes import type_util
>>> type_util._isinstance(set(), typing.Sized)
False
>>> isinstance(set(), typing.Sized)
True
The first False
is surprising. I would expect it to be True
like isinstance
is.
>>> import typing
>>> from pytypes import type_util
>>> type_util._isinstance(frozenset({1, 2, 'a', None, 'b'}), typing.AbstractSet[typing.Union[str, int, None]])
False
>>> type_util._isinstance({1, 2, 'a', None, 'b'}, typing.AbstractSet[typing.Union[str, int, type(None)]])
True
>>> issubclass(frozenset, typing.AbstractSet)
True
The following code:
from typing import Any, Tuple
from pytypes import TypeChecker
def f() -> Tuple[Any, ...]:
return ()
with TypeChecker():
f()
print("OK")
fails as follows:
$ python3 Test.py
Traceback (most recent call last):
File "Test.py", line 9, in <module>
f()
File "Test.py", line 6, in f
return ()
pytypes.exceptions.ReturnTypeError:
__main__.f
returned incompatible type:
Expected: Tuple[Any]
Received: Tuple[]
The way the stub file implementation is done it will only work when all imports can be resolved using the Python files. A simple example when this is not the case is type aliases. For example imagine:
# util.pyi
from typing import Union
MagicParam = Union[int, float]
# magic.pyi
from .util import MagicParam
def a() -> MagicParam: ...
Loading magic.pyi
will break with an import error of MagicParam
as that is not defined inside the corresponding util.py
. And given it's a type alias it should not be. As is used solely by the typing system.
The above example works with mypy, following the priority list described in PEP-561 resolution order.
When loading stub files start with a clean import system, that first searches for pyi
files, and if not present fallback to py
. I have a prof of concept level of this here https://github.com/gaborbernat/prefer-stubs-python-import. If you think this request is reasonable I can make a PR for it. Thanks!
from typing import Dict
from pytypes import typechecked
@typechecked
def foo(a: Dict):
pass
foo({'name': 'test2', 'surface': 1})
Raises
pytypes.exceptions.InputTypeError:
autoclass.tests.test_readme.foo
called with incompatible types:
Expected: Tuple[Dict]
Received: Tuple[Dict[str, Union[str, int]]]
While it should not.
Note that it also makes PyCharm 2017.2.4 and 2017.3 crash when executed in the python terminal :
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Program Files\JetBrains\PyCharm Community Edition 2017.2.3\helpers\pydev\_pydev_bundle\pydev_console_utils.py", line 251, in add_exec
more = self.do_add_exec(code_fragment)
File "C:\Program Files\JetBrains\PyCharm Community Edition 2017.2.3\helpers\pydev\pydevconsole.py", line 123, in do_add_exec
command.run()
File "C:\Program Files\JetBrains\PyCharm Community Edition 2017.2.3\helpers\pydev\pydevconsole.py", line 82, in run
self.more = self.interpreter.runsource(text, '<input>', symbol)
File "C:\Miniconda3\envs\tools\lib\code.py", line 75, in runsource
self.runcode(code)
File "C:\Miniconda3\envs\tools\lib\code.py", line 95, in runcode
self.showtraceback()
File "C:\Miniconda3\envs\tools\lib\code.py", line 149, in showtraceback
sys.excepthook(ei[0], ei[1], last_tb)
File "C:\Miniconda3\envs\tools\lib\site-packages\pytypes\util.py", line 816, in _pytypes_excepthook
traceback.print_exception(exctype, value, tb, _calc_traceback_limit(tb))
File "C:\Miniconda3\envs\tools\lib\site-packages\pytypes\util.py", line 760, in _calc_traceback_limit
if tb2.tb_next.tb_frame.f_code.co_filename.split(os.sep)[-2] == 'pytypes' and not \
IndexError: list index out of range
Ideally such a method would provide parameters to specify if the caller wishes to
>>> import typing
>>> from pytypes import type_util
>>> type_util._isinstance([], typing.Sequence)
True
>>> type_util._isinstance([], typing.Sequence[int])
False
False
there is surprising. I understand why it happens: because internally isinstance
is converted to issubclass
and Sequence[Any]
is not a subclass of Sequence[int]
.
This is probably a Jython issue, but I'd like to have a fallback, since pytypes used to work with Jython apart from this.
As far as I understand, this is about some functionality of setuptools.
I didn't explicitly run setup.py on Jython, so something might be ill-configured.
However, I also didn't do such a thing on CPython, but there it runs out of the box.
How to fix it?
Hi! while investigating a PR, I found this in checker_tp
: (pytypes.typechecker._typeinspect_func:781
)
if prop or prop_getter:
slf = True
util._warn_argname('property using non-idiomatic self argname',
func0, slf, clsm)
check_args = args_kw[1:] # omit self
check_args = args_kw # <--- will always overwrite the `check_args` from the previous line!
I don't know enough about the logic involved to fix it, but I'm guessing it was intended to be this:
if prop or prop_getter:
slf = True
util._warn_argname('property using non-idiomatic self argname',
func0, slf, clsm)
check_args = args_kw[1:] # omit self
else:
check_args = args_kw
(That also fixes some bugs I hit because of "non-idiomatic self" in @properties
, but that's for another time)
The following code:
from typing import Iterable
from pytypes import TypeChecker
def f(a: Iterable[str]) -> None:
pass
with TypeChecker():
f((c for c in 'abc'))
print("OK")
fails as follows:
$ python3 Test.py
Traceback (most recent call last):
File "Test.py", line 9, in <module>
f((c for c in 'abc'))
File "Test.py", line 5, in f
def f(a: Iterable[str]) -> None:
pytypes.exceptions.InputTypeError:
__main__.f
called with incompatible types:
Expected: Tuple[Iterable[str]]
Received: Tuple[Generator]
I think this might be an impossible issue to fix because Python iterators (and all other standard collections) can hold elements of multiple types. Feel free to close without much consideration.
If I have a class that extends generic and has a method that takes an iterator, I cannot type check that the iterator has all elements of the desired type. This arises in the use case of creating a typed list which supports extend
.
from typing import TypeVar, Generic, Iterator
from pytypes import typechecked
T = TypeVar('T')
class TypList(Generic[T], list):
@typechecked
def append(self, obj: T) -> None:
super().append(obj)
@typechecked
def extend(self, iterable: Iterator[T]) -> None:
super().extend(iterable)
@typechecked
def insert(self, index: int, obj: T) -> None:
super().insert(index, obj)
class IntList(TypList[int]):
...
il = IntList()
il.append(1) # No error, as expected
il.append("a") # InputTypeError as expected
il.extend(iter([1, 2, 3])) # No error, as expected
il.extend(iter(["a", "b", "c"])) # No error, somewhat unexpected
print(il) # [1, 1, 2, 3, 'a', 'b', 'c'] <-- Ideally would only hold ints
In this case, a perfectly reasonable workaround is the check the contents of iterable
manually, not using the decorator.
>>> import typing
>>> from pytypes import type_util
>>> T = typing.TypeVar('T')
>>> class Foo(typing.Generic[T]):
... pass
...
>>> type_util.resolve_fw_decl(Foo)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not iterable
Currently it is trying to guess the module, but this is not always possible. For example, it does not work for me if I call get_type_hints
while the module is being defined and module does not yet exist.
A workaround for me is that currently I set im_class
attribute on the function I want to get type hints for, but I think it might be cleaner if there would be an optional argument get_type_hints
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.