Snake_case aliases to camelCased methods in unittest

Would a class wrapper serve your needs?
Maybe something like:

import unittest


def attribute_error(self, *args, **kwargs):
    raise AttributeError
    

def my_unit_test(cls):
    cls.assert_raises = cls.assertRaises
    cls.assert_True = cls.assertTrue
    cls.assertTrue = attribute_error
    cls.assertRaises = attribute_error
    # ...
    return cls


@my_unit_test
class MyTest(unittest.TestCase):

    def test_1(self):
        self.assert_True(1)
        
    def test_2(self):
        with self.assert_raises(AttributeError):
            self.assertTrue(1)
               
    
if __name__ == '__main__':
    unittest.main()
    
1 Like

Fortunately there is pytest and I am not sentenced to use camelCase in Python code :wink:

1 Like

How long a deprecation period are you thinking of?

Python 2.6 (in 2006) introduced threading.current_thread() as an alias for threading.currentThread() etc. They were officilaly deprecated in Python 3.10 (2020), but with no schedule for actual removal.

Internal consistency is more important than PEP 8 compliance.

1 Like

Maybe this mythical Python 4.0?

1 Like

Whatever the period may be, at its end every use of deprecated method should be replaced with a new method. Every existing test, in every project that uses unittest, should be rewritten. You can imagine how much it will cost in man-hours? It is easier to create a new package snake_names_unittest and make every project in the world using it.

2 Likes

7 posts were split to a new topic: Codecrumbs: deprecate and refactor code across library boundaries

There was a similar discussion a few weeks ago about renaming or aliasing members of the datetime module to follow PEP-8 naming conventions:

The sentiment was that this type of change in the stdlib has much more churn to cause in the ecosystem than benefits, since these are widely used features that may even predate PEP-8.

Libs, frameworks, projects in general would have to be adjusted to prepare for a possible future removal of the old names. Searches on the web would also be affected by redundancy and indirection of names between old and new content, which has a high potential for causing confusion in the public, specially newcomers.

There are other modules that suffer from the same inconsistency, such as logging, which would also be quite problematic to change. Once you change X, there will certainly be people who will demand that you also change Y.

There are things that are less painful to accept as “facts of life” :man_shrugging:

Snake casing more methods in the standard library would be a good thing in my opinion, even if duplicate aliases would of course have to be kept around. The added consistency would help codebases look more clean, and it’s one less minor hump to remember for new programmers.

Especially when writing your own assertions, it currently introduces an choice: do I match the style of the unittest module and make my new assertion camelCase, or match the project styleguides and write it in snake_case? Either option doesn’t look great.

3 Likes

Yep. The downside is that all the consistency you gain across the stdlib is lost within the module, leading to questions like “should I use assertNotEqual or assert_not_equal?” - and the correct answer will be “use assertNotEqual, it works on all versions of Python”. There’s no easy way to do this, which is why PEP 8 specifically says:

In particular: do not break backwards compatibility just to comply with this PEP!

5 Likes

2 posts were merged into an existing topic: Codecrumbs: deprecate and refactor code across library boundaries

In my humble opinion, unless you really need to reduce dependency count, you might as well just use pytest, which just uses assert and decorators, no methods. Given that Python ecosystem has a much better alternative in every way, changing the naming of methods is just sprinkling glitter on an older fruit, instead of buying a fresh one. So there are basically two paths:

  1. You work on a code base which already uses unittest CamelCase methods for its unit tests. Great, then for the sake of consistency it’s better that there is only one CamelCase way of naming methods, instead of raising confusion by potentially having CamelCase methods mixed with snake_case ones.

  2. You work on a code base which does not have unit tests written yet. Then, why are you not using pytest?

Because the Python language and community deserves consistency.

It’s not about reasoning for personal projects, it’s for a better future. - Python has made my current present better (than what I had with other programming languages 20+ years ago). Why not invest in a better future today? I think that’s what drives most of “us” who speak for this topic.

2 Likes

I feel like a much better future would be drafting a PEP which adds pytest-style unit tests to stdlib :slight_smile: Either way, the cost is the same (the previous way of CamelCase unittest methods would be considered as “un-Pythonic”), but the benefit of change would be much larger.

1 Like

In my own experience, in spite of not belonging to the stdlib, pytest is closer to being the one true go-to tool than unittest.

4 Likes

Sure, I agree. It feels more “pythonic”, if you want so.

The point is, though, that the unittest module is part of the standard library, which gives (newcomers) a feeling that it’s the endorsed go-to solution. And it’s not, if you want to write pythonic code. That hurts!

That’s why it were great to get the code style fixed. We shouldn’t care about PEP8 religion and counter-religion. Python as a welcoming, consistent environment is at stake. That’s it, nothing more.

1 Like

Seriously? Are you saying that Python as a language seems unwelcoming, simply because one of the standard library modules follows a different naming convention? Yes, it’s a point of friction, but isn’t this overblowing the problem just a bit?

Ignoring the exaggerated rhetoric, there’s an important point that people are missing. Changing the unittest module will impact all projects that currently use it for testing, requiring them to spend effort that could be spent elsewhere, simply making cosmetic changes. And they need to test those changes to make sure they got them right - which involves testing your test suite, which is a further complication (especially for projects with complex test infrastructures).

And one project that is a heavy user of unittest is CPython itself. So making this change would have a double cost to the CPython project. Probably even more, as I suspect that the tests for the unittest module itself would be even more complex to update than the average test module…

All of that would suck up resources and effort that could have been spent on adding new features to the language, or improving performance, or simply fixing existing bugs. Is changing from one arbitrary naming convention to another, simply for the sake of “consistency” really worth that cost?

Edit: Before someone says that by having aliases, there’s no need to change, doesn’t that pretty fundamentally ruin the point of the exercise? If CPython itself doesn’t use the recommended forms, what sort of message does that give?

I’m not a native speaker. Maybe “is at stake” is too strong as a statement.

Just wanted to support others’ opinion, because the discussion seemed a bit unbalanced to me.

1 Like

This feeling is the actual problem, not unittest’s naming conventions. The solution is not to revise unittest but to nudge the ecosystem towards pytest while keeping unittest for backwards compatibility. It’s mostly a social problem.

It is widely agreed upon by now that the “batteries included” principle has become more of a bottleneck than a feature. The challenge today is encouraging the use of certain third-party libraries in spite of their “unofficial” status. A similar situation exists with urllib vs requests and to a lesser extent re vs regex.

3 Likes

Hmm. Were you a core dev back when Python 2.6 was current? If not, we may need someone else to answer this: How was the transition from threading.currentThread() to threading.current_thread() handled? Was there pressure to convert the stdlib, or was it left untouched? This might be a special case, though, since 2.6 and 2.7 were both created with Python 3 in mind.

2 Likes