From c3dc2a65acf4103f9f13b739d6c81baf34373b8a Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Sun, 9 Jul 2023 00:08:39 +0200 Subject: [PATCH 1/9] Add extra_stacklevel argument --- deprecated/classic.py | 17 ++++++++++++----- deprecated/sphinx.py | 17 +++++++++++++++-- tests/test_deprecated.py | 15 ++++++++++----- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/deprecated/classic.py b/deprecated/classic.py index 6ca3f27..7af4ebd 100644 --- a/deprecated/classic.py +++ b/deprecated/classic.py @@ -83,7 +83,7 @@ def some_old_function(x, y): return x + y """ - def __init__(self, reason="", version="", action=None, category=DeprecationWarning): + def __init__(self, reason="", version="", action=None, category=DeprecationWarning, extra_stacklevel=0): """ Construct a wrapper adapter. @@ -109,11 +109,17 @@ def __init__(self, reason="", version="", action=None, category=DeprecationWarni The warning category to use for the deprecation warning. By default, the category class is :class:`~DeprecationWarning`, you can inherit this class to define your own deprecation warning category. + + :type extra_stacklevel: int + :param extra_stacklevel: + The offset to apply to the stacklevel of the emitted warning. + By default, no offset is applied. """ self.reason = reason or "" self.version = version or "" self.action = action self.category = category + self.extra_stacklevel = extra_stacklevel super(ClassicAdapter, self).__init__() def get_deprecated_msg(self, wrapped, instance): @@ -164,9 +170,9 @@ def wrapped_cls(cls, *args, **kwargs): if self.action: with warnings.catch_warnings(): warnings.simplefilter(self.action, self.category) - warnings.warn(msg, category=self.category, stacklevel=_class_stacklevel) + warnings.warn(msg, category=self.category, stacklevel=_class_stacklevel + self.extra_stacklevel) else: - warnings.warn(msg, category=self.category, stacklevel=_class_stacklevel) + warnings.warn(msg, category=self.category, stacklevel=_class_stacklevel + self.extra_stacklevel) if old_new1 is object.__new__: return old_new1(cls) # actually, we don't know the real signature of *old_new1* @@ -265,6 +271,7 @@ def some_old_function(x, y): category = kwargs.get('category', DeprecationWarning) adapter_cls = kwargs.pop('adapter_cls', ClassicAdapter) adapter = adapter_cls(**kwargs) + extra_stacklevel = kwargs.get("extra_stacklevel", 0) wrapped = args[0] if inspect.isclass(wrapped): @@ -279,9 +286,9 @@ def wrapper_function(wrapped_, instance_, args_, kwargs_): if action: with warnings.catch_warnings(): warnings.simplefilter(action, category) - warnings.warn(msg, category=category, stacklevel=_routine_stacklevel) + warnings.warn(msg, category=category, stacklevel=_routine_stacklevel + extra_stacklevel) else: - warnings.warn(msg, category=category, stacklevel=_routine_stacklevel) + warnings.warn(msg, category=category, stacklevel=_routine_stacklevel + extra_stacklevel) return wrapped_(*args_, **kwargs_) return wrapper_function(wrapped) diff --git a/deprecated/sphinx.py b/deprecated/sphinx.py index be6dce9..bf00653 100644 --- a/deprecated/sphinx.py +++ b/deprecated/sphinx.py @@ -48,6 +48,7 @@ def __init__( version="", action=None, category=DeprecationWarning, + extra_stacklevel=0, line_length=70, ): """ @@ -80,6 +81,11 @@ def __init__( By default, the category class is :class:`~DeprecationWarning`, you can inherit this class to define your own deprecation warning category. + :type extra_stacklevel: int + :param extra_stacklevel: + The offset to apply to the stacklevel of the emitted warning. + By default, no offset is applied. + :type line_length: int :param line_length: Max line length of the directive text. If non nul, a long text is wrapped in several lines. @@ -89,7 +95,9 @@ def __init__( raise ValueError("'version' argument is required in Sphinx directives") self.directive = directive self.line_length = line_length - super(SphinxAdapter, self).__init__(reason=reason, version=version, action=action, category=category) + super(SphinxAdapter, self).__init__( + reason=reason, version=version, action=action, category=category, extra_stacklevel=extra_stacklevel + ) def __call__(self, wrapped): """ @@ -102,7 +110,7 @@ def __call__(self, wrapped): # -- build the directive division fmt = ".. {directive}:: {version}" if self.version else ".. {directive}::" div_lines = [fmt.format(directive=self.directive, version=self.version)] - width = self.line_length - 3 if self.line_length > 3 else 2 ** 16 + width = self.line_length - 3 if self.line_length > 3 else 2**16 reason = textwrap.dedent(self.reason).strip() for paragraph in reason.splitlines(): if paragraph: @@ -248,6 +256,11 @@ def deprecated(reason="", version="", line_length=70, **kwargs): The warning category to use for the deprecation warning. By default, the category class is :class:`~DeprecationWarning`, you can inherit this class to define your own deprecation warning category. + + - "extra_stacklevel": + The offset to apply to the stacklevel of the emitted warning. + By default, no offset is applied. + :return: a decorator used to deprecate a function. diff --git a/tests/test_deprecated.py b/tests/test_deprecated.py index e4c00ef..5cbc293 100644 --- a/tests/test_deprecated.py +++ b/tests/test_deprecated.py @@ -11,6 +11,10 @@ class MyDeprecationWarning(DeprecationWarning): pass +class WrongStackLevelWarning(DeprecationWarning): + pass + + _PARAMS = [ None, ((), {}), @@ -19,6 +23,7 @@ class MyDeprecationWarning(DeprecationWarning): ((), {'version': '1.2.3'}), ((), {'action': 'once'}), ((), {'category': MyDeprecationWarning}), + ((), {'extra_stacklevel': 1, 'category': WrongStackLevelWarning}), ] @@ -136,7 +141,7 @@ def test_classic_deprecated_function__warns(classic_deprecated_function): warn = warns[0] assert issubclass(warn.category, DeprecationWarning) assert "deprecated function (or staticmethod)" in str(warn.message) - assert warn.filename == __file__, 'Incorrect warning stackLevel' + assert warn.filename == __file__ or warn.category is WrongStackLevelWarning, 'Incorrect warning stackLevel' # noinspection PyShadowingNames @@ -148,7 +153,7 @@ def test_classic_deprecated_class__warns(classic_deprecated_class): warn = warns[0] assert issubclass(warn.category, DeprecationWarning) assert "deprecated class" in str(warn.message) - assert warn.filename == __file__, 'Incorrect warning stackLevel' + assert warn.filename == __file__ or warn.category is WrongStackLevelWarning, 'Incorrect warning stackLevel' # noinspection PyShadowingNames @@ -161,7 +166,7 @@ def test_classic_deprecated_method__warns(classic_deprecated_method): warn = warns[0] assert issubclass(warn.category, DeprecationWarning) assert "deprecated method" in str(warn.message) - assert warn.filename == __file__, 'Incorrect warning stackLevel' + assert warn.filename == __file__ or warn.category is WrongStackLevelWarning, 'Incorrect warning stackLevel' # noinspection PyShadowingNames @@ -173,7 +178,7 @@ def test_classic_deprecated_static_method__warns(classic_deprecated_static_metho warn = warns[0] assert issubclass(warn.category, DeprecationWarning) assert "deprecated function (or staticmethod)" in str(warn.message) - assert warn.filename == __file__, 'Incorrect warning stackLevel' + assert warn.filename == __file__ or warn.category is WrongStackLevelWarning, 'Incorrect warning stackLevel' # noinspection PyShadowingNames @@ -189,7 +194,7 @@ def test_classic_deprecated_class_method__warns(classic_deprecated_class_method) assert "deprecated class method" in str(warn.message) else: assert "deprecated function (or staticmethod)" in str(warn.message) - assert warn.filename == __file__, 'Incorrect warning stackLevel' + assert warn.filename == __file__ or warn.category is WrongStackLevelWarning, 'Incorrect warning stackLevel' def test_should_raise_type_error(): From 759b7b1bef60209318a55ab5f0acec3859cb3f5b Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Sun, 9 Jul 2023 13:40:27 +0200 Subject: [PATCH 2/9] Add functional test --- tests/test_deprecated.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/test_deprecated.py b/tests/test_deprecated.py index 5cbc293..ceb3b2f 100644 --- a/tests/test_deprecated.py +++ b/tests/test_deprecated.py @@ -263,3 +263,18 @@ def fun(): fun() fun() assert len(warns) == 1 + + +def test_extra_stacklevel(): + @deprecated.classic.deprecated(version='1.2.1', reason="deprecated function", extra_stacklevel=1) + def inner(): + pass + + def outer(): + inner() + + warnings.simplefilter("default", category=DeprecationWarning) + with warnings.catch_warnings(record=True) as warns: + outer() + outer() + assert len(warns) == 2 From 62731632354fdb55cff8aa89acf176b5dc345ddb Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Sun, 9 Jul 2023 13:40:52 +0200 Subject: [PATCH 3/9] Update CHANGELOG --- CHANGELOG.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ec2f685..1e43f51 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -28,6 +28,8 @@ Fix - Resolve Python 2.7 support issue introduced in v1.2.14 in ``sphinx.py``. +- Fix #69: Add ``extra_stacklevel`` argument for interoperating with other wrapper functions (refer to #68 for a concrete use case). + Other ----- From 34703e5e4726716d172f806184b2dbd5d056f360 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Sun, 9 Jul 2023 14:00:10 +0200 Subject: [PATCH 4/9] Improve documentation --- deprecated/classic.py | 14 ++++++++++++-- deprecated/sphinx.py | 18 ++++++++++++------ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/deprecated/classic.py b/deprecated/classic.py index 7af4ebd..69860bc 100644 --- a/deprecated/classic.py +++ b/deprecated/classic.py @@ -112,8 +112,12 @@ def __init__(self, reason="", version="", action=None, category=DeprecationWarni :type extra_stacklevel: int :param extra_stacklevel: - The offset to apply to the stacklevel of the emitted warning. - By default, no offset is applied. + Number of additonal stacklevels to consider instrumentation rather than user code. + With the default value of 0, the warning refers to where the class was instantiated + or the function was called. + + .. versionchanged:: 1.2.15 + Add the *extra_stacklevel* parameter. """ self.reason = reason or "" self.version = version or "" @@ -258,6 +262,12 @@ def some_old_function(x, y): def some_old_function(x, y): return x + y + The *extra_stacklevel* keyword argument allows you to specify additional stacklevels + to consider instrumentation rather than user code. With the default value of 0, the + warning refers to where the class was instantiated or the function was called. + + .. versionchanged:: 1.2.15 + Add the *extra_stacklevel* parameter. """ if args and isinstance(args[0], string_types): kwargs['reason'] = args[0] diff --git a/deprecated/sphinx.py b/deprecated/sphinx.py index bf00653..bd74522 100644 --- a/deprecated/sphinx.py +++ b/deprecated/sphinx.py @@ -22,8 +22,6 @@ import re import textwrap -import wrapt - from deprecated.classic import ClassicAdapter from deprecated.classic import deprecated as _classic_deprecated @@ -83,12 +81,16 @@ def __init__( :type extra_stacklevel: int :param extra_stacklevel: - The offset to apply to the stacklevel of the emitted warning. - By default, no offset is applied. + Number of additonal stacklevels to consider instrumentation rather than user code. + With the default value of 0, the warning refers to where the class was instantiated + or the function was called. :type line_length: int :param line_length: Max line length of the directive text. If non nul, a long text is wrapped in several lines. + + .. versionchanged:: 1.2.15 + Add the *extra_stacklevel* parameter. """ if not version: # https://github.com/tantale/deprecated/issues/40 @@ -258,14 +260,18 @@ def deprecated(reason="", version="", line_length=70, **kwargs): you can inherit this class to define your own deprecation warning category. - "extra_stacklevel": - The offset to apply to the stacklevel of the emitted warning. - By default, no offset is applied. + Number of additional stacklevels to consider instrumentation rather than user code. + With the default value of 0, the warning refers to where the class was instantiated + or the function was called. :return: a decorator used to deprecate a function. .. versionchanged:: 1.2.13 Change the signature of the decorator to reflect the valid use cases. + + .. versionchanged:: 1.2.15 + Add the *extra_stacklevel* parameter. """ directive = kwargs.pop('directive', 'deprecated') adapter_cls = kwargs.pop('adapter_cls', SphinxAdapter) From b53076c2dccf7954038fdeca349814d058e1e177 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Sun, 9 Jul 2023 14:20:04 +0200 Subject: [PATCH 5/9] Refactor: Move function wrapping logic into adapter --- deprecated/classic.py | 52 ++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/deprecated/classic.py b/deprecated/classic.py index 69860bc..47707ac 100644 --- a/deprecated/classic.py +++ b/deprecated/classic.py @@ -171,12 +171,13 @@ def __call__(self, wrapped): def wrapped_cls(cls, *args, **kwargs): msg = self.get_deprecated_msg(wrapped, None) + stacklevel = _class_stacklevel + self.extra_stacklevel if self.action: with warnings.catch_warnings(): warnings.simplefilter(self.action, self.category) - warnings.warn(msg, category=self.category, stacklevel=_class_stacklevel + self.extra_stacklevel) + warnings.warn(msg, category=self.category, stacklevel=stacklevel) else: - warnings.warn(msg, category=self.category, stacklevel=_class_stacklevel + self.extra_stacklevel) + warnings.warn(msg, category=self.category, stacklevel=stacklevel) if old_new1 is object.__new__: return old_new1(cls) # actually, we don't know the real signature of *old_new1* @@ -184,6 +185,24 @@ def wrapped_cls(cls, *args, **kwargs): wrapped.__new__ = staticmethod(wrapped_cls) + elif inspect.isroutine(wrapped): + @wrapt.decorator + def wrapper_function(wrapped_, instance_, args_, kwargs_): + msg = self.get_deprecated_msg(wrapped_, instance_) + stacklevel = _routine_stacklevel + self.extra_stacklevel + if self.action: + with warnings.catch_warnings(): + warnings.simplefilter(self.action, self.category) + warnings.warn(msg, category=self.category, stacklevel=stacklevel) + else: + warnings.warn(msg, category=self.category, stacklevel=stacklevel) + return wrapped_(*args_, **kwargs_) + + return wrapper_function(wrapped) + + else: + raise TypeError(repr(type(wrapped))) + return wrapped @@ -265,9 +284,6 @@ def some_old_function(x, y): The *extra_stacklevel* keyword argument allows you to specify additional stacklevels to consider instrumentation rather than user code. With the default value of 0, the warning refers to where the class was instantiated or the function was called. - - .. versionchanged:: 1.2.15 - Add the *extra_stacklevel* parameter. """ if args and isinstance(args[0], string_types): kwargs['reason'] = args[0] @@ -277,33 +293,9 @@ def some_old_function(x, y): raise TypeError(repr(type(args[0]))) if args: - action = kwargs.get('action') - category = kwargs.get('category', DeprecationWarning) adapter_cls = kwargs.pop('adapter_cls', ClassicAdapter) adapter = adapter_cls(**kwargs) - extra_stacklevel = kwargs.get("extra_stacklevel", 0) - wrapped = args[0] - if inspect.isclass(wrapped): - wrapped = adapter(wrapped) - return wrapped - - elif inspect.isroutine(wrapped): - - @wrapt.decorator(adapter=adapter) - def wrapper_function(wrapped_, instance_, args_, kwargs_): - msg = adapter.get_deprecated_msg(wrapped_, instance_) - if action: - with warnings.catch_warnings(): - warnings.simplefilter(action, category) - warnings.warn(msg, category=category, stacklevel=_routine_stacklevel + extra_stacklevel) - else: - warnings.warn(msg, category=category, stacklevel=_routine_stacklevel + extra_stacklevel) - return wrapped_(*args_, **kwargs_) - - return wrapper_function(wrapped) - - else: - raise TypeError(repr(type(wrapped))) + return adapter(wrapped) return functools.partial(deprecated, **kwargs) From 0c7c6d2be6fd1f18f6b94b622a90dffb4d622338 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Sun, 9 Jul 2023 14:34:34 +0200 Subject: [PATCH 6/9] Add suggested tutorial updates Co-authored-by: Laurent LAPORTE --- docs/source/tutorial.rst | 25 +++++++++++++++++++ .../warning_ctrl/extra_stacklevel_demo.py | 24 ++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 docs/source/tutorial/warning_ctrl/extra_stacklevel_demo.py diff --git a/docs/source/tutorial.rst b/docs/source/tutorial.rst index 86cf056..00fb237 100644 --- a/docs/source/tutorial.rst +++ b/docs/source/tutorial.rst @@ -242,3 +242,28 @@ function will raise an exception because the *action* is set to "error". File "path/to/deprecated/classic.py", line 274, in wrapper_function warnings.warn(msg, category=category, stacklevel=_stacklevel) DeprecationWarning: Call to deprecated function (or staticmethod) foo. (do not call it) + + +Modifying the deprecated code reference +--------------------------------------- + +By default, when a deprecated function or class is called, the warning message indicates the location of the caller. + +The ``extra_stacklevel`` parameter allows customizing the stack level reference in the deprecation warning message. + +This parameter is particularly useful in scenarios where you have a factory or utility function that creates deprecated +objects or performs deprecated operations. By specifying an ``extra_stacklevel`` value, you can control the stack level +at which the deprecation warning is emitted, making it appear as if the calling function is the deprecated one, +rather than the actual deprecated entity. + +For example, if you have a factory function ``create_object()`` that creates deprecated objects, you can use +the ``extra_stacklevel`` parameter to emit the deprecation warning at the calling location. This provides clearer and +more actionable deprecation messages, allowing developers to identify and update the code that invokes the deprecated +functionality. + +For instance: + +.. literalinclude:: tutorial/warning_ctrl/extra_stacklevel_demo.py + +Please note that the ``extra_stacklevel`` value should be an integer indicating the number of stack levels to skip +when emitting the deprecation warning. diff --git a/docs/source/tutorial/warning_ctrl/extra_stacklevel_demo.py b/docs/source/tutorial/warning_ctrl/extra_stacklevel_demo.py new file mode 100644 index 0000000..3c0516c --- /dev/null +++ b/docs/source/tutorial/warning_ctrl/extra_stacklevel_demo.py @@ -0,0 +1,24 @@ +import warnings + +from deprecated import deprecated + + +@deprecated(version='1.0', extra_stacklevel=1) +class MyObject(object): + def __init__(self, name): + self.name = name + + def __str__(self): + return "object: {name}".format(name=self.name) + + +def create_object(name): + return MyObject(name) + + +if __name__ == '__main__': + warnings.filterwarnings("default", category=DeprecationWarning) + # warn here: + print(create_object("orange")) + # and also here: + print(create_object("banane")) From 0f30714ddb464c59074e41a3c70aeddd3f056a00 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Sun, 9 Jul 2023 14:38:33 +0200 Subject: [PATCH 7/9] Add suggested unit test for extra_stacklevel Co-authored-by: Laurent LAPORTE --- tests/test_deprecated.py | 62 ++++++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/tests/test_deprecated.py b/tests/test_deprecated.py index ceb3b2f..0e467ae 100644 --- a/tests/test_deprecated.py +++ b/tests/test_deprecated.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import inspect import sys import warnings @@ -265,16 +266,59 @@ def fun(): assert len(warns) == 1 +def test_default_stacklevel(): + """ + The objective of this unit test is to ensure that the triggered warning message, + when invoking the 'use_foo' function, correctly indicates the line where the + deprecated 'foo' function is called. + """ + + @deprecated.classic.deprecated + def foo(): + pass + + def use_foo(): + foo() + + with warnings.catch_warnings(record=True) as warns: + warnings.simplefilter("always") + use_foo() + + # Check that the warning path matches the module path + warn = warns[0] + assert warn.filename == __file__ + + # Check that the line number points to the first line inside 'use_foo' + use_foo_lineno = inspect.getsourcelines(use_foo)[1] + assert warn.lineno == use_foo_lineno + 1 + + def test_extra_stacklevel(): - @deprecated.classic.deprecated(version='1.2.1', reason="deprecated function", extra_stacklevel=1) - def inner(): + """ + The unit test utilizes an 'extra_stacklevel' of 1 to ensure that the warning message + accurately identifies the caller of the deprecated function. It verifies that when + the 'use_foo' function is called, the warning message correctly indicates the line + where the call to 'use_foo' is made. + """ + + @deprecated.classic.deprecated(extra_stacklevel=1) + def foo(): pass - - def outer(): - inner() - warnings.simplefilter("default", category=DeprecationWarning) + def use_foo(): + foo() + + def demo(): + use_foo() + with warnings.catch_warnings(record=True) as warns: - outer() - outer() - assert len(warns) == 2 + warnings.simplefilter("always") + demo() + + # Check that the warning path matches the module path + warn = warns[0] + assert warn.filename == __file__ + + # Check that the line number points to the first line inside 'demo' + demo_lineno = inspect.getsourcelines(demo)[1] + assert warn.lineno == demo_lineno + 1 From 0959c9c35fe056301338d0fbc016d8b829c8e731 Mon Sep 17 00:00:00 2001 From: Laurent LAPORTE Date: Sun, 9 Jul 2023 21:17:30 +0200 Subject: [PATCH 8/9] docs: fix typo and grammar in docstrings and comments --- deprecated/classic.py | 12 ++++++------ deprecated/sphinx.py | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/deprecated/classic.py b/deprecated/classic.py index 47707ac..7b36b29 100644 --- a/deprecated/classic.py +++ b/deprecated/classic.py @@ -17,7 +17,7 @@ try: # If the C extension for wrapt was compiled and wrapt/_wrappers.pyd exists, then the # stack level that should be passed to warnings.warn should be 2. However, if using - # a pure python wrapt, a extra stacklevel is required. + # a pure python wrapt, an extra stacklevel is required. import wrapt._wrappers _routine_stacklevel = 2 @@ -101,7 +101,7 @@ def __init__(self, reason="", version="", action=None, category=DeprecationWarni :param action: A warning filter used to activate or not the deprecation warning. Can be one of "error", "ignore", "always", "default", "module", or "once". - If ``None`` or empty, the the global filtering mechanism is used. + If ``None`` or empty, the global filtering mechanism is used. See: `The Warnings Filter`_ in the Python documentation. :type category: type @@ -112,7 +112,7 @@ def __init__(self, reason="", version="", action=None, category=DeprecationWarni :type extra_stacklevel: int :param extra_stacklevel: - Number of additonal stacklevels to consider instrumentation rather than user code. + Number of additional stack levels to consider instrumentation rather than user code. With the default value of 0, the warning refers to where the class was instantiated or the function was called. @@ -255,7 +255,7 @@ def some_old_function(x, y): return x + y The *category* keyword argument allow you to specify the deprecation warning class of your choice. - By default, :exc:`DeprecationWarning` is used but you can choose :exc:`FutureWarning`, + By default, :exc:`DeprecationWarning` is used, but you can choose :exc:`FutureWarning`, :exc:`PendingDeprecationWarning` or a custom subclass. .. code-block:: python @@ -269,7 +269,7 @@ def some_old_function(x, y): The *action* keyword argument allow you to locally change the warning filtering. *action* can be one of "error", "ignore", "always", "default", "module", or "once". - If ``None``, empty or missing, the the global filtering mechanism is used. + If ``None``, empty or missing, the global filtering mechanism is used. See: `The Warnings Filter`_ in the Python documentation. .. code-block:: python @@ -281,7 +281,7 @@ def some_old_function(x, y): def some_old_function(x, y): return x + y - The *extra_stacklevel* keyword argument allows you to specify additional stacklevels + The *extra_stacklevel* keyword argument allows you to specify additional stack levels to consider instrumentation rather than user code. With the default value of 0, the warning refers to where the class was instantiated or the function was called. """ diff --git a/deprecated/sphinx.py b/deprecated/sphinx.py index bd74522..ba0e21b 100644 --- a/deprecated/sphinx.py +++ b/deprecated/sphinx.py @@ -70,7 +70,7 @@ def __init__( :param action: A warning filter used to activate or not the deprecation warning. Can be one of "error", "ignore", "always", "default", "module", or "once". - If ``None`` or empty, the the global filtering mechanism is used. + If ``None`` or empty, the global filtering mechanism is used. See: `The Warnings Filter`_ in the Python documentation. :type category: type @@ -81,7 +81,7 @@ def __init__( :type extra_stacklevel: int :param extra_stacklevel: - Number of additonal stacklevels to consider instrumentation rather than user code. + Number of additional stack levels to consider instrumentation rather than user code. With the default value of 0, the warning refers to where the class was instantiated or the function was called. @@ -163,7 +163,7 @@ def get_deprecated_msg(self, wrapped, instance): """ msg = super(SphinxAdapter, self).get_deprecated_msg(wrapped, instance) - # Strip Sphinx cross reference syntax (like ":function:", ":py:func:" and ":py:meth:") + # Strip Sphinx cross-reference syntax (like ":function:", ":py:func:" and ":py:meth:") # Possible values are ":role:`foo`", ":domain:role:`foo`" # where ``role`` and ``domain`` should match "[a-zA-Z]+" msg = re.sub(r"(?: : [a-zA-Z]+ )? : [a-zA-Z]+ : (`[^`]*`)", r"\1", msg, flags=re.X) @@ -173,7 +173,7 @@ def get_deprecated_msg(self, wrapped, instance): def versionadded(reason="", version="", line_length=70): """ This decorator can be used to insert a "versionadded" directive - in your function/class docstring in order to documents the + in your function/class docstring in order to document the version of the project which adds this new functionality in your library. :param str reason: @@ -203,7 +203,7 @@ def versionadded(reason="", version="", line_length=70): def versionchanged(reason="", version="", line_length=70): """ This decorator can be used to insert a "versionchanged" directive - in your function/class docstring in order to documents the + in your function/class docstring in order to document the version of the project which modifies this functionality in your library. :param str reason: @@ -232,7 +232,7 @@ def versionchanged(reason="", version="", line_length=70): def deprecated(reason="", version="", line_length=70, **kwargs): """ This decorator can be used to insert a "deprecated" directive - in your function/class docstring in order to documents the + in your function/class docstring in order to document the version of the project which deprecates this functionality in your library. :param str reason: @@ -252,15 +252,15 @@ def deprecated(reason="", version="", line_length=70, **kwargs): - "action": A warning filter used to activate or not the deprecation warning. Can be one of "error", "ignore", "always", "default", "module", or "once". - If ``None``, empty or missing, the the global filtering mechanism is used. + If ``None``, empty or missing, the global filtering mechanism is used. - "category": The warning category to use for the deprecation warning. By default, the category class is :class:`~DeprecationWarning`, you can inherit this class to define your own deprecation warning category. - + - "extra_stacklevel": - Number of additional stacklevels to consider instrumentation rather than user code. + Number of additional stack levels to consider instrumentation rather than user code. With the default value of 0, the warning refers to where the class was instantiated or the function was called. From 75dfbfd6b0f569e6cd6f85501005bc1bad485703 Mon Sep 17 00:00:00 2001 From: Laurent LAPORTE Date: Sun, 9 Jul 2023 21:23:36 +0200 Subject: [PATCH 9/9] fix(typing): improve parameter typing --- deprecated/classic.py | 4 ++-- deprecated/sphinx.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deprecated/classic.py b/deprecated/classic.py index 7b36b29..84f683c 100644 --- a/deprecated/classic.py +++ b/deprecated/classic.py @@ -97,14 +97,14 @@ def __init__(self, reason="", version="", action=None, category=DeprecationWarni If you follow the `Semantic Versioning `_, the version number has the format "MAJOR.MINOR.PATCH". - :type action: str + :type action: Literal["default", "error", "ignore", "always", "module", "once"] :param action: A warning filter used to activate or not the deprecation warning. Can be one of "error", "ignore", "always", "default", "module", or "once". If ``None`` or empty, the global filtering mechanism is used. See: `The Warnings Filter`_ in the Python documentation. - :type category: type + :type category: Type[Warning] :param category: The warning category to use for the deprecation warning. By default, the category class is :class:`~DeprecationWarning`, diff --git a/deprecated/sphinx.py b/deprecated/sphinx.py index ba0e21b..70ef050 100644 --- a/deprecated/sphinx.py +++ b/deprecated/sphinx.py @@ -66,14 +66,14 @@ def __init__( If you follow the `Semantic Versioning `_, the version number has the format "MAJOR.MINOR.PATCH". - :type action: str + :type action: Literal["default", "error", "ignore", "always", "module", "once"] :param action: A warning filter used to activate or not the deprecation warning. Can be one of "error", "ignore", "always", "default", "module", or "once". If ``None`` or empty, the global filtering mechanism is used. See: `The Warnings Filter`_ in the Python documentation. - :type category: type + :type category: Type[Warning] :param category: The warning category to use for the deprecation warning. By default, the category class is :class:`~DeprecationWarning`,