Hello community, here is the log from the commit of package python3-transaction for openSUSE:Factory checked in at 2016-11-22 18:59:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python3-transaction (Old) and /work/SRC/openSUSE:Factory/.python3-transaction.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "python3-transaction" Changes: -------- --- /work/SRC/openSUSE:Factory/python3-transaction/python3-transaction.changes 2016-11-17 12:44:26.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.python3-transaction.new/python3-transaction.changes 2016-11-22 18:59:05.000000000 +0100 @@ -1,0 +2,11 @@ +Sun Nov 20 18:45:08 UTC 2016 - arun@gmx.de + +- update to version 2.0.3: + * The user and description fields must now be set with text + (unicode) data. Previously, if bytes were provided, they’d be + decoded as ASCII. It was decided that this would lead to bugs that + were hard to test for. + * Also, the transaction meta-data field, extended_info has been + renamed to extension. + +------------------------------------------------------------------- Old: ---- transaction-2.0.2.tar.gz New: ---- transaction-2.0.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python3-transaction.spec ++++++ --- /var/tmp/diff_new_pack.gbReME/_old 2016-11-22 18:59:06.000000000 +0100 +++ /var/tmp/diff_new_pack.gbReME/_new 2016-11-22 18:59:06.000000000 +0100 @@ -17,7 +17,7 @@ Name: python3-transaction -Version: 2.0.2 +Version: 2.0.3 Release: 0 Summary: Transaction management for Python License: ZPL-2.1 ++++++ transaction-2.0.2.tar.gz -> transaction-2.0.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/CHANGES.rst new/transaction-2.0.3/CHANGES.rst --- old/transaction-2.0.2/CHANGES.rst 2016-11-13 22:11:02.000000000 +0100 +++ new/transaction-2.0.3/CHANGES.rst 2016-11-17 21:50:36.000000000 +0100 @@ -1,6 +1,17 @@ Changes ======= +2.0.3 (2016-11-17) +------------------ + +- The user and description fields must now be set with text (unicode) + data. Previously, if bytes were provided, they'd be decoded as + ASCII. It was decided that this would lead to bugs that were hard + to test for. + + Also, the transaction meta-data field, ``extended_info`` has been + renamed to ``extension``. + 2.0.2 (2016-11-13) ------------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/PKG-INFO new/transaction-2.0.3/PKG-INFO --- old/transaction-2.0.2/PKG-INFO 2016-11-13 22:12:15.000000000 +0100 +++ new/transaction-2.0.3/PKG-INFO 2016-11-17 21:51:31.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: transaction -Version: 2.0.2 +Version: 2.0.3 Summary: Transaction management for Python Home-page: https://github.com/zopefoundation/transaction Author: Zope Corporation @@ -36,6 +36,17 @@ Changes ======= + 2.0.3 (2016-11-17) + ------------------ + + - The user and description fields must now be set with text (unicode) + data. Previously, if bytes were provided, they'd be decoded as + ASCII. It was decided that this would lead to bugs that were hard + to test for. + + Also, the transaction meta-data field, ``extended_info`` has been + renamed to ``extension``. + 2.0.2 (2016-11-13) ------------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/docs/convenience.rst new/transaction-2.0.3/docs/convenience.rst --- old/transaction-2.0.2/docs/convenience.rst 2016-11-11 23:13:48.000000000 +0100 +++ new/transaction-2.0.3/docs/convenience.rst 2016-11-17 21:36:10.000000000 +0100 @@ -23,7 +23,7 @@ >>> with transaction.manager as t: ... dm['z'] = 3 - ... t.note('test 3') + ... t.note(u'test 3') >>> dm['z'] 3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/docs/convenience.rst~ new/transaction-2.0.3/docs/convenience.rst~ --- old/transaction-2.0.2/docs/convenience.rst~ 2016-11-11 21:26:05.000000000 +0100 +++ new/transaction-2.0.3/docs/convenience.rst~ 2016-11-11 23:13:48.000000000 +0100 @@ -28,8 +28,8 @@ >>> dm['z'] 3 - >>> dm.last_note - 'test 3' + >>> dm.last_note == u'test 3' + True >>> with transaction.manager: #doctest ELLIPSIS ... dm['z'] = 4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/setup.py new/transaction-2.0.3/setup.py --- old/transaction-2.0.2/setup.py 2016-11-13 22:11:35.000000000 +0100 +++ new/transaction-2.0.3/setup.py 2016-11-17 21:51:01.000000000 +0100 @@ -11,7 +11,7 @@ # FOR A PARTICULAR PURPOSE. # ############################################################################## -version = '2.0.2' +version = '2.0.3' import os from setuptools import setup, find_packages diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/t.py new/transaction-2.0.3/t.py --- old/transaction-2.0.2/t.py 1970-01-01 01:00:00.000000000 +0100 +++ new/transaction-2.0.3/t.py 2016-11-16 20:16:04.000000000 +0100 @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- + +def f(): + """ + doc ☯ + """ + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/transaction/_compat.py~ new/transaction-2.0.3/transaction/_compat.py~ --- old/transaction-2.0.2/transaction/_compat.py~ 1970-01-01 01:00:00.000000000 +0100 +++ new/transaction-2.0.3/transaction/_compat.py~ 2016-04-28 20:29:54.000000000 +0200 @@ -0,0 +1,90 @@ +import sys +import types + +PY3 = sys.version_info[0] == 3 +JYTHON = sys.platform.startswith('java') + +if PY3: # pragma: no cover + string_types = str, + integer_types = int, + class_types = type, + text_type = str + binary_type = bytes + long = int +else: + string_types = basestring, + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + long = long + +def bytes_(s, encoding='latin-1', errors='strict'): #pragma NO COVER + if isinstance(s, text_type): + return s.encode(encoding, errors) + return s + +if PY3: # pragma: no cover + def native_(s, encoding='latin-1', errors='strict'): #pragma NO COVER + if isinstance(s, text_type): + return s + return str(s, encoding, errors) +else: + def native_(s, encoding='latin-1', errors='strict'): #pragma NO COVER + if isinstance(s, text_type): + return s.encode(encoding, errors) + return str(s) + +if PY3: #pragma NO COVER + from io import StringIO +else: + from io import BytesIO as StringIO + +if PY3: #pragma NO COVER + from collections import MutableMapping +else: + from UserDict import UserDict as MutableMapping + +if PY3: # pragma: no cover + import builtins + exec_ = getattr(builtins, "exec") + + + def reraise(tp, value, tb=None): #pragma NO COVER + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + +else: # pragma: no cover + def exec_(code, globs=None, locs=None): #pragma NO COVER + """Execute code in a namespace.""" + if globs is None: + frame = sys._getframe(1) + globs = frame.f_globals + if locs is None: + locs = frame.f_locals + del frame + elif locs is None: + locs = globs + exec("""exec code in globs, locs""") + + exec_("""def reraise(tp, value, tb=None): + raise tp, value, tb +""") + + +if PY3: #pragma NO COVER + try: + from threading import get_ident as get_thread_ident + except ImportError: + from threading import _get_ident as get_thread_ident +else: + from thread import get_ident as get_thread_ident + + +if PY3: + def func_name(func): #pragma NO COVER + return func.__name__ +else: + def func_name(func): #pragma NO COVER + return func.func_name diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/transaction/_manager.py new/transaction-2.0.3/transaction/_manager.py --- old/transaction-2.0.2/transaction/_manager.py 2016-11-08 18:55:06.000000000 +0100 +++ new/transaction-2.0.3/transaction/_manager.py 2016-11-17 21:36:10.000000000 +0100 @@ -25,6 +25,7 @@ from transaction.interfaces import TransientError from transaction.weakset import WeakSet from transaction._compat import reraise +from transaction._compat import text_type from transaction._transaction import Transaction @@ -178,6 +179,9 @@ else: doc = name + if doc and not isinstance(doc, text_type): + doc = doc.decode('utf-8') + for i in range(1, tries + 1): txn = self.begin() if doc: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/transaction/_manager.py~ new/transaction-2.0.3/transaction/_manager.py~ --- old/transaction-2.0.2/transaction/_manager.py~ 2016-11-07 19:32:33.000000000 +0100 +++ new/transaction-2.0.3/transaction/_manager.py~ 2016-11-08 18:55:06.000000000 +0100 @@ -146,7 +146,7 @@ if number: attempt = Attempt(self) yield attempt - if attempt.sucess: + if attempt.success: break else: yield self @@ -160,6 +160,42 @@ if (should_retry is not None) and should_retry(error): return True + run_no_func_types = int, type(None) + def run(self, func=None, tries=3): + if isinstance(func, self.run_no_func_types): + if func is not None: + tries = func + return lambda func: self.run(func, tries) + + if tries <= 0: + raise ValueError("tries must be positive") + + name = func.__name__ + doc = func.__doc__ + if name != '_': + if doc: + doc = name + '\n\n' + doc + else: + doc = name + + for i in range(1, tries + 1): + txn = self.begin() + if doc: + txn.note(doc) + + try: + result = func() + txn.commit() + except Exception as v: + if i == tries: + raise # that was our last chance + retry = self._retryable(v.__class__, v) + txn.abort() + if not retry: + raise + else: + return result + class ThreadTransactionManager(TransactionManager, threading.local): """Thread-aware transaction manager. @@ -170,7 +206,7 @@ class Attempt(object): - sucess = False + success = False def __init__(self, manager): self.manager = manager @@ -192,6 +228,6 @@ except: return self._retry_or_raise(*sys.exc_info()) else: - self.sucess = True + self.success = True else: return self._retry_or_raise(t, v, tb) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/transaction/_transaction.py new/transaction-2.0.3/transaction/_transaction.py --- old/transaction-2.0.2/transaction/_transaction.py 2016-11-13 22:05:52.000000000 +0100 +++ new/transaction-2.0.3/transaction/_transaction.py 2016-11-17 21:50:07.000000000 +0100 @@ -27,6 +27,7 @@ from transaction._compat import native_ from transaction._compat import bytes_ from transaction._compat import StringIO +from transaction._compat import text_type _marker = object() @@ -100,9 +101,9 @@ # manager as a key, because we can't guess whether the actual # resource managers will be safe to use as dict keys. - # The user, description, and extended_info attributes are accessed + # The user, description, and extension attributes are accessed # directly by storages, leading underscore notwithstanding. - self.extended_info = {} + self.extension = {} self.log = _makeLogger() self.log.debug("new transaction") @@ -122,11 +123,11 @@ def _extension(self): # for backward compatibility, since most clients used this # absent any formal API. - return self.extended_info + return self.extension @_extension.setter def _extension(self, v): - self.extended_info = v + self.extension = v @property def user(self): @@ -134,7 +135,9 @@ @user.setter def user(self, v): - self._user = v + u'' # + u'' to make sure it's unicode + if not isinstance(v, text_type): + raise TypeError("User must be text (unicode)") + self._user = v @property def description(self): @@ -142,7 +145,9 @@ @description.setter def description(self, v): - self._description = v + u'' # + u'' to make sure it's unicode + if not isinstance(v, text_type): + raise TypeError("Description must be text (unicode)") + self._description = v def isDoomed(self): """ See ITransaction. @@ -528,21 +533,28 @@ def note(self, text): """ See ITransaction. """ + if not isinstance(text, text_type): + raise TypeError("Note must be text (unicode)") + text = text.strip() if self.description: self.description += u"\n" + text else: self.description = text - def setUser(self, user_name, path="/"): + def setUser(self, user_name, path=u"/"): """ See ITransaction. """ + if not isinstance(user_name, text_type): + raise TypeError("User name must be text (unicode)") + if not isinstance(path, text_type): + raise TypeError("Path must be text (unicode)") self.user = u"%s %s" % (path, user_name) def setExtendedInfo(self, name, value): """ See ITransaction. """ - self.extended_info[name + u''] = value # + u'' to make sure it's unicode + self.extension[name] = value # TODO: We need a better name for the adapters. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/transaction/_transaction.py~ new/transaction-2.0.3/transaction/_transaction.py~ --- old/transaction-2.0.2/transaction/_transaction.py~ 2016-11-11 21:24:49.000000000 +0100 +++ new/transaction-2.0.3/transaction/_transaction.py~ 2016-11-13 22:05:52.000000000 +0100 @@ -124,6 +124,10 @@ # absent any formal API. return self.extended_info + @_extension.setter + def _extension(self, v): + self.extended_info = v + @property def user(self): return self._user diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/transaction/interfaces.py new/transaction-2.0.3/transaction/interfaces.py --- old/transaction-2.0.2/transaction/interfaces.py 2016-11-11 21:24:49.000000000 +0100 +++ new/transaction-2.0.3/transaction/interfaces.py 2016-11-17 21:50:07.000000000 +0100 @@ -125,12 +125,8 @@ raise an exception, or truncate the value). """) - extended_info = Attribute( - """A dictionary containing application-defined metadata. - - Keys must be text (unicode). Values must be simple values - serializable with json or pickle (not instances). - """) + extension = Attribute( + "A dictionary containing application-defined metadata.") def commit(): """Finalize the transaction. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/transaction/interfaces.py~ new/transaction-2.0.3/transaction/interfaces.py~ --- old/transaction-2.0.2/transaction/interfaces.py~ 2016-11-08 18:55:06.000000000 +0100 +++ new/transaction-2.0.3/transaction/interfaces.py~ 2016-11-11 21:24:49.000000000 +0100 @@ -105,7 +105,7 @@ """A user name associated with the transaction. The format of the user name is defined by the application. The value - is of Python type str. Storages record the user value, as meta-data, + is text (unicode). Storages record the user value, as meta-data, when a transaction commits. A storage may impose a limit on the size of the value; behavior is @@ -116,7 +116,7 @@ description = Attribute( """A textual description of the transaction. - The value is of Python type str. Method note() is the intended + The value is text (unicode). Method note() is the intended way to set the value. Storages record the description, as meta-data, when a transaction commits. @@ -125,6 +125,13 @@ raise an exception, or truncate the value). """) + extended_info = Attribute( + """A dictionary containing application-defined metadata. + + Keys must be text (unicode). Values must be simple values + serializable with json or pickle (not instances). + """) + def commit(): """Finalize the transaction. @@ -167,7 +174,7 @@ """ def note(text): - """Add text to the transaction description. + """Add text (unicode) to the transaction description. This modifies the `.description` attribute; see its docs for more detail. First surrounding whitespace is stripped from `text`. If @@ -176,21 +183,17 @@ appended to `.description`. """ - def setUser(user_name, path="/"): - """Set the user name. - - path should be provided if needed to further qualify the - identified user. This is a convenience method used by Zope. - It sets the .user attribute to str(path) + " " + str(user_name). - This sets the `.user` attribute; see its docs for more detail. - """ - def setExtendedInfo(name, value): """Add extension data to the transaction. - name is the name of the extension property to set, of Python type - str; value must be picklable. Multiple calls may be made to set - multiple extension properties, provided the names are distinct. + name + is the text (unicode) name of the extension property to set + + value + must be picklable and json serializable (not an instance). + + Multiple calls may be made to set multiple extension + properties, provided the names are distinct. Storages record the extension data, as meta-data, when a transaction commits. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/transaction/tests/test__transaction.py new/transaction-2.0.3/transaction/tests/test__transaction.py --- old/transaction-2.0.2/transaction/tests/test__transaction.py 2016-11-13 22:05:52.000000000 +0100 +++ new/transaction-2.0.3/transaction/tests/test__transaction.py 2016-11-17 21:50:07.000000000 +0100 @@ -76,8 +76,8 @@ self.assertEqual(txn._resources, []) self.assertEqual(txn._adapters, {}) self.assertEqual(txn._voted, {}) - self.assertEqual(txn.extended_info, {}) - self.assertTrue(txn._extension is txn.extended_info) # legacy + self.assertEqual(txn.extension, {}) + self.assertTrue(txn._extension is txn.extension) # legacy self.assertTrue(txn.log is logger) self.assertEqual(len(logger._log), 1) self.assertEqual(logger._log[0][0], 'debug') @@ -983,37 +983,43 @@ def test_note(self): txn = self._makeOne() try: - txn.note('This is a note.') + txn.note(u'This is a note.') self.assertEqual(txn.description, u'This is a note.') - txn.note('Another.') + txn.note(u'Another.') self.assertEqual(txn.description, u'This is a note.\nAnother.') finally: txn.abort() - def test_description_nonascii_bytes(self): + def test_description_bytes(self): txn = self._makeOne() - with self.assertRaises((UnicodeDecodeError, TypeError)): - txn.description = b'\xc2\x80' + with self.assertRaises(TypeError): + txn.description = b'haha' def test_setUser_default_path(self): txn = self._makeOne() - txn.setUser('phreddy') + txn.setUser(u'phreddy') self.assertEqual(txn.user, u'/ phreddy') def test_setUser_explicit_path(self): txn = self._makeOne() - txn.setUser('phreddy', '/bedrock') + txn.setUser(u'phreddy', u'/bedrock') self.assertEqual(txn.user, u'/bedrock phreddy') - def test_user_nonascii_bytes(self): + def test_user_bytes(self): txn = self._makeOne() - with self.assertRaises((UnicodeDecodeError, TypeError)): - txn.user = b'\xc2\x80' + with self.assertRaises(TypeError): + txn.user = b'phreddy' + with self.assertRaises(TypeError): + txn.setUser(b'phreddy', u'/bedrock') + with self.assertRaises(TypeError): + txn.setUser(u'phreddy', b'/bedrock') + with self.assertRaises(TypeError): + txn.setUser(b'phreddy') def test_setExtendedInfo_single(self): txn = self._makeOne() txn.setExtendedInfo('frob', 'qux') - self.assertEqual(txn.extended_info, {u'frob': 'qux'}) + self.assertEqual(txn.extension, {u'frob': 'qux'}) self.assertTrue(txn._extension is txn._extension) # legacy def test_setExtendedInfo_multiple(self): @@ -1029,7 +1035,7 @@ txn = self._makeOne() txn._extension = dict(baz='spam') txn.setExtendedInfo('frob', 'qux') - self.assertEqual(txn.extended_info, {u'frob': 'qux', 'baz': 'spam'}) + self.assertEqual(txn.extension, {u'frob': 'qux', 'baz': 'spam'}) def test_data(self): txn = self._makeOne() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/transaction/tests/test__transaction.py~ new/transaction-2.0.3/transaction/tests/test__transaction.py~ --- old/transaction-2.0.2/transaction/tests/test__transaction.py~ 2016-11-11 21:24:49.000000000 +0100 +++ new/transaction-2.0.3/transaction/tests/test__transaction.py~ 2016-11-13 22:05:52.000000000 +0100 @@ -1024,6 +1024,13 @@ self.assertEqual(txn._extension, {u'frob': 'quxxxx', u'baz': 'spam'}) self.assertTrue(txn._extension is txn._extension) # legacy + def test__extension_settable(self): + # Because ZEO sets it. I'll fix ZEO, but maybe something else will break + txn = self._makeOne() + txn._extension = dict(baz='spam') + txn.setExtendedInfo('frob', 'qux') + self.assertEqual(txn.extended_info, {u'frob': 'qux', 'baz': 'spam'}) + def test_data(self): txn = self._makeOne() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/transaction.egg-info/PKG-INFO new/transaction-2.0.3/transaction.egg-info/PKG-INFO --- old/transaction-2.0.2/transaction.egg-info/PKG-INFO 2016-11-13 22:12:13.000000000 +0100 +++ new/transaction-2.0.3/transaction.egg-info/PKG-INFO 2016-11-17 21:51:29.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: transaction -Version: 2.0.2 +Version: 2.0.3 Summary: Transaction management for Python Home-page: https://github.com/zopefoundation/transaction Author: Zope Corporation @@ -36,6 +36,17 @@ Changes ======= + 2.0.3 (2016-11-17) + ------------------ + + - The user and description fields must now be set with text (unicode) + data. Previously, if bytes were provided, they'd be decoded as + ASCII. It was decided that this would lead to bugs that were hard + to test for. + + Also, the transaction meta-data field, ``extended_info`` has been + renamed to ``extension``. + 2.0.2 (2016-11-13) ------------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transaction-2.0.2/transaction.egg-info/SOURCES.txt new/transaction-2.0.3/transaction.egg-info/SOURCES.txt --- old/transaction-2.0.2/transaction.egg-info/SOURCES.txt 2016-11-13 22:12:15.000000000 +0100 +++ new/transaction-2.0.3/transaction.egg-info/SOURCES.txt 2016-11-17 21:51:31.000000000 +0100 @@ -10,6 +10,7 @@ rtd.txt setup.cfg setup.py +t.py tox.ini docs/Makefile docs/Makefile~ @@ -31,6 +32,7 @@ docs/_templates/placeholder.txt transaction/__init__.py transaction/_compat.py +transaction/_compat.py~ transaction/_manager.py transaction/_manager.py~ transaction/_transaction.py