briancurtin / deprecation Goto Github PK
View Code? Open in Web Editor NEWA library to handle automated deprecations
License: Apache License 2.0
A library to handle automated deprecations
License: Apache License 2.0
http://deprecation.readthedocs.io/en/latest/sample.html ends up blank for some reason.
While joining the function.__doc__
-string with the deprecation_note
-string the indentation isn't handled properly. Let's look at this example:
@deprecated(deprecated_in="0.0.3", removed_in="0.1.0",
current_version="0.0.4",
details="Do not use this function any more.")
def testfunc():
"""Test function.
Returns
-------
name : str
Some string
"""
return "Teststring"
def newfunc():
"""Test function.
Returns
-------
name : str
Some string
"""
return "Teststring"
Output of help(testfunc)
(broken):
testfunc()
Test function.
Returns
-------
name : str
Some string
*Deprecated in 0.0.3, to be removed in 0.1.0. Do not use this function any more.*
Output of help(newfunc)
(correct):
newfunc()
Test function.
Returns
-------
name : str
Some string
The indentation of the function (numpy-style) docstring has been broken by the addition of the deprecation_note
. While this might seem like a minor cosmetic issue, this breaks proper docstring processing in eg. sphinx
.
The sdist package at PyPI is missing tox.ini
. Please add the missing tox.ini
file to sdist to make downstream testing easier. Please note that the test-requirements.txt
file (needed by tox.ini
) is missing from sdist too.
Thank you.
It would be nice if static type checkers like mypy could pick up the types of this package (cfr. https://mypy.readthedocs.io/en/stable/installed_packages.html#creating-pep-561-compatible-packages)
This looks quite interesting; however, it'd be highly beneficial to be able to optionally specify what is replacing the call.
import deprecation
@deprecation.deprecated(deprecated_in="1.0", removed_in="2.0",
current_version=__version__,
details="Reasoning for change", replaced_by=bar)
def foo():
"""Do some stuff"""
return bar()
def bar():
"""Do some stuff using new API"""
return 1
details
could probably be used more for reasoning behind the change while replaced_by
could be used to explicitly note the new method if it was provided.
NOTE: replaced_by
could either be an object or a string. If an object then the string could be formed via '.'.join([replaced_by.__module__, replaced_by.__name__])
.
Output text related to replaced_by
should simply be:
Please update usage of "foo" to "bar".
Reasoning: By calling out explicitly this way some uniformity is provided in the messaging to users.
Yes, this could be achieved by details
but then the calling project would have to implement a standard on how to write out details
in a way that clearly communicates the change to the user. By reserving details
for more detailed reasoning (ex: foo had a security issue and needed to go away because X
) and taking in replaced_by
type argument the updated API can be consistently and reliably communicated.
NOTE: This might be one aspect of #17, but it probably stands on its own since (a) it could be achieved without #17 and (b) #17 would only enhance the capability.
DeprecatedWarning.__str__
doesn't play nicely with None
values, such as what happens when you call deprecation.deprecated()
with no arguments. This ends up showing up in the interpreter messages when run with python -Wd
, though it doesn't affect docstrings.
/.../deprecation.py:183: DeprecatedWarning: fn is deprecated as of None and will be removed in None.
warnings.warn(the_warning)
This just doesn’t make sense. Two tiny packages which do the same, both of them have to be packaged for all Linux/other distributions, all of them checked for security or whatever-else issues. Could you please guys join the effort?
Thank you.
Decorating a test with fail_if_not_removed
when the test expects a pytest fixture causes a TypeError
due to a missing argument.
For example:
@deprecation.fail_if_not_removed
def test_get_pt_bounds(peak):
peak.get_pt_bounds()
Results in:
../../../../.local/lib/python3.6/site-packages/deprecation.py:264 (test_get_pt_bounds)
args = (), kwargs = {}, caught_warnings = []
def test_inner(*args, **kwargs):
with warnings.catch_warnings(record=True) as caught_warnings:
warnings.simplefilter("always")
> rv = method(*args, **kwargs)
E TypeError: test_get_pt_bounds() missing 1 required positional argument: 'peak'
/home/domdf/.local/lib/python3.6/site-packages/deprecation.py:268: TypeError
From the documentation I can't see an alternative way to pass the fixture to the test
When looking at upgrading this package in NixOS/nixpkgs#87100,
I noticed that PyPi has a v2.1 for this package, but there's no corresponding release here. Is the PyPi release a mistake or malicious?
Here I would like to discuss the possibility to extend the functionality of this package to notice about forthcoming API changes and the like.
In many cases functions/classes/methods (you name it) are not deprecated but a change in the API will take place. So it would be useful to warn the user about forthcoming changes with a special decorator.
We used this in the past in our package but would like to see it added here, where it belongs (IMHO). Please have a look at possible use cases here.
The current code would naturally need quite bit of lifting to adapt it to this packages style.
Thoughts?
Deprecation decorator doesn't work on classes if the class being deprecated has a subclass that inherits from it, even if all the subclasses are marked deprecated as well.
I see in pypi that this library is not supported in Python >= 3.8
Is there a reason for this?
What can be done to change it?
When a project uses the setuptools_scm
package to create version number strings fromSCM automatically, the version strings look like: 0.11.2.dev208+g1e95728.d20171223
. Using these version strings with the deprecation module causes things to fail:
tests/block/test_block.py:1: in <module>
import lz4.block
.tox/py/lib/python3.6/site-packages/lz4/__init__.py:14: in <module>
details="Use the lz4.library_version_number function instead")
.tox/py/lib/python3.6/site-packages/deprecation.py:131: in deprecated
current_version = version.StrictVersion(current_version)
/usr/lib64/python3.6/distutils/version.py:40: in __init__
self.parse(vstring)
/usr/lib64/python3.6/distutils/version.py:137: in parse
raise ValueError("invalid version number '%s'" % vstring)
E ValueError: invalid version number '0.11.2.dev208+g1e95728.d20171223'
This is caused by this piece of code:
@deprecated(deprecated_in="0.14", removed_in="1.0",
current_version=VERSION,
details="Use the lz4.library_version_number function instead")
Removing the current_version
argument resolves the problem but of course then you lose the ability to raise exceptions when a function hasn't been removed.
It would probably be better to use packaging.version.parse for version string comparisons, which is the standard used by setuptools, I think.
Hello,
Would it be possible to include the docs
folder in PyPI tarballs? We at Gentoo usually rely on those to build the documentation.
Looks like before tagging __version__
as not updated
Line 20 in c2c1e6b
I am using anyio with asyncio. It seems to me that the decorator messes with the async frameworks and causes the test to be skipped.
Example 1: this test is ignored with "SKIPPED (async def function and no async plugin installed (see warnings))"
import deprecation
import pytest
@deprecation.fail_if_not_removed
@pytest.mark.anyio
async def test_async():
assert True
Example 2: If I switch the decorators around, I see another message in addition: "coroutine 'test_async' was never awaited":
import deprecation
import pytest
@pytest.mark.anyio
@deprecation.fail_if_not_removed
async def test_async():
assert True
[kimyentruong@sage-mac0045:~/Documents/synapsePythonClient] $python
Python 3.6.2 (default, Jul 17 2017, 16:44:45)
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import deprecation
>>> deprecation.__version__
'1.0'
[kimyentruong@sage-mac0045:~/Documents/synapsePythonClient] $pip3 show deprecation
Name: deprecation
Version: 2.0.2
Summary: A library to handle automated deprecations
Home-page: http://deprecation.readthedocs.io/
Author: Brian Curtin
Author-email: [email protected]
License: Apache 2
Location: /usr/local/lib/python3.6/site-packages
Requires: packaging
Required-by:
Hi. I just hit and interesting use case that I was not able to solve with this library. There is a module level variable and it's name has changed. Since is is not a function, I cannot decorate it with @deprecated(...)
.
I searched for possible solutions and found a couple of them in here: https://stackoverflow.com/questions/922550/how-to-mark-a-global-as-deprecated-in-python I liked the second solution with the Deprecated class, becasue it is similar to @deprecated(...)
and would allow to have the same interface.
I'm considering making a pull request but would like to check first if there would be an appetite for that.
There's currently an issue that https://pypi.python.org/pypi/deprecation is taken on PyPI, but it was done by a developer who seems like they started a project and then dropped it. There's one release you can see from the PyPI simple index that is effectively a NotImplementedError
package to reserve the name.
I've reached out to that person to see if I can use the package name, and eventually something like PEP 541 could be helpful here.
It would be nice to keep PyPI releases and git tags in sync :)
__version__ = "1.0"
at the top of deprecation.py and the hardcoded 1.0 in the docs/conf.py file should be replaced with something that makes it nice.
Minor usability issue, should be easy to fix.
Tried using it today and got a weird error.
Traceback (most recent call last):
...
File "/home/.../lib/python3.7/site-packages/deprecation.py", line 232, in _function_wrapper
function.__doc__ = "".join(string_list)
AttributeError: 'list' object attribute '__doc__' is read-only
This was easily resolved by changing the decorating line from @deprecated
to @deprecated()
, but expected behavior for most decorators (ime) is to behave identically if arguments were given or not.
If you're fine with this @briancurtin I'll make a PR.
When trying to package (RPM packaging) the deprecation module, I get:
[ 5s] + '[' -d _build.python3 ']'
[ 5s] + echo python3
[ 5s] + /usr/bin/python3 setup.py build '--executable=/usr/bin/python3 -s'
[ 5s] Traceback (most recent call last):
[ 5s] File "setup.py", line 17, in <module>
[ 5s] long_description=open("README.rst").read(),
[ 5s] File "/usr/lib64/python3.6/encodings/ascii.py", line 26, in decode
[ 5s] return codecs.ascii_decode(input, self.errors)[0]
[ 5s] UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 1918: ordinal not in range(128)
[ 5s] error: Bad exit status from /var/tmp/rpm-tmp.5z1jLX (%build)
[ 5s]
this line throws for builtin (native) functions/classes because __doc__
is not writable
Unit tests marked with the fail_if_not_removed
decorator are not discovered by nose, because the test methods are renamed by the decorator to _inner
and that does not match the default nose pattern.
Tested solution:
In fail_if_not_removed
, return test_inner
instead of _inner
.
unittest2
is no longer maintained anbd should not be used with python 3.x
+ /usr/bin/pytest -ra
=========================================================================== test session starts ============================================================================
platform linux -- Python 3.8.12, pytest-6.2.5, py-1.10.0, pluggy-0.13.1
benchmark: 3.4.1 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
Using --randomly-seed=9223936
rootdir: /home/tkloczko/rpmbuild/BUILD/deprecation-2.1.0
plugins: forked-1.3.0, shutil-1.7.0, virtualenv-1.7.0, expect-1.1.0, flake8-1.0.7, timeout-1.4.2, betamax-0.8.1, freezegun-0.4.2, aspectlib-1.5.2, toolbox-0.5, rerunfailures-9.1.1, requests-mock-1.9.3, cov-2.12.1, flaky-3.7.0, benchmark-3.4.1, xdist-2.3.0, pylama-7.7.1, datadir-1.3.1, regressions-2.2.0, xprocess-0.18.1, black-0.3.12, asyncio-0.15.1, subtests-0.5.0, isort-2.0.0, hypothesis-6.14.6, mock-3.6.1, profiling-1.7.0, randomly-3.8.0, nose2pytest-1.0.8, pyfakefs-4.5.1, tornado-0.8.1, twisted-1.13.3, aiohttp-0.3.0, localserver-0.5.0, anyio-3.3.1, trio-0.7.0, cases-3.6.4, yagot-0.5.0, Faker-8.14.0
collected 0 items / 1 error
================================================================================== ERRORS ==================================================================================
________________________________________________________________ ERROR collecting tests/test_deprecation.py ________________________________________________________________
ImportError while importing test module '/home/tkloczko/rpmbuild/BUILD/deprecation-2.1.0/tests/test_deprecation.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/usr/lib64/python3.8/importlib/__init__.py:127: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
tests/test_deprecation.py:15: in <module>
import unittest2
E ModuleNotFoundError: No module named 'unittest2'
========================================================================= short test summary info ==========================================================================
ERROR tests/test_deprecation.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
============================================================================= 1 error in 0.28s =============================================================================
pytest-xprocess reminder::Be sure to terminate the started process by running 'pytest --xkill' if you have not explicitly done so in your fixture with 'xprocess.getinfo(<process_name>).terminate()'.
Seems like some overlap here, maybe could be merged?
I'd like the ability to wrap deprecation warnings within another sphinx admonition such as info
or warning
. My idea is to have an admonition
argument in deprecated()
which defaults to None
but optionally takes the name of an admonition. The results would be as follows:
@deprecated(deprecated_in="1.0", details="This function is deprecated")
def my_func():
"""Docstring for the function"""
# leads to the following docstring:
"""Docstring for the function
.. deprecated::1.0
This function is deprecated
"""
# versus
@deprecated(deprecated_in="1.0", details="This function is deprecated", admonition='warning')
def my_func():
"""Docstring for the function"""
# leads to the following docstring:
"""Docstring for the function
.. warning::
.. deprecated::1.0
This function is deprecated
"""
I already have clone with this implemented, the patch is very straightforward. If you agree to implement this I can make a PR.
Happy to change the name of the argument if you prefer as well.
#30 mentions a situation where the test decorator doesn't work properly with nose
. We should support nose
in tox and travis so that this fix doesn't end up being a regression later on if someone changes that name or refactors it. This should be done in addition to the current setup that uses unittest
discovery.
>>> warn = deprecation.DeprecatedWarning("depricated", 1, 2)
>>> warn.args
()
currently warnings generated through this module do not set the args property. This is making the library incomparable with the latest release of pytest-xdist since they are using those args as a way of recreating the warning on the manager thread.
How can I apply a future_warning? I need to warn user that some API are not stable, and prone to change later
When I load other libraries (see my attached chardet-3.0.4-py2.py3-none-any.whl example) into artifactory and then click on the PyPi info I see what is shown in the attachment, valid PyPi information. I am then able to pip install the file from our internal artifactory server.
When I load deprecation version 2.0 everything works fine (see attachment).
But when I load deprecation versions after 2.0 (2.0.1 and 2.0.2) I don't get the PyPi information when clicking on the tab in artifactory (see attachment) and I am unable to access it from pip install.
Perhaps the decorator should use the deprecated
directive. See http://www.sphinx-doc.org/en/stable/markup/para.html#directive-deprecated
Note: I was originally going to use that but did not for some reason, and I can't remember why. I think it had to do with an old project I was building this for at the time not supporting that directive?
Depending on the versioning scheme used by a project, it can be difficult to tell in advance the version number at which code can be removed. Sometimes, though, it is easier to tell when it should be removed. Google Guava, for example, guarantees all methods marked deprecated will be kept around for two years post-deprecation.
It would be convenient to handle this by allowing a date (in some TBD format) to be passed for the removed_in
argument.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.