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

use getattr_static in spy instead of __getattributes__ #224

Merged
merged 4 commits into from Jan 10, 2021

Conversation

yesthesoup
Copy link
Contributor

@yesthesoup yesthesoup commented Jan 7, 2021

When attempting to use mocker.spy on a Stripe class in my project, I ran into this error:

    def test_create_customer(self, mocker):
>       stripe_spy = mocker.spy(stripe.Customer, 'create')

tests/[...]/test_stripe_customer_service.py:16:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <pytest_mock.plugin.MockerFixture object at 0x10d6ebdd0>, obj = <class 'stripe.api_resources.customer.Customer'>, name = 'create'

    def spy(self, obj: object, name: str) -> unittest.mock.MagicMock:
        """
        Create a spy of method. It will run method normally, but it is now
        possible to use `mock` call features with it, like call count.

        :param obj: An object.
        :param name: A method in object.
        :return: Spy object.
        """
        method = getattr(obj, name)

        autospec = inspect.ismethod(method) or inspect.isfunction(method)
        # Can't use autospec classmethod or staticmethod objects
        # see: https://bugs.python.org/issue23078
        if inspect.isclass(obj):
            # Bypass class descriptor:
            # http://stackoverflow.com/questions/14187973/python3-check-if-method-is-static
            try:
>               value = obj.__getattribute__(obj, name)  # type:ignore
E               TypeError: descriptor '__getattribute__' requires a 'dict' object but received a 'type'

venv/lib/python3.7/site-packages/pytest_mock/plugin.py:110: TypeError

Here is the Customer source code for reference, a class inheriting from multiple parent classes and including some custom method wrappers.

While digging in order to fix this, I ended up at the stackoverflow question linked to in the original code which mentioned the inspect module's method getattr_static available as of 3.2. This will accomplish the same behaviour as before, as well as work for a larger variety of classes.

I also checked up on the bug that this workaround is there for in the first place, and it was fixed in 3.7 it seems, so eventually autospec can be true by default in theory.

I don't quite know how to reproduce the exact kind of class that would have caused this error in the first place, open to suggestions in order to add a test for it.

@@ -162,7 +162,7 @@ def test_mock_patch_dict_resetall(mocker: MockerFixture) -> None:
],
)
def test_mocker_aliases(name: str, pytestconfig: Any) -> None:
from pytest_mock.plugin import _get_mock_module
from pytest_mock.plugin import _get_mock_module # type: ignore
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the pre-commit mypy run caught these imports with error: Cannot find implementation or library
but now the linting test is failing because of them...any ideas?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, but I've moved _get_mock_module and parse_ini_boolean to a _util.py module: this makes it clear this is not part of the API plus should fix that particular problem.

This also avoids having to use "#type:ignore" when importing them on tests.
@nicoddemus nicoddemus merged commit 379b623 into pytest-dev:master Jan 10, 2021
@nicoddemus
Copy link
Member

nicoddemus commented Jan 10, 2021

Awesome, thanks for the contribution!

@nicoddemus
Copy link
Member

3.5.1 has been released. 🎉

Thanks again!

@yesthesoup
Copy link
Contributor Author

3.5.1 has been released. 🎉

Thanks again!

Thanks for your help on this one!

@yesthesoup yesthesoup deleted the spy-getattr_static branch January 11, 2021 21:27
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

Successfully merging this pull request may close these issues.

None yet

2 participants