Search code examples
pythonprivatepylint

Pylint w0212-Warning while doing unittests


we often use this double underscore prefix for internal methods of our classes. This usually raises a W0212 during unit-testing, because we call the proctected methods directly e.g. TestClass().__my_private_method().

I know that in Python there are no private methods. Nevertheless I find this practice of using the underscore prefix good for structural reasons, e.g., it makes it quite obvious to other developers how to use a class.

Now I found this fix for the W0212-Warning from the phoenix-github-page:

class Foo:
    def __bar(self):
        pass

    def baz(self):
        return self.__bar()


foo = Foo()
foo.baz()

Based on this you could create a method for unittest without disabling W0212 like this:

class SomeClass:
    """ some docstring
    """
    def __init__(self) -> None:
        self.myattr = 1

    def __my_protected_method(self):
        return self.myattr + 1

    def __another_protected_method(self):
        return self.myattr + 2

    def method_for_unittests(self, method_name):
        if method_name == "my_protected_method":
            return self.__my_protected_method()
        if method_name == "another_protected_method":
            return self.__another_protected_method()
        return None

This seems like a nicer solution than using a seperate .pylintrc (suggested here). This begs the following questions:

  1. Does my solution make sense or should we just stick with #pylint: disable=protected-access?
  2. Or do you maybe have a better solution using a special decorator? I saw something here, which made me curious. I have little experience writing decorators, therefore the comparatively naive question.

Solution

  • With pylint it's always possible to disable the message, or to make it disappear by using a hack. But it's better to simply disable messages than to hack something that will make pylint stop complaining (but won't make the code better). The best thing to do is to understand the underlying issue to fix it.

    If you're creating a function that will be used only for tests (a test only API) you're doing a hack to make pylint think you're using a public API. What you should do instead is to test private/protected methods through the public interface of your function (through the real API used everywhere) as pointed out by @jonrscharpe in comment.

    If you can't do that, then it means that a private class is hiding inside your code waiting to be created.

    Advertisement: We're trying to include and improve the documentation work of valid-phoenix that you linked in the question into pylint. You can help the pylint team make better suggestions of fixes, see https://github.com/PyCQA/pylint/issues/5953