• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

domdfcoding / deprecation-alias / 17469354358

04 Sep 2025 03:44PM UTC coverage: 96.923%. Remained the same
17469354358

Pull #51

github

web-flow
Bump pypa/gh-action-pypi-publish in /.github/workflows

Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.4.2 to 1.13.0.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/v1.4.2...v1.13.0)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-version: 1.13.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #51: Bump pypa/gh-action-pypi-publish from 1.4.2 to 1.13.0 in /.github/workflows

63 of 65 relevant lines covered (96.92%)

0.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.92
/deprecation_alias/__init__.py
1
#!/usr/bin/env python3
2
#
3
#  __init__.py
4
"""
5
A wrapper around 'deprecation' providing support for deprecated aliases.
6
"""
7
#
8
#  Copyright © 2020 Dominic Davis-Foster <dominic@davis-foster.co.uk>
9
#  License: Apache Software License
10
#  See the LICENSE file for details.
11
#
12
#  Based on https://github.com/briancurtin/deprecation
13
#  Modified to only change the docstring of the wrapper and not the original function.
14
#
15

16
# stdlib
17
import datetime
1✔
18
import functools
1✔
19
import textwrap
1✔
20
import warnings
1✔
21
from typing import Callable, Optional, Union
1✔
22

23
# 3rd party
24
import deprecation  # type: ignore
1✔
25
from packaging import version
1✔
26

27
__author__: str = "Dominic Davis-Foster"
1✔
28
__copyright__: str = "2020 Dominic Davis-Foster"
1✔
29
__license__: str = "Apache Software License"
1✔
30
__version__: str = "0.4.0"
1✔
31
__email__: str = "dominic@davis-foster.co.uk"
1✔
32

33
__all__ = ["deprecated"]
1✔
34

35

36
def deprecated(
1✔
37
                deprecated_in: Optional[str] = None,
38
                removed_in: Union[str, datetime.date, None] = None,
39
                current_version: Optional[str] = None,
40
                details: str = '',
41
                name: Optional[str] = None,
42
                func: Optional[Callable] = None,
43
                ) -> Callable:
44
        r"""Decorate a function to signify its deprecation.
45

46
        This function wraps a method that will soon be removed and does two things:
47

48
        * The docstring of the method will be modified to include a notice
49
          about deprecation, e.g., "Deprecated since 0.9.11. Use foo instead."
50
        * Raises a :class:`deprecation.DeprecatedWarning`
51
          via the :mod:`warnings` module, which is a subclass of the built-in
52
          :class:`DeprecationWarning`. Note that built-in
53
          :class:`DeprecationWarning`\s are ignored by default, so for users
54
          to be informed of said warnings they will need to enable them -- see
55
          the :mod:`warnings` module documentation for more details.
56

57
        :param deprecated_in: The version at which the decorated method is considered
58
                deprecated. This will usually be the next version to be released when
59
                the decorator is added. The default is :py:obj:`None`, which effectively
60
                means immediate deprecation. If this is not specified, then the
61
                ``removed_in`` and ``current_version`` arguments are ignored.
62
        :no-default deprecated_in:
63

64
        :param removed_in: The version or :class:`datetime.date` when the decorated
65
                method will be removed. The default is :py:obj:`None`, specifying that
66
                the function is not currently planned to be removed.
67

68
                .. note::
69

70
                        This parameter cannot be set to a value if ``deprecated_in=None``.
71

72
        :no-default removed_in:
73

74
        :param current_version: The source of version information for the currently
75
                running code. This will usually be a ``__version__`` attribute in your
76
                library. The default is :py:obj:`None`. When ``current_version=None``
77
                the automation to determine if the wrapped function is actually in
78
                a period of deprecation or time for removal does not work, causing a
79
                :class:`~deprecation.DeprecatedWarning` to be raised in all cases.
80
        :no-default current_version:
81

82
        :param details: Extra details to be added to the method docstring and
83
                warning. For example, the details may point users to a replacement
84
                method, such as "Use the foo_bar method instead".
85

86
        :param name: The name of the deprecated function, if an alias is being
87
                deprecated. Default is to the name of the decorated function.
88
        :no-default name:
89

90
        :param func: The function to deprecate. Can be used as an alternative to using the ``@deprecated(...)`` decorator.
91
                If provided ``deprecated`` can't be used as a decorator.
92
        :no-default func:
93

94
        .. versionchanged:: 0.2.0  Added the ``func`` argument.
95
        .. versionchanged:: 0.3.0  The warning in the documentation is always shown.
96
        """
97

98
        # You can't just jump to removal. It's weird, unfair, and also makes
99
        # building up the docstring weird.
100
        if deprecated_in is None and removed_in is not None:
1✔
101
                raise TypeError("Cannot set removed_in to a value without also setting deprecated_in")
1✔
102

103
        # Only warn when it's appropriate. There may be cases when it makes sense
104
        # to add this decorator before a formal deprecation period begins.
105
        # In CPython, PendingDeprecatedWarning gets used in that period,
106
        # so perhaps mimick that at some point.
107
        is_deprecated = False
1✔
108
        is_unsupported = False
1✔
109

110
        # StrictVersion won't take a None or a "", so make whatever goes to it
111
        # is at least *something*. Compare versions only if removed_in is not
112
        # of type datetime.date
113
        if isinstance(removed_in, datetime.date):
1✔
114
                if datetime.date.today() >= removed_in:
1✔
115
                        is_unsupported = True
×
116
                else:
117
                        is_deprecated = True
1✔
118
        elif current_version:
1✔
119
                current_version = version.parse(current_version)  # type: ignore
1✔
120

121
                if removed_in is not None and current_version >= version.parse(removed_in):  # type: ignore
1✔
122
                        is_unsupported = True
1✔
123
                elif deprecated_in is not None and current_version >= version.parse(deprecated_in):  # type: ignore
1✔
124
                        is_deprecated = True
1✔
125
        else:
126
                # If we can't actually calculate that we're in a period of
127
                # deprecation...well, they used the decorator, so it's deprecated.
128
                # This will cover the case of someone just using
129
                # @deprecated("1.0") without the other advantages.
130
                is_deprecated = True
×
131

132
        should_warn = any([is_deprecated, is_unsupported])
1✔
133

134
        def _function_wrapper(function):
1✔
135
                # Everything *should* have a docstring, but just in case...
136
                existing_docstring = function.__doc__ or ''
1✔
137

138
                # split docstring at first occurrence of newline
139
                string_list = existing_docstring.split('\n', 1)
1✔
140

141
                # The various parts of this decorator being optional makes for
142
                # a number of ways the deprecation notice could go. The following
143
                # makes for a nicely constructed sentence with or without any
144
                # of the parts.
145

146
                parts = {"deprecated_in": '', "removed_in": '', "details": ''}
1✔
147

148
                if deprecated_in:
1✔
149
                        parts["deprecated_in"] = f" {deprecated_in}"
1✔
150
                if removed_in:
1✔
151
                        # If removed_in is a date, use "removed on"
152
                        # If removed_in is a version, use "removed in"
153
                        if isinstance(removed_in, datetime.date):
1✔
154
                                parts["removed_in"] = f"\n   This will be removed on {removed_in}."
1✔
155
                        else:
156
                                parts["removed_in"] = f"\n   This will be removed in {removed_in}."
1✔
157
                if details:
1✔
158
                        parts["details"] = f" {details}"
1✔
159

160
                deprecation_note = ".. deprecated::{deprecated_in}{removed_in}{details}".format_map(parts)
1✔
161

162
                # default location for insertion of deprecation note
163
                loc = 1
1✔
164

165
                if len(string_list) > 1:
1✔
166
                        # With a multi-line docstring, when we modify
167
                        # existing_docstring to add our deprecation_note,
168
                        # if we're not careful we'll interfere with the
169
                        # indentation levels of the contents below the
170
                        # first line, or as PEP 257 calls it, the summary
171
                        # line. Since the summary line can start on the
172
                        # same line as the """, dedenting the whole thing
173
                        # won't help. Split the summary and contents up,
174
                        # dedent the contents independently, then join
175
                        # summary, dedent'ed contents, and our
176
                        # deprecation_note.
177

178
                        # in-place dedent docstring content
179
                        string_list[1] = textwrap.dedent(string_list[1])
1✔
180

181
                        # we need another newline
182
                        string_list.insert(loc, '\n')
1✔
183

184
                        # change the message_location if we add to end of docstring
185
                        # do this always if not "top"
186
                        if deprecation.message_location != "top":
1✔
187
                                loc = 3
1✔
188

189
                # insert deprecation note and dual newline
190
                string_list.insert(loc, deprecation_note)
1✔
191
                string_list.insert(loc, "\n\n")
1✔
192

193
                @functools.wraps(function)
1✔
194
                def _inner(*args, **kwargs):
1✔
195
                        if should_warn:
1✔
196
                                if is_unsupported:
1✔
197
                                        cls = deprecation.UnsupportedWarning
1✔
198
                                else:
199
                                        cls = deprecation.DeprecatedWarning
1✔
200

201
                                the_warning = cls(name or function.__name__, deprecated_in, removed_in, details)
1✔
202
                                warnings.warn(the_warning, category=DeprecationWarning, stacklevel=2)
1✔
203

204
                        return function(*args, **kwargs)
1✔
205

206
                _inner.__doc__ = ''.join(string_list)
1✔
207

208
                return _inner
1✔
209

210
        if func is None:
1✔
211
                return _function_wrapper
1✔
212
        else:
213
                return _function_wrapper(func)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc