Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are Mixin classes abstract base classes

Tags:

python

pycharm

Are Mixin classes abstract base classes? In the example below, the calls to test_base would fail because python wouldn't be able to resolve self.assertEqual for example.

Also, is PyCharm incorrect as flagging Mixin classes like the one below has having unresolved attribute errors?

class TestConverterMixin(object):
    def setUp(self):
        self.alt_hasher = getattr(hash, self.converter.__class__.__name__)

    def test_base(self):
        with self.settings(PASSWORD_HASHERS=[self.hasher, ]):
            load_hashers(settings.PASSWORD_HASHERS)

            for password in PASSWORDS:
                orig = self.alt_hasher.encrypt(password)
                conv = self.converter.from_orig(orig)

                # see if we get a working hash:
                self.assertTrue(check_password(password, conv))

                # convert back and test with passlib:
                back = self.converter.to_orig(conv)
                self.assertEqual(orig, back)
like image 977
smithy Avatar asked Jan 18 '15 14:01

smithy


2 Answers

Are Mixin classes AbstractBaseClasses? The most accurate answer for your case is no but it probably should be.

Your class as a stand-alone cannot survive for you reasons you pointed out. By making it an ABC you explicitly tell anyone looking at your class (like pycharm) that

from abc import ABCMeta, abstractmethod

class TestConverterMixin(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def assertEqual(self, other):
        "Need concrete implementation somewhere"

    .... the rest of your code 

The problem is that you would need this for all of the other methods (self.AssertTrue, self.converter etc). You could have something else in mind but this seriously looks like just a subclass of unittest.TestCase to me.

Oh and was PyCharm wrong. No, they got it right. If you made this an ABC or a subclass of TestCase, they would not have complained. If you used Interfaces, like zope.Interface, pycharm and the like usually get that wrong since they don't understand the registration and lookup process.(it is outside the python core)

like image 128
Phil Cooper Avatar answered Sep 29 '22 13:09

Phil Cooper


I kept having troubles to get PyCharm to not complain about unresolved attribute reference errors on mixin classes. In particular, I also had mixin classes depending on other mixin classes for which I couldn't make one inherit from the other. But then I found this almost perfect way to make PyCharm 2017.1 happy:

class Human:
    def is_male(self):
        return True

class BeardMixin:
    _facial_hair = {'length': 7, 'color': 'brown'}

    def has_beard(self):
        return True

class BeardLengthMixin:
    """Mixin for class Human with BeardMixin to provide get_beard_length()"""

    def get_beard_length(self):
        assert isinstance(self, (Human, BeardMixin))
        # PyCharm will now not complain about any of these 3 attributes
        if self.is_male() and self.has_beard():
            return self._facial_hair['length']

The assert statement gives PyCharm the necessary information about which types self could be. There's a drawback though: The assert statement itself does not do what you think it does: It only checks that self is of either type, not whether it's of both. Unfortunately, using two assert statements doesn't work, because the second overrides the first one as far as PyCharm's type deduction is concerned.

like image 37
jlh Avatar answered Sep 29 '22 13:09

jlh