tantale / deprecated Goto Github PK
View Code? Open in Web Editor NEWPython @deprecated decorator to deprecate old python classes, functions or methods.
License: MIT License
Python @deprecated decorator to deprecate old python classes, functions or methods.
License: MIT License
Some old code imported everything from a submodule into the top-level namespace:
# a/__init__.py:
from . import b
from .b import *
We want calling code to use a.b.foo()
instead of a.foo()
, but do it gently.
Basically, we want direct use of a.foo()
to be deprecated, but without having list manually list all of the imported names. I currently have this implemented with importlib
:
################################################################
# import from b into namespace but mark as deprecated
################################################################
import importlib as __importlib
import deprecated as __deprecated
import types as __types
__b_module = __importlib.import_module('.b', __name__)
# is there an __all__? if so respect it
if "__all__" in __b_module.__dict__:
__names = __b_module.__dict__["__all__"]
else:
# otherwise we import all names that don't begin with _
__names = [x for x in __b_module.__dict__ if not x.startswith("_")]
# decorate the items as they get pulled into the namespace
globals().update({
k: (
__deprecated.deprecated(getattr(__b_module, k), action="always", reason="use `b` namespace")
if not isinstance(getattr(__b_module, k), __types.ModuleType)
else getattr(__b_module, k)
)
for k in __names
})
It would be nice to have a way to wrap this into a function or decorator or something similar, so that I could simply do something like:
deprecated.import_all('.b', action="always", reason="use `b` namespace")
I'm not sure how this works with the magic of globals()
though.
I was wondering whether you'd be open to lifting the typestubs from typeshed (https://github.com/python/typeshed/tree/main/stubs/Deprecated/deprecated) directly into this repository. That would make the types easier to maintain (since they live with the code) and make it easier for users to consume (since they can get them directly when installing deprecated
instead of having to install the separate types-deprecated
module.
If you're open to this, I'd be happy to spend some time doing the port!
Désapprouver un paramètre de fonction
Cet article concerne l’ajout d’un (ou plusieurs) décorateur(s) permettant de désapprouver l’utilisation d’un paramètre de fonction. Par exemple :
@deprecated_param(version="0.2.3",
reason="you may consider using *styles* instead.",
deprecated_args='color background_color')
def paragraph(text, color=None, background_color=None, styles=None):
styles = styles or {}
if color:
styles['color'] = color
if background_color:
styles['background-color'] = background_color
html_styles = " ".join("{k}: {v};".format(k=k, v=v) for k, v in styles.items())
html_text = xml.sax.saxutils.escape(text)
return ('<p styles="{html_styles}">{html_text}</p>'
.format(html_styles=html_styles, html_text=html_text))
Un tel décorateur pourrait être codé ainsi :
import functools
def deprecated_param(version, reason, deprecated_args):
def decorate(func):
@functools.wraps(func)
def call(*args, **kwargs):
# todo: check deprecated arguments here...
return func(*args, **kwargs)
return call
return decorate
Utiliser un décorateur pour désapprouver l’usage d’un paramètre de fonction est intéressant et offre certains avantages :
Désavantage :
Autre considération importante :
Outre le cas de déprécation de l’usage d’un paramètre, on pourrait aussi émettre un avertissement dans les cas suivants :
Les cas d’utilisation cités ci-dessus rentrent dans 3 catégories :
(Cette rubrique est incomplète)
Avant de ce lancer dans une implémentation complexe, il faudrait étudier ce qui ce fait, d’une part dans la Bibliothèque Standard, et d’autre part dans les bibliothèques populaires du monde Open Source telles que : pip, urllib3, boto3, six, requests, setuptools, futures, Flask, Django, etc.
Au moins deux questions sont à considérer concernant la déprécation :
(Cette rubrique est incomplète)
L’implémentation d’un décorateur de déprécation de paramètre doit être flexible. Il est nécessaire d’être aussi souple que possible et de reprendre ce qu’il existe pour @deprecated.basic.deprecated
et @deprecated.sphinx.deprecated
. Notamment, l’usage de Wrapt est un must-have.
Il faut aussi définir des cas de tests qui correspondent aux scénarios les plus courant. Il est probable aussi que certaines situations atypiques soient clairement non implémentées.
Pour l’instant, je souhaite continuer le support de Python 2.7, car il est encore utilisé part 25 % des utilisateurs (selon le sondage State of Developer Ecosystem de 2018).
We plan to use deprecated
with our mixed C++/python codebase, including using it to decorate C++ functions and classes at the python level, so that python users see deprecation warnings (instead of just seeing them at compile time). However, there's an odd interaction between pybind11
and deprecated
when marking methods of classes as deprecated.
Pybind11-wrapped classes report the type
of their methods as <instanceMethod>
, not <function>
in python. Thus the deprecated
code at classic.py:225
will register False and it will fall into the else: raise TypeError()
. One possible solution to this would be for that elif
on line 225 to read elif inspect.isfunction(wrapped) or inspect.ismethod(wrapped):
. I'm not sure whether this is the best approach though.
@ktlim and @TallJimbo would be able to say more about the details of the pybind11 side of things.
LSST's deprecation guidelines are online here, and the initial sketch of updates to that to support deprecating methods of classes is in this PR, which spawned this Issue.
https://anaconda.org/conda-forge/deprecated
Latest version there is still 1.2.6
Please publish 1.2.7 release to conda
Thank you
(Feature request)
I would like to see a way to move a class, function, or method from one name to another, deprecating the old name.
So you could say:
class NewName:
...
OldName = deprecated_name(NewName)
I would say that it should raise a warning on direct use (ideally when the code referring to it is compiled, but implementing that would be unacceptably magical).
Tell us what should happen.
@deprecated(reason="Use .guid.provider")
@property
def provider(self):
return self.guid.provider
Tell us what happens instead.
File "/Users/glen/scm/plex/PlexTraktSync/plex_trakt_sync/plex_api.py", line 126, in PlexLibraryItem
def provider(self):
File "/Users/glen/scm/plex/PlexTraktSync/.direnv/python-3.9.5/lib/python3.9/site-packages/deprecated/classic.py", line 261, in deprecated
raise TypeError(repr(type(args[0])))
TypeError: <class 'property'>
Packit failed on creating pull-requests in dist-git:
dist-git branch | error |
---|---|
master |
Failed to download file from URL https://files.pythonhosted.org/packages/source/D/Deprecated/Deprecated-v1.2.9.tar.gz. Reason: 'Not Found'. |
You can re-trigger the update by adding /packit propose-update
to the issue comment.
According to
Line 161 in f5eebcd
deprecated
package depends on the wrapt
package (most recent 1.*
-compatible version).
Unfortunately, the wrapt
package does not follow semantic versioning which means that the installation of the deprecated
package might fail if a new 1.*
release of the wrapt
package comes out. This is what happened recently with the release of version 1.13.0 of wrapt
not being able to install on Windows+Python2.7. For details refer to GrahamDumpleton/wrapt#189.
Unfortunately, the developers of wrapt
do not plan to adhere to semantic versioning, which means that for deprecated
to work reliably for its users, it might be a good idea to adapt the version specification of the wrapt
package.
First, pin the version of wrapt
to ==1.12.1
and release deprecated
as 1.2.14
Then pin the version of wrapt
to ==1.13.1
and release deprecated
as 2.0.0
, stating that the support for Python2.7 on Windows is dropped or drop support for Python 2.7 on all platforms (as it might be difficult to specify the combination with Windows in the setup scripts...)
After releasing deprecated v1.2.14
with wrapt==1.12.1
, one could consider unpinning wrapt again (wrapt<2
), however, given that wrapt
does not adhere to semantic versioning, this should be considered dangerous (e.g. they consider dropping support for Python2.7 in 1.14.0).
Make sure that you do not have wrapt
installed. Install deprecated
on Windows+Python2.7
python -m pip install deprecated=1.2.13
The installation succeeds.
The installation fails with the following error:
Collecting wrapt<2,>=1.10
Using cached wrapt-1.13.1.tar.gz (48 kB)
Using legacy 'setup.py install' for wrapt, since package 'wheel' is not installed.
Installing collected packages: wrapt
Running setup.py install for wrapt ... error
ERROR: Command errored out with exit status 1:
command: 'C:\Python27\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'c:\\users\\361dda~1\\appdata\\local\\temp\\pip-install-9vpyu6\\wrapt\\setup.py'"'"'; __file__='"'"'c:\\users\\361dda~1\\appdata\\local\\temp\\pip-install-9vpyu6\\wrapt\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'c:\users\361dda~1\appdata\local\temp\pip-record-zbb4wg\install-record.txt' --single-version-externally-managed --compile --install-headers 'C:\Python27\Include\wrapt'
cwd: c:\users\361dda~1\appdata\local\temp\pip-install-9vpyu6\wrapt\
Complete output (15 lines):
C:\Python27\lib\distutils\extension.py:133: UserWarning: Unknown Extension options: 'optional'
warnings.warn(msg)
running install
running build
running build_py
creating build
creating build\lib.win-amd64-2.7
creating build\lib.win-amd64-2.7\wrapt
copying src\wrapt\decorators.py -> build\lib.win-amd64-2.7\wrapt
copying src\wrapt\importer.py -> build\lib.win-amd64-2.7\wrapt
copying src\wrapt\wrappers.py -> build\lib.win-amd64-2.7\wrapt
copying src\wrapt\__init__.py -> build\lib.win-amd64-2.7\wrapt
running build_ext
building 'wrapt._wrappers' extension
error: Microsoft Visual C++ 9.0 is required. Get it from http://aka.ms/vcpython27
----------------------------------------
ERROR: Command errored out with exit status 1: 'C:\Python27\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'c:\\users\\361dda~1\\appdata\\local\\temp\\pip-install-9vpyu6\\wrapt\\setup.py'"'"'; __file__='"'"'c:\\users\\361dda~1\\appdata\\local\\temp\\pip-install-9vpyu6\\wrapt\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'c:\users\361dda~1\appdata\local\temp\pip-record-zbb4wg\install-record.txt' --single-version-externally-managed --compile --install-headers 'C:\Python27\Include\wrapt' Check the logs for full command output.
Whatever the convention I select for pydocstring (D212: start on the first line or D213: start on second line) I should get the same results when building documentation with Sphinx. I found out that if I use D212 (default behaviour for ruff) in combination with deprecated
, then the indetation is shifted and the parameters are interpreted as quotes.
I created a small repository that you can launch by executing "nox" from the root. that shows the behavior.
This works as expected:
@versionadded(version="0.0.1", reason="because")
def titi (a, b) -> None:
"""
A one line short description
pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum
Args:
a: the first parameter
b: a second parameter
Returns:
nothing
"""
return
but this doesn't:
@versionadded(version="0.0.1", reason="because")
def tutu (a, b) -> None:
"""A one line short description
pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum pim pam poum
Args:
a: the first parameter
b: a second parameter
Returns:
nothing
"""
return
see this RDT page for the result.
In the following example, the deprecated.sphinx.deprecated
must update the docstring of the class:
from deprecated.sphinx import deprecated
@deprecated(reason="It is deprecated", version="1.2.3")
class Foo:
"""
Description of Foo
"""
The expected docstring should be something like:
Description of Foo
.. deprecated:: 1.2.3
It is deprecated
The actual docstring is:
Description of Foo
Say you use the sphinx decorator with Sphinx syntax references like this:
from deprecated.sphinx import deprecated
@deprecated(reason="Use :py:func:`add` instead", version="1.2.3")
def add(x, y):
return x + y
add(2,3)
the DeprecationWarning will say:
Call to deprecated function (or staticmethod) add. (Use :py:func:`add` instead) -- Deprecated since version 1.2.3.
For a normal user of my library this :py:func:
looks weird.
The user typically does not know/care that I use Sphinx as documentation build tool, let alone that they understand this syntax.
Strip this kind of Sphinx syntax from the DeprecationWarning
message
Subclass a class that is marked as deprecated shouldn't raises an error.
Subclassing a class that's deprecated raises a TypeError
>>> from deprecated import deprecated
>>> @deprecated
... class MyClass: pass
...
>>> class MyOtherClass(MyClass): pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/alex/.virtualenvs/uptime-backend/lib/python3.6/site-packages/wrapt/decorators.py", line 128, in __init__
adapter = kwargs.pop('adapter')
KeyError: 'adapter'
>>>
Sorry for the duplicate issue with vrcmarcos/python-deprecated#7 but I saw that this is here that I should have opened the issue as the library was renamed.
Paste the following into a file named once.py
from deprecated import deprecated
@deprecated(reason='this should happen once', action='once')
def a():
return
a()
a()
a()
I expect the deprecation warning to print once:
$ python3 once.py
once.py:6: DeprecationWarning: Call to deprecated function (or staticmethod) a. (this should happen once)
a()
Tell us what happens instead.
$ python3 once.py
once.py:6: DeprecationWarning: Call to deprecated function (or staticmethod) a. (this should happen once)
a()
once.py:7: DeprecationWarning: Call to deprecated function (or staticmethod) a. (this should happen once)
a()
once.py:8: DeprecationWarning: Call to deprecated function (or staticmethod) a. (this should happen once)
a()
Note: this issue is slightly different from the issue #24 aims to solve. #24 deals with actions specified by global warning filters while this issue deals with actions specified to the @deprecated
decorator.
This is not a problem in Python 2. This is only a problem in Python 3 due to the way warnings.catch_warnings()
works. Entering and exiting the warnings.catch_warnings()
context manager causes Python 3 to clear out its warning registries. The warning registries keep track of which warnings have fired in order to enforce actions like "once", "default", and "module". When deprecated
fires its warning inside warnings.catch_warnings()
, the warning registries will always be empty, so "once", "default", and "module" end up behaving like "always". I'm not sure there's much we can do to fix this problem.
It looks like this project is not packaged in Fedora.
Do you plan to package it into Fedora?
Do you think it would be possible to add Fedora RPM spec file into this repository?
We have a project https://packit.dev/, which would automate it a bit once here is a configuration file .packit.yaml
What do you think about it?
I would be glad for any kind of response.
When setting the action="once"
option, the deprecation warning should only be logged once.
from deprecated import deprecated
@deprecated(action='once')
def my_func():
print("running the old func")
if __name__ == "__main__":
my_func()
my_func()
my_func()
The deprecation warning is displayed every time the function is called:
DeprecationWarning: Call to deprecated function (or staticmethod) my_func.
my_func()
DeprecationWarning: Call to deprecated function (or staticmethod) my_func.
my_func()
DeprecationWarning: Call to deprecated function (or staticmethod) my_func.
my_func()
running the old func
running the old func
running the old func
Current setup.py express the dependency on wrapt as:
install_requires=[
'wrapt < 2, >= 1',
],
However using wrapt 1.9.0 (since it's the current version available on debian stretch) fails with:
____________________ ERROR collecting tests/test.py _____________________
tests/test.py:4: in <module>
import deprecated
deprecated/__init__.py:13: in <module>
from deprecated.classic import deprecated
deprecated/classic.py:18: in <module>
class ClassicAdapter(wrapt.AdapterFactory):
E AttributeError: module 'wrapt' has no attribute 'AdapterFactory'
(as well as in other tests).
Using wrapt 1.10+ works as expected.
My PR (#61) was recently pushed to the repository, it's nothing fancy but it's solving an issue for anyone using the ruff linter with the docstring default parameter. As the ruff project is getting much attention maybe this could be integrated in a patch release to be available for pypi installation.
Using isinstance() for classes annotated with the deprecated library should work as expected, regardless of the number of annotations.
from deprecated.sphinx import versionadded
from deprecated.sphinx import versionchanged
from deprecated.sphinx import deprecated
@versionadded(version='X.Y', reason='some reason')
class VersionAdded:
pass
@versionadded(version='X.Y', reason='some reason')
class VersionAddedChild(VersionAdded):
pass
@versionchanged(version='X.Y', reason='some reason')
class VersionChanged:
pass
@versionchanged(version='X.Y', reason='some reason')
class VersionChangedChild(VersionChanged):
pass
@deprecated(version='X.Y', reason='some reason')
class Deprecated_:
pass
@deprecated(version='Y.Z', reason='some reason')
class DeprecatedChild_(Deprecated_):
pass
@versionadded(version='X.Y')
@versionchanged(version='X.Y.Z')
class AddedChanged:
pass
# should all be True
print([isinstance(VersionAddedChild(), VersionAddedChild), isinstance(VersionAddedChild(), VersionAdded)])
print([isinstance(VersionChangedChild(), VersionChangedChild), isinstance(VersionChangedChild(), VersionChanged)])
print([isinstance(DeprecatedChild_(), DeprecatedChild_), isinstance(DeprecatedChild_(), Deprecated_)])
print([isinstance(AddedChanged(), AddedChanged)])
Tell us what happens instead.
[False, False]
[False, False]
[True, True] # seems to have been addressed on 0e944e0
[False]
Packit failed on creating pull-requests in dist-git:
dist-git branch | error |
---|---|
master |
Failed to download file from URL https://files.pythonhosted.org/packages/source/D/Deprecated/Deprecated-v1.2.10.tar.gz. Reason: 'Not Found'. |
You can re-trigger the update by adding /packit propose-update
to the issue comment.
/packit propose-update
This issue tracker is a tool to address bugs in Deprecated itself.
Please use Stack Overflow for general questions about using Deprecated
or issues not related to Deprecated Library.
If you'd like to report a bug in Deprecated, fill out the template below. Provide
any extra information that may be useful/related to your problem.
Ideally, create an Minimal, Complete, and Verifiable example,
which helps us understand the problem and helps check that it is not caused by something in your code.
I'm hoping to use the decorator to create sphinx output.
print(a.__doc__)
.. deprecated:: 3.0.35
This staticmethod has been deprecated. :func:`get_it_id()` is
recommended instead. Example:
.. code-block:: python
from test_lib_dry_lab.lib.aplace.anotherlongerplace import Lookup
rwo = Lookup('ID222').item[0]
rwo.get_it_id()
'AY20'
When using sphinx to deprecate a function, I'm noticing its continuing text on a new line. Is there a way to prevent this?
.. deprecated:: 3.0.35
This staticmethod has been deprecated. :func:`get_it_id()` is
recommended instead. Example:
.. code-block:: python
from test_lib_dry_lab.lib.aplace.anotherlongerplace import
Lookup
rwo = Lookup('ID222').item[0]
rwo.get_it_id()
'AY20'
According to the this example versionadded
should not emit the warning, but when I run the test code it does.
from deprecated.sphinx import versionadded
class Macros(object):
class Macro(object):
def __call__(self, *args,**kwargs):
...
@versionadded(version='0.7.0')
class HiveDatabase(Macro):
...
I expected this will work fine
when I run pytest...
tests/context/test_macros.py: 12 tests with warnings
/Users/user/IdeaProjects/airsflow/airsflow/context/macros.py:58: DeprecationWarning: Call to deprecated class HiveDatabase. -- Deprecated since version 0.7.0.
return cls(ctx, *args, namespace=namespace, context=context, **kwargs)
When warning filters are applied, I'd expect the warnings to be suppressed.
import warnings
from deprecated import deprecated
warnings.simplefilter("ignore")
@deprecated(version='1.2.1', reason="deprecated function")
def fun():
print("fun")
fun()
The script emits a warning message:
test_dep.py:10: DeprecationWarning: Call to deprecated function (or staticmethod) fun. (deprecated function) -- Deprecated since version 1.2.1.
fun()
fun
First of all looks like it is not possible cleanly build documentation usinf raw sphinx-build command.
+ /usr/bin/sphinx-build -n -T -b man docs/source build/sphinx/man
Running Sphinx v4.5.0
making output directory... done
loading intersphinx inventory from https://docs.python.org/3/objects.inv...
loading intersphinx inventory from https://wrapt.readthedocs.io/en/latest/objects.inv...
loading intersphinx inventory from http://flask.pocoo.org/docs/1.0/objects.inv...
loading intersphinx inventory from https://docs.djangoproject.com/en/2.1/_objects/...
intersphinx inventory has moved: http://flask.pocoo.org/docs/1.0/objects.inv -> https://flask.palletsprojects.com/en/1.0.x/objects.inv
building [mo]: targets for 0 po files that are out of date
building [man]: all manpages
updating environment: [new config] 10 added, 0 changed, 0 removed
reading sources... [100%] white_paper
WARNING: autodoc: failed to import module 'deprecated'; the following exception was raised:
No module named 'deprecated'
WARNING: autodoc: failed to import module 'classic' from module 'deprecated'; the following exception was raised:
No module named 'deprecated'
WARNING: autodoc: failed to import module 'sphinx' from module 'deprecated'; the following exception was raised:
No module named 'deprecated'
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
writing... python-deprecated.3 { installation introduction tutorial sphinx_deco white_paper api changelog license contributing } /home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/tutorial.rst:20: WARNING: py:meth reference target not found: deprecated
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/tutorial.rst:120: WARNING: py:func reference target not found: deprecated.deprecated
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/tutorial.rst:155: WARNING: py:func reference target not found: deprecated.classic.deprecated
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/tutorial.rst:155: WARNING: py:func reference target not found: deprecated.sphinx.deprecated
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/tutorial.rst:200: WARNING: py:func reference target not found: deprecated.classic.deprecated
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/tutorial.rst:200: WARNING: py:func reference target not found: deprecated.sphinx.deprecated
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/sphinx_deco.rst:77: WARNING: py:func reference target not found: deprecated.sphinx.deprecated
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/sphinx_deco.rst:78: WARNING: py:func reference target not found: deprecated.sphinx.versionadded
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/sphinx_deco.rst:79: WARNING: py:func reference target not found: deprecated.sphinx.versionchanged
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:78: WARNING: py:mod reference target not found: asyncio.tasks
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:128: WARNING: py:mod reference target not found: flask.app
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:128: WARNING: py:mod reference target not found: flask.helpers
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:168: WARNING: py:exc reference target not found: flask.exthook.ExtDeprecationWarning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:202: WARNING: py:mod reference target not found: django.utils.deprecation
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:204: WARNING: py:exc reference target not found: django.utils.deprecation.RemovedInDjango31Warning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:206: WARNING: py:exc reference target not found: django.utils.deprecation.RemovedInDjango40Warning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:208: WARNING: py:exc reference target not found: django.utils.deprecation.RemovedInNextVersionWarning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:208: WARNING: py:exc reference target not found: django.utils.deprecation.RemovedInDjango40Warning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:211: WARNING: py:exc reference target not found: django.utils.deprecation.RemovedInNextVersionWarning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:215: WARNING: py:class reference target not found: django.contrib.postgres.forms.ranges.FloatRangeField
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:231: WARNING: py:exc reference target not found: django.utils.deprecation.RemovedInDjango31Warning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:235: WARNING: py:meth reference target not found: django.conf.LazySettings.FILE_CHARSET
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:235: WARNING: py:class reference target not found: django.conf.LazySettings
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:255: WARNING: py:exc reference target not found: django.utils.deprecation.RemovedInDjango40Warning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:267: WARNING: py:class reference target not found: django.utils.deprecation.warn_about_renamed_method
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:267: WARNING: py:class reference target not found: django.utils.deprecation.RenameMethodsBase
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:292: WARNING: py:class reference target not found: lxml.xpath._XPathEvaluatorBase`(:file:`src/lxml/xpath.pxi
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:312: WARNING: py:class reference target not found: lxml.etree._ElementTree
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:343: WARNING: py:func reference target not found: deprecated.sphinx.deprecated
CHANGELOG.rst:29: WARNING: py:func reference target not found: deprecated.sphinx.deprecated
CHANGELOG.rst:61: WARNING: py:mod reference target not found: deprecated.sphinx
CHANGELOG.rst:80: WARNING: py:class reference target not found: deprecated.sphinx.SphinxAdapter
CHANGELOG.rst:242: WARNING: py:class reference target not found: deprecated.classic.ClassicAdapter
CHANGELOG.rst:248: WARNING: py:class reference target not found: deprecated.classic.ClassicAdapter
CHANGELOG.rst:248: WARNING: py:class reference target not found: deprecated.sphinx.SphinxAdapter
CHANGELOG.rst:284: WARNING: py:mod reference target not found: deprecated.sphinx
CHANGELOG.rst:354: WARNING: py:func reference target not found: deprecated.deprecated
CHANGELOG.rst:422: WARNING: py:func reference target not found: deprecated.deprecated
CHANGELOG.rst:425: WARNING: py:mod reference target not found: deprecated
done
build succeeded, 42 warnings.
Fiirst part of warnings can be fixed by patch like below
--- a/docs/source/conf.py~ 2022-05-13 08:06:41.000000000 +0000
+++ b/docs/source/conf.py 2022-05-13 08:10:22.286693027 +0000
@@ -17,9 +17,9 @@
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
-# import os
-# import sys
-# sys.path.insert(0, os.path.abspath('.'))
+import os
+import sys
+sys.path.insert(0, os.path.abspath('../..'))
# -- General configuration ------------------------------------------------
That patch is doing exacly what is mentioned in comment above modified lines.
Than .. on building my packages I'm using sphinx-build
command with -n
switch which shows warmings about missing references. These are not critical issues.
Here is the output with warnings:
+ /usr/bin/sphinx-build -n -T -b man docs/source build/sphinx/man
Running Sphinx v4.5.0
making output directory... done
loading intersphinx inventory from https://docs.python.org/3/objects.inv...
loading intersphinx inventory from https://wrapt.readthedocs.io/en/latest/objects.inv...
loading intersphinx inventory from http://flask.pocoo.org/docs/1.0/objects.inv...
loading intersphinx inventory from https://docs.djangoproject.com/en/2.1/_objects/...
intersphinx inventory has moved: http://flask.pocoo.org/docs/1.0/objects.inv -> https://flask.palletsprojects.com/en/1.0.x/objects.inv
building [mo]: targets for 0 po files that are out of date
building [man]: all manpages
updating environment: [new config] 10 added, 0 changed, 0 removed
reading sources... [100%] white_paper
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
writing... python-deprecated.3 { installation introduction tutorial sphinx_deco white_paper api changelog license contributing } /home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/tutorial.rst:120: WARNING: py:func reference target not found: deprecated.deprecated
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:78: WARNING: py:mod reference target not found: asyncio.tasks
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:128: WARNING: py:mod reference target not found: flask.app
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:128: WARNING: py:mod reference target not found: flask.helpers
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:168: WARNING: py:exc reference target not found: flask.exthook.ExtDeprecationWarning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:202: WARNING: py:mod reference target not found: django.utils.deprecation
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:204: WARNING: py:exc reference target not found: django.utils.deprecation.RemovedInDjango31Warning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:206: WARNING: py:exc reference target not found: django.utils.deprecation.RemovedInDjango40Warning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:208: WARNING: py:exc reference target not found: django.utils.deprecation.RemovedInNextVersionWarning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:208: WARNING: py:exc reference target not found: django.utils.deprecation.RemovedInDjango40Warning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:211: WARNING: py:exc reference target not found: django.utils.deprecation.RemovedInNextVersionWarning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:215: WARNING: py:class reference target not found: django.contrib.postgres.forms.ranges.FloatRangeField
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:231: WARNING: py:exc reference target not found: django.utils.deprecation.RemovedInDjango31Warning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:235: WARNING: py:meth reference target not found: django.conf.LazySettings.FILE_CHARSET
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:235: WARNING: py:class reference target not found: django.conf.LazySettings
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:255: WARNING: py:exc reference target not found: django.utils.deprecation.RemovedInDjango40Warning
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:267: WARNING: py:class reference target not found: django.utils.deprecation.warn_about_renamed_method
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:267: WARNING: py:class reference target not found: django.utils.deprecation.RenameMethodsBase
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:292: WARNING: py:class reference target not found: lxml.xpath._XPathEvaluatorBase`(:file:`src/lxml/xpath.pxi
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/docs/source/white_paper.rst:312: WARNING: py:class reference target not found: lxml.etree._ElementTree
CHANGELOG.rst:354: WARNING: py:func reference target not found: deprecated.deprecated
CHANGELOG.rst:422: WARNING: py:func reference target not found: deprecated.deprecated
done
build succeeded, 22 warnings.
This article concerns the addition of one (or more) decorator(s) to deprecate the use of a function parameter. For example:
@deprecated_param(version="0.2.3",
reason="you may consider using *styles* instead.",
deprecated_args='color background_color')
def paragraph(text, color=None, background_color=None, styles=None):
styles = styles or {}
if color:
styles['color'] = color
if background_color:
styles['background-color'] = background_color
html_styles = " ".join("{k}: {v};".format(k=k, v=v) for k, v in styles.items())
html_text = xml.sax.saxutils.escape(text)
return ('<p styles="{html_styles}">{html_text}</p>'
.format(html_styles=html_styles, html_text=html_text))
Such a decorator could be coded as follows:
import functools
def deprecated_param(version, reason, deprecated_args):
def decorate(func):
@functools.wraps(func)
def call(*args, **kwargs):
# todo: check deprecated arguments here...
return func(*args, **kwargs)
return call
return decorate
Using a decorator to deprecate the use of a function parameter is interesting and offers some advantages:
Disadvantages:
In addition to the case of deprecating a parameter usage, a warning could also be issued in the following cases:
The use cases mentioned above fall into 3 categories:
The third case (modified parameter) is the most difficult to specify in general terms.
(This section is incomplete)
Before starting a complex implementation, it would be necessary to study how it is done, on one hand in the Standard Library, and on the other hand in the popular libraries of the Open Source world such as: pip, urllib3, boto3, six, requests, setuptools, futures, Flask, Django…
At least two questions must be considered regarding deprecation:
(This section is incomplete)
A parameter deprecation decorator implementation must be flexible. It is necessary to be as flexible as possible and to use what exists for @deprecated.basic.deprecated
and @deprecated.sphinx.deprecated
. Especially, the use of Wrapt is a must-have.
It is also necessary to define test cases that correspond to the most common scenarios. It is also likely that some atypical situations are clearly not implemented.
For now, I would like to continue supporting Python 2.7, as it is still used by 25% of users (according to the 2018 State of Developer Ecosystem survey).
I was looking at the deprecated files and see there is a .travis.yml file. I remember last year that travis dropped support for open source repositories. There is no travis badge in the readme so I was asking myself, is it still used ?
If no would you be opened to move the test to a github action ?
I checked deprecated and other packages in search of this and I couldn't find it. So I end up making my own deprecation help function mne-tools/mne-python#5844
Check it out and if you think this is desirable, maybe we can cut a PR out of it.
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.
Files also as briancurtin/deprecation#51
Tests should pass ;-).
This is most likely due to Python 3.9 fixing @classmethod
behavior (see also: GrahamDumpleton/wrapt#160). Now the deprecation is correctly reported as 'class method' rather than 'deprecated function (or staticmethod)'.
GLOB sdist-make: /tmp/deprecated/setup.py
py39 inst-nodeps: /tmp/deprecated/.tox/.tmp/package/1/Deprecated-1.2.11.zip
py39 installed: attrs==19.3.0,coverage==4.5.4,Deprecated @ file:///tmp/deprecated/.tox/.tmp/package/1/Deprecated-1.2.11.zip,more-itertools==8.3.0,packaging==20.4,pluggy==0.13.1,py==1.8.1,pyparsing==2.4.7,pytest==5.4.2,pytest-cov==2.9.0,six==1.15.0,wcwidth==0.1.9,wrapt==1.12.1
py39 run-test-pre: PYTHONHASHSEED='2163554996'
py39 run-test: commands[0] | pytest --cov-report term-missing --cov=deprecated tests/
============================= test session starts ==============================
platform linux -- Python 3.9.0b1, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
cachedir: .tox/py39/.pytest_cache
rootdir: /tmp/deprecated, inifile: setup.cfg
plugins: cov-2.9.0
collected 156 items
tests/test.py .. [ 1%]
tests/test_deprecated.py ............................FFFFFFF...... [ 27%]
tests/test_deprecated_class.py ....... [ 32%]
tests/test_deprecated_metaclass.py .... [ 34%]
tests/test_sphinx.py ................................................... [ 67%]
...............................FFFFFFF...... [ 95%]
tests/test_sphinx_class.py ... [ 97%]
tests/test_sphinx_metaclass.py .... [100%]
=================================== FAILURES ===================================
______________ test_classic_deprecated_class_method__warns[None] _______________
classic_deprecated_class_method = <class 'tests.test_deprecated.classic_deprecated_class_method.<locals>.Foo5'>
def test_classic_deprecated_class_method__warns(classic_deprecated_class_method):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
cls = classic_deprecated_class_method()
cls.foo5()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
> assert "deprecated function (or staticmethod)" in str(warn.message)
E AssertionError: assert 'deprecated function (or staticmethod)' in 'Call to deprecated class method foo5.'
E + where 'Call to deprecated class method foo5.' = str(DeprecationWarning('Call to deprecated class method foo5.'))
E + where DeprecationWarning('Call to deprecated class method foo5.') = <warnings.WarningMessage object at 0x7f2804045a00>.message
tests/test_deprecated.py:187: AssertionError
_ test_classic_deprecated_class_method__warns[classic_deprecated_class_method1] _
classic_deprecated_class_method = <class 'tests.test_deprecated.classic_deprecated_class_method.<locals>.Foo5'>
def test_classic_deprecated_class_method__warns(classic_deprecated_class_method):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
cls = classic_deprecated_class_method()
cls.foo5()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
> assert "deprecated function (or staticmethod)" in str(warn.message)
E AssertionError: assert 'deprecated function (or staticmethod)' in 'Call to deprecated class method foo5.'
E + where 'Call to deprecated class method foo5.' = str(DeprecationWarning('Call to deprecated class method foo5.'))
E + where DeprecationWarning('Call to deprecated class method foo5.') = <warnings.WarningMessage object at 0x7f2804062b50>.message
tests/test_deprecated.py:187: AssertionError
_ test_classic_deprecated_class_method__warns[classic_deprecated_class_method2] _
classic_deprecated_class_method = <class 'tests.test_deprecated.classic_deprecated_class_method.<locals>.Foo5'>
def test_classic_deprecated_class_method__warns(classic_deprecated_class_method):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
cls = classic_deprecated_class_method()
cls.foo5()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
> assert "deprecated function (or staticmethod)" in str(warn.message)
E AssertionError: assert 'deprecated function (or staticmethod)' in 'Call to deprecated class method foo5. (Good reason)'
E + where 'Call to deprecated class method foo5. (Good reason)' = str(DeprecationWarning('Call to deprecated class method foo5. (Good reason)'))
E + where DeprecationWarning('Call to deprecated class method foo5. (Good reason)') = <warnings.WarningMessage object at 0x7f2804071190>.message
tests/test_deprecated.py:187: AssertionError
_ test_classic_deprecated_class_method__warns[classic_deprecated_class_method3] _
classic_deprecated_class_method = <class 'tests.test_deprecated.classic_deprecated_class_method.<locals>.Foo5'>
def test_classic_deprecated_class_method__warns(classic_deprecated_class_method):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
cls = classic_deprecated_class_method()
cls.foo5()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
> assert "deprecated function (or staticmethod)" in str(warn.message)
E AssertionError: assert 'deprecated function (or staticmethod)' in 'Call to deprecated class method foo5. (Good reason)'
E + where 'Call to deprecated class method foo5. (Good reason)' = str(DeprecationWarning('Call to deprecated class method foo5. (Good reason)'))
E + where DeprecationWarning('Call to deprecated class method foo5. (Good reason)') = <warnings.WarningMessage object at 0x7f28040625b0>.message
tests/test_deprecated.py:187: AssertionError
_ test_classic_deprecated_class_method__warns[classic_deprecated_class_method4] _
classic_deprecated_class_method = <class 'tests.test_deprecated.classic_deprecated_class_method.<locals>.Foo5'>
def test_classic_deprecated_class_method__warns(classic_deprecated_class_method):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
cls = classic_deprecated_class_method()
cls.foo5()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
> assert "deprecated function (or staticmethod)" in str(warn.message)
E AssertionError: assert 'deprecated function (or staticmethod)' in 'Call to deprecated class method foo5. -- Deprecated since version 1.2.3.'
E + where 'Call to deprecated class method foo5. -- Deprecated since version 1.2.3.' = str(DeprecationWarning('Call to deprecated class method foo5. -- Deprecated since version 1.2.3.'))
E + where DeprecationWarning('Call to deprecated class method foo5. -- Deprecated since version 1.2.3.') = <warnings.WarningMessage object at 0x7f2804071a30>.message
tests/test_deprecated.py:187: AssertionError
_ test_classic_deprecated_class_method__warns[classic_deprecated_class_method5] _
classic_deprecated_class_method = <class 'tests.test_deprecated.classic_deprecated_class_method.<locals>.Foo5'>
def test_classic_deprecated_class_method__warns(classic_deprecated_class_method):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
cls = classic_deprecated_class_method()
cls.foo5()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
> assert "deprecated function (or staticmethod)" in str(warn.message)
E AssertionError: assert 'deprecated function (or staticmethod)' in 'Call to deprecated class method foo5.'
E + where 'Call to deprecated class method foo5.' = str(DeprecationWarning('Call to deprecated class method foo5.'))
E + where DeprecationWarning('Call to deprecated class method foo5.') = <warnings.WarningMessage object at 0x7f28040452b0>.message
tests/test_deprecated.py:187: AssertionError
_ test_classic_deprecated_class_method__warns[classic_deprecated_class_method6] _
classic_deprecated_class_method = <class 'tests.test_deprecated.classic_deprecated_class_method.<locals>.Foo5'>
def test_classic_deprecated_class_method__warns(classic_deprecated_class_method):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
cls = classic_deprecated_class_method()
cls.foo5()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
> assert "deprecated function (or staticmethod)" in str(warn.message)
E AssertionError: assert 'deprecated function (or staticmethod)' in 'Call to deprecated class method foo5.'
E + where 'Call to deprecated class method foo5.' = str(MyDeprecationWarning('Call to deprecated class method foo5.'))
E + where MyDeprecationWarning('Call to deprecated class method foo5.') = <warnings.WarningMessage object at 0x7f280405c2e0>.message
tests/test_deprecated.py:187: AssertionError
_______________ test_sphinx_deprecated_class_method__warns[None] _______________
sphinx_deprecated_class_method = <class 'tests.test_sphinx.sphinx_deprecated_class_method.<locals>.Foo5'>
def test_sphinx_deprecated_class_method__warns(sphinx_deprecated_class_method):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
cls = sphinx_deprecated_class_method()
cls.foo5()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
> assert "deprecated function (or staticmethod)" in str(warn.message)
E AssertionError: assert 'deprecated function (or staticmethod)' in 'Call to deprecated class method foo5.'
E + where 'Call to deprecated class method foo5.' = str(DeprecationWarning('Call to deprecated class method foo5.'))
E + where DeprecationWarning('Call to deprecated class method foo5.') = <warnings.WarningMessage object at 0x7f2803fcb310>.message
tests/test_sphinx.py:337: AssertionError
_ test_sphinx_deprecated_class_method__warns[sphinx_deprecated_class_method1] __
sphinx_deprecated_class_method = <class 'tests.test_sphinx.sphinx_deprecated_class_method.<locals>.Foo5'>
def test_sphinx_deprecated_class_method__warns(sphinx_deprecated_class_method):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
cls = sphinx_deprecated_class_method()
cls.foo5()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
> assert "deprecated function (or staticmethod)" in str(warn.message)
E AssertionError: assert 'deprecated function (or staticmethod)' in 'Call to deprecated class method foo5.'
E + where 'Call to deprecated class method foo5.' = str(DeprecationWarning('Call to deprecated class method foo5.'))
E + where DeprecationWarning('Call to deprecated class method foo5.') = <warnings.WarningMessage object at 0x7f2803fe6f10>.message
tests/test_sphinx.py:337: AssertionError
_ test_sphinx_deprecated_class_method__warns[sphinx_deprecated_class_method2] __
sphinx_deprecated_class_method = <class 'tests.test_sphinx.sphinx_deprecated_class_method.<locals>.Foo5'>
def test_sphinx_deprecated_class_method__warns(sphinx_deprecated_class_method):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
cls = sphinx_deprecated_class_method()
cls.foo5()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
> assert "deprecated function (or staticmethod)" in str(warn.message)
E AssertionError: assert 'deprecated function (or staticmethod)' in 'Call to deprecated class method foo5. (Good reason)'
E + where 'Call to deprecated class method foo5. (Good reason)' = str(DeprecationWarning('Call to deprecated class method foo5. (Good reason)'))
E + where DeprecationWarning('Call to deprecated class method foo5. (Good reason)') = <warnings.WarningMessage object at 0x7f2803ff10d0>.message
tests/test_sphinx.py:337: AssertionError
_ test_sphinx_deprecated_class_method__warns[sphinx_deprecated_class_method3] __
sphinx_deprecated_class_method = <class 'tests.test_sphinx.sphinx_deprecated_class_method.<locals>.Foo5'>
def test_sphinx_deprecated_class_method__warns(sphinx_deprecated_class_method):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
cls = sphinx_deprecated_class_method()
cls.foo5()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
> assert "deprecated function (or staticmethod)" in str(warn.message)
E AssertionError: assert 'deprecated function (or staticmethod)' in 'Call to deprecated class method foo5. (Good reason)'
E + where 'Call to deprecated class method foo5. (Good reason)' = str(DeprecationWarning('Call to deprecated class method foo5. (Good reason)'))
E + where DeprecationWarning('Call to deprecated class method foo5. (Good reason)') = <warnings.WarningMessage object at 0x7f2803fe1790>.message
tests/test_sphinx.py:337: AssertionError
_ test_sphinx_deprecated_class_method__warns[sphinx_deprecated_class_method4] __
sphinx_deprecated_class_method = <class 'tests.test_sphinx.sphinx_deprecated_class_method.<locals>.Foo5'>
def test_sphinx_deprecated_class_method__warns(sphinx_deprecated_class_method):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
cls = sphinx_deprecated_class_method()
cls.foo5()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
> assert "deprecated function (or staticmethod)" in str(warn.message)
E AssertionError: assert 'deprecated function (or staticmethod)' in 'Call to deprecated class method foo5. -- Deprecated since version 1.2.3.'
E + where 'Call to deprecated class method foo5. -- Deprecated since version 1.2.3.' = str(DeprecationWarning('Call to deprecated class method foo5. -- Deprecated since version 1.2.3.'))
E + where DeprecationWarning('Call to deprecated class method foo5. -- Deprecated since version 1.2.3.') = <warnings.WarningMessage object at 0x7f28040bdac0>.message
tests/test_sphinx.py:337: AssertionError
_ test_sphinx_deprecated_class_method__warns[sphinx_deprecated_class_method5] __
sphinx_deprecated_class_method = <class 'tests.test_sphinx.sphinx_deprecated_class_method.<locals>.Foo5'>
def test_sphinx_deprecated_class_method__warns(sphinx_deprecated_class_method):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
cls = sphinx_deprecated_class_method()
cls.foo5()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
> assert "deprecated function (or staticmethod)" in str(warn.message)
E AssertionError: assert 'deprecated function (or staticmethod)' in 'Call to deprecated class method foo5.'
E + where 'Call to deprecated class method foo5.' = str(DeprecationWarning('Call to deprecated class method foo5.'))
E + where DeprecationWarning('Call to deprecated class method foo5.') = <warnings.WarningMessage object at 0x7f2803fead60>.message
tests/test_sphinx.py:337: AssertionError
_ test_sphinx_deprecated_class_method__warns[sphinx_deprecated_class_method6] __
sphinx_deprecated_class_method = <class 'tests.test_sphinx.sphinx_deprecated_class_method.<locals>.Foo5'>
def test_sphinx_deprecated_class_method__warns(sphinx_deprecated_class_method):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
cls = sphinx_deprecated_class_method()
cls.foo5()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
> assert "deprecated function (or staticmethod)" in str(warn.message)
E AssertionError: assert 'deprecated function (or staticmethod)' in 'Call to deprecated class method foo5.'
E + where 'Call to deprecated class method foo5.' = str(MyDeprecationWarning('Call to deprecated class method foo5.'))
E + where MyDeprecationWarning('Call to deprecated class method foo5.') = <warnings.WarningMessage object at 0x7f280405cac0>.message
tests/test_sphinx.py:337: AssertionError
=============================== warnings summary ===============================
tests/test_deprecated_class.py::test_simple_class_deprecation_with_args
/tmp/deprecated/tests/test_deprecated_class.py:148: DeprecationWarning: Call to deprecated class MyClass. (kwargs class)
MyClass(5)
-- Docs: https://docs.pytest.org/en/latest/warnings.html
----------- coverage: platform linux, python 3.9.0-beta-1 ------------
Name Stmts Miss Cover Missing
------------------------------------------------------
deprecated/__init__.py 3 0 100%
deprecated/classic.py 79 6 92% 25-30, 290
deprecated/sphinx.py 38 2 95% 124, 150
------------------------------------------------------
TOTAL 120 8 93%
=========================== short test summary info ============================
FAILED tests/test_deprecated.py::test_classic_deprecated_class_method__warns[None]
FAILED tests/test_deprecated.py::test_classic_deprecated_class_method__warns[classic_deprecated_class_method1]
FAILED tests/test_deprecated.py::test_classic_deprecated_class_method__warns[classic_deprecated_class_method2]
FAILED tests/test_deprecated.py::test_classic_deprecated_class_method__warns[classic_deprecated_class_method3]
FAILED tests/test_deprecated.py::test_classic_deprecated_class_method__warns[classic_deprecated_class_method4]
FAILED tests/test_deprecated.py::test_classic_deprecated_class_method__warns[classic_deprecated_class_method5]
FAILED tests/test_deprecated.py::test_classic_deprecated_class_method__warns[classic_deprecated_class_method6]
FAILED tests/test_sphinx.py::test_sphinx_deprecated_class_method__warns[None]
FAILED tests/test_sphinx.py::test_sphinx_deprecated_class_method__warns[sphinx_deprecated_class_method1]
FAILED tests/test_sphinx.py::test_sphinx_deprecated_class_method__warns[sphinx_deprecated_class_method2]
FAILED tests/test_sphinx.py::test_sphinx_deprecated_class_method__warns[sphinx_deprecated_class_method3]
FAILED tests/test_sphinx.py::test_sphinx_deprecated_class_method__warns[sphinx_deprecated_class_method4]
FAILED tests/test_sphinx.py::test_sphinx_deprecated_class_method__warns[sphinx_deprecated_class_method5]
FAILED tests/test_sphinx.py::test_sphinx_deprecated_class_method__warns[sphinx_deprecated_class_method6]
================== 14 failed, 142 passed, 1 warning in 0.52s ===================
ERROR: InvocationError for command /tmp/deprecated/.tox/py39/bin/pytest --cov-report term-missing --cov=deprecated tests/ (exited with code 1)
___________________________________ summary ____________________________________
ERROR: py39: commands failed
I just wanted to notify you that PEP-702 introduces support for an official @deprecated() decorator (https://peps.python.org/pep-0702/).
Are you planning on relying on it for the deprecated decorator ?
I'm trying to package your module as an rpm package. So I'm using the typical PEP517 based build, install and test cycle used on building packages from non-root account.
python3 -sBm build -w --no-isolation
build
with --no-isolation
I'm using during all processes only locally installed modulesHere is pytest output:
+ PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-deprecated-1.2.13-5.fc35.x86_64/usr/lib64/python3.8/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-deprecated-1.2.13-5.fc35.x86_64/usr/lib/python3.8/site-packages
+ /usr/bin/pytest -ra
=========================================================================== test session starts ============================================================================
platform linux -- Python 3.8.13, pytest-7.1.2, pluggy-1.0.0
rootdir: /home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13, configfile: setup.cfg
collected 159 items
tests/test.py .. [ 1%]
tests/test_deprecated.py ......................................... [ 27%]
tests/test_deprecated_class.py ....... [ 31%]
tests/test_deprecated_metaclass.py .... [ 33%]
tests/test_sphinx.py .................................................................................. [ 85%]
tests/test_sphinx_adapter.py ............ [ 93%]
tests/test_sphinx_class.py ....... [ 97%]
tests/test_sphinx_metaclass.py .... [100%]
============================================================================= warnings summary =============================================================================
tests/test_deprecated_class.py::test_simple_class_deprecation_with_args
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/tests/test_deprecated_class.py:148: DeprecationWarning: Call to deprecated class MyClass. (kwargs class)
MyClass(5)
tests/test_sphinx_class.py::test_isinstance_deprecated
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/tests/test_sphinx_class.py:134: DeprecationWarning: Call to deprecated class DeprecatedChildCls. (some reason) -- Deprecated since version Y.Z.
instance = DeprecatedChildCls()
tests/test_sphinx_class.py::test_isinstance_deprecated
/home/tkloczko/rpmbuild/BUILD/deprecated-1.2.13/deprecated/classic.py:173: DeprecationWarning: Call to deprecated class DeprecatedCls. (some reason) -- Deprecated since version X.Y.
return old_new1(cls, *args, **kwargs)
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
===================================================================== 159 passed, 3 warnings in 0.44s ======================================================================
Tests should pass, as they did in 1.2.7.
To run tests, I've added ,pypy3
to PyTest conditions in tox.ini
.
The following tests fails with PyPy3:
==================================================================== FAILURES =====================================================================
___________________________________________________ test_classic_deprecated_class__warns[None] ____________________________________________________
classic_deprecated_class = <class 'tests.test_deprecated.classic_deprecated_class.<locals>.Foo2'>
def test_classic_deprecated_class__warns(classic_deprecated_class):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
classic_deprecated_class()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
assert "deprecated class" in str(warn.message)
> assert warn.filename == __file__, 'Incorrect warning stackLevel'
E AssertionError: Incorrect warning stackLevel
E assert '/tmp/depreca...est/python.py' == '/tmp/depreca...deprecated.py'
E - /tmp/deprecated-1.2.8/tests/test_deprecated.py
E + /tmp/deprecated-1.2.8/.tox/pypy3/site-packages/_pytest/python.py
tests/test_deprecated.py:150: AssertionError
_________________________________________ test_classic_deprecated_class__warns[classic_deprecated_class1] _________________________________________
classic_deprecated_class = <class 'tests.test_deprecated.classic_deprecated_class.<locals>.Foo2'>
def test_classic_deprecated_class__warns(classic_deprecated_class):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
classic_deprecated_class()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
assert "deprecated class" in str(warn.message)
> assert warn.filename == __file__, 'Incorrect warning stackLevel'
E AssertionError: Incorrect warning stackLevel
E assert '/tmp/depreca...est/python.py' == '/tmp/depreca...deprecated.py'
E - /tmp/deprecated-1.2.8/tests/test_deprecated.py
E + /tmp/deprecated-1.2.8/.tox/pypy3/site-packages/_pytest/python.py
tests/test_deprecated.py:150: AssertionError
_________________________________________ test_classic_deprecated_class__warns[classic_deprecated_class2] _________________________________________
classic_deprecated_class = <class 'tests.test_deprecated.classic_deprecated_class.<locals>.Foo2'>
def test_classic_deprecated_class__warns(classic_deprecated_class):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
classic_deprecated_class()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
assert "deprecated class" in str(warn.message)
> assert warn.filename == __file__, 'Incorrect warning stackLevel'
E AssertionError: Incorrect warning stackLevel
E assert '/tmp/depreca...est/python.py' == '/tmp/depreca...deprecated.py'
E - /tmp/deprecated-1.2.8/tests/test_deprecated.py
E + /tmp/deprecated-1.2.8/.tox/pypy3/site-packages/_pytest/python.py
tests/test_deprecated.py:150: AssertionError
_________________________________________ test_classic_deprecated_class__warns[classic_deprecated_class3] _________________________________________
classic_deprecated_class = <class 'tests.test_deprecated.classic_deprecated_class.<locals>.Foo2'>
def test_classic_deprecated_class__warns(classic_deprecated_class):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
classic_deprecated_class()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
assert "deprecated class" in str(warn.message)
> assert warn.filename == __file__, 'Incorrect warning stackLevel'
E AssertionError: Incorrect warning stackLevel
E assert '/tmp/depreca...est/python.py' == '/tmp/depreca...deprecated.py'
E - /tmp/deprecated-1.2.8/tests/test_deprecated.py
E + /tmp/deprecated-1.2.8/.tox/pypy3/site-packages/_pytest/python.py
tests/test_deprecated.py:150: AssertionError
_________________________________________ test_classic_deprecated_class__warns[classic_deprecated_class4] _________________________________________
classic_deprecated_class = <class 'tests.test_deprecated.classic_deprecated_class.<locals>.Foo2'>
def test_classic_deprecated_class__warns(classic_deprecated_class):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
classic_deprecated_class()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
assert "deprecated class" in str(warn.message)
> assert warn.filename == __file__, 'Incorrect warning stackLevel'
E AssertionError: Incorrect warning stackLevel
E assert '/tmp/depreca...est/python.py' == '/tmp/depreca...deprecated.py'
E - /tmp/deprecated-1.2.8/tests/test_deprecated.py
E + /tmp/deprecated-1.2.8/.tox/pypy3/site-packages/_pytest/python.py
tests/test_deprecated.py:150: AssertionError
_________________________________________ test_classic_deprecated_class__warns[classic_deprecated_class5] _________________________________________
classic_deprecated_class = <class 'tests.test_deprecated.classic_deprecated_class.<locals>.Foo2'>
def test_classic_deprecated_class__warns(classic_deprecated_class):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
classic_deprecated_class()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
assert "deprecated class" in str(warn.message)
> assert warn.filename == __file__, 'Incorrect warning stackLevel'
E AssertionError: Incorrect warning stackLevel
E assert '/tmp/depreca...est/python.py' == '/tmp/depreca...deprecated.py'
E - /tmp/deprecated-1.2.8/tests/test_deprecated.py
E + /tmp/deprecated-1.2.8/.tox/pypy3/site-packages/_pytest/python.py
tests/test_deprecated.py:150: AssertionError
_________________________________________ test_classic_deprecated_class__warns[classic_deprecated_class6] _________________________________________
classic_deprecated_class = <class 'tests.test_deprecated.classic_deprecated_class.<locals>.Foo2'>
def test_classic_deprecated_class__warns(classic_deprecated_class):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
classic_deprecated_class()
assert len(warns) == 1
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
assert "deprecated class" in str(warn.message)
> assert warn.filename == __file__, 'Incorrect warning stackLevel'
E AssertionError: Incorrect warning stackLevel
E assert '/tmp/depreca...est/python.py' == '/tmp/depreca...deprecated.py'
E - /tmp/deprecated-1.2.8/tests/test_deprecated.py
E + /tmp/deprecated-1.2.8/.tox/pypy3/site-packages/_pytest/python.py
tests/test_deprecated.py:150: AssertionError
================================================================ warnings summary =================================================================
tests/test_deprecated_class.py::test_simple_class_deprecation_with_args
/tmp/deprecated-1.2.8/.tox/pypy3/site-packages/_pytest/python.py:184: DeprecationWarning: Call to deprecated class MyClass. (kwargs class)
result = testfunction(**testargs)
-- Docs: https://docs.pytest.org/en/latest/warnings.html
----------- coverage: platform linux, python 3.6.9-final-0 -----------
Name Stmts Miss Cover Missing
------------------------------------------------------
deprecated/__init__.py 3 0 100%
deprecated/classic.py 71 3 96% 22, 130, 280
deprecated/sphinx.py 36 2 94% 124, 150
------------------------------------------------------
TOTAL 110 5 95%
============================================================= short test summary info =============================================================
FAILED tests/test_deprecated.py::test_classic_deprecated_class__warns[None] - AssertionError: Incorrect warning stackLevel
FAILED tests/test_deprecated.py::test_classic_deprecated_class__warns[classic_deprecated_class1] - AssertionError: Incorrect warning stackLevel
FAILED tests/test_deprecated.py::test_classic_deprecated_class__warns[classic_deprecated_class2] - AssertionError: Incorrect warning stackLevel
FAILED tests/test_deprecated.py::test_classic_deprecated_class__warns[classic_deprecated_class3] - AssertionError: Incorrect warning stackLevel
FAILED tests/test_deprecated.py::test_classic_deprecated_class__warns[classic_deprecated_class4] - AssertionError: Incorrect warning stackLevel
FAILED tests/test_deprecated.py::test_classic_deprecated_class__warns[classic_deprecated_class5] - AssertionError: Incorrect warning stackLevel
FAILED tests/test_deprecated.py::test_classic_deprecated_class__warns[classic_deprecated_class6] - AssertionError: Incorrect warning stackLevel
==================================================== 7 failed, 148 passed, 1 warning in 20.18s ====================================================
I don't know if this isn't a problem with pytest itself and/or pypy3. However,
$ pypy3 --version
Python 3.6.9 (1608da62bfc71e8ac775121dd0b21bb72e61c6ea, Dec 25 2019, 15:23:23)
[PyPy 7.3.0 with GCC 9.2.0]
Over at coroa/pandas-indexing#27, I am about to deprecate a pandas accessor, but since these accessors are classes, which are instantiated by pandas upon access the warning is not emitted since the stacklevel
is too low.
import pandas as pd
from deprecated import deprecated
@pd.api.extensions.register_dataframe_accessor("idx")
@deprecated
class IdxAccessor:
def __init__(self, pandas_obj):
self._obj = pandas_obj
df = pd.DataFrame()
df.idx
will only emit with a warnings.simplefilter("always")
warnings.simplefilter("default")
(edit: changed to include "default" which was pointed out below), since the callstack looks like:
Cell In[4], line 11
df.idx
File ~/.local/conda/envs/aneris2/lib/python3.10/site-packages/pandas/core/accessor.py:182 in __get__
accessor_obj = self._accessor(obj)
File ~/.local/conda/envs/aneris2/lib/python3.10/site-packages/deprecated/classic.py:169 in wrapped_cls
warnings.warn(msg, category=self.category, stacklevel=_class_stacklevel)
so that the last stacklevel=2
setting points to the pandas.core.accessor
module instead of the user code.
Would you accept a PR to add a stacklevel_offset
or stacklevel
argument to deprecated which would either be added like:
warnings.warn(msg, category=self.category, stacklevel=_class_stacklevel + stacklevel_offset)
or could be used to replace the default stacklevel
, like:
warnings.warn(msg, category=self.category, stacklevel=_class_stacklevel if stacklevel is None else stacklevel)
This is a feature request (I think): I would like deprecated
to be able to yield warnings on a method call, even when overriding the implementation in a subclass. In particular, I would like to be able to deprecate abstract methods.
Running…
from deprecated import deprecated
class Parent:
@deprecated(reason='try not to laugh')
def fun(self, arg):
raise NotImplementedError()
class Child(Parent):
def fun(self, arg):
print(arg)
print('yaye!')
some = Child()
some.fun('whoops')
…I would like to see…
DeprecationWarning: Call to deprecated method fun. (try not to laugh)
some.fun('whoops')
whoops
yaye!
However, since the method is overriden, I can see no warning:
whoops
yaye!
Packit failed on creating pull-requests in dist-git:
dist-git branch | error |
---|---|
master |
Failed to download file from URL https://files.pythonhosted.org/packages/source/D/Deprecated/Deprecated-v1.2.8.tar.gz. Reason: 'Not Found'. |
You can re-trigger the update by adding /packit propose-update
to the issue comment.
This is a feature idea, not a bug report.
It would be great if deprecated
could warn about deprecated arguments, e.g. like
@deprecated_arg(name="old_arg_name", since="1.2", version=mypackage.__version__, reason="'old_arg_name' is not consistent with some reference")
def my_function(old_arg_name, other_args):
pass
which would yield a message like:
"my_function" called with deprecated argument "old_arg_name"
Optionally with a new name hint, so
@deprecated_arg(name="old_arg_name", new_name="new_arg_name", since="1.2", version=mypackage.__version__)
def my_function(old_arg_name, other_args):
pass
which would yield a message like:
"my_function" called with deprecated argument "old_arg_name". Please use "new_arg_name"
Packit failed on creating pull-requests in dist-git:
dist-git branch | error |
---|---|
f34 |
Ref 'remotes/origin/f34' did not resolve to an object |
You can retrigger the update by adding a comment (/packit propose-downstream
) into this issue.
The link to the GitHub project is missing in the documentation.
The setup.py
file contains:
project_urls={
"Documentation": "https://deprecated.readthedocs.io/en/latest/",
"Source": "https://github.com/tantale/deprecated",
"Bug Tracker": "https://github.com/tantale/deprecated/issues",
}
The "Source" and "Bug Tracker" links must appears in the documentation.
It would be nice to keep PyPI releases and git tags in sync :)
No exception, returns class as expected.
# Paste a minimal example that causes the problem.
@deprecated('kwargs class')
class ClassKwargs(object):
def __init__(self, a=5):
super(ClassKwargs, self).__init__()
self.state = a
def method(self):
return self.state
ClassKwargs(6)
Not complete traceback but most important part:
ClassKwargs(6)
File "/home/matt/miniconda3/envs/df/lib/python3.5/site-packages/deprecated/classic.py", line 104, in wrapped_cls
return old_new1(*args, **kwargs)
TypeError: object() takes no parameters
The Sphinx versionadded
, versionchanged
, and deprecated
directives have a non-optional version
argument. However, Deprecated will happily generate a Sphinx directive that is missing the version argument:
deprecated/deprecated/sphinx.py
Line 100 in a02525b
Hi! First of all, thank you so much for writing this library, it really helps me maintaining deprecations around my source code.
Nevertheless, I realised that there is one problem related with the serialization process (with both pickle
and dill
) which I believe is related with the wrapt
library and the GrahamDumpleton/wrapt#102 issue, in which the author aims to implement the __reduce_ex__
.
Tell us what should happen.
from pickle import dumps
from deprecated import deprecated
@deprecated
def foo():
return 'bar'
print(dumps(foo))
Tell us what happens instead.
Traceback (most recent call last):
File "~/development/open-source/deprecated/proof.py", line 11, in <module>
print(dumps(foo))
NotImplementedError: object proxy must define __reduce_ex__()
In case of replacing the pickle
module by dill
, the error trace is more descriptive:
Traceback (most recent call last):
File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/pydevd.py", line 1434, in _exec
pydev_imports.execfile(file, globals, locals) # execute the script
File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
exec(compile(contents+"\n", file, 'exec'), glob, loc)
File "/Users/garciparedes/development/open-source/deprecated/proof.py", line 11, in <module>
print(dumps(foo))
File "/Users/garciparedes/development/open-source/deprecated/venv/lib/python3.7/site-packages/dill/_dill.py", line 265, in dumps
dump(obj, file, protocol, byref, fmode, recurse, **kwds)#, strictio)
File "/Users/garciparedes/development/open-source/deprecated/venv/lib/python3.7/site-packages/dill/_dill.py", line 259, in dump
Pickler(file, protocol, **_kwds).dump(obj)
File "~/development/open-source/deprecated/venv/lib/python3.7/site-packages/dill/_dill.py", line 445, in dump
StockPickler.dump(self, obj)
File "/usr/local/Cellar/python/3.7.6_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/pickle.py", line 437, in dump
self.save(obj)
File "/usr/local/Cellar/python/3.7.6_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/pickle.py", line 524, in save
rv = reduce(self.proto)
NotImplementedError: object proxy must define __reduce_ex__()
3.7.6
1.2.8
Type stubs for this library were submitted to typeshed in python/typeshed#4423
You don't need to take any action, but:
a) If you wish to include type stubs as part of your package, we're happy to transfer them to this repo (or potentially aid with the addition of inline types)
b) If you want us to remove the stubs from typeshed, we will!
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.