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

Add deprecations for tests written for nose #9907

Merged
merged 11 commits into from Oct 9, 2022

Conversation

symonk
Copy link
Member

@symonk symonk commented May 1, 2022

Adds deprecation warnings for tests written in nose, namely around setup and teardown aspects; as we support limited functionality.

I went with a pytest 8.x deprecation as I think that is the norm here. I also notice a few things when reviewing docs locally:

my version was showing 6.3.x-dev* was my fault;
tox -e docs does not work in python 3.10+ due to an upstream issue in sphinx/util/typing.py we may need a version bump there? I will chase that up in a second

closes #9886

Todo:

  • Implement a solution for call_optional(...)
  • Investigate the mention of @with_setup etc.

@symonk symonk requested a review from nicoddemus May 1, 2022 15:29
doc/en/deprecations.rst Outdated Show resolved Hide resolved
@@ -38,5 +41,6 @@ def call_optional(obj: object, name: str) -> bool:
return False
# If there are any problems allow the exception to raise rather than
# silently ignoring it.
warnings.warn(NOSE_SUPPORT, stacklevel=2)
Copy link
Member Author

Choose a reason for hiding this comment

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

not sure if we can unwind this into a user-space to be more helpful

Copy link
Member

Choose a reason for hiding this comment

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

Indeed, but I think we should at least display the method name (and module), as well as the test that triggered this, if possible.

Copy link
Member Author

@symonk symonk Aug 7, 2022

Choose a reason for hiding this comment

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

any preferred way to handle this one @nicoddemus; we have the item in scope when called, could just pass the nodeid into a formattable warning? however some unit tests don't pass that obviously; I'm not sure how many edge cases there can be for this nose stuff; I've everything else fixed up I think but as-is its something like:

def call_optional(obj: object, name: str, nodeid: str) -> bool:
    method = getattr(obj, name, None)
    if method is None:
        return False
    is_fixture = getfixturemarker(method) is not None
    if is_fixture:
        return False
    if not callable(method):
        return False
    # If there are any problems allow the exception to raise rather than
    # silently ignoring it.
    warnings.warn(NOSE_SUPPORT.format(nodeid=nodeid, nose_method=name), stacklevel=2)
    method()
    return True

which I don't really like; ok to use inspect here to derive some of that info? or perhaps __qualname__ / __module__ would suffice on the existing function obj passed?

Will push what I have for now as I'm out of time today; not happy with it tho so i'm hoping to change the call_optional here still based on your feedback. Please have a look at see what you think the cleanest way to handle that is; will update when I get back, thanks 👍 (I'm expecting some unit test failures now, on the call_optional(...) specifics.

Copy link
Member

@nicoddemus nicoddemus left a comment

Choose a reason for hiding this comment

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

Thanks @symonk!

Left a few suggestions, please take a look. 👍

doc/en/deprecations.rst Outdated Show resolved Hide resolved
doc/en/how-to/nose.rst Outdated Show resolved Hide resolved
@@ -38,5 +41,6 @@ def call_optional(obj: object, name: str) -> bool:
return False
# If there are any problems allow the exception to raise rather than
# silently ignoring it.
warnings.warn(NOSE_SUPPORT, stacklevel=2)
Copy link
Member

Choose a reason for hiding this comment

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

Indeed, but I think we should at least display the method name (and module), as well as the test that triggered this, if possible.

@The-Compiler
Copy link
Member

Does this only affect @with_setup, or also undecorated plain setup and teardown methods on test classes? The latter is technically part of our nose support, but as far as I'm aware, there are many projects using them with pytest-style tests without being aware that they are supposed to be nose specific...

@nicoddemus
Copy link
Member

there are many projects using them with pytest-style tests without being aware that they are supposed to be nose specific...

Good point. In that case they will get a warning, and we should mention in the deprecation docs how to port it to use something pytest-native.

@nicoddemus nicoddemus added this to the 7.2 milestone Jun 14, 2022
@nicoddemus
Copy link
Member

Moved to 7.2 milestone. 👍

@symonk
Copy link
Member Author

symonk commented Jun 20, 2022

Sorry folks, I will get this one wrapped up shortly

@nicoddemus
Copy link
Member

@symonk gentle ping. 😁

@symonk
Copy link
Member Author

symonk commented Aug 7, 2022

@symonk gentle ping. grin

will get a look, thanks!

@hwaking

This comment was marked as spam.

Copy link
Member

@nicoddemus nicoddemus left a comment

Choose a reason for hiding this comment

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

Thanks @symonk!

Went ahead and fixed the tests and added information on how to port code in the deprecation docs. 👍

@nicoddemus
Copy link
Member

@The-Compiler would appreciate a review if possible. 👍

@nicoddemus nicoddemus changed the title Add deprecations for tests written for nose Add deprecations for tests written for nose [SQUASH] Sep 15, 2022
Copy link
Member

@The-Compiler The-Compiler left a comment

Choose a reason for hiding this comment

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

Seems fine implementation-wise other than a few doc nitpicks (feel free to ignore if you disagree), and perhaps a missing test.

I'm still somewhat lukewarm about dropping bare setup and teardown methods... Unfortunately, I see no easy way to find out how much usage of those there is, as searching for it will of course also pick up fixtures (only limited to repos containing conftest.py to try and avoid unittest.py testsuites).

Maybe we'll just need to do it and see how many people complain...

edit: The more I look at it, the more I seem to see genuine cases of this being used in numpy, celery, ceph, and similar high-profile projects...

doc/en/deprecations.rst Outdated Show resolved Hide resolved
doc/en/deprecations.rst Outdated Show resolved Hide resolved
@@ -231,3 +231,31 @@ def test_importing_instance_is_deprecated(pytester: Pytester) -> None:
match=re.escape("The pytest.Instance collector type is deprecated"),
):
from _pytest.python import Instance # noqa: F401


def test_nose_deprecated(pytester: Pytester) -> None:
Copy link
Member

Choose a reason for hiding this comment

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

Should also have a test using bare setup and teardown methods?

Copy link
Member

Choose a reason for hiding this comment

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

Glad you asked this, it was not emitting a warning for setup and teardown 😬

@nicoddemus
Copy link
Member

nicoddemus commented Sep 15, 2022

edit: The more I look at it, the more I seem to see genuine cases of this being used in numpy, celery, ceph, and similar high-profile projects...

I see, thanks for looking into it.

I strongly believe we should deprecate nose, but given that people have been using setup and teardown for methods thinking this was part of the pytest core feature set, we have a few options:

  1. Go ahead with the deprecation: to be fair it is a simple find/replace, and is backward-compatible with very old pytest versions (ancient versions even).
  2. Make support for setup and teardown methods pytest native, outside nose.

Implementing 2) should be trivial, we already support setup_method and teardown_method named-methods, so it should be just a matter of extending that to setup and teardown names.

@Exirel
Copy link

Exirel commented Sep 15, 2022

Implementing 2) should be trivial, we already support setup_method and teardown_method named-methods, so it should be just a matter of extending that to setup and teardown names.

Hi! Sopel dev here, and here is our story. For the next major release of our IRC Bot, we try to support Python 3.10 and the latest version of pytest. When working on that, we discovered an issue with our test suite: for some unknown reason at the time, pytest would suddenly think that our setup function was now a test hook function. That was very unfortunate for a moment.

We were very happy when we understood the problem, and the solution: we deactivated the nose plugin, and all our problems went away.

So, from our perspective, we are fine with the following options:

  • remove the nose plugin from pytest
  • keep the plugin, but make sure we can deactivate it
  • officially support setup/teardown function, but making sure it is configurable (opt-out, opt-in, regex pattern, etc.)

Basically: we really need to make sure we can still run pytest without having to change our codebase, or our user's codebase, to accommodate for something that was not, as far as I know, officially documented (at least until now).

@nicoddemus
Copy link
Member

officially support setup/teardown function, but making sure it is configurable (opt-out, opt-in, regex pattern, etc.)

Just to make it clear, my proposal is to support setup/teardown methods, not functions. IIUC that would not affect your test suite, right?

@Exirel
Copy link

Exirel commented Sep 16, 2022

to support setup/teardown methods, not functions.

Oh! You're right, I was worried about functions, not methods. In that case, and since pytest has a configuration for class naming convention, we would not have any problem with that. Thanks for the clarification. 👍

@nicoddemus
Copy link
Member

nicoddemus commented Sep 16, 2022

Thanks @Exirel for the feedback! 👍

I updated my original post to make it clearer too.

@nicoddemus
Copy link
Member

@The-Compiler what do you think regarding #9907 (comment)?

I'm leaning towards 1), mostly because we are showing a deprecation, and the fix is trivial by doing a simple find/replace.

@nicoddemus
Copy link
Member

nicoddemus commented Oct 9, 2022

The warning message now includes the text To remove this warning, rename it to '{method}_method(self) for plain setup/teardown methods.

@The-Compiler
Copy link
Member

@The-Compiler what do you think regarding #9907 (comment)?

I'm leaning towards 1), mostly because we are showing a deprecation, and the fix is trivial by doing a simple find/replace.

Seems fine to me, though I see one problem: Once the deprecation period is over, it turns into a silent failure, depending on what the user does in those methods.

@nicoddemus
Copy link
Member

Seems fine to me, though I see one problem: Once the deprecation period is over, it turns into a silent failure, depending on what the user does in those methods.

Yeah I agree it is not perfect, unfortunately.

We should make a point to add a big note to the release notes when we drop the functionality, I think is the best we can do.

@nicoddemus
Copy link
Member

Btw @The-Compiler could you give this another pass over? Thanks!

Copy link
Member

@The-Compiler The-Compiler left a comment

Choose a reason for hiding this comment

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

Looks great! Just a few small doc comments. Don't feel strongly about them, except the changelog one.

.gitignore Outdated Show resolved Hide resolved
@@ -0,0 +1 @@
The functionality for running tests written for ``nose`` has been officially deprecated.
Copy link
Member

Choose a reason for hiding this comment

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

This should be a bit more verbose: It should point out that this also includes setup and teardown methods (since users don't seem to be aware of that being a nose thing), and it should have a link to the detailed deprecation docs.

Copy link
Member

Choose a reason for hiding this comment

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

Indeed, done. 👍

doc/en/deprecations.rst Outdated Show resolved Hide resolved
@nicoddemus nicoddemus changed the title Add deprecations for tests written for nose [SQUASH] Add deprecations for tests written for nose Oct 9, 2022
@nicoddemus nicoddemus merged commit 3bf2bc5 into pytest-dev:main Oct 9, 2022
@nicoddemus
Copy link
Member

Thanks @symonk and @The-Compiler!

Sign up for free to 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.

Deprecate and remove nose plugin
5 participants