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

Introduce @deprecated decorators for functions and enforce warnings as errors in tests #4757

Open
wants to merge 26 commits into
base: develop
Choose a base branch
from

Conversation

RohitP2005
Copy link
Contributor

@RohitP2005 RohitP2005 commented Jan 14, 2025

Description

This pull request has implemented deprecation decorators as wrapper for a function's arguement and the fucntion itself and has added -W flag to ensure the deprecation warnings are treated as error

Related to: #2028

Type of change

  • New feature (non-breaking change that adds functionality)
  • Optimization (back-end change that speeds up the code)
  • Bug fix (non-breaking change which fixes an issue)
  • Deprecation (non-breaking change that deprecates functionality with warnings)

Key checklist:

  • No style issues: $ pre-commit run --all-files (or $ nox -s pre-commit) (see CONTRIBUTING.md for how to set this up to run automatically when committing locally)
  • All tests pass: $ python -m pytest -W error (or $ nox -s tests) (ensure warnings are treated as errors to catch deprecation notices)
  • The documentation builds: $ python -m pytest --doctest-plus src (or $ nox -s doctests)

You can run integration tests, unit tests, and doctests together at once using $ nox -s quick.

Further checks:

  • Code is commented, particularly in hard-to-understand areas, including deprecation warnings and helper functions.
  • Tests added for any new functionality or to prove that the deprecation warnings are effective.
  • Confirm that any borrowed code from Astropy is appropriately attributed according to its license.

@RohitP2005
Copy link
Contributor Author

Previous Discussions : #4745 (comment)

Copy link
Contributor

@kratman kratman left a comment

Choose a reason for hiding this comment

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

I think one of the main reasons for doing this is to track the date of the deprecation warnings. This does not seem to be in these changes.

Realistically the warnings work as-is, but we want to automate the removal of them. Right now I use git-blame to remove old warnings every 6 months or so. The extra decorators and such are just additional overhead unless we use it for something better than the current warnings

@kratman
Copy link
Contributor

kratman commented Jan 14, 2025

Original issue request: "Replace existing deprecation warnings/errors with deprecation package so tests fail after a few releases."

@RohitP2005
Copy link
Contributor Author

RohitP2005 commented Jan 14, 2025

Okay , I misunderstood that the deprecation package was not required and we needed a pythonic way.
Now i understand @kratman , Thankyou for the clarification .

I will just go ahead with the deprecation package with my next commit

Apologies for the confusion

@RohitP2005
Copy link
Contributor Author

@kratman, I've implemented the deprecation package for four of the existing deprecation warnings. Could you please guide me on any potential improvements?

Regarding renamed and deprecated arguments, it seems the deprecation package doesn't natively handle these cases. Do you have any suggestions on how to approach this? I considered writing custom decorators to manage them. Does that sound like a good plan?

Copy link

codecov bot commented Jan 16, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.71%. Comparing base (0d5af5c) to head (808d5cd).

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #4757   +/-   ##
========================================
  Coverage    98.70%   98.71%           
========================================
  Files          304      304           
  Lines        23432    23452   +20     
========================================
+ Hits         23129    23151   +22     
+ Misses         303      301    -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@kratman
Copy link
Contributor

kratman commented Jan 17, 2025

Does the package you use allow for tests to fail when the deprecation is old?

@RohitP2005
Copy link
Contributor Author

Does the package you use allow for tests to fail when the deprecation is old?

No, the deprecation package does not natively support automatically failing tests when a deprecation is old

Copy link
Member

@agriyakhetarpal agriyakhetarpal left a comment

Choose a reason for hiding this comment

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

I think I agree with the general idea here, and the @deprecated decorator looks neat. If there's no way to make the deprecated functions fail directly, that's fine – we should proceed with your suggestion in the PR description:

has added -W flag to ensure the deprecation warnings are treated as an error

I don't see this change here, but yes, please feel free to configure pytest with this, as the deprecation warnings would then be caught in the tests if they use it. Then, you can fix any pending deprecation warnings unrelated to your changes that show up in the test suite. If there are a bunch of them and they are not straightforward to fix, it is also okay to filter them using the filterwarnings configuration option and open a new issue about removing them to work on later.

See also: https://docs.pytest.org/en/stable/how-to/capture-warnings.html#controlling-warnings

Regarding deprecating a specific argument in a function, yes, adding a custom decorator for this sounds great. If you think it will require a bit of experimentation, I'm happy to help review it in a follow-up PR (you may edit the PR description to mark this PR as related to #2028, but not fixing it). Limiting the scope of this PR sounds good to me to get it in.

Thanks!

@RohitP2005 RohitP2005 marked this pull request as ready for review February 13, 2025 13:53
Copy link
Member

@agriyakhetarpal agriyakhetarpal left a comment

Choose a reason for hiding this comment

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

Thanks, @RohitP2005! Could you please edit the PR title to make it more specific? As discussed, the follow-up task would be to address #4757 (review). I have a few more changes to suggest. We should also replace any other existing deprecation warnings with the decorators you added.

pyproject.toml Outdated
Comment on lines 233 to 235
# convert internal warnings as errors
"error::DeprecationWarning:pybamm.*",
#ignore external DeprecationWarning
Copy link
Contributor

Choose a reason for hiding this comment

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

Have you confirmed that it works in this order? Since you say that they are errors, then right below ignore all deprecation warnings

Copy link
Member

Choose a reason for hiding this comment

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

Yes, it would be good to double-check this. Usually, the right order is to make PyBaMM-specific warnings errors, and then ignore any other warnings (such as UserWarnings that are expected). But at the same time, all warnings should start as errors.

Copy link
Contributor Author

@RohitP2005 RohitP2005 Feb 14, 2025

Choose a reason for hiding this comment

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

@kratman
I suggeest we should order them in following way

filterwarnings = [
    "error",

    # ignore external DeprecationWarning
    "ignore::DeprecationWarning",

    # convert internal warnings as errors
    "error::DeprecationWarning:pybamm.*",

    # ignore internal nbmake warnings
    'ignore:unclosed \<socket.socket:ResourceWarning',
    'ignore:unclosed event loop \<:ResourceWarning',
    "ignore::UserWarning",
    "ignore::RuntimeWarning",
]

  1. "error": Treat all warnings as errors by default.
  2. "ignore::DeprecationWarning": Ignore all DeprecationWarnings unless specified below.
  3. Ignoring internal nbmake warnings: Ignore specific ResourceWarnings related to unclosed sockets and event loops.
  4. "error::DeprecationWarning:pybamm.*": Treat PyBaMM-specific DeprecationWarnings as errors.
  5. Ignoring other warnings: Ignore UserWarning and RuntimeWarning, which are expected but not critical.

This order ensures all warnings are caught as errors, while selectively ignoring or treating warnings related to PyBaMM and internal processes.

Copy link
Member

Choose a reason for hiding this comment

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

On second thought, one thing here is that we should also ensure that we aren't completely ignoring DeprecationWarnings added by projects. For example, we wouldn't want to use deprecated APIs by other libraries on which we depend. Doing so will make us vulnerable to things breaking, as we haven't pinned those libraries – that is, when they cut a new release wherein those deprecated APIs are removed, functionality from older PyBaMM versions won't be usable later in time, because we would not have seen those deprecation warnings in our tests and the newer versions of those dependencies would be fetched (unless we make an active effort to bump our minimum bounds for our dependencies to cap resolution for older PyBaMM versions, which we should).

So, having rethought this, my suggestion is to stick to https://learn.scientific-python.org/development/guides/pytest/#configuring-pytest as much as possible, ignore external DeprecationWarnings that cannot be fixed, and fix any other DeprecationWarnings (or ignore them and leave them as TODOs if they are hard to fix).

@RohitP2005 RohitP2005 changed the title Deprecation decorators for functions Introduce @deprecated decorators for functions and enforce warnings as errors in tests Feb 14, 2025
Copy link
Member

@agriyakhetarpal agriyakhetarpal left a comment

Choose a reason for hiding this comment

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

Thanks, @RohitP2005! Could you please resolve the conflicts here? It looks close to merging with not many more changes required.

pyproject.toml Outdated
Comment on lines 233 to 235
# convert internal warnings as errors
"error::DeprecationWarning:pybamm.*",
#ignore external DeprecationWarning
Copy link
Member

Choose a reason for hiding this comment

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

On second thought, one thing here is that we should also ensure that we aren't completely ignoring DeprecationWarnings added by projects. For example, we wouldn't want to use deprecated APIs by other libraries on which we depend. Doing so will make us vulnerable to things breaking, as we haven't pinned those libraries – that is, when they cut a new release wherein those deprecated APIs are removed, functionality from older PyBaMM versions won't be usable later in time, because we would not have seen those deprecation warnings in our tests and the newer versions of those dependencies would be fetched (unless we make an active effort to bump our minimum bounds for our dependencies to cap resolution for older PyBaMM versions, which we should).

So, having rethought this, my suggestion is to stick to https://learn.scientific-python.org/development/guides/pytest/#configuring-pytest as much as possible, ignore external DeprecationWarnings that cannot be fixed, and fix any other DeprecationWarnings (or ignore them and leave them as TODOs if they are hard to fix).

Comment on lines 1 to 5
import functools
import warnings


def deprecate_arguments(deprecated_args, deprecated_in, removed_in, current_version):
Copy link
Member

Choose a reason for hiding this comment

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

Let's add type hints here while we can:

Suggested change
import functools
import warnings
def deprecate_arguments(deprecated_args, deprecated_in, removed_in, current_version):
from __future__ import annotations
import functools
import warnings
def deprecate_arguments(deprecated_args: dict[str], deprecated_in: str, removed_in: str, current_version: str):

Copy link
Member

@agriyakhetarpal agriyakhetarpal left a comment

Choose a reason for hiding this comment

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

Thanks, @RohitP2005! Could you please resolve the conflicts here? It looks close to merging with not many more changes required.

agriyakhetarpal

This comment was marked as duplicate.

@RohitP2005
Copy link
Contributor Author

Thanks, @RohitP2005! Could you please resolve the conflicts here? It looks close to merging with not many more changes required.

Okay @agriyakhetarpal will address all those changes in next commit as requested.

@@ -216,6 +217,8 @@ required_plugins = [
addopts = [
"-nauto",
"-vra",
"-ra",
"--showlocals",
Copy link
Member

Choose a reason for hiding this comment

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

I'm curious: is there a reason you think we should opt for this option? Do you feel that our tracebacks are limited?

Comment on lines 421 to 430
@deprecate_arguments(
deprecated_args={
"electrode diffusivity": "Use 'particle diffusivity' instead.",
"1 + dlnf/dlnc": "Use 'Thermodynamic factor' instead.",
},
deprecated_in="24.1.0",
removed_in="25.3.0",
current_version="25.1.0",
msg="Update your parameter names to avoid future compatibility issues.",
)
Copy link
Member

Choose a reason for hiding this comment

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

Could we have multiple messages per argument? The current message here is not informative enough, and is rather a step back in comparison to the messages that currently exist already. That is, it would be nice if @deprecate_arguments() could take a dictionary, i.e., accept a key-value pair for an argument and its corresponding deprecation message. The current approach you've taken doesn't seem to accommodate this behaviour.

@agriyakhetarpal
Copy link
Member

I've reviewed the changes again. Sorry if you were adding any other changes during my review!

@RohitP2005
Copy link
Contributor Author

Hey @kratman could u trigger the CIs for this one
@agriyakhetarpal I think this PR is good to go now.

@RohitP2005
Copy link
Contributor Author

RohitP2005 commented Feb 22, 2025

@arjxn-py Thanks for initiating the CI's
Can anyone help me with the pkg_resources is deprecated as an API
I tried silencing it and still it pops up
Any possible fix for this

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.

5 participants