From: Michael Olbrich <m.olbrich@pengutronix.de>
To: ptxdist@pengutronix.de
Cc: Roland Hieber <rhi@pengutronix.de>
Subject: Re: [ptxdist] [APPLIED] canfestival: port to Python 3
Date: Tue, 19 Mar 2024 07:44:54 +0100 [thread overview]
Message-ID: <20240319064454.3793651-1-m.olbrich@pengutronix.de> (raw)
In-Reply-To: <20240312103109.3581087-1-rhi@pengutronix.de>
Thanks, applied as 1ac1aaf668c383d54431e262c68ee0b539c15cae.
Michael
[sent from post-receive hook]
On Tue, 19 Mar 2024 07:44:54 +0100, Roland Hieber <rhi@pengutronix.de> wrote:
> The gnosis library is extracted and moved around by the objdictgen
> Makefile. Extract it early and do the same moving-around in the extract
> stage so we can patch it in PTXdist.
>
> Not all of the Python code was ported, only enough to make the build
> work, which calls objdictgen.py to generate the C code for the examples.
> The examples are fairly extensive, so this should work for most
> user-supplied XML schema definitions. Of gnosis, only the XML pickle
> modules and the introspection module was ported since those are the only
> modules used by objdictgen. The test cases were mostly ignored, and some
> of them that test Python-specific class internals also don't apply any
> more since Python 3 refactored the whole type system. Also no care was
> taken to stay compatible with Python 1 (duh!) or Python 2.
>
> Upstream is apparently still dead, judging from the Mercurial repo (last
> commit in 2019), the messages in the SourceForge mailing list archive
> (last message in 2020, none by the authors), and the issue tracker (last
> in 2020, none by the authors). gnosis is a whole different can of worms
> which doesn't even have a publicly available repository or contact
> information. So no attempt was made to send the changes upstream.
>
> Remove a comment which referenced the old repository URL, which no
> longer exists, and remove the recipe from staging.
>
> Signed-off-by: Roland Hieber <rhi@pengutronix.de>
> Message-Id: <20240312103109.3581087-1-rhi@pengutronix.de>
> Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
>
> diff --git a/patches/canfestival-3+hg20180126.794/0007-gnosis-port-to-python3.patch b/patches/canfestival-3+hg20180126.794/0007-gnosis-port-to-python3.patch
> new file mode 100644
> index 000000000000..bc62c6b9a4e0
> --- /dev/null
> +++ b/patches/canfestival-3+hg20180126.794/0007-gnosis-port-to-python3.patch
> @@ -0,0 +1,1912 @@
> +From: Roland Hieber <rhi@pengutronix.de>
> +Date: Sun, 11 Feb 2024 22:51:48 +0100
> +Subject: [PATCH] gnosis: port to python3
> +
> +Not all of the code was ported, only enough to make objdictgen calls in
> +the Makefile work enough to generate the code in examples/.
> +---
> + objdictgen/gnosis/__init__.py | 7 +-
> + objdictgen/gnosis/doc/xml_matters_39.txt | 2 +-
> + objdictgen/gnosis/indexer.py | 2 +-
> + objdictgen/gnosis/magic/dtdgenerator.py | 2 +-
> + objdictgen/gnosis/magic/multimethods.py | 4 +-
> + objdictgen/gnosis/pyconfig.py | 34 ++++-----
> + objdictgen/gnosis/trigramlib.py | 2 +-
> + objdictgen/gnosis/util/XtoY.py | 22 +++---
> + objdictgen/gnosis/util/introspect.py | 30 ++++----
> + objdictgen/gnosis/util/test/__init__.py | 0
> + objdictgen/gnosis/util/test/funcs.py | 2 +-
> + objdictgen/gnosis/util/test/test_data2attr.py | 16 ++---
> + objdictgen/gnosis/util/test/test_introspect.py | 39 +++++-----
> + objdictgen/gnosis/util/test/test_noinit.py | 43 ++++++------
> + .../gnosis/util/test/test_variants_noinit.py | 53 +++++++++-----
> + objdictgen/gnosis/util/xml2sql.py | 2 +-
> + objdictgen/gnosis/xml/indexer.py | 14 ++--
> + objdictgen/gnosis/xml/objectify/_objectify.py | 14 ++--
> + objdictgen/gnosis/xml/objectify/utils.py | 4 +-
> + objdictgen/gnosis/xml/pickle/__init__.py | 4 +-
> + objdictgen/gnosis/xml/pickle/_pickle.py | 82 ++++++++++------------
> + objdictgen/gnosis/xml/pickle/doc/HOWTO.extensions | 6 +-
> + objdictgen/gnosis/xml/pickle/exception.py | 2 +
> + objdictgen/gnosis/xml/pickle/ext/__init__.py | 2 +-
> + objdictgen/gnosis/xml/pickle/ext/_mutate.py | 17 +++--
> + objdictgen/gnosis/xml/pickle/ext/_mutators.py | 14 ++--
> + objdictgen/gnosis/xml/pickle/parsers/_dom.py | 34 ++++-----
> + objdictgen/gnosis/xml/pickle/parsers/_sax.py | 41 ++++++-----
> + objdictgen/gnosis/xml/pickle/test/test_all.py | 6 +-
> + .../gnosis/xml/pickle/test/test_badstring.py | 2 +-
> + objdictgen/gnosis/xml/pickle/test/test_bltin.py | 2 +-
> + objdictgen/gnosis/xml/pickle/test/test_mutators.py | 18 ++---
> + objdictgen/gnosis/xml/pickle/test/test_unicode.py | 31 ++++----
> + objdictgen/gnosis/xml/pickle/util/__init__.py | 4 +-
> + objdictgen/gnosis/xml/pickle/util/_flags.py | 11 ++-
> + objdictgen/gnosis/xml/pickle/util/_util.py | 20 +++---
> + objdictgen/gnosis/xml/relax/lex.py | 12 ++--
> + objdictgen/gnosis/xml/relax/rnctree.py | 2 +-
> + objdictgen/gnosis/xml/xmlmap.py | 32 ++++-----
> + 39 files changed, 322 insertions(+), 312 deletions(-)
> + create mode 100644 objdictgen/gnosis/util/test/__init__.py
> + create mode 100644 objdictgen/gnosis/xml/pickle/exception.py
> +
> +diff --git a/objdictgen/gnosis/__init__.py b/objdictgen/gnosis/__init__.py
> +index ec2768738626..8d7bc5a5a467 100644
> +--- a/objdictgen/gnosis/__init__.py
> ++++ b/objdictgen/gnosis/__init__.py
> +@@ -1,9 +1,8 @@
> + import string
> + from os import sep
> +-s = string
> +-d = s.join(s.split(__file__, sep)[:-1], sep)+sep
> +-_ = lambda f: s.rstrip(open(d+f).read())
> +-l = lambda f: s.split(_(f),'\n')
> ++d = sep.join(__file__.split(sep)[:-1])+sep
> ++_ = lambda f: open(d+f).read().rstrip()
> ++l = lambda f: _(f).split('\n')
> +
> + try:
> + __doc__ = _('README')
> +diff --git a/objdictgen/gnosis/doc/xml_matters_39.txt b/objdictgen/gnosis/doc/xml_matters_39.txt
> +index 136c20a6ae95..b2db8b83fd92 100644
> +--- a/objdictgen/gnosis/doc/xml_matters_39.txt
> ++++ b/objdictgen/gnosis/doc/xml_matters_39.txt
> +@@ -273,7 +273,7 @@ SERIALIZING TO XML
> + out.write(' %s=%s' % attr)
> + out.write('>')
> + for node in content(o):
> +- if type(node) in StringTypes:
> ++ if type(node) == str:
> + out.write(node)
> + else:
> + write_xml(node, out=out)
> +diff --git a/objdictgen/gnosis/indexer.py b/objdictgen/gnosis/indexer.py
> +index e975afd5aeb6..60f1b742ec94 100644
> +--- a/objdictgen/gnosis/indexer.py
> ++++ b/objdictgen/gnosis/indexer.py
> +@@ -182,7 +182,7 @@ def recurse_files(curdir, pattern, exclusions, func=echo_fname, *args, **kw):
> + elif type(pattern)==type(re.compile('')):
> + if pattern.match(name):
> + files.append(fname)
> +- elif type(pattern) is StringType:
> ++ elif type(pattern) is str:
> + if fnmatch.fnmatch(name, pattern):
> + files.append(fname)
> +
> +diff --git a/objdictgen/gnosis/magic/dtdgenerator.py b/objdictgen/gnosis/magic/dtdgenerator.py
> +index 9f6368f4c0df..d06f80364616 100644
> +--- a/objdictgen/gnosis/magic/dtdgenerator.py
> ++++ b/objdictgen/gnosis/magic/dtdgenerator.py
> +@@ -83,7 +83,7 @@ class DTDGenerator(type):
> + map(lambda x: expand(x, subs), subs.keys())
> +
> + # On final pass, substitute-in to the declarations
> +- for decl, i in zip(decl_list, xrange(maxint)):
> ++ for decl, i in zip(decl_list, range(maxint)):
> + for name, sub in subs.items():
> + decl = decl.replace(name, sub)
> + decl_list[i] = decl
> +diff --git a/objdictgen/gnosis/magic/multimethods.py b/objdictgen/gnosis/magic/multimethods.py
> +index 699f4ffb5bbe..d1fe0302e631 100644
> +--- a/objdictgen/gnosis/magic/multimethods.py
> ++++ b/objdictgen/gnosis/magic/multimethods.py
> +@@ -59,7 +59,7 @@ def lexicographic_mro(signature, matches):
> + # Schwartzian transform to weight match sigs, left-to-right"
> + proximity = lambda klass, mro: mro.index(klass)
> + mros = [klass.mro() for klass in signature]
> +- for (sig,func,nm),i in zip(matches,xrange(1000)):
> ++ for (sig,func,nm),i in zip(matches,range(1000)):
> + matches[i] = (map(proximity, sig, mros), matches[i])
> + matches.sort()
> + return map(lambda t:t[1], matches)
> +@@ -71,7 +71,7 @@ def weighted_mro(signature, matches):
> + proximity = lambda klass, mro: mro.index(klass)
> + sum = lambda lst: reduce(add, lst)
> + mros = [klass.mro() for klass in signature]
> +- for (sig,func,nm),i in zip(matches,xrange(1000)):
> ++ for (sig,func,nm),i in zip(matches,range(1000)):
> + matches[i] = (sum(map(proximity,sig,mros)), matches[i])
> + matches.sort()
> + return map(lambda t:t[1], matches)
> +diff --git a/objdictgen/gnosis/pyconfig.py b/objdictgen/gnosis/pyconfig.py
> +index b2419f2c4ba3..255fe42f9a1f 100644
> +--- a/objdictgen/gnosis/pyconfig.py
> ++++ b/objdictgen/gnosis/pyconfig.py
> +@@ -45,7 +45,7 @@
> + # just that each testcase compiles & runs OK.
> +
> + # Note: Compatibility with Python 1.5 is required here.
> +-import __builtin__, string
> ++import string
> +
> + # FYI, there are tests for these PEPs:
> + #
> +@@ -105,15 +105,15 @@ def compile_code( codestr ):
> + if codestr and codestr[-1] != '\n':
> + codestr = codestr + '\n'
> +
> +- return __builtin__.compile(codestr, 'dummyname', 'exec')
> ++ return compile(codestr, 'dummyname', 'exec')
> +
> + def can_run_code( codestr ):
> + try:
> + eval( compile_code(codestr) )
> + return 1
> +- except Exception,exc:
> ++ except Exception as exc:
> + if SHOW_DEBUG_INFO:
> +- print "RUN EXC ",str(exc)
> ++ print("RUN EXC ",str(exc))
> +
> + return 0
> +
> +@@ -359,11 +359,11 @@ def Can_AssignDoc():
> +
> + def runtest(msg, test):
> + r = test()
> +- print "%-40s %s" % (msg,['no','yes'][r])
> ++ print("%-40s %s" % (msg,['no','yes'][r]))
> +
> + def runtest_1arg(msg, test, arg):
> + r = test(arg)
> +- print "%-40s %s" % (msg,['no','yes'][r])
> ++ print("%-40s %s" % (msg,['no','yes'][r]))
> +
> + if __name__ == '__main__':
> +
> +@@ -372,37 +372,37 @@ if __name__ == '__main__':
> + # show banner w/version
> + try:
> + v = sys.version_info
> +- print "Python %d.%d.%d-%s [%s, %s]" % (v[0],v[1],v[2],str(v[3]),
> +- os.name,sys.platform)
> ++ print("Python %d.%d.%d-%s [%s, %s]" % (v[0],v[1],v[2],str(v[3]),
> ++ os.name,sys.platform))
> + except:
> + # Python 1.5 lacks sys.version_info
> +- print "Python %s [%s, %s]" % (string.split(sys.version)[0],
> +- os.name,sys.platform)
> ++ print("Python %s [%s, %s]" % (string.split(sys.version)[0],
> ++ os.name,sys.platform))
> +
> + # Python 1.5
> +- print " ** Python 1.5 features **"
> ++ print(" ** Python 1.5 features **")
> + runtest("Can assign to __doc__?", Can_AssignDoc)
> +
> + # Python 1.6
> +- print " ** Python 1.6 features **"
> ++ print(" ** Python 1.6 features **")
> + runtest("Have Unicode?", Have_Unicode)
> + runtest("Have string methods?", Have_StringMethods)
> +
> + # Python 2.0
> +- print " ** Python 2.0 features **"
> ++ print(" ** Python 2.0 features **" )
> + runtest("Have augmented assignment?", Have_AugmentedAssignment)
> + runtest("Have list comprehensions?", Have_ListComprehensions)
> + runtest("Have 'import module AS ...'?", Have_ImportAs)
> +
> + # Python 2.1
> +- print " ** Python 2.1 features **"
> ++ print(" ** Python 2.1 features **" )
> + runtest("Have __future__?", Have_Future)
> + runtest("Have rich comparison?", Have_RichComparison)
> + runtest("Have function attributes?", Have_FunctionAttributes)
> + runtest("Have nested scopes?", Have_NestedScopes)
> +
> + # Python 2.2
> +- print " ** Python 2.2 features **"
> ++ print(" ** Python 2.2 features **" )
> + runtest("Have True/False?", Have_TrueFalse)
> + runtest("Have 'object' type?", Have_ObjectClass)
> + runtest("Have __slots__?", Have_Slots)
> +@@ -415,7 +415,7 @@ if __name__ == '__main__':
> + runtest("Unified longs/ints?", Have_UnifiedLongInts)
> +
> + # Python 2.3
> +- print " ** Python 2.3 features **"
> ++ print(" ** Python 2.3 features **" )
> + runtest("Have enumerate()?", Have_Enumerate)
> + runtest("Have basestring?", Have_Basestring)
> + runtest("Longs > maxint in range()?", Have_LongRanges)
> +@@ -425,7 +425,7 @@ if __name__ == '__main__':
> + runtest_1arg("bool is a baseclass [expect 'no']?", IsLegal_BaseClass, 'bool')
> +
> + # Python 2.4
> +- print " ** Python 2.4 features **"
> ++ print(" ** Python 2.4 features **" )
> + runtest("Have builtin sets?", Have_BuiltinSets)
> + runtest("Have function/method decorators?", Have_Decorators)
> + runtest("Have multiline imports?", Have_MultilineImports)
> +diff --git a/objdictgen/gnosis/trigramlib.py b/objdictgen/gnosis/trigramlib.py
> +index 3127638e22a0..3dc75ef16f49 100644
> +--- a/objdictgen/gnosis/trigramlib.py
> ++++ b/objdictgen/gnosis/trigramlib.py
> +@@ -23,7 +23,7 @@ def simplify_null(text):
> + def generate_trigrams(text, simplify=simplify):
> + "Iterator on trigrams in (simplified) text"
> + text = simplify(text)
> +- for i in xrange(len(text)-3):
> ++ for i in range(len(text)-3):
> + yield text[i:i+3]
> +
> + def read_trigrams(fname):
> +diff --git a/objdictgen/gnosis/util/XtoY.py b/objdictgen/gnosis/util/XtoY.py
> +index 9e2816216488..fc252b5d3dd0 100644
> +--- a/objdictgen/gnosis/util/XtoY.py
> ++++ b/objdictgen/gnosis/util/XtoY.py
> +@@ -27,20 +27,20 @@ def aton(s):
> +
> + if re.match(re_float, s): return float(s)
> +
> +- if re.match(re_long, s): return long(s)
> ++ if re.match(re_long, s): return int(s[:-1]) # remove 'L' postfix
> +
> + if re.match(re_int, s): return int(s)
> +
> + m = re.match(re_hex, s)
> + if m:
> +- n = long(m.group(3),16)
> ++ n = int(m.group(3),16)
> + if n < sys.maxint: n = int(n)
> + if m.group(1)=='-': n = n * (-1)
> + return n
> +
> + m = re.match(re_oct, s)
> + if m:
> +- n = long(m.group(3),8)
> ++ n = int(m.group(3),8)
> + if n < sys.maxint: n = int(n)
> + if m.group(1)=='-': n = n * (-1)
> + return n
> +@@ -51,28 +51,26 @@ def aton(s):
> + r, i = s.split(':')
> + return complex(float(r), float(i))
> +
> +- raise SecurityError, \
> +- "Malicious string '%s' passed to to_number()'d" % s
> ++ raise SecurityError( \
> ++ "Malicious string '%s' passed to to_number()'d" % s)
> +
> + # we use ntoa() instead of repr() to ensure we have a known output format
> + def ntoa(n):
> + "Convert a number to a string without calling repr()"
> +- if isinstance(n,IntType):
> +- s = "%d" % n
> +- elif isinstance(n,LongType):
> ++ if isinstance(n,int):
> + s = "%ldL" % n
> +- elif isinstance(n,FloatType):
> ++ elif isinstance(n,float):
> + s = "%.17g" % n
> + # ensure a '.', adding if needed (unless in scientific notation)
> + if '.' not in s and 'e' not in s:
> + s = s + '.'
> +- elif isinstance(n,ComplexType):
> ++ elif isinstance(n,complex):
> + # these are always used as doubles, so it doesn't
> + # matter if the '.' shows up
> + s = "%.17g:%.17g" % (n.real,n.imag)
> + else:
> +- raise ValueError, \
> +- "Unknown numeric type: %s" % repr(n)
> ++ raise ValueError( \
> ++ "Unknown numeric type: %s" % repr(n))
> + return s
> +
> + def to_number(s):
> +diff --git a/objdictgen/gnosis/util/introspect.py b/objdictgen/gnosis/util/introspect.py
> +index 2eef3679211e..bf7425277d17 100644
> +--- a/objdictgen/gnosis/util/introspect.py
> ++++ b/objdictgen/gnosis/util/introspect.py
> +@@ -18,12 +18,10 @@ from types import *
> + from operator import add
> + from gnosis.util.combinators import or_, not_, and_, lazy_any
> +
> +-containers = (ListType, TupleType, DictType)
> +-simpletypes = (IntType, LongType, FloatType, ComplexType, StringType)
> +-if gnosis.pyconfig.Have_Unicode():
> +- simpletypes = simpletypes + (UnicodeType,)
> ++containers = (list, tuple, dict)
> ++simpletypes = (int, float, complex, str)
> + datatypes = simpletypes+containers
> +-immutabletypes = simpletypes+(TupleType,)
> ++immutabletypes = simpletypes+(tuple,)
> +
> + class undef: pass
> +
> +@@ -34,15 +32,13 @@ def isinstance_any(o, types):
> +
> + isContainer = lambda o: isinstance_any(o, containers)
> + isSimpleType = lambda o: isinstance_any(o, simpletypes)
> +-isInstance = lambda o: type(o) is InstanceType
> ++isInstance = lambda o: isinstance(o, object)
> + isImmutable = lambda o: isinstance_any(o, immutabletypes)
> +
> +-if gnosis.pyconfig.Have_ObjectClass():
> +- isNewStyleInstance = lambda o: issubclass(o.__class__,object) and \
> +- not type(o) in datatypes
> +-else:
> +- isNewStyleInstance = lambda o: 0
> +-isOldStyleInstance = lambda o: isinstance(o, ClassType)
> ++# Python 3 only has new-style classes
> ++import inspect
> ++isNewStyleInstance = lambda o: inspect.isclass(o)
> ++isOldStyleInstance = lambda o: False
> + isClass = or_(isOldStyleInstance, isNewStyleInstance)
> +
> + if gnosis.pyconfig.Have_ObjectClass():
> +@@ -95,7 +91,7 @@ def attr_dict(o, fillslots=0):
> + dct[attr] = getattr(o,attr)
> + return dct
> + else:
> +- raise TypeError, "Object has neither __dict__ nor __slots__"
> ++ raise TypeError("Object has neither __dict__ nor __slots__")
> +
> + attr_keys = lambda o: attr_dict(o).keys()
> + attr_vals = lambda o: attr_dict(o).values()
> +@@ -129,10 +125,10 @@ def setCoreData(o, data, force=0):
> + new = o.__class__(data)
> + attr_update(new, attr_dict(o)) # __slots__ safe attr_dict()
> + o = new
> +- elif isinstance(o, DictType):
> ++ elif isinstance(o, dict):
> + o.clear()
> + o.update(data)
> +- elif isinstance(o, ListType):
> ++ elif isinstance(o, list):
> + o[:] = data
> + return o
> +
> +@@ -141,7 +137,7 @@ def getCoreData(o):
> + if hasCoreData(o):
> + return isinstance_any(o, datatypes)(o)
> + else:
> +- raise TypeError, "Unhandled type in getCoreData for: ", o
> ++ raise TypeError("Unhandled type in getCoreData for: ", o)
> +
> + def instance_noinit(C):
> + """Create an instance of class C without calling __init__
> +@@ -166,7 +162,7 @@ def instance_noinit(C):
> + elif isNewStyleInstance(C):
> + return C.__new__(C)
> + else:
> +- raise TypeError, "You must specify a class to create instance of."
> ++ raise TypeError("You must specify a class to create instance of.")
> +
> + if __name__ == '__main__':
> + "We could use some could self-tests (see test/ subdir though)"
> +diff --git a/objdictgen/gnosis/util/test/__init__.py b/objdictgen/gnosis/util/test/__init__.py
> +new file mode 100644
> +index 000000000000..e69de29bb2d1
> +diff --git a/objdictgen/gnosis/util/test/funcs.py b/objdictgen/gnosis/util/test/funcs.py
> +index 5d39d80bc3d4..28647fa14da0 100644
> +--- a/objdictgen/gnosis/util/test/funcs.py
> ++++ b/objdictgen/gnosis/util/test/funcs.py
> +@@ -1,4 +1,4 @@
> + import os, sys, string
> +
> + def pyver():
> +- return string.split(sys.version)[0]
> ++ return sys.version.split()[0]
> +diff --git a/objdictgen/gnosis/util/test/test_data2attr.py b/objdictgen/gnosis/util/test/test_data2attr.py
> +index fb5b9cd5cff4..24281a5ed761 100644
> +--- a/objdictgen/gnosis/util/test/test_data2attr.py
> ++++ b/objdictgen/gnosis/util/test/test_data2attr.py
> +@@ -1,5 +1,5 @@
> + from sys import version
> +-from gnosis.util.introspect import data2attr, attr2data
> ++from ..introspect import data2attr, attr2data
> +
> + if version >= '2.2':
> + class NewList(list): pass
> +@@ -14,20 +14,20 @@ if version >= '2.2':
> + nd.attr = 'spam'
> +
> + nl = data2attr(nl)
> +- print nl, getattr(nl, '__coredata__', 'No __coredata__')
> ++ print(nl, getattr(nl, '__coredata__', 'No __coredata__'))
> + nl = attr2data(nl)
> +- print nl, getattr(nl, '__coredata__', 'No __coredata__')
> ++ print(nl, getattr(nl, '__coredata__', 'No __coredata__'))
> +
> + nt = data2attr(nt)
> +- print nt, getattr(nt, '__coredata__', 'No __coredata__')
> ++ print(nt, getattr(nt, '__coredata__', 'No __coredata__'))
> + nt = attr2data(nt)
> +- print nt, getattr(nt, '__coreData__', 'No __coreData__')
> ++ print(nt, getattr(nt, '__coreData__', 'No __coreData__'))
> +
> + nd = data2attr(nd)
> +- print nd, getattr(nd, '__coredata__', 'No __coredata__')
> ++ print(nd, getattr(nd, '__coredata__', 'No __coredata__'))
> + nd = attr2data(nd)
> +- print nd, getattr(nd, '__coredata__', 'No __coredata__')
> ++ print(nd, getattr(nd, '__coredata__', 'No __coredata__'))
> + else:
> +- print "data2attr() and attr2data() only work on 2.2+ new-style objects"
> ++ print("data2attr() and attr2data() only work on 2.2+ new-style objects")
> +
> +
> +diff --git a/objdictgen/gnosis/util/test/test_introspect.py b/objdictgen/gnosis/util/test/test_introspect.py
> +index 57e78ba2d88b..42aa10037570 100644
> +--- a/objdictgen/gnosis/util/test/test_introspect.py
> ++++ b/objdictgen/gnosis/util/test/test_introspect.py
> +@@ -1,7 +1,7 @@
> +
> +-import gnosis.util.introspect as insp
> ++from .. import introspect as insp
> + import sys
> +-from funcs import pyver
> ++from .funcs import pyver
> +
> + def test_list( ovlist, tname, test ):
> +
> +@@ -9,9 +9,9 @@ def test_list( ovlist, tname, test ):
> + sys.stdout.write('OBJ %s ' % str(o))
> +
> + if (v and test(o)) or (not v and not test(o)):
> +- print "%s = %d .. OK" % (tname,v)
> ++ print("%s = %d .. OK" % (tname,v))
> + else:
> +- raise "ERROR - Wrong answer to test."
> ++ raise Exception("ERROR - Wrong answer to test.")
> +
> + # isContainer
> + ol = [ ([], 1),
> +@@ -40,30 +40,35 @@ ol = [ (foo1(), 1),
> + (foo2(), 1),
> + (foo3(), 0) ]
> +
> +-test_list( ol, 'isInstance', insp.isInstance)
> ++if pyver()[0] <= "2":
> ++ # in python >= 3, all variables are instances of object
> ++ test_list( ol, 'isInstance', insp.isInstance)
> +
> + # isInstanceLike
> + ol = [ (foo1(), 1),
> + (foo2(), 1),
> + (foo3(), 0)]
> +
> +-test_list( ol, 'isInstanceLike', insp.isInstanceLike)
> ++if pyver()[0] <= "2":
> ++ # in python >= 3, all variables are instances of object
> ++ test_list( ol, 'isInstanceLike', insp.isInstanceLike)
> +
> +-from types import *
> ++if pyver()[0] <= "2":
> ++ from types import *
> +
> +-def is_oldclass(o):
> +- if isinstance(o,ClassType):
> +- return 1
> +- else:
> +- return 0
> ++ def is_oldclass(o):
> ++ if isinstance(o,ClassType):
> ++ return 1
> ++ else:
> ++ return 0
> +
> +-ol = [ (foo1,1),
> +- (foo2,1),
> +- (foo3,0)]
> ++ ol = [ (foo1,1),
> ++ (foo2,1),
> ++ (foo3,0)]
> +
> +-test_list(ol,'is_oldclass',is_oldclass)
> ++ test_list(ol,'is_oldclass',is_oldclass)
> +
> +-if pyver() >= '2.2':
> ++if pyver()[0] <= "2" and pyver() >= '2.2':
> + # isNewStyleClass
> + ol = [ (foo1,0),
> + (foo2,0),
> +diff --git a/objdictgen/gnosis/util/test/test_noinit.py b/objdictgen/gnosis/util/test/test_noinit.py
> +index a057133f2c0d..e027ce2390c6 100644
> +--- a/objdictgen/gnosis/util/test/test_noinit.py
> ++++ b/objdictgen/gnosis/util/test/test_noinit.py
> +@@ -1,28 +1,31 @@
> +-from gnosis.util.introspect import instance_noinit
> ++from ..introspect import instance_noinit
> ++from .funcs import pyver
> +
> +-class Old_noinit: pass
> ++if pyver()[0] <= "2":
> ++ class Old_noinit: pass
> +
> +-class Old_init:
> +- def __init__(self): print "Init in Old"
> ++ class Old_init:
> ++ def __init__(self): print("Init in Old")
> +
> +-class New_slots_and_init(int):
> +- __slots__ = ('this','that')
> +- def __init__(self): print "Init in New w/ slots"
> ++ class New_slots_and_init(int):
> ++ __slots__ = ('this','that')
> ++ def __init__(self): print("Init in New w/ slots")
> +
> +-class New_init_no_slots(int):
> +- def __init__(self): print "Init in New w/o slots"
> ++ class New_init_no_slots(int):
> ++ def __init__(self): print("Init in New w/o slots")
> +
> +-class New_slots_no_init(int):
> +- __slots__ = ('this','that')
> ++ class New_slots_no_init(int):
> ++ __slots__ = ('this','that')
> +
> +-class New_no_slots_no_init(int):
> +- pass
> ++ class New_no_slots_no_init(int):
> ++ pass
> +
> +-print "----- This should be the only line -----"
> +-instance_noinit(Old_noinit)
> +-instance_noinit(Old_init)
> +-instance_noinit(New_slots_and_init)
> +-instance_noinit(New_slots_no_init)
> +-instance_noinit(New_init_no_slots)
> +-instance_noinit(New_no_slots_no_init)
> +
> ++ instance_noinit(Old_noinit)
> ++ instance_noinit(Old_init)
> ++ instance_noinit(New_slots_and_init)
> ++ instance_noinit(New_slots_no_init)
> ++ instance_noinit(New_init_no_slots)
> ++ instance_noinit(New_no_slots_no_init)
> ++
> ++print("----- This should be the only line -----")
> +diff --git a/objdictgen/gnosis/util/test/test_variants_noinit.py b/objdictgen/gnosis/util/test/test_variants_noinit.py
> +index d2ea9a4fc46f..758a89d13660 100644
> +--- a/objdictgen/gnosis/util/test/test_variants_noinit.py
> ++++ b/objdictgen/gnosis/util/test/test_variants_noinit.py
> +@@ -1,25 +1,46 @@
> +-from gnosis.util.introspect import hasSlots, hasInit
> ++from ..introspect import hasSlots, hasInit
> + from types import *
> ++from .funcs import pyver
> +
> + class Old_noinit: pass
> +
> + class Old_init:
> +- def __init__(self): print "Init in Old"
> ++ def __init__(self): print("Init in Old")
> +
> +-class New_slots_and_init(int):
> +- __slots__ = ('this','that')
> +- def __init__(self): print "Init in New w/ slots"
> ++if pyver()[0] <= "2":
> ++ class New_slots_and_init(int):
> ++ __slots__ = ('this','that')
> ++ def __init__(self): print("Init in New w/ slots")
> +
> +-class New_init_no_slots(int):
> +- def __init__(self): print "Init in New w/o slots"
> ++ class New_init_no_slots(int):
> ++ def __init__(self): print("Init in New w/o slots")
> +
> +-class New_slots_no_init(int):
> +- __slots__ = ('this','that')
> ++ class New_slots_no_init(int):
> ++ __slots__ = ('this','that')
> +
> +-class New_no_slots_no_init(int):
> +- pass
> ++ class New_no_slots_no_init(int):
> ++ pass
> ++
> ++else:
> ++ # nonempty __slots__ not supported for subtype of 'int' in Python 3
> ++ class New_slots_and_init:
> ++ __slots__ = ('this','that')
> ++ def __init__(self): print("Init in New w/ slots")
> ++
> ++ class New_init_no_slots:
> ++ def __init__(self): print("Init in New w/o slots")
> ++
> ++ class New_slots_no_init:
> ++ __slots__ = ('this','that')
> ++
> ++ class New_no_slots_no_init:
> ++ pass
> ++
> ++if pyver()[0] <= "2":
> ++ from UserDict import UserDict
> ++else:
> ++ from collections import UserDict
> +
> +-from UserDict import UserDict
> + class MyDict(UserDict):
> + pass
> +
> +@@ -43,7 +64,7 @@ def one():
> + obj.__class__ = C
> + return obj
> +
> +- print "----- This should be the only line -----"
> ++ print("----- This should be the only line -----")
> + instance_noinit(MyDict)
> + instance_noinit(Old_noinit)
> + instance_noinit(Old_init)
> +@@ -75,7 +96,7 @@ def two():
> + obj = C()
> + return obj
> +
> +- print "----- Same test, fpm version of instance_noinit() -----"
> ++ print("----- Same test, fpm version of instance_noinit() -----")
> + instance_noinit(MyDict)
> + instance_noinit(Old_noinit)
> + instance_noinit(Old_init)
> +@@ -90,7 +111,7 @@ def three():
> + if hasattr(C,'__init__') and isinstance(C.__init__,MethodType):
> + # the class defined init - remove it temporarily
> + _init = C.__init__
> +- print _init
> ++ print(_init)
> + del C.__init__
> + obj = C()
> + C.__init__ = _init
> +@@ -99,7 +120,7 @@ def three():
> + obj = C()
> + return obj
> +
> +- print "----- Same test, dqm version of instance_noinit() -----"
> ++ print("----- Same test, dqm version of instance_noinit() -----")
> + instance_noinit(MyDict)
> + instance_noinit(Old_noinit)
> + instance_noinit(Old_init)
> +diff --git a/objdictgen/gnosis/util/xml2sql.py b/objdictgen/gnosis/util/xml2sql.py
> +index 818661321db0..751985d88f23 100644
> +--- a/objdictgen/gnosis/util/xml2sql.py
> ++++ b/objdictgen/gnosis/util/xml2sql.py
> +@@ -77,7 +77,7 @@ def walkNodes(py_obj, parent_info=('',''), seq=0):
> + member = getattr(py_obj,colname)
> + if type(member) == InstanceType:
> + walkNodes(member, self_info)
> +- elif type(member) == ListType:
> ++ elif type(member) == list:
> + for memitem in member:
> + if isinstance(memitem,_XO_):
> + seq += 1
> +diff --git a/objdictgen/gnosis/xml/indexer.py b/objdictgen/gnosis/xml/indexer.py
> +index 6e7f6941b506..45638b6d04ff 100644
> +--- a/objdictgen/gnosis/xml/indexer.py
> ++++ b/objdictgen/gnosis/xml/indexer.py
> +@@ -87,17 +87,11 @@ class XML_Indexer(indexer.PreferredIndexer, indexer.TextSplitter):
> + if type(member) is InstanceType:
> + xpath = xpath_suffix+'/'+membname
> + self.recurse_nodes(member, xpath.encode('UTF-8'))
> +- elif type(member) is ListType:
> ++ elif type(member) is list:
> + for i in range(len(member)):
> + xpath = xpath_suffix+'/'+membname+'['+str(i+1)+']'
> + self.recurse_nodes(member[i], xpath.encode('UTF-8'))
> +- elif type(member) is StringType:
> +- if membname != 'PCDATA':
> +- xpath = xpath_suffix+'/@'+membname
> +- self.add_nodetext(member, xpath.encode('UTF-8'))
> +- else:
> +- self.add_nodetext(member, xpath_suffix.encode('UTF-8'))
> +- elif type(member) is UnicodeType:
> ++ elif type(member) is str:
> + if membname != 'PCDATA':
> + xpath = xpath_suffix+'/@'+membname
> + self.add_nodetext(member.encode('UTF-8'),
> +@@ -122,11 +116,11 @@ class XML_Indexer(indexer.PreferredIndexer, indexer.TextSplitter):
> + self.fileids[node_index] = node_id
> +
> + for word in words:
> +- if self.words.has_key(word):
> ++ if word in self.words.keys():
> + entry = self.words[word]
> + else:
> + entry = {}
> +- if entry.has_key(node_index):
> ++ if node_index in entry.keys():
> + entry[node_index] = entry[node_index]+1
> + else:
> + entry[node_index] = 1
> +diff --git a/objdictgen/gnosis/xml/objectify/_objectify.py b/objdictgen/gnosis/xml/objectify/_objectify.py
> +index 27da2e451417..476dd9cd6245 100644
> +--- a/objdictgen/gnosis/xml/objectify/_objectify.py
> ++++ b/objdictgen/gnosis/xml/objectify/_objectify.py
> +@@ -43,10 +43,10 @@ def content(o):
> + return o._seq or []
> + def children(o):
> + "The child nodes (not PCDATA) of o"
> +- return [x for x in content(o) if type(x) not in StringTypes]
> ++ return [x for x in content(o) if type(x) is not str]
> + def text(o):
> + "List of textual children"
> +- return [x for x in content(o) if type(x) in StringTypes]
> ++ return [x for x in content(o) if type(x) is not str]
> + def dumps(o):
> + "The PCDATA in o (preserves whitespace)"
> + return "".join(text(o))
> +@@ -59,7 +59,7 @@ def tagname(o):
> + def attributes(o):
> + "List of (XML) attributes of o"
> + return [(k,v) for k,v in o.__dict__.items()
> +- if k!='PCDATA' and type(v) in StringTypes]
> ++ if k!='PCDATA' and type(v) is not str]
> +
> + #-- Base class for objectified XML nodes
> + class _XO_:
> +@@ -95,7 +95,7 @@ def _makeAttrDict(attr):
> + if not attr:
> + return {}
> + try:
> +- attr.has_key('dummy')
> ++ 'dummy' in attr.keys()
> + except AttributeError:
> + # assume a W3C NamedNodeMap
> + attr_dict = {}
> +@@ -116,7 +116,7 @@ class XML_Objectify:
> + or hasattr(xml_src,'childNodes')):
> + self._dom = xml_src
> + self._fh = None
> +- elif type(xml_src) in (StringType, UnicodeType):
> ++ elif type(xml_src) is str:
> + if xml_src[0]=='<': # looks like XML
> + from cStringIO import StringIO
> + self._fh = StringIO(xml_src)
> +@@ -210,7 +210,7 @@ class ExpatFactory:
> + # Does our current object have a child of this type already?
> + if hasattr(self._current, pyname):
> + # Convert a single child object into a list of children
> +- if type(getattr(self._current, pyname)) is not ListType:
> ++ if type(getattr(self._current, pyname)) is not list:
> + setattr(self._current, pyname, [getattr(self._current, pyname)])
> + # Add the new subtag to the list of children
> + getattr(self._current, pyname).append(py_obj)
> +@@ -290,7 +290,7 @@ def pyobj_from_dom(dom_node):
> + # does a py_obj attribute corresponding to the subtag already exist?
> + elif hasattr(py_obj, node_name):
> + # convert a single child object into a list of children
> +- if type(getattr(py_obj, node_name)) is not ListType:
> ++ if type(getattr(py_obj, node_name)) is not list:
> + setattr(py_obj, node_name, [getattr(py_obj, node_name)])
> + # add the new subtag to the list of children
> + getattr(py_obj, node_name).append(pyobj_from_dom(node))
> +diff --git a/objdictgen/gnosis/xml/objectify/utils.py b/objdictgen/gnosis/xml/objectify/utils.py
> +index 781a189d2f04..431d9a0220da 100644
> +--- a/objdictgen/gnosis/xml/objectify/utils.py
> ++++ b/objdictgen/gnosis/xml/objectify/utils.py
> +@@ -39,7 +39,7 @@ def write_xml(o, out=stdout):
> + out.write(' %s=%s' % attr)
> + out.write('>')
> + for node in content(o):
> +- if type(node) in StringTypes:
> ++ if type(node) is str:
> + out.write(node)
> + else:
> + write_xml(node, out=out)
> +@@ -119,7 +119,7 @@ def pyobj_printer(py_obj, level=0):
> + if type(member) == InstanceType:
> + descript += '\n'+(' '*level)+'{'+membname+'}\n'
> + descript += pyobj_printer(member, level+3)
> +- elif type(member) == ListType:
> ++ elif type(member) == list:
> + for i in range(len(member)):
> + descript += '\n'+(' '*level)+'['+membname+'] #'+str(i+1)
> + descript += (' '*level)+'\n'+pyobj_printer(member[i],level+3)
> +diff --git a/objdictgen/gnosis/xml/pickle/__init__.py b/objdictgen/gnosis/xml/pickle/__init__.py
> +index 34f90e50acba..4031142776c6 100644
> +--- a/objdictgen/gnosis/xml/pickle/__init__.py
> ++++ b/objdictgen/gnosis/xml/pickle/__init__.py
> +@@ -4,7 +4,7 @@ Please see the information at gnosis.xml.pickle.doc for
> + explanation of usage, design, license, and other details
> + """
> + from gnosis.xml.pickle._pickle import \
> +- XML_Pickler, XMLPicklingError, XMLUnpicklingError, \
> ++ XML_Pickler, \
> + dump, dumps, load, loads
> +
> + from gnosis.xml.pickle.util import \
> +@@ -13,3 +13,5 @@ from gnosis.xml.pickle.util import \
> + setParser, setVerbose, enumParsers
> +
> + from gnosis.xml.pickle.ext import *
> ++
> ++from gnosis.xml.pickle.exception import XMLPicklingError, XMLUnpicklingError
> +diff --git a/objdictgen/gnosis/xml/pickle/_pickle.py b/objdictgen/gnosis/xml/pickle/_pickle.py
> +index a5275e4830f6..5e1fa1c609f5 100644
> +--- a/objdictgen/gnosis/xml/pickle/_pickle.py
> ++++ b/objdictgen/gnosis/xml/pickle/_pickle.py
> +@@ -29,24 +29,17 @@ import gnosis.pyconfig
> +
> + from types import *
> +
> +-try: # Get a usable StringIO
> +- from cStringIO import StringIO
> +-except:
> +- from StringIO import StringIO
> ++from io import StringIO
> +
> + # default settings
> +-setInBody(IntType,0)
> +-setInBody(FloatType,0)
> +-setInBody(LongType,0)
> +-setInBody(ComplexType,0)
> +-setInBody(StringType,0)
> ++setInBody(int,0)
> ++setInBody(float,0)
> ++setInBody(complex,0)
> + # our unicode vs. "regular string" scheme relies on unicode
> + # strings only being in the body, so this is hardcoded.
> +-setInBody(UnicodeType,1)
> ++setInBody(str,1)
> +
> +-# Define exceptions and flags
> +-XMLPicklingError = "gnosis.xml.pickle.XMLPicklingError"
> +-XMLUnpicklingError = "gnosis.xml.pickle.XMLUnpicklingError"
> ++from gnosis.xml.pickle.exception import XMLPicklingError, XMLUnpicklingError
> +
> + # Maintain list of object identities for multiple and cyclical references
> + # (also to keep temporary objects alive)
> +@@ -79,7 +72,7 @@ class StreamWriter:
> + self.iohandle = gzip.GzipFile(None,'wb',9,self.iohandle)
> +
> + def append(self,item):
> +- if type(item) in (ListType, TupleType): item = ''.join(item)
> ++ if type(item) in (list, tuple): item = ''.join(item)
> + self.iohandle.write(item)
> +
> + def getvalue(self):
> +@@ -102,7 +95,7 @@ def StreamReader( stream ):
> + appropriate for reading the stream."""
> +
> + # turn strings into stream
> +- if type(stream) in [StringType,UnicodeType]:
> ++ if type(stream) is str:
> + stream = StringIO(stream)
> +
> + # determine if we have a gzipped stream by checking magic
> +@@ -128,8 +121,8 @@ class XML_Pickler:
> + if isInstanceLike(py_obj):
> + self.to_pickle = py_obj
> + else:
> +- raise XMLPicklingError, \
> +- "XML_Pickler must be initialized with Instance (or None)"
> ++ raise XMLPicklingError( \
> ++ "XML_Pickler must be initialized with Instance (or None)")
> +
> + def dump(self, iohandle, obj=None, binary=0, deepcopy=None):
> + "Write the XML representation of obj to iohandle."
> +@@ -151,7 +144,8 @@ class XML_Pickler:
> + if parser:
> + return parser(fh, paranoia=paranoia)
> + else:
> +- raise XMLUnpicklingError, "Unknown parser %s" % getParser()
> ++ raise XMLUnpicklingError("Unknown parser %s. Available parsers: %r" %
> ++ (getParser(), enumParsers()))
> +
> + def dumps(self, obj=None, binary=0, deepcopy=None, iohandle=None):
> + "Create the XML representation as a string."
> +@@ -159,15 +153,15 @@ class XML_Pickler:
> + if deepcopy is None: deepcopy = getDeepCopy()
> +
> + # write to a file or string, either compressed or not
> +- list = StreamWriter(iohandle,binary)
> ++ list_ = StreamWriter(iohandle,binary)
> +
> + # here are our three forms:
> + if obj is not None: # XML_Pickler().dumps(obj)
> +- return _pickle_toplevel_obj(list,obj, deepcopy)
> ++ return _pickle_toplevel_obj(list_,obj, deepcopy)
> + elif hasattr(self,'to_pickle'): # XML_Pickler(obj).dumps()
> +- return _pickle_toplevel_obj(list,self.to_pickle, deepcopy)
> ++ return _pickle_toplevel_obj(list_,self.to_pickle, deepcopy)
> + else: # myXML_Pickler().dumps()
> +- return _pickle_toplevel_obj(list,self, deepcopy)
> ++ return _pickle_toplevel_obj(list_,self, deepcopy)
> +
> + def loads(self, xml_str, paranoia=None):
> + "Load a pickled object from the given XML string."
> +@@ -221,8 +215,8 @@ def _pickle_toplevel_obj(xml_list, py_obj, deepcopy):
> + # sanity check until/if we eventually support these
> + # at the toplevel
> + if in_body or extra:
> +- raise XMLPicklingError, \
> +- "Sorry, mutators can't set in_body and/or extra at the toplevel."
> ++ raise XMLPicklingError( \
> ++ "Sorry, mutators can't set in_body and/or extra at the toplevel.")
> + famtype = famtype + 'family="obj" type="%s" ' % mtype
> +
> + module = _module(py_obj)
> +@@ -250,10 +244,10 @@ def _pickle_toplevel_obj(xml_list, py_obj, deepcopy):
> + # know that (or not care)
> + return xml_list.getvalue()
> +
> +-def pickle_instance(obj, list, level=0, deepcopy=0):
> ++def pickle_instance(obj, list_, level=0, deepcopy=0):
> + """Pickle the given object into a <PyObject>
> +
> +- Add XML tags to list. Level is indentation (for aesthetic reasons)
> ++ Add XML tags to list_. Level is indentation (for aesthetic reasons)
> + """
> + # concept: to pickle an object, we pickle two things:
> + #
> +@@ -278,8 +272,8 @@ def pickle_instance(obj, list, level=0, deepcopy=0):
> + try:
> + len(args) # must be a sequence, from pickle.py
> + except:
> +- raise XMLPicklingError, \
> +- "__getinitargs__() must return a sequence"
> ++ raise XMLPicklingError( \
> ++ "__getinitargs__() must return a sequence")
> + except:
> + args = None
> +
> +@@ -293,22 +287,22 @@ def pickle_instance(obj, list, level=0, deepcopy=0):
> + # save initargs, if we have them
> + if args is not None:
> + # put them in an <attr name="__getinitargs__" ...> container
> +- list.append(_attr_tag('__getinitargs__', args, level, deepcopy))
> ++ list_.append(_attr_tag('__getinitargs__', args, level, deepcopy))
> +
> + # decide how to save the "stuff", depending on whether we need
> + # to later grab it back as a single object
> + if not hasattr(obj,'__setstate__'):
> +- if type(stuff) is DictType:
> ++ if type(stuff) is dict:
> + # don't need it as a single object - save keys/vals as
> + # first-level attributes
> + for key,val in stuff.items():
> +- list.append(_attr_tag(key, val, level, deepcopy))
> ++ list_.append(_attr_tag(key, val, level, deepcopy))
> + else:
> +- raise XMLPicklingError, \
> +- "__getstate__ must return a DictType here"
> ++ raise XMLPicklingError( \
> ++ "__getstate__ must return a dict here")
> + else:
> + # else, encapsulate the "stuff" in an <attr name="__getstate__" ...>
> +- list.append(_attr_tag('__getstate__', stuff, level, deepcopy))
> ++ list_.append(_attr_tag('__getstate__', stuff, level, deepcopy))
> +
> + #--- Functions to create XML output tags ---
> + def _attr_tag(name, thing, level=0, deepcopy=0):
> +@@ -395,8 +389,8 @@ def _family_type(family,typename,mtype,mextra):
> +
> + # sanity in case Python changes ...
> + if gnosis.pyconfig.Have_BoolClass() and gnosis.pyconfig.IsLegal_BaseClass('bool'):
> +- raise XMLPicklingError, \
> +- "Assumption broken - can now use bool as baseclass!"
> ++ raise XMLPicklingError( \
> ++ "Assumption broken - can now use bool as baseclass!")
> +
> + Have_BoolClass = gnosis.pyconfig.Have_BoolClass()
> +
> +@@ -459,7 +453,7 @@ def _tag_completer(start_tag, orig_thing, close_tag, level, deepcopy):
> + pickle_instance(thing, tag_body, level+1, deepcopy)
> + else:
> + close_tag = ''
> +- elif isinstance_any(thing, (IntType, LongType, FloatType, ComplexType)):
> ++ elif isinstance_any(thing, (int, float, complex)):
> + #thing_str = repr(thing)
> + thing_str = ntoa(thing)
> +
> +@@ -476,13 +470,13 @@ def _tag_completer(start_tag, orig_thing, close_tag, level, deepcopy):
> + start_tag = start_tag + '%s value="%s" />\n' % \
> + (_family_type('atom','numeric',mtag,mextra),thing_str)
> + close_tag = ''
> +- elif isinstance_any(thing, (StringType,UnicodeType)):
> ++ elif isinstance_any(thing, str):
> + #XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
> + # special check for now - this will be fixed in the next major
> + # gnosis release, so I don't care that the code is inline & gross
> + # for now
> + #XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
> +- if isinstance(thing,UnicodeType):
> ++ if isinstance(thing,str):
> + # can't pickle unicode containing the special "escape" sequence
> + # we use for putting strings in the XML body (they'll be unpickled
> + # as strings, not unicode, if we do!)
> +@@ -493,7 +487,7 @@ def _tag_completer(start_tag, orig_thing, close_tag, level, deepcopy):
> + if not is_legal_xml(thing):
> + raise Exception("Unpickleable Unicode value. To be fixed in next major Gnosis release.")
> +
> +- if isinstance(thing,StringType) and getInBody(StringType):
> ++ if isinstance(thing,str) and getInBody(str):
> + # technically, this will crash safe_content(), but I prefer to
> + # have the test here for clarity
> + try:
> +@@ -525,7 +519,7 @@ def _tag_completer(start_tag, orig_thing, close_tag, level, deepcopy):
> + # before pickling subitems, in case it contains self-references
> + # (we CANNOT just move the visited{} update to the top of this
> + # function, since that would screw up every _family_type() call)
> +- elif type(thing) is TupleType:
> ++ elif type(thing) is tuple:
> + start_tag, do_copy = \
> + _tag_compound(start_tag,_family_type('seq','tuple',mtag,mextra),
> + orig_thing,deepcopy)
> +@@ -534,7 +528,7 @@ def _tag_completer(start_tag, orig_thing, close_tag, level, deepcopy):
> + tag_body.append(_item_tag(item, level+1, deepcopy))
> + else:
> + close_tag = ''
> +- elif type(thing) is ListType:
> ++ elif type(thing) is list:
> + start_tag, do_copy = \
> + _tag_compound(start_tag,_family_type('seq','list',mtag,mextra),
> + orig_thing,deepcopy)
> +@@ -545,7 +539,7 @@ def _tag_completer(start_tag, orig_thing, close_tag, level, deepcopy):
> + tag_body.append(_item_tag(item, level+1, deepcopy))
> + else:
> + close_tag = ''
> +- elif type(thing) in [DictType]:
> ++ elif type(thing) in [dict]:
> + start_tag, do_copy = \
> + _tag_compound(start_tag,_family_type('map','dict',mtag,mextra),
> + orig_thing,deepcopy)
> +@@ -583,7 +577,7 @@ def _tag_completer(start_tag, orig_thing, close_tag, level, deepcopy):
> + thing)
> + close_tag = close_tag.lstrip()
> + except:
> +- raise XMLPicklingError, "non-handled type %s" % type(thing)
> ++ raise XMLPicklingError("non-handled type %s" % type(thing))
> +
> + # need to keep a ref to the object for two reasons -
> + # 1. we can ref it later instead of copying it into the XML stream
> +diff --git a/objdictgen/gnosis/xml/pickle/doc/HOWTO.extensions b/objdictgen/gnosis/xml/pickle/doc/HOWTO.extensions
> +index e0bf7a253c48..13c320aafa21 100644
> +--- a/objdictgen/gnosis/xml/pickle/doc/HOWTO.extensions
> ++++ b/objdictgen/gnosis/xml/pickle/doc/HOWTO.extensions
> +@@ -51,11 +51,11 @@ integers into strings:
> +
> + Now, to add silly_mutator to xml_pickle, you do:
> +
> +- m = silly_mutator( IntType, "silly_string", in_body=1 )
> ++ m = silly_mutator( int, "silly_string", in_body=1 )
> + mutate.add_mutator( m )
> +
> + Explanation:
> +- The parameter "IntType" says that we want to catch integers.
> ++ The parameter "int" says that we want to catch integers.
> + "silly_string" will be the typename in the XML stream.
> + "in_body=1" tells xml_pickle to place the value string in the body
> + of the tag.
> +@@ -79,7 +79,7 @@ Mutator can define two additional functions:
> + # return 1 if we can unmutate mobj, 0 if not
> +
> + By default, a Mutator will be asked to mutate/unmutate all objects of
> +-the type it registered ("IntType", in our silly example). You would
> ++the type it registered ("int", in our silly example). You would
> + only need to override wants_obj/wants_mutated to provide specialized
> + sub-type handling (based on content, for example). test_mutators.py
> + shows examples of how to do this.
> +diff --git a/objdictgen/gnosis/xml/pickle/exception.py b/objdictgen/gnosis/xml/pickle/exception.py
> +new file mode 100644
> +index 000000000000..a19e257bd8d8
> +--- /dev/null
> ++++ b/objdictgen/gnosis/xml/pickle/exception.py
> +@@ -0,0 +1,2 @@
> ++class XMLPicklingError(Exception): pass
> ++class XMLUnpicklingError(Exception): pass
> +diff --git a/objdictgen/gnosis/xml/pickle/ext/__init__.py b/objdictgen/gnosis/xml/pickle/ext/__init__.py
> +index df60171f5229..3833065f7750 100644
> +--- a/objdictgen/gnosis/xml/pickle/ext/__init__.py
> ++++ b/objdictgen/gnosis/xml/pickle/ext/__init__.py
> +@@ -6,7 +6,7 @@ __author__ = ["Frank McIngvale (frankm@hiwaay.net)",
> + "David Mertz (mertz@gnosis.cx)",
> + ]
> +
> +-from _mutate import \
> ++from ._mutate import \
> + can_mutate,mutate,can_unmutate,unmutate,\
> + add_mutator,remove_mutator,XMLP_Mutator, XMLP_Mutated, \
> + get_unmutator, try_mutate
> +diff --git a/objdictgen/gnosis/xml/pickle/ext/_mutate.py b/objdictgen/gnosis/xml/pickle/ext/_mutate.py
> +index aa8da4f87d62..43481a8c5331 100644
> +--- a/objdictgen/gnosis/xml/pickle/ext/_mutate.py
> ++++ b/objdictgen/gnosis/xml/pickle/ext/_mutate.py
> +@@ -3,8 +3,7 @@ from types import *
> + from gnosis.util.introspect import isInstanceLike, hasCoreData
> + import gnosis.pyconfig
> +
> +-XMLPicklingError = "gnosis.xml.pickle.XMLPicklingError"
> +-XMLUnpicklingError = "gnosis.xml.pickle.XMLUnpicklingError"
> ++from gnosis.xml.pickle.exception import XMLPicklingError, XMLUnpicklingError
> +
> + # hooks for adding mutators
> + # each dict entry is a list of chained mutators
> +@@ -25,8 +24,8 @@ _has_coredata_cache = {}
> +
> + # sanity in case Python changes ...
> + if gnosis.pyconfig.Have_BoolClass() and gnosis.pyconfig.IsLegal_BaseClass('bool'):
> +- raise XMLPicklingError, \
> +- "Assumption broken - can now use bool as baseclass!"
> ++ raise XMLPicklingError( \
> ++ "Assumption broken - can now use bool as baseclass!")
> +
> + Have_BoolClass = gnosis.pyconfig.Have_BoolClass()
> +
> +@@ -54,7 +53,7 @@ def get_mutator(obj):
> + if not hasattr(obj,'__class__'):
> + return None
> +
> +- if _has_coredata_cache.has_key(obj.__class__):
> ++ if obj.__class__ in _has_coredata_cache.keys():
> + return _has_coredata_cache[obj.__class__]
> +
> + if hasCoreData(obj):
> +@@ -76,8 +75,8 @@ def mutate(obj):
> + tobj = mutator.mutate(obj)
> +
> + if not isinstance(tobj,XMLP_Mutated):
> +- raise XMLPicklingError, \
> +- "Bad type returned from mutator %s" % mutator
> ++ raise XMLPicklingError( \
> ++ "Bad type returned from mutator %s" % mutator)
> +
> + return (mutator.tag,tobj.obj,mutator.in_body,tobj.extra)
> +
> +@@ -96,8 +95,8 @@ def try_mutate(obj,alt_tag,alt_in_body,alt_extra):
> + tobj = mutator.mutate(obj)
> +
> + if not isinstance(tobj,XMLP_Mutated):
> +- raise XMLPicklingError, \
> +- "Bad type returned from mutator %s" % mutator
> ++ raise XMLPicklingError( \
> ++ "Bad type returned from mutator %s" % mutator)
> +
> + return (mutator.tag,tobj.obj,mutator.in_body,tobj.extra)
> +
> +diff --git a/objdictgen/gnosis/xml/pickle/ext/_mutators.py b/objdictgen/gnosis/xml/pickle/ext/_mutators.py
> +index 142f611ea7b4..645dc4e64eed 100644
> +--- a/objdictgen/gnosis/xml/pickle/ext/_mutators.py
> ++++ b/objdictgen/gnosis/xml/pickle/ext/_mutators.py
> +@@ -1,5 +1,5 @@
> +-from _mutate import XMLP_Mutator, XMLP_Mutated
> +-import _mutate
> ++from gnosis.xml.pickle.ext._mutate import XMLP_Mutator, XMLP_Mutated
> ++import gnosis.xml.pickle.ext._mutate as _mutate
> + import sys, string
> + from types import *
> + from gnosis.util.introspect import isInstanceLike, attr_update, \
> +@@ -176,16 +176,16 @@ def olddata_to_newdata(data,extra,paranoia):
> + (module,klass) = extra.split()
> + o = obj_from_name(klass,module,paranoia)
> +
> +- #if isinstance(o,ComplexType) and \
> +- # type(data) in [StringType,UnicodeType]:
> ++ #if isinstance(o,complex) and \
> ++ # type(data) is str:
> + # # yuck ... have to strip () from complex data before
> + # # passing to __init__ (ran into this also in one of the
> + # # parsers ... maybe the () shouldn't be in the XML at all?)
> + # if data[0] == '(' and data[-1] == ')':
> + # data = data[1:-1]
> +
> +- if isinstance_any(o,(IntType,FloatType,ComplexType,LongType)) and \
> +- type(data) in [StringType,UnicodeType]:
> ++ if isinstance_any(o,(int,float,complex)) and \
> ++ type(data) is str:
> + data = aton(data)
> +
> + o = setCoreData(o,data)
> +@@ -208,7 +208,7 @@ class mutate_bltin_instances(XMLP_Mutator):
> +
> + def mutate(self,obj):
> +
> +- if isinstance(obj,UnicodeType):
> ++ if isinstance(obj,str):
> + # unicode strings are required to be placed in the body
> + # (by our encoding scheme)
> + self.in_body = 1
> +diff --git a/objdictgen/gnosis/xml/pickle/parsers/_dom.py b/objdictgen/gnosis/xml/pickle/parsers/_dom.py
> +index 0703331b8e48..8582f5c8f1a7 100644
> +--- a/objdictgen/gnosis/xml/pickle/parsers/_dom.py
> ++++ b/objdictgen/gnosis/xml/pickle/parsers/_dom.py
> +@@ -17,8 +17,7 @@ except ImportError:
> + array_type = 'array'
> +
> + # Define exceptions and flags
> +-XMLPicklingError = "gnosis.xml.pickle.XMLPicklingError"
> +-XMLUnpicklingError = "gnosis.xml.pickle.XMLUnpicklingError"
> ++from gnosis.xml.pickle.exception import XMLPicklingError, XMLUnpicklingError
> +
> + # Define our own TRUE/FALSE syms, based on Python version.
> + if pyconfig.Have_TrueFalse():
> +@@ -70,7 +69,10 @@ def unpickle_instance(node, paranoia):
> +
> + # next, decide what "stuff" is supposed to go into pyobj
> + if hasattr(raw,'__getstate__'):
> +- stuff = raw.__getstate__
> ++ # Note: this code path was apparently never taken in Python 2, but
> ++ # __getstate__ is a function, and it makes no sense below to call
> ++ # __setstate__ or attr_update() with a function instead of a dict.
> ++ stuff = raw.__getstate__()
> + else:
> + stuff = raw.__dict__
> +
> +@@ -78,7 +80,7 @@ def unpickle_instance(node, paranoia):
> + if hasattr(pyobj,'__setstate__'):
> + pyobj.__setstate__(stuff)
> + else:
> +- if type(stuff) is DictType: # must be a Dict if no __setstate__
> ++ if type(stuff) is dict: # must be a Dict if no __setstate__
> + # see note in pickle.py/load_build() about restricted
> + # execution -- do the same thing here
> + #try:
> +@@ -92,9 +94,9 @@ def unpickle_instance(node, paranoia):
> + # does violate the pickle protocol, or because PARANOIA was
> + # set too high, and we couldn't create the real class, so
> + # __setstate__ is missing (and __stateinfo__ isn't a dict)
> +- raise XMLUnpicklingError, \
> +- "Non-DictType without setstate violates pickle protocol."+\
> +- "(PARANOIA setting may be too high)"
> ++ raise XMLUnpicklingError( \
> ++ "Non-dict without setstate violates pickle protocol."+\
> ++ "(PARANOIA setting may be too high)")
> +
> + return pyobj
> +
> +@@ -120,7 +122,7 @@ def get_node_valuetext(node):
> + # a value= attribute. ie. pickler can place it in either
> + # place (based on user preference) and unpickler doesn't care
> +
> +- if node._attrs.has_key('value'):
> ++ if 'value' in node._attrs.keys():
> + # text in tag
> + ttext = node.getAttribute('value')
> + return unsafe_string(ttext)
> +@@ -165,8 +167,8 @@ def _fix_family(family,typename):
> + elif typename == 'False':
> + return 'uniq'
> + else:
> +- raise XMLUnpicklingError, \
> +- "family= must be given for unknown type %s" % typename
> ++ raise XMLUnpicklingError( \
> ++ "family= must be given for unknown type %s" % typename)
> +
> + def _thing_from_dom(dom_node, container=None, paranoia=1):
> + "Converts an [xml_pickle] DOM tree to a 'native' Python object"
> +@@ -248,7 +250,7 @@ def _thing_from_dom(dom_node, container=None, paranoia=1):
> + node.getAttribute('module'),
> + paranoia)
> + else:
> +- raise XMLUnpicklingError, "Unknown lang type %s" % node_type
> ++ raise XMLUnpicklingError("Unknown lang type %s" % node_type)
> + elif node_family == 'uniq':
> + # uniq is another special type that is handled here instead
> + # of below.
> +@@ -268,9 +270,9 @@ def _thing_from_dom(dom_node, container=None, paranoia=1):
> + elif node_type == 'False':
> + node_val = FALSE_VALUE
> + else:
> +- raise XMLUnpicklingError, "Unknown uniq type %s" % node_type
> ++ raise XMLUnpicklingError("Unknown uniq type %s" % node_type)
> + else:
> +- raise XMLUnpicklingError, "UNKNOWN family %s,%s,%s" % (node_family,node_type,node_name)
> ++ raise XMLUnpicklingError("UNKNOWN family %s,%s,%s" % (node_family,node_type,node_name))
> +
> + # step 2 - take basic thing and make exact thing
> + # Note there are several NOPs here since node_val has been decided
> +@@ -313,7 +315,7 @@ def _thing_from_dom(dom_node, container=None, paranoia=1):
> + #elif ext.can_handle_xml(node_type,node_valuetext):
> + # node_val = ext.xml_to_obj(node_type, node_valuetext, paranoia)
> + else:
> +- raise XMLUnpicklingError, "Unknown type %s,%s" % (node,node_type)
> ++ raise XMLUnpicklingError("Unknown type %s,%s" % (node,node_type))
> +
> + if node.nodeName == 'attr':
> + setattr(container,node_name,node_val)
> +@@ -329,8 +331,8 @@ def _thing_from_dom(dom_node, container=None, paranoia=1):
> + # <entry> has no id for refchecking
> +
> + else:
> +- raise XMLUnpicklingError, \
> +- "element %s is not in PyObjects.dtd" % node.nodeName
> ++ raise XMLUnpicklingError( \
> ++ "element %s is not in PyObjects.dtd" % node.nodeName)
> +
> + return container
> +
> +diff --git a/objdictgen/gnosis/xml/pickle/parsers/_sax.py b/objdictgen/gnosis/xml/pickle/parsers/_sax.py
> +index 4a6b42ad5858..6810135a52de 100644
> +--- a/objdictgen/gnosis/xml/pickle/parsers/_sax.py
> ++++ b/objdictgen/gnosis/xml/pickle/parsers/_sax.py
> +@@ -19,17 +19,16 @@ from gnosis.util.XtoY import to_number
> +
> + import sys, os, string
> + from types import *
> +-from StringIO import StringIO
> ++from io import StringIO
> +
> + # Define exceptions and flags
> +-XMLPicklingError = "gnosis.xml.pickle.XMLPicklingError"
> +-XMLUnpicklingError = "gnosis.xml.pickle.XMLUnpicklingError"
> ++from gnosis.xml.pickle.exception import XMLPicklingError, XMLUnpicklingError
> +
> + DEBUG = 0
> +
> + def dbg(msg,force=0):
> + if DEBUG or force:
> +- print msg
> ++ print(msg)
> +
> + class _EmptyClass: pass
> +
> +@@ -64,12 +63,12 @@ class xmlpickle_handler(ContentHandler):
> + def prstk(self,force=0):
> + if DEBUG == 0 and not force:
> + return
> +- print "**ELEM STACK**"
> ++ print("**ELEM STACK**")
> + for i in self.elem_stk:
> +- print str(i)
> +- print "**VALUE STACK**"
> ++ print(str(i))
> ++ print("**VALUE STACK**")
> + for i in self.val_stk:
> +- print str(i)
> ++ print(str(i))
> +
> + def save_obj_id(self,obj,elem):
> +
> +@@ -201,8 +200,8 @@ class xmlpickle_handler(ContentHandler):
> + elem[4].get('module'),
> + self.paranoia)
> + else:
> +- raise XMLUnpicklingError, \
> +- "Unknown lang type %s" % elem[2]
> ++ raise XMLUnpicklingError( \
> ++ "Unknown lang type %s" % elem[2])
> +
> + elif family == 'uniq':
> + # uniq is a special type - we don't know how to unpickle
> +@@ -225,12 +224,12 @@ class xmlpickle_handler(ContentHandler):
> + elif elem[2] == 'False':
> + obj = FALSE_VALUE
> + else:
> +- raise XMLUnpicklingError, \
> +- "Unknown uniq type %s" % elem[2]
> ++ raise XMLUnpicklingError( \
> ++ "Unknown uniq type %s" % elem[2])
> + else:
> +- raise XMLUnpicklingError, \
> ++ raise XMLUnpicklingError( \
> + "UNKNOWN family %s,%s,%s" % \
> +- (family,elem[2],elem[3])
> ++ (family,elem[2],elem[3]))
> +
> + # step 2 -- convert basic -> specific type
> + # (many of these are NOPs, but included for clarity)
> +@@ -286,8 +285,8 @@ class xmlpickle_handler(ContentHandler):
> +
> + else:
> + self.prstk(1)
> +- raise XMLUnpicklingError, \
> +- "UNHANDLED elem %s"%elem[2]
> ++ raise XMLUnpicklingError( \
> ++ "UNHANDLED elem %s"%elem[2])
> +
> + # push on stack and save obj ref
> + self.val_stk.append((elem[0],elem[3],obj))
> +@@ -328,7 +327,7 @@ class xmlpickle_handler(ContentHandler):
> +
> + def endDocument(self):
> + if DEBUG == 1:
> +- print "NROBJS "+str(self.nr_objs)
> ++ print("NROBJS "+str(self.nr_objs))
> +
> + def startElement(self,name,attrs):
> + dbg("** START ELEM %s,%s"%(name,attrs._attrs))
> +@@ -406,17 +405,17 @@ class xmlpickle_handler(ContentHandler):
> +
> + # implement the ErrorHandler interface here as well
> + def error(self,exception):
> +- print "** ERROR - dumping stacks"
> ++ print("** ERROR - dumping stacks")
> + self.prstk(1)
> + raise exception
> +
> + def fatalError(self,exception):
> +- print "** FATAL ERROR - dumping stacks"
> ++ print("** FATAL ERROR - dumping stacks")
> + self.prstk(1)
> + raise exception
> +
> + def warning(self,exception):
> +- print "WARNING"
> ++ print("WARNING")
> + raise exception
> +
> + # Implement EntityResolver interface (called when the parser runs
> +@@ -435,7 +434,7 @@ class xmlpickle_handler(ContentHandler):
> + def thing_from_sax(filehandle=None,paranoia=1):
> +
> + if DEBUG == 1:
> +- print "**** SAX PARSER ****"
> ++ print("**** SAX PARSER ****")
> +
> + e = ExpatParser()
> + m = xmlpickle_handler(paranoia)
> +diff --git a/objdictgen/gnosis/xml/pickle/test/test_all.py b/objdictgen/gnosis/xml/pickle/test/test_all.py
> +index 916dfa168806..a3f931621280 100644
> +--- a/objdictgen/gnosis/xml/pickle/test/test_all.py
> ++++ b/objdictgen/gnosis/xml/pickle/test/test_all.py
> +@@ -178,7 +178,7 @@ pechof(tout,"Sanity check: OK")
> + parser_dict = enumParsers()
> +
> + # test with DOM parser, if available
> +-if parser_dict.has_key('DOM'):
> ++if 'DOM' in parser_dict.keys():
> +
> + # make sure the USE_.. files are gone
> + unlink("USE_SAX")
> +@@ -199,7 +199,7 @@ else:
> + pechof(tout,"** SKIPPING DOM parser **")
> +
> + # test with SAX parser, if available
> +-if parser_dict.has_key("SAX"):
> ++if "SAX" in parser_dict.keys():
> +
> + touch("USE_SAX")
> +
> +@@ -220,7 +220,7 @@ else:
> + pechof(tout,"** SKIPPING SAX parser **")
> +
> + # test with cEXPAT parser, if available
> +-if parser_dict.has_key("cEXPAT"):
> ++if "cEXPAT" in parser_dict.keys():
> +
> + touch("USE_CEXPAT");
> +
> +diff --git a/objdictgen/gnosis/xml/pickle/test/test_badstring.py b/objdictgen/gnosis/xml/pickle/test/test_badstring.py
> +index 837154f99a77..e8452e6c3857 100644
> +--- a/objdictgen/gnosis/xml/pickle/test/test_badstring.py
> ++++ b/objdictgen/gnosis/xml/pickle/test/test_badstring.py
> +@@ -88,7 +88,7 @@ try:
> + # safe_content assumes it can always convert the string
> + # to unicode, which isn't true
> + # ex: pickling a UTF-8 encoded value
> +- setInBody(StringType, 1)
> ++ setInBody(str, 1)
> + f = Foo('\xed\xa0\x80')
> + x = xml_pickle.dumps(f)
> + print "************* ERROR *************"
> +diff --git a/objdictgen/gnosis/xml/pickle/test/test_bltin.py b/objdictgen/gnosis/xml/pickle/test/test_bltin.py
> +index c23c14785dc8..bd1e4afca149 100644
> +--- a/objdictgen/gnosis/xml/pickle/test/test_bltin.py
> ++++ b/objdictgen/gnosis/xml/pickle/test/test_bltin.py
> +@@ -48,7 +48,7 @@ foo = foo_class()
> +
> + # try putting numeric content in body (doesn't matter which
> + # numeric type)
> +-setInBody(ComplexType,1)
> ++setInBody(complex,1)
> +
> + # test both code paths
> +
> +diff --git a/objdictgen/gnosis/xml/pickle/test/test_mutators.py b/objdictgen/gnosis/xml/pickle/test/test_mutators.py
> +index ea049cf6421a..d8e531629d39 100644
> +--- a/objdictgen/gnosis/xml/pickle/test/test_mutators.py
> ++++ b/objdictgen/gnosis/xml/pickle/test/test_mutators.py
> +@@ -27,8 +27,8 @@ class mystring(XMLP_Mutator):
> + # (here we fold two types to a single tagname)
> +
> + print "*** TEST 1 ***"
> +-my1 = mystring(StringType,"MyString",in_body=1)
> +-my2 = mystring(UnicodeType,"MyString",in_body=1)
> ++my1 = mystring(str,"MyString",in_body=1)
> ++my2 = mystring(str,"MyString",in_body=1)
> +
> + mutate.add_mutator(my1)
> + mutate.add_mutator(my2)
> +@@ -57,8 +57,8 @@ mutate.remove_mutator(my2)
> +
> + print "*** TEST 2 ***"
> +
> +-my1 = mystring(StringType,"string",in_body=1)
> +-my2 = mystring(UnicodeType,"string",in_body=1)
> ++my1 = mystring(str,"string",in_body=1)
> ++my2 = mystring(str,"string",in_body=1)
> +
> + mutate.add_mutator(my1)
> + mutate.add_mutator(my2)
> +@@ -86,14 +86,14 @@ print z
> + # mynumlist handles lists of integers and pickles them as "n,n,n,n"
> + # mycharlist does the same for single-char strings
> + #
> +-# otherwise, the ListType builtin handles the list
> ++# otherwise, the list builtin handles the list
> +
> + class mynumlist(XMLP_Mutator):
> +
> + def wants_obj(self,obj):
> + # I only want lists of integers
> + for i in obj:
> +- if type(i) is not IntType:
> ++ if type(i) is not int:
> + return 0
> +
> + return 1
> +@@ -113,7 +113,7 @@ class mycharlist(XMLP_Mutator):
> + def wants_obj(self,obj):
> + # I only want lists of single chars
> + for i in obj:
> +- if type(i) is not StringType or \
> ++ if type(i) is not str or \
> + len(i) != 1:
> + return 0
> +
> +@@ -135,8 +135,8 @@ class mycharlist(XMLP_Mutator):
> +
> + print "*** TEST 3 ***"
> +
> +-my1 = mynumlist(ListType,"NumList",in_body=1)
> +-my2 = mycharlist(ListType,"CharList",in_body=1)
> ++my1 = mynumlist(list,"NumList",in_body=1)
> ++my2 = mycharlist(list,"CharList",in_body=1)
> +
> + mutate.add_mutator(my1)
> + mutate.add_mutator(my2)
> +diff --git a/objdictgen/gnosis/xml/pickle/test/test_unicode.py b/objdictgen/gnosis/xml/pickle/test/test_unicode.py
> +index 2ab724664348..cf22ef6ad57b 100644
> +--- a/objdictgen/gnosis/xml/pickle/test/test_unicode.py
> ++++ b/objdictgen/gnosis/xml/pickle/test/test_unicode.py
> +@@ -2,13 +2,12 @@
> +
> + from gnosis.xml.pickle import loads,dumps
> + from gnosis.xml.pickle.util import setInBody
> +-from types import StringType, UnicodeType
> + import funcs
> +
> + funcs.set_parser()
> +
> + #-- Create some unicode and python strings (and an object that contains them)
> +-ustring = u"Alef: %s, Omega: %s" % (unichr(1488), unichr(969))
> ++ustring = u"Alef: %s, Omega: %s" % (chr(1488), chr(969))
> + pstring = "Only US-ASCII characters"
> + estring = "Only US-ASCII with line breaks\n\tthat was a tab"
> + class C:
> +@@ -25,12 +24,12 @@ xml = dumps(o)
> + #print '------------* Restored attributes from different strings *--------------'
> + o2 = loads(xml)
> + # check types explicitly, since comparison will coerce types
> +-if not isinstance(o2.ustring,UnicodeType):
> +- raise "AAGH! Didn't get UnicodeType"
> +-if not isinstance(o2.pstring,StringType):
> +- raise "AAGH! Didn't get StringType for pstring"
> +-if not isinstance(o2.estring,StringType):
> +- raise "AAGH! Didn't get StringType for estring"
> ++if not isinstance(o2.ustring,str):
> ++ raise "AAGH! Didn't get str"
> ++if not isinstance(o2.pstring,str):
> ++ raise "AAGH! Didn't get str for pstring"
> ++if not isinstance(o2.estring,str):
> ++ raise "AAGH! Didn't get str for estring"
> +
> + #print "UNICODE:", `o2.ustring`, type(o2.ustring)
> + #print "PLAIN: ", o2.pstring, type(o2.pstring)
> +@@ -43,18 +42,18 @@ if o.ustring != o2.ustring or \
> +
> + #-- Pickle with Python strings in body
> + #print '\n------------* Pickle with Python strings in body *----------------------'
> +-setInBody(StringType, 1)
> ++setInBody(str, 1)
> + xml = dumps(o)
> + #print xml,
> + #print '------------* Restored attributes from different strings *--------------'
> + o2 = loads(xml)
> + # check types explicitly, since comparison will coerce types
> +-if not isinstance(o2.ustring,UnicodeType):
> +- raise "AAGH! Didn't get UnicodeType"
> +-if not isinstance(o2.pstring,StringType):
> +- raise "AAGH! Didn't get StringType for pstring"
> +-if not isinstance(o2.estring,StringType):
> +- raise "AAGH! Didn't get StringType for estring"
> ++if not isinstance(o2.ustring,str):
> ++ raise "AAGH! Didn't get str"
> ++if not isinstance(o2.pstring,str):
> ++ raise "AAGH! Didn't get str for pstring"
> ++if not isinstance(o2.estring,str):
> ++ raise "AAGH! Didn't get str for estring"
> +
> + #print "UNICODE:", `o2.ustring`, type(o2.ustring)
> + #print "PLAIN: ", o2.pstring, type(o2.pstring)
> +@@ -67,7 +66,7 @@ if o.ustring != o2.ustring or \
> +
> + #-- Pickle with Unicode strings in attributes (FAIL)
> + #print '\n------------* Pickle with Unicode strings in XML attrs *----------------'
> +-setInBody(UnicodeType, 0)
> ++setInBody(str, 0)
> + try:
> + xml = dumps(o)
> + raise "FAIL: We should not be allowed to put Unicode in attrs"
> +diff --git a/objdictgen/gnosis/xml/pickle/util/__init__.py b/objdictgen/gnosis/xml/pickle/util/__init__.py
> +index 3eb05ee45b5e..46771ba97622 100644
> +--- a/objdictgen/gnosis/xml/pickle/util/__init__.py
> ++++ b/objdictgen/gnosis/xml/pickle/util/__init__.py
> +@@ -1,5 +1,5 @@
> +-from _flags import *
> +-from _util import \
> ++from gnosis.xml.pickle.util._flags import *
> ++from gnosis.xml.pickle.util._util import \
> + _klass, _module, _EmptyClass, subnodes, \
> + safe_eval, safe_string, unsafe_string, safe_content, unsafe_content, \
> + _mini_getstack, _mini_currentframe, \
> +diff --git a/objdictgen/gnosis/xml/pickle/util/_flags.py b/objdictgen/gnosis/xml/pickle/util/_flags.py
> +index 3555b0123251..969acd316e5f 100644
> +--- a/objdictgen/gnosis/xml/pickle/util/_flags.py
> ++++ b/objdictgen/gnosis/xml/pickle/util/_flags.py
> +@@ -32,17 +32,22 @@ def enumParsers():
> + try:
> + from gnosis.xml.pickle.parsers._dom import thing_from_dom
> + dict['DOM'] = thing_from_dom
> +- except: pass
> ++ except:
> ++ print("Notice: no DOM parser available")
> ++ raise
> +
> + try:
> + from gnosis.xml.pickle.parsers._sax import thing_from_sax
> + dict['SAX'] = thing_from_sax
> +- except: pass
> ++ except:
> ++ print("Notice: no SAX parser available")
> ++ raise
> +
> + try:
> + from gnosis.xml.pickle.parsers._cexpat import thing_from_cexpat
> + dict['cEXPAT'] = thing_from_cexpat
> +- except: pass
> ++ except:
> ++ print("Notice: no cEXPAT parser available")
> +
> + return dict
> +
> +diff --git a/objdictgen/gnosis/xml/pickle/util/_util.py b/objdictgen/gnosis/xml/pickle/util/_util.py
> +index 86e7339a9090..46d99eb1f9bc 100644
> +--- a/objdictgen/gnosis/xml/pickle/util/_util.py
> ++++ b/objdictgen/gnosis/xml/pickle/util/_util.py
> +@@ -158,8 +158,8 @@ def get_class_from_name(classname, modname=None, paranoia=1):
> + dbg("**ERROR - couldn't get class - paranoia = %s" % str(paranoia))
> +
> + # *should* only be for paranoia == 2, but a good failsafe anyways ...
> +- raise XMLUnpicklingError, \
> +- "Cannot create class under current PARANOIA setting!"
> ++ raise XMLUnpicklingError( \
> ++ "Cannot create class under current PARANOIA setting!")
> +
> + def obj_from_name(classname, modname=None, paranoia=1):
> + """Given a classname, optional module name, return an object
> +@@ -192,14 +192,14 @@ def _module(thing):
> +
> + def safe_eval(s):
> + if 0: # Condition for malicious string in eval() block
> +- raise "SecurityError", \
> +- "Malicious string '%s' should not be eval()'d" % s
> ++ raise SecurityError( \
> ++ "Malicious string '%s' should not be eval()'d" % s)
> + else:
> + return eval(s)
> +
> + def safe_string(s):
> +- if isinstance(s, UnicodeType):
> +- raise TypeError, "Unicode strings may not be stored in XML attributes"
> ++ if isinstance(s, str):
> ++ raise TypeError("Unicode strings may not be stored in XML attributes")
> +
> + # markup XML entities
> + s = s.replace('&', '&')
> +@@ -215,7 +215,7 @@ def unsafe_string(s):
> + # for Python escapes, exec the string
> + # (niggle w/ literalizing apostrophe)
> + s = s.replace("'", r"\047")
> +- exec "s='"+s+"'"
> ++ exec("s='"+s+"'")
> + # XML entities (DOM does it for us)
> + return s
> +
> +@@ -226,7 +226,7 @@ def safe_content(s):
> + s = s.replace('>', '>')
> +
> + # wrap "regular" python strings as unicode
> +- if isinstance(s, StringType):
> ++ if isinstance(s, str):
> + s = u"\xbb\xbb%s\xab\xab" % s
> +
> + return s.encode('utf-8')
> +@@ -237,7 +237,7 @@ def unsafe_content(s):
> + # don't have to "unescape" XML entities (parser does it for us)
> +
> + # unwrap python strings from unicode wrapper
> +- if s[:2]==unichr(187)*2 and s[-2:]==unichr(171)*2:
> ++ if s[:2]==chr(187)*2 and s[-2:]==chr(171)*2:
> + s = s[2:-2].encode('us-ascii')
> +
> + return s
> +@@ -248,7 +248,7 @@ def subnodes(node):
> + # for PyXML > 0.8, childNodes includes both <DOM Elements> and
> + # DocumentType objects, so we have to separate them.
> + return filter(lambda n: hasattr(n,'_attrs') and \
> +- n.nodeName<>'#text', node.childNodes)
> ++ n.nodeName!='#text', node.childNodes)
> +
> + #-------------------------------------------------------------------
> + # Python 2.0 doesn't have the inspect module, so we provide
> +diff --git a/objdictgen/gnosis/xml/relax/lex.py b/objdictgen/gnosis/xml/relax/lex.py
> +index 833213c3887f..59b0c6ba5851 100644
> +--- a/objdictgen/gnosis/xml/relax/lex.py
> ++++ b/objdictgen/gnosis/xml/relax/lex.py
> +@@ -252,7 +252,7 @@ class Lexer:
> + # input() - Push a new string into the lexer
> + # ------------------------------------------------------------
> + def input(self,s):
> +- if not isinstance(s,types.StringType):
> ++ if not isinstance(s,str):
> + raise ValueError, "Expected a string"
> + self.lexdata = s
> + self.lexpos = 0
> +@@ -314,7 +314,7 @@ class Lexer:
> +
> + # Verify type of the token. If not in the token map, raise an error
> + if not self.optimize:
> +- if not self.lextokens.has_key(newtok.type):
> ++ if not newtok.type in self.lextokens.keys():
> + raise LexError, ("%s:%d: Rule '%s' returned an unknown token type '%s'" % (
> + func.func_code.co_filename, func.func_code.co_firstlineno,
> + func.__name__, newtok.type),lexdata[lexpos:])
> +@@ -453,7 +453,7 @@ def lex(module=None,debug=0,optimize=0,lextab="lextab"):
> + tokens = ldict.get("tokens",None)
> + if not tokens:
> + raise SyntaxError,"lex: module does not define 'tokens'"
> +- if not (isinstance(tokens,types.ListType) or isinstance(tokens,types.TupleType)):
> ++ if not (isinstance(tokens,list) or isinstance(tokens,tuple)):
> + raise SyntaxError,"lex: tokens must be a list or tuple."
> +
> + # Build a dictionary of valid token names
> +@@ -470,7 +470,7 @@ def lex(module=None,debug=0,optimize=0,lextab="lextab"):
> + if not is_identifier(n):
> + print "lex: Bad token name '%s'" % n
> + error = 1
> +- if lexer.lextokens.has_key(n):
> ++ if n in lexer.lextokens.keys():
> + print "lex: Warning. Token '%s' multiply defined." % n
> + lexer.lextokens[n] = None
> + else:
> +@@ -489,7 +489,7 @@ def lex(module=None,debug=0,optimize=0,lextab="lextab"):
> + for f in tsymbols:
> + if isinstance(ldict[f],types.FunctionType):
> + fsymbols.append(ldict[f])
> +- elif isinstance(ldict[f],types.StringType):
> ++ elif isinstance(ldict[f],str):
> + ssymbols.append((f,ldict[f]))
> + else:
> + print "lex: %s not defined as a function or string" % f
> +@@ -565,7 +565,7 @@ def lex(module=None,debug=0,optimize=0,lextab="lextab"):
> + error = 1
> + continue
> +
> +- if not lexer.lextokens.has_key(name[2:]):
> ++ if not name[2:] in lexer.lextokens.keys():
> + print "lex: Rule '%s' defined for an unspecified token %s." % (name,name[2:])
> + error = 1
> + continue
> +diff --git a/objdictgen/gnosis/xml/relax/rnctree.py b/objdictgen/gnosis/xml/relax/rnctree.py
> +index 5430d858f012..2eee519828f9 100644
> +--- a/objdictgen/gnosis/xml/relax/rnctree.py
> ++++ b/objdictgen/gnosis/xml/relax/rnctree.py
> +@@ -290,7 +290,7 @@ def scan_NS(nodes):
> + elif node.type == NS:
> + ns, url = map(str.strip, node.value.split('='))
> + OTHER_NAMESPACE[ns] = url
> +- elif node.type == ANNOTATION and not OTHER_NAMESPACE.has_key('a'):
> ++ elif node.type == ANNOTATION and not 'a' in OTHER_NAMESPACE.keys():
> + OTHER_NAMESPACE['a'] =\
> + '"http://relaxng.org/ns/compatibility/annotations/1.0"'
> + elif node.type == DATATYPES:
> +diff --git a/objdictgen/gnosis/xml/xmlmap.py b/objdictgen/gnosis/xml/xmlmap.py
> +index 5f37cab24395..8103e902ae29 100644
> +--- a/objdictgen/gnosis/xml/xmlmap.py
> ++++ b/objdictgen/gnosis/xml/xmlmap.py
> +@@ -17,7 +17,7 @@
> + # codes. Anyways, Python 2.2 and up have fixed this bug, but
> + # I have used workarounds in the code here for compatibility.
> + #
> +-# So, in several places you'll see I've used unichr() instead of
> ++# So, in several places you'll see I've used chr() instead of
> + # coding the u'' directly due to this bug. I'm guessing that
> + # might be a little slower.
> + #
> +@@ -26,18 +26,10 @@ __all__ = ['usplit','is_legal_xml','is_legal_xml_char']
> +
> + import re
> +
> +-# define True/False if this Python doesn't have them (only
> +-# used in this file)
> +-try:
> +- a = True
> +-except:
> +- True = 1
> +- False = 0
> +-
> + def usplit( uval ):
> + """
> + Split Unicode string into a sequence of characters.
> +- \U sequences are considered to be a single character.
> ++ \\U sequences are considered to be a single character.
> +
> + You should assume you will get a sequence, and not assume
> + anything about the type of sequence (i.e. list vs. tuple vs. string).
> +@@ -65,8 +57,8 @@ def usplit( uval ):
> + # the second character is in range (0xdc00 - 0xdfff), then
> + # it is a 2-character encoding
> + if len(uval[i:]) > 1 and \
> +- uval[i] >= unichr(0xD800) and uval[i] <= unichr(0xDBFF) and \
> +- uval[i+1] >= unichr(0xDC00) and uval[i+1] <= unichr(0xDFFF):
> ++ uval[i] >= chr(0xD800) and uval[i] <= chr(0xDBFF) and \
> ++ uval[i+1] >= chr(0xDC00) and uval[i+1] <= chr(0xDFFF):
> +
> + # it's a two character encoding
> + clist.append( uval[i:i+2] )
> +@@ -106,10 +98,10 @@ def make_illegal_xml_regex():
> + using the codes (D800-DBFF),(DC00-DFFF), which are both illegal
> + when used as single chars, from above.
> +
> +- Python won't let you define \U character ranges, so you can't
> +- just say '\U00010000-\U0010FFFF'. However, you can take advantage
> ++ Python won't let you define \\U character ranges, so you can't
> ++ just say '\\U00010000-\\U0010FFFF'. However, you can take advantage
> + of the fact that (D800-DBFF) and (DC00-DFFF) are illegal, unless
> +- part of a 2-character sequence, to match for the \U characters.
> ++ part of a 2-character sequence, to match for the \\U characters.
> + """
> +
> + # First, add a group for all the basic illegal areas above
> +@@ -124,9 +116,9 @@ def make_illegal_xml_regex():
> +
> + # I've defined this oddly due to the bug mentioned at the top of this file
> + re_xml_illegal += u'([%s-%s][^%s-%s])|([^%s-%s][%s-%s])|([%s-%s]$)|(^[%s-%s])' % \
> +- (unichr(0xd800),unichr(0xdbff),unichr(0xdc00),unichr(0xdfff),
> +- unichr(0xd800),unichr(0xdbff),unichr(0xdc00),unichr(0xdfff),
> +- unichr(0xd800),unichr(0xdbff),unichr(0xdc00),unichr(0xdfff))
> ++ (chr(0xd800),chr(0xdbff),chr(0xdc00),chr(0xdfff),
> ++ chr(0xd800),chr(0xdbff),chr(0xdc00),chr(0xdfff),
> ++ chr(0xd800),chr(0xdbff),chr(0xdc00),chr(0xdfff))
> +
> + return re.compile( re_xml_illegal )
> +
> +@@ -156,7 +148,7 @@ def is_legal_xml_char( uchar ):
> +
> + Otherwise, the first char of a legal 2-character
> + sequence will be incorrectly tagged as illegal, on
> +- Pythons where \U is stored as 2-chars.
> ++ Pythons where \\U is stored as 2-chars.
> + """
> +
> + # due to inconsistencies in how \U is handled (based on
> +@@ -175,7 +167,7 @@ def is_legal_xml_char( uchar ):
> + (uchar >= u'\u000b' and uchar <= u'\u000c') or \
> + (uchar >= u'\u000e' and uchar <= u'\u0019') or \
> + # always illegal as single chars
> +- (uchar >= unichr(0xd800) and uchar <= unichr(0xdfff)) or \
> ++ (uchar >= chr(0xd800) and uchar <= chr(0xdfff)) or \
> + (uchar >= u'\ufffe' and uchar <= u'\uffff')
> + )
> + elif len(uchar) == 2:
> diff --git a/patches/canfestival-3+hg20180126.794/0008-port-to-python3.patch b/patches/canfestival-3+hg20180126.794/0008-port-to-python3.patch
> new file mode 100644
> index 000000000000..133c509c6e5c
> --- /dev/null
> +++ b/patches/canfestival-3+hg20180126.794/0008-port-to-python3.patch
> @@ -0,0 +1,945 @@
> +From: Roland Hieber <rhi@pengutronix.de>
> +Date: Sun, 11 Feb 2024 22:28:38 +0100
> +Subject: [PATCH] Port to Python 3
> +
> +Not all of the code was ported, only enough to make objdictgen calls in
> +the Makefile work enough to generate the code in examples/.
> +---
> + objdictgen/commondialogs.py | 2 +-
> + objdictgen/eds_utils.py | 76 ++++++++++++++++++++--------------------
> + objdictgen/gen_cfile.py | 25 +++++++------
> + objdictgen/networkedit.py | 4 +--
> + objdictgen/node.py | 57 +++++++++++++++---------------
> + objdictgen/nodeeditortemplate.py | 10 +++---
> + objdictgen/nodelist.py | 2 +-
> + objdictgen/nodemanager.py | 25 +++++++------
> + objdictgen/objdictedit.py | 22 ++++++------
> + objdictgen/objdictgen.py | 20 +++++------
> + 10 files changed, 122 insertions(+), 121 deletions(-)
> +
> +diff --git a/objdictgen/commondialogs.py b/objdictgen/commondialogs.py
> +index 77d6705bd70b..38b840b617c0 100644
> +--- a/objdictgen/commondialogs.py
> ++++ b/objdictgen/commondialogs.py
> +@@ -1566,7 +1566,7 @@ class DCFEntryValuesDialog(wx.Dialog):
> + if values != "":
> + data = values[4:]
> + current = 0
> +- for i in xrange(BE_to_LE(values[:4])):
> ++ for i in range(BE_to_LE(values[:4])):
> + value = {}
> + value["Index"] = BE_to_LE(data[current:current+2])
> + value["Subindex"] = BE_to_LE(data[current+2:current+3])
> +diff --git a/objdictgen/eds_utils.py b/objdictgen/eds_utils.py
> +index 969bae91dce5..aad8491681ac 100644
> +--- a/objdictgen/eds_utils.py
> ++++ b/objdictgen/eds_utils.py
> +@@ -53,8 +53,8 @@ BOOL_TRANSLATE = {True : "1", False : "0"}
> + ACCESS_TRANSLATE = {"RO" : "ro", "WO" : "wo", "RW" : "rw", "RWR" : "rw", "RWW" : "rw", "CONST" : "ro"}
> +
> + # Function for verifying data values
> +-is_integer = lambda x: type(x) in (IntType, LongType)
> +-is_string = lambda x: type(x) in (StringType, UnicodeType)
> ++is_integer = lambda x: type(x) == int
> ++is_string = lambda x: type(x) == str
> + is_boolean = lambda x: x in (0, 1)
> +
> + # Define checking of value for each attribute
> +@@ -174,7 +174,7 @@ def ParseCPJFile(filepath):
> + try:
> + computed_value = int(value, 16)
> + except:
> +- raise SyntaxError, _("\"%s\" is not a valid value for attribute \"%s\" of section \"[%s]\"")%(value, keyname, section_name)
> ++ raise SyntaxError(_("\"%s\" is not a valid value for attribute \"%s\" of section \"[%s]\"")%(value, keyname, section_name))
> + elif value.isdigit() or value.startswith("-") and value[1:].isdigit():
> + # Second case, value is a number and starts with "0" or "-0", then it's an octal value
> + if value.startswith("0") or value.startswith("-0"):
> +@@ -193,59 +193,59 @@ def ParseCPJFile(filepath):
> +
> + if keyname.upper() == "NETNAME":
> + if not is_string(computed_value):
> +- raise SyntaxError, _("Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\"")%(value, keyname, section_name)
> ++ raise SyntaxError(_("Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\"")%(value, keyname, section_name))
> + topology["Name"] = computed_value
> + elif keyname.upper() == "NODES":
> + if not is_integer(computed_value):
> +- raise SyntaxError, _("Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\"")%(value, keyname, section_name)
> ++ raise SyntaxError(_("Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\"")%(value, keyname, section_name))
> + topology["Number"] = computed_value
> + elif keyname.upper() == "EDSBASENAME":
> + if not is_string(computed_value):
> +- raise SyntaxError, _("Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\"")%(value, keyname, section_name)
> ++ raise SyntaxError(_("Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\"")%(value, keyname, section_name))
> + topology["Path"] = computed_value
> + elif nodepresent_result:
> + if not is_boolean(computed_value):
> +- raise SyntaxError, _("Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\"")%(value, keyname, section_name)
> ++ raise SyntaxError(_("Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\"")%(value, keyname, section_name))
> + nodeid = int(nodepresent_result.groups()[0])
> + if nodeid not in topology["Nodes"].keys():
> + topology["Nodes"][nodeid] = {}
> + topology["Nodes"][nodeid]["Present"] = computed_value
> + elif nodename_result:
> + if not is_string(value):
> +- raise SyntaxError, _("Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\"")%(value, keyname, section_name)
> ++ raise SyntaxError(_("Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\"")%(value, keyname, section_name))
> + nodeid = int(nodename_result.groups()[0])
> + if nodeid not in topology["Nodes"].keys():
> + topology["Nodes"][nodeid] = {}
> + topology["Nodes"][nodeid]["Name"] = computed_value
> + elif nodedcfname_result:
> + if not is_string(computed_value):
> +- raise SyntaxError, _("Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\"")%(value, keyname, section_name)
> ++ raise SyntaxError(_("Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\"")%(value, keyname, section_name))
> + nodeid = int(nodedcfname_result.groups()[0])
> + if nodeid not in topology["Nodes"].keys():
> + topology["Nodes"][nodeid] = {}
> + topology["Nodes"][nodeid]["DCFName"] = computed_value
> + else:
> +- raise SyntaxError, _("Keyname \"%s\" not recognised for section \"[%s]\"")%(keyname, section_name)
> ++ raise SyntaxError(_("Keyname \"%s\" not recognised for section \"[%s]\"")%(keyname, section_name))
> +
> + # All lines that are not empty and are neither a comment neither not a valid assignment
> + elif assignment.strip() != "":
> +- raise SyntaxError, _("\"%s\" is not a valid CPJ line")%assignment.strip()
> ++ raise SyntaxError(_("\"%s\" is not a valid CPJ line")%assignment.strip())
> +
> + if "Number" not in topology.keys():
> +- raise SyntaxError, _("\"Nodes\" keyname in \"[%s]\" section is missing")%section_name
> ++ raise SyntaxError(_("\"Nodes\" keyname in \"[%s]\" section is missing")%section_name)
> +
> + if topology["Number"] != len(topology["Nodes"]):
> +- raise SyntaxError, _("\"Nodes\" value not corresponding to number of nodes defined")
> ++ raise SyntaxError(_("\"Nodes\" value not corresponding to number of nodes defined"))
> +
> + for nodeid, node in topology["Nodes"].items():
> + if "Present" not in node.keys():
> +- raise SyntaxError, _("\"Node%dPresent\" keyname in \"[%s]\" section is missing")%(nodeid, section_name)
> ++ raise SyntaxError(_("\"Node%dPresent\" keyname in \"[%s]\" section is missing")%(nodeid, section_name))
> +
> + networks.append(topology)
> +
> + # In other case, there is a syntax problem into CPJ file
> + else:
> +- raise SyntaxError, _("Section \"[%s]\" is unrecognized")%section_name
> ++ raise SyntaxError(_("Section \"[%s]\" is unrecognized")%section_name)
> +
> + return networks
> +
> +@@ -275,7 +275,7 @@ def ParseEDSFile(filepath):
> + if section_name.upper() not in eds_dict:
> + eds_dict[section_name.upper()] = values
> + else:
> +- raise SyntaxError, _("\"[%s]\" section is defined two times")%section_name
> ++ raise SyntaxError(_("\"[%s]\" section is defined two times")%section_name)
> + # Second case, section name is an index name
> + elif index_result:
> + # Extract index number
> +@@ -288,7 +288,7 @@ def ParseEDSFile(filepath):
> + values["subindexes"] = eds_dict[index]["subindexes"]
> + eds_dict[index] = values
> + else:
> +- raise SyntaxError, _("\"[%s]\" section is defined two times")%section_name
> ++ raise SyntaxError(_("\"[%s]\" section is defined two times")%section_name)
> + is_entry = True
> + # Third case, section name is a subindex name
> + elif subindex_result:
> +@@ -301,14 +301,14 @@ def ParseEDSFile(filepath):
> + if subindex not in eds_dict[index]["subindexes"]:
> + eds_dict[index]["subindexes"][subindex] = values
> + else:
> +- raise SyntaxError, _("\"[%s]\" section is defined two times")%section_name
> ++ raise SyntaxError(_("\"[%s]\" section is defined two times")%section_name)
> + is_entry = True
> + # Third case, section name is a subindex name
> + elif index_objectlinks_result:
> + pass
> + # In any other case, there is a syntax problem into EDS file
> + else:
> +- raise SyntaxError, _("Section \"[%s]\" is unrecognized")%section_name
> ++ raise SyntaxError(_("Section \"[%s]\" is unrecognized")%section_name)
> +
> + for assignment in assignments:
> + # Escape any comment
> +@@ -330,13 +330,13 @@ def ParseEDSFile(filepath):
> + test = int(value.upper().replace("$NODEID+", ""), 16)
> + computed_value = "\"%s\""%value
> + except:
> +- raise SyntaxError, _("\"%s\" is not a valid formula for attribute \"%s\" of section \"[%s]\"")%(value, keyname, section_name)
> ++ raise SyntaxError(_("\"%s\" is not a valid formula for attribute \"%s\" of section \"[%s]\"")%(value, keyname, section_name))
> + # Second case, value starts with "0x", then it's an hexadecimal value
> + elif value.startswith("0x") or value.startswith("-0x"):
> + try:
> + computed_value = int(value, 16)
> + except:
> +- raise SyntaxError, _("\"%s\" is not a valid value for attribute \"%s\" of section \"[%s]\"")%(value, keyname, section_name)
> ++ raise SyntaxError(_("\"%s\" is not a valid value for attribute \"%s\" of section \"[%s]\"")%(value, keyname, section_name))
> + elif value.isdigit() or value.startswith("-") and value[1:].isdigit():
> + # Third case, value is a number and starts with "0", then it's an octal value
> + if value.startswith("0") or value.startswith("-0"):
> +@@ -354,17 +354,17 @@ def ParseEDSFile(filepath):
> + if is_entry:
> + # Verify that keyname is a possible attribute
> + if keyname.upper() not in ENTRY_ATTRIBUTES:
> +- raise SyntaxError, _("Keyname \"%s\" not recognised for section \"[%s]\"")%(keyname, section_name)
> ++ raise SyntaxError(_("Keyname \"%s\" not recognised for section \"[%s]\"")%(keyname, section_name))
> + # Verify that value is valid
> + elif not ENTRY_ATTRIBUTES[keyname.upper()](computed_value):
> +- raise SyntaxError, _("Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\"")%(value, keyname, section_name)
> ++ raise SyntaxError(_("Invalid value \"%s\" for keyname \"%s\" of section \"[%s]\"")%(value, keyname, section_name))
> + else:
> + values[keyname.upper()] = computed_value
> + else:
> + values[keyname.upper()] = computed_value
> + # All lines that are not empty and are neither a comment neither not a valid assignment
> + elif assignment.strip() != "":
> +- raise SyntaxError, _("\"%s\" is not a valid EDS line")%assignment.strip()
> ++ raise SyntaxError(_("\"%s\" is not a valid EDS line")%assignment.strip())
> +
> + # If entry is an index or a subindex
> + if is_entry:
> +@@ -384,7 +384,7 @@ def ParseEDSFile(filepath):
> + attributes = _("Attributes %s are")%_(", ").join(["\"%s\""%attribute for attribute in missing])
> + else:
> + attributes = _("Attribute \"%s\" is")%missing.pop()
> +- raise SyntaxError, _("Error on section \"[%s]\":\n%s required for a %s entry")%(section_name, attributes, ENTRY_TYPES[values["OBJECTTYPE"]]["name"])
> ++ raise SyntaxError(_("Error on section \"[%s]\":\n%s required for a %s entry")%(section_name, attributes, ENTRY_TYPES[values["OBJECTTYPE"]]["name"]))
> + # Verify that parameters defined are all in the possible parameters
> + if not keys.issubset(possible):
> + unsupported = keys.difference(possible)
> +@@ -392,7 +392,7 @@ def ParseEDSFile(filepath):
> + attributes = _("Attributes %s are")%_(", ").join(["\"%s\""%attribute for attribute in unsupported])
> + else:
> + attributes = _("Attribute \"%s\" is")%unsupported.pop()
> +- raise SyntaxError, _("Error on section \"[%s]\":\n%s unsupported for a %s entry")%(section_name, attributes, ENTRY_TYPES[values["OBJECTTYPE"]]["name"])
> ++ raise SyntaxError(_("Error on section \"[%s]\":\n%s unsupported for a %s entry")%(section_name, attributes, ENTRY_TYPES[values["OBJECTTYPE"]]["name"]))
> +
> + VerifyValue(values, section_name, "ParameterValue")
> + VerifyValue(values, section_name, "DefaultValue")
> +@@ -409,10 +409,10 @@ def VerifyValue(values, section_name, param):
> + elif values["DATATYPE"] == 0x01:
> + values[param.upper()] = {0 : False, 1 : True}[values[param.upper()]]
> + else:
> +- if not isinstance(values[param.upper()], (IntType, LongType)) and values[param.upper()].upper().find("$NODEID") == -1:
> ++ if not isinstance(values[param.upper()], int) and values[param.upper()].upper().find("$NODEID") == -1:
> + raise
> + except:
> +- raise SyntaxError, _("Error on section \"[%s]\":\n%s incompatible with DataType")%(section_name, param)
> ++ raise SyntaxError(_("Error on section \"[%s]\":\n%s incompatible with DataType")%(section_name, param))
> +
> +
> + # Function that write an EDS file after generate it's content
> +@@ -531,7 +531,7 @@ def GenerateFileContent(Node, filepath):
> + # Define section name
> + text = "\n[%X]\n"%entry
> + # If there is only one value, it's a VAR entry
> +- if type(values) != ListType:
> ++ if type(values) != list:
> + # Extract the informations of the first subindex
> + subentry_infos = Node.GetSubentryInfos(entry, 0)
> + # Generate EDS informations for the entry
> +@@ -636,7 +636,7 @@ def GenerateEDSFile(filepath, node):
> + # Write file
> + WriteFile(filepath, content)
> + return None
> +- except ValueError, message:
> ++ except ValueError as essage:
> + return _("Unable to generate EDS file\n%s")%message
> +
> + # Function that generate the CPJ file content for the nodelist
> +@@ -696,7 +696,7 @@ def GenerateNode(filepath, nodeID = 0):
> + if values["OBJECTTYPE"] == 2:
> + values["DATATYPE"] = values.get("DATATYPE", 0xF)
> + if values["DATATYPE"] != 0xF:
> +- raise SyntaxError, _("Domain entry 0x%4.4X DataType must be 0xF(DOMAIN) if defined")%entry
> ++ raise SyntaxError(_("Domain entry 0x%4.4X DataType must be 0xF(DOMAIN) if defined")%entry)
> + # Add mapping for entry
> + Node.AddMappingEntry(entry, name = values["PARAMETERNAME"], struct = 1)
> + # Add mapping for first subindex
> +@@ -713,7 +713,7 @@ def GenerateNode(filepath, nodeID = 0):
> + # Add mapping for first subindex
> + Node.AddMappingEntry(entry, 0, values = {"name" : "Number of Entries", "type" : 0x05, "access" : "ro", "pdo" : False})
> + # Add mapping for other subindexes
> +- for subindex in xrange(1, int(max_subindex) + 1):
> ++ for subindex in range(1, int(max_subindex) + 1):
> + # if subindex is defined
> + if subindex in values["subindexes"]:
> + Node.AddMappingEntry(entry, subindex, values = {"name" : values["subindexes"][subindex]["PARAMETERNAME"],
> +@@ -727,7 +727,7 @@ def GenerateNode(filepath, nodeID = 0):
> + ## elif values["OBJECTTYPE"] == 9:
> + ## # Verify that the first subindex is defined
> + ## if 0 not in values["subindexes"]:
> +-## raise SyntaxError, "Error on entry 0x%4.4X:\nSubindex 0 must be defined for a RECORD entry"%entry
> ++## raise SyntaxError("Error on entry 0x%4.4X:\nSubindex 0 must be defined for a RECORD entry"%entry)
> + ## # Add mapping for entry
> + ## Node.AddMappingEntry(entry, name = values["PARAMETERNAME"], struct = 7)
> + ## # Add mapping for first subindex
> +@@ -740,7 +740,7 @@ def GenerateNode(filepath, nodeID = 0):
> + ## "pdo" : values["subindexes"][1].get("PDOMAPPING", 0) == 1,
> + ## "nbmax" : 0xFE})
> + ## else:
> +-## raise SyntaxError, "Error on entry 0x%4.4X:\nA RECORD entry must have at least 2 subindexes"%entry
> ++## raise SyntaxError("Error on entry 0x%4.4X:\nA RECORD entry must have at least 2 subindexes"%entry)
> +
> + # Define entry for the new node
> +
> +@@ -763,7 +763,7 @@ def GenerateNode(filepath, nodeID = 0):
> + max_subindex = max(values["subindexes"].keys())
> + Node.AddEntry(entry, value = [])
> + # Define value for all subindexes except the first
> +- for subindex in xrange(1, int(max_subindex) + 1):
> ++ for subindex in range(1, int(max_subindex) + 1):
> + # Take default value if it is defined and entry is defined
> + if subindex in values["subindexes"] and "PARAMETERVALUE" in values["subindexes"][subindex]:
> + value = values["subindexes"][subindex]["PARAMETERVALUE"]
> +@@ -774,9 +774,9 @@ def GenerateNode(filepath, nodeID = 0):
> + value = GetDefaultValue(Node, entry, subindex)
> + Node.AddEntry(entry, subindex, value)
> + else:
> +- raise SyntaxError, _("Array or Record entry 0x%4.4X must have a \"SubNumber\" attribute")%entry
> ++ raise SyntaxError(_("Array or Record entry 0x%4.4X must have a \"SubNumber\" attribute")%entry)
> + return Node
> +- except SyntaxError, message:
> ++ except SyntaxError as message:
> + return _("Unable to import EDS file\n%s")%message
> +
> + #-------------------------------------------------------------------------------
> +@@ -784,5 +784,5 @@ def GenerateNode(filepath, nodeID = 0):
> + #-------------------------------------------------------------------------------
> +
> + if __name__ == '__main__':
> +- print ParseEDSFile("examples/PEAK MicroMod.eds")
> ++ print(ParseEDSFile("examples/PEAK MicroMod.eds"))
> +
> +diff --git a/objdictgen/gen_cfile.py b/objdictgen/gen_cfile.py
> +index 0945f52dc405..be452121fce9 100644
> +--- a/objdictgen/gen_cfile.py
> ++++ b/objdictgen/gen_cfile.py
> +@@ -61,9 +61,9 @@ def GetValidTypeInfos(typename, items=[]):
> + result = type_model.match(typename)
> + if result:
> + values = result.groups()
> +- if values[0] == "UNSIGNED" and int(values[1]) in [i * 8 for i in xrange(1, 9)]:
> ++ if values[0] == "UNSIGNED" and int(values[1]) in [i * 8 for i in range(1, 9)]:
> + typeinfos = ("UNS%s"%values[1], None, "uint%s"%values[1], True)
> +- elif values[0] == "INTEGER" and int(values[1]) in [i * 8 for i in xrange(1, 9)]:
> ++ elif values[0] == "INTEGER" and int(values[1]) in [i * 8 for i in range(1, 9)]:
> + typeinfos = ("INTEGER%s"%values[1], None, "int%s"%values[1], False)
> + elif values[0] == "REAL" and int(values[1]) in (32, 64):
> + typeinfos = ("%s%s"%(values[0], values[1]), None, "real%s"%values[1], False)
> +@@ -82,11 +82,11 @@ def GetValidTypeInfos(typename, items=[]):
> + elif values[0] == "BOOLEAN":
> + typeinfos = ("UNS8", None, "boolean", False)
> + else:
> +- raise ValueError, _("""!!! %s isn't a valid type for CanFestival.""")%typename
> ++ raise ValueError(_("""!!! %s isn't a valid type for CanFestival.""")%typename)
> + if typeinfos[2] not in ["visible_string", "domain"]:
> + internal_types[typename] = typeinfos
> + else:
> +- raise ValueError, _("""!!! %s isn't a valid type for CanFestival.""")%typename
> ++ raise ValueError(_("""!!! %s isn't a valid type for CanFestival.""")%typename)
> + return typeinfos
> +
> + def ComputeValue(type, value):
> +@@ -107,7 +107,7 @@ def WriteFile(filepath, content):
> + def GetTypeName(Node, typenumber):
> + typename = Node.GetTypeName(typenumber)
> + if typename is None:
> +- raise ValueError, _("""!!! Datatype with value "0x%4.4X" isn't defined in CanFestival.""")%typenumber
> ++ raise ValueError(_("""!!! Datatype with value "0x%4.4X" isn't defined in CanFestival.""")%typenumber)
> + return typename
> +
> + def GenerateFileContent(Node, headerfilepath, pointers_dict = {}):
> +@@ -189,7 +189,7 @@ def GenerateFileContent(Node, headerfilepath, pointers_dict = {}):
> + texts["index"] = index
> + strIndex = ""
> + entry_infos = Node.GetEntryInfos(index)
> +- texts["EntryName"] = entry_infos["name"].encode('ascii','replace')
> ++ texts["EntryName"] = entry_infos["name"]
> + values = Node.GetEntry(index)
> + callbacks = Node.HasEntryCallbacks(index)
> + if index in variablelist:
> +@@ -198,13 +198,13 @@ def GenerateFileContent(Node, headerfilepath, pointers_dict = {}):
> + strIndex += "\n/* index 0x%(index)04X : %(EntryName)s. */\n"%texts
> +
> + # Entry type is VAR
> +- if not isinstance(values, ListType):
> ++ if not isinstance(values, list):
> + subentry_infos = Node.GetSubentryInfos(index, 0)
> + typename = GetTypeName(Node, subentry_infos["type"])
> + typeinfos = GetValidTypeInfos(typename, [values])
> + if typename is "DOMAIN" and index in variablelist:
> + if not typeinfos[1]:
> +- raise ValueError, _("\nDomain variable not initialized\nindex : 0x%04X\nsubindex : 0x00")%index
> ++ raise ValueError(_("\nDomain variable not initialized\nindex : 0x%04X\nsubindex : 0x00")%index)
> + texts["subIndexType"] = typeinfos[0]
> + if typeinfos[1] is not None:
> + texts["suffixe"] = "[%d]"%typeinfos[1]
> +@@ -298,14 +298,14 @@ def GenerateFileContent(Node, headerfilepath, pointers_dict = {}):
> + name = "%(NodeName)s_Index%(index)04X"%texts
> + name=UnDigitName(name);
> + strIndex += " ODCallback_t %s_callbacks[] = \n {\n"%name
> +- for subIndex in xrange(len(values)):
> ++ for subIndex in range(len(values)):
> + strIndex += " NULL,\n"
> + strIndex += " };\n"
> + indexCallbacks[index] = "*callbacks = %s_callbacks; "%name
> + else:
> + indexCallbacks[index] = ""
> + strIndex += " subindex %(NodeName)s_Index%(index)04X[] = \n {\n"%texts
> +- for subIndex in xrange(len(values)):
> ++ for subIndex in range(len(values)):
> + subentry_infos = Node.GetSubentryInfos(index, subIndex)
> + if subIndex < len(values) - 1:
> + sep = ","
> +@@ -514,8 +514,7 @@ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
> + $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
> + */
> + """%texts
> +- contentlist = indexContents.keys()
> +- contentlist.sort()
> ++ contentlist = sorted(indexContents.keys())
> + for index in contentlist:
> + fileContent += indexContents[index]
> +
> +@@ -600,6 +599,6 @@ def GenerateFile(filepath, node, pointers_dict = {}):
> + WriteFile(filepath, content)
> + WriteFile(headerfilepath, header)
> + return None
> +- except ValueError, message:
> ++ except ValueError as message:
> + return _("Unable to Generate C File\n%s")%message
> +
> +diff --git a/objdictgen/networkedit.py b/objdictgen/networkedit.py
> +index 6577d6f9760b..2ba72e6962e1 100644
> +--- a/objdictgen/networkedit.py
> ++++ b/objdictgen/networkedit.py
> +@@ -541,13 +541,13 @@ class networkedit(wx.Frame, NetworkEditorTemplate):
> + find_index = True
> + index, subIndex = result
> + result = OpenPDFDocIndex(index, ScriptDirectory)
> +- if isinstance(result, (StringType, UnicodeType)):
> ++ if isinstance(result, str):
> + message = wx.MessageDialog(self, result, _("ERROR"), wx.OK|wx.ICON_ERROR)
> + message.ShowModal()
> + message.Destroy()
> + if not find_index:
> + result = OpenPDFDocIndex(None, ScriptDirectory)
> +- if isinstance(result, (StringType, UnicodeType)):
> ++ if isinstance(result, str):
> + message = wx.MessageDialog(self, result, _("ERROR"), wx.OK|wx.ICON_ERROR)
> + message.ShowModal()
> + message.Destroy()
> +diff --git a/objdictgen/node.py b/objdictgen/node.py
> +index e73dacbe8248..acaf558a00c6 100755
> +--- a/objdictgen/node.py
> ++++ b/objdictgen/node.py
> +@@ -21,7 +21,7 @@
> + #License along with this library; if not, write to the Free Software
> + #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> +
> +-import cPickle
> ++import _pickle as cPickle
> + from types import *
> + import re
> +
> +@@ -348,7 +348,7 @@ def FindMapVariableList(mappingdictionary, Node, compute=True):
> + name = mappingdictionary[index]["values"][subIndex]["name"]
> + if mappingdictionary[index]["struct"] & OD_IdenticalSubindexes:
> + values = Node.GetEntry(index)
> +- for i in xrange(len(values) - 1):
> ++ for i in range(len(values) - 1):
> + computed_name = name
> + if compute:
> + computed_name = StringFormat(computed_name, 1, i + 1)
> +@@ -568,7 +568,7 @@ class Node:
> + elif subIndex == 1:
> + self.Dictionary[index] = [value]
> + return True
> +- elif subIndex > 0 and type(self.Dictionary[index]) == ListType and subIndex == len(self.Dictionary[index]) + 1:
> ++ elif subIndex > 0 and type(self.Dictionary[index]) == list and subIndex == len(self.Dictionary[index]) + 1:
> + self.Dictionary[index].append(value)
> + return True
> + return False
> +@@ -582,7 +582,7 @@ class Node:
> + if value != None:
> + self.Dictionary[index] = value
> + return True
> +- elif type(self.Dictionary[index]) == ListType and 0 < subIndex <= len(self.Dictionary[index]):
> ++ elif type(self.Dictionary[index]) == list and 0 < subIndex <= len(self.Dictionary[index]):
> + if value != None:
> + self.Dictionary[index][subIndex - 1] = value
> + return True
> +@@ -594,7 +594,7 @@ class Node:
> + if index in self.Dictionary:
> + if (comment != None or save != None or callback != None) and index not in self.ParamsDictionary:
> + self.ParamsDictionary[index] = {}
> +- if subIndex == None or type(self.Dictionary[index]) != ListType and subIndex == 0:
> ++ if subIndex == None or type(self.Dictionary[index]) != list and subIndex == 0:
> + if comment != None:
> + self.ParamsDictionary[index]["comment"] = comment
> + if save != None:
> +@@ -602,7 +602,7 @@ class Node:
> + if callback != None:
> + self.ParamsDictionary[index]["callback"] = callback
> + return True
> +- elif type(self.Dictionary[index]) == ListType and 0 <= subIndex <= len(self.Dictionary[index]):
> ++ elif type(self.Dictionary[index]) == list and 0 <= subIndex <= len(self.Dictionary[index]):
> + if (comment != None or save != None or callback != None) and subIndex not in self.ParamsDictionary[index]:
> + self.ParamsDictionary[index][subIndex] = {}
> + if comment != None:
> +@@ -626,7 +626,7 @@ class Node:
> + if index in self.ParamsDictionary:
> + self.ParamsDictionary.pop(index)
> + return True
> +- elif type(self.Dictionary[index]) == ListType and subIndex == len(self.Dictionary[index]):
> ++ elif type(self.Dictionary[index]) == list and subIndex == len(self.Dictionary[index]):
> + self.Dictionary[index].pop(subIndex - 1)
> + if index in self.ParamsDictionary:
> + if subIndex in self.ParamsDictionary[index]:
> +@@ -657,7 +657,7 @@ class Node:
> + def GetEntry(self, index, subIndex = None, compute = True):
> + if index in self.Dictionary:
> + if subIndex == None:
> +- if type(self.Dictionary[index]) == ListType:
> ++ if type(self.Dictionary[index]) == list:
> + values = [len(self.Dictionary[index])]
> + for value in self.Dictionary[index]:
> + values.append(self.CompileValue(value, index, compute))
> +@@ -665,11 +665,11 @@ class Node:
> + else:
> + return self.CompileValue(self.Dictionary[index], index, compute)
> + elif subIndex == 0:
> +- if type(self.Dictionary[index]) == ListType:
> ++ if type(self.Dictionary[index]) == list:
> + return len(self.Dictionary[index])
> + else:
> + return self.CompileValue(self.Dictionary[index], index, compute)
> +- elif type(self.Dictionary[index]) == ListType and 0 < subIndex <= len(self.Dictionary[index]):
> ++ elif type(self.Dictionary[index]) == list and 0 < subIndex <= len(self.Dictionary[index]):
> + return self.CompileValue(self.Dictionary[index][subIndex - 1], index, compute)
> + return None
> +
> +@@ -682,28 +682,28 @@ class Node:
> + self.ParamsDictionary = {}
> + if index in self.Dictionary:
> + if subIndex == None:
> +- if type(self.Dictionary[index]) == ListType:
> ++ if type(self.Dictionary[index]) == list:
> + if index in self.ParamsDictionary:
> + result = []
> +- for i in xrange(len(self.Dictionary[index]) + 1):
> ++ for i in range(len(self.Dictionary[index]) + 1):
> + line = DefaultParams.copy()
> + if i in self.ParamsDictionary[index]:
> + line.update(self.ParamsDictionary[index][i])
> + result.append(line)
> + return result
> + else:
> +- return [DefaultParams.copy() for i in xrange(len(self.Dictionary[index]) + 1)]
> ++ return [DefaultParams.copy() for i in range(len(self.Dictionary[index]) + 1)]
> + else:
> + result = DefaultParams.copy()
> + if index in self.ParamsDictionary:
> + result.update(self.ParamsDictionary[index])
> + return result
> +- elif subIndex == 0 and type(self.Dictionary[index]) != ListType:
> ++ elif subIndex == 0 and type(self.Dictionary[index]) != list:
> + result = DefaultParams.copy()
> + if index in self.ParamsDictionary:
> + result.update(self.ParamsDictionary[index])
> + return result
> +- elif type(self.Dictionary[index]) == ListType and 0 <= subIndex <= len(self.Dictionary[index]):
> ++ elif type(self.Dictionary[index]) == list and 0 <= subIndex <= len(self.Dictionary[index]):
> + result = DefaultParams.copy()
> + if index in self.ParamsDictionary and subIndex in self.ParamsDictionary[index]:
> + result.update(self.ParamsDictionary[index][subIndex])
> +@@ -780,23 +780,23 @@ class Node:
> + if self.UserMapping[index]["struct"] & OD_IdenticalSubindexes:
> + if self.IsStringType(self.UserMapping[index]["values"][subIndex]["type"]):
> + if self.IsRealType(values["type"]):
> +- for i in xrange(len(self.Dictionary[index])):
> ++ for i in range(len(self.Dictionary[index])):
> + self.SetEntry(index, i + 1, 0.)
> + elif not self.IsStringType(values["type"]):
> +- for i in xrange(len(self.Dictionary[index])):
> ++ for i in range(len(self.Dictionary[index])):
> + self.SetEntry(index, i + 1, 0)
> + elif self.IsRealType(self.UserMapping[index]["values"][subIndex]["type"]):
> + if self.IsStringType(values["type"]):
> +- for i in xrange(len(self.Dictionary[index])):
> ++ for i in range(len(self.Dictionary[index])):
> + self.SetEntry(index, i + 1, "")
> + elif not self.IsRealType(values["type"]):
> +- for i in xrange(len(self.Dictionary[index])):
> ++ for i in range(len(self.Dictionary[index])):
> + self.SetEntry(index, i + 1, 0)
> + elif self.IsStringType(values["type"]):
> +- for i in xrange(len(self.Dictionary[index])):
> ++ for i in range(len(self.Dictionary[index])):
> + self.SetEntry(index, i + 1, "")
> + elif self.IsRealType(values["type"]):
> +- for i in xrange(len(self.Dictionary[index])):
> ++ for i in range(len(self.Dictionary[index])):
> + self.SetEntry(index, i + 1, 0.)
> + else:
> + if self.IsStringType(self.UserMapping[index]["values"][subIndex]["type"]):
> +@@ -883,14 +883,13 @@ class Node:
> + """
> + def GetIndexes(self):
> + listindex = self.Dictionary.keys()
> +- listindex.sort()
> +- return listindex
> ++ return sorted(listindex)
> +
> + """
> + Print the Dictionary values
> + """
> + def Print(self):
> +- print self.PrintString()
> ++ print(self.PrintString())
> +
> + def PrintString(self):
> + result = ""
> +@@ -899,7 +898,7 @@ class Node:
> + for index in listindex:
> + name = self.GetEntryName(index)
> + values = self.Dictionary[index]
> +- if isinstance(values, ListType):
> ++ if isinstance(values, list):
> + result += "%04X (%s):\n"%(index, name)
> + for subidx, value in enumerate(values):
> + subentry_infos = self.GetSubentryInfos(index, subidx + 1)
> +@@ -918,17 +917,17 @@ class Node:
> + value += (" %0"+"%d"%(size * 2)+"X")%BE_to_LE(data[i+7:i+7+size])
> + i += 7 + size
> + count += 1
> +- elif isinstance(value, IntType):
> ++ elif isinstance(value, int):
> + value = "%X"%value
> + result += "%04X %02X (%s): %s\n"%(index, subidx+1, subentry_infos["name"], value)
> + else:
> +- if isinstance(values, IntType):
> ++ if isinstance(values, int):
> + values = "%X"%values
> + result += "%04X (%s): %s\n"%(index, name, values)
> + return result
> +
> + def CompileValue(self, value, index, compute = True):
> +- if isinstance(value, (StringType, UnicodeType)) and value.upper().find("$NODEID") != -1:
> ++ if isinstance(value, str) and value.upper().find("$NODEID") != -1:
> + base = self.GetBaseIndex(index)
> + try:
> + raw = eval(value)
> +@@ -1153,7 +1152,7 @@ def LE_to_BE(value, size):
> + """
> +
> + data = ("%" + str(size * 2) + "." + str(size * 2) + "X") % value
> +- list_car = [data[i:i+2] for i in xrange(0, len(data), 2)]
> ++ list_car = [data[i:i+2] for i in range(0, len(data), 2)]
> + list_car.reverse()
> + return "".join([chr(int(car, 16)) for car in list_car])
> +
> +diff --git a/objdictgen/nodeeditortemplate.py b/objdictgen/nodeeditortemplate.py
> +index 462455f01df1..dc7c3743620d 100644
> +--- a/objdictgen/nodeeditortemplate.py
> ++++ b/objdictgen/nodeeditortemplate.py
> +@@ -83,10 +83,10 @@ class NodeEditorTemplate:
> + text = _("%s: %s entry of struct %s%s.")%(name,category,struct,number)
> + self.Frame.HelpBar.SetStatusText(text, 2)
> + else:
> +- for i in xrange(3):
> ++ for i in range(3):
> + self.Frame.HelpBar.SetStatusText("", i)
> + else:
> +- for i in xrange(3):
> ++ for i in range(3):
> + self.Frame.HelpBar.SetStatusText("", i)
> +
> + def RefreshProfileMenu(self):
> +@@ -95,7 +95,7 @@ class NodeEditorTemplate:
> + edititem = self.Frame.EditMenu.FindItemById(self.EDITMENU_ID)
> + if edititem:
> + length = self.Frame.AddMenu.GetMenuItemCount()
> +- for i in xrange(length-6):
> ++ for i in range(length-6):
> + additem = self.Frame.AddMenu.FindItemByPosition(6)
> + self.Frame.AddMenu.Delete(additem.GetId())
> + if profile not in ("None", "DS-301"):
> +@@ -201,7 +201,7 @@ class NodeEditorTemplate:
> + dialog.SetIndex(index)
> + if dialog.ShowModal() == wx.ID_OK:
> + result = self.Manager.AddMapVariableToCurrent(*dialog.GetValues())
> +- if not isinstance(result, (StringType, UnicodeType)):
> ++ if not isinstance(result, str):
> + self.RefreshBufferState()
> + self.RefreshCurrentIndexList()
> + else:
> +@@ -215,7 +215,7 @@ class NodeEditorTemplate:
> + dialog.SetTypeList(self.Manager.GetCustomisableTypes())
> + if dialog.ShowModal() == wx.ID_OK:
> + result = self.Manager.AddUserTypeToCurrent(*dialog.GetValues())
> +- if not isinstance(result, (StringType, UnicodeType)):
> ++ if not isinstance(result, str):
> + self.RefreshBufferState()
> + self.RefreshCurrentIndexList()
> + else:
> +diff --git a/objdictgen/nodelist.py b/objdictgen/nodelist.py
> +index 97576ac24210..d1356434fe97 100644
> +--- a/objdictgen/nodelist.py
> ++++ b/objdictgen/nodelist.py
> +@@ -184,7 +184,7 @@ class NodeList:
> + result = self.Manager.OpenFileInCurrent(masterpath)
> + else:
> + result = self.Manager.CreateNewNode("MasterNode", 0x00, "master", "", "None", "", "heartbeat", ["DS302"])
> +- if not isinstance(result, types.IntType):
> ++ if not isinstance(result, int):
> + return result
> + return None
> +
> +diff --git a/objdictgen/nodemanager.py b/objdictgen/nodemanager.py
> +index 8ad5d83b430e..9394e05e76cd 100755
> +--- a/objdictgen/nodemanager.py
> ++++ b/objdictgen/nodemanager.py
> +@@ -31,6 +31,8 @@ import eds_utils, gen_cfile
> + from types import *
> + import os, re
> +
> ++_ = lambda x: x
> ++
> + UndoBufferLength = 20
> +
> + type_model = re.compile('([\_A-Z]*)([0-9]*)')
> +@@ -65,7 +67,7 @@ class UndoBuffer:
> + self.MinIndex = 0
> + self.MaxIndex = 0
> + # Initialising buffer with currentstate at the first place
> +- for i in xrange(UndoBufferLength):
> ++ for i in range(UndoBufferLength):
> + if i == 0:
> + self.Buffer.append(currentstate)
> + else:
> +@@ -285,7 +287,8 @@ class NodeManager:
> + self.SetCurrentFilePath(filepath)
> + return index
> + except:
> +- return _("Unable to load file \"%s\"!")%filepath
> ++ print( _("Unable to load file \"%s\"!")%filepath)
> ++ raise
> +
> + """
> + Save current node in a file
> +@@ -378,7 +381,7 @@ class NodeManager:
> + default = self.GetTypeDefaultValue(subentry_infos["type"])
> + # First case entry is record
> + if infos["struct"] & OD_IdenticalSubindexes:
> +- for i in xrange(1, min(number,subentry_infos["nbmax"]-length) + 1):
> ++ for i in range(1, min(number,subentry_infos["nbmax"]-length) + 1):
> + node.AddEntry(index, length + i, default)
> + if not disable_buffer:
> + self.BufferCurrentNode()
> +@@ -386,7 +389,7 @@ class NodeManager:
> + # Second case entry is array, only possible for manufacturer specific
> + elif infos["struct"] & OD_MultipleSubindexes and 0x2000 <= index <= 0x5FFF:
> + values = {"name" : "Undefined", "type" : 5, "access" : "rw", "pdo" : True}
> +- for i in xrange(1, min(number,0xFE-length) + 1):
> ++ for i in range(1, min(number,0xFE-length) + 1):
> + node.AddMappingEntry(index, length + i, values = values.copy())
> + node.AddEntry(index, length + i, 0)
> + if not disable_buffer:
> +@@ -408,7 +411,7 @@ class NodeManager:
> + nbmin = 1
> + # Entry is a record, or is an array of manufacturer specific
> + if infos["struct"] & OD_IdenticalSubindexes or 0x2000 <= index <= 0x5FFF and infos["struct"] & OD_IdenticalSubindexes:
> +- for i in xrange(min(number, length - nbmin)):
> ++ for i in range(min(number, length - nbmin)):
> + self.RemoveCurrentVariable(index, length - i)
> + self.BufferCurrentNode()
> +
> +@@ -497,7 +500,7 @@ class NodeManager:
> + default = self.GetTypeDefaultValue(subentry_infos["type"])
> + node.AddEntry(index, value = [])
> + if "nbmin" in subentry_infos:
> +- for i in xrange(subentry_infos["nbmin"]):
> ++ for i in range(subentry_infos["nbmin"]):
> + node.AddEntry(index, i + 1, default)
> + else:
> + node.AddEntry(index, 1, default)
> +@@ -581,7 +584,7 @@ class NodeManager:
> + for menu,list in self.CurrentNode.GetSpecificMenu():
> + for i in list:
> + iinfos = self.GetEntryInfos(i)
> +- indexes = [i + incr * iinfos["incr"] for incr in xrange(iinfos["nbmax"])]
> ++ indexes = [i + incr * iinfos["incr"] for incr in range(iinfos["nbmax"])]
> + if index in indexes:
> + found = True
> + diff = index - i
> +@@ -613,10 +616,10 @@ class NodeManager:
> + if struct == rec:
> + values = {"name" : name + " %d[(sub)]", "type" : 0x05, "access" : "rw", "pdo" : True, "nbmax" : 0xFE}
> + node.AddMappingEntry(index, 1, values = values)
> +- for i in xrange(number):
> ++ for i in range(number):
> + node.AddEntry(index, i + 1, 0)
> + else:
> +- for i in xrange(number):
> ++ for i in range(number):
> + values = {"name" : "Undefined", "type" : 0x05, "access" : "rw", "pdo" : True}
> + node.AddMappingEntry(index, i + 1, values = values)
> + node.AddEntry(index, i + 1, 0)
> +@@ -1029,7 +1032,7 @@ class NodeManager:
> + editors = []
> + values = node.GetEntry(index, compute = False)
> + params = node.GetParamsEntry(index)
> +- if isinstance(values, ListType):
> ++ if isinstance(values, list):
> + for i, value in enumerate(values):
> + data.append({"value" : value})
> + data[-1].update(params[i])
> +@@ -1049,7 +1052,7 @@ class NodeManager:
> + "type" : None, "value" : None,
> + "access" : None, "save" : "option",
> + "callback" : "option", "comment" : "string"}
> +- if isinstance(values, ListType) and i == 0:
> ++ if isinstance(values, list) and i == 0:
> + if 0x1600 <= index <= 0x17FF or 0x1A00 <= index <= 0x1C00:
> + editor["access"] = "raccess"
> + else:
> +diff --git a/objdictgen/objdictedit.py b/objdictgen/objdictedit.py
> +index 9efb1ae83c0b..1a356fa2e7c5 100755
> +--- a/objdictgen/objdictedit.py
> ++++ b/objdictgen/objdictedit.py
> +@@ -30,8 +30,8 @@ __version__ = "$Revision: 1.48 $"
> +
> + if __name__ == '__main__':
> + def usage():
> +- print _("\nUsage of objdictedit.py :")
> +- print "\n %s [Filepath, ...]\n"%sys.argv[0]
> ++ print(_("\nUsage of objdictedit.py :"))
> ++ print("\n %s [Filepath, ...]\n"%sys.argv[0])
> +
> + try:
> + opts, args = getopt.getopt(sys.argv[1:], "h", ["help"])
> +@@ -343,7 +343,7 @@ class objdictedit(wx.Frame, NodeEditorTemplate):
> + if self.ModeSolo:
> + for filepath in filesOpen:
> + result = self.Manager.OpenFileInCurrent(os.path.abspath(filepath))
> +- if isinstance(result, (IntType, LongType)):
> ++ if isinstance(result, int):
> + new_editingpanel = EditingPanel(self.FileOpened, self, self.Manager)
> + new_editingpanel.SetIndex(result)
> + self.FileOpened.AddPage(new_editingpanel, "")
> +@@ -392,13 +392,13 @@ class objdictedit(wx.Frame, NodeEditorTemplate):
> + find_index = True
> + index, subIndex = result
> + result = OpenPDFDocIndex(index, ScriptDirectory)
> +- if isinstance(result, (StringType, UnicodeType)):
> ++ if isinstance(result, str):
> + message = wx.MessageDialog(self, result, _("ERROR"), wx.OK|wx.ICON_ERROR)
> + message.ShowModal()
> + message.Destroy()
> + if not find_index:
> + result = OpenPDFDocIndex(None, ScriptDirectory)
> +- if isinstance(result, (StringType, UnicodeType)):
> ++ if isinstance(result, str):
> + message = wx.MessageDialog(self, result, _("ERROR"), wx.OK|wx.ICON_ERROR)
> + message.ShowModal()
> + message.Destroy()
> +@@ -448,7 +448,7 @@ class objdictedit(wx.Frame, NodeEditorTemplate):
> + answer = dialog.ShowModal()
> + dialog.Destroy()
> + if answer == wx.ID_YES:
> +- for i in xrange(self.Manager.GetBufferNumber()):
> ++ for i in range(self.Manager.GetBufferNumber()):
> + if self.Manager.CurrentIsSaved():
> + self.Manager.CloseCurrent()
> + else:
> +@@ -542,7 +542,7 @@ class objdictedit(wx.Frame, NodeEditorTemplate):
> + NMT = dialog.GetNMTManagement()
> + options = dialog.GetOptions()
> + result = self.Manager.CreateNewNode(name, id, nodetype, description, profile, filepath, NMT, options)
> +- if isinstance(result, (IntType, LongType)):
> ++ if isinstance(result, int):
> + new_editingpanel = EditingPanel(self.FileOpened, self, self.Manager)
> + new_editingpanel.SetIndex(result)
> + self.FileOpened.AddPage(new_editingpanel, "")
> +@@ -570,7 +570,7 @@ class objdictedit(wx.Frame, NodeEditorTemplate):
> + filepath = dialog.GetPath()
> + if os.path.isfile(filepath):
> + result = self.Manager.OpenFileInCurrent(filepath)
> +- if isinstance(result, (IntType, LongType)):
> ++ if isinstance(result, int):
> + new_editingpanel = EditingPanel(self.FileOpened, self, self.Manager)
> + new_editingpanel.SetIndex(result)
> + self.FileOpened.AddPage(new_editingpanel, "")
> +@@ -603,7 +603,7 @@ class objdictedit(wx.Frame, NodeEditorTemplate):
> + result = self.Manager.SaveCurrentInFile()
> + if not result:
> + self.SaveAs()
> +- elif not isinstance(result, (StringType, UnicodeType)):
> ++ elif not isinstance(result, str):
> + self.RefreshBufferState()
> + else:
> + message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
> +@@ -621,7 +621,7 @@ class objdictedit(wx.Frame, NodeEditorTemplate):
> + filepath = dialog.GetPath()
> + if os.path.isdir(os.path.dirname(filepath)):
> + result = self.Manager.SaveCurrentInFile(filepath)
> +- if not isinstance(result, (StringType, UnicodeType)):
> ++ if not isinstance(result, str):
> + self.RefreshBufferState()
> + else:
> + message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
> +@@ -665,7 +665,7 @@ class objdictedit(wx.Frame, NodeEditorTemplate):
> + filepath = dialog.GetPath()
> + if os.path.isfile(filepath):
> + result = self.Manager.ImportCurrentFromEDSFile(filepath)
> +- if isinstance(result, (IntType, LongType)):
> ++ if isinstance(result, int):
> + new_editingpanel = EditingPanel(self.FileOpened, self, self.Manager)
> + new_editingpanel.SetIndex(result)
> + self.FileOpened.AddPage(new_editingpanel, "")
> +diff --git a/objdictgen/objdictgen.py b/objdictgen/objdictgen.py
> +index 9d5131b7a8c9..6dd88737fa18 100644
> +--- a/objdictgen/objdictgen.py
> ++++ b/objdictgen/objdictgen.py
> +@@ -29,8 +29,8 @@ from nodemanager import *
> + _ = lambda x: x
> +
> + def usage():
> +- print _("\nUsage of objdictgen.py :")
> +- print "\n %s XMLFilePath CFilePath\n"%sys.argv[0]
> ++ print(_("\nUsage of objdictgen.py :"))
> ++ print("\n %s XMLFilePath CFilePath\n"%sys.argv[0])
> +
> + try:
> + opts, args = getopt.getopt(sys.argv[1:], "h", ["help"])
> +@@ -57,20 +57,20 @@ if __name__ == '__main__':
> + if fileIn != "" and fileOut != "":
> + manager = NodeManager()
> + if os.path.isfile(fileIn):
> +- print _("Parsing input file")
> ++ print(_("Parsing input file"))
> + result = manager.OpenFileInCurrent(fileIn)
> +- if not isinstance(result, (StringType, UnicodeType)):
> ++ if not isinstance(result, str):
> + Node = result
> + else:
> +- print result
> ++ print(result)
> + sys.exit(-1)
> + else:
> +- print _("%s is not a valid file!")%fileIn
> ++ print(_("%s is not a valid file!")%fileIn)
> + sys.exit(-1)
> +- print _("Writing output file")
> ++ print(_("Writing output file"))
> + result = manager.ExportCurrentToCFile(fileOut)
> +- if isinstance(result, (UnicodeType, StringType)):
> +- print result
> ++ if isinstance(result, str):
> ++ print(result)
> + sys.exit(-1)
> +- print _("All done")
> ++ print(_("All done"))
> +
> diff --git a/patches/canfestival-3+hg20180126.794/series b/patches/canfestival-3+hg20180126.794/series
> index 73f9b660f25f..06183b8a76fa 100644
> --- a/patches/canfestival-3+hg20180126.794/series
> +++ b/patches/canfestival-3+hg20180126.794/series
> @@ -5,4 +5,6 @@
> 0003-Makefile.in-fix-suffix-rules.patch
> 0004-let-canfestival.h-include-config.h.patch
> 0005-Use-include-.-instead-of-include-.-for-own-files.patch
> -# 3c7ac338090e2d1acca872cb33f8371f - git-ptx-patches magic
> +0007-gnosis-port-to-python3.patch
> +0008-port-to-python3.patch
> +# c4e00d98381c6fe694a31333755e24e4 - git-ptx-patches magic
> diff --git a/rules/canfestival.in b/rules/canfestival.in
> index 3c455569e455..1716c209cede 100644
> --- a/rules/canfestival.in
> +++ b/rules/canfestival.in
> @@ -1,16 +1,11 @@
> -## SECTION=staging
> -## old section:
> -### SECTION=networking
> +## SECTION=networking
>
> config CANFESTIVAL
> tristate
> - select HOST_SYSTEM_PYTHON
> + select HOST_SYSTEM_PYTHON3
> prompt "canfestival"
> help
> CanFestival is an OpenSource CANOpen framework, licensed with GPLv2 and
> LGPLv2. For details, see the project web page:
>
> http://www.canfestival.org/
> -
> - STAGING: remove in PTXdist 2024.12.0
> - Upstream is dead and needs Python 2 to build, which is also dead.
> diff --git a/rules/canfestival.make b/rules/canfestival.make
> index 91d1d973ae60..09bb0b067d82 100644
> --- a/rules/canfestival.make
> +++ b/rules/canfestival.make
> @@ -17,7 +17,6 @@ endif
> #
> # Paths and names
> #
> -# Taken from https://hg.beremiz.org/CanFestival-3/rev/8bfe0ac00cdb
> CANFESTIVAL_VERSION := 3+hg20180126.794
> CANFESTIVAL_MD5 := c97bca1c4a81a17b1a75a1f8d068b2b3 00042e5396db4403b3feb43acc2aa1e5
> CANFESTIVAL := canfestival-$(CANFESTIVAL_VERSION)
> @@ -30,6 +29,24 @@ CANFESTIVAL_LICENSE_FILES := \
> file://LICENCE;md5=085e7fb76fb3fa8ba9e9ed0ce95a43f9 \
> file://COPYING;startline=17;endline=25;md5=2964e968dd34832b27b656f9a0ca2dbf
>
> +CANFESTIVAL_GNOSIS_SOURCE := $(CANFESTIVAL_DIR)/objdictgen/Gnosis_Utils-current.tar.gz
> +CANFESTIVAL_GNOSIS_DIR := $(CANFESTIVAL_DIR)/objdictgen/gnosis-tar-gz
> +
> +# ----------------------------------------------------------------------------
> +# Extract
> +# ----------------------------------------------------------------------------
> +
> +$(STATEDIR)/canfestival.extract:
> + @$(call targetinfo)
> + @$(call clean, $(CANFESTIVAL_DIR))
> + @$(call extract, CANFESTIVAL)
> + @# this is what objdictgen/Makfile does, but we want to patch gnosis
> + @$(call extract, CANFESTIVAL_GNOSIS)
> + @mv $(CANFESTIVAL_DIR)/objdictgen/gnosis-tar-gz/gnosis \
> + $(CANFESTIVAL_DIR)/objdictgen/gnosis
> + @$(call patchin, CANFESTIVAL)
> + @$(call touch)
> +
> # ----------------------------------------------------------------------------
> # Prepare
> # ----------------------------------------------------------------------------
prev parent reply other threads:[~2024-03-19 6:46 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-20 10:33 [ptxdist] [PATCH] " Roland Hieber
2024-03-07 15:52 ` Michael Olbrich
2024-03-07 17:32 ` Roland Hieber
2024-03-08 7:15 ` Michael Olbrich
2024-03-08 7:51 ` Michael Olbrich
2024-03-12 10:31 ` [ptxdist] [PATCH v2] " Roland Hieber
2024-03-19 6:44 ` Michael Olbrich [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240319064454.3793651-1-m.olbrich@pengutronix.de \
--to=m.olbrich@pengutronix.de \
--cc=ptxdist@pengutronix.de \
--cc=rhi@pengutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox