git: 7e3893dcbb58 - main - devel/py-testoob: Fix build with setuptools 58.0.0+

From: Po-Chuan Hsieh <sunpoet_at_FreeBSD.org>
Date: Fri, 25 Mar 2022 13:50:14 UTC
The branch main has been updated by sunpoet:

URL: https://cgit.FreeBSD.org/ports/commit/?id=7e3893dcbb5817683ec6cb20d0e13a453bc05ff7

commit 7e3893dcbb5817683ec6cb20d0e13a453bc05ff7
Author:     Po-Chuan Hsieh <sunpoet@FreeBSD.org>
AuthorDate: 2022-03-25 13:32:25 +0000
Commit:     Po-Chuan Hsieh <sunpoet@FreeBSD.org>
CommitDate: 2022-03-25 13:38:12 +0000

    devel/py-testoob: Fix build with setuptools 58.0.0+
    
    With hat:       python
---
 devel/py-testoob/Makefile         |    2 +-
 devel/py-testoob/files/patch-2to3 | 1689 +++++++++++++++++++++++++++++++++++++
 2 files changed, 1690 insertions(+), 1 deletion(-)

diff --git a/devel/py-testoob/Makefile b/devel/py-testoob/Makefile
index b0783cdc5231..0f181e61f91c 100644
--- a/devel/py-testoob/Makefile
+++ b/devel/py-testoob/Makefile
@@ -18,7 +18,7 @@ OPTIONS_DEFINE=	TWISTED
 TWISTED_DESC=	enable running in threads
 
 NO_ARCH=	yes
-USES=		python:3.6+ tar:bzip2
+USES=		dos2unix python:3.6+ tar:bzip2
 USE_PYTHON=	autoplist distutils
 
 TWISTED_RUN_DEPENDS=	${PYTHON_PKGNAMEPREFIX}twisted>=0:devel/py-twisted@${PY_FLAVOR}
diff --git a/devel/py-testoob/files/patch-2to3 b/devel/py-testoob/files/patch-2to3
new file mode 100644
index 000000000000..3efb8ad30356
--- /dev/null
+++ b/devel/py-testoob/files/patch-2to3
@@ -0,0 +1,1689 @@
+--- src/testoob/asserter.py.orig	2022-03-18 18:45:28 UTC
++++ src/testoob/asserter.py
+@@ -32,7 +32,7 @@ class Asserter:
+         # Prevent recursion (accures in testoob tests, when ran with testoob :-) ).
+         if getattr(Class, method_name).__name__ == "_assert_reporting_func":
+             return
+-        variables = eval("Class.%s" % method_name).func_code.co_varnames
++        variables = eval("Class.%s" % method_name).__code__.co_varnames
+         setattr(Class, "_real_function_%s" % method_name, eval("Class.%s" % method_name))
+         method = eval("Class._real_function_%s" % method_name)
+         def _assert_reporting_func(*args, **kwargs):
+@@ -45,7 +45,7 @@ class Asserter:
+                 num_free_args -= 1
+                 additional_args = args[num_free_args:] + additional_args
+             # Can't be a dictionary, because the order matters.
+-            varList = zip(variables[1:], (args[1:num_free_args] + additional_args))
++            varList = list(zip(variables[1:], (args[1:num_free_args] + additional_args)))
+             # Here is some evil did to find the function which called me.
+             test = sys._getframe().f_back.f_locals["self"]
+             # If we run something that has no reporter, it should just run
+@@ -54,7 +54,7 @@ class Asserter:
+                 return method(*args, **kwargs)
+             try:
+                 method(*args, **kwargs)
+-            except Exception, e:
++            except Exception as e:
+                 self._reporters[test].addAssert(test, method_name, varList, e)
+                 raise
+             self._reporters[test].addAssert(test, method_name, varList, None)
+--- src/testoob/commandline/__init__.py.orig	2022-03-18 18:45:28 UTC
++++ src/testoob/commandline/__init__.py
+@@ -17,8 +17,8 @@ def module_list():
+ 
+ def load_options():
+     for module in module_list():
+-        exec "import %s" % module
++        exec("import %s" % module)
+ 
+ load_options()
+ 
+-import parsing
++from . import parsing
+--- src/testoob/compatibility/itertools.py.orig	2022-03-18 18:45:28 UTC
++++ src/testoob/compatibility/itertools.py
+@@ -20,8 +20,8 @@ takewhile(pred, seq) --> seq[0], seq[1], until pred fa
+ dropwhile(pred, seq) --> seq[n], seq[n+1], starting when pred fails
+ groupby(iterable[, keyfunc]) --> sub-iterators grouped by value of keyfunc(v)
+ """
+-from __future__ import generators
+ 
++
+ __all__ = ['chain', 'count', 'cycle', 'dropwhile', 'groupby', 'ifilter',
+            'ifilterfalse', 'imap', 'islice', 'izip', 'repeat', 'starmap',
+            'takewhile', 'tee']
+@@ -48,14 +48,14 @@ class chain:
+     def __iter__(self):
+         return self
+ 
+-    def next(self):
++    def __next__(self):
+         try:
+-            next_elt = self._cur_iterable_iter.next()
++            next_elt = next(self._cur_iterable_iter)
+         except StopIteration:
+             # The current list's iterator is exhausted, switch to next one
+-            self._cur_iterable_iter = iter(self._iterables_iter.next())
++            self._cur_iterable_iter = iter(next(self._iterables_iter))
+             try:
+-                next_elt = self._cur_iterable_iter.next()
++                next_elt = next(self._cur_iterable_iter)
+             except AttributeError:
+                 # CPython raises a TypeError when next() is not defined
+                 raise TypeError('%s has no next() method' % \
+@@ -92,7 +92,7 @@ class count:
+     def __iter__(self):
+         return self
+ 
+-    def next(self):
++    def __next__(self):
+         self.times += 1
+         return self.times
+ 
+@@ -125,15 +125,15 @@ class cycle:
+     def __iter__(self):
+         return self
+ 
+-    def next(self):
++    def __next__(self):
+         # XXX Could probably be improved
+         try:
+-            next_elt = self._cur_iter.next()
++            next_elt = next(self._cur_iter)
+             if self._must_save:
+                 self._saved.append(next_elt)
+         except StopIteration:
+             self._cur_iter = iter(self._saved)
+-            next_elt = self._cur_iter.next()
++            next_elt = next(self._cur_iter)
+             self._must_save = False
+         except AttributeError:
+             # CPython raises a TypeError when next() is not defined
+@@ -167,9 +167,9 @@ class dropwhile:
+     def __iter__(self):
+         return self
+ 
+-    def next(self):
++    def __next__(self):
+         try:
+-            value = self._iter.next()
++            value = next(self._iter)
+         except AttributeError:
+             # CPython raises a TypeError when next() is not defined
+             raise TypeError('%s has no next() method' % \
+@@ -177,7 +177,7 @@ class dropwhile:
+         if self._dropped:
+             return value
+         while self._predicate(value):
+-            value = self._iter.next()
++            value = next(self._iter)
+         self._dropped = True
+         return value
+ 
+@@ -205,15 +205,15 @@ class groupby:
+             key = lambda x: x
+         self.keyfunc = key
+         self.it = iter(iterable)
+-        self.tgtkey = self.currkey = self.currvalue = xrange(0)
++        self.tgtkey = self.currkey = self.currvalue = range(0)
+ 
+     def __iter__(self):
+         return self
+ 
+-    def next(self):
++    def __next__(self):
+         while self.currkey == self.tgtkey:
+             try:
+-                self.currvalue = self.it.next() # Exit on StopIteration
++                self.currvalue = next(self.it) # Exit on StopIteration
+             except AttributeError:
+                 # CPython raises a TypeError when next() is not defined
+                 raise TypeError('%s has no next() method' % \
+@@ -225,7 +225,7 @@ class groupby:
+     def _grouper(self, tgtkey):
+         while self.currkey == tgtkey:
+             yield self.currvalue
+-            self.currvalue = self.it.next() # Exit on StopIteration
++            self.currvalue = next(self.it) # Exit on StopIteration
+             self.currkey = self.keyfunc(self.currvalue)
+ 
+ 
+@@ -257,9 +257,9 @@ class ifilter(_ifilter_base):
+             if predicate(x):
+                 yield x
+     """
+-    def next(self):
++    def __next__(self):
+         try:
+-            next_elt = self._iter.next()
++            next_elt = next(self._iter)
+         except AttributeError:
+             # CPython raises a TypeError when next() is not defined
+             raise TypeError('%s has no next() method' % \
+@@ -267,7 +267,7 @@ class ifilter(_ifilter_base):
+         while True:
+             if self._predicate(next_elt):
+                 return next_elt
+-            next_elt = self._iter.next()
++            next_elt = next(self._iter)
+ 
+ class ifilterfalse(_ifilter_base):
+     """Make an iterator that filters elements from iterable returning
+@@ -283,9 +283,9 @@ class ifilterfalse(_ifilter_base):
+             if not predicate(x):
+                 yield x
+     """
+-    def next(self):
++    def __next__(self):
+         try:
+-            next_elt = self._iter.next()
++            next_elt = next(self._iter)
+         except AttributeError:
+             # CPython raises a TypeError when next() is not defined
+             raise TypeError('%s has no next() method' % \
+@@ -293,7 +293,7 @@ class ifilterfalse(_ifilter_base):
+         while True:
+             if not self._predicate(next_elt):
+                 return next_elt
+-            next_elt = self._iter.next()
++            next_elt = next(self._iter)
+ 
+ 
+ 
+@@ -322,14 +322,14 @@ class imap:
+     """
+     def __init__(self, function, iterable, *other_iterables):
+         self._func = function
+-        self._iters = map(iter, (iterable, ) + other_iterables)
++        self._iters = list(map(iter, (iterable, ) + other_iterables))
+ 
+     def __iter__(self):
+         return self
+ 
+-    def next(self):
++    def __next__(self):
+         try:
+-            args = [it.next() for it in self._iters]
++            args = [next(it) for it in self._iters]
+         except AttributeError:
+             # CPython raises a TypeError when next() is not defined
+             raise TypeError('%s has no next() method' % \
+@@ -357,15 +357,15 @@ class islice:
+     def __init__(self, iterable, *args):
+         s = slice(*args)
+         self.start, self.stop, self.step = s.start or 0, s.stop, s.step
+-        if not isinstance(self.start, (int, long)):
++        if not isinstance(self.start, int):
+            raise ValueError("Start argument must be an integer")
+-        if self.stop is not None and not isinstance(self.stop, (int,long)):
++        if self.stop is not None and not isinstance(self.stop, int):
+            raise ValueError("Stop argument must be an integer or None")
+         if self.step is None:
+             self.step = 1
+         if self.start<0 or (self.stop is not None and self.stop<0
+            ) or self.step<=0:
+-            raise ValueError, "indices for islice() must be positive"
++            raise ValueError("indices for islice() must be positive")
+         self.it = iter(iterable)
+         self.donext = None
+         self.cnt = 0
+@@ -373,10 +373,10 @@ class islice:
+     def __iter__(self):
+         return self
+ 
+-    def next(self):
++    def __next__(self):
+         if self.donext is None:
+             try:
+-                self.donext = self.it.next
++                self.donext = self.it.__next__
+             except AttributeError:
+                 raise TypeError
+         while self.cnt < self.start:
+@@ -403,17 +403,17 @@ class izip:
+             yield tuple(result)
+     """
+     def __init__(self, *iterables):
+-        self._iterators = map(iter, iterables)
++        self._iterators = list(map(iter, iterables))
+         self._result = [None] * len(self._iterators)
+ 
+     def __iter__(self):
+         return self
+ 
+-    def next(self):
++    def __next__(self):
+         if not self._iterators:
+             raise StopIteration()
+         try:
+-            return tuple([i.next() for i in self._iterators])
++            return tuple([next(i) for i in self._iterators])
+         except AttributeError:
+             # CPython raises a TypeError when next() is not defined
+             raise TypeError('%s has no next() method' % (i))
+@@ -439,7 +439,7 @@ class repeat:
+     def __init__(self, obj, times=None):
+         self._obj = obj
+         if times is not None:
+-            xrange(times) # Raise a TypeError
++            range(times) # Raise a TypeError
+             if times < 0:
+                 times = 0
+         self._times = times
+@@ -447,7 +447,7 @@ class repeat:
+     def __iter__(self):
+         return self
+ 
+-    def next(self):
++    def __next__(self):
+         # next() *need* to decrement self._times when consumed
+         if self._times is not None:
+             if self._times <= 0:
+@@ -489,10 +489,10 @@ class starmap:
+     def __iter__(self):
+         return self
+ 
+-    def next(self):
++    def __next__(self):
+         # CPython raises a TypeError when the iterator doesn't return a tuple
+         try:
+-            t = self._iter.next()
++            t = next(self._iter)
+         except AttributeError:
+             # CPython raises a TypeError when next() is not defined
+             raise TypeError('%s has no next() method' % self._iter)
+@@ -522,9 +522,9 @@ class takewhile:
+     def __iter__(self):
+         return self
+ 
+-    def next(self):
++    def __next__(self):
+         try:
+-            value = self._iter.next()
++            value = next(self._iter)
+         except AttributeError:
+             # CPython raises a TypeError when next() is not defined
+             raise TypeError('%s has no next() method' % \
+@@ -544,7 +544,7 @@ class TeeData(object):
+         # iterates until 'i' if not done yet
+         while i>= len(self.data):
+             try:
+-                self.data.append( self._iter.next() )
++                self.data.append( next(self._iter) )
+             except AttributeError:
+                 # CPython raises a TypeError when next() is not defined
+                 raise TypeError('%s has no next() method' % self._iter)
+@@ -565,7 +565,7 @@ class TeeObject(object):
+             self.tee_data = TeeData(iter(iterable))
+             self.pos = 0
+ 
+-    def next(self):
++    def __next__(self):
+         data = self.tee_data[self.pos]
+         self.pos += 1
+         return data
+@@ -603,6 +603,6 @@ def tee(iterable, n=2):
+     if isinstance(iterable, TeeObject):
+         # a,b = tee(range(10)) ; c,d = tee(a) ; self.assert_(a is c)
+         return tuple([iterable] +
+-        [TeeObject(tee_data=iterable.tee_data) for i in xrange(n-1)])
++        [TeeObject(tee_data=iterable.tee_data) for i in range(n-1)])
+     tee_data = TeeData(iter(iterable))
+-    return tuple([TeeObject(tee_data=tee_data) for i in xrange(n)])
++    return tuple([TeeObject(tee_data=tee_data) for i in range(n)])
+--- src/testoob/compatibility/optparse.py.orig	2022-03-18 18:45:28 UTC
++++ src/testoob/compatibility/optparse.py
+@@ -70,7 +70,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH D
+ 
+ import sys, os
+ import types
+-import textwrap
++from . import textwrap
+ 
+ class OptParseError (Exception):
+     def __init__ (self, msg):
+@@ -161,10 +161,10 @@ class HelpFormatter:
+         self.level -= 1
+ 
+     def format_usage (self, usage):
+-        raise NotImplementedError, "subclasses must implement"
++        raise NotImplementedError("subclasses must implement")
+ 
+     def format_heading (self, heading):
+-        raise NotImplementedError, "subclasses must implement"
++        raise NotImplementedError("subclasses must implement")
+ 
+     def format_description (self, description):
+         desc_width = self.width - self.current_indent
+@@ -280,7 +280,7 @@ class TitledHelpFormatter (HelpFormatter):
+ 
+ 
+ _builtin_cvt = { "int" : (int, "integer"),
+-                 "long" : (long, "long integer"),
++                 "long" : (int, "long integer"),
+                  "float" : (float, "floating-point"),
+                  "complex" : (complex, "complex") }
+ 
+@@ -434,7 +434,7 @@ class Option:
+         # Filter out None because early versions of Optik had exactly
+         # one short option and one long option, either of which
+         # could be None.
+-        opts = filter(None, opts)
++        opts = [_f for _f in opts if _f]
+         if not opts:
+             raise TypeError("at least one option string must be supplied")
+         return opts
+@@ -462,7 +462,7 @@ class Option:
+ 
+     def _set_attrs (self, attrs):
+         for attr in self.ATTRS:
+-            if attrs.has_key(attr):
++            if attr in attrs:
+                 setattr(self, attr, attrs[attr])
+                 del attrs[attr]
+             else:
+@@ -472,7 +472,7 @@ class Option:
+                     setattr(self, attr, None)
+         if attrs:
+             raise OptionError(
+-                "invalid keyword arguments: %s" % ", ".join(attrs.keys()),
++                "invalid keyword arguments: %s" % ", ".join(list(attrs.keys())),
+                 self)
+ 
+ 
+@@ -507,7 +507,7 @@ class Option:
+             if self.choices is None:
+                 raise OptionError(
+                     "must supply a list of choices for type 'choice'", self)
+-            elif type(self.choices) not in (types.TupleType, types.ListType):
++            elif type(self.choices) not in (tuple, list):
+                 raise OptionError(
+                     "choices must be a list of strings ('%s' supplied)"
+                     % str(type(self.choices)).split("'")[1], self)
+@@ -547,12 +547,12 @@ class Option:
+                 raise OptionError(
+                     "callback not callable: %r" % self.callback, self)
+             if (self.callback_args is not None and
+-                type(self.callback_args) is not types.TupleType):
++                type(self.callback_args) is not tuple):
+                 raise OptionError(
+                     "callback_args, if supplied, must be a tuple: not %r"
+                     % self.callback_args, self)
+             if (self.callback_kwargs is not None and
+-                type(self.callback_kwargs) is not types.DictType):
++                type(self.callback_kwargs) is not dict):
+                 raise OptionError(
+                     "callback_kwargs, if supplied, must be a dict: not %r"
+                     % self.callback_kwargs, self)
+@@ -636,7 +636,7 @@ class Option:
+             parser.print_version()
+             sys.exit(0)
+         else:
+-            raise RuntimeError, "unknown action %r" % self.action
++            raise RuntimeError("unknown action %r" % self.action)
+ 
+         return 1
+ 
+@@ -662,7 +662,7 @@ class Values:
+ 
+     def __init__ (self, defaults=None):
+         if defaults:
+-            for (attr, val) in defaults.items():
++            for (attr, val) in list(defaults.items()):
+                 setattr(self, attr, val)
+ 
+     def __repr__ (self):
+@@ -677,7 +677,7 @@ class Values:
+         are silently ignored.
+         """
+         for attr in dir(self):
+-            if dict.has_key(attr):
++            if attr in dict:
+                 dval = dict[attr]
+                 if dval is not None:
+                     setattr(self, attr, dval)
+@@ -696,7 +696,7 @@ class Values:
+         elif mode == "loose":
+             self._update_loose(dict)
+         else:
+-            raise ValueError, "invalid update mode: %r" % mode
++            raise ValueError("invalid update mode: %r" % mode)
+ 
+     def read_module (self, modname, mode="careful"):
+         __import__(modname)
+@@ -705,7 +705,7 @@ class Values:
+ 
+     def read_file (self, filename, mode="careful"):
+         vars = {}
+-        execfile(filename, vars)
++        exec(compile(open(filename, "rb").read(), filename, 'exec'), vars)
+         self._update(vars, mode)
+ 
+     def ensure_value (self, attr, value):
+@@ -775,7 +775,7 @@ class OptionContainer:
+ 
+     def set_conflict_handler (self, handler):
+         if handler not in ("ignore", "error", "resolve"):
+-            raise ValueError, "invalid conflict_resolution value %r" % handler
++            raise ValueError("invalid conflict_resolution value %r" % handler)
+         self.conflict_handler = handler
+ 
+     def set_description (self, description):
+@@ -787,10 +787,10 @@ class OptionContainer:
+     def _check_conflict (self, option):
+         conflict_opts = []
+         for opt in option._short_opts:
+-            if self._short_opt.has_key(opt):
++            if opt in self._short_opt:
+                 conflict_opts.append((opt, self._short_opt[opt]))
+         for opt in option._long_opts:
+-            if self._long_opt.has_key(opt):
++            if opt in self._long_opt:
+                 conflict_opts.append((opt, self._long_opt[opt]))
+ 
+         if conflict_opts:
+@@ -817,14 +817,14 @@ class OptionContainer:
+         """add_option(Option)
+            add_option(opt_str, ..., kwarg=val, ...)
+         """
+-        if type(args[0]) is types.StringType:
++        if type(args[0]) is bytes:
+             option = self.option_class(*args, **kwargs)
+         elif len(args) == 1 and not kwargs:
+             option = args[0]
+             if not isinstance(option, Option):
+-                raise TypeError, "not an Option instance: %r" % option
++                raise TypeError("not an Option instance: %r" % option)
+         else:
+-            raise TypeError, "invalid arguments"
++            raise TypeError("invalid arguments")
+ 
+         self._check_conflict(option)
+ 
+@@ -838,7 +838,7 @@ class OptionContainer:
+         if option.dest is not None:     # option has a dest, we need a default
+             if option.default is not NO_DEFAULT:
+                 self.defaults[option.dest] = option.default
+-            elif not self.defaults.has_key(option.dest):
++            elif option.dest not in self.defaults:
+                 self.defaults[option.dest] = None
+ 
+         return option
+@@ -854,8 +854,8 @@ class OptionContainer:
+                 self._long_opt.get(opt_str))
+ 
+     def has_option (self, opt_str):
+-        return (self._short_opt.has_key(opt_str) or
+-                self._long_opt.has_key(opt_str))
++        return (opt_str in self._short_opt or
++                opt_str in self._long_opt)
+ 
+     def remove_option (self, opt_str):
+         option = self._short_opt.get(opt_str)
+@@ -1065,16 +1065,16 @@ class OptionParser (OptionContainer):
+ 
+     def add_option_group (self, *args, **kwargs):
+         # XXX lots of overlap with OptionContainer.add_option()
+-        if type(args[0]) is types.StringType:
++        if type(args[0]) is bytes:
+             group = OptionGroup(self, *args, **kwargs)
+         elif len(args) == 1 and not kwargs:
+             group = args[0]
+             if not isinstance(group, OptionGroup):
+-                raise TypeError, "not an OptionGroup instance: %r" % group
++                raise TypeError("not an OptionGroup instance: %r" % group)
+             if group.parser is not self:
+-                raise ValueError, "invalid OptionGroup (wrong parser)"
++                raise ValueError("invalid OptionGroup (wrong parser)")
+         else:
+-            raise TypeError, "invalid arguments"
++            raise TypeError("invalid arguments")
+ 
+         self.option_groups.append(group)
+         return group
+@@ -1128,7 +1128,7 @@ class OptionParser (OptionContainer):
+ 
+         try:
+             stop = self._process_args(largs, rargs, values)
+-        except (BadOptionError, OptionValueError), err:
++        except (BadOptionError, OptionValueError) as err:
+             self.error(err.msg)
+ 
+         args = largs + rargs
+@@ -1313,7 +1313,7 @@ class OptionParser (OptionContainer):
+         or not defined.
+         """
+         if self.usage:
+-            print >>file, self.get_usage()
++            print(self.get_usage(), file=file)
+ 
+     def get_version (self):
+         if self.version:
+@@ -1330,7 +1330,7 @@ class OptionParser (OptionContainer):
+         name.  Does nothing if self.version is empty or undefined.
+         """
+         if self.version:
+-            print >>file, self.get_version()
++            print(self.get_version(), file=file)
+ 
+     def format_option_help (self, formatter=None):
+         if formatter is None:
+@@ -1381,11 +1381,11 @@ def _match_abbrev (s, wordmap):
+     'words', raise BadOptionError.
+     """
+     # Is there an exact match?
+-    if wordmap.has_key(s):
++    if s in wordmap:
+         return s
+     else:
+         # Isolate all words with s as a prefix.
+-        possibilities = [word for word in wordmap.keys()
++        possibilities = [word for word in list(wordmap.keys())
+                          if word.startswith(s)]
+         # No exact match, so there had better be just one possibility.
+         if len(possibilities) == 1:
+--- src/testoob/compatibility/sets.py.orig	2022-03-18 18:45:28 UTC
++++ src/testoob/compatibility/sets.py
+@@ -54,9 +54,9 @@ what's tested is actually `z in y'.
+ # - Raymond Hettinger added a number of speedups and other
+ #   improvements.
+ 
+-from __future__ import generators
++
+ try:
+-    from itertools import ifilter, ifilterfalse
++    from .itertools import ifilter, ifilterfalse
+ except ImportError:
+     # Code to make the module run under Py2.2
+     def ifilter(predicate, iterable):
+@@ -73,10 +73,6 @@ except ImportError:
+         for x in iterable:
+             if not predicate(x):
+                 yield x
+-    try:
+-        True, False
+-    except NameError:
+-        True, False = (0==0, 0!=0)
+ 
+ __all__ = ['BaseSet', 'Set', 'ImmutableSet']
+ 
+@@ -91,7 +87,7 @@ class BaseSet(object):
+         """This is an abstract class."""
+         # Don't call this from a concrete subclass!
+         if self.__class__ is BaseSet:
+-            raise TypeError, ("BaseSet is an abstract class.  "
++            raise TypeError("BaseSet is an abstract class.  "
+                               "Use Set or ImmutableSet.")
+ 
+     # Standard protocols: __len__, __repr__, __str__, __iter__
+@@ -111,7 +107,7 @@ class BaseSet(object):
+     __str__ = __repr__
+ 
+     def _repr(self, sorted=False):
+-        elements = self._data.keys()
++        elements = list(self._data.keys())
+         if sorted:
+             elements.sort()
+         return '%s(%r)' % (self.__class__.__name__, elements)
+@@ -121,7 +117,7 @@ class BaseSet(object):
+ 
+         This is the keys iterator for the underlying dict.
+         """
+-        return self._data.iterkeys()
++        return iter(self._data.keys())
+ 
+     # Three-way comparison is not supported.  However, because __eq__ is
+     # tried before __cmp__, if Set x == Set y, x.__eq__(y) returns True and
+@@ -129,7 +125,7 @@ class BaseSet(object):
+     # case).
+ 
+     def __cmp__(self, other):
+-        raise TypeError, "can't compare sets using cmp()"
++        raise TypeError("can't compare sets using cmp()")
+ 
+     # Equality comparisons using the underlying dicts.  Mixed-type comparisons
+     # are allowed here, where Set == z for non-Set z always returns False,
+@@ -231,7 +227,7 @@ class BaseSet(object):
+             little, big = self, other
+         else:
+             little, big = other, self
+-        common = ifilter(big._data.has_key, little)
++        common = filter(big._data.has_key, little)
+         return self.__class__(common)
+ 
+     def __xor__(self, other):
+@@ -256,9 +252,9 @@ class BaseSet(object):
+             otherdata = other._data
+         except AttributeError:
+             otherdata = Set(other)._data
+-        for elt in ifilterfalse(otherdata.has_key, selfdata):
++        for elt in filterfalse(otherdata.has_key, selfdata):
+             data[elt] = value
+-        for elt in ifilterfalse(selfdata.has_key, otherdata):
++        for elt in filterfalse(selfdata.has_key, otherdata):
+             data[elt] = value
+         return result
+ 
+@@ -283,7 +279,7 @@ class BaseSet(object):
+         except AttributeError:
+             otherdata = Set(other)._data
+         value = True
+-        for elt in ifilterfalse(otherdata.has_key, self):
++        for elt in filterfalse(otherdata.has_key, self):
+             data[elt] = value
+         return result
+ 
+@@ -309,7 +305,7 @@ class BaseSet(object):
+         self._binary_sanity_check(other)
+         if len(self) > len(other):  # Fast check for obvious cases
+             return False
+-        for elt in ifilterfalse(other._data.has_key, self):
++        for elt in filterfalse(other._data.has_key, self):
+             return False
+         return True
+ 
+@@ -318,7 +314,7 @@ class BaseSet(object):
+         self._binary_sanity_check(other)
+         if len(self) < len(other):  # Fast check for obvious cases
+             return False
+-        for elt in ifilterfalse(self._data.has_key, other):
++        for elt in filterfalse(self._data.has_key, other):
+             return False
+         return True
+ 
+@@ -340,7 +336,7 @@ class BaseSet(object):
+         # Check that the other argument to a binary operation is also
+         # a set, raising a TypeError otherwise.
+         if not isinstance(other, BaseSet):
+-            raise TypeError, "Binary operation only permitted between sets"
++            raise TypeError("Binary operation only permitted between sets")
+ 
+     def _compute_hash(self):
+         # Calculate hash code for a set by xor'ing the hash codes of
+@@ -438,7 +434,7 @@ class Set(BaseSet):
+     def __hash__(self):
+         """A Set cannot be hashed."""
+         # We inherit object.__hash__, so we must deny this explicitly
+-        raise TypeError, "Can't hash a Set, only an ImmutableSet."
++        raise TypeError("Can't hash a Set, only an ImmutableSet.")
+ 
+     # In-place union, intersection, differences.
+     # Subtle:  The xyz_update() functions deliberately return None,
+@@ -501,7 +497,7 @@ class Set(BaseSet):
+             other = Set(other)
+         if self is other:
+             self.clear()
+-        for elt in ifilter(data.has_key, other):
++        for elt in filter(data.has_key, other):
+             del data[elt]
+ 
+     # Python dict-like mass mutations: update, clear
+--- src/testoob/compatibility/subprocess.py.orig	2022-03-18 18:45:28 UTC
++++ src/testoob/compatibility/subprocess.py
+@@ -403,13 +403,6 @@ try:
+ except:
+     MAXFD = 256
+ 
+-# True/False does not exist on 2.2.0
+-try:
+-    False
+-except NameError:
+-    False = 0
+-    True = 1
+-
+ _active = []
+ 
+ def _cleanup():
+@@ -600,7 +593,7 @@ class Popen(object):
+                 # Detach and turn into fd
+                 p2cwrite = p2cwrite.Detach()
+                 p2cwrite = msvcrt.open_osfhandle(p2cwrite, 0)
+-            elif type(stdin) == types.IntType:
++            elif type(stdin) == int:
+                 p2cread = msvcrt.get_osfhandle(stdin)
+             else:
+                 # Assuming file-like object
+@@ -614,7 +607,7 @@ class Popen(object):
+                 # Detach and turn into fd
+                 c2pread = c2pread.Detach()
+                 c2pread = msvcrt.open_osfhandle(c2pread, 0)
+-            elif type(stdout) == types.IntType:
++            elif type(stdout) == int:
+                 c2pwrite = msvcrt.get_osfhandle(stdout)
+             else:
+                 # Assuming file-like object
+@@ -630,7 +623,7 @@ class Popen(object):
+                 errread = msvcrt.open_osfhandle(errread, 0)
+             elif stderr == STDOUT:
+                 errwrite = c2pwrite
+-            elif type(stderr) == types.IntType:
++            elif type(stderr) == int:
+                 errwrite = msvcrt.get_osfhandle(stderr)
+             else:
+                 # Assuming file-like object
+@@ -673,13 +666,13 @@ class Popen(object):
+                            errread, errwrite):
+             """Execute program (MS Windows version)"""
+ 
+-            if not isinstance(args, types.StringTypes):
++            if not isinstance(args, (str,)):
+                 args = list2cmdline(args)
+ 
+             if shell:
+                 comspec = os.environ.get("COMSPEC", "cmd.exe")
+                 args = comspec + " /c " + args
+-                if (GetVersion() >= 0x80000000L or
++                if (GetVersion() >= 0x80000000 or
+                         os.path.basename(comspec).lower() == "command.com"):
+                     # Win9x, or using command.com on NT. We need to
+                     # use the w9xpopen intermediate program. For more
+@@ -716,7 +709,7 @@ class Popen(object):
+                                          env,
+                                          cwd,
+                                          startupinfo)
+-            except pywintypes.error, e:
++            except pywintypes.error as e:
+                 # Translate pywintypes.error to WindowsError, which is
+                 # a subclass of OSError.  FIXME: We should really
+                 # translate errno using _sys_errlist (or simliar), but
+@@ -835,7 +828,7 @@ class Popen(object):
+                 pass
+             elif stdin == PIPE:
+                 p2cread, p2cwrite = os.pipe()
+-            elif type(stdin) == types.IntType:
++            elif type(stdin) == int:
+                 p2cread = stdin
+             else:
+                 # Assuming file-like object
+@@ -845,7 +838,7 @@ class Popen(object):
+                 pass
+             elif stdout == PIPE:
+                 c2pread, c2pwrite = os.pipe()
+-            elif type(stdout) == types.IntType:
++            elif type(stdout) == int:
+                 c2pwrite = stdout
+             else:
+                 # Assuming file-like object
+@@ -857,7 +850,7 @@ class Popen(object):
+                 errread, errwrite = os.pipe()
+             elif stderr == STDOUT:
+                 errwrite = c2pwrite
+-            elif type(stderr) == types.IntType:
++            elif type(stderr) == int:
+                 errwrite = stderr
+             else:
+                 # Assuming file-like object
+@@ -896,7 +889,7 @@ class Popen(object):
+                            errread, errwrite):
+             """Execute program (POSIX version)"""
+ 
+-            if isinstance(args, types.StringTypes):
++            if isinstance(args, (str,)):
+                 args = [args]
+ 
+             if shell:
+@@ -1100,8 +1093,8 @@ def _demo_posix():
+     # Example 1: Simple redirection: Get process list
+     #
+     plist = Popen(["ps"], stdout=PIPE).communicate()[0]
+-    print "Process list:"
+-    print plist
++    print("Process list:")
++    print(plist)
+ 
+     #
+     # Example 2: Change uid before executing child
+@@ -1113,42 +1106,42 @@ def _demo_posix():
+     #
+     # Example 3: Connecting several subprocesses
+     #
+-    print "Looking for 'hda'..."
++    print("Looking for 'hda'...")
+     p1 = Popen(["dmesg"], stdout=PIPE)
+     p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
+-    print repr(p2.communicate()[0])
++    print(repr(p2.communicate()[0]))
+ 
+     #
+     # Example 4: Catch execution error
+     #
+-    print
+-    print "Trying a weird file..."
++    print()
++    print("Trying a weird file...")
+     try:
+-        print Popen(["/this/path/does/not/exist"]).communicate()
+-    except OSError, e:
++        print(Popen(["/this/path/does/not/exist"]).communicate())
++    except OSError as e:
+         if e.errno == errno.ENOENT:
+-            print "The file didn't exist.  I thought so..."
+-            print "Child traceback:"
+-            print e.child_traceback
++            print("The file didn't exist.  I thought so...")
++            print("Child traceback:")
++            print(e.child_traceback)
+         else:
+-            print "Error", e.errno
++            print("Error", e.errno)
+     else:
+-        print >>sys.stderr, "Gosh.  No error."
++        print("Gosh.  No error.", file=sys.stderr)
+ 
+ 
+ def _demo_windows():
+     #
+     # Example 1: Connecting several subprocesses
+     #
+-    print "Looking for 'PROMPT' in set output..."
++    print("Looking for 'PROMPT' in set output...")
+     p1 = Popen("set", stdout=PIPE, shell=True)
+     p2 = Popen('find "PROMPT"', stdin=p1.stdout, stdout=PIPE)
+-    print repr(p2.communicate()[0])
++    print(repr(p2.communicate()[0]))
+ 
+     #
+     # Example 2: Simple execution of program
+     #
+-    print "Executing calc..."
++    print("Executing calc...")
+     p = Popen("calc")
+     p.wait()
+ 
+--- src/testoob/compatibility/textwrap.py.orig	2022-03-18 18:45:28 UTC
++++ src/testoob/compatibility/textwrap.py
+@@ -10,14 +10,6 @@ __revision__ = "$Id: textwrap.py,v 1.32.8.2 2004/05/13
+ 
+ import string, re
+ 
+-# Do the right thing with boolean values for all known Python versions
+-# (so this module can be copied to projects that don't depend on Python
+-# 2.3, e.g. Optik and Docutils).
+-try:
+-    True, False
+-except NameError:
+-    (True, False) = (1, 0)
+-
+ __all__ = ['TextWrapper', 'wrap', 'fill']
+ 
+ # Hardcode the recognized whitespace characters to the US-ASCII
+@@ -69,7 +61,7 @@ class TextWrapper:
+     whitespace_trans = string.maketrans(_whitespace, ' ' * len(_whitespace))
+ 
+     unicode_whitespace_trans = {}
+-    uspace = ord(u' ')
++    uspace = ord(' ')
+     for x in map(ord, _whitespace):
+         unicode_whitespace_trans[x] = uspace
+ 
+@@ -123,7 +115,7 @@ class TextWrapper:
+         if self.replace_whitespace:
+             if isinstance(text, str):
+                 text = text.translate(self.whitespace_trans)
+-            elif isinstance(text, unicode):
++            elif isinstance(text, str):
+                 text = text.translate(self.unicode_whitespace_trans)
+         return text
+ 
+@@ -140,7 +132,7 @@ class TextWrapper:
+           'use', ' ', 'the', ' ', '-b', ' ', 'option!'
+         """
+         chunks = self.wordsep_re.split(text)
+-        chunks = filter(None, chunks)
++        chunks = [_f for _f in chunks if _f]
+         return chunks
+ 
+     def _fix_sentence_endings(self, chunks):
+--- src/testoob/compatibility/trace.py.orig	2022-03-18 18:45:28 UTC
++++ src/testoob/compatibility/trace.py
+@@ -59,7 +59,7 @@ import types
+ import gc
+ 
+ try:
+-    import cPickle
++    import pickle
+     pickle = cPickle
+ except ImportError:
+     import pickle
+@@ -116,11 +116,11 @@ class Ignore:
+         self._mods = modules or []
+         self._dirs = dirs or []
*** 739 LINES SKIPPED ***