7

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)
smithy
  • 417
  • 1
  • 7
  • 14

2 Answers2

5

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)

Phil Cooper
  • 5,747
  • 1
  • 25
  • 41
  • thank you - Yes, I am looking unittest generally, it just seems in some cases a Mixin works better, but maybe a subclass of unitest.TestCase is just as good. – smithy Jan 18 '15 at 16:34
2

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.

jlh
  • 4,349
  • 40
  • 45
  • That looked like a cool trick, so I tried it on my mixin and it did stop it from complaining about the unresolved references to attributes on the intended super class ... but now it started complaining about unresolved references to class methods ON THE MIXIN. Oh well, just going to live with some yellow marks. – aptwebapps Jun 21 '18 at 13:16
  • 1
    @aptwebapps: `assert isinstance(self, A) and isinstance(self, AMixin)` - this helped me, but I don't like that I would have to put it in multiple places (methods). – Kukosk Sep 26 '18 at 21:55