mailarchive of the ptxdist mailing list
 help / color / mirror / Atom feed
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('&', '&amp;')
> +@@ -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('>', '&gt;')
> + 
> +     # 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
>  # ----------------------------------------------------------------------------



      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