Skip to content

Property with int return type causes error #318

Closed

Description

@HJDCampbell

Things to check first

  • I have searched the existing issues and didn't find my bug already reported there

  • I have checked that my bug is still present in the latest release

Typeguard version

3.0.1

Python version

3.10

What happened?

Thanks for updating Typeguard, though unfortunately, version 3.0.1 causes an error in my code. I've reduced the error down to the example below, which is hopefully self-explanatory!

How can we reproduce the bug?

This code:

from typeguard import typechecked


@typechecked
class foo:
    @property
    def fub(self) -> int:
        return 5

a = foo()
print(a.fub)

Causes the traceback:

C:\Users\Hamish\Git\msm\.venv310\Scripts\python.exe C:\Users\Hamish\Git\msm\msm\typeguardtest.py 
Traceback (most recent call last):
  File "C:\Users\Hamish\Git\msm\msm\typeguardtest.py", line 11, in <module>
    print(a.fub)
  File "C:\Users\Hamish\Git\msm\msm\typeguardtest.py", line 7, in fub
    def fub(self) -> int:
  File "C:\Users\Hamish\Git\msm\.venv310\lib\site-packages\typeguard\_memo.py", line 70, in __init__
    self.type_hints = _type_hints_map[func]
  File "C:\Users\Hamish\AppData\Local\Programs\Python\Python310\lib\weakref.py", line 416, in __getitem__
    return self.data[ref(key)]
TypeError: cannot create weak reference to 'property' object

Process finished with exit code 1

I'm expecting this code to run without any error (and print 5).

Please let me know if you'd like any more information, and thank you for maintaining this package!

Activity

  1. HJDCampbell commented on Mar 16, 2023

    @HJDCampbell
    Author

    Also:

    • removing the int return type (so that fub() has no return type) means the code runs with no error.
    • Same error occurs when trying to return a str or float from fub()
  2. changed the title [-]Property with int return causes error[/-] [+]Property with int return type causes error[/+] on Mar 16, 2023
  3. agronholm commented on Mar 16, 2023

    @agronholm
    Owner

    Yeah, if you remove the annotation, the method doesn't get instrumented since there would be nothing to check for.

  4. agronholm commented on Mar 16, 2023

    @agronholm
    Owner

    It's too bad I didn't have a test covering this case. The changes I'm working on now are really the only way forward. The instrumentation needs to copy the annotations into the function body itself.

  5. agronholm commented on Mar 18, 2023

    @agronholm
    Owner

    The root cause for this is the same as in #315: typeguard's inability to obtain the original function instance to retrieve the correct type hints. I have a fix in the works that bypasses the issue by duplicating the type annotations in the function body.

  6. agronholm commented on Mar 19, 2023

    @agronholm
    Owner

    Would you mind trying the 4.0-dev branch? Your snippet at least works properly with that.

  7. corwinjoy commented on Mar 21, 2023

    @corwinjoy

    I actually ran into a similar problem with setters. I have a class that defines an args property like:

        @property
        def _args(self) -> Tuple[Union[torch.Tensor, "LinearOperator", int], ...]:
            return self._args_memo
    
        @_args.setter
        def _args(self, args: Tuple[Union[torch.Tensor, "LinearOperator", int], ...]) -> None:
            self._args_memo = args
    

    and then in the class init method I have

       def __init__(self, *args, **kwargs):
            self._args = args
    

    typeguard throws a spurious error on self._args = args because it mistakenly calls the getter function for _args rather than the setter. This worked fine under the old version so I think it may be related.

  8. corwinjoy commented on Mar 21, 2023

    @corwinjoy

    The above produces a stack trace like that shown below, but it's just a fancy way of saying that the wrapper is trying to invoke the getter function instead of the setter.

    ../linear_operator/operators/_linear_operator.py:152: in __init__
        self._args = args
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = <decorator>
    args = (<linear_operator.operators.dense_linear_operator.DenseLinearOperator object at 0x7f6124c47730>, (tensor([[ 1.5693, -0...7],
            [ 0.1743, -0.2726,  1.3835, -0.2421],
            [-0.3467,  0.2257, -0.2421,  1.5709]], requires_grad=True),))
    kwargs = {}, memo_stack = []
    fn = <function LinearOperator._args at 0x7f6124613910>
    
    E           TypeError: LinearOperator._args() takes 1 positional argument but 2 were given
    
  9. agronholm commented on Mar 22, 2023

    @agronholm
    Owner

    That was fixed in 835fb65 but not part of a release yet. I discovered two other problem with local variable assignments, where iterable unpacking (x, *y = ...) gave incorrect results. I plan to make another patch release once this has been handled.

  10. HJDCampbell commented on Mar 22, 2023

    @HJDCampbell
    Author

    Would you mind trying the 4.0-dev branch? Your snippet at least works properly with that.

    That branch works perfectly with my code, it even picked up a small bug! Thank you :)

  11. agronholm commented on Mar 30, 2023

    @agronholm
    Owner

    Yes, this was already reported by the original poster, and is already fixed in the 4.0-dev branch. Do you have something to add?

  12. agronholm commented on Mar 30, 2023

    @agronholm
    Owner

    What's importing CallMemo? There is no mention of that in the entire typeguard codebase in 4.0-dev.

  13. agronholm commented on Mar 30, 2023

    @agronholm
    Owner

    You're using the wrong branch or revision. CallMemo was entirely removed in a66d170.

  14. AckslD commented on Mar 30, 2023

    @AckslD

    Try removing any .pyc, I had a similar issue

  15. agronholm commented on Mar 30, 2023

    @agronholm
    Owner

    But if leftover .pyc files are the issue, where is the source code that shows CallMemo coming from?

  16. AckslD commented on Mar 30, 2023

    @AckslD

    Sorry, but I'm not sure I can say. But when I had the OPs issue I tried downgrading to typeguard<3.0.0 but then got the error re CallMemo. I was then very confused since after grepping for CallMemo I couldn't find any source code importing it. However after clearing any .pyc files the issue went away.

  17. agronholm commented on Mar 30, 2023

    @agronholm
    Owner

    At any rate, when upgrading Typeguard, clearing any -typeguard.pyc files is a good idea.

  18. agronholm commented on Apr 1, 2023

    @agronholm
    Owner

    FYI: 4.0.0rc1 is out. I will likely update the .pyc suffix to -typeguard400 or similar once the final release is out. Until then, continue to clear the .pyc files when you update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions