Run-time type checker for Python

Overview
Build Status Code Coverage https://readthedocs.org/projects/typeguard/badge/?version=latest

This library provides run-time type checking for functions defined with PEP 484 argument (and return) type annotations.

Four principal ways to do type checking are provided, each with its pros and cons:

  1. the check_argument_types() and check_return_type() functions:
    • debugger friendly (except when running with the pydev debugger with the C extension installed)
    • does not work reliably with dynamically defined type hints (e.g. in nested functions)
  2. the @typechecked decorator:
    • automatically type checks yields and sends of returned generators (regular and async)
    • adds an extra frame to the call stack for every call to a decorated function
  3. the stack profiler hook (with TypeChecker('packagename'):) (deprecated):
    • emits warnings instead of raising TypeError
    • requires very few modifications to the code
    • multiple TypeCheckers can be stacked/nested
    • does not work reliably with dynamically defined type hints (e.g. in nested functions)
    • may cause problems with badly behaving debuggers or profilers
    • cannot distinguish between an exception being raised and a None being returned
  4. the import hook (typeguard.importhook.install_import_hook()):
    • automatically annotates classes and functions with @typechecked on import
    • no code changes required in target modules
    • requires imports of modules you need to check to be deferred until after the import hook has been installed
    • may clash with other import hooks

See the documentation for further instructions.

Comments
  • Modify check_type to work without memo

    Modify check_type to work without memo

    In my project I would like to check arbitrary object against PEP 484 definition. check_type seems to be what I need, but it requires a memo object which I do not have in my use case.

    opened by Kentzo 39
  • Quoted annotations do not work in cyclic imports

    Quoted annotations do not work in cyclic imports

    Python usually doesn't allow cyclic imports, but they're sometimes necessary for proper static type annotations. When that is the case, the cyclic import is guarded by if TYPE_CHECKING: and annotations for types imported from such a module are quoted like strings to avoid errors at runtime. That's a standard practice recommended by mypy developers.

    However, any program that uses this approach to annotations seems incompatible with typeguard. Consider this example:

    A.py:

    from typeguard import TypeChecker
    
    from B import B
    
    class A:
        def f(self, b: B) -> None:
            b.f(self)
    
    with TypeChecker(('__main__', 'A', 'B')):
        A().f(B())
    

    B.py:

    from typing import TYPE_CHECKING
    
    if TYPE_CHECKING:
        from A import A
    
    class B:
        def f(self, a: 'A') -> None:
            print("OK")
    

    If typeguard is disabled, the program performs fairly well as it is in fact absolutely correct in runtime, and also correct from mypy point of view:

    $ mypy A.py B.py
    $ python3 A.py 
    OK
    

    However if it is run with typeguard, the following fatal exception occurs:

    $ python3 A.py 
    /usr/local/lib/python3.6/dist-packages/typeguard/__init__.py:657: UserWarning: the system profiling hook has changed unexpectedly
      warn('the system profiling hook has changed unexpectedly')
    Traceback (most recent call last):
      File "A.py", line 10, in <module>
        A().f(B())
      File "A.py", line 7, in f
        b.f(self)
      File "/home/vmz/git/userfe/B.py", line 7, in f
        def f(self, a: 'A') -> None:
      File "/usr/local/lib/python3.6/dist-packages/typeguard/__init__.py", line 690, in __call__
        memo = self._call_memos[frame] = _CallMemo(func, frame)
      File "/usr/local/lib/python3.6/dist-packages/typeguard/__init__.py", line 55, in __init__
        hints = get_type_hints(func)
      File "/usr/lib/python3.6/typing.py", line 1543, in get_type_hints
        value = _eval_type(value, globalns, localns)
      File "/usr/lib/python3.6/typing.py", line 350, in _eval_type
        return t._eval_type(globalns, localns)
      File "/usr/lib/python3.6/typing.py", line 245, in _eval_type
        eval(self.__forward_code__, globalns, localns),
      File "<string>", line 1, in <module>
    NameError: name 'A' is not defined
    
    opened by jolaf 37
  • Add ability to override typeguard default checks

    Add ability to override typeguard default checks

    This PR is related to the question here: https://github.com/agronholm/typeguard/issues/184

    After following the path of adding Union[int, np.int64] everywhere, which fixed the problem with typeguard, now I have 30 issues with mypy because np.int64 behaves as an int (so it can be passed to range for example) but mypy will complain if a variable which is typed Union[int, np.int64] is passed to range.

    This PR allows the user to provide a function that, for example, makes typeguard treat np.int64 as int.

    [x] added function register_override [x] added tests [x] extended docs

    opened by luk-f-a 21
  • Test failures with 2.11.1

    Test failures with 2.11.1

    This is also reproduceable for me on 2.11.0 but not on 2.10.0

    This is when running the test suite with python -m pytest

    ==================================== ERRORS ==================================== __________________ ERROR collecting tests/test_importhook.py ___________________ ImportError while importing test module '/builddir/build/BUILD/typeguard-2.11.1/tests/test_importhook.py'. Hint: make sure your test modules/packages have valid Python names. Traceback: /usr/lib64/python3.9/importlib/init.py:127: in import_module return _bootstrap._gcd_import(name[level:], package, level) tests/test_importhook.py:9: in from typeguard.importhook import TypeguardFinder, install_import_hook E ModuleNotFoundError: No module named 'typeguard' ___________________ ERROR collecting tests/test_typeguard.py ___________________ ImportError while importing test module '/builddir/build/BUILD/typeguard-2.11.1/tests/test_typeguard.py'. Hint: make sure your test modules/packages have valid Python names. Traceback: /usr/lib64/python3.9/importlib/init.py:127: in import_module return _bootstrap._gcd_import(name[level:], package, level) tests/test_typeguard.py:16: in from typeguard import ( E ModuleNotFoundError: No module named 'typeguard' ________________ ERROR collecting tests/test_typeguard_py36.py _________________ ImportError while importing test module '/builddir/build/BUILD/typeguard-2.11.1/tests/test_typeguard_py36.py'. Hint: make sure your test modules/packages have valid Python names. Traceback: /usr/lib64/python3.9/importlib/init.py:127: in import_module return _bootstrap._gcd_import(name[level:], package, level) tests/test_typeguard_py36.py:7: in from typeguard import TypeChecker, typechecked E ModuleNotFoundError: No module named 'typeguard' !!!!!!!!!!!!!!!!!!! Interrupted: 3 errors during collection !!!!!!!!!!!!!!!!!!!! ============================== 3 errors in 0.24s ===============================

    opened by snecklifter 20
  • question: use to check type compatibility?

    question: use to check type compatibility?

    I am writing a distributed execution system, in which messages are sent among task nodes implemented by python functions. Before they are run, the flow graph is "compiled". During this step, I would like to check types of messages.

    I can get the type annotation of a message from both sender and receiver, and am searching for a way to check if these two types are compatible with one another. (In particular, if a message created by the sender will be of the type expected by the receiver, if the sender respects the type annotation.) Can I do this with typeguard? An example or pointer to the docs would be much appreciated if it is possible. If not, any suggestions as to another package that can help me?

    question 
    opened by shaunc 20
  • Fill missing type hints

    Fill missing type hints

    Closes: #240

    typeguard.typechecking is too complex to annotate correctly. So please tell me your advice, or annotate it instead of me.

    $ mypy src
    src/typeguard/__init__.py:1133: error: Function is missing a return type
    annotation  [no-untyped-def]
        def typechecked(func=None, *, always=False, _localns: Optional[Dict[st...
        ^
    src/typeguard/__init__.py:1133: error: Function is missing a type annotation
    for one or more arguments  [no-untyped-def]
        def typechecked(func=None, *, always=False, _localns: Optional[Dict[st...
        ^
    src/typeguard/__init__.py:1164: error: No overload variant of "typechecked"
    matches argument types "Union[FunctionType, MethodType, Type[Any]]", "Any",
    "Dict[str, Any]"  [call-overload]
                                typechecked(attr, always=always, _localns=func...
                                ^
    src/typeguard/__init__.py:1164: note: Possible overload variants:
    src/typeguard/__init__.py:1164: note:     def typechecked(*, always: bool = ...) -> Callable[[T_CallableOrType], T_CallableOrType]
    src/typeguard/__init__.py:1164: note:     def [T_CallableOrType] typechecked(func: T_CallableOrType, *, always: bool = ...) -> T_CallableOrType
    src/typeguard/__init__.py:1168: error: No overload variant of "typechecked"
    matches argument types "Callable[..., Any]", "Any", "Dict[str, Any]" 
    [call-overload]
                            wrapped = typechecked(attr.__func__, always=always...
                                      ^
    src/typeguard/__init__.py:1168: note: Possible overload variants:
    src/typeguard/__init__.py:1168: note:     def typechecked(*, always: bool = ...) -> Callable[[T_CallableOrType], T_CallableOrType]
    src/typeguard/__init__.py:1168: note:     def [T_CallableOrType] typechecked(func: T_CallableOrType, *, always: bool = ...) -> T_CallableOrType
    src/typeguard/__init__.py:1174: error: Argument 3 to "getattr" has incompatible
    type "Tuple[]"; expected "bool"  [arg-type]
        ...ty_func is not None and getattr(property_func, "__annotations__", ()):
                                                                             ^
    src/typeguard/__init__.py:1175: error: No overload variant of "typechecked"
    matches argument types "Any", "Any", "Dict[str, Any]"  [call-overload]
                                kwargs[name] = typechecked(
                                               ^
    src/typeguard/__init__.py:1175: note: Possible overload variants:
    src/typeguard/__init__.py:1175: note:     def typechecked(*, always: bool = ...) -> Callable[[T_CallableOrType], T_CallableOrType]
    src/typeguard/__init__.py:1175: note:     def [T_CallableOrType] typechecked(func: T_CallableOrType, *, always: bool = ...) -> T_CallableOrType
    src/typeguard/__init__.py:1179: error: Argument 1 to "property" has
    incompatible type "**Dict[str, Optional[str]]"; expected
    "Optional[Callable[[Any], Any]]"  [arg-type]
                        setattr(func, key, attr.__class__(**kwargs))
                                                            ^
    src/typeguard/__init__.py:1179: error: Argument 1 to "property" has
    incompatible type "**Dict[str, Optional[str]]"; expected
    "Optional[Callable[[Any, Any], None]]"  [arg-type]
                        setattr(func, key, attr.__class__(**kwargs))
                                                            ^
    src/typeguard/__init__.py:1179: error: Argument 1 to "property" has
    incompatible type "**Dict[str, Optional[str]]"; expected
    "Optional[Callable[[Any], None]]"  [arg-type]
                        setattr(func, key, attr.__class__(**kwargs))
                                                            ^
    src/typeguard/__init__.py:1219: error: Returning Any from function declared to
    return
    "Union[TypeCheckedGenerator, TypeCheckedAsyncGenerator, GeneratorType[Any, Any, Any]]"
     [no-any-return]
                return retval
                ^
    Found 10 errors in 1 file (checked 3 source files)
    
    opened by eggplants 18
  • Import hook crashes on pkg_resources

    Import hook crashes on pkg_resources

    The following code:

    from typeguard.importhook import install_import_hook
    
    install_import_hook('')
    
    import pkg_resources
    

    produces the following output:

    $ python3 Test.py 
    Traceback (most recent call last):
      File "Test.py", line 5, in <module>
        import pkg_resources
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
      File "/usr/local/lib/python3.6/dist-packages/typeguard-2.6.0.post5-py3.6.egg/typeguard/importhook.py", line 82, in exec_module
        return super().exec_module(module)
      File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 77, in <module>
        __import__('pkg_resources.extern.packaging.requirements')
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
      File "/usr/local/lib/python3.6/dist-packages/typeguard-2.6.0.post5-py3.6.egg/typeguard/importhook.py", line 82, in exec_module
        return super().exec_module(module)
      File "/usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/requirements.py", line 9, in <module>
        from pkg_resources.extern.pyparsing import stringStart, stringEnd, originalTextFor, ParseException
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 656, in _load_unlocked
      File "<frozen importlib._bootstrap>", line 626, in _load_backward_compatible
      File "/usr/lib/python3/dist-packages/pkg_resources/extern/__init__.py", line 43, in load_module
        __import__(extant)
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
      File "/usr/local/lib/python3.6/dist-packages/typeguard-2.6.0.post5-py3.6.egg/typeguard/importhook.py", line 82, in exec_module
        return super().exec_module(module)
      File "/usr/lib/python3/dist-packages/pkg_resources/_vendor/pyparsing.py", line 5353, in <module>
        class pyparsing_common:
      File "/usr/local/lib/python3.6/dist-packages/typeguard-2.6.0.post5-py3.6.egg/typeguard/__init__.py", line 721, in typechecked
        if callable(attr) and attr.__qualname__.startswith(prefix):
    AttributeError: 'Combine' object has no attribute '__qualname__'
    Error in sys.excepthook:
    Traceback (most recent call last):
      File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 63, in apport_excepthook
        from apport.fileutils import likely_packaged, get_recent_crashes
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
      File "/usr/local/lib/python3.6/dist-packages/typeguard-2.6.0.post5-py3.6.egg/typeguard/importhook.py", line 82, in exec_module
        return super().exec_module(module)
      File "/usr/lib/python3/dist-packages/apport/__init__.py", line 5, in <module>
        from apport.report import Report
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
      File "/usr/local/lib/python3.6/dist-packages/typeguard-2.6.0.post5-py3.6.egg/typeguard/importhook.py", line 82, in exec_module
        return super().exec_module(module)
      File "/usr/lib/python3/dist-packages/apport/report.py", line 28, in <module>
        import problem_report
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
      File "/usr/local/lib/python3.6/dist-packages/typeguard-2.6.0.post5-py3.6.egg/typeguard/importhook.py", line 82, in exec_module
        return super().exec_module(module)
      File "/usr/lib/python3/dist-packages/problem_report.py", line 16, in <module>
        from email.mime.multipart import MIMEMultipart
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
      File "/usr/local/lib/python3.6/dist-packages/typeguard-2.6.0.post5-py3.6.egg/typeguard/importhook.py", line 82, in exec_module
        return super().exec_module(module)
      File "/usr/lib/python3.6/email/mime/multipart.py", line 9, in <module>
        from email.mime.base import MIMEBase
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
      File "/usr/local/lib/python3.6/dist-packages/typeguard-2.6.0.post5-py3.6.egg/typeguard/importhook.py", line 82, in exec_module
        return super().exec_module(module)
      File "/usr/lib/python3.6/email/mime/base.py", line 9, in <module>
        import email.policy
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
      File "/usr/local/lib/python3.6/dist-packages/typeguard-2.6.0.post5-py3.6.egg/typeguard/importhook.py", line 82, in exec_module
        return super().exec_module(module)
      File "/usr/lib/python3.6/email/policy.py", line 26, in <module>
        class EmailPolicy(Policy):
      File "/usr/local/lib/python3.6/dist-packages/typeguard-2.6.0.post5-py3.6.egg/typeguard/__init__.py", line 721, in typechecked
        if callable(attr) and attr.__qualname__.startswith(prefix):
    AttributeError: 'HeaderRegistry' object has no attribute '__qualname__'
    
    Original exception was:
    Traceback (most recent call last):
      File "Test.py", line 5, in <module>
        import pkg_resources
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
      File "/usr/local/lib/python3.6/dist-packages/typeguard-2.6.0.post5-py3.6.egg/typeguard/importhook.py", line 82, in exec_module
        return super().exec_module(module)
      File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 77, in <module>
        __import__('pkg_resources.extern.packaging.requirements')
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
      File "/usr/local/lib/python3.6/dist-packages/typeguard-2.6.0.post5-py3.6.egg/typeguard/importhook.py", line 82, in exec_module
        return super().exec_module(module)
      File "/usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/requirements.py", line 9, in <module>
        from pkg_resources.extern.pyparsing import stringStart, stringEnd, originalTextFor, ParseException
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 656, in _load_unlocked
      File "<frozen importlib._bootstrap>", line 626, in _load_backward_compatible
      File "/usr/lib/python3/dist-packages/pkg_resources/extern/__init__.py", line 43, in load_module
        __import__(extant)
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
      File "/usr/local/lib/python3.6/dist-packages/typeguard-2.6.0.post5-py3.6.egg/typeguard/importhook.py", line 82, in exec_module
        return super().exec_module(module)
      File "/usr/lib/python3/dist-packages/pkg_resources/_vendor/pyparsing.py", line 5353, in <module>
        class pyparsing_common:
      File "/usr/local/lib/python3.6/dist-packages/typeguard-2.6.0.post5-py3.6.egg/typeguard/__init__.py", line 721, in typechecked
        if callable(attr) and attr.__qualname__.startswith(prefix):
    AttributeError: 'Combine' object has no attribute '__qualname__'
    
    bug 
    opened by jolaf 17
  • About performance

    About performance

    Hi!

    Thanks for the project, looks very good and interesting. I want to ask you some questions about performance: do you have any metrics (or thoughts) how usage of typechecked or TypeChecker affects on performance? And do you use your library in production or this just a prototype for fun?

    question 
    opened by Gr1N 15
  • Yield type inferred incorrectly in nested Generators

    Yield type inferred incorrectly in nested Generators

    The following code:

    from typing import Generator
    
    from typeguard import TypeChecker
    
    def a() -> Generator[str, None, None]:
        yield "OK"
    
    def b() -> Generator[Generator[str, None, None], None, None]:
        yield a()
        yield a()
    
    with TypeChecker('__main__'):
        for f in b():
            print(next(f))
    

    produces the following output:

    $ python3 Test.py 
    OK
    /usr/local/lib/python3.6/dist-packages/typeguard/__init__.py:932: TypeWarning: [MainThread] return from __main__.b() at Test.py:10: type of yielded value must be str; got generator instead
      warn(TypeWarning(memo, event, frame, exc))
    OK
    

    Note that the problem occurs only at the second yield, but not at the first one.

    This is an old issue that I'm observing for some time, but I thought it to be a consequence of #77, but #77 is fixed now in v2.5.1, but this issue still persists.

    opened by jolaf 13
  • Generator annotations are not interpreted according to PEP 484

    Generator annotations are not interpreted according to PEP 484

    Try this example:

    from typing import Generator, no_type_check
    from warnings import filterwarnings
    
    from typeguard import TypeChecker, TypeWarning
    
    
    def generator_example() -> Generator[int, None, None]:
        for i in range(3):
            yield i
    
    
    def main() -> None:
        filterwarnings("error", category=TypeWarning)
        checker = TypeChecker("__main__")
        checker.start()
        results = generator_example()
        for result in results:
            print(result)
    
    
    if __name__ == "__main__":
        main()
    

    I get: typeguard.TypeWarning: [MainThread] return from __main__.generator_example() at generator_fail.py:9: type of the return value must be collections.abc.Generator; got int instead

    As a workaround, I decorate generators with @no_type_check.

    enhancement 
    opened by mihaic 13
  • Handles type checks for Type[Protocol]

    Handles type checks for Type[Protocol]

    I noticed that typeguard wasn't able to correctly type check passed in classes when the type hint was a Type[Protocol]. You would receive an error like: TypeError: Protocols with non-method members don't support issubclass(). Using isinstance() in these situations would be able to correctly type check the passed in class. I also added a warning when a Protocol wasn't annotated with runtime_checkable to make it more explicit when typeguard was unable to perform type checking.

    Tests: Added a data protocol to improve coverage Added a test for checking Type[Protocol]

    opened by williamlw999-fb 12
  • Subscripted generics cannot be used with class and instance checks

    Subscripted generics cannot be used with class and instance checks

    from typing import Tuple
    from typeguard import typechecked
    
    
    @typechecked
    def foo() -> Tuple[bool, bool]:
        return False, False
    
    
    // this works
    foo()
    
    class UnrelatedThing:
        __class_getitem__ = classmethod(type(Tuple[int]))
    
    // this throws TypeError: Subscripted generics cannot be used with class and instance checks
    foo()
    
    

    This appears to have been fixed by 0fbb5b8f8c7b24361a6289122d5c8e87ba3b10ef, but no release has been made since then.

    Would it be possible to make a new stable release so we can pick up this fix?

    opened by apmorton 0
  • Fixed an exception when a dict has mixed bytes and str keys

    Fixed an exception when a dict has mixed bytes and str keys

    The following code demonstrates the problem that is fixed by this PR:

    from typing import TypedDict
    
    from typeguard import typechecked
    
    class TestDict(TypedDict):
        a: str
    
    @typechecked
    def test() -> TestDict:
        return {
            'str': 'test',
            b'bytes': 'test'
        }
    
    test()
    
    $ ./test.py 
    Traceback (most recent call last):
      File "/home/ldef/typeguard/src/./test.py", line 16, in <module>
        test()
      File "/home/ldef/typeguard/src/typeguard/__init__.py", line 285, in wrapper
        check_return_type(retval, memo)
      File "/home/ldef/typeguard/src/typeguard/__init__.py", line 172, in check_return_type
        check_type_internal(retval, memo.type_hints["return"], memo)
      File "/home/ldef/typeguard/src/typeguard/_checkers.py", line 568, in check_type_internal
        checker(value, origin_type, args, memo)
      File "/home/ldef/typeguard/src/typeguard/_checkers.py", line 220, in check_typed_dict
        raise TypeCheckError(f"has unexpected extra key(s): {keys_formatted}")
    typeguard._exceptions.TypeCheckError: the return value has unexpected extra key(s): "b'bytes'", "str"
    
    opened by biolds 5
  • AttributeError: 'CPUDispatcher' object has no attribute '__globals__' with numba.njit decorated function

    AttributeError: 'CPUDispatcher' object has no attribute '__globals__' with numba.njit decorated function

    Describe the bug I am using the numba.njit decorator to decorate a function. When I execute pytest with typeguard, I get an error when this decorated function is called: AttributeError: 'CPUDispatcher' object has no attribute '__globals__'. When trying to narrow down the error and trying to reproduce with a minimal working example, I found out that the error only occurs when the decorated function is imported absolutely from a module. When the same function is imported with a relative import there is no error.

    To Reproduce I have three different files: two source files (one for absolute and one for relative import) and one pytest file: src/my_module/numba_typeguard.py (absolute import)

    from typing import TypeVar
    
    import numpy as np
    import numpy.typing as npt
    from numba import njit
    
    T = TypeVar("T", bound=np.generic)
    
    
    @njit
    def numba_sum(
        array: npt.NDArray[T],
    ) -> T:
        return np.sum(array)
    

    tests/numba_typeguard.py (relative import) same function as above but in tests directory.

    from typing import TypeVar
    
    import numpy as np
    import numpy.typing as npt
    from numba import njit
    
    T = TypeVar("T", bound=np.generic)
    
    
    @njit
    def numba_sum_local(
        array: npt.NDArray[T],
    ) -> T:
        return np.sum(array)
    

    tests/test_numba_typeguard.py

    import numpy as np
    from my_module.numba_typeguard import numba_sum
    from .numba_typeguard import numba_sum_local
    
    
    def test_numba_sum_njit() -> None:
        x = np.arange(4)
        s = numba_sum(x)
        assert s == np.sum(x)
    
    
    def test_numba_sum() -> None:
        x = np.arange(4)
        s = numba_sum.py_func(x)
        assert s == np.sum(x)
    
    
    def test_numba_sum_local_njit() -> None:
        x = np.arange(4)
        s = numba_sum_local(x)
        assert s == np.sum(x)
    
    
    def test_numba_sum_local() -> None:
        x = np.arange(4)
        s = numba_sum_local.py_func(x)
        assert s == np.sum(x)
    

    The following is the error I get:

    ======================================================================================================================================= FAILURES =======================================================================================================================================
    _________________________________________________________________________________________________________________________________ test_numba_sum_njit __________________________________________________________________________________________________________________________________
    
        def test_numba_sum_njit() -> None:
            x = np.arange(4)
    >       s = numba_sum(x)
    
    tests/test_numba_typeguard.py:8:
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    .nox/typeguard-3-9/lib/python3.9/site-packages/typeguard/__init__.py:1031: in wrapper
        memo = _CallMemo(python_func, _localns, args=args, kwargs=kwargs)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    self = <typeguard._CallMemo object at 0x7f9db523c880>, func = CPUDispatcher(<function numba_sum at 0x7f9db52fa5e0>)
    frame_locals = {'T': ~T, 'TypeVar': <class 'typing.TypeVar'>, '__builtins__': {'ArithmeticError': <class 'ArithmeticError'>, 'Asserti...s/.nox/typeguard-3-9/lib/python3.9/site-packages/my_module/__pycache__/numba_typeguard.cpython-39.pyc', ...}
    args = (array([0, 1, 2, 3]),), kwargs = {}, forward_refs_policy = <ForwardRefPolicy.ERROR: 1>
    
        def __init__(self, func: Callable, frame_locals: Optional[Dict[str, Any]] = None,
                     args: tuple = None, kwargs: Dict[str, Any] = None,
                     forward_refs_policy=ForwardRefPolicy.ERROR):
    >       super().__init__(func.__globals__, frame_locals)
    E       AttributeError: 'CPUDispatcher' object has no attribute '__globals__'
    
    .nox/typeguard-3-9/lib/python3.9/site-packages/typeguard/__init__.py:191: AttributeError
    

    Expected behavior I expect the error not to depend on relative vs absolute import.

    Additional context As I do not know if this is related to typeguard alone or something else and as I am using the hypermodern python template, I raised also an issue there: https://github.com/cjolowicz/cookiecutter-hypermodern-python/issues/1271

    I tried to remove the py.typed file in the src/my_module directory, but this did not resolve the error.

    opened by gatoniel 0
  • typeguard doesn't check types like

    typeguard doesn't check types like "a | b"

    It seems typeguard doesn't support types like "a | b" that is introduced in PEP604.

    To Reproduce

    from typeguard import typechecked
    from typing import Union
    
    @typechecked
    def f(x: int | float):
      print(x)
    
    @typechecked
    def g(x: Union[int, float]):
      print(x)
    
    f("a")
    g("a")
    

    Expected behavior Both should raise TypeError, but in reality f("a") just passed without raising an exception.

    opened by jingfeijia-tsy 2
  • optionally allow extra keys in typed dicts via check_type

    optionally allow extra keys in typed dicts via check_type

    What

    This PR:

    • adds an optional kwarg allow_extra to check_type
    • allow_extra defaults to False
    • if allow_extra is True, any TypedDict checks will allow extra keys over value, rather than raise a TypeCheckError

    Why

    After reading https://github.com/python/mypy/issues/4617, it does not appear that TypedDict will allow extra keys (fields) any time soon.

    I like to use typeguard to validate data coming from outside process bounds. I use check_type for that. This lets me re-use the Python type hints already specified in the code base. This is better (IMO) than specifying things a second time with, say, Pydantic, or Marshmallow. In most cases this data is JSON, and most of the time it's envelope'd into a dictionary.

    opened by jomido 2
  • [Doc] TypeError: check_type() missing 1 required positional argument: 'expected_type'

    [Doc] TypeError: check_type() missing 1 required positional argument: 'expected_type'

    Describe the bug

    https://typeguard.readthedocs.io/en/latest/userguide.html#checking-types-directly

    from typeguard import check_type
    
    # Raises TypeError if there's a problem
    check_type([1234], List[int])
    

    To Reproduce

    Run the above code. Get error:

    TypeError: check_type() missing 1 required positional argument: 'expected_type'
    

    Suggested changes

    from typeguard import check_type
    
    a = [1234]
    # Raises TypeError if there's a problem
    check_type('a', a, List[int])
    
    documentation 
    opened by ayaka14732 3
Owner
Alex Grönholm
Alex Grönholm
Trace all method entries and exits, the exit also prints the return value, if it is of basic type

Trace all method entries and exits, the exit also prints the return value, if it is of basic type. The apk must have set the android:debuggable="true" flag.

Kurt Nistelberger 7 Aug 10, 2022
Little helper to run Steam apps under Proton with a GDB debugger

protongdb A small little helper for running games with Proton and debugging with GDB Requirements At least Python 3.5 protontricks pip package and its

Joshie 21 Nov 27, 2022
pdb++, a drop-in replacement for pdb (the Python debugger)

pdb++, a drop-in replacement for pdb What is it? This module is an extension of the pdb module of the standard library. It is meant to be fully compat

null 1k Dec 24, 2022
Full-screen console debugger for Python

PuDB: a console-based visual debugger for Python Its goal is to provide all the niceties of modern GUI-based debuggers in a more lightweight and keybo

Andreas Klöckner 2.6k Jan 1, 2023
Trace any Python program, anywhere!

lptrace lptrace is strace for Python programs. It lets you see in real-time what functions a Python program is running. It's particularly useful to de

Karim Hamidou 687 Nov 20, 2022
Debugging manhole for python applications.

Overview docs tests package Manhole is in-process service that will accept unix domain socket connections and present the stacktraces for all threads

Ionel Cristian Mărieș 332 Dec 7, 2022
Debugger capable of attaching to and injecting code into python processes.

DISCLAIMER: This is not an official google project, this is just something I wrote while at Google. Pyringe What this is Pyringe is a python debugger

Google 1.6k Dec 15, 2022
(OLD REPO) Line-by-line profiling for Python - Current repo ->

line_profiler and kernprof line_profiler is a module for doing line-by-line profiling of functions. kernprof is a convenient script for running either

Robert Kern 3.6k Jan 6, 2023
Monitor Memory usage of Python code

Memory Profiler This is a python module for monitoring memory consumption of a process as well as line-by-line analysis of memory consumption for pyth

Fabian Pedregosa 80 Nov 18, 2022
Sampling profiler for Python programs

py-spy: Sampling profiler for Python programs py-spy is a sampling profiler for Python programs. It lets you visualize what your Python program is spe

Ben Frederickson 9.5k Jan 8, 2023
🔥 Pyflame: A Ptracing Profiler For Python. This project is deprecated and not maintained.

Pyflame: A Ptracing Profiler For Python (This project is deprecated and not maintained.) Pyflame is a high performance profiling tool that generates f

Uber Archive 3k Jan 7, 2023
Visual profiler for Python

vprof vprof is a Python package providing rich and interactive visualizations for various Python program characteristics such as running time and memo

Nick Volynets 3.9k Jan 1, 2023
Parsing ELF and DWARF in Python

pyelftools pyelftools is a pure-Python library for parsing and analyzing ELF files and DWARF debugging information. See the User's guide for more deta

Eli Bendersky 1.6k Jan 4, 2023
pdb++, a drop-in replacement for pdb (the Python debugger)

pdb++, a drop-in replacement for pdb What is it? This module is an extension of the pdb module of the standard library. It is meant to be fully compat

null 1k Jan 2, 2023
Graphical Python debugger which lets you easily view the values of all evaluated expressions

birdseye birdseye is a Python debugger which records the values of expressions in a function call and lets you easily view them after the function exi

Alex Hall 1.5k Dec 24, 2022
A powerful set of Python debugging tools, based on PySnooper

snoop snoop is a powerful set of Python debugging tools. It's primarily meant to be a more featureful and refined version of PySnooper. It also includ

Alex Hall 874 Jan 8, 2023
Inject code into running Python processes

pyrasite Tools for injecting arbitrary code into running Python processes. homepage: http://pyrasite.com documentation: http://pyrasite.rtfd.org downl

Luke Macken 2.7k Jan 8, 2023
Cyberbrain: Python debugging, redefined.

Cyberbrain1(电子脑) aims to free programmers from debugging.

laike9m 2.3k Jan 7, 2023
Voltron is an extensible debugger UI toolkit written in Python.

Voltron is an extensible debugger UI toolkit written in Python. It aims to improve the user experience of various debuggers (LLDB, GDB, VDB an

snare 5.9k Dec 30, 2022