From d2052638e363ce38a7a69019916b15efd3cc4672 Mon Sep 17 00:00:00 2001 From: Jason Madden Date: Wed, 2 Aug 2017 10:34:43 -0500 Subject: [PATCH 1/2] Drop Python 3.3 - Run doctests on all versions of Python. - Badges in README.rst --- .coveragerc | 4 ++ .travis.yml | 7 ++-- CHANGES.rst | 2 + README.rst | 20 +++++----- docs/api.rst | 103 ++++++++++++++++++++++++++++----------------------- setup.py | 1 - tox.ini | 16 ++++---- 7 files changed, 84 insertions(+), 69 deletions(-) diff --git a/.coveragerc b/.coveragerc index 1ec95d8..75842f7 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,5 +1,9 @@ [run] source = zope.deprecation +omit = + *old_location.py + */new_package/* + */old_package/* [report] exclude_lines = diff --git a/.travis.yml b/.travis.yml index 707f8cd..25aa140 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,15 +2,14 @@ language: python sudo: false python: - 2.7 - - 3.3 - 3.4 - 3.5 - 3.6 - pypy-5.6.0 - - pypy3.3-5.5-alpha + - pypy3.5-5.8.0 script: - coverage run -m zope.testrunner --test-path=src - + - coverage run -a -m sphinx -b doctest -d docs/_build/doctrees docs docs/_build/doctest after_success: - coveralls notifications: @@ -19,7 +18,7 @@ notifications: install: - pip install -U pip setuptools - pip install -U coveralls coverage - - pip install -U -e ".[test]" + - pip install -U -e ".[test,docs]" cache: pip diff --git a/CHANGES.rst b/CHANGES.rst index 8f7459e..bb143ce 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -11,6 +11,8 @@ - Add support for Python 3.6. +- Drop support for Python 3.3. + 4.2.0 (2016-11-07) ================== diff --git a/README.rst b/README.rst index c3b342f..93b625b 100644 --- a/README.rst +++ b/README.rst @@ -3,23 +3,25 @@ ====================== .. image:: https://img.shields.io/pypi/v/zope.deprecation.svg - :target: https://pypi.python.org/pypi/zope.deprecation/ - :alt: Latest Version + :target: https://pypi.python.org/pypi/zope.deprecation/ + :alt: Latest release + +.. image:: https://img.shields.io/pypi/pyversions/zope.deprecation.svg + :target: https://pypi.org/project/zope.deprecation/ + :alt: Supported Python versions .. image:: https://travis-ci.org/zopefoundation/zope.deprecation.png?branch=master :target: https://travis-ci.org/zopefoundation/zope.deprecation - :alt: Build Status - -.. image:: https://readthedocs.org/projects/zopedeprecation/badge/?version=latest - :target: http://zopedeprecation.readthedocs.io/en/latest/ - :alt: Documentation Status .. image:: https://coveralls.io/repos/github/zopefoundation/zope.deprecation/badge.svg?branch=master :target: https://coveralls.io/github/zopefoundation/zope.deprecation?branch=master - :alt: Coverage Status + +.. image:: https://readthedocs.org/projects/zopedeprecation/badge/?version=latest + :target: httpl://zopedeprecation.readthedocs.io/en/latest/ + :alt: Documentation Status This package provides a simple function called ``deprecated(names, reason)`` to mark deprecated modules, classes, functions, methods and properties. -Please see http://zopedeprecation.readthedocs.io for the documentation. +Please see https://zopedeprecation.readthedocs.io for the documentation. diff --git a/docs/api.rst b/docs/api.rst index d2e639a..053d555 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,8 +1,9 @@ -:mod:`zope.deprecation` API -=========================== +============================= + :mod:`zope.deprecation` API +============================= Deprecating objects inside a module ------------------------------------ +=================================== Let's start with a demonstration of deprecating any name inside a module. To demonstrate the functionality, First, let's set up an example module containing @@ -17,27 +18,27 @@ fixtures we will use: >>> zope.deprecation.__path__.append(tmp_d) >>> doctest_ex = '''\ ... from . import deprecated - ... - ... def demo1(): #pragma NO COVER (used only in doctests) + ... + ... def demo1(): ... return 1 ... deprecated('demo1', 'demo1 is no more.') - ... - ... def demo2(): #pragma NO COVER (used only in doctests) + ... + ... def demo2(): ... return 2 ... deprecated('demo2', 'demo2 is no more.') - ... - ... def demo3(): #pragma NO COVER (used only in doctests) + ... + ... def demo3(): ... return 3 ... deprecated('demo3', 'demo3 is no more.') - ... - ... def demo4(): #pragma NO COVER (used only in doctests) + ... + ... def demo4(): ... return 4 - ... def deprecatedemo4(): #pragma NO COVER (used only in doctests) + ... def deprecatedemo4(): ... """Demonstrate that deprecated() also works in a local scope.""" ... deprecated('demo4', 'demo4 is no more.') ... ''' >>> with open(os.path.join(tmp_d, 'doctest_ex.py'), 'w') as f: - ... f.write(doctest_ex) + ... _ = f.write(doctest_ex) The first argument to the ``deprecated()`` function is a list of names that should be declared deprecated. If the first argument is a string, it is @@ -55,9 +56,9 @@ Let's now see how the deprecation warnings are displayed. ... del warnings.filters[:] ... doctest_ex.demo1() 1 - >>> print log[0].category.__name__ + >>> print(log[0].category.__name__) DeprecationWarning - >>> print log[0].message + >>> print(log[0].message) demo1: demo1 is no more. >>> import zope.deprecation.doctest_ex @@ -65,7 +66,7 @@ Let's now see how the deprecation warnings are displayed. ... del warnings.filters[:] ... zope.deprecation.doctest_ex.demo2() 2 - >>> print log[0].message + >>> print(log[0].message) demo2: demo2 is no more. You can see that merely importing the affected module or one of its parents @@ -78,7 +79,7 @@ name directly, the deprecation warning will be raised immediately. >>> with warnings.catch_warnings(record=True) as log: ... del warnings.filters[:] ... from zope.deprecation.doctest_ex import demo3 - >>> print log[0].message + >>> print(log[0].message) demo3: demo3 is no more. Deprecation can also happen inside a function. When we first access @@ -99,12 +100,12 @@ the next access: ... del warnings.filters[:] ... doctest_ex.demo4() 4 - >>> print log[0].message + >>> print(log[0].message) demo4: demo4 is no more. Deprecating methods and properties ----------------------------------- +================================== New let's see how properties and methods can be deprecated. We are going to use the same function as before, except that this time, we do not pass in names @@ -141,7 +142,7 @@ And here is the result: ... del warnings.filters[:] ... my.foo 1 - >>> print log[0].message + >>> print(log[0].message) foo is no more. >>> with warnings.catch_warnings(record=True) as log: ... del warnings.filters[:] @@ -153,7 +154,7 @@ And here is the result: ... del warnings.filters[:] ... my.blah() 3 - >>> print log[0].message + >>> print(log[0].message) blah() is no more. >>> with warnings.catch_warnings(record=True) as log: ... del warnings.filters[:] @@ -165,12 +166,12 @@ And here is the result: ... del warnings.filters[:] ... my.clap() 5 - >>> print log[0].message + >>> print(log[0].message) clap() is no more. Deprecating modules -------------------- +=================== It is also possible to deprecate whole modules. This is useful when creating module aliases for backward compatibility. Let's imagine, @@ -191,7 +192,7 @@ our deprecation message as expected: >>> with warnings.catch_warnings(record=True) as log: ... del warnings.filters[:] ... from zope.wanda import deprecated - >>> print log[0].message + >>> print(log[0].message) A module called Wanda is now zope.deprecation. Before we move on, we should clean up: @@ -203,7 +204,7 @@ Before we move on, we should clean up: Moving modules --------------- +============== When a module is moved, you often want to support importing from the old location for a while, generating a deprecation warning when @@ -222,27 +223,30 @@ module on the new location should be used: >>> def create_module(modules=(), **kw): #** highlightfail ... modules = dict(modules) ... modules.update(kw) - ... modules.update(kw) ... for name, src in sorted(modules.items()): ... pname = name.split('.') ... if pname[-1] == '__init__': ... os.mkdir(os.path.join(tmp_d, *pname[:-1])) #* highlightfail ... name = '.'.join(pname[:-1]) - ... open(os.path.join(tmp_d, *pname)+'.py', 'w').write(src) #* hf + ... with open(os.path.join(tmp_d, *pname) + '.py', 'w') as f: + ... f.write(src) #* hf ... created_modules.append(name) + ... import importlib + ... if hasattr(importlib, 'invalidate_caches'): + ... importlib.invalidate_caches() >>> create_module(old_location= ... ''' ... import zope.deprecation ... zope.deprecation.moved('zope.deprecation.new_location', 'version 2') ... ''') - + and we define the module in the new location: .. doctest:: >>> create_module(new_location= ... '''\ - ... print "new module imported" + ... print("new module imported") ... x = 42 ... ''') @@ -255,7 +259,7 @@ the old location: ... del warnings.filters[:] ... import zope.deprecation.old_location new module imported - >>> print log[0].message + >>> print(log[0].message) ... # doctest: +NORMALIZE_WHITESPACE zope.deprecation.old_location has moved to zope.deprecation.new_location. Import of zope.deprecation.old_location will become unsupported @@ -264,29 +268,29 @@ the old location: 42 Moving packages ---------------- +=============== -When moving packages, you need to leave placeholders for each +When moving packages, you need to leave placeholders for each module. Let's look at an example: .. doctest:: >>> create_module({ ... 'new_package.__init__': '''\ - ... print __name__, 'imported' + ... print(__name__ + ' imported') ... x=0 ... ''', ... 'new_package.m1': '''\ - ... print __name__, 'imported' + ... print(__name__ + ' imported') ... x=1 ... ''', ... 'new_package.m2': '''\ - ... print __name__, 'imported' + ... print(__name__ + ' imported') ... def x(): ... pass ... ''', ... 'new_package.m3': '''\ - ... print __name__, 'imported' + ... print(__name__ + ' imported') ... x=3 ... ''', ... 'old_package.__init__': '''\ @@ -312,7 +316,7 @@ Now, if we import the old modules, we'll get warnings: ... del warnings.filters[:] ... import zope.deprecation.old_package zope.deprecation.new_package imported - >>> print log[0].message + >>> print(log[0].message) ... # doctest: +NORMALIZE_WHITESPACE zope.deprecation.old_package has moved to zope.deprecation.new_package. Import of zope.deprecation.old_package will become unsupported in version 2 @@ -323,7 +327,7 @@ Now, if we import the old modules, we'll get warnings: ... del warnings.filters[:] ... import zope.deprecation.old_package.m1 zope.deprecation.new_package.m1 imported - >>> print log[0].message + >>> print(log[0].message) ... # doctest: +NORMALIZE_WHITESPACE zope.deprecation.old_package.m1 has moved to zope.deprecation.new_package.m1. Import of zope.deprecation.old_package.m1 will become unsupported in @@ -335,7 +339,7 @@ Now, if we import the old modules, we'll get warnings: ... del warnings.filters[:] ... import zope.deprecation.old_package.m2 zope.deprecation.new_package.m2 imported - >>> print log[0].message + >>> print(log[0].message) ... # doctest: +NORMALIZE_WHITESPACE zope.deprecation.old_package.m2 has moved to zope.deprecation.new_package.m2. Import of zope.deprecation.old_package.m2 will become unsupported in @@ -343,7 +347,7 @@ Now, if we import the old modules, we'll get warnings: >>> zope.deprecation.old_package.m2.x is zope.deprecation.new_package.m2.x True - >>> (zope.deprecation.old_package.m2.x.func_globals + >>> (zope.deprecation.old_package.m2.x.__globals__ ... is zope.deprecation.new_package.m2.__dict__) True @@ -351,14 +355,19 @@ Now, if we import the old modules, we'll get warnings: 'zope.deprecation.new_package.m2' We'll get an error if we try to import m3, because we didn't create a -placeholder for it: +placeholder for it (Python 3.6 started raising ModuleNotFoundError, a +subclass of ImportError with a different error message than earlier +releases so we can't see that directly): .. doctest:: - >>> import zope.deprecation.old_package.m3 - Traceback (most recent call last): - ... - ImportError: No module named m3 + >>> try: + ... import zope.deprecation.old_package.m3 + ... except ImportError as e: + ... print("No module named" in str(e)) + ... print("m3" in str(e)) + True + True Before we move on, let's clean up the temporary modules / packages: @@ -371,7 +380,7 @@ Before we move on, let's clean up the temporary modules / packages: Temporarily turning off deprecation warnings --------------------------------------------- +============================================ In some cases it is desireable to turn off the deprecation warnings for a short time. @@ -420,7 +429,7 @@ Inside a suppressor's scope, that status is always false: ... del warnings.filters[:] ... foo.bar 1 - >>> print log[0].message + >>> print(log[0].message) bar is no more. If needed, your code can manage the depraction warnings manually using diff --git a/setup.py b/setup.py index 38813bc..b72a779 100644 --- a/setup.py +++ b/setup.py @@ -47,7 +47,6 @@ def read(*rnames): "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", diff --git a/tox.ini b/tox.ini index 98e115b..3101b6b 100644 --- a/tox.ini +++ b/tox.ini @@ -1,26 +1,28 @@ [tox] envlist = - py27,py33,py34,py35,py36,pypy,pypy3,coverage,docs + py27,py34,py35,py36,pypy,pypy3 [testenv] +usedevelop = true commands = coverage run -m zope.testrunner --test-path=src [] + coverage run -a -m sphinx -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest deps = - .[test] + .[test,docs] coverage setenv = COVERAGE_FILE=.coverage.{envname} [testenv:coverage] +usedevelop = true setenv = COVERAGE_FILE=.coverage -skip_install = true commands = coverage erase coverage combine - coverage report - coverage html - coverage xml + coverage report -i + coverage html -i + coverage xml -i [testenv:docs] basepython = @@ -28,5 +30,3 @@ basepython = commands = sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest -deps = - Sphinx From 219fac0e90770ac84132dac64ee772cc440ddb43 Mon Sep 17 00:00:00 2001 From: Jason Madden Date: Wed, 2 Aug 2017 13:09:39 -0500 Subject: [PATCH 2/2] 100% coverage in any given individual python environment. Restore docs env to default list. --- src/zope/deprecation/deprecation.py | 7 +------ tox.ini | 14 ++------------ 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/zope/deprecation/deprecation.py b/src/zope/deprecation/deprecation.py index d114650..6f90723 100644 --- a/src/zope/deprecation/deprecation.py +++ b/src/zope/deprecation/deprecation.py @@ -21,12 +21,7 @@ import types import warnings -PY3 = sys.version_info[0] == 3 - -if PY3: - str_and_sequence_types = (str, list, tuple) -else: - str_and_sequence_types = (basestring, list, tuple) +str_and_sequence_types = (str if str is not bytes else basestring, list, tuple) class ShowSwitch(object): """Simple stack-based switch.""" diff --git a/tox.ini b/tox.ini index 3101b6b..e14aa31 100644 --- a/tox.ini +++ b/tox.ini @@ -1,29 +1,19 @@ [tox] envlist = - py27,py34,py35,py36,pypy,pypy3 + py27,py34,py35,py36,pypy,pypy3,docs [testenv] usedevelop = true commands = coverage run -m zope.testrunner --test-path=src [] coverage run -a -m sphinx -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest + coverage report -i --fail-under=100 deps = .[test,docs] coverage setenv = COVERAGE_FILE=.coverage.{envname} -[testenv:coverage] -usedevelop = true -setenv = - COVERAGE_FILE=.coverage -commands = - coverage erase - coverage combine - coverage report -i - coverage html -i - coverage xml -i - [testenv:docs] basepython = python2.7