Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent prefix "called_" for methods on mock objects in safe mode #100690

Closed
cklein opened this issue Jan 2, 2023 · 8 comments
Closed

Prevent prefix "called_" for methods on mock objects in safe mode #100690

cklein opened this issue Jan 2, 2023 · 8 comments
Labels
type-feature A feature request or enhancement

Comments

@cklein
Copy link
Contributor

cklein commented Jan 2, 2023

Prevent prefix "called_" for methods on mock objects in safe mode

Pitch

In safe mode, there's already support for catching typos for accessing the assertion methods:

By default, accessing any attribute whose name starts with assert, assret, asert, aseert or assrt will raise an AttributeError.

Given you have a valid assertion to check whether a mocked function has been called:

assert mock_foo.called

If you now want to check the arguments, and do not pay full attention, you can end up with a tautology like

assert mock_foo.called_once_with(param="test")

The issue: mock_foo.called_once_with is not a valid (assertion) method and therefore an instance of mock.Mock is returned. Because instances of mock.Mock evaluate to true, the assertion is equivalent to assert True.
Like with the preventing the call of methods that start with assert and assret (issue 21238) and also disallowing the typos asert, aseert, and assrt (#23165), this error will not cause a test failure.

Analyzing public repositories on github.com, the Python standard library (thanks @terryjreedy for fixing it in #100647), and our internal code base revealed what seems to be a common source of errors. In our own code base, we have had more than 500 of these issues. More than 50% of those failed after fixing the assertion call, which could potentially have covered existing bugs by relying on bad tests.

Previous discussion

https://discuss.python.org/t/include-prefix-called-in-list-of-forbidden-method-prefixes-for-mock-objects-in-unsafe-mode/22249/4

Linked PRs

@cklein
Copy link
Contributor Author

cklein commented Jan 2, 2023

Pinging @terryjreedy and @gpshead as requested in the discussion.

@tirkarthi
Copy link
Member

To add a similar example Apache Airflow also fixed places where has_calls was used instead of assert_has_calls apache/airflow#20453

@cklein
Copy link
Contributor Author

cklein commented Jan 3, 2023

@tirkarthi Thanks, I'm going to add this name.

@merwok
Copy link
Member

merwok commented Jan 3, 2023

My opinion: this can only happen in test suites that use assert thing, which is not pyunit style but for example pytest style.
Our doc (and commit messages) should continue to not use assert thing style. But for the people that do use the other style, it’s worth detecting this little bug magnet, for the same reason assret_* or assert_thing are detected.

@AlexWaygood
Copy link
Member

I also think this would be a useful check to add. It's very common to use unittest.mock in the context of a pytest test suite, and it's something I've used in the past. I would have appreciated this kind of check when writing those tests.

@merwok
Copy link
Member

merwok commented Jan 6, 2023

I categorized this request as a new feature, but the PR is marked bugfix with backports. Which should it be?
This is a good change, catching legitimate bugs in user code, and in a safe module, but it seems clear to me that it’s a new feature.

(adding @cjw296 here who reviewed the PR)

@AlexWaygood
Copy link
Member

To me it also seemed like a new feature, which should probably go into main, but not be backported. (Though backports via the third-party mock package on PyPI seems fine.)

@cjw296
Copy link
Contributor

cjw296 commented Jan 6, 2023

I don't agree: there was code there to catch this kind of problem, but it was insufficient / buggy. I'm fine with backporting this to 3.10 and 3.11, but since the two of you feel otherwise, I'm fine to remove those labels. They can always be added back later.

@cjw296 cjw296 closed this as completed Jan 6, 2023
cjw296 pushed a commit that referenced this issue Jan 6, 2023
…en when using Mock (#100691)

Mock objects which are not unsafe will now raise an AttributeError when accessing an
attribute that matches the name of an assertion but without the prefix `assert_`, e.g. accessing `called_once` instead of `assert_called_once`.

This is in addition to this already happening for accessing attributes with prefixes assert, assret, asert, aseert, and assrt.
sobolevn added a commit to sobolevn/cpython that referenced this issue Jan 7, 2023
openstack-mirroring pushed a commit to openstack/charm-cinder that referenced this issue Jan 31, 2023
test_clean_storage_unmount incorrectly used 'called_with' instead of
'assert_called_with' which just made a mock function call and didn't
check or assert that the function was actually called.

As a result this function didn't actually test anything, the expected
parameters were not correct so they have been updated.

An error to catch this accidental mistake was added in the recently
released mock 5.0.1 (python/cpython#100690)
  AttributeError: 'called_with' is not a valid assertion.
  Use a spec for the mock if 'called_with' is meant to be an attribute.

The mock library ships in python as unittest.mock but also publishes the
latest code as the 'mock' python package so that older python versions
can get the latest code. The stable branches currently install mock
but the master branch does not, so this error does not actually appear
on master but only the <=yoga stable branches currently. The test is
however wrong either way.

Change-Id: I3076778e8fc62c086651d29abb2c5a3d9921be97
openstack-mirroring pushed a commit to openstack/openstack that referenced this issue Jan 31, 2023
* Update charm-cinder from branch 'master'
  to ceafd9f67f3a5f404091d1f2fff7d2dcc9c71f47
  - Fix missing assert_ prefix on called_with
    
    test_clean_storage_unmount incorrectly used 'called_with' instead of
    'assert_called_with' which just made a mock function call and didn't
    check or assert that the function was actually called.
    
    As a result this function didn't actually test anything, the expected
    parameters were not correct so they have been updated.
    
    An error to catch this accidental mistake was added in the recently
    released mock 5.0.1 (python/cpython#100690)
      AttributeError: 'called_with' is not a valid assertion.
      Use a spec for the mock if 'called_with' is meant to be an attribute.
    
    The mock library ships in python as unittest.mock but also publishes the
    latest code as the 'mock' python package so that older python versions
    can get the latest code. The stable branches currently install mock
    but the master branch does not, so this error does not actually appear
    on master but only the <=yoga stable branches currently. The test is
    however wrong either way.
    
    Change-Id: I3076778e8fc62c086651d29abb2c5a3d9921be97
openstack-mirroring pushed a commit to openstack/charm-cinder that referenced this issue Feb 14, 2023
test_clean_storage_unmount incorrectly used 'called_with' instead of
'assert_called_with' which just made a mock function call and didn't
check or assert that the function was actually called.

As a result this function didn't actually test anything, the expected
parameters were not correct so they have been updated.

An error to catch this accidental mistake was added in the recently
released mock 5.0.1 (python/cpython#100690)
  AttributeError: 'called_with' is not a valid assertion.
  Use a spec for the mock if 'called_with' is meant to be an attribute.

The mock library ships in python as unittest.mock but also publishes the
latest code as the 'mock' python package so that older python versions
can get the latest code. The stable branches currently install mock
but the master branch does not, so this error does not actually appear
on master but only the <=yoga stable branches currently. The test is
however wrong either way.

Change-Id: I3076778e8fc62c086651d29abb2c5a3d9921be97
openstack-mirroring pushed a commit to openstack/charm-cinder that referenced this issue Feb 14, 2023
test_clean_storage_unmount incorrectly used 'called_with' instead of
'assert_called_with' which just made a mock function call and didn't
check or assert that the function was actually called.

As a result this function didn't actually test anything, the expected
parameters were not correct so they have been updated.

An error to catch this accidental mistake was added in the recently
released mock 5.0.1 (python/cpython#100690)
  AttributeError: 'called_with' is not a valid assertion.
  Use a spec for the mock if 'called_with' is meant to be an attribute.

The mock library ships in python as unittest.mock but also publishes the
latest code as the 'mock' python package so that older python versions
can get the latest code. The stable branches currently install mock
but the master branch does not, so this error does not actually appear
on master but only the <=yoga stable branches currently. The test is
however wrong either way.

Change-Id: I3076778e8fc62c086651d29abb2c5a3d9921be97
openstack-mirroring pushed a commit to openstack/charm-cinder that referenced this issue Feb 14, 2023
test_clean_storage_unmount incorrectly used 'called_with' instead of
'assert_called_with' which just made a mock function call and didn't
check or assert that the function was actually called.

As a result this function didn't actually test anything, the expected
parameters were not correct so they have been updated.

An error to catch this accidental mistake was added in the recently
released mock 5.0.1 (python/cpython#100690)
  AttributeError: 'called_with' is not a valid assertion.
  Use a spec for the mock if 'called_with' is meant to be an attribute.

The mock library ships in python as unittest.mock but also publishes the
latest code as the 'mock' python package so that older python versions
can get the latest code. The stable branches currently install mock
but the master branch does not, so this error does not actually appear
on master but only the <=yoga stable branches currently. The test is
however wrong either way.

Change-Id: I3076778e8fc62c086651d29abb2c5a3d9921be97
openstack-mirroring pushed a commit to openstack/charm-cinder that referenced this issue Feb 14, 2023
test_clean_storage_unmount incorrectly used 'called_with' instead of
'assert_called_with' which just made a mock function call and didn't
check or assert that the function was actually called.

As a result this function didn't actually test anything, the expected
parameters were not correct so they have been updated.

An error to catch this accidental mistake was added in the recently
released mock 5.0.1 (python/cpython#100690)
  AttributeError: 'called_with' is not a valid assertion.
  Use a spec for the mock if 'called_with' is meant to be an attribute.

The mock library ships in python as unittest.mock but also publishes the
latest code as the 'mock' python package so that older python versions
can get the latest code. The stable branches currently install mock
but the master branch does not, so this error does not actually appear
on master but only the <=yoga stable branches currently. The test is
however wrong either way.

Change-Id: I3076778e8fc62c086651d29abb2c5a3d9921be97
openstack-mirroring pushed a commit to openstack/charm-cinder that referenced this issue Feb 16, 2023
test_clean_storage_unmount incorrectly used 'called_with' instead of
'assert_called_with' which just made a mock function call and didn't
check or assert that the function was actually called.

As a result this function didn't actually test anything, the expected
parameters were not correct so they have been updated.

An error to catch this accidental mistake was added in the recently
released mock 5.0.1 (python/cpython#100690)
  AttributeError: 'called_with' is not a valid assertion.
  Use a spec for the mock if 'called_with' is meant to be an attribute.

The mock library ships in python as unittest.mock but also publishes the
latest code as the 'mock' python package so that older python versions
can get the latest code. The stable branches currently install mock
but the master branch does not, so this error does not actually appear
on master but only the <=yoga stable branches currently. The test is
however wrong either way.

Change-Id: I3076778e8fc62c086651d29abb2c5a3d9921be97
openstack-mirroring pushed a commit to openstack/charm-cinder that referenced this issue Feb 17, 2023
test_clean_storage_unmount incorrectly used 'called_with' instead of
'assert_called_with' which just made a mock function call and didn't
check or assert that the function was actually called.

As a result this function didn't actually test anything, the expected
parameters were not correct so they have been updated.

An error to catch this accidental mistake was added in the recently
released mock 5.0.1 (python/cpython#100690)
  AttributeError: 'called_with' is not a valid assertion.
  Use a spec for the mock if 'called_with' is meant to be an attribute.

The mock library ships in python as unittest.mock but also publishes the
latest code as the 'mock' python package so that older python versions
can get the latest code. The stable branches currently install mock
but the master branch does not, so this error does not actually appear
on master but only the <=yoga stable branches currently. The test is
however wrong either way.

Change-Id: I3076778e8fc62c086651d29abb2c5a3d9921be97
gasman added a commit to gasman/wagtail that referenced this issue Oct 4, 2023
As per python/cpython#100690 , these assertions were a no-op and Python 3.12 guards against this.
gasman added a commit to wagtail/wagtail that referenced this issue Oct 5, 2023
As per python/cpython#100690 , these assertions were a no-op and Python 3.12 guards against this.
zaro0508 pushed a commit to Sceptre/sceptre that referenced this issue Dec 3, 2023
Adds explicit support for Python 3.12. These are the minimal changes I needed for `pytest` to pass on 3.12 and macOS:

* Replaces deprecated [`datetime.datetime.utcnow`](https://docs.python.org/3/library/datetime.html#datetime.datetime.utcnow)
* Replaces `called_once_with` with `assert_called_once_with`, which now [raises](python/cpython#100690) `AttributeError: 'called_once_with' is not a valid assertion`
* Bumps `pytest` due to `DeprecationWarning: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead` pytest-dev/pytest#10977
* Refreshes the lockfile

depends on #1393
QSchulz added a commit to QSchulz/recitale that referenced this issue Dec 30, 2023
Python v3.12 and later raise an exception for this line with the
following message:
"""
AttributeError: 'called_once_with' is not a valid assertion. Use a spec for the mock if 'called_once_with' is meant to be an attribute.. Did you mean: 'assert_called_once_with'?
"""

A bit of research returned commit 1d4d677d1c90 ("gh-100690: Raise an
AttributeError when the assert_ prefix is forgotten when using Mock
(#100691)") from CPython git history, which in turns points at
python/cpython#100690.

This GitHub issue mentions that called_once_with returns a Mock object
instead of doing a proper assertion. This test is basically a no-op.

Therefore, let's fix the test by doing a proper assertion.

Fixes: 94d64c8 ("test: image: improve code coverage by testing BaseImage")
Signed-off-by: Quentin Schulz <foss+recitale@0leil.net>
QSchulz added a commit to recitale/recitale that referenced this issue Dec 30, 2023
Python v3.12 and later raise an exception for this line with the
following message:
"""
AttributeError: 'called_once_with' is not a valid assertion. Use a spec for the mock if 'called_once_with' is meant to be an attribute.. Did you mean: 'assert_called_once_with'?
"""

A bit of research returned commit 1d4d677d1c90 ("gh-100690: Raise an
AttributeError when the assert_ prefix is forgotten when using Mock
(#100691)") from CPython git history, which in turns points at
python/cpython#100690.

This GitHub issue mentions that called_once_with returns a Mock object
instead of doing a proper assertion. This test is basically a no-op.

Therefore, let's fix the test by doing a proper assertion.

Fixes: 94d64c8 ("test: image: improve code coverage by testing BaseImage")
Signed-off-by: Quentin Schulz <foss+recitale@0leil.net>
clenk added a commit to mitre/caldera that referenced this issue Feb 8, 2024
Silvanoc added a commit to linkml/linkml that referenced this issue Feb 17, 2024
Prevent prefix "called_" for methods on mock objects in safe mode.

See python/cpython#100690

Signed-off-by: Silvano Cirujano Cuesta <silvano.cirujano-cuesta@siemens.com>
Silvanoc added a commit to linkml/linkml that referenced this issue Mar 6, 2024
Prevent prefix "called_" for methods on mock objects in safe mode.

See python/cpython#100690

Signed-off-by: Silvano Cirujano Cuesta <silvano.cirujano-cuesta@siemens.com>
Silvanoc added a commit to linkml/linkml that referenced this issue Mar 21, 2024
Prevent prefix "called_" for methods on mock objects in safe mode.

See python/cpython#100690

Signed-off-by: Silvano Cirujano Cuesta <silvano.cirujano-cuesta@siemens.com>
MVrachev added a commit to MVrachev/repository-service-tuf-cli that referenced this issue May 16, 2024
Subprocesses have changed where exception messages are stored.
From stdout exception messages are moved to stderr and we need to adapt.

Additionally, we use `called_once`` for one test for a mock where we
need to migrate to `assert_called_once_with` as for python 12
called_once is gone: python/cpython#100690

Signed-off-by: Martin Vrachev <martin.vrachev@broadcom.com>
kairoaraujo pushed a commit to repository-service-tuf/repository-service-tuf-cli that referenced this issue May 16, 2024
* Fix unit tests caused by internal python changes

Subprocesses have changed where exception messages are stored.
From stdout exception messages are moved to stderr and we need to adapt.

Additionally, we use `called_once`` for one test for a mock where we
need to migrate to `assert_called_once_with` as for python 12
called_once is gone: python/cpython#100690

Signed-off-by: Martin Vrachev <martin.vrachev@broadcom.com>

* Fix "ValueError: stderr not separately captured"

This error is given by subprocess when we want to access the stderr
of the test_result object returned from click.invoke.
This is fixed by using "mix_stderr" on CliRunner level.

https://click.palletsprojects.com/en/latest/api/#testing

Signed-off-by: Martin Vrachev <martin.vrachev@broadcom.com>

---------

Signed-off-by: Martin Vrachev <martin.vrachev@broadcom.com>
joeyorlando added a commit to grafana/oncall that referenced this issue Jun 10, 2024
# What this PR does

- bumps `uwsgi` to latest version (`2.0.26`), which unblocks us from
bumping Python to 3.12
- bumps Python to 3.12.3
- refactor the Snyk GitHub Actions workflow to use the composable
actions for installed frontend and backend dependencies
- fixes several `AttributeError`s in our tests that went from a warning
to an error in Python 3.12 (see
python/cpython#100690)

# Which issue(s) this PR closes

Closes #4358
Closes #4387
NicolasT added a commit to NicolasT/gptsum that referenced this issue Jun 17, 2024
`called_with` was likely not the right call to make, since this
would return a mock instance. Instead, use `assert_called_with`.

See: python/cpython#100690
openstack-mirroring pushed a commit to openstack/charm-neutron-openvswitch that referenced this issue Sep 24, 2024
Python 3.12 has removed long-deprecated unittest features [1],
therefore some of the existing unit test fail when run on Python
3.12. This patch replaces the 'assertEquals' with 'assertTrue' or
'assertFalse', depending on the usage.

This patch also fixes the 'test_amqp_changed' and 'test_amqp_departed'
test methods which improperly called 'called_with' which is no longer
a valid assertion method [2]. And in fact on Python < 3.12 the
'test_amqp_changed' and 'test_amqp_departed' pass their assertions,
when they actually should fail due to the out-of-sync with
'amqp-relation-changed' and 'amqp-relation-departed' hook code.
In this case the 'called_with' is replaced with 'assert_called_once'.

[1] https://docs.python.org/3.12/whatsnew/3.12.html#id3
[2] python/cpython#100690

Change-Id: I90b400f6bafe8f03f04f991d9fe58635d19b8b2e
Signed-off-by: Marcin Wilk <marcin.wilk@canonical.com>
openstack-mirroring pushed a commit to openstack/openstack that referenced this issue Sep 24, 2024
* Update charm-neutron-openvswitch from branch 'master'
  to 63465640fef8d545e8038f1960c17da0201bc03d
  - Fix Python 3.12 unittest compatibility
    
    Python 3.12 has removed long-deprecated unittest features [1],
    therefore some of the existing unit test fail when run on Python
    3.12. This patch replaces the 'assertEquals' with 'assertTrue' or
    'assertFalse', depending on the usage.
    
    This patch also fixes the 'test_amqp_changed' and 'test_amqp_departed'
    test methods which improperly called 'called_with' which is no longer
    a valid assertion method [2]. And in fact on Python < 3.12 the
    'test_amqp_changed' and 'test_amqp_departed' pass their assertions,
    when they actually should fail due to the out-of-sync with
    'amqp-relation-changed' and 'amqp-relation-departed' hook code.
    In this case the 'called_with' is replaced with 'assert_called_once'.
    
    [1] https://docs.python.org/3.12/whatsnew/3.12.html#id3
    [2] python/cpython#100690
    
    Change-Id: I90b400f6bafe8f03f04f991d9fe58635d19b8b2e
    Signed-off-by: Marcin Wilk <marcin.wilk@canonical.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

5 participants