Hello community, here is the log from the commit of package python-venusian for openSUSE:Factory checked in at 2015-02-06 22:38:15 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-venusian (Old) and /work/SRC/openSUSE:Factory/.python-venusian.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-venusian" Changes: -------- --- /work/SRC/openSUSE:Factory/python-venusian/python-venusian.changes 2014-01-02 09:12:53.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.python-venusian.new/python-venusian.changes 2015-02-06 22:38:15.000000000 +0100 @@ -1,0 +2,14 @@ +Fri Feb 6 11:12:24 UTC 2015 - h...@urpla.net + +- update to version 1.0 + - Fix an issue under PyPy > 2.0 where attached decorators may not be found. + - Drop support of Python 2.4 / 2.5 / Jython. + - Add lift and onlyliftedfrom class decorators to allow for inheritance of + venusian decorators attached to superclass methods. See the API + documentation for more information. + - Fix bug where otherwise undecorated subclass of a superclass that had + venusian decorators on it would inherit its superclass’ decorations. + Venusian decorators should have never been inherited implicitly. See + https://github.com/Pylons/venusian/issues/11#issuecomment-4977352 + +------------------------------------------------------------------- Old: ---- venusian-1.0a8.tar.gz New: ---- venusian-1.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-venusian.spec ++++++ --- /var/tmp/diff_new_pack.vY09Et/_old 2015-02-06 22:38:16.000000000 +0100 +++ /var/tmp/diff_new_pack.vY09Et/_new 2015-02-06 22:38:16.000000000 +0100 @@ -1,8 +1,8 @@ # # spec file for package python-venusian # -# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. -# Copyright (c) 2013 LISA GmbH, Bingen, Germany. +# Copyright (c) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2015 LISA GmbH, Bingen, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,12 +12,13 @@ # case the license is the MIT License). An "Open Source License" is a # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# + # Please submit bugfixes or comments via http://bugs.opensuse.org/ # + Name: python-venusian -Version: 1.0a8 +Version: 1.0 Release: 0 Url: http://pylonsproject.org Summary: A library for deferring decorator actions @@ -31,9 +32,9 @@ BuildRequires: python-Sphinx BuildRequires: python-repoze.sphinx.autointerface # Test requirements: +BuildRequires: python-coverage BuildRequires: python-nose BuildRequires: python-nose-exclude -BuildRequires: python-coverage %if 0%{?suse_version} && 0%{?suse_version} <= 1110 %{!?python_sitelib: %global python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} %else ++++++ venusian-1.0a8.tar.gz -> venusian-1.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/.gitignore new/venusian-1.0/.gitignore --- old/venusian-1.0a8/.gitignore 2012-08-22 19:36:20.000000000 +0200 +++ new/venusian-1.0/.gitignore 2013-04-15 09:41:53.000000000 +0200 @@ -8,7 +8,7 @@ .coverage .tox/ nosetests.xml -pyramid/coverage.xml +coverage.xml tutorial.db env*/ jyenv/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/CHANGES.txt new/venusian-1.0/CHANGES.txt --- old/venusian-1.0a8/CHANGES.txt 2013-04-15 09:36:17.000000000 +0200 +++ new/venusian-1.0/CHANGES.txt 2014-06-30 19:14:58.000000000 +0200 @@ -1,3 +1,19 @@ +1.0 (2014-06-30) +---------------- + +- Fix an issue under PyPy > 2.0 where attached decorators may not be found. + +- Drop support of Python 2.4 / 2.5 / Jython. + +- Add ``lift`` and ``onlyliftedfrom`` class decorators to allow for inheritance + of venusian decorators attached to superclass methods. See the API + documentation for more information. + +- Fix bug where otherwise undecorated subclass of a superclass that had + venusian decorators on it would inherit its superclass' decorations. + Venusian decorators should have never been inherited implicitly. See + https://github.com/Pylons/venusian/issues/11#issuecomment-4977352 + 1.0a8 (2013-04-15) ------------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/PKG-INFO new/venusian-1.0/PKG-INFO --- old/venusian-1.0a8/PKG-INFO 2013-04-15 09:40:42.000000000 +0200 +++ new/venusian-1.0/PKG-INFO 2014-06-30 19:27:32.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: venusian -Version: 1.0a8 +Version: 1.0 Summary: A library for deferring decorator actions Home-page: http://pylonsproject.org Author: Chris McDonough, Agendaless Consulting @@ -18,6 +18,22 @@ http://docs.pylonsproject.org/projects/venusian/en/latest/ + 1.0 (2014-06-30) + ---------------- + + - Fix an issue under PyPy > 2.0 where attached decorators may not be found. + + - Drop support of Python 2.4 / 2.5 / Jython. + + - Add ``lift`` and ``onlyliftedfrom`` class decorators to allow for inheritance + of venusian decorators attached to superclass methods. See the API + documentation for more information. + + - Fix bug where otherwise undecorated subclass of a superclass that had + venusian decorators on it would inherit its superclass' decorations. + Venusian decorators should have never been inherited implicitly. See + https://github.com/Pylons/venusian/issues/11#issuecomment-4977352 + 1.0a8 (2013-04-15) ------------------ @@ -188,13 +204,11 @@ Classifier: Development Status :: 3 - Alpha Classifier: Intended Audience :: Developers Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2.4 -Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Programming Language :: Python :: Implementation :: Jython diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/docs/api.rst new/venusian-1.0/docs/api.rst --- old/venusian-1.0a8/docs/api.rst 2011-02-16 05:26:39.000000000 +0100 +++ new/venusian-1.0/docs/api.rst 2013-06-08 22:41:26.000000000 +0200 @@ -9,5 +9,8 @@ .. autoclass:: AttachInfo - .. autofunction:: attach(wrapped, callback, category=None) + .. autofunction:: attach(wrapped, callback, category=None, name=None) + .. autoclass:: lift + + .. auutoclass:: onlyliftedfrom diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/docs/conf.py new/venusian-1.0/docs/conf.py --- old/venusian-1.0a8/docs/conf.py 2013-04-15 09:38:27.000000000 +0200 +++ new/venusian-1.0/docs/conf.py 2014-06-30 19:12:57.000000000 +0200 @@ -15,6 +15,7 @@ import sys import os import datetime +import pkg_resources # Add and use Pylons theme if 'sphinx-build' in ' '.join(sys.argv): # protect against dumb importers @@ -80,7 +81,7 @@ # other places throughout the built documents. # # The short X.Y version. -version = '1.0a8' +version = pkg_resources.get_distribution('pyramid').version # The full version, including alpha/beta/rc tags. release = version diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/docs/index.rst new/venusian-1.0/docs/index.rst --- old/venusian-1.0a8/docs/index.rst 2013-04-15 09:35:27.000000000 +0200 +++ new/venusian-1.0/docs/index.rst 2013-04-29 05:41:40.000000000 +0200 @@ -1,3 +1,5 @@ +.. _venusian: + Venusian ======== @@ -7,8 +9,7 @@ until a separate "scan" phase. This library is most useful for framework authors. It is compatible with -CPython versions 2.4, 2.5, 2.6, 2.7, and 3.2. It also is known to work on -PyPy 1.5 and Jython 2.5.2. +CPython versions 2.6, 2.7, and 3.2+. It is also known to work on PyPy 1.5. .. note:: @@ -315,7 +316,7 @@ def add(self, name, ob): self.registered.append((name, ob)) - register = Register() + registry = Registry() scanner = venusian.Scanner(registry=registry) scanner.scan(theapp) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/setup.py new/venusian-1.0/setup.py --- old/venusian-1.0a8/setup.py 2013-04-15 09:36:38.000000000 +0200 +++ new/venusian-1.0/setup.py 2014-06-30 19:14:39.000000000 +0200 @@ -26,28 +26,30 @@ README = '' CHANGES = '' -tests_extras = ['nose', 'nose-exclude', 'coverage'] +tests_extras = [ + 'nose', + 'nose-exclude<0.2', # 0.2.X has issues under py3 + 'coverage' + ] docs_extras = ['Sphinx', 'repoze.sphinx.autointerface'] setup(name='venusian', - version='1.0a8', + version='1.0', description='A library for deferring decorator actions', long_description=README + '\n\n' + CHANGES, classifiers=[ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "Programming Language :: Python", - "Programming Language :: Python :: 2.4", - "Programming Language :: Python :: 2.5", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", - "Programming Language :: Python :: Implementation :: Jython", - ], + ], keywords='web wsgi zope', author="Chris McDonough, Agendaless Consulting", author_email="pylons-de...@googlegroups.com", @@ -59,7 +61,7 @@ extras_require = { 'testing':tests_extras, 'docs':docs_extras, - }, + }, tests_require = [], install_requires = [], # Normal "setup.py test" can't support running the venusian tests under diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/tox.ini new/venusian-1.0/tox.ini --- old/venusian-1.0a8/tox.ini 2012-10-18 21:25:17.000000000 +0200 +++ new/venusian-1.0/tox.ini 2014-06-30 17:12:22.000000000 +0200 @@ -1,17 +1,13 @@ [tox] envlist = - py25,py26,py27,py32,jython,pypy,cover + py26,py27,py32,py33,py34,pypy,cover [testenv] commands = python setup.py nosetests deps = nose - nose-exclude - -[testenv:jython] -commands = - jython setup.py nosetests + nose-exclude<0.2 [testenv:cover] basepython = @@ -20,9 +16,12 @@ python setup.py nosetests --with-xunit --with-xcoverage deps = nose - coverage==3.4 + coverage nosexcover - nose-exclude + nose-exclude<0.2 + +# nose-exclude 0.2.X breaks both pypy and python3; see +# https://bitbucket.org/kgrandis/nose-exclude/issue/10/test-failures-with-python-3 # we separate coverage into its own testenv because a) "last run wins" wrt # cobertura jenkins reporting and b) pypy and jython can't handle any diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/venusian/__init__.py new/venusian-1.0/venusian/__init__.py --- old/venusian-1.0a8/venusian/__init__.py 2013-04-15 09:35:27.000000000 +0200 +++ new/venusian-1.0/venusian/__init__.py 2014-06-30 19:25:25.000000000 +0200 @@ -1,12 +1,18 @@ import imp -from inspect import getmembers +from inspect import getmembers, getmro, isclass + import sys -from venusian.compat import iter_modules -from venusian.compat import is_nonstr_iter +from venusian.compat import ( + iter_modules, + is_nonstr_iter, + INT_TYPES, + ) + from venusian.advice import getFrameInfo ATTACH_ATTR = '__venusian_callbacks__' +LIFTONLY_ATTR = '__venusian_liftonly_callbacks__' class Scanner(object): def __init__(self, **kw): @@ -150,7 +156,7 @@ # catchall except: return here, which in any other case would # be high treason. attached_categories = getattr(ob, ATTACH_ATTR) - if not attached_categories.attached_to(ob): + if not attached_categories.attached_to(mod_name, name, ob): return except: return @@ -159,8 +165,8 @@ category_keys.sort() for category in category_keys: callbacks = attached_categories.get(category, []) - for callback, callback_mod_name in callbacks: - if callback_mod_name != mod_name: + for callback, cb_mod_name, liftid, scope in callbacks: + if cb_mod_name != mod_name: # avoid processing objects that were imported into this # module but were not actually defined there continue @@ -254,41 +260,68 @@ class Categories(dict): def __init__(self, attached_to): super(dict, self).__init__() - if attached_to is None: - self.attached_id = None + if isinstance(attached_to, tuple): + self.attached_id = attached_to else: self.attached_id = id(attached_to) + self.lifted = False - def attached_to(self, obj): - if self.attached_id: + def attached_to(self, mod_name, name, obj): + if isinstance(self.attached_id, INT_TYPES): return self.attached_id == id(obj) - return True - -def attach(wrapped, callback, category=None, depth=1): + return self.attached_id == (mod_name, name) + +def attach(wrapped, callback, category=None, depth=1, name=None): """ Attach a callback to the wrapped object. It will be found later during a scan. This function returns an instance of the - :class:`venusian.AttachInfo` class.""" + :class:`venusian.AttachInfo` class. + + ``category`` should be ``None`` or a string representing a decorator + category name. + + ``name`` should be ``None`` or a string representing a subcategory within + the category. This will be used by the ``lift`` class decorator to + determine if decorations of a method should be inherited or overridden. + """ frame = sys._getframe(depth+1) scope, module, f_locals, f_globals, codeinfo = getFrameInfo(frame) module_name = getattr(module, '__name__', None) + wrapped_name = getattr(wrapped, '__name__', None) + class_name = codeinfo[2] + + liftid = '%s %s' % (wrapped_name, name) + if scope == 'class': # we're in the midst of a class statement - categories = f_locals.setdefault(ATTACH_ATTR, Categories(None)) + categories = f_locals.get(ATTACH_ATTR, None) + if categories is None or not categories.attached_to( + module_name, class_name, None + ): + categories = Categories((module_name, class_name)) + f_locals[ATTACH_ATTR] = categories callbacks = categories.setdefault(category, []) - callbacks.append((callback, module_name)) else: categories = getattr(wrapped, ATTACH_ATTR, None) - if categories is None or not categories.attached_to(wrapped): + if categories is None or not categories.attached_to( + module_name, class_name, wrapped + ): # if there aren't any attached categories, or we've retrieved # some by inheritance, we need to create new ones categories = Categories(wrapped) setattr(wrapped, ATTACH_ATTR, categories) callbacks = categories.setdefault(category, []) - callbacks.append((callback, module_name)) + + callbacks.append((callback, module_name, liftid, scope)) + return AttachInfo( - scope=scope, module=module, locals=f_locals, globals=f_globals, - category=category, codeinfo=codeinfo) + scope=scope, + module=module, + locals=f_locals, + globals=f_globals, + category=category, + codeinfo=codeinfo, + ) def walk_packages(path=None, prefix='', onerror=None, ignore=None): """Yields (module_loader, name, ispkg) for all modules recursively @@ -359,3 +392,158 @@ yield item else: yield importer, name, ispkg + + +class lift(object): + """ + A class decorator which 'lifts' superclass venusian configuration + decorations into subclasses. For example:: + + from venusian import lift + from somepackage import venusian_decorator + + class Super(object): + @venusian_decorator() + def boo(self): pass + + @venusian_decorator() + def hiss(self): pass + + @venusian_decorator() + def jump(self): pass + + @lift() + class Sub(Super): + def boo(self): pass + + def hiss(self): pass + + @venusian_decorator() + def smack(self): pass + + The above configuration will cause the callbacks of seven venusian + decorators. The ones attached to Super.boo, Super.hiss, and Super.jump + *plus* ones attached to Sub.boo, Sub.hiss, Sub.hump and Sub.smack. + + If a subclass overrides a decorator on a method, its superclass decorators + will be ignored for the subclass. That means that in this configuration: + + from venusian import lift + from somepackage import venusian_decorator + + class Super(object): + @venusian_decorator() + def boo(self): pass + + @venusian_decorator() + def hiss(self): pass + + @lift() + class Sub(Super): + + def boo(self): pass + + @venusian_decorator() + def hiss(self): pass + + Only four, not five decorator callbacks will be run: the ones attached to + Super.boo and Super.hiss, the inherited one of Sub.boo and the + non-inherited one of Sub.hiss. The inherited decorator on Super.hiss will + be ignored for the subclass. + + The ``lift`` decorator takes a single argument named 'categories'. If + supplied, it should be a tuple of category names. Only decorators + in this category will be lifted if it is suppled. + + """ + def __init__(self, categories=None): + self.categories = categories + + def __call__(self, wrapped): + if not isclass(wrapped): + raise RuntimeError( + '"lift" only works as a class decorator; you tried to use ' + 'it against %r' % wrapped + ) + frame = sys._getframe(1) + scope, module, f_locals, f_globals, codeinfo = getFrameInfo(frame) + module_name = getattr(module, '__name__', None) + newcategories = Categories(wrapped) + newcategories.lifted = True + for cls in getmro(wrapped): + attached_categories = cls.__dict__.get(ATTACH_ATTR, None) + if attached_categories is None: + attached_categories = cls.__dict__.get(LIFTONLY_ATTR, None) + if attached_categories is not None: + for cname, category in attached_categories.items(): + if cls is not wrapped: + if self.categories and not cname in self.categories: + continue + callbacks = newcategories.get(cname, []) + newcallbacks = [] + for cb, _, liftid, cscope in category: + append = True + toappend = (cb, module_name, liftid, cscope) + if cscope == 'class': + for ncb, _, nliftid, nscope in callbacks: + if (nscope == 'class' and liftid == nliftid): + append = False + if append: + newcallbacks.append(toappend) + newcategory = list(callbacks) + newcallbacks + newcategories[cname] = newcategory + if attached_categories.lifted: + break + if newcategories: # if it has any keys + setattr(wrapped, ATTACH_ATTR, newcategories) + return wrapped + +class onlyliftedfrom(object): + """ + A class decorator which marks a class as 'only lifted from'. Decorations + made on methods of the class won't have their callbacks called directly, + but classes which inherit from only-lifted-from classes which also use the + ``lift`` class decorator will use the superclass decoration callbacks. + + For example:: + + from venusian import lift, onlyliftedfrom + from somepackage import venusian_decorator + + @onlyliftedfrom() + class Super(object): + @venusian_decorator() + def boo(self): pass + + @venusian_decorator() + def hiss(self): pass + + @lift() + class Sub(Super): + + def boo(self): pass + + def hiss(self): pass + + Only two decorator callbacks will be run: the ones attached to Sub.boo and + Sub.hiss. The inherited decorators on Super.boo and Super.hiss will be + not be registered. + """ + def __call__(self, wrapped): + if not isclass(wrapped): + raise RuntimeError( + '"onlyliftedfrom" only works as a class decorator; you tried ' + 'to use it against %r' % wrapped + ) + cats = getattr(wrapped, ATTACH_ATTR, None) + class_name = wrapped.__name__ + module_name = wrapped.__module__ + key = (module_name, class_name, wrapped) + if cats is None or not cats.attached_to(*key): + # we either have no categories or our categories are defined + # in a superclass + return + delattr(wrapped, ATTACH_ATTR) + setattr(wrapped, LIFTONLY_ATTR, cats) + return wrapped + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/venusian/advice.py new/venusian-1.0/venusian/advice.py --- old/venusian-1.0a8/venusian/advice.py 2011-08-16 23:47:25.000000000 +0200 +++ new/venusian-1.0/venusian/advice.py 2013-04-29 05:41:18.000000000 +0200 @@ -53,12 +53,13 @@ frameinfo = inspect.getframeinfo(frame) try: sourceline = frameinfo[3][0].strip() - except: # dont understand circumstance here, 3rdparty code without comment + except: #pragma NO COVER + # dont understand circumstance here, 3rdparty code without comment sourceline = frameinfo[3] codeinfo = frameinfo[0], frameinfo[1], frameinfo[2], sourceline - if not namespaceIsModule: + if not namespaceIsModule: #pragma no COVER # some kind of funky exec kind = "exec" # don't know how to repeat this scenario elif sameNamespace and not hasModule: @@ -67,7 +68,7 @@ kind = "class" elif not sameNamespace: kind = "function call" - else: + else: #pragma NO COVER # How can you have f_locals is f_globals, and have '__module__' set? # This is probably module-level code, but with a '__module__' variable. kind = "unknown" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/venusian/compat/__init__.py new/venusian-1.0/venusian/compat/__init__.py --- old/venusian-1.0a8/venusian/compat/__init__.py 2012-02-09 04:31:48.000000000 +0100 +++ new/venusian-1.0/venusian/compat/__init__.py 2014-06-30 19:24:53.000000000 +0200 @@ -16,3 +16,7 @@ def is_nonstr_iter(v): return hasattr(v, '__iter__') +if PY3: + INT_TYPES = (int,) +else: + INT_TYPES = (int, long) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/venusian/tests/fixtures/lifting1.py new/venusian-1.0/venusian/tests/fixtures/lifting1.py --- old/venusian-1.0a8/venusian/tests/fixtures/lifting1.py 1970-01-01 01:00:00.000000000 +0100 +++ new/venusian-1.0/venusian/tests/fixtures/lifting1.py 2013-06-08 22:41:26.000000000 +0200 @@ -0,0 +1,33 @@ +from venusian import lift +from venusian.tests.fixtures import decorator + +class Super1(object): # pragma: no cover + @decorator() + def classname(self): pass + + @decorator() + def boo(self): pass + + @decorator() + def ram(self): pass + + def jump(self): pass + +class Super2(object): # pragma: no cover + def boo(self): pass + + @decorator() + def hiss(self): pass + + @decorator() + def jump(self): pass + +@lift() +class Sub(Super1, Super2): # pragma: no cover + def boo(self): pass + + def hiss(self): pass + + @decorator() + def smack(self): pass + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/venusian/tests/fixtures/lifting2.py new/venusian-1.0/venusian/tests/fixtures/lifting2.py --- old/venusian-1.0a8/venusian/tests/fixtures/lifting2.py 1970-01-01 01:00:00.000000000 +0100 +++ new/venusian-1.0/venusian/tests/fixtures/lifting2.py 2013-06-08 22:41:26.000000000 +0200 @@ -0,0 +1,35 @@ +from venusian import lift, onlyliftedfrom +from venusian.tests.fixtures import decorator + +@onlyliftedfrom() +class Super1(object): # pragma: no cover + @decorator() + def classname(self): pass + + @decorator() + def boo(self): pass + + @decorator() + def ram(self): pass + + def jump(self): pass + +@onlyliftedfrom() +class Super2(object): # pragma: no cover + def boo(self): pass + + @decorator() + def hiss(self): pass + + @decorator() + def jump(self): pass + +@lift() +class Sub(Super1, Super2): # pragma: no cover + def boo(self): pass + + def hiss(self): pass + + @decorator() + def smack(self): pass + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/venusian/tests/fixtures/lifting3.py new/venusian-1.0/venusian/tests/fixtures/lifting3.py --- old/venusian-1.0a8/venusian/tests/fixtures/lifting3.py 1970-01-01 01:00:00.000000000 +0100 +++ new/venusian-1.0/venusian/tests/fixtures/lifting3.py 2013-06-08 22:41:26.000000000 +0200 @@ -0,0 +1,38 @@ +from venusian import lift, onlyliftedfrom +from venusian.tests.fixtures import decorator + +@onlyliftedfrom() +class NoDefinitions(object): + pass + +@onlyliftedfrom() +class Super1(object): # pragma: no cover + @decorator() + def classname(self): pass + + @decorator() + def boo(self): pass + + @decorator() + def ram(self): pass + + def jump(self): pass + +class Super2(object): # pragma: no cover + def boo(self): pass + + @decorator() + def hiss(self): pass + + @decorator() + def jump(self): pass + +@lift() +class Sub(Super1, Super2): # pragma: no cover + def boo(self): pass + + def hiss(self): pass + + @decorator() + def smack(self): pass + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/venusian/tests/fixtures/lifting4.py new/venusian-1.0/venusian/tests/fixtures/lifting4.py --- old/venusian-1.0a8/venusian/tests/fixtures/lifting4.py 1970-01-01 01:00:00.000000000 +0100 +++ new/venusian-1.0/venusian/tests/fixtures/lifting4.py 2013-06-08 22:41:26.000000000 +0200 @@ -0,0 +1,23 @@ +from venusian import lift, onlyliftedfrom +from venusian.tests.fixtures import ( + categorydecorator, + categorydecorator2, + ) + +@onlyliftedfrom() +class Super(object): # pragma: no cover + @categorydecorator() + def hiss(self): pass + + @categorydecorator2() + def jump(self): pass + +@lift(('mycategory',)) +class Sub(Super): # pragma: no cover + def hiss(self): pass + + def jump(self): pass + + @categorydecorator2() + def smack(self): pass + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/venusian/tests/fixtures/lifting5.py new/venusian-1.0/venusian/tests/fixtures/lifting5.py --- old/venusian-1.0a8/venusian/tests/fixtures/lifting5.py 1970-01-01 01:00:00.000000000 +0100 +++ new/venusian-1.0/venusian/tests/fixtures/lifting5.py 2013-06-08 22:41:26.000000000 +0200 @@ -0,0 +1,38 @@ +from venusian import lift +from venusian.tests.fixtures import decorator + +class Super1(object): # pragma: no cover + @decorator() + def classname(self): pass + + @decorator() + def boo(self): pass + + @decorator() + def ram(self): pass + + @decorator() + def jump(self): pass + +@lift() +class Super2(Super1): # pragma: no cover + @decorator() + def boo(self): pass + + @decorator() + def hiss(self): pass + + @decorator() + def jump(self): pass + +@lift() +class Sub(Super2): # pragma: no cover + @decorator() + def boo(self): pass + + @decorator() + def hiss(self): pass + + @decorator() + def smack(self): pass + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/venusian/tests/fixtures/subclassing.py new/venusian-1.0/venusian/tests/fixtures/subclassing.py --- old/venusian-1.0a8/venusian/tests/fixtures/subclassing.py 1970-01-01 01:00:00.000000000 +0100 +++ new/venusian-1.0/venusian/tests/fixtures/subclassing.py 2013-06-08 22:57:05.000000000 +0200 @@ -0,0 +1,15 @@ +from venusian.tests.fixtures import decorator + +class Super(object): # pragma: no cover + @decorator() + def classname(self): pass + + @decorator() + def boo(self): pass + + +# the Sub class must not inherit the decorations of its superclass when scanned + +class Sub(Super): # pragma: no cover + pass + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/venusian/tests/test_venusian.py new/venusian-1.0/venusian/tests/test_venusian.py --- old/venusian-1.0a8/venusian/tests/test_venusian.py 2012-08-22 20:19:38.000000000 +0200 +++ new/venusian-1.0/venusian/tests/test_venusian.py 2013-06-08 23:12:55.000000000 +0200 @@ -575,6 +575,260 @@ self.assertEqual(test.registrations[1]['ob'], func1) self.assertEqual(test.registrations[1]['function'], True) + def test_lifting1(self): + from venusian.tests.fixtures import lifting1 + test = Test() + scanner = self._makeOne(test=test) + scanner.scan(lifting1) + test.registrations.sort( + key=lambda x: (x['name'], x['attr'], x['ob'].__module__) + ) + self.assertEqual(len(test.registrations), 11) + + self.assertEqual(test.registrations[0]['attr'], 'boo') + self.assertEqual(test.registrations[0]['name'], 'Sub') + self.assertEqual(test.registrations[0]['ob'], lifting1.Sub) + + self.assertEqual(test.registrations[1]['attr'], 'classname') + self.assertEqual(test.registrations[1]['name'], 'Sub') + self.assertEqual(test.registrations[1]['ob'], lifting1.Sub) + + self.assertEqual(test.registrations[2]['attr'], 'hiss') + self.assertEqual(test.registrations[2]['name'], 'Sub') + self.assertEqual(test.registrations[2]['ob'], lifting1.Sub) + + self.assertEqual(test.registrations[3]['attr'], 'jump') + self.assertEqual(test.registrations[3]['name'], 'Sub') + self.assertEqual(test.registrations[3]['ob'], lifting1.Sub) + + self.assertEqual(test.registrations[4]['attr'], 'ram') + self.assertEqual(test.registrations[4]['name'], 'Sub') + self.assertEqual(test.registrations[4]['ob'], lifting1.Sub) + + self.assertEqual(test.registrations[5]['attr'], 'smack') + self.assertEqual(test.registrations[5]['name'], 'Sub') + self.assertEqual(test.registrations[5]['ob'], lifting1.Sub) + + self.assertEqual(test.registrations[6]['attr'], 'boo') + self.assertEqual(test.registrations[6]['name'], 'Super1') + self.assertEqual(test.registrations[6]['ob'], lifting1.Super1) + + self.assertEqual(test.registrations[7]['attr'], 'classname') + self.assertEqual(test.registrations[7]['name'], 'Super1') + self.assertEqual(test.registrations[7]['ob'], lifting1.Super1) + + self.assertEqual(test.registrations[8]['attr'], 'ram') + self.assertEqual(test.registrations[8]['name'], 'Super1') + self.assertEqual(test.registrations[8]['ob'], lifting1.Super1) + + self.assertEqual(test.registrations[9]['attr'], 'hiss') + self.assertEqual(test.registrations[9]['name'], 'Super2') + self.assertEqual(test.registrations[9]['ob'], lifting1.Super2) + + self.assertEqual(test.registrations[10]['attr'], 'jump') + self.assertEqual(test.registrations[10]['name'], 'Super2') + self.assertEqual(test.registrations[10]['ob'], lifting1.Super2) + + def test_lifting2(self): + from venusian.tests.fixtures import lifting2 + test = Test() + scanner = self._makeOne(test=test) + scanner.scan(lifting2) + test.registrations.sort( + key=lambda x: (x['name'], x['attr'], x['ob'].__module__) + ) + self.assertEqual(len(test.registrations), 6) + + self.assertEqual(test.registrations[0]['attr'], 'boo') + self.assertEqual(test.registrations[0]['name'], 'Sub') + self.assertEqual(test.registrations[0]['ob'], lifting2.Sub) + + self.assertEqual(test.registrations[1]['attr'], 'classname') + self.assertEqual(test.registrations[1]['name'], 'Sub') + self.assertEqual(test.registrations[1]['ob'], lifting2.Sub) + + self.assertEqual(test.registrations[2]['attr'], 'hiss') + self.assertEqual(test.registrations[2]['name'], 'Sub') + self.assertEqual(test.registrations[2]['ob'], lifting2.Sub) + + self.assertEqual(test.registrations[3]['attr'], 'jump') + self.assertEqual(test.registrations[3]['name'], 'Sub') + self.assertEqual(test.registrations[3]['ob'], lifting2.Sub) + + self.assertEqual(test.registrations[4]['attr'], 'ram') + self.assertEqual(test.registrations[4]['name'], 'Sub') + self.assertEqual(test.registrations[4]['ob'], lifting2.Sub) + + self.assertEqual(test.registrations[5]['attr'], 'smack') + self.assertEqual(test.registrations[5]['name'], 'Sub') + self.assertEqual(test.registrations[5]['ob'], lifting2.Sub) + + def test_lifting3(self): + from venusian.tests.fixtures import lifting3 + test = Test() + scanner = self._makeOne(test=test) + scanner.scan(lifting3) + test.registrations.sort( + key=lambda x: (x['name'], x['attr'], x['ob'].__module__) + ) + self.assertEqual(len(test.registrations), 8) + + self.assertEqual(test.registrations[0]['attr'], 'boo') + self.assertEqual(test.registrations[0]['name'], 'Sub') + self.assertEqual(test.registrations[0]['ob'], lifting3.Sub) + + self.assertEqual(test.registrations[1]['attr'], 'classname') + self.assertEqual(test.registrations[1]['name'], 'Sub') + self.assertEqual(test.registrations[1]['ob'], lifting3.Sub) + + self.assertEqual(test.registrations[2]['attr'], 'hiss') + self.assertEqual(test.registrations[2]['name'], 'Sub') + self.assertEqual(test.registrations[2]['ob'], lifting3.Sub) + + self.assertEqual(test.registrations[3]['attr'], 'jump') + self.assertEqual(test.registrations[3]['name'], 'Sub') + self.assertEqual(test.registrations[3]['ob'], lifting3.Sub) + + self.assertEqual(test.registrations[4]['attr'], 'ram') + self.assertEqual(test.registrations[4]['name'], 'Sub') + self.assertEqual(test.registrations[4]['ob'], lifting3.Sub) + + self.assertEqual(test.registrations[5]['attr'], 'smack') + self.assertEqual(test.registrations[5]['name'], 'Sub') + self.assertEqual(test.registrations[5]['ob'], lifting3.Sub) + + self.assertEqual(test.registrations[6]['attr'], 'hiss') + self.assertEqual(test.registrations[6]['name'], 'Super2') + self.assertEqual(test.registrations[6]['ob'], lifting3.Super2) + + self.assertEqual(test.registrations[7]['attr'], 'jump') + self.assertEqual(test.registrations[7]['name'], 'Super2') + self.assertEqual(test.registrations[7]['ob'], lifting3.Super2) + + def test_lifting4(self): + from venusian.tests.fixtures import lifting4 + test = Test() + scanner = self._makeOne(test=test) + scanner.scan(lifting4) + test.registrations.sort( + key=lambda x: (x['name'], x['attr'], x['ob'].__module__) + ) + self.assertEqual(len(test.registrations), 2) + + self.assertEqual(test.registrations[0]['attr'], 'hiss') + self.assertEqual(test.registrations[0]['name'], 'Sub') + self.assertEqual(test.registrations[0]['ob'], lifting4.Sub) + + self.assertEqual(test.registrations[1]['attr'], 'smack') + self.assertEqual(test.registrations[1]['name'], 'Sub') + self.assertEqual(test.registrations[1]['ob'], lifting4.Sub) + + def test_lifting5(self): + from venusian.tests.fixtures import lifting5 + test = Test() + scanner = self._makeOne(test=test) + scanner.scan(lifting5) + test.registrations.sort( + key=lambda x: (x['name'], x['attr'], x['ob'].__module__) + ) + self.assertEqual(len(test.registrations), 15) + + self.assertEqual(test.registrations[0]['attr'], 'boo') + self.assertEqual(test.registrations[0]['name'], 'Sub') + self.assertEqual(test.registrations[0]['ob'], lifting5.Sub) + + self.assertEqual(test.registrations[1]['attr'], 'classname') + self.assertEqual(test.registrations[1]['name'], 'Sub') + self.assertEqual(test.registrations[1]['ob'], lifting5.Sub) + + self.assertEqual(test.registrations[2]['attr'], 'hiss') + self.assertEqual(test.registrations[2]['name'], 'Sub') + self.assertEqual(test.registrations[2]['ob'], lifting5.Sub) + + self.assertEqual(test.registrations[3]['attr'], 'jump') + self.assertEqual(test.registrations[3]['name'], 'Sub') + self.assertEqual(test.registrations[3]['ob'], lifting5.Sub) + + self.assertEqual(test.registrations[4]['attr'], 'ram') + self.assertEqual(test.registrations[4]['name'], 'Sub') + self.assertEqual(test.registrations[4]['ob'], lifting5.Sub) + + self.assertEqual(test.registrations[5]['attr'], 'smack') + self.assertEqual(test.registrations[5]['name'], 'Sub') + self.assertEqual(test.registrations[5]['ob'], lifting5.Sub) + + self.assertEqual(test.registrations[6]['attr'], 'boo') + self.assertEqual(test.registrations[6]['name'], 'Super1') + self.assertEqual(test.registrations[6]['ob'], lifting5.Super1) + + self.assertEqual(test.registrations[7]['attr'], 'classname') + self.assertEqual(test.registrations[7]['name'], 'Super1') + self.assertEqual(test.registrations[7]['ob'], lifting5.Super1) + + self.assertEqual(test.registrations[8]['attr'], 'jump') + self.assertEqual(test.registrations[8]['name'], 'Super1') + self.assertEqual(test.registrations[8]['ob'], lifting5.Super1) + + self.assertEqual(test.registrations[9]['attr'], 'ram') + self.assertEqual(test.registrations[9]['name'], 'Super1') + self.assertEqual(test.registrations[9]['ob'], lifting5.Super1) + + self.assertEqual(test.registrations[10]['attr'], 'boo') + self.assertEqual(test.registrations[10]['name'], 'Super2') + self.assertEqual(test.registrations[10]['ob'], lifting5.Super2) + + self.assertEqual(test.registrations[11]['attr'], 'classname') + self.assertEqual(test.registrations[11]['name'], 'Super2') + self.assertEqual(test.registrations[11]['ob'], lifting5.Super2) + + self.assertEqual(test.registrations[12]['attr'], 'hiss') + self.assertEqual(test.registrations[12]['name'], 'Super2') + self.assertEqual(test.registrations[12]['ob'], lifting5.Super2) + + self.assertEqual(test.registrations[13]['attr'], 'jump') + self.assertEqual(test.registrations[13]['name'], 'Super2') + self.assertEqual(test.registrations[13]['ob'], lifting5.Super2) + + self.assertEqual(test.registrations[14]['attr'], 'ram') + self.assertEqual(test.registrations[14]['name'], 'Super2') + self.assertEqual(test.registrations[14]['ob'], lifting5.Super2) + + def test_subclassing(self): + from venusian.tests.fixtures import subclassing + test = Test() + scanner = self._makeOne(test=test) + scanner.scan(subclassing) + test.registrations.sort( + key=lambda x: (x['name'], x['attr'], x['ob'].__module__) + ) + self.assertEqual(len(test.registrations), 2) + + self.assertEqual(test.registrations[0]['attr'], 'boo') + self.assertEqual(test.registrations[0]['name'], 'Super') + self.assertEqual(test.registrations[0]['ob'], subclassing.Super) + + self.assertEqual(test.registrations[1]['attr'], 'classname') + self.assertEqual(test.registrations[1]['name'], 'Super') + self.assertEqual(test.registrations[1]['ob'], subclassing.Super) + +class Test_lift(unittest.TestCase): + def _makeOne(self, categories=None): + from venusian import lift + return lift(categories) + + def test_not_class(self): + inst = self._makeOne() + self.assertRaises(RuntimeError, inst, None) + +class Test_onlyliftedfrom(unittest.TestCase): + def _makeOne(self): + from venusian import onlyliftedfrom + return onlyliftedfrom() + + def test_not_class(self): + inst = self._makeOne() + self.assertRaises(RuntimeError, inst, None) + def md(name): # pragma: no cover if name in sys.modules: del sys.modules[name] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/venusian.egg-info/PKG-INFO new/venusian-1.0/venusian.egg-info/PKG-INFO --- old/venusian-1.0a8/venusian.egg-info/PKG-INFO 2013-04-15 09:40:41.000000000 +0200 +++ new/venusian-1.0/venusian.egg-info/PKG-INFO 2014-06-30 19:27:30.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: venusian -Version: 1.0a8 +Version: 1.0 Summary: A library for deferring decorator actions Home-page: http://pylonsproject.org Author: Chris McDonough, Agendaless Consulting @@ -18,6 +18,22 @@ http://docs.pylonsproject.org/projects/venusian/en/latest/ + 1.0 (2014-06-30) + ---------------- + + - Fix an issue under PyPy > 2.0 where attached decorators may not be found. + + - Drop support of Python 2.4 / 2.5 / Jython. + + - Add ``lift`` and ``onlyliftedfrom`` class decorators to allow for inheritance + of venusian decorators attached to superclass methods. See the API + documentation for more information. + + - Fix bug where otherwise undecorated subclass of a superclass that had + venusian decorators on it would inherit its superclass' decorations. + Venusian decorators should have never been inherited implicitly. See + https://github.com/Pylons/venusian/issues/11#issuecomment-4977352 + 1.0a8 (2013-04-15) ------------------ @@ -188,13 +204,11 @@ Classifier: Development Status :: 3 - Alpha Classifier: Intended Audience :: Developers Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2.4 -Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Programming Language :: Python :: Implementation :: Jython diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/venusian.egg-info/SOURCES.txt new/venusian-1.0/venusian.egg-info/SOURCES.txt --- old/venusian-1.0a8/venusian.egg-info/SOURCES.txt 2013-04-15 09:40:42.000000000 +0200 +++ new/venusian-1.0/venusian.egg-info/SOURCES.txt 2014-06-30 19:27:32.000000000 +0200 @@ -33,6 +33,12 @@ venusian/tests/fixtures/category.py venusian/tests/fixtures/classdecorator.py venusian/tests/fixtures/inheritance.py +venusian/tests/fixtures/lifting1.py +venusian/tests/fixtures/lifting2.py +venusian/tests/fixtures/lifting3.py +venusian/tests/fixtures/lifting4.py +venusian/tests/fixtures/lifting5.py +venusian/tests/fixtures/subclassing.py venusian/tests/fixtures/attrerror/__init__.py venusian/tests/fixtures/attrerror/will_cause_import_error.py venusian/tests/fixtures/attrerror_package/__init__.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/venusian-1.0a8/venusian.egg-info/requires.txt new/venusian-1.0/venusian.egg-info/requires.txt --- old/venusian-1.0a8/venusian.egg-info/requires.txt 2013-04-15 09:40:41.000000000 +0200 +++ new/venusian-1.0/venusian.egg-info/requires.txt 2014-06-30 19:27:30.000000000 +0200 @@ -1,10 +1,9 @@ - [docs] Sphinx repoze.sphinx.autointerface [testing] nose -nose-exclude -coverage \ No newline at end of file +nose-exclude<0.2 +coverage -- To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org For additional commands, e-mail: opensuse-commit+h...@opensuse.org