Skip to content

Fix crash introduced in Python 3.8 in _AttributeInjection. #78

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

andrewborba10
Copy link

Problem: getattr() is now called on all class attributes when
building a Mock that has a spec provided. This triggers a
crash in _AttributeInjection because Mocks are typically created
before the configuration process has completed.

Solution: Stop raising InjectionError when getattr is called on
an attribute, and instead return a sentinel type that represents
a null value. This allows reflective logic to complete without
issue.

Problem: getattr() is now called on all class attributes when
building a Mock that has a `spec` provided. This triggers a
crash in _AttributeInjection because Mocks are typically created
before the configuration process has completed.

Solution: Stop raising InjectionError when getattr is called on
an attribute, and instead return a sentinel type that represents
a null value. This allows reflective logic to complete without
issue.
except InjectorException:
return _NullInjectedAttribute()


class _AttributeInjection(object):
Copy link

@dineshtrivedi dineshtrivedi Feb 1, 2021

Choose a reason for hiding this comment

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

@andrewborba10 I was curious to see your changes, and it made me wonder one thing.

You added a new _AttributeInjection class like below:

class _NullInjectedAttribute(object):
    """
    Returned for injected attributes that don't have an injection configuration.
    """
    pass


class _AttributeInjection(object):
    def __init__(self, cls):
        self._cls = cls

    def __get__(self, obj, owner):
        # Some Python internals (starting in 3.8 specifically) may call
        # getattr() for a class's attributes to do some reflective inspection.
        # That triggers this codepath, potentially before inject.configure()
        # has been called, which is why we should silently return a sentinel
        # type representing a null value instead of raising.
        try:
            return instance(self._cls)
        except InjectorException:
            return _NullInjectedAttribute()

It seems to me that now we should delete this _AttributeInjection class that does not return the sentinel value. And maybe we could also add the type hints to the new class.

Am I missing something?

Copy link
Author

Choose a reason for hiding this comment

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

That was definitely unintentional, I meant to modify the existing class. It sounds like Ivan might have some other changes in mind, so I'll let him apply those with the fix to remove the old class.

@ivankorobkov
Copy link
Owner

Hi!

I'm a little busy right now. I'll try to take a look this week.

@fadedDexofan
Copy link

@ivankorobkov Hi. Any progress in looking? 😀

@ivankorobkov
Copy link
Owner

@fadedDexofan Hi, I'm sorry guys, I've been really busy for the last couple of months. The PR does not look good to me, so I just can't merge it without some changes. I'll try to look into it today or tomorrow.

@philippeboyd
Copy link

@ivankorobkov any news on this?

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.

5 participants