Index: test/test_anypy_hashlib.py =================================================================== --- test/test_anypy_hashlib.py (revision 0) +++ test/test_anypy_hashlib.py (revision 4116) @@ -0,0 +1,134 @@ +import unittest +import warnings + +import roundup.anypy.hashlib_ + +class UntestableWarning(Warning): + pass + +# suppress deprecation warnings; -> warnings.filters[0]: +warnings.simplefilter(action='ignore', + category=DeprecationWarning, + append=0) + +try: + import sha +except: + warnings.warn('sha module functions', UntestableWarning) + sha = None + +try: + import md5 +except: + warnings.warn('md5 module functions', UntestableWarning) + md5 = None + +try: + import hashlib +except: + warnings.warn('hashlib module functions', UntestableWarning) + hashlib = None + +# preserve other warning filters set elsewhere: +del warnings.filters[0] + +if not (sha or md5) and not hashlib: + warnings.warn('anypy.hashlib_ sanity', UntestableWarning) + +class TestCase_anypy_hashlib(unittest.TestCase): + """test the hashlib compatibility layer""" + + testdata = ( + ('', + 'da39a3ee5e6b4b0d3255bfef95601890afd80709', + 'd41d8cd98f00b204e9800998ecf8427e'), + ('Strange women lying in ponds distributing swords' + ' is no basis for a system of government.', + 'da9b2b00466b00411038c057681fe67349f92d7d', + 'b71c5178d316ec446c25386f4857d4f9'), + ('Ottos Mops hopst fort', + 'fdf7e6c54cf07108c86edd8d47c90450671c2c81', + 'a3dce74bee59ee92f1038263e5252500'), + ('Dieser Satz kein Verb', + '3030aded8a079b92043a39dc044a35443959dcdd', + '2f20c69d514228011fb0d32e14dd5d80'), + ) + + # the following two are always excecuted: + def test_sha1_expected_anypy(self): + """...anypy.hashlib_.sha1().hexdigest() yields expected results""" + for src, SHA, MD5 in self.testdata: + self.assertEqual(roundup.anypy.hashlib_.sha1(src).hexdigest(), SHA) + + def test_md5_expected_anypy(self): + """...anypy.hashlib_.md5().hexdigest() yields expected results""" + for src, SHA, MD5 in self.testdata: + self.assertEqual(roundup.anypy.hashlib_.md5(src).hexdigest(), MD5) + + # execution depending on availability of modules: + if md5 and hashlib: + def test_md5_continuity(self): + """md5.md5().digest() == hashlib.md5().digest()""" + if md5.md5 is hashlib.md5: + return + else: + for s, i1, i2 in self.testdata: + self.assertEqual(md5.md5(s).digest(), + hashlib.md5().digest()) + + if md5: + def test_md5_expected(self): + """md5.md5().hexdigest() yields expected results""" + for src, SHA, MD5 in self.testdata: + self.assertEqual(md5.md5(src).hexdigest(), MD5) + + def test_md5_new(self): + """md5.new is md5.md5, or at least yields expected results""" + if md5.new is md5.md5: + return + else: + for src, SHA, MD5 in self.testdata: + self.assertEqual(md5.md5(src).hexdigest(), MD5) + + if sha and hashlib: + def test_sha1_continuity(self): + """sha.sha().digest() == hashlib.sha1().digest()""" + if sha.sha is hashlib.sha1: + return + else: + for s in self.testdata: + self.assertEqual(sha.sha(s).digest(), + hashlib.sha1().digest()) + + if sha: + def test_sha_expected(self): + """sha.sha().hexdigest() yields expected results""" + for src, SHA, MD5 in self.testdata: + self.assertEqual(sha.sha(src).hexdigest(), SHA) + + # fails for me with Python 2.3; unittest module bug? + def test_sha_new(self): + """sha.new is sha.sha, or at least yields expected results""" + if sha.new is sha.sha: + return + else: + import pdb + pdb.set_trace() + for src, SHA, MD5 in self.testdata: + self.assertEqual(sha.new(src).hexdigest(), SHA) + + if hashlib: + def test_sha1_expected_hashlib(self): + """hashlib.sha1().hexdigest() yields expected results""" + for src, SHA, MD5 in self.testdata: + self.assertEqual(hashlib.sha1(src).hexdigest(), SHA) + + def test_md5_expected_hashlib(self): + """hashlib.md5().hexdigest() yields expected results""" + for src, SHA, MD5 in self.testdata: + self.assertEqual(hashlib.md5(src).hexdigest(), MD5) + +if __name__ == '__main__': + unittest.main() + +# vim: ts=8 et sts=4 sw=4 si Index: test/db_test_base.py =================================================================== --- test/db_test_base.py (revision 4128) +++ test/db_test_base.py (working copy) @@ -17,7 +17,9 @@ # # $Id: db_test_base.py,v 1.101 2008-08-19 01:40:59 richard Exp $ -import unittest, os, shutil, errno, imp, sys, time, pprint, sets, base64, os.path +import unittest, os, shutil, errno, imp, sys, time, pprint, base64, os.path +# Python 2.3 ... 2.6 compatibility: +from roundup.anypy.sets_ import set from roundup.hyperdb import String, Password, Link, Multilink, Date, \ Interval, DatabaseError, Boolean, Number, Node @@ -280,7 +282,7 @@ # try a couple of the built-in iterable types to make # sure that we accept them and handle them properly # try a set as input for the multilink - nid = self.db.issue.create(title="spam", nosy=sets.Set(u1)) + nid = self.db.issue.create(title="spam", nosy=set(u1)) if commit: self.db.commit() self.assertEqual(self.db.issue.get(nid, "nosy"), [u1]) self.assertRaises(TypeError, self.db.issue.set, nid, @@ -290,7 +292,7 @@ if commit: self.db.commit() self.assertEqual(self.db.issue.get(nid, "nosy"), []) # make sure we accept a frozen set - self.db.issue.set(nid, nosy=sets.Set([u1,u2])) + self.db.issue.set(nid, nosy=set([u1,u2])) if commit: self.db.commit() l = [u1,u2]; l.sort() m = self.db.issue.get(nid, "nosy"); m.sort() @@ -483,12 +485,12 @@ others = nodeids[:] others.remove('1') - self.assertEqual(sets.Set(self.db.status.getnodeids()), - sets.Set(nodeids)) - self.assertEqual(sets.Set(self.db.status.getnodeids(retired=True)), - sets.Set(['1'])) - self.assertEqual(sets.Set(self.db.status.getnodeids(retired=False)), - sets.Set(others)) + self.assertEqual(set(self.db.status.getnodeids()), + set(nodeids)) + self.assertEqual(set(self.db.status.getnodeids(retired=True)), + set(['1'])) + self.assertEqual(set(self.db.status.getnodeids(retired=False)), + set(others)) self.assert_(self.db.status.is_retired('1')) Index: test/test_hyperdbvals.py =================================================================== --- test/test_hyperdbvals.py (revision 4128) +++ test/test_hyperdbvals.py (working copy) @@ -10,7 +10,8 @@ # # $Id: test_hyperdbvals.py,v 1.3 2006-08-18 01:26:19 richard Exp $ -import unittest, os, shutil, errno, sys, difflib, cgi, re, sha +import unittest, os, shutil, errno, sys, difflib, cgi, re +from roundup.anypy.hashlib_ import sha1 from roundup import init, instance, password, hyperdb, date @@ -80,7 +81,7 @@ self.assert_(isinstance(val, password.Password)) val = self._test('password', '{crypt}a string') self.assert_(isinstance(val, password.Password)) - s = sha.sha('a string').hexdigest() + s = sha1('a string').hexdigest() val = self._test('password', '{SHA}'+s) self.assert_(isinstance(val, password.Password)) self.assertEqual(val, 'a string') Index: scripts/import_sf.py =================================================================== --- scripts/import_sf.py (revision 4128) +++ scripts/import_sf.py (working copy) @@ -21,7 +21,9 @@ And you're done! ''' -import sys, sets, os, csv, time, urllib2, httplib, mimetypes, urlparse +import sys, os, csv, time, urllib2, httplib, mimetypes, urlparse +# Python 2.3 ... 2.6 compatibility: +from roundup.anypy.sets_ import set try: import cElementTree as ElementTree @@ -53,8 +55,8 @@ def fetch_files(xml_file, file_dir): """ Fetch files referenced in the xml_file into the dir file_dir. """ root = ElementTree.parse(xml_file).getroot() - to_fetch = sets.Set() - deleted = sets.Set() + to_fetch = set() + deleted = set() for artifact in root.find('artifacts'): for field in artifact.findall('field'): if field.get('name') == 'artifact_id': @@ -73,7 +75,7 @@ deleted.add((aid, fid)) to_fetch = to_fetch - deleted - got = sets.Set(os.listdir(file_dir)) + got = set(os.listdir(file_dir)) to_fetch = to_fetch - got # load cached urls (sigh) @@ -122,10 +124,10 @@ # parse out the XML artifacts = [] - categories = sets.Set() - users = sets.Set() - add_files = sets.Set() - remove_files = sets.Set() + categories = set() + users = set() + add_files = set() + remove_files = set() for artifact in root.find('artifacts'): d = {} op = {} @@ -254,7 +256,7 @@ else: d['status'] = unread - nosy = sets.Set() + nosy = set() for message in artifact.get('messages', []): authid = users[message['user_name']] if not message['body']: continue Index: roundup/hyperdb.py =================================================================== --- roundup/hyperdb.py (revision 4128) +++ roundup/hyperdb.py (working copy) @@ -23,7 +23,8 @@ # standard python modules import os, re, shutil, weakref -from sets import Set +# Python 2.3 ... 2.6 compatibility: +from roundup.anypy.sets_ import set # roundup modules import date, password @@ -194,7 +195,7 @@ # definitely in the new list (in case of e.g. # =A,+B, which should replace the old # list with A,B) - set = 1 + do_set = 1 newvalue = [] for item in value: item = item.strip() @@ -207,10 +208,10 @@ if item.startswith('-'): remove = 1 item = item[1:] - set = 0 + do_set = 0 elif item.startswith('+'): item = item[1:] - set = 0 + do_set = 0 # look up the value itemid = convertLinkValue(db, propname, self, item) @@ -229,7 +230,7 @@ # that's it, set the new Multilink property value, # or overwrite it completely - if set: + if do_set: value = newvalue else: value = curvalue @@ -488,7 +489,7 @@ v = self._val if not isinstance(self._val, type([])): v = [self._val] - vals = Set(v) + vals = set(v) vals.intersection_update(val) self._val = [v for v in vals] else: Index: roundup/password.py =================================================================== --- roundup/password.py (revision 4128) +++ roundup/password.py (working copy) @@ -21,12 +21,12 @@ """ __docformat__ = 'restructuredtext' -import sha, md5, re, string, random +import re, string, random +from roundup.anypy.hashlib_ import md5, sha1 try: import crypt -except: +except ImportError: crypt = None - pass class PasswordValueError(ValueError): ''' The password value is not valid ''' @@ -38,9 +38,9 @@ if plaintext is None: plaintext = "" if scheme == 'SHA': - s = sha.sha(plaintext).hexdigest() + s = sha1(plaintext).hexdigest() elif scheme == 'MD5': - s = md5.md5(plaintext).hexdigest() + s = md5(plaintext).hexdigest() elif scheme == 'crypt' and crypt is not None: if other is not None: salt = other Index: roundup/install_util.py =================================================================== --- roundup/install_util.py (revision 4128) +++ roundup/install_util.py (working copy) @@ -21,7 +21,8 @@ """ __docformat__ = 'restructuredtext' -import os, sha, shutil +import os, shutil +from roundup.anypy.hashlib_ import sha1 sgml_file_types = [".xml", ".ent", ".html"] hash_file_types = [".py", ".sh", ".conf", ".cgi"] @@ -59,7 +60,7 @@ del lines[-1] # calculate current digest - digest = sha.new() + digest = sha1() for line in lines: digest.update(line) @@ -74,7 +75,7 @@ def __init__(self, filename): self.filename = filename - self.digest = sha.new() + self.digest = sha1() self.file = open(self.filename, "w") def write(self, data): Index: roundup/anypy/hashlib_.py =================================================================== --- roundup/anypy/hashlib_.py (revision 0) +++ roundup/anypy/hashlib_.py (revision 0) @@ -0,0 +1,11 @@ +""" +anypy.hashlib_: encapsulation of hashlib/md5/sha1/sha +""" + +try: + from hashlib import md5, sha1 # new in Python 2.5 +except ImportError: + from md5 import md5 # deprecated in Python 2.6 + from sha import sha as sha1 # deprecated in Python 2.6 + +# vim: ts=8 sts=4 sw=4 si Index: roundup/anypy/TODO.TXT =================================================================== --- roundup/anypy/TODO.TXT (revision 0) +++ roundup/anypy/TODO.TXT (revision 0) @@ -0,0 +1,26 @@ +Python compatiblity TODO +~~~~~~~~~~~~~~~~~~~~~~~~ + +- the popen2 module is deprecated as of Python 2.6; + the subprocess module is available since Python 2.4, + thus a roundup.anypy.subprocess_ module is needed + +- the MimeWriter module is deprecated as of Python 2.6. The email package is + available since Python 2.2, thus we should manage without a ...email_ + module; however, it has suffered some API changes over the time + (http://docs.python.org/library/email.html#package-history), + so this is not sure. + + Here's an incomplete replacement table: + + MimeWriter usage checked for + -> email usage Python ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~ + MimeWriter.MimeWriter + -> email.Message.Message (2.3) + + MimeWriter.MimeWrite.addheader + -> email.Message.Message.add_header (2.3) + + +# vim: si Index: roundup/anypy/sets_.py =================================================================== --- roundup/anypy/sets_.py (revision 0) +++ roundup/anypy/sets_.py (revision 0) @@ -0,0 +1,30 @@ +""" +anypy.sets_: sets compatibility module + +uses the built-in type 'set' if available, and thus avoids +deprecation warnings. Simple usage: + +Change all + from sets import Set +to + from roundup.anypy.sets_ import set + +and use 'set' instead of 'Set'. +To avoid unnecessary imports, you can: + + try: + set + except NameError: + from roundup.anypy.sets_ import set + +see: +http://docs.python.org/library/sets.html#comparison-to-the-built-in-set-types + +""" + +try: + set = set # built-in since Python 2.4 +except NameError, TypeError: + from sets import Set as set # deprecated as of Python 2.6 + +# vim: ts=8 sts=4 sw=4 si et Index: roundup/anypy/__init__.py =================================================================== --- roundup/anypy/__init__.py (revision 0) +++ roundup/anypy/__init__.py (revision 0) @@ -0,0 +1,7 @@ +""" +roundup.anypy - compatibility layer for any Python 2.3+ +""" +VERSION = '.'.join(map(str, + (0, + 1, # hashlib_, sets_ + ))) Index: roundup/anypy/README.TXT =================================================================== --- roundup/anypy/README.TXT (revision 0) +++ roundup/anypy/README.TXT (revision 0) @@ -0,0 +1,57 @@ +roundup.anypy package - Python version compatibility layer +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Roundup currently supports Python 2.3 to 2.6; however, some modules +have been introduced, while others have been deprecated. The modules +in this package provide the functionalities which are used by Roundup + +- adapting the most recent Python usage +- using new built-in functionality +- avoiding deprecation warnings + +Use the modules in this package to preserve Roundup's compatibility. + +sets_: sets compatibility module +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Since Python 2.4, there is a built-in type 'set'; therefore, the 'sets' +module is deprecated since version 2.6. As far as Roundup is concerned, +the usage is identical; see +http://docs.python.org/library/sets.html#comparison-to-the-built-in-set-types + +Uses the built-in type 'set' if available, and thus avoids +deprecation warnings. Simple usage: + +Change all:: + from sets import Set + +to:: + from roundup.anypy.sets_ import set + +and use 'set' instead of 'Set' (or sets.Set, respectively). +To avoid unnecessary imports, you can:: + + try: + set + except NameError: + from roundup.anypy.sets_ import set + +hashlib_: md5/sha/hashlib compatibility +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The md5 and sha modules are deprecated since Python 2.6; the hashlib +module, introduced with Python 2.5, is recommended instead. + +Change all:: + import md5 + md5.md5(), md5.new() + import sha + sha.sha(), sha.new() + +to:: + from roundup.anypy.hashlib_ import md5 + md5() + from roundup.anypy.hashlib_ import sha1 + sha1() + +# vim: si Index: roundup/backends/indexer_common.py =================================================================== --- roundup/backends/indexer_common.py (revision 4128) +++ roundup/backends/indexer_common.py (working copy) @@ -1,5 +1,7 @@ #$Id: indexer_common.py,v 1.11 2008-09-11 19:41:07 schlatterbeck Exp $ -import re, sets +import re +# Python 2.3 ... 2.6 compatibility: +from roundup.anypy.sets_ import set from roundup import hyperdb @@ -17,7 +19,7 @@ class Indexer: def __init__(self, db): - self.stopwords = sets.Set(STOPWORDS) + self.stopwords = set(STOPWORDS) for word in db.config[('main', 'indexer_stopwords')]: self.stopwords.add(word) Index: roundup/backends/indexer_rdbms.py =================================================================== --- roundup/backends/indexer_rdbms.py (revision 4128) +++ roundup/backends/indexer_rdbms.py (working copy) @@ -3,7 +3,9 @@ is a mapping of words to occurance IDs. The second maps the IDs to (Class, propname, itemid) instances. ''' -import re, sets +import re +# Python 2.3 ... 2.6 compatibility: +from roundup.anypy.sets_ import set from roundup.backends.indexer_common import Indexer as IndexerBase @@ -65,7 +67,7 @@ text = unicode(text, "utf-8", "replace").upper() wordlist = [w.encode("utf-8", "replace") for w in re.findall(r'(?u)\b\w{2,25}\b', text)] - words = sets.Set() + words = set() for word in wordlist: if self.is_stopword(word): continue if len(word) > 25: continue Index: templates/classic/detectors/nosyreaction.py =================================================================== --- templates/classic/detectors/nosyreaction.py (revision 4128) +++ templates/classic/detectors/nosyreaction.py (working copy) @@ -17,7 +17,8 @@ # #$Id: nosyreaction.py,v 1.4 2005-04-04 08:47:14 richard Exp $ -import sets +# Python 2.3 ... 2.6 compatibility: +from roundup.anypy.sets_ import set from roundup import roundupdb, hyperdb @@ -67,7 +68,7 @@ '''Update the nosy list for changes to the assignedto ''' # nodeid will be None if this is a new node - current_nosy = sets.Set() + current_nosy = set() if nodeid is None: ok = ('new', 'yes') else: @@ -87,7 +88,7 @@ continue current_nosy.add(value) - new_nosy = sets.Set(current_nosy) + new_nosy = set(current_nosy) # add assignedto(s) to the nosy list if newvalues.has_key('assignedto') and newvalues['assignedto'] is not None: