Skip to content
Commits on Source (4)
[bumpversion]
current_version = 1.2.6
current_version = 1.2.7
commit = True
tag = False
message = Prepare next version {new_version} (unreleased)
......@@ -16,3 +16,7 @@ replace = __version__ = "{new_version}"
search = release = "{current_version}"
replace = release = "{new_version}"
[bumpversion:file:python-deprecated.spec]
search = (?<=Version:\s+){current_version}
replace = {new_version}
......@@ -185,7 +185,6 @@ var/
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
......
specfile_path: python-deprecated.spec
synced_files:
- python-deprecated.spec
- .packit.yaml
upstream_project_name: Deprecated
downstream_package_name: python-deprecated
create_pr: false
jobs:
- job: propose_downstream
trigger: release
metadata:
dist_git_branch: master
- job: propose_downstream
trigger: release
metadata:
dist_git_branch: f30
- job: propose_downstream
trigger: release
metadata:
dist_git_branch: f29
- job: copr_build
trigger: pull_request
metadata:
targets:
- fedora-30-x86_64
- fedora-29-x86_64
- fedora-rawhide-x86_64
......@@ -5,9 +5,9 @@ python:
- "3.4"
- "3.5"
- "3.6"
# - "3.7" # Not available yet (Unable to download 3.7 archive).
- "3.7-dev" # 3.7 development branch
- "nightly" # currently points to 3.7-dev
- "3.7"
- "3.8"
- "3.8-dev" # 3.8 development branch
# - "pypy" # some unit tests fail
install:
- pip install tox-travis
......
......@@ -18,6 +18,26 @@ and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0
(only in comment or documentation).
v1.2.7 (2019-11-11)
===================
Bug fix release
Fix
---
- Warning displays the correct filename and line number when decorating a function if wrapt
does not have the compiled c extension.
Other
-----
- Support packit for Pull Request tests and sync to Fedora (thanks to Petr Hráček).
Supported since v1.2.6.
- Add `Black <https://black.readthedocs.io/en/latest/>`_ configuration file.
v1.2.6 (2019-07-06)
===================
......
python-deprecated (1.2.6-2) UNRELEASED; urgency=medium
python-deprecated (1.2.7-1) unstable; urgency=medium
* New upstream release.
* Bump Standards-Version to 4.4.1, no changes.
-- Bas Couwenberg <sebastic@debian.org> Mon, 30 Sep 2019 19:51:11 +0200
-- Bas Couwenberg <sebastic@debian.org> Tue, 12 Nov 2019 05:32:12 +0100
python-deprecated (1.2.6-1) unstable; urgency=medium
......
......@@ -8,6 +8,6 @@ Python ``@deprecated`` decorator to deprecate old python classes, functions or m
"""
#: Module Version Number, see `PEP 396 <https://www.python.org/dev/peps/pep-0396/>`_.
__version__ = "1.2.6"
__version__ = "1.2.7"
from deprecated.classic import deprecated
......@@ -12,6 +12,16 @@ import warnings
import wrapt
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.
import wrapt._wrappers
_stacklevel = 2
except ImportError:
_stacklevel = 3
string_types = (type(b''), type(u''))
......@@ -122,9 +132,7 @@ class ClassicAdapter(wrapt.AdapterFactory):
fmt += " ({reason})"
if self.version:
fmt += " -- Deprecated since version {version}."
return fmt.format(name=wrapped.__name__,
reason=self.reason or "",
version=self.version or "")
return fmt.format(name=wrapped.__name__, reason=self.reason or "", version=self.version or "")
def __call__(self, wrapped):
"""
......@@ -229,7 +237,7 @@ def deprecated(*args, **kwargs):
msg = adapter.get_deprecated_msg(wrapped_, instance_)
with warnings.catch_warnings():
warnings.simplefilter(action, category)
warnings.warn(msg, category=category, stacklevel=2)
warnings.warn(msg, category=category, stacklevel=_stacklevel)
return wrapped_(*args_, **kwargs_)
return wrapper_function(wrapped)
......
......@@ -82,8 +82,9 @@ class SphinxAdapter(ClassicAdapter):
:return: the decorated class or function.
"""
reason = textwrap.dedent(self.reason).strip()
reason = '\n'.join(textwrap.fill(line, width=70, initial_indent=' ', subsequent_indent=' ')
for line in reason.splitlines()).strip()
reason = '\n'.join(
textwrap.fill(line, width=70, initial_indent=' ', subsequent_indent=' ') for line in reason.splitlines()
).strip()
docstring = textwrap.dedent(wrapped.__doc__ or "")
if docstring:
docstring += "\n\n"
......@@ -180,7 +181,4 @@ def deprecated(*args, **kwargs):
"""
directive = kwargs.pop('directive', 'deprecated')
adapter_cls = kwargs.pop('adapter_cls', SphinxAdapter)
return _classic_deprecated(*args,
directive=directive,
adapter_cls=adapter_cls,
**kwargs)
return _classic_deprecated(*args, directive=directive, adapter_cls=adapter_cls, **kwargs)
......@@ -31,11 +31,13 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.autodoc',
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.intersphinx',
'sphinx.ext.coverage',
'sphinx.ext.githubpages']
'sphinx.ext.githubpages',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
......@@ -59,7 +61,7 @@ author = 'Marcos CARDOSO & Laurent LAPORTE'
# built documents.
#
# The full version, including alpha/beta/rc tags.
release = "1.2.6"
release = "1.2.7"
# The short X.Y version.
version = release.rpartition('.')[0]
......@@ -143,18 +145,14 @@ latex_elements = {
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'Deprecated.tex', 'Deprecated Documentation',
'Marcos CARDOSO and Laurent LAPORTE', 'manual'),
(master_doc, 'Deprecated.tex', 'Deprecated Documentation', 'Marcos CARDOSO and Laurent LAPORTE', 'manual')
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'deprecated', 'Deprecated Documentation',
[author], 1)
]
man_pages = [(master_doc, 'deprecated', 'Deprecated Documentation', [author], 1)]
# -- Options for Texinfo output -------------------------------------------
......@@ -162,17 +160,23 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'Deprecated', 'Deprecated Documentation',
author, 'Deprecated', 'Python @deprecated decorator to deprecate old python classes, functions or methods.',
'Miscellaneous'),
(
master_doc,
'Deprecated',
'Deprecated Documentation',
author,
'Deprecated',
'Python @deprecated decorator to deprecate old python classes, functions or methods.',
'Miscellaneous',
)
]
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'https://docs.python.org/3/': None,
intersphinx_mapping = {
'https://docs.python.org/3/': None,
'https://wrapt.readthedocs.io/en/latest/': None,
'http://flask.pocoo.org/docs/1.0/': None,
'django': ('https://docs.djangoproject.com/en/2.1/',
'https://docs.djangoproject.com/en/2.1/_objects/'),
'django': ('https://docs.djangoproject.com/en/2.1/', 'https://docs.djangoproject.com/en/2.1/_objects/'),
}
# -- Options for EPub output -------------------------------------------
......@@ -182,9 +186,8 @@ epub_theme = 'epub'
epub_theme_options = {
# relbar1: If this is true, the relbar1 block is inserted in the epub output, otherwise it is omitted.
'relbar1': False,
# footer: If this is true, the footer block is inserted in the epub output, otherwise it is omitted.
'footer': False
'footer': False,
}
epub_title = "Python Deprecated Library v1.2 Documentation"
epub_description = "Python @deprecated decorator to deprecate old python classes, functions or methods."
......
......@@ -14,15 +14,15 @@ from deprecated.sphinx import versionchanged
Just guess!
""",
version='0.3.0')
version='0.3.0',
)
@versionchanged(
reason='Well, I add a new feature in this function. '
'It is very useful as you can see in the example below, so try it. '
'This is a very very very very very long sentence.',
version='0.2.0')
@versionadded(
reason='Here is my new function.',
version='0.1.0')
version='0.2.0',
)
@versionadded(reason='Here is my new function.', version='0.1.0')
def successor(n):
"""
Calculate the successor of a number.
......
[tool.black]
line-length = 120
skip-string-normalization = true
target-version = ['py27', 'py34', 'py35', 'py36', 'py37', 'py38']
include = '\.pyi?$'
%global srcname Deprecated
%global pkgname deprecated
Name: python-%{pkgname}
Version: 1.2.7
Release: 2%{?dist}
Summary: Python decorator to deprecate old python classes, functions or methods
License: MIT
URL: https://github.com/tantale/%{pkgname}
Source0: https://files.pythonhosted.org/packages/source/D/%{srcname}/%{srcname}-%{version}.tar.gz
BuildArch: noarch
%description
Python @deprecated decorator to deprecate old python classes,
functions or methods.
%package -n python3-%{pkgname}
Summary: %{summary}
BuildRequires: python3-devel
BuildRequires: python3-setuptools
%{?python_provide:%python_provide python3-%{pkgname}}
%description -n python3-%{pkgname}
Python @deprecated decorator to deprecate old python classes,
functions or methods.
%prep
%autosetup -n %{srcname}-%{version}
rm -rf %{pkgname}.egg-info
%build
%py3_build
%install
%py3_install
%files -n python3-%{pkgname}
%license LICENSE.rst
%doc README.md
%{python3_sitelib}/%{pkgname}/
%{python3_sitelib}/%{srcname}-%{version}-*.egg-info/
%changelog
* Fri Jul 26 2019 Petr Hracek <phracek@redhat.com> - 1.2.7-2
- Fix python3_sitelib issue
* Fri Jul 26 2019 Petr Hracek <phracek@redhat.com> - 1.2.7-1
- Initial package
......@@ -143,12 +143,13 @@ from setuptools import setup
setup(
name='Deprecated',
version='1.2.6',
version='1.2.7',
url='https://github.com/tantale/deprecated',
project_urls={
"Documentation": "https://deprecated.readthedocs.io/en/latest/",
"Source": "https://github.com/tantale/deprecated",
"Bug Tracker": "https://github.com/tantale/deprecated/issues"},
"Bug Tracker": "https://github.com/tantale/deprecated/issues",
},
license='MIT',
author='Laurent LAPORTE', # since v1.1.0
author_email='tantale.solutions@gmail.com',
......@@ -156,9 +157,7 @@ setup(
long_description=__doc__,
keywords='deprecate,deprecated,deprecation,warning,warn,decorator',
packages=['deprecated'],
install_requires=[
'wrapt < 2, >= 1.10',
],
install_requires=['wrapt < 2, >= 1.10'],
zip_safe=False,
include_package_data=True,
platforms='any',
......@@ -176,7 +175,7 @@ setup(
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Topic :: Software Development :: Libraries :: Python Modules'
'Topic :: Software Development :: Libraries :: Python Modules',
],
extras_require={
'dev': [
......@@ -187,8 +186,7 @@ setup(
'PyTest-Cov < 2.6 ; python_version < "3"',
'bumpversion < 1',
'sphinx < 2',
],
]
},
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
)
......@@ -10,7 +10,8 @@ class MyDeprecationWarning(DeprecationWarning):
pass
_PARAMS = [None,
_PARAMS = [
None,
((), {}),
(('Good reason',), {}),
((), {'reason': 'Good reason'}),
......@@ -23,6 +24,7 @@ _PARAMS = [None,
@pytest.fixture(scope="module", params=_PARAMS)
def classic_deprecated_function(request):
if request.param is None:
@deprecated.classic.deprecated
def foo1():
pass
......@@ -41,6 +43,7 @@ def classic_deprecated_function(request):
@pytest.fixture(scope="module", params=_PARAMS)
def classic_deprecated_class(request):
if request.param is None:
@deprecated.classic.deprecated
class Foo2(object):
pass
......@@ -59,6 +62,7 @@ def classic_deprecated_class(request):
@pytest.fixture(scope="module", params=_PARAMS)
def classic_deprecated_method(request):
if request.param is None:
class Foo3(object):
@deprecated.classic.deprecated
def foo3(self):
......@@ -79,6 +83,7 @@ def classic_deprecated_method(request):
@pytest.fixture(scope="module", params=_PARAMS)
def classic_deprecated_static_method(request):
if request.param is None:
class Foo4(object):
@staticmethod
@deprecated.classic.deprecated
......@@ -101,6 +106,7 @@ def classic_deprecated_static_method(request):
@pytest.fixture(scope="module", params=_PARAMS)
def classic_deprecated_class_method(request):
if request.param is None:
class Foo5(object):
@classmethod
@deprecated.classic.deprecated
......@@ -129,6 +135,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'
# noinspection PyShadowingNames
......@@ -140,6 +147,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'
# noinspection PyShadowingNames
......@@ -152,6 +160,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'
# noinspection PyShadowingNames
......@@ -163,6 +172,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'
# noinspection PyShadowingNames
......@@ -175,6 +185,7 @@ def test_classic_deprecated_class_method__warns(classic_deprecated_class_method)
warn = warns[0]
assert issubclass(warn.category, DeprecationWarning)
assert "deprecated function (or staticmethod)" in str(warn.message)
assert warn.filename == __file__, 'Incorrect warning stackLevel'
def test_should_raise_type_error():
......
......@@ -11,7 +11,6 @@ def with_metaclass(meta, *bases):
# metaclass for one level of class instantiation that replaces itself with
# the actual metaclass.
class metaclass(type):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
......@@ -71,7 +70,6 @@ def test_with_metaclass():
@deprecated.classic.deprecated
class MyClass(with_metaclass(Meta)):
def __init__(self, a, b=5):
self.a = a
self.b = b
......@@ -98,7 +96,6 @@ def test_with_singleton_metaclass():
@deprecated.classic.deprecated
class MyClass(with_metaclass(Singleton)):
def __init__(self, a, b=5):
self.a = a
self.b = b
......
......@@ -11,8 +11,10 @@ import pytest
import deprecated.sphinx
@pytest.fixture(scope="module",
params=[None,
@pytest.fixture(
scope="module",
params=[
None,
"""This function adds *x* and *y*.""",
"""
This function adds *x* and *y*.
......@@ -20,37 +22,53 @@ import deprecated.sphinx
:param x: number *x*
:param y: number *y*
:return: sum = *x* + *y*
"""])
""",
],
)
def docstring(request):
return request.param
@pytest.fixture(scope="module",
params=['versionadded', 'versionchanged', 'deprecated'])
@pytest.fixture(scope="module", params=['versionadded', 'versionchanged', 'deprecated'])
def directive(request):
return request.param
# noinspection PyShadowingNames
@pytest.mark.parametrize("reason, version, expected", [
('A good reason',
@pytest.mark.parametrize(
"reason, version, expected",
[
(
'A good reason',
'1.2.0',
textwrap.dedent("""\
textwrap.dedent(
"""\
.. {directive}:: {version}
{reason}
""")),
(None,
"""
),
),
(
None,
'1.2.0',
textwrap.dedent("""\
textwrap.dedent(
"""\
.. {directive}:: {version}
""")),
('A good reason',
"""
),
),
(
'A good reason',
None,
textwrap.dedent("""\
textwrap.dedent(
"""\
.. {directive}::
{reason}
""")),
])
"""
),
),
],
)
def test_has_sphinx_docstring(docstring, directive, reason, version, expected):
# The function:
def foo(x, y):
......@@ -77,27 +95,43 @@ def test_has_sphinx_docstring(docstring, directive, reason, version, expected):
# noinspection PyShadowingNames
@pytest.mark.skipif(sys.version_info < (3, 3),
reason="Classes should have mutable docstrings -- resolved in python 3.3")
@pytest.mark.parametrize("reason, version, expected", [
('A good reason',
@pytest.mark.skipif(
sys.version_info < (3, 3), reason="Classes should have mutable docstrings -- resolved in python 3.3"
)
@pytest.mark.parametrize(
"reason, version, expected",
[
(
'A good reason',
'1.2.0',
textwrap.dedent("""\
textwrap.dedent(
"""\
.. {directive}:: {version}
{reason}
""")),
(None,
"""
),
),
(
None,
'1.2.0',
textwrap.dedent("""\
textwrap.dedent(
"""\
.. {directive}:: {version}
""")),
('A good reason',
"""
),
),
(
'A good reason',
None,
textwrap.dedent("""\
textwrap.dedent(
"""\
.. {directive}::
{reason}
""")),
])
"""
),
),
],
)
def test_cls_has_sphinx_docstring(docstring, directive, reason, version, expected):
# The class:
class Foo(object):
......@@ -127,7 +161,8 @@ class MyDeprecationWarning(DeprecationWarning):
pass
_PARAMS = [None,
_PARAMS = [
None,
((), {}),
(('Good reason',), {}),
((), {'reason': 'Good reason'}),
......@@ -140,6 +175,7 @@ _PARAMS = [None,
@pytest.fixture(scope="module", params=_PARAMS)
def sphinx_deprecated_function(request):
if request.param is None:
@deprecated.sphinx.deprecated
def foo1():
pass
......@@ -158,6 +194,7 @@ def sphinx_deprecated_function(request):
@pytest.fixture(scope="module", params=_PARAMS)
def sphinx_deprecated_class(request):
if request.param is None:
@deprecated.sphinx.deprecated
class Foo2(object):
pass
......@@ -176,6 +213,7 @@ def sphinx_deprecated_class(request):
@pytest.fixture(scope="module", params=_PARAMS)
def sphinx_deprecated_method(request):
if request.param is None:
class Foo3(object):
@deprecated.sphinx.deprecated
def foo3(self):
......@@ -196,6 +234,7 @@ def sphinx_deprecated_method(request):
@pytest.fixture(scope="module", params=_PARAMS)
def sphinx_deprecated_static_method(request):
if request.param is None:
class Foo4(object):
@staticmethod
@deprecated.sphinx.deprecated
......@@ -218,6 +257,7 @@ def sphinx_deprecated_static_method(request):
@pytest.fixture(scope="module", params=_PARAMS)
def sphinx_deprecated_class_method(request):
if request.param is None:
class Foo5(object):
@classmethod
@deprecated.sphinx.deprecated
......@@ -249,8 +289,9 @@ def test_sphinx_deprecated_function__warns(sphinx_deprecated_function):
# noinspection PyShadowingNames
@pytest.mark.skipif(sys.version_info < (3, 3),
reason="Classes should have mutable docstrings -- resolved in python 3.3")
@pytest.mark.skipif(
sys.version_info < (3, 3), reason="Classes should have mutable docstrings -- resolved in python 3.3"
)
def test_sphinx_deprecated_class__warns(sphinx_deprecated_class):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter("always")
......
......@@ -41,8 +41,9 @@ def test_class_deprecation_using_a_simple_decorator():
assert stream.getvalue().strip() == u"I am deprecated!"
@pytest.mark.skipif(sys.version_info < (3, 3),
reason="Classes should have mutable docstrings -- resolved in python 3.3")
@pytest.mark.skipif(
sys.version_info < (3, 3), reason="Classes should have mutable docstrings -- resolved in python 3.3"
)
def test_class_deprecation_using_deprecated_decorator():
@deprecated.sphinx.deprecated
class MyBaseClass(object):
......@@ -61,8 +62,9 @@ def test_class_deprecation_using_deprecated_decorator():
assert issubclass(MySubClass, MyBaseClass)
@pytest.mark.skipif(sys.version_info < (3, 3),
reason="Classes should have mutable docstrings -- resolved in python 3.3")
@pytest.mark.skipif(
sys.version_info < (3, 3), reason="Classes should have mutable docstrings -- resolved in python 3.3"
)
def test_subclass_deprecation_using_deprecated_decorator():
@deprecated.sphinx.deprecated
class MyBaseClass(object):
......
......@@ -11,7 +11,6 @@ def with_metaclass(meta, *bases):
# metaclass for one level of class instantiation that replaces itself with
# the actual metaclass.
class metaclass(type):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
......@@ -71,7 +70,6 @@ def test_with_metaclass():
@deprecated.classic.deprecated
class MyClass(with_metaclass(Meta)):
def __init__(self, a, b=5):
self.a = a
self.b = b
......@@ -98,7 +96,6 @@ def test_with_singleton_metaclass():
@deprecated.classic.deprecated
class MyClass(with_metaclass(Singleton)):
def __init__(self, a, b=5):
self.a = a
self.b = b
......
......@@ -9,7 +9,7 @@
[tox]
# py32 not supported by tox and pytest
envlist =
py{27,34,35,36,37}-wrapt{1.10,1.11}
py{27,34,35,36,37,38}-wrapt{1.10,1.11}
pypy
docs
......@@ -18,9 +18,9 @@ commands = pytest --cov-report term-missing --cov=deprecated tests/
deps =
py27,py34,py35: pip >= 9.0.3, < 19.2
py27,py34: PyTest < 5
py35,py36,py37,pypy: PyTest
py35,py36,py37,py38,pypy: PyTest
py27,py34: PyTest-Cov < 2.6
py35,py36,py37,pypy: PyTest-Cov
py35,py36,py37,py38,pypy: PyTest-Cov
wrapt1.10: wrapt ~= 1.10.0
wrapt1.11: wrapt ~= 1.11.0
......