Skip to content

gh-71339: Add additional assertion methods for unittest - #128707

Merged
serhiy-storchaka merged 7 commits into
python:mainfrom
serhiy-storchaka:extra-assertions
Jan 14, 2025
Merged

gh-71339: Add additional assertion methods for unittest#128707
serhiy-storchaka merged 7 commits into
python:mainfrom
serhiy-storchaka:extra-assertions

Conversation

@serhiy-storchaka

@serhiy-storchakaserhiy-storchaka commented Jan 10, 2025

Copy link
Copy Markdown
Member

Add the following methods:

  • assertHasAttr() and assertNotHasAttr()
  • assertIsSubclass() and assertNotIsSubclass()
  • assertStartsWith() and assertNotStartsWith()
  • assertEndsWith() and assertNotEndsWith()

Also improve error messages for assertIsInstance() and assertNotIsInstance().


📚 Documentation preview 📚: https://cpython-previews--128707.org.readthedocs.build/

Add the following methods:
* assertHasAttr() and assertNotHasAttr()
* assertIsSubclass() and assertNotIsSubclass()
* assertStartswith() and assertNotStartswith()
* assertEndswith() and assertNotEndswith()
Also improve error messages for assertIsInstance() and
assertNotIsInstance().
@hugovk

Copy link
Copy Markdown
Member

Great!

  • assertStartsWith() and assertEndsWith() has been renamed to assertStartswith() and assertEndswith().

I recommend assertStartsWith() and assertEndsWith(), both for readability, and for accessibility -- screen readers will have a better chance with the extra capitals.

It doesn't really matter that startswith is all lower case, because we're creating a new method name.

(And we already have assertIsInstance, which checks isinstance, and not assertIsinstance.)

@serhiy-storchaka

Copy link
Copy Markdown
MemberAuthor

I wrote them initially as assertStartsWith() and assertEndsWith(), but renamed to assertStartswith() and assertEndswith() as the result of the discussion on the issue.

@serhiy-storchaka

Copy link
Copy Markdown
MemberAuthor

I created a poll: https://discuss.python.org/t/assertstartwith-vs-assertstartwith/76701.

@JelleZijlstraJelleZijlstra left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good but I agree with Hugo that the name should be assertStartsWith.

@cjw296

Copy link
Copy Markdown
Contributor

Looks like the poll is pretty unanimous :-)

The changes look great, but I'll admit I'm unlikely to use them as I tend to avoid the UnitTest base class where possible now.

@cjw296
cjw296 removed their request for review January 11, 2025 18:21
Comment threadDoc/library/unittest.rst Outdated
Comment threadDoc/library/unittest.rst Outdated
Comment threadDoc/whatsnew/3.14.rst Outdated
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>

@vstinnervstinner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM. Just a few minor coding style remarks.

Comment threadLib/unittest/case.py Outdated
if not isinstance(obj, cls):
standardMsg = '%s is not an instance of %r' % (safe_repr(obj), cls)
if isinstance(cls, tuple):
standardMsg = '%s is not an instance of any of %r' % (safe_repr(obj), cls)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You may use f-strings :-)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Actually, '%s is not an instance of any of %r' % (safe_repr(obj), cls) and f'{safe_repr(obj)!s} is not an instance of any of {cls!r}' produce the same bytecode. So the difference is only in readability, which is at large part subjective. I was not sure that inlining expressions in f-strings would make the code more readable, but if you think so...

Comment threadLib/unittest/case.py Outdated

def assertIsSubclass(self, cls, superclass, msg=None):
try:
r = issubclass(cls, superclass)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You may avoid variables of a single letter: use "res" or "result". Same remark for new functions below.

@picnixzpicnixz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Just some docs nits and LGTM. I'm very happy to have assertHasAttr because I needed it a lot in my personal projects.

Comment threadDoc/library/unittest.rst
Comment threadDoc/library/unittest.rst
@serhiy-storchaka
serhiy-storchaka merged commit 06cad77 into python:mainJan 14, 2025
@serhiy-storchaka
serhiy-storchaka deleted the extra-assertions branch January 14, 2025 08:02
@vstinner

Copy link
Copy Markdown
Member

Nice additions, thanks @serhiy-storchaka.

serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this pull request Jan 14, 2025
…honGH-128707)
Add a mix-in class ExtraAssertions containing the following methods:
* assertHasAttr() and assertNotHasAttr()
* assertIsSubclass() and assertNotIsSubclass()
* assertStartsWith() and assertNotStartsWith()
* assertEndsWith() and assertNotEndsWith()
(cherry picked from commit 06cad77)
@bedevere-app

Copy link
Copy Markdown

GH-128815 is a backport of this pull request to the 3.13 branch.

serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this pull request Jan 14, 2025
…honGH-128707)
Add a mix-in class ExtraAssertions containing the following methods:
* assertHasAttr() and assertNotHasAttr()
* assertIsSubclass() and assertNotIsSubclass()
* assertStartsWith() and assertNotStartsWith()
* assertEndsWith() and assertNotEndsWith()
(cherry picked from commit 06cad77)
serhiy-storchaka added a commit that referenced this pull request Jan 20, 2025
…-128707) (GH-128815)
Add a mix-in class ExtraAssertions containing the following methods:
* assertHasAttr() and assertNotHasAttr()
* assertIsSubclass() and assertNotIsSubclass()
* assertStartsWith() and assertNotStartsWith()
* assertEndsWith() and assertNotEndsWith()
(cherry picked from commit 06cad77)
serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this pull request Jan 20, 2025
…t.support (pythonGH-128707) (pythonGH-128815)
Add a mix-in class ExtraAssertions containing the following methods:
* assertHasAttr() and assertNotHasAttr()
* assertIsSubclass() and assertNotIsSubclass()
* assertStartsWith() and assertNotStartsWith()
* assertEndsWith() and assertNotEndsWith()
(cherry picked from commit c6a566e)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
(cherry picked from commit 06cad77)
serhiy-storchaka added a commit that referenced this pull request Jan 20, 2025
…-128707) (GH-128815) (GH-129059)
Add a mix-in class ExtraAssertions containing the following methods:
* assertHasAttr() and assertNotHasAttr()
* assertIsSubclass() and assertNotIsSubclass()
* assertStartsWith() and assertNotStartsWith()
* assertEndsWith() and assertNotEndsWith()
(cherry picked from commit c6a566e)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
(cherry picked from commit 06cad77)
Sign up for freeto 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.

7 participants

@serhiy-storchaka@hugovk@cjw296@vstinner@jaraco@JelleZijlstra@picnixz