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

[py] added decorator for handling deprecations. #12432

Closed

Conversation

sandeepsuryaprasad
Copy link
Contributor

@sandeepsuryaprasad sandeepsuryaprasad commented Jul 27, 2023

Thanks for contributing to Selenium!
A PR well described will help maintainers to quickly review and merge it

Before submitting your PR, please check our contributing guidelines.
Avoid large PRs, help reviewers by making them as simple and short as possible.

Description

The motivation for this PR is #12409
In this PR, I have created a decorator to handle deprecations in a much better and maintainable way.

Motivation and Context

  • I have created two decorators deprecated_function and deprecated_attributes in selenium/deprecated.py
  • Any deprecated function would be decorated with deprecated_function decorator which takes care of logging warning message and from what version of selenium the function would be deprecated.
  • Any deprecated instance variable would be decorated with deprecated_attributes decorator, which takes care of logging appropriate warning message for corresponding deprecated variable.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • I have read the contributing document.
  • [] My change requires a change to the documentation.
  • [] I have updated the documentation accordingly.
  • [] I have added tests to cover my changes.
  • All new and existing tests passed.

@titusfortner
Copy link
Member

This is a cool idea, but I'm not sure the advantage of this over a more straightforward method? Does it show up differently in the IDE with this annotation? Does the wrapper know the name of the function so we don't have to put it in the string?

py/selenium/deprecated.py Outdated Show resolved Hide resolved
for attr in attrs:
_attr = getattr(args[0], attr, None)
if _attr:
warn(f"'{message}': will be removed from {removed_from_version}", DeprecationWarning, 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.

does stacklevel=2 play nice with a decorator (especially one with args?) in terms of the stack in the output? would need to double check

py/selenium/deprecated.py Outdated Show resolved Hide resolved
@symonk
Copy link
Member

symonk commented Jul 27, 2023

this stuff is quite trick with edge cases, for example a @staticmethod wouldn't have an instance to pass as args[0] if we ever needed to decorate it, is it simpler if we define a function and call that in places we are currently deprecating things? ie.

from selenium.deprecations import deprecated

deprecated(message=..., version=4.12")  

Theres possibly alot of edge cases with the decorator approach.
Either way, i'll close my draft PR since we can colloborate as part of this work here.

@codecov-commenter
Copy link

Codecov Report

Patch coverage: 46.00% and project coverage change: -0.76% ⚠️

Comparison is base (60a054b) 57.40% compared to head (433d398) 56.65%.
Report is 5 commits behind head on trunk.

❗ Current head 433d398 differs from pull request most recent head 630a135. Consider uploading reports for the commit 630a135 to get more accurate results

❗ Your organization is not using the GitHub App Integration. As a result you may experience degraded service beginning May 15th. Please install the Github App Integration for your organization. Read more.

Additional details and impacted files
@@            Coverage Diff             @@
##            trunk   #12432      +/-   ##
==========================================
- Coverage   57.40%   56.65%   -0.76%     
==========================================
  Files          86       87       +1     
  Lines        5369     5368       -1     
  Branches      206      207       +1     
==========================================
- Hits         3082     3041      -41     
- Misses       2081     2120      +39     
- Partials      206      207       +1     
Files Changed Coverage Δ
py/selenium/deprecated.py 30.00% <30.00%> (ø)
py/selenium/webdriver/edge/service.py 84.00% <33.33%> (-5.29%) ⬇️
py/selenium/webdriver/safari/webdriver.py 36.53% <33.33%> (-11.68%) ⬇️
py/selenium/webdriver/firefox/firefox_profile.py 19.32% <50.00%> (+0.48%) ⬆️
py/selenium/webdriver/ie/service.py 86.20% <50.00%> (-3.45%) ⬇️
py/selenium/webdriver/remote/webdriver.py 40.04% <50.00%> (-0.10%) ⬇️
py/selenium/webdriver/safari/service.py 76.66% <50.00%> (-3.98%) ⬇️
py/selenium/webdriver/chromium/service.py 87.09% <66.66%> (-3.53%) ⬇️
py/selenium/webdriver/firefox/options.py 64.19% <66.66%> (-7.72%) ⬇️
py/selenium/webdriver/firefox/service.py 88.88% <66.66%> (-2.54%) ⬇️
... and 1 more

... and 3 files with indirect coverage changes

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

@sandeepsuryaprasad
Copy link
Contributor Author

This is a cool idea, but I'm not sure the advantage of this over a more straightforward method? Does it show up differently in the IDE with this annotation? Does the wrapper know the name of the function so we don't have to put it in the string?

Yes wrappers know the name of the function. func.__name__ will give the name of the function which we have decorated.

@sandeepsuryaprasad
Copy link
Contributor Author

sandeepsuryaprasad commented Jul 28, 2023

this stuff is quite trick with edge cases, for example a @staticmethod wouldn't have an instance to pass as args[0] if we ever needed to decorate it, is it simpler if we define a function and call that in places we are currently deprecating things? ie.

from selenium.deprecations import deprecated

deprecated(message=..., version=4.12")  

Theres possibly alot of edge cases with the decorator approach. Either way, i'll close my draft PR since we can colloborate as part of this work here.

I have checked for static and class methods, deprecated_function decorator works fine in both cases. But if we want to make a function instead of decorator, that is also perfectly fine..

@sandeepsuryaprasad
Copy link
Contributor Author

Getting ModuleNotFound error while trying to import the decorator from deprecated.py module. This is the file that is newly added to selenium folder.

@sandeepsuryaprasad
Copy link
Contributor Author

sandeepsuryaprasad commented Jul 28, 2023

Actually we don't have to write custom decorator. In typing_extensions module we do have deprecated decorator.
and in python 3.12 (yet to be released) there is a PEP to include this in typing module
https://peps.python.org/pep-0702/#example

@symonk symonk added the C-py label Jul 29, 2023
@titusfortner
Copy link
Member

aha, this is the PR I was looking for last week and couldn't find when I raised #13402

I think we decided we want to use the annotation that is in typing_extensions instead of this.

@sandeepsuryaprasad sandeepsuryaprasad deleted the deprecation branch November 24, 2024 04:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants