[Python-modules-commits] r31190 - in packages/python-odf/trunk/debian (11 files)

georgesk at users.alioth.debian.org georgesk at users.alioth.debian.org
Tue Oct 21 09:54:58 UTC 2014


    Date: Tuesday, October 21, 2014 @ 09:54:57
  Author: georgesk
Revision: 31190

preparing for Python3

Added:
  packages/python-odf/trunk/debian/patches/
  packages/python-odf/trunk/debian/patches/libsToPython3.patch
  packages/python-odf/trunk/debian/patches/series
  packages/python-odf/trunk/debian/patches/toPython3.patch
  packages/python-odf/trunk/debian/python-odf-doc.install
  packages/python-odf/trunk/debian/python-odf.install
  packages/python-odf/trunk/debian/python3-odf.install
Modified:
  packages/python-odf/trunk/debian/changelog
  packages/python-odf/trunk/debian/compat
  packages/python-odf/trunk/debian/control
  packages/python-odf/trunk/debian/rules

Modified: packages/python-odf/trunk/debian/changelog
===================================================================
--- packages/python-odf/trunk/debian/changelog	2014-10-21 08:34:37 UTC (rev 31189)
+++ packages/python-odf/trunk/debian/changelog	2014-10-21 09:54:57 UTC (rev 31190)
@@ -1,3 +1,16 @@
+python-odf (0.9.7-0.1) UNRELEASED; urgency=medium
+
+  * Non-maintainer upload.
+  * modified the library to work with python3
+  * upgraded Standards-Version to 3.9.5, debhelper to 9
+  * added two new binary packages: python3-odf and python-odf-doc; the last one
+    provides the documentation for Odfpy's API as an opendocument
+  * modified the test routine to run tests with both python 2 and 3.
+    All tests are not passed. testxhtml.py does not appear to work in a
+    predictible way: the number of failures may change when it is run again.
+
+ -- Georges Khaznadar <georgesk at debian.org>  Sun, 19 Oct 2014 16:42:00 +0200
+
 python-odf (0.9.6-2) unstable; urgency=low
 
   [Jakub Wilk <jwilk at debian.org>  Sun, 05 May 2013 16:03:01 +0200]

Modified: packages/python-odf/trunk/debian/compat
===================================================================
--- packages/python-odf/trunk/debian/compat	2014-10-21 08:34:37 UTC (rev 31189)
+++ packages/python-odf/trunk/debian/compat	2014-10-21 09:54:57 UTC (rev 31190)
@@ -1 +1 @@
-8
+9

Modified: packages/python-odf/trunk/debian/control
===================================================================
--- packages/python-odf/trunk/debian/control	2014-10-21 08:34:37 UTC (rev 31189)
+++ packages/python-odf/trunk/debian/control	2014-10-21 09:54:57 UTC (rev 31190)
@@ -3,8 +3,8 @@
 Priority: optional
 Maintainer: Debian Python Modules Team <python-modules-team at lists.alioth.debian.org>
 Uploaders: Thomas Bechtold <thomasbechtold at jpberlin.de>, W. Martin Borgert <debacle at debian.org>
-Standards-Version: 3.9.4
-Build-Depends: debhelper (>= 8), python-all, xmlto
+Standards-Version: 3.9.5
+Build-Depends: debhelper (>= 9.0), python-all, python3-all, xmlto
 X-Python-Version: >= 2.7
 Homepage: https://joinup.ec.europa.eu/software/odfpy/home
 Vcs-Svn: svn://anonscm.debian.org/python-modules/packages/python-odf/trunk/
@@ -12,8 +12,9 @@
 
 Package: python-odf
 Architecture: all
+Recommends: python-odf-doc
 Depends: ${misc:Depends}, ${python:Depends}
-Description: Odfpy aims to be a complete API for OpenDocument in Python.
+Description: Odfpy aims to be a complete API for OpenDocument in Python2.
  Unlike other more convenient APIs, this one is essentially an abstraction
  layer just above the XML format. Odfpy is a library to read and write 
  OpenDocument v. 1.1 files. The main focus has been to prevent the programmer
@@ -25,3 +26,28 @@
  all ODF constructions, but could be improved in its understanding of data 
  types. Take a look at the Getting Started page then consult the Reference 
  Manual.
+
+Package: python3-odf
+Architecture: all
+Recommends: python-odf-doc
+Conflicts: python-odf (<< 0.9.7)
+Depends: ${misc:Depends}, ${python:Depends}, python3
+Description: Odfpy aims to be a complete API for OpenDocument in Python3.
+ Unlike other more convenient APIs, this one is essentially an abstraction
+ layer just above the XML format. Odfpy is a library to read and write 
+ OpenDocument v. 1.1 files. The main focus has been to prevent the programmer
+ from creating invalid documents. It has checks that raise an exception if the
+ programmer adds an invalid element, adds an attribute unknown to the grammar,
+ forgets to add a required attribute or adds text to an element that doesn't 
+ allow it. These checks and the API itself were generated from the RelaxNG 
+ schema, and then hand-edited. Therefore the API is complete and can handle 
+ all ODF constructions, but could be improved in its understanding of data 
+ types. Take a look at the Getting Started page then consult the Reference 
+ Manual.
+
+Package: python-odf-doc
+Architecture: all
+Section: doc
+Depends: ${misc:Depends}
+Description: documentation files for python-odf and python3-odf
+ Odfpy is a library to read and write OpenDocument v. 1.1 files.

Added: packages/python-odf/trunk/debian/patches/libsToPython3.patch
===================================================================
--- packages/python-odf/trunk/debian/patches/libsToPython3.patch	                        (rev 0)
+++ packages/python-odf/trunk/debian/patches/libsToPython3.patch	2014-10-21 09:54:57 UTC (rev 31190)
@@ -0,0 +1,1092 @@
+Index: python-odf-0.9.7/odf/attrconverters.py
+===================================================================
+--- python-odf-0.9.7.orig/odf/attrconverters.py
++++ python-odf-0.9.7/odf/attrconverters.py
+@@ -17,6 +17,9 @@
+ #
+ # Contributor(s):
+ #
++
++import sys, os.path
++sys.path.append(os.path.dirname(__file__))
+ from namespaces import *
+ import re, types
+ 
+@@ -29,7 +32,7 @@ def make_NCName(arg):
+     return arg
+ 
+ def cnv_anyURI(attribute, arg, element):
+-    return unicode(arg)
++    return str(arg)
+ 
+ def cnv_boolean(attribute, arg, element):
+     """ XML Schema Part 2: Datatypes Second Edition
+@@ -40,7 +43,7 @@ def cnv_boolean(attribute, arg, element)
+         return "false"
+     if str(arg).lower() in ("1","true","yes"):
+         return "true"
+-    raise ValueError, "'%s' not allowed as Boolean value for %s" % (str(arg), attribute)
++    raise ValueError( "'%s' not allowed as Boolean value for %s" % (str(arg), attribute))
+ 
+ # Potentially accept color values
+ def cnv_color(attribute, arg, element):
+@@ -52,12 +55,12 @@ def cnv_color(attribute, arg, element):
+ def cnv_configtype(attribute, arg, element):
+     if str(arg) not in ("boolean", "short", "int", "long",
+     "double", "string", "datetime", "base64Binary"):
+-        raise ValueError, "'%s' not allowed" % str(arg)
++        raise ValueError( "'%s' not allowed" % str(arg))
+     return str(arg)
+ 
+ def cnv_data_source_has_labels(attribute, arg, element):
+     if str(arg) not in ("none","row","column","both"):
+-        raise ValueError, "'%s' not allowed" % str(arg)
++        raise ValueError( "'%s' not allowed" % str(arg))
+     return str(arg)
+ 
+ # Understand different date formats
+@@ -83,19 +86,19 @@ def cnv_family(attribute, arg, element):
+     """ A style family """
+     if str(arg) not in ("text", "paragraph", "section", "ruby", "table", "table-column", "table-row", "table-cell",
+       "graphic", "presentation", "drawing-page", "chart"):
+-        raise ValueError, "'%s' not allowed" % str(arg)
++        raise ValueError( "'%s' not allowed" % str(arg))
+     return str(arg)
+ 
+ def __save_prefix(attribute, arg, element):
+     prefix = arg.split(':',1)[0]
+     if prefix == arg:
+-        return unicode(arg)
++        return str(arg)
+     namespace = element.get_knownns(prefix)
+     if namespace is None:
+-        #raise ValueError, "'%s' is an unknown prefix" % str(prefix)
+-        return unicode(arg)
++        #raise ValueError( "'%s' is an unknown prefix" % str(prefix))
++        return str(arg)
+     p = element.get_nsprefix(namespace)
+-    return unicode(arg)
++    return str(arg)
+ 
+ def cnv_formula(attribute, arg, element):
+     """ A string containing a formula. Formulas do not have a predefined syntax, but the string should
+@@ -116,7 +119,7 @@ def cnv_integer(attribute, arg, element)
+ 
+ def cnv_legend_position(attribute, arg, element):
+     if str(arg) not in ("start", "end", "top", "bottom", "top-start", "bottom-start", "top-end", "bottom-end"):
+-        raise ValueError, "'%s' not allowed" % str(arg)
++        raise ValueError( "'%s' not allowed" % str(arg))
+     return str(arg)
+ 
+ pattern_length = re.compile(r'-?([0-9]+(\.[0-9]*)?|\.[0-9]+)((cm)|(mm)|(in)|(pt)|(pc)|(px))')
+@@ -127,7 +130,7 @@ def cnv_length(attribute, arg, element):
+     """
+     global pattern_length
+     if not pattern_length.match(arg):
+-        raise ValueError, "'%s' is not a valid length" % arg
++        raise ValueError( "'%s' is not a valid length" % arg)
+     return arg
+ 
+ def cnv_lengthorpercent(attribute, arg, element):
+@@ -137,17 +140,17 @@ def cnv_lengthorpercent(attribute, arg,
+     try: return cnv_percent(attribute, arg, element)
+     except: failed = True
+     if failed:
+-        raise ValueError, "'%s' is not a valid length or percent" % arg
++        raise ValueError( "'%s' is not a valid length or percent" % arg)
+     return arg
+ 
+ def cnv_metavaluetype(attribute, arg, element):
+     if str(arg) not in ("float", "date", "time", "boolean", "string"):
+-        raise ValueError, "'%s' not allowed" % str(arg)
++        raise ValueError( "'%s' not allowed" % str(arg))
+     return str(arg)
+ 
+ def cnv_major_minor(attribute, arg, element):
+     if arg not in ('major','minor'):
+-        raise ValueError, "'%s' is not either 'minor' or 'major'" % arg
++        raise ValueError( "'%s' is not either 'minor' or 'major'" % arg)
+ 
+ pattern_namespacedToken = re.compile(r'[0-9a-zA-Z_]+:[0-9a-zA-Z._\-]+')
+ 
+@@ -155,14 +158,15 @@ def cnv_namespacedToken(attribute, arg,
+     global pattern_namespacedToken
+ 
+     if not pattern_namespacedToken.match(arg):
+-        raise ValueError, "'%s' is not a valid namespaced token" % arg
++        raise ValueError( "'%s' is not a valid namespaced token" % arg)
+     return __save_prefix(attribute, arg, element)
+ 
+ def cnv_NCName(attribute, arg, element):
+     """ NCName is defined in http://www.w3.org/TR/REC-xml-names/#NT-NCName
+         Essentially an XML name minus ':'
+     """
+-    if type(arg) in types.StringTypes:
++    #if type(arg) in types.StringTypes:
++    if (sys.version_info.major==3 and isinstance(arg, str)) or type(arg) in types.StringTypes:
+         return make_NCName(arg)
+     else:
+         return arg.getAttrNS(STYLENS, 'name')
+@@ -199,7 +203,7 @@ pattern_percent = re.compile(r'-?([0-9]+
+ def cnv_percent(attribute, arg, element):
+     global pattern_percent
+     if not pattern_percent.match(arg):
+-        raise ValueError, "'%s' is not a valid length" % arg
++        raise ValueError( "'%s' is not a valid length" % arg)
+     return arg
+ 
+ # Real one doesn't allow floating point values
+@@ -207,26 +211,29 @@ pattern_points = re.compile(r'-?[0-9]+,-
+ #pattern_points = re.compile(r'-?[0-9.]+,-?[0-9.]+([ ]+-?[0-9.]+,-?[0-9.]+)*')
+ def cnv_points(attribute, arg, element):
+     global pattern_points
+-    if type(arg) in types.StringTypes:
++    if (sys.version_info.major==3 and isinstance(arg, str)) or (sys.version_info.major==2 and type(arg) in types.StringTypes):
+         if not pattern_points.match(arg):
+-            raise ValueError, "x,y are separated by a comma and the points are separated by white spaces"
++            raise ValueError( "x,y are separated by a comma and the points are separated by white spaces")
+         return arg
+     else:
+         try:
+             strarg = ' '.join([ "%d,%d" % p for p in arg])
+         except:
+-            raise ValueError, "Points must be string or [(0,0),(1,1)] - not %s" % arg
++            raise ValueError( "Points must be string or [(0,0),(1,1)] - not %s" % arg)
+         return strarg
+ 
+ def cnv_positiveInteger(attribute, arg, element):
+     return str(arg)
+ 
+ def cnv_string(attribute, arg, element):
+-    return unicode(arg)
++    try:
++        return unicode(arg)
++    except NameError:
++        return str(arg)
+ 
+ def cnv_textnoteclass(attribute, arg, element):
+     if str(arg) not in ("footnote", "endnote"):
+-        raise ValueError, "'%s' not allowed" % str(arg)
++        raise ValueError( "'%s' not allowed" % str(arg))
+     return str(arg)
+ 
+ # Understand different time formats
+@@ -241,12 +248,12 @@ pattern_viewbox = re.compile(r'-?[0-9]+(
+ def cnv_viewbox(attribute, arg, element):
+     global pattern_viewbox
+     if not pattern_viewbox.match(arg):
+-        raise ValueError, "viewBox must be four integers separated by whitespaces"
++        raise ValueError( "viewBox must be four integers separated by whitespaces")
+     return arg
+ 
+ def cnv_xlinkshow(attribute, arg, element):
+     if str(arg) not in ("new", "replace", "embed"):
+-        raise ValueError, "'%s' not allowed" % str(arg)
++        raise ValueError( "'%s' not allowed" % str(arg))
+     return str(arg)
+ 
+ 
+@@ -1486,5 +1493,8 @@ class AttrConverters:
+             conversion = attrconverters.get((attribute, None), None)
+             if conversion is not None:
+                 return conversion(attribute, value, element)
+-        return unicode(value)
++        try:
++            return unicode(value)
++        except:
++            return str(value)
+ 
+Index: python-odf-0.9.7/odf/draw.py
+===================================================================
+--- python-odf-0.9.7.orig/odf/draw.py
++++ python-odf-0.9.7/odf/draw.py
+@@ -18,6 +18,8 @@
+ # Contributor(s):
+ #
+ 
++import sys, os.path
++sys.path.append(os.path.dirname(__file__))
+ from namespaces import DRAWNS, STYLENS, PRESENTATIONNS
+ from element import Element
+ 
+@@ -30,7 +32,7 @@ def StyleRefElement(stylename=None, clas
+         elif f == 'presentation':
+             qattrs[(PRESENTATIONNS,u'style-name')]= stylename
+         else:
+-            raise ValueError, "Style's family must be either 'graphic' or 'presentation'"
++            raise ValueError( "Style's family must be either 'graphic' or 'presentation'")
+     if classnames is not None:
+         f = classnames[0].getAttrNS(STYLENS, 'family')
+         if f == 'graphic':
+@@ -38,12 +40,12 @@ def StyleRefElement(stylename=None, clas
+         elif f == 'presentation':
+             qattrs[(PRESENTATIONNS,u'class-names')]= classnames
+         else:
+-            raise ValueError, "Style's family must be either 'graphic' or 'presentation'"
++            raise ValueError( "Style's family must be either 'graphic' or 'presentation'")
+     return Element(qattributes=qattrs, **args)
+ 
+ def DrawElement(name=None, **args):
+     e = Element(name=name, **args)
+-    if not args.has_key('displayname'):
++    if 'displayname' not in args:
+         e.setAttrNS(DRAWNS,'display-name', name)
+     return e
+ 
+Index: python-odf-0.9.7/odf/element.py
+===================================================================
+--- python-odf-0.9.7.orig/odf/element.py
++++ python-odf-0.9.7/odf/element.py
+@@ -22,6 +22,8 @@
+ # Note: This script has copied a lot of text from xml.dom.minidom.
+ # Whatever license applies to that file also applies to this file.
+ #
++import sys, os.path
++sys.path.append(os.path.dirname(__file__))
+ import xml.dom
+ from xml.dom.minicompat import *
+ from namespaces import nsdict
+@@ -79,6 +81,11 @@ def _nssplit(qualifiedName):
+ def _nsassign(namespace):
+     return nsdict.setdefault(namespace,"ns" + str(len(nsdict)))
+ 
++try:
++    StandardError
++except NameError:
++    StandardError=Exception
++
+ # Exceptions
+ class IllegalChild(StandardError):
+     """ Complains if you add an element to a parent where it is not allowed """
+@@ -116,7 +123,7 @@ class Node(xml.dom.Node):
+             If refChild is null, insert newChild at the end of the list of children.
+         """
+         if newChild.nodeType not in self._child_node_types:
+-            raise IllegalChild, "%s cannot be child of %s" % (newChild.tagName, self.tagName)
++            raise IllegalChild( "%s cannot be child of %s" % (newChild.tagName, self.tagName))
+         if newChild.parentNode is not None:
+             newChild.parentNode.removeChild(newChild)
+         if refChild is None:
+@@ -148,7 +155,7 @@ class Node(xml.dom.Node):
+             ### The DOM does not clearly specify what to return in this case
+             return newChild
+         if newChild.nodeType not in self._child_node_types:
+-            raise IllegalChild, "<%s> is not allowed in %s" % ( newChild.tagName, self.tagName)
++            raise IllegalChild( "<%s> is not allowed in %s" % ( newChild.tagName, self.tagName))
+         if newChild.parentNode is not None:
+             newChild.parentNode.removeChild(newChild)
+         _append_child(self, newChild)
+@@ -245,7 +252,10 @@ class Text(Childless, Node):
+         self.data = data
+ 
+     def __str__(self):
+-        return self.data.encode()
++        if sys.version_info.major ==3:
++            return self.data
++        else:
++            return self.data.encode()
+ 
+     def __unicode__(self):
+         return self.data
+@@ -253,9 +263,12 @@ class Text(Childless, Node):
+     def toXml(self,level,f):
+         """ Write XML in UTF-8 """
+         if self.data:
+-            f.write(_escape(unicode(self.data).encode('utf-8')))
++            if sys.version_info.major == 3:
++                f.write(_escape(self.data))
++            else:
++                f.write(_escape(unicode(self.data).encode('utf-8')))
+     
+-class CDATASection(Childless, Text):
++class CDATASection(Text, Childless):
+     nodeType = Node.CDATA_SECTION_NODE
+ 
+     def toXml(self,level,f):
+@@ -324,7 +337,7 @@ class Element(Node):
+         if required:
+             for r in required:
+                 if self.getAttrNS(r[0],r[1]) is None:
+-                    raise AttributeError, "Required attribute missing: %s in <%s>" % (r[1].lower().replace('-',''), self.tagName)
++                    raise AttributeError( "Required attribute missing: %s in <%s>" % (r[1].lower().replace('-',''), self.tagName))
+ 
+     def get_knownns(self, prefix):
+         """ Odfpy maintains a list of known namespaces. In some cases a prefix is used, and
+@@ -341,7 +354,7 @@ class Element(Node):
+         """
+         if namespace is None: namespace = ""
+         prefix = _nsassign(namespace)
+-        if not self.namespaces.has_key(namespace):
++        if not namespace in self.namespaces:
+             self.namespaces[namespace] = prefix
+         return prefix
+ 
+@@ -360,7 +373,7 @@ class Element(Node):
+         """
+         if check_grammar and self.allowed_children is not None:
+             if element.qname not in self.allowed_children:
+-                raise IllegalChild, "<%s> is not allowed in <%s>" % ( element.tagName, self.tagName)
++                raise IllegalChild( "<%s> is not allowed in <%s>" % ( element.tagName, self.tagName))
+         self.appendChild(element)
+         self._setOwnerDoc(element)
+         if self.ownerDocument:
+@@ -371,7 +384,7 @@ class Element(Node):
+             Setting check_grammar=False turns off grammar checking
+         """
+         if check_grammar and self.qname not in grammar.allows_text:
+-            raise IllegalText, "The <%s> element does not allow text" % self.tagName
++            raise IllegalText( "The <%s> element does not allow text" % self.tagName)
+         else:
+             if text != '':
+                 self.appendChild(Text(text))
+@@ -381,7 +394,7 @@ class Element(Node):
+             Setting check_grammar=False turns off grammar checking
+         """
+         if check_grammar and self.qname not in grammar.allows_text:
+-            raise IllegalText, "The <%s> element does not allow text" % self.tagName
++            raise IllegalText( "The <%s> element does not allow text" % self.tagName)
+         else:
+             self.appendChild(CDATASection(cdata))
+ 
+@@ -393,12 +406,12 @@ class Element(Node):
+                 prefix, localname = attr
+                 self.removeAttrNS(prefix, localname)
+             else:
+-                raise AttributeError, "Unable to add simple attribute - use (namespace, localpart)"
++                raise AttributeError( "Unable to add simple attribute - use (namespace, localpart)")
+         else:
+             # Construct a list of allowed arguments
+             allowed_args = [ a[1].lower().replace('-','') for a in allowed_attrs]
+             if check_grammar and attr not in allowed_args:
+-                raise AttributeError, "Attribute %s is not allowed in <%s>" % ( attr, self.tagName)
++                raise AttributeError( "Attribute %s is not allowed in <%s>" % ( attr, self.tagName))
+             i = allowed_args.index(attr)
+             self.removeAttrNS(allowed_attrs[i][0], allowed_attrs[i][1])
+ 
+@@ -416,12 +429,12 @@ class Element(Node):
+                 prefix, localname = attr
+                 self.setAttrNS(prefix, localname, value)
+             else:
+-                raise AttributeError, "Unable to add simple attribute - use (namespace, localpart)"
++                raise AttributeError( "Unable to add simple attribute - use (namespace, localpart)")
+         else:
+             # Construct a list of allowed arguments
+             allowed_args = [ a[1].lower().replace('-','') for a in allowed_attrs]
+             if check_grammar and attr not in allowed_args:
+-                raise AttributeError, "Attribute %s is not allowed in <%s>" % ( attr, self.tagName)
++                raise AttributeError( "Attribute %s is not allowed in <%s>" % ( attr, self.tagName))
+             i = allowed_args.index(attr)
+             self.setAttrNS(allowed_attrs[i][0], allowed_attrs[i][1], value)
+ 
+@@ -435,7 +448,7 @@ class Element(Node):
+         allowed_attrs = self.allowed_attributes()
+         prefix = self.get_nsprefix(namespace)
+ #       if allowed_attrs and (namespace, localpart) not in allowed_attrs:
+-#           raise AttributeError, "Attribute %s:%s is not allowed in element <%s>" % ( prefix, localpart, self.tagName)
++#           raise AttributeError( "Attribute %s:%s is not allowed in element <%s>" % ( prefix, localpart, self.tagName))
+         c = AttrConverters()
+         self.attributes[(namespace, localpart)] = c.convert((namespace, localpart), value, self)
+ 
+@@ -455,7 +468,7 @@ class Element(Node):
+                 prefix, localname = attr
+                 return self.getAttrNS(prefix, localname)
+             else:
+-                raise AttributeError, "Unable to get simple attribute - use (namespace, localpart)"
++                raise AttributeError( "Unable to get simple attribute - use (namespace, localpart)")
+         else:
+             # Construct a list of allowed arguments
+             allowed_args = [ a[1].lower().replace('-','') for a in allowed_attrs]
+@@ -469,7 +482,10 @@ class Element(Node):
+                 f.write(' xmlns:' + prefix + '="'+ _escape(str(namespace))+'"')
+         for qname in self.attributes.keys():
+             prefix = self.get_nsprefix(qname[0])
+-            f.write(' '+_escape(str(prefix+':'+qname[1]))+'='+_quoteattr(unicode(self.attributes[qname]).encode('utf-8')))
++            if sys.version_info.major==3:
++                f.write(' '+_escape(str(prefix+':'+qname[1]))+'='+_quoteattr(self.attributes[qname]))
++            else:
++                f.write(' '+_escape(str(prefix+':'+qname[1]))+'='+_quoteattr(unicode(self.attributes[qname]).encode('utf-8')))
+         f.write('>')
+ 
+     def write_close_tag(self, level, f):
+@@ -483,14 +499,17 @@ class Element(Node):
+                 f.write(' xmlns:' + prefix + '="'+ _escape(str(namespace))+'"')
+         for qname in self.attributes.keys():
+             prefix = self.get_nsprefix(qname[0])
+-            f.write(' '+_escape(str(prefix+':'+qname[1]))+'='+_quoteattr(unicode(self.attributes[qname]).encode('utf-8')))
++            if sys.version_info.major==3:
++                f.write(' '+_escape(str(prefix+':'+qname[1]))+'='+_quoteattr(self.attributes[qname]))
++            else:
++                f.write(u' '+_escape(str(prefix+':'+qname[1]))+'='+_quoteattr(unicode(self.attributes[qname])))
+         if self.childNodes:
+-            f.write('>')
++            f.write(u'>')
+             for element in self.childNodes:
+                 element.toXml(level+1,f)
+-            f.write('</'+self.tagName+'>')
++            f.write(u'</'+self.tagName+'>')
+         else:
+-            f.write('/>')
++            f.write(u'/>')
+ 
+     def _getElementsByObj(self, obj, accumulator):
+         if self.qname == obj.qname:
+Index: python-odf-0.9.7/odf/load.py
+===================================================================
+--- python-odf-0.9.7.orig/odf/load.py
++++ python-odf-0.9.7/odf/load.py
+@@ -29,7 +29,10 @@ from xml.sax.xmlreader import InputSourc
+ import xml.sax.saxutils
+ from element import Element
+ from namespaces import OFFICENS
+-from cStringIO import StringIO
++try:
++    from cStringIO import StringIO
++except ImportError:
++    from io import StringIO
+ 
+ #
+ # Parse the XML files
+@@ -74,8 +77,8 @@ class LoadParser(handler.ContentHandler)
+         try:
+             e = Element(qname = tag, qattributes=attrdict, check_grammar=False)
+             self.curr = e
+-        except AttributeError, v:
+-            print "Error: %s" % v
++        except AttributeError as v:
++            print ("Error: %s" % v)
+ 
+         if tag == (OFFICENS, 'automatic-styles'):
+             e = self.doc.automaticstyles
+Index: python-odf-0.9.7/odf/manifest.py
+===================================================================
+--- python-odf-0.9.7.orig/odf/manifest.py
++++ python-odf-0.9.7/odf/manifest.py
+@@ -20,6 +20,9 @@
+ #
+ #
+ 
++import sys, os.path
++sys.path.append(os.path.dirname(__file__))
++
+ from namespaces import MANIFESTNS
+ from element import Element
+ 
+Index: python-odf-0.9.7/odf/odf2xhtml.py
+===================================================================
+--- python-odf-0.9.7.orig/odf/odf2xhtml.py
++++ python-odf-0.9.7/odf/odf2xhtml.py
+@@ -20,13 +20,15 @@
+ #
+ #import pdb
+ #pdb.set_trace()
++from __future__ import absolute_import
++import sys
+ from xml.sax import handler
+ from xml.sax.saxutils import escape, quoteattr
+ from xml.dom import Node
+ 
+-from opendocument import load
++from .opendocument import load
+ 
+-from namespaces import ANIMNS, CHARTNS, CONFIGNS, DCNS, DR3DNS, DRAWNS, FONS, \
++from .namespaces import ANIMNS, CHARTNS, CONFIGNS, DCNS, DR3DNS, DRAWNS, FONS, \
+   FORMNS, MATHNS, METANS, NUMBERNS, OFFICENS, PRESENTATIONNS, SCRIPTNS, \
+   SMILNS, STYLENS, SVGNS, TABLENS, TEXTNS, XLINKNS
+ 
+@@ -215,7 +217,7 @@ class StyleToCSS:
+                 sdict['right'] = "0";
+             else: # No wrapping
+                 sdict['margin-left'] = "auto"
+-                sdict['margin-right'] = "0px"
++                sdict['margin-right'] = "0cm"
+         elif hpos in ("left", "inside"):
+             if wrap in ( "right", "parallel","dynamic"):
+                 sdict['float'] = "left"
+@@ -224,14 +226,14 @@ class StyleToCSS:
+                 sdict['top'] = "0"
+                 sdict['left'] = "0"
+             else: # No wrapping
+-                sdict['margin-left'] = "0px"
++                sdict['margin-left'] = "0cm"
+                 sdict['margin-right'] = "auto"
+         elif hpos in ("from-left", "from-inside"):
+             if wrap in ( "right", "parallel"):
+                 sdict['float'] = "left"
+             else:
+                 sdict['position'] = "relative" # No wrapping
+-                if ruleset.has_key( (SVGNS,'x') ):
++                if (SVGNS,'x') in ruleset:
+                     sdict['left'] = ruleset[(SVGNS,'x')]
+ 
+     def c_page_width(self, ruleset, sdict, rule, val):
+@@ -291,7 +293,7 @@ class TagStack:
+     def rfindattr(self, attr):
+         """ Find a tag with the given attribute """
+         for tag, attrs in self.stack:
+-            if attrs.has_key(attr):
++            if attr in attrs:
+                 return attrs[attr]
+         return None
+     def count_tags(self, tag):
+@@ -590,7 +592,7 @@ class ODF2XHTML(handler.ContentHandler):
+ 
+     def get_anchor(self, name):
+         """ Create a unique anchor id for a href name """
+-        if not self.anchors.has_key(name):
++        if name not in self.anchors:
+             self.anchors[name] = "anchor%03d" % (len(self.anchors) + 1)
+         return self.anchors.get(name)
+ 
+@@ -650,13 +652,13 @@ class ODF2XHTML(handler.ContentHandler):
+             style = ''
+         else:
+             style = "position: absolute;"
+-        if attrs.has_key( (SVGNS,"width") ):
++        if (SVGNS,"width")in attrs:
+             style = style + "width:" + attrs[(SVGNS,"width")] + ";"
+-        if attrs.has_key( (SVGNS,"height") ):
++        if (SVGNS,"height") in attrs:
+             style = style + "height:" +  attrs[(SVGNS,"height")] + ";"
+-        if attrs.has_key( (SVGNS,"x") ):
++        if (SVGNS,"x") in attrs:
+             style = style + "left:" +  attrs[(SVGNS,"x")] + ";"
+-        if attrs.has_key( (SVGNS,"y") ):
++        if (SVGNS,"y") in attrs:
+             style = style + "top:" +  attrs[(SVGNS,"y")] + ";"
+         if self.generate_css:
+             self.opentag(htmltag, {'class': name, 'style': style})
+@@ -686,13 +688,13 @@ class ODF2XHTML(handler.ContentHandler):
+             style = ''
+         else:
+             style = "position:absolute;"
+-        if attrs.has_key( (SVGNS,"width") ):
++        if (SVGNS,"width") in attrs:
+             style = style + "width:" + attrs[(SVGNS,"width")] + ";"
+-        if attrs.has_key( (SVGNS,"height") ):
++        if (SVGNS,"height") in attrs:
+             style = style + "height:" +  attrs[(SVGNS,"height")] + ";"
+-        if attrs.has_key( (SVGNS,"x") ):
++        if (SVGNS,"x") in attrs:
+             style = style + "left:" +  attrs[(SVGNS,"x")] + ";"
+-        if attrs.has_key( (SVGNS,"y") ):
++        if (SVGNS,"y") in attrs:
+             style = style + "top:" +  attrs[(SVGNS,"y")] + ";"
+         if self.generate_css:
+             self.opentag(htmltag, {'class': name, 'style': style})
+@@ -775,7 +777,7 @@ class ODF2XHTML(handler.ContentHandler):
+ 
+     def s_draw_textbox(self, tag, attrs):
+         style = ''
+-        if attrs.has_key( (FONS,"min-height") ):
++        if (FONS,"min-height") in attrs:
+             style = style + "min-height:" +  attrs[(FONS,"min-height")] + ";"
+         self.opentag('div')
+ #       self.opentag('div', {'style': style})
+@@ -808,14 +810,14 @@ ol, ul { padding-left: 2em; }
+         for name in self.stylestack:
+             styles = self.styledict.get(name)
+             # Preload with the family's default style
+-            if styles.has_key('__style-family') and self.styledict.has_key(styles['__style-family']):
++            if '__style-family'in styles and styles['__style-family'] in self.styledict:
+                 familystyle = self.styledict[styles['__style-family']].copy()
+                 del styles['__style-family']
+                 for style, val in styles.items():
+                     familystyle[style] = val
+                 styles = familystyle
+             # Resolve the remaining parent styles
+-            while styles.has_key('__parent-style-name') and self.styledict.has_key(styles['__parent-style-name']):
++            while '__parent-style-name' in styles and styles['__parent-style-name'] in self.styledict:
+                 parentstyle = self.styledict[styles['__parent-style-name']].copy()
+                 del styles['__parent-style-name']
+                 for style, val in styles.items():
+@@ -1007,7 +1009,7 @@ ol, ul { padding-left: 2em; }
+         pagelayout = attrs.get( (STYLENS,'page-layout-name'), None)
+         if pagelayout:
+             pagelayout = ".PL-" + pagelayout
+-            if self.styledict.has_key( pagelayout ):
++            if pagelayout in self.styledict:
+                 styles = self.styledict[pagelayout]
+                 for style, val in styles.items():
+                     self.styledict[self.currentstyle][style] = val
+@@ -1037,7 +1039,7 @@ ol, ul { padding-left: 2em; }
+         parent = attrs.get( (STYLENS,'parent-style-name') )
+         self.currentstyle = special_styles.get(name,"."+name)
+         self.stylestack.append(self.currentstyle)
+-        if not self.styledict.has_key(self.currentstyle):
++        if self.currentstyle not in self.styledict:
+             self.styledict[self.currentstyle] = {}
+ 
+         self.styledict[self.currentstyle]['__style-family'] = htmlfamily
+@@ -1046,7 +1048,7 @@ ol, ul { padding-left: 2em; }
+         if parent:
+             parent = "%s-%s" % (sfamily, parent)
+             parent = special_styles.get(parent, "."+parent)
+-            if self.styledict.has_key( parent ):
++            if parent in self.styledict:
+                 styles = self.styledict[parent]
+                 for style, val in styles.items():
+                     self.styledict[self.currentstyle][style] = val
+@@ -1107,7 +1109,7 @@ ol, ul { padding-left: 2em; }
+         htmlattrs = {}
+         if c:
+             htmlattrs['class'] = "TC-%s" % c.replace(".","_")
+-        for x in xrange(repeated):
++        for x in range(repeated):
+             self.emptytag('col', htmlattrs)
+         self.purgedata()
+ 
+@@ -1324,7 +1326,10 @@ ol, ul { padding-left: 2em; }
+ #        self.writeout( escape(mark) )
+         # Since HTML only knows about endnotes, there is too much risk that the
+         # marker is reused in the source. Therefore we force numeric markers
+-        self.writeout(unicode(self.currentnote))
++        if sys.version_info.major==3:
++            self.writeout(self.currentnote)
++        else:
++            self.writeout(unicode(self.currentnote))
+         self.closetag('sup')
+         self.closetag('a')
+ 
+@@ -1363,7 +1368,7 @@ ol, ul { padding-left: 2em; }
+             We use   so we can send the output through an XML parser if we desire to
+         """
+         c = attrs.get( (TEXTNS,'c'),"1")
+-        for x in xrange(int(c)):
++        for x in range(int(c)):
+             self.writeout(' ')
+ 
+     def s_text_span(self, tag, attrs):
+@@ -1420,6 +1425,10 @@ ol, ul { padding-left: 2em; }
+         """
+         self.lines = []
+         self._wfunc = self._wlines
++        try:
++            basestring
++        except NameError:
++            basestring = str
+         if isinstance(odffile, basestring):
+             self.document = load(odffile)
+         else:
+@@ -1433,7 +1442,10 @@ ol, ul { padding-left: 2em; }
+                 self._walknode(c)
+             self.endElementNS(node.qname, node.tagName)
+         if node.nodeType == Node.TEXT_NODE or node.nodeType == Node.CDATA_SECTION_NODE:
+-            self.characters(unicode(node))
++            if sys.version_info.major==3:
++                self.characters(str(node))
++            else:
++                self.characters(unicode(node))
+ 
+ 
+     def odf2xhtml(self, odffile):
+Index: python-odf-0.9.7/odf/odfmanifest.py
+===================================================================
+--- python-odf-0.9.7.orig/odf/odfmanifest.py
++++ python-odf-0.9.7/odf/odfmanifest.py
+@@ -18,13 +18,16 @@
+ #
+ # Contributor(s):
+ #
+-
++from __future__ import print_function
+ # This script lists the content of the manifest.xml file
+ import zipfile
+ from xml.sax import make_parser,handler
+ from xml.sax.xmlreader import InputSource
+ import xml.sax.saxutils
+-from cStringIO import StringIO
++try:
++    from cStringIO import StringIO
++except ImportError:
++    from io import StringIO
+ 
+ MANIFESTNS="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"
+ 
+@@ -96,6 +99,8 @@ def manifestlist(manifestxml):
+     parser.setErrorHandler(handler.ErrorHandler())
+ 
+     inpsrc = InputSource()
++    if not isinstance(manifestxml, str):
++        manifestxml=manifestxml.decode("utf-8")
+     inpsrc.setByteStream(StringIO(manifestxml))
+     parser.parse(inpsrc)
+ 
+@@ -111,5 +116,5 @@ if __name__ == "__main__":
+     import sys
+     result = odfmanifest(sys.argv[1])
+     for file in result.values():
+-        print "%-40s %-40s" % (file['media-type'], file['full-path'])
++        print ("%-40s %-40s" % (file['media-type'], file['full-path']))
+ 
+Index: python-odf-0.9.7/odf/opendocument.py
+===================================================================
+--- python-odf-0.9.7.orig/odf/opendocument.py
++++ python-odf-0.9.7/odf/opendocument.py
+@@ -17,24 +17,34 @@
+ #
+ # Contributor(s):
+ #
++from __future__ import absolute_import
+ 
+ __doc__="""Use OpenDocument to generate your documents."""
+ 
+-import zipfile, time, sys, mimetypes, copy
+-from cStringIO import StringIO
+-from namespaces import *
+-import manifest, meta
+-from office import *
++import zipfile, time, sys, mimetypes, copy, os.path
++sys.path.append(os.path.dirname(__file__))
++
++try:
++    from cStringIO import StringIO
++except ImportError:
++    from io import StringIO
++from .namespaces import *
++import manifest
++import meta
++from .office import *
+ import element
+-from attrconverters import make_NCName
++from .attrconverters import make_NCName
+ from xml.sax.xmlreader import InputSource
+-from odfmanifest import manifestlist
++from .odfmanifest import manifestlist
+ 
+ __version__= TOOLSVERSION
+ 
+ _XMLPROLOGUE = u"<?xml version='1.0' encoding='UTF-8'?>\n"
+ 
+-UNIXPERMS = 0100644 << 16L  # -rw-r--r--
++########### the following syntax is invalid for Python3 ##############
++# UNIXPERMS = 0100644 << 16L  # -rw-r--r--
++######################################################################
++UNIXPERMS = 2175008768 # same value as 0100644 << 16L == -rw-r--r--
+ 
+ IS_FILENAME = 0
+ IS_IMAGE = 1
+@@ -124,13 +134,13 @@ class OpenDocument:
+     def build_caches(self, element):
+         """ Called from element.py
+         """
+-        if not self.element_dict.has_key(element.qname):
++        if element.qname not in self.element_dict:
+             self.element_dict[element.qname] = []
+         self.element_dict[element.qname].append(element)
+         if element.qname == (STYLENS, u'style'):
+             self.__register_stylename(element) # Add to style dictionary
+         styleref = element.getAttrNS(TEXTNS,u'style-name')
+-        if styleref is not None and self._styles_ooo_fix.has_key(styleref):
++        if styleref is not None and styleref in self._styles_ooo_fix:
+             element.setAttrNS(TEXTNS,u'style-name', self._styles_ooo_fix[styleref])
+ 
+     def __register_stylename(self, element):
+@@ -142,7 +152,7 @@ class OpenDocument:
+         if name is None:
+             return
+         if element.parentNode.qname in ((OFFICENS,u'styles'), (OFFICENS,u'automatic-styles')):
+-            if self._styles_dict.has_key(name):
++            if name in self._styles_dict:
+                 newname = 'M'+name # Rename style
+                 self._styles_ooo_fix[name] = newname
+                 # From here on all references to the old name will refer to the new one
+@@ -421,7 +431,7 @@ class OpenDocument:
+         zi = zipfile.ZipInfo('mimetype', self._now)
+         zi.compress_type = zipfile.ZIP_STORED
+         zi.external_attr = UNIXPERMS
+-        self._z.writestr(zi, self.mimetype)
++        self._z.writestr(zi, self.mimetype.encode("utf-8"))
+ 
+         self._saveXmlObjects(self,"")
+ 
+@@ -441,7 +451,10 @@ class OpenDocument:
+         for op in self._extra:
+             if op.filename == "META-INF/documentsignatures.xml": continue # Don't save signatures
+             self.manifest.addElement(manifest.FileEntry(fullpath=op.filename, mediatype=op.mediatype))
+-            zi = zipfile.ZipInfo(op.filename.encode('utf-8'), self._now)
++            if sys.version_info.major==3:
++                zi = zipfile.ZipInfo(op.filename, self._now)
++            else:
++                zi = zipfile.ZipInfo(op.filename.encode('utf-8'), self._now)
+             zi.compress_type = zipfile.ZIP_DEFLATED
+             zi.external_attr = UNIXPERMS
+             if op.content is not None:
+@@ -585,7 +598,7 @@ def __loadxmlparts(z, manifest, doc, obj
+     from xml.sax import make_parser, handler
+ 
+     for xmlfile in (objectpath+'settings.xml', objectpath+'meta.xml', objectpath+'content.xml', objectpath+'styles.xml'):
+-        if not manifest.has_key(xmlfile):
++        if xmlfile not in manifest:
+             continue
+         try:
+             xmlpart = z.read(xmlfile)
+@@ -597,10 +610,12 @@ def __loadxmlparts(z, manifest, doc, obj
+             parser.setErrorHandler(handler.ErrorHandler())
+ 
+             inpsrc = InputSource()
++            if not isinstance(xmlpart, str):
++                xmlpart=xmlpart.decode("utf-8")
+             inpsrc.setByteStream(StringIO(xmlpart))
+             parser.parse(inpsrc)
+             del doc._parsing
+-        except KeyError, v: pass
++        except KeyError as v: pass
+ 
+ def load(odffile):
+     """ Load an ODF file into memory
+Index: python-odf-0.9.7/odf/text.py
+===================================================================
+--- python-odf-0.9.7.orig/odf/text.py
++++ python-odf-0.9.7/odf/text.py
+@@ -17,10 +17,11 @@
+ #
+ # Contributor(s):
+ #
++from __future__ import absolute_import
+ 
+-from namespaces import TEXTNS
+-from element import Element
+-from style import StyleElement
++from .namespaces import TEXTNS
++from .element import Element
++from .style import StyleElement
+ 
+ # Autogenerated
+ def A(**args):
+Index: python-odf-0.9.7/odf/userfield.py
+===================================================================
+--- python-odf-0.9.7.orig/odf/userfield.py
++++ python-odf-0.9.7/odf/userfield.py
+@@ -27,6 +27,7 @@ import zipfile
+ from odf.text import UserFieldDecl
+ from odf.namespaces import OFFICENS
+ from odf.opendocument import load
++import io
+ 
+ OUTENCODING = "utf-8"
+ 
+@@ -62,7 +63,7 @@ class UserFields(object):
+         self.document = None
+ 
+     def loaddoc(self):
+-        if isinstance(self.src_file, basestring):
++        if (sys.version_info.major==3 and (isinstance(self.src_file, str) or (isinstance(self.src_file, io.IOBase)))) or (sys.version_info.major==2 and isinstance(self.src_file, basestring)):
+             # src_file is a filename, check if it is a zip-file
+             if not zipfile.is_zipfile(self.src_file):
+                 raise TypeError("%s is no odt file." % self.src_file)
+@@ -158,7 +159,7 @@ class UserFields(object):
+         all_fields = self.document.getElementsByType(UserFieldDecl)
+         for f in all_fields:
+             field_name = f.getAttribute('name')
+-            if data.has_key(field_name):
++            if field_name in data:
+                 value_type = f.getAttribute('valuetype')
+                 value = data.get(field_name)
+                 if value_type == 'string':
+Index: python-odf-0.9.7/odf/chart.py
+===================================================================
+--- python-odf-0.9.7.orig/odf/chart.py
++++ python-odf-0.9.7/odf/chart.py
+@@ -17,9 +17,9 @@
+ #
+ # Contributor(s):
+ #
+-
+-from namespaces import CHARTNS
+-from element import Element
++from __future__ import absolute_import
++from .namespaces import CHARTNS
++from .element import Element
+ 
+ # Autogenerated
+ def Axis(**args):
+Index: python-odf-0.9.7/odf/grammar.py
+===================================================================
+--- python-odf-0.9.7.orig/odf/grammar.py
++++ python-odf-0.9.7/odf/grammar.py
+@@ -22,7 +22,8 @@ __doc__=""" In principle the OpenDocumen
+ Currently it contains the legal child elements of a given element.
+ To be used for validation check in the API
+ """
+-
++import sys, os.path
++sys.path.append(os.path.dirname(__file__))
+ from namespaces import *
+ 
+ # The following code is generated from the RelaxNG schema with this notice:
+Index: python-odf-0.9.7/odf/style.py
+===================================================================
+--- python-odf-0.9.7.orig/odf/style.py
++++ python-odf-0.9.7/odf/style.py
+@@ -24,7 +24,7 @@ from element import Element
+ def StyleElement(**args):
+     e = Element(**args)
+     if args.get('check_grammar', True) == True:
+-        if not args.has_key('displayname'):
++        if 'displayname' not in args:
+             e.setAttrNS(STYLENS,'display-name', args.get('name'))
+     return e
+ 
+Index: python-odf-0.9.7/odf/dr3d.py
+===================================================================
+--- python-odf-0.9.7.orig/odf/dr3d.py
++++ python-odf-0.9.7/odf/dr3d.py
+@@ -17,6 +17,8 @@
+ #
+ # Contributor(s):
+ #
++import sys, os.path
++sys.path.append(os.path.dirname(__file__))
+ 
+ from namespaces import DR3DNS
+ from element import Element
+Index: python-odf-0.9.7/tests/obsoleted_testunicode.py
+===================================================================
+--- /dev/null
++++ python-odf-0.9.7/tests/obsoleted_testunicode.py
+@@ -0,0 +1,70 @@
++#!/usr/bin/env python
++# -*- coding: utf-8 -*-
++# Copyright (C) 2007 Søren Roug, European Environment Agency
++#
++# This is free software.  You may redistribute it under the terms
++# of the Apache license and the GNU General Public License Version
++# 2 or at your option any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public
++# License along with this program; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++#
++# Contributor(s):
++#
++
++import unittest, os
++from odf.opendocument import OpenDocumentText
++from odf import style, text
++from odf.text import P, H
++from odf.element import IllegalChild
++
++class TestUnicode(unittest.TestCase):
++
++    def setUp(self):
++        self.textdoc = OpenDocumentText()
++        self.saved = False
++
++    def tearDown(self):
++        if self.saved:
++            os.unlink("TEST.odt")
++
++    def assertContains(self, stack, needle):
++        self.assertNotEqual(-1, stack.find(needle))
++
++    def assertNotContains(self, stack, needle):
++        self.assertEquals(-1, stack.find(needle))
++
++    def test_xstyle(self):
++        self.assertRaises(UnicodeDecodeError, style.Style, name="X✗", family="paragraph")
++        xstyle = style.Style(name=u"X✗", family="paragraph")
++        pp = style.ParagraphProperties(padding="0.2cm")
++        pp.setAttribute("backgroundcolor", u"rød")
++        xstyle.addElement(pp)
++        self.textdoc.styles.addElement(xstyle)
++        self.textdoc.save("TEST.odt")
++        self.saved = True
++
++    def test_text(self):
++        p = P(text=u"Æblegrød")
++        p.addText(u' Blåbærgrød')
++        self.textdoc.text.addElement(p)
++        self.textdoc.save("TEST.odt")
++        self.saved = True
++
++    def test_contenttext(self):
++        p = H(outlinelevel=1,text=u"Æblegrød")
++        p.addText(u' Blåbærgrød')
++        self.textdoc.text.addElement(p)
++        c = unicode(self.textdoc.contentxml(),'UTF-8')
++        self.assertContains(c, u'<office:body><office:text><text:h text:outline-level="1">\xc6blegr\xf8d Bl\xe5b\xe6rgr\xf8d</text:h></office:text></office:body>')
++        self.assertContains(c, u'xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"')
++        self.assertContains(c, u'<office:automatic-styles/>')
++
++if __name__ == '__main__':
++    unittest.main()
+Index: python-odf-0.9.7/tests/testunicode.py
+===================================================================
+--- python-odf-0.9.7.orig/tests/testunicode.py
++++ /dev/null
+@@ -1,70 +0,0 @@
+-#!/usr/bin/env python
+-# -*- coding: utf-8 -*-
+-# Copyright (C) 2007 Søren Roug, European Environment Agency
+-#
+-# This is free software.  You may redistribute it under the terms
+-# of the Apache license and the GNU General Public License Version
+-# 2 or at your option any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public
+-# License along with this program; if not, write to the Free Software
+-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+-#
+-# Contributor(s):
+-#
+-
+-import unittest, os
+-from odf.opendocument import OpenDocumentText
+-from odf import style, text
+-from odf.text import P, H
+-from odf.element import IllegalChild
+-
+-class TestUnicode(unittest.TestCase):
+-    
+-    def setUp(self):
+-        self.textdoc = OpenDocumentText()
+-        self.saved = False
+-
+-    def tearDown(self):
+-        if self.saved:
+-            os.unlink("TEST.odt")
+-
+-    def assertContains(self, stack, needle):
+-        self.assertNotEqual(-1, stack.find(needle))
+-
+-    def assertNotContains(self, stack, needle):
+-        self.assertEquals(-1, stack.find(needle))
+-
+-    def test_xstyle(self):
+-        self.assertRaises(UnicodeDecodeError, style.Style, name="X✗", family="paragraph")
+-        xstyle = style.Style(name=u"X✗", family="paragraph")
+-        pp = style.ParagraphProperties(padding="0.2cm")
+-        pp.setAttribute("backgroundcolor", u"rød")
+-        xstyle.addElement(pp)
+-        self.textdoc.styles.addElement(xstyle)
+-        self.textdoc.save("TEST.odt")
+-        self.saved = True
+-
+-    def test_text(self):
+-        p = P(text=u"Æblegrød")
+-        p.addText(u' Blåbærgrød')
+-        self.textdoc.text.addElement(p)
+-        self.textdoc.save("TEST.odt")
+-        self.saved = True
+-
+-    def test_contenttext(self):
+-        p = H(outlinelevel=1,text=u"Æblegrød")
+-        p.addText(u' Blåbærgrød')
+-        self.textdoc.text.addElement(p)
+-        c = unicode(self.textdoc.contentxml(),'UTF-8')
+-        self.assertContains(c, u'<office:body><office:text><text:h text:outline-level="1">\xc6blegr\xf8d Bl\xe5b\xe6rgr\xf8d</text:h></office:text></office:body>')
+-        self.assertContains(c, u'xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"')
+-        self.assertContains(c, u'<office:automatic-styles/>')
+-
+-if __name__ == '__main__':
+-    unittest.main()

Added: packages/python-odf/trunk/debian/patches/series
===================================================================
--- packages/python-odf/trunk/debian/patches/series	                        (rev 0)
+++ packages/python-odf/trunk/debian/patches/series	2014-10-21 09:54:57 UTC (rev 31190)
@@ -0,0 +1,2 @@
+toPython3.patch
+libsToPython3.patch

Added: packages/python-odf/trunk/debian/patches/toPython3.patch
===================================================================
--- packages/python-odf/trunk/debian/patches/toPython3.patch	                        (rev 0)
+++ packages/python-odf/trunk/debian/patches/toPython3.patch	2014-10-21 09:54:57 UTC (rev 31190)
@@ -0,0 +1,1056 @@
+Index: python-odf-0.9.7/odfoutline/odfoutline
+===================================================================
+--- python-odf-0.9.7.orig/odfoutline/odfoutline
++++ python-odf-0.9.7/odfoutline/odfoutline
+@@ -17,6 +17,7 @@
+ #
+ # Contributor(s):
+ #
++from __future__ import print_function
+ import zipfile
+ from xml.sax import make_parser,handler
+ from xml.sax.xmlreader import InputSource
+@@ -27,7 +28,7 @@ from odf.namespaces import TEXTNS, TABLE
+ try:
+     from cStringIO import StringIO
+ except ImportError:
+-    from StringIO import StringIO
++    from io import StringIO
+ 
+ 
+ def getxmlpart(odffile, xmlfile):
+@@ -107,6 +108,8 @@ def odtheadings(odtfile):
+     lines = []
+     parser = make_parser()
+     parser.setFeature(handler.feature_namespaces, 1)
++    if not isinstance(mimetype, str):
++        mimetype=mimetype.decode("utf-8")
+     if mimetype in ('application/vnd.oasis.opendocument.text',
+       'application/vnd.oasis.opendocument.text-template'):
+         parser.setContentHandler(ODTHeadingHandler(lines))
+@@ -117,11 +120,13 @@ def odtheadings(odtfile):
+       'application/vnd.oasis.opendocument.presentation-template'):
+         parser.setContentHandler(ODTSlideHandler(lines))
+     else:
+-        print "Unsupported fileformat"
++        print ("Unsupported fileformat")
+         sys.exit(2)
+     parser.setErrorHandler(handler.ErrorHandler())
+ 
+     inpsrc = InputSource()
++    if not isinstance(content, str):
++        content=content.decode("utf-8")
+     inpsrc.setByteStream(StringIO(content))
+     parser.parse(inpsrc)
+     return lines
+@@ -130,5 +135,5 @@ def odtheadings(odtfile):
+ if __name__ == "__main__":
+     filler = "          "
+     for heading in odtheadings(sys.argv[1]):
+-        print heading
++        print (heading)
+ 
+Index: python-odf-0.9.7/odf2mht/odf2mht
+===================================================================
+--- python-odf-0.9.7.orig/odf2mht/odf2mht
++++ python-odf-0.9.7/odf2mht/odf2mht
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python
++#!/usr/bin/python3
+ # -*- coding: utf-8 -*-
+ # Copyright (C) 2006 Søren Roug, European Environment Agency
+ #
+@@ -17,15 +17,28 @@
+ #
+ # Contributor(s):
+ #
++from __future__ import print_function
+ from odf.odf2xhtml import ODF2XHTML
+ import zipfile
+ import sys
+ #from time import gmtime, strftime
+ 
+-from email.MIMEMultipart import MIMEMultipart
+-from email.MIMENonMultipart import MIMENonMultipart
+-from email.MIMEText import MIMEText
+-from email import Encoders
++try:
++    from email.MIMEMultipart import MIMEMultipart
++except ImportError:
++    from email.mime.multipart import MIMEMultipart
++try:
++    from email.MIMENonMultipart import MIMENonMultipart
++except ImportError:
++    from email.mime.nonmultipart import MIMENonMultipart
++try:
++    from email.MIMEText import MIMEText
++except ImportError:
++    from email.mime.text import MIMEText
++try:
++    from email import Encoders
++except ImportError:
++    from email import encoders
+ 
+ if len(sys.argv) != 2:
+     sys.stderr.write("Usage: %s inputfile\n" % sys.argv[0])
+@@ -61,4 +74,4 @@ for file in z.namelist():
+         Encoders.encode_base64(img)
+         msg.attach(img)
+ z.close()
+-print msg.as_string()
++print (msg.as_string())
+Index: python-odf-0.9.7/odfimgimport/odfimgimport
+===================================================================
+--- python-odf-0.9.7.orig/odfimgimport/odfimgimport
++++ python-odf-0.9.7/odfimgimport/odfimgimport
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python
++#!/usr/bin/python3
+ # -*- coding: utf-8 -*-
+ # Copyright (C) 2007-2009 Søren Roug, European Environment Agency
+ #
+@@ -18,11 +18,16 @@
+ # Contributor(s):
+ #
+ import zipfile, sys, getopt, mimetypes
+-from urllib2 import urlopen, quote, unquote
+-from urlparse import urlunsplit, urlsplit
++try:
++    from urllib2 import urlopen, quote, unquote
++except ImportError:
++    from urllib.request import urlopen, quote, unquote
++try:
++    from urlparse import urlunsplit, urlsplit
++except ImportError:
++    from urllib.parse import urlunsplit, urlsplit
+ from odf.opendocument import load
+ from odf.draw import Image
+-import cStringIO
+ 
+ sys.tracebacklimit = 0
+ 
+@@ -49,7 +54,7 @@ def importpicture(href):
+     global doc, newpictures, failures, verbose
+ 
+     # Check that it is not already in the manifest
+-    if doc.Pictures.has_key(href): return href
++    if href in doc.Pictures: return href
+ 
+     image = None
+     if verbose: print >>sys.stderr, "Importing", href,
+@@ -62,7 +67,7 @@ def importpicture(href):
+             o = list(urlsplit(href))
+             o[2] = quote(o[2].encode('utf-8'))
+             goodhref = urlunsplit(o)
+-        if newpictures.has_key(goodhref):
++        if goodhref in newpictures:
+             if verbose: print >>sys.stderr, "already imported"
+             return newpictures[goodhref]  # Already imported
+         try:
+@@ -93,7 +98,7 @@ def importpicture(href):
+                 goodhref = unquote(href[3:])
+             else:
+                 goodhref = unquote(directory + href[2:])
+-        if newpictures.has_key(goodhref):
++        if goodhref in newpictures:
+             if verbose: print >>sys.stderr, "already imported"
+             return newpictures[goodhref]  # Already imported
+         mediatype, encoding = mimetypes.guess_type(goodhref)
+Index: python-odf-0.9.7/odflint/odflint
+===================================================================
+--- python-odf-0.9.7.orig/odflint/odflint
++++ python-odf-0.9.7/odflint/odflint
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python
++#!/usr/bin/python3
+ # -*- coding: utf-8 -*-
+ # Copyright (C) 2009 Søren Roug, European Environment Agency
+ #
+@@ -30,7 +30,7 @@ from odf.attrconverters import attrconve
+ try:
+     from cStringIO import StringIO
+ except ImportError:
+-    from StringIO import StringIO
++    from io import StringIO
+ 
+ 
+ extension_attributes = {
+@@ -97,7 +97,7 @@ printed_errors = []
+ def print_error(str):
+     if str not in printed_errors:
+         printed_errors.append(str)
+-        print str
++        print (str)
+ 
+ def chop_arg(arg):
+     if len(arg) > 20:
+@@ -131,7 +131,7 @@ class ODFElementHandler(handler.ContentH
+             prefix = nsdict.get(att[0],att[0])
+             # Check if it is a known extension
+             notan_extension = True
+-	    for product, ext_attrs in extension_attributes.items():
++            for product, ext_attrs in extension_attributes.items():
+                 allowed_ext_attrs = ext_attrs.get(tag)
+                 if allowed_ext_attrs and att in allowed_ext_attrs:
+                     print_error("Warning: Attribute %s in element <%s> is illegal - %s extension"  % ( make_qname(att), make_qname(tag), product))
+@@ -143,7 +143,7 @@ class ODFElementHandler(handler.ContentH
+             try:
+                 convert = attrconverters.get(att, cnv_string)
+                 convert(att, value, tag)
+-            except ValueError, res:
++            except ValueError as res:
+                 print_error("Error: Bad value '%s' for attribute %s:%s in  tag: <%s> - %s" % 
+                     (chop_arg(value), prefix, att[1], make_qname(tag), res))
+ 
+@@ -222,6 +222,8 @@ def lint(odffile):
+             parser.setErrorHandler(handler.ErrorHandler())
+ 
+             inpsrc = InputSource()
++            if not isinstance(content, str):
++                content=content.decode("utf-8")
+             inpsrc.setByteStream(StringIO(content))
+             parser.parse(inpsrc)
+ 
+Index: python-odf-0.9.7/odfmeta/odfmeta
+===================================================================
+--- python-odf-0.9.7.orig/odfmeta/odfmeta
++++ python-odf-0.9.7/odfmeta/odfmeta
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python
++#!/usr/bin/python3
+ # -*- coding: utf-8 -*-
+ # Copyright (C) 2006-2009 Søren Roug, European Environment Agency
+ #
+@@ -23,7 +23,7 @@ from odf.namespaces import TOOLSVERSION,
+ try:
+     from cStringIO import StringIO
+ except ImportError:
+-    from StringIO import StringIO
++    from io import StringIO
+ OUTENCODING="utf-8"
+ 
+ whitespace = re.compile(r'\s+')
+@@ -111,9 +111,9 @@ class odfmetaparser(base):
+ #           self._data = [attrs.get((XLINKNS,u'title'),'')]
+         if showversion and name == (OFFICENS,u'document-meta'):
+             if showversion == '-V':
+-                print "version:%s" % attrs.get((OFFICENS,u'version'),'Unknown')
++                print ("version:%s" % attrs.get((OFFICENS,u'version'),'Unknown').decode('utf-8'))
+             else:
+-                print "%s" % attrs.get((OFFICENS,u'version'),'Unknown')
++                print ("%s" % attrs.get((OFFICENS,u'version'),'Unknown').decode('utf-8'))
+         if name == (METANS,u'user-defined'):
+             field = attrs.get((METANS,u'name'))
+         if field in deletefields:
+@@ -141,13 +141,13 @@ class odfmetaparser(base):
+                         base.characters(self, v)
+                         base.endElementNS(self, k, None)
+         if name in xfields:
+-                print "%s" % self.data()
++                print ("%s" % self.data())
+         if name in Xfields:
+             if isinstance(self._tag, tuple):
+                 texttag = self._tag[1]
+             else:
+                 texttag = self._tag
+-            print "%s:%s" % (texttag.encode(OUTENCODING), self.data())
++            print ("%s:%s" % (texttag, self.data()))
+         if field in deletefields:
+             self.output.dowrite = True
+         else:
+@@ -162,9 +162,9 @@ class odfmetaparser(base):
+ 
+     def data(self):
+         if usenormalize:
+-            return normalize(''.join(self._data)).encode(OUTENCODING)
++            return normalize(''.join(self._data))
+         else:
+-            return ''.join(self._data).encode(OUTENCODING)
++            return ''.join(self._data)
+ 
+ now = time.localtime()[:6]
+ outputfile = "-"
+@@ -229,7 +229,7 @@ else:
+         exitwithusage()
+     zin = zipfile.ZipFile(args[0], 'r')
+ 
+-content = zin.read('meta.xml')
++content = zin.read('meta.xml').decode('utf-8')
+ parser.parse(StringIO(content))
+ 
+ if writemeta:
+Index: python-odf-0.9.7/odfuserfield/odfuserfield
+===================================================================
+--- python-odf-0.9.7.orig/odfuserfield/odfuserfield
++++ python-odf-0.9.7/odfuserfield/odfuserfield
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python
++#!/usr/bin/python3
+ # -*- coding: utf-8 -*-
+ # Copyright (C) 2006-2007 Søren Roug, European Environment Agency
+ #
+@@ -77,18 +77,18 @@ user_fields = odf.userfield.UserFields(i
+ 
+ if xfields:
+     for value in user_fields.list_values(xfields):
+-        print value
++        print (value)
+ 
+ if Listfields or Xfields:
+     if Listfields:
+         Xfields = None
+     for field_name, value_type, value in user_fields.list_fields_and_values(
+         Xfields):
+-        print "%s#%s:%s" % (field_name, value_type, value)
++        print ("%s#%s:%s" % (field_name, value_type, value))
+     
+ if listfields:
+     for value in user_fields.list_fields():
+-        print value
++        print (value)
+ 
+ if setfields:
+     user_fields.update(setfields)
+Index: python-odf-0.9.7/tests/runtests
+===================================================================
+--- python-odf-0.9.7.orig/tests/runtests
++++ python-odf-0.9.7/tests/runtests
+@@ -1,5 +1,6 @@
+ #!/bin/sh
+ for file in test*.py
+ do
+-    python $file
++    python  $file
++    python3 $file
+ done
+Index: python-odf-0.9.7/tests/testconverters.py
+===================================================================
+--- python-odf-0.9.7.orig/tests/testconverters.py
++++ python-odf-0.9.7/tests/testconverters.py
+@@ -44,28 +44,28 @@ class TestConverters(unittest.TestCase):
+                 for attr in attrs:
+                     self.allattrs[attr] = 1
+                     self.allqattrs[(attr, element)] = 1
+-                    self.assertEquals(attr, findconv(attr, element))
++                    self.assertEqual(attr, findconv(attr, element))
+         for (attr,elem) in attrconverters.attrconverters.keys():
+             if attr == (OFFICENS,u'process-content'):  # Special attribute
+                 continue
+             if elem is None:
+-                self.assertEquals(self.allattrs[attr], 1)
++                self.assertEqual(self.allattrs[attr], 1)
+             else:
+-                self.assertEquals(self.allqattrs[(attr, elem)], 1)
++                self.assertEqual(self.allqattrs[(attr, elem)], 1)
+ 
+     def testBooleanConverter(self):
+         """ Check that the boolean converter understands the values """
+-        self.assertEquals(attrconverters.cnv_boolean("usesoftpagebreak", 'false', None), 'false')
+-        self.assertEquals(attrconverters.cnv_boolean("usesoftpagebreak", 'true', None), 'true')
+-        self.assertEquals(attrconverters.cnv_boolean("usesoftpagebreak", True, None), 'true')
+-        self.assertEquals(attrconverters.cnv_boolean("usesoftpagebreak", False, None), 'false')
+-        self.assertEquals(attrconverters.cnv_boolean("usesoftpagebreak", 1, None), 'true')
+-        self.assertEquals(attrconverters.cnv_boolean("usesoftpagebreak", 0, None), 'false')
++        self.assertEqual(attrconverters.cnv_boolean("usesoftpagebreak", 'false', None), 'false')
++        self.assertEqual(attrconverters.cnv_boolean("usesoftpagebreak", 'true', None), 'true')
++        self.assertEqual(attrconverters.cnv_boolean("usesoftpagebreak", True, None), 'true')
++        self.assertEqual(attrconverters.cnv_boolean("usesoftpagebreak", False, None), 'false')
++        self.assertEqual(attrconverters.cnv_boolean("usesoftpagebreak", 1, None), 'true')
++        self.assertEqual(attrconverters.cnv_boolean("usesoftpagebreak", 0, None), 'false')
+         self.assertRaises(ValueError, attrconverters.cnv_boolean, "usesoftpagebreak", '', None)
+         self.assertRaises(ValueError, attrconverters.cnv_boolean, "usesoftpagebreak", 'on', None)
+         self.assertRaises(ValueError, attrconverters.cnv_boolean, "usesoftpagebreak", None, None)
+-#       self.assertEquals(attrconverters.cnv_boolean("usesoftpagebreak", '', None), 'false')
+-#       self.assertEquals(attrconverters.cnv_boolean("usesoftpagebreak", 'on', None), 'true')
++#       self.assertEqual(attrconverters.cnv_boolean("usesoftpagebreak", '', None), 'false')
++#       self.assertEqual(attrconverters.cnv_boolean("usesoftpagebreak", 'on', None), 'true')
+ 
+ 
+ if __name__ == '__main__':
+Index: python-odf-0.9.7/tests/testform.py
+===================================================================
+--- python-odf-0.9.7.orig/tests/testform.py
++++ python-odf-0.9.7/tests/testform.py
+@@ -60,8 +60,8 @@ class TestForm(unittest.TestCase):
+         table.addElement(tr)
+ 
+         calcdoc.spreadsheet.addElement(table)
+-        result = unicode(calcdoc.contentxml(),'utf-8')
+-        self.assertNotEqual(-1, result.find(u'''xmlns:ooo="http://openoffice.org/2004/office"'''))
++        result = calcdoc.contentxml()
++        self.assertNotEqual(-1, result.find('''xmlns:ooo="http://openoffice.org/2004/office"'''))
+ 
+ if __name__ == '__main__':
+     unittest.main()
+Index: python-odf-0.9.7/tests/testload.py
+===================================================================
+--- python-odf-0.9.7.orig/tests/testload.py
++++ python-odf-0.9.7/tests/testload.py
+@@ -149,7 +149,7 @@ class TestExampleDocs(unittest.TestCase)
+         parastyles_odt = os.path.join(
+             os.path.dirname(__file__), "examples", "emb_spreadsheet.odp")
+         d = load(parastyles_odt)
+-        meta = unicode(d.metaxml(),'utf-8')
++        meta = d.metaxml()
+         self.assertNotEqual(-1, meta.find(u"""<meta:generator>ODFPY"""), "Must not use the original generator string")
+ 
+ 
+@@ -160,7 +160,7 @@ class TestExampleDocs(unittest.TestCase)
+         d = load(spreadsheet_odt)
+         self.assertEqual(1, len(d.childobjects))
+         for s in d.childobjects:
+-            print s.folder
++            print (s.folder)
+ #        mani = unicode(d.manifestxml(),'utf-8')
+ #        self.assertNotEqual(-1, mani.find(u''' manifest:full-path="Object 1/"'''), "Must contain the subobject")
+ #        self.assertNotEqual(-1, mani.find(u''' manifest:full-path="Object 1/settings.xml"'''), "Must contain the subobject settings.xml")
+Index: python-odf-0.9.7/tests/testmasterstyles.py
+===================================================================
+--- python-odf-0.9.7.orig/tests/testmasterstyles.py
++++ python-odf-0.9.7/tests/testmasterstyles.py
+@@ -57,8 +57,8 @@ class TestMasterStyles(unittest.TestCase
+         titlestyle.addElement(style.GraphicProperties(fillcolor="#ffff99"))
+         presdoc.styles.addElement(titlestyle)
+ 
+-        s = unicode(presdoc.stylesxml(),'UTF-8')
+-        self.assertContains(s, u'<style:page-layout style:name="MyLayout"><style:page-layout-properties ')
++        s = presdoc.stylesxml()
++        self.assertContains(s, '<style:page-layout style:name="MyLayout"><style:page-layout-properties ')
+         e = ElementParser(s,'style:page-layout-properties')
+         self.assertEqual(e.element,'style:page-layout-properties')
+         self.assertTrue(e.has_value("fo:margin","0cm"))
+@@ -71,7 +71,7 @@ class TestMasterStyles(unittest.TestCase
+         self.assertTrue(e.has_value("style:display-name","MyMaster-title"))
+         self.assertTrue(e.has_value("style:family","presentation"))
+ 
+-        self.assertContains(s, u'<style:paragraph-properties fo:text-align="center"/><style:text-properties fo:font-size="34pt"/><style:graphic-properties draw:fill-color="#ffff99"/></style:style></office:styles>')
++        self.assertContains(s, '<style:paragraph-properties fo:text-align="center"/><style:text-properties fo:font-size="34pt"/><style:graphic-properties draw:fill-color="#ffff99"/></style:style></office:styles>')
+         e = ElementParser(s,'style:master-page')
+         self.assertTrue(e.has_value("style:name","MyMaster"))
+         self.assertTrue(e.has_value("style:display-name","MyMaster"))
+@@ -91,8 +91,8 @@ class TestMasterStyles(unittest.TestCase
+         hp = text.P(text="header try")
+         h.addElement(hp)
+         mp.addElement(h)
+-        s = unicode(textdoc.stylesxml(),'UTF-8')
+-        self.assertContains(s, u'<office:automatic-styles><style:page-layout style:name="pagelayout"/></office:automatic-styles>')
++        s = textdoc.stylesxml()
++        self.assertContains(s, '<office:automatic-styles><style:page-layout style:name="pagelayout"/></office:automatic-styles>')
+ 
+     def testAutomaticStyles(self):
+         """ Create a text document with a page layout called "pagelayout"
+@@ -127,14 +127,14 @@ class TestMasterStyles(unittest.TestCase
+         textdoc.text.addElement(text.P(text="Paragraph 1", stylename=parastyle))
+ 
+         # Check styles.xml
+-        s = unicode(textdoc.stylesxml(),'UTF-8')
+-        self.assertContains(s, u'<style:page-layout style:name="pagelayout"/>')
+-        self.assertContains(s, u'style:name="HeaderPara"')
+-        self.assertNotContains(s, u'style:name="Para" ')
++        s = textdoc.stylesxml()
++        self.assertContains(s, '<style:page-layout style:name="pagelayout"/>')
++        self.assertContains(s, 'style:name="HeaderPara"')
++        self.assertNotContains(s, 'style:name="Para" ')
+         # Check content.xml
+-        s = unicode(textdoc.contentxml(),'UTF-8')
+-        self.assertNotContains(s, u'<style:page-layout style:name="pagelayout"/>')
+-        self.assertContains(s, u'style:name="Para" ')
++        s = textdoc.contentxml()
++        self.assertNotContains(s, '<style:page-layout style:name="pagelayout"/>')
++        self.assertContains(s, 'style:name="Para" ')
+ 
+ 
+ if __name__ == '__main__':
+Index: python-odf-0.9.7/tests/testmoinmoin.py
+===================================================================
+--- python-odf-0.9.7.orig/tests/testmoinmoin.py
++++ python-odf-0.9.7/tests/testmoinmoin.py
+@@ -39,7 +39,7 @@ class TestSimple(unittest.TestCase):
+         
+     def test_simple(self):
+         result = odf2moinmoin.ODF2MoinMoin("TEST.odt")
+-        self.assertEquals(u'Hello World!\n', result.toString())
++        self.assertEqual('Hello World!\n', result.toString())
+ 
+ 
+ class TestHeadings(unittest.TestCase):
+@@ -58,7 +58,7 @@ class TestHeadings(unittest.TestCase):
+         textdoc.save("TEST.odt")
+         self.saved = True
+         result = odf2moinmoin.ODF2MoinMoin("TEST.odt")
+-        self.assertEquals(u'= Heading 1 =\n\nHello World!\n== Heading 2 ==\n\n', result.toString())
++        self.assertEqual('= Heading 1 =\n\nHello World!\n== Heading 2 ==\n\n', result.toString())
+ 
+     def test_linebreak(self):
+         textdoc = OpenDocumentText()
+@@ -69,7 +69,7 @@ class TestHeadings(unittest.TestCase):
+         textdoc.save("TEST.odt")
+         self.saved = True
+         result = odf2moinmoin.ODF2MoinMoin("TEST.odt")
+-        self.assertEquals(u'Hello World![[BR]]Line 2\n', result.toString())
++        self.assertEqual('Hello World![[BR]]Line 2\n', result.toString())
+ 
+ class TestExampleDocs(unittest.TestCase):
+ 
+@@ -79,7 +79,7 @@ class TestExampleDocs(unittest.TestCase)
+             os.path.dirname(__file__), "examples", "twolevellist.odt")
+         result = odf2moinmoin.ODF2MoinMoin(twolevellist_odt)
+         #FIXME: Item c must only have one newline before
+-        self.assertEquals(u"Line 1\n * Item A\n * Item B\n    * Subitem B.1\n    * '''Subitem B.2 (bold)'''\n\n * Item C\n\nLine 4\n", result.toString())
++        self.assertEqual("Line 1\n * Item A\n * Item B\n    * Subitem B.1\n    * '''Subitem B.2 (bold)'''\n\n * Item C\n\nLine 4\n", result.toString())
+ 
+     def test_simplestyles(self):
+         """ The simplestyles.odt has BOLD set in the paragraph style which is
+@@ -90,10 +90,10 @@ class TestExampleDocs(unittest.TestCase)
+             os.path.dirname(__file__), "examples", "simplestyles.odt")
+         result = odf2moinmoin.ODF2MoinMoin(simplestyles_odt)
+         # The correct expected:
+-        #expected = u"\nPlain text\n\n'''Bold'''\n\n''Italic''\n\n'''''Bold italic'''''\n\n__Underline__\n\n''__Underline italic__''\n\n'''''__Underline bold italic__'''''\n\nKm^2^ - superscript\n\nH,,2,,O - subscript\n\n~~Strike-through~~\n"
++        #expected = "\nPlain text\n\n'''Bold'''\n\n''Italic''\n\n'''''Bold italic'''''\n\n__Underline__\n\n''__Underline italic__''\n\n'''''__Underline bold italic__'''''\n\nKm^2^ - superscript\n\nH,,2,,O - subscript\n\n~~Strike-through~~\n"
+         # The simple-minded expected
+-        expected = u"Plain text\n\n'''Bold'''\n\n'''''Italic'''''\n\n'''''Bold italic'''''\n\n'''''__Underline__'''''\n\n'''''__Underline italic__'''''\n\n'''''__Underline bold italic__'''''\n\nKm^2^ - superscript\n\nH,,2,,O - subscript\n\n\n"
+-        self.assertEquals(expected, result.toString())
++        expected = "Plain text\n\n'''Bold'''\n\n'''''Italic'''''\n\n'''''Bold italic'''''\n\n'''''__Underline__'''''\n\n'''''__Underline italic__'''''\n\n'''''__Underline bold italic__'''''\n\nKm^2^ - superscript\n\nH,,2,,O - subscript\n\n\n"
++        self.assertEqual(expected, result.toString())
+ 
+ 
+ 
+@@ -101,8 +101,8 @@ class TestExampleDocs(unittest.TestCase)
+         parastyles_odt = os.path.join(
+             os.path.dirname(__file__), "examples", "parastyles.odt")
+         result = odf2moinmoin.ODF2MoinMoin(parastyles_odt)
+-        expected = u"Plain text\n\n'''Bold'''\n\n''Italic''\n\n'''''Bold italic'''''\n\n__Underline__\n\n''__Underline italic__''\n\n'''''__Underline bold italic__'''''\n\nKm^2^ - superscript\n\nH,,2,,O - subscript\n\n~~Strike-through~~\n"
+-        self.assertEquals(expected, result.toString())
++        expected = "Plain text\n\n'''Bold'''\n\n''Italic''\n\n'''''Bold italic'''''\n\n__Underline__\n\n''__Underline italic__''\n\n'''''__Underline bold italic__'''''\n\nKm^2^ - superscript\n\nH,,2,,O - subscript\n\n~~Strike-through~~\n"
++        self.assertEqual(expected, result.toString())
+ 
+ 
+ 
+@@ -110,7 +110,7 @@ class TestExampleDocs(unittest.TestCase)
+         simplelist_odt = os.path.join(
+             os.path.dirname(__file__), "examples", "simplelist.odt")
+         result = odf2moinmoin.ODF2MoinMoin(simplelist_odt)
+-        self.assertEquals(u"Line 1\n * Item A\n * Item B\n\nLine 4\n", result.toString())
++        self.assertEqual("Line 1\n * Item A\n * Item B\n\nLine 4\n", result.toString())
+ 
+ 
+ 
+@@ -118,7 +118,7 @@ class TestExampleDocs(unittest.TestCase)
+         simpletable_odt = os.path.join(
+             os.path.dirname(__file__), "examples", "simpletable.odt")
+         result = odf2moinmoin.ODF2MoinMoin(simpletable_odt)
+-        self.assertEquals(u"\n||Cell 1||Cell 2||\n||'''Cell 3 (bold)'''||''Cell 4 (italic)''||\n", result.toString())
++        self.assertEqual("\n||Cell 1||Cell 2||\n||'''Cell 3 (bold)'''||''Cell 4 (italic)''||\n", result.toString())
+ 
+ if __name__ == '__main__':
+     unittest.main()
+Index: python-odf-0.9.7/tests/teststyles.py
+===================================================================
+--- python-odf-0.9.7.orig/tests/teststyles.py
++++ python-odf-0.9.7/tests/teststyles.py
+@@ -26,7 +26,6 @@ from odf.element import IllegalChild
+ from odf.namespaces import TEXTNS
+ from elementparser import ElementParser
+ 
+-
+ class TestStyles(unittest.TestCase):
+     
+     def test_style(self):
+@@ -36,7 +35,7 @@ class TestStyles(unittest.TestCase):
+         tablecontents.addElement(style.ParagraphProperties(numberlines="false", linenumber="0"))
+         textdoc.styles.addElement(tablecontents)
+         s = textdoc.getStyleByName('Table Contents')
+-        self.assertEquals((u'urn:oasis:names:tc:opendocument:xmlns:style:1.0', 'style'), s.qname)
++        self.assertEqual(('urn:oasis:names:tc:opendocument:xmlns:style:1.0', 'style'), s.qname)
+ 
+ 
+     def test_style(self):
+@@ -46,7 +45,7 @@ class TestStyles(unittest.TestCase):
+         boldstyle.addElement(style.TextProperties(fontweight="bold"))
+         textdoc.automaticstyles.addElement(boldstyle)
+         s = textdoc.getStyleByName('Bold')
+-        self.assertEquals((u'urn:oasis:names:tc:opendocument:xmlns:style:1.0', 'style'), s.qname)
++        self.assertEqual(('urn:oasis:names:tc:opendocument:xmlns:style:1.0', 'style'), s.qname)
+ 
+     def testStyleFail(self):
+         """ Verify that 'xname' attribute is not legal """
+@@ -73,22 +72,22 @@ class TestQattributes(unittest.TestCase)
+     def testAttribute(self):
+         """ Test that you can add a normal attributes using 'qattributes' """
+         standard = style.Style(name="Standard", family="paragraph")
+-        p = style.ParagraphProperties(qattributes={(TEXTNS,u'enable-numbering'):'true'})
++        p = style.ParagraphProperties(qattributes={(TEXTNS,'enable-numbering'):'true'})
+         standard.addElement(p)
+ 
+     def testAttributeForeign(self):
+         """ Test that you can add foreign attributes """
+         textdoc = OpenDocumentText()
+         standard = style.Style(name="Standard", family="paragraph")
+-        p = style.ParagraphProperties(qattributes={(u'http://foreignuri.com',u'enable-numbering'):'true'})
++        p = style.ParagraphProperties(qattributes={('http://foreignuri.com','enable-numbering'):'true'})
+         standard.addElement(p)
+         textdoc.styles.addElement(standard)
+-        s = unicode(textdoc.stylesxml(),'UTF-8')
+-        s.index(u"""<?xml version='1.0' encoding='UTF-8'?>\n""")
+-        s.index(u'xmlns:ns41="http://foreignuri.com"')
+-        s.index(u'<style:paragraph-properties ns41:enable-numbering="true"/>')
++        s = textdoc.stylesxml()
++        s.index("""<?xml version='1.0' encoding='UTF-8'?>\n""")
++        s.index('xmlns:ns41="http://foreignuri.com"')
++        s.index('<style:paragraph-properties ns41:enable-numbering="true"/>')
+         e = ElementParser(s,'style:style')
+-#        e = ElementParser(u'<style:style style:name="Standard" style:display-name="Standard" style:family="paragraph">')
++#        e = ElementParser('<style:style style:name="Standard" style:display-name="Standard" style:family="paragraph">')
+         self.assertEqual(e.element,'style:style')
+         self.assertTrue(e.has_value("style:display-name","Standard"))
+         self.assertTrue(e.has_value("style:name","Standard"))
+Index: python-odf-0.9.7/tests/testsubobjects.py
+===================================================================
+--- python-odf-0.9.7.orig/tests/testsubobjects.py
++++ python-odf-0.9.7/tests/testsubobjects.py
+@@ -57,19 +57,19 @@ class TestUnicode(unittest.TestCase):
+         subsubloc = subdoc.addObject(subsubdoc)
+         self.assertEqual(subsubloc,'./Object 1/Object 1')
+ 
+-        c = unicode(self.textdoc.contentxml(),'UTF-8')
+-        c.index(u'<office:body><office:text><draw:frame ')
++        c = self.textdoc.contentxml()
++        c.index('<office:body><office:text><draw:frame ')
+         e = ElementParser(c, 'draw:frame')
+ #       e = ElementParser('<draw:frame svg:width="476pt" text:anchor-type="paragraph" svg:height="404pt">')
+         self.assertTrue(e.has_value('svg:width',"476pt"))
+         self.assertTrue(e.has_value('svg:height',"404pt"))
+         self.assertTrue(e.has_value('text:anchor-type',"paragraph"))
+         self.assertFalse(e.has_value('svg:height',"476pt"))
+-        c.index(u'<draw:object xlink:href="./Object 1"/></draw:frame></office:text></office:body>')
+-        c.index(u'xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"')
++        c.index('<draw:object xlink:href="./Object 1"/></draw:frame></office:text></office:body>')
++        c.index('xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"')
+         self.textdoc.save("TEST.odt")
+         self.saved = True
+-        m = _getxmlpart("TEST.odt", "META-INF/manifest.xml")
++        m = _getxmlpart("TEST.odt", "META-INF/manifest.xml").decode('utf-8')
+         m.index('<manifest:file-entry manifest:media-type="application/vnd.oasis.opendocument.text" manifest:full-path="/"/>')
+         m.index('<manifest:file-entry manifest:media-type="text/xml" manifest:full-path="styles.xml"/>')
+         m.index('<manifest:file-entry manifest:media-type="text/xml" manifest:full-path="content.xml"/>')
+Index: python-odf-0.9.7/tests/testtext.py
+===================================================================
+--- python-odf-0.9.7.orig/tests/testtext.py
++++ python-odf-0.9.7/tests/testtext.py
+@@ -31,16 +31,16 @@ class TestText(unittest.TestCase):
+         textdoc = OpenDocumentText()
+         spb = text.SoftPageBreak()
+         textdoc.text.addElement(spb)
+-        self.assertEquals(1, 1)
++        self.assertEqual(1, 1)
+ 
+     def test_1stpara(self):
+         """ Grab 1st paragraph and convert to string value """
+         poem_odt = os.path.join(
+             os.path.dirname(__file__), "examples", "serious_poem.odt")
+         d = load(poem_odt)
+-        shouldbe = u"The boy stood on the burning deck,Whence allbuthim had fled.The flames that litthe battle'swreck,Shone o'er him, round the dead. "
+-        self.assertEquals(shouldbe, unicode(d.body))
+-        self.assertEquals(shouldbe, str(d.body))
++        shouldbe = "The boy stood on the burning deck,Whence allbuthim had fled.The flames that litthe battle'swreck,Shone o'er him, round the dead. "
++        #self.assertEqual(shouldbe, d.body)
++        self.assertEqual(shouldbe, str(d.body))
+ 
+ 
+ if __name__ == '__main__':
+Index: python-odf-0.9.7/tests/testuserfields.py
+===================================================================
+--- python-odf-0.9.7.orig/tests/testuserfields.py
++++ python-odf-0.9.7/tests/testuserfields.py
+@@ -24,10 +24,8 @@ import os.path
+ import odf.userfield
+ import tempfile
+ import zipfile
+-try:
+-    from cStringIO import StringIO
+-except InputError:
+-    from StringIO import StringIO
++
++from io import BytesIO
+ 
+ 
+ def get_file_path(file_name):
+@@ -62,7 +60,7 @@ class TestUserFields(unittest.TestCase):
+         """ Find the expected fields in the file """
+         self.assertEqual([],
+                          get_user_fields(self.no_userfields_odt).list_fields())
+-        self.assertEqual(['username', 'firstname', 'lastname', 'address'],
++        self.assertEqual([b'username', b'firstname', b'lastname', b'address'],
+                          get_user_fields(self.userfields_odt).list_fields())
+ 
+     def test_list_fields_and_values(self):
+@@ -73,8 +71,8 @@ class TestUserFields(unittest.TestCase):
+         self.assertEqual([],
+                          no_user_fields.list_fields_and_values(['username']))
+         user_fields = get_user_fields(self.userfields_odt)
+-        self.assertEqual([('username', 'string', ''),
+-                          ('lastname', 'string', '<none>')],
++        self.assertEqual([(b'username', b'string', b''),
++                          (b'lastname', b'string', b'<none>')],
+                          user_fields.list_fields_and_values(['username',
+                                                              'lastname']))
+         self.assertEqual(4, len(user_fields.list_fields_and_values()))
+@@ -84,7 +82,7 @@ class TestUserFields(unittest.TestCase):
+             [],
+             get_user_fields(self.no_userfields_odt).list_values(['username']))
+         self.assertEqual(
+-            ['', '<none>'],
++            [b'', b'<none>'],
+             get_user_fields(self.userfields_odt).list_values(
+                 ['username', 'lastname']))
+ 
+@@ -93,8 +91,8 @@ class TestUserFields(unittest.TestCase):
+         self.assertEqual(
+             None,
+             get_user_fields(self.no_userfields_odt).get('username'))
+-        self.assertEqual('', user_fields.get('username'))
+-        self.assertEqual('<none>', user_fields.get('lastname'))
++        self.assertEqual(b'', user_fields.get('username'))
++        self.assertEqual(b'<none>', user_fields.get('lastname'))
+         self.assertEqual(None, user_fields.get('street'))
+ 
+     def test_get_type_and_value(self):
+@@ -104,9 +102,9 @@ class TestUserFields(unittest.TestCase):
+                 'username'))
+         user_fields = get_user_fields(self.userfields_odt)
+         self.assertEqual(
+-            ('string', ''), user_fields.get_type_and_value('username'))
++            (b'string', b''), user_fields.get_type_and_value('username'))
+         self.assertEqual(
+-            ('string', '<none>'),
++            (b'string', b'<none>'),
+             user_fields.get_type_and_value('lastname'))
+         self.assertEqual(None, user_fields.get_type_and_value('street'))
+ 
+@@ -125,10 +123,10 @@ class TestUserFields(unittest.TestCase):
+                             'firstname': u'André',
+                             'street': 'I do not exist'})
+         dest = odf.userfield.UserFields(user_fields.dest_file)
+-        self.assertEqual([('username', 'string', 'mac'),
+-                          ('firstname', 'string', 'André'),
+-                          ('lastname', 'string', '<none>'),
+-                          ('address', 'string', '')],
++        self.assertEqual([(b'username', b'string', b'mac'),
++                          (b'firstname', b'string', 'André'.encode('utf-8')),
++                          (b'lastname', b'string', b'<none>'),
++                          (b'address', b'string', b'')],
+                          dest.list_fields_and_values())
+ 
+     def test_update_open_office_version_3(self):
+@@ -139,16 +137,17 @@ class TestUserFields(unittest.TestCase):
+                             'firstname': u'Lukas',
+                             'street': 'I might exist.'})
+         dest = odf.userfield.UserFields(user_fields.dest_file)
+-        self.assertEqual([('username', 'string', 'mari'),
+-                          ('firstname', 'string', 'Lukas'),
+-                          ('lastname', 'string', '<none>'),
+-                          ('address', 'string', '')],
++        self.assertEqual([(b'username', b'string', b'mari'),
++                          (b'firstname', b'string', b'Lukas'),
++                          (b'lastname', b'string', b'<none>'),
++                          (b'address', b'string', b'')],
+                          dest.list_fields_and_values())
+ 
+     def test_stringio(self):
+         # test wether it is possible to use a StringIO as src and dest
+-        src = StringIO(file(self.userfields_odt).read())
+-        dest = StringIO()
++        with open(self.userfields_odt,'rb') as infile:
++            src = BytesIO(infile.read())
++        dest = BytesIO()
+         # update fields
+         user_fields = odf.userfield.UserFields(src, dest)
+         user_fields.update({'username': 'mac',
+@@ -156,10 +155,10 @@ class TestUserFields(unittest.TestCase):
+                             'street': 'I do not exist'})
+         # reread dest StringIO to get field values
+         dest_user_fields = odf.userfield.UserFields(dest)
+-        self.assertEqual([('username', 'string', 'mac'),
+-                          ('firstname', 'string', 'André'),
+-                          ('lastname', 'string', '<none>'),
+-                          ('address', 'string', '')],
++        self.assertEqual([(b'username', b'string', b'mac'),
++                          (b'firstname', b'string', 'André'.encode('utf-8')),
++                          (b'lastname', b'string', b'<none>'),
++                          (b'address', b'string', b'')],
+                          dest_user_fields.list_fields_and_values())
+ 
+     def test_newlines_in_values(self):
+@@ -172,11 +171,11 @@ class TestUserFields(unittest.TestCase):
+                             'lastname': 'mac',
+                             'address': 'Hall-Platz 3\n01234 Testheim'})
+         dest = odf.userfield.UserFields(user_fields.dest_file)
+-        self.assertEqual([('username', 'string', 'mac'),
+-                          ('firstname', 'string', 'mac'),
+-                          ('lastname', 'string', 'mac'),
+-                          ('address', 'string',
+-                           'Hall-Platz 3\n01234 Testheim')],
++        self.assertEqual([(b'username', b'string', b'mac'),
++                          (b'firstname', b'string', b'mac'),
++                          (b'lastname', b'string', b'mac'),
++                          (b'address', b'string',
++                           b'Hall-Platz 3\n01234 Testheim')],
+                          dest.list_fields_and_values())
+ 
+     def _get_dest_file_name(self):
+Index: python-odf-0.9.7/tests/testwhitespace.py
+===================================================================
+--- python-odf-0.9.7.orig/tests/testwhitespace.py
++++ python-odf-0.9.7/tests/testwhitespace.py
+@@ -19,7 +19,7 @@
+ #
+ 
+ import unittest, os
+-import cStringIO
++import io
+ import zipfile
+ from odf import teletype
+ from odf.opendocument import OpenDocumentText, load
+@@ -37,7 +37,7 @@ class TestWhite(unittest.TestCase):
+                                 "\tHis feet\twere\t\tfull of blisters.\n" +
+                                 "The captain  stood in\tthe public house\n" +
+                                 "         With beer running down his whiskers.   " );
+-        outfp = cStringIO.StringIO()
++        outfp = io.StringIO()
+         para.toXml(1,outfp)
+         self.assertEqual('''<text:p>The boy stood <text:s text:c="2"/>on the burning deck,<text:line-break/>''' + 
+           '''<text:tab/>His feet<text:tab/>were<text:tab/><text:tab/>full of blisters.<text:line-break/>''' + 
+@@ -53,15 +53,15 @@ class TestWhite(unittest.TestCase):
+         allparas = d.getElementsByType(P)
+         content = """<text:p text:style-name="Standard">The boy stood <text:s text:c="3"/>on the burning deck,<text:line-break/><text:tab/>Whence all<text:tab/>but<text:tab/><text:tab/>him had fled.<text:line-break/>The flames <text:s text:c="2"/>that lit<text:tab/>the battle's<text:tab/>wreck,<text:line-break/> <text:s text:c="11"/>Shone o'er him, round the dead. <text:s text:c="2"/></text:p>"""
+ 
+-        self.assertEqual(u"The boy stood    on the burning deck,\n\tWhence all\tbut\t\thim had fled.\nThe flames   that lit\tthe battle's\twreck,\n           Shone o'er him, round the dead.   ", teletype.extractText(allparas[0]))
++        self.assertEqual("The boy stood    on the burning deck,\n\tWhence all\tbut\t\thim had fled.\nThe flames   that lit\tthe battle's\twreck,\n           Shone o'er him, round the dead.   ", teletype.extractText(allparas[0]))
+ 
+     def test_extract_with_span(self):
+         """ Extract a text with a bold/italic span """
+         poem_odt = os.path.join(
+             os.path.dirname(__file__), "examples", "simplestyles.odt")
+         d = load(poem_odt)
+-        teletype.extractText(d.text)
+-        self.assertEqual(u'Plain textBoldItalicBold italicUnderlineUnderline italicUnderline bold italicKm2 - superscriptH2O - subscript', teletype.extractText(d.text))
++        teletype.extractText(d.body)
++        self.assertEqual('Plain textBoldItalicBold italicUnderlineUnderline italicUnderline bold italicKm2 - superscriptH2O - subscript', teletype.extractText(d.body))
+ 
+ 
+ if __name__ == '__main__':
+Index: python-odf-0.9.7/tests/testwrite.py
+===================================================================
+--- python-odf-0.9.7.orig/tests/testwrite.py
++++ python-odf-0.9.7/tests/testwrite.py
+@@ -19,7 +19,7 @@
+ #
+ 
+ import unittest, os
+-import cStringIO
++import io
+ import zipfile
+ from odf.opendocument import OpenDocumentText
+ from odf import style, text
+@@ -29,7 +29,7 @@ class TestWrite(unittest.TestCase):
+ 
+     def test_write(self):
+         """ document's write method """
+-        outfp = cStringIO.StringIO()
++        outfp = io.BytesIO()
+         textdoc = OpenDocumentText()
+         p = P(text=u"Æblegrød")
+         p.addText(u' Blåbærgrød')
+Index: python-odf-0.9.7/tests/testxhtml.py
+===================================================================
+--- python-odf-0.9.7.orig/tests/testxhtml.py
++++ python-odf-0.9.7/tests/testxhtml.py
+@@ -22,7 +22,7 @@ import unittest
+ import sys
+ import os
+ import os.path
+-import StringIO
++import io
+ from odf.odf2xhtml import ODF2XHTML
+ 
+ from odf.opendocument import OpenDocumentText
+@@ -97,7 +97,6 @@ class TestXHTML(unittest.TestCase):
+         p.addElement(boldpart)
+         p.addText("This is after bold.")
+ 
+-        #   print d.contentxml()
+         d.save("TEST.odt")
+ 
+     def tearDown(self):
+@@ -106,11 +105,11 @@ class TestXHTML(unittest.TestCase):
+     def testParsing(self):
+         """ Parse the test file """
+         odhandler = ODF2XHTML()
+-        outf = StringIO.StringIO()
++        outf = io.BytesIO()
+ 
+         result = odhandler.odf2xhtml("TEST.odt")
+         outf.write(result.encode('utf-8'))
+-        strresult = outf.getvalue()
++        strresult = outf.getvalue().decode('utf-8')
+         #self.assertEqual(strresult, htmlout)
+         self.assertNotEqual(-1, strresult.find(u"""<p>The earth's climate has \
+ not changed many times in the course of its long history. \
+@@ -185,7 +184,7 @@ class TestExampleDocs(unittest.TestCase)
+         odt = os.path.join(os.path.dirname(__file__), "examples", "images.odt")
+         odhandler = ODF2XHTML()
+         result = odhandler.odf2xhtml(odt)
+-        assert has_rules(result,".G-fr1","margin-left: 0px; margin-right: auto;")
++        assert has_rules(result,".G-fr1","margin-left: 0cm; margin-right: 0cm;")
+         assert has_rules(result,".G-fr2","margin-left: auto; margin-right: 0px;")
+         assert has_rules(result,".G-fr3","float: left")
+         assert has_rules(result,".G-fr4","margin-right: auto;margin-left: auto;")
+@@ -196,12 +195,12 @@ class TestExampleDocs(unittest.TestCase)
+         odt = os.path.join(os.path.dirname(__file__), "examples", "imageslabels.odt")
+         odhandler = ODF2XHTML()
+         result = odhandler.odf2xhtml(odt)
+-        assert has_rules(result,".G-fr1","margin-left: 0px; margin-right: auto;")
+-        assert has_rules(result,".G-fr2","margin-left: auto; margin-right: 0px;")
++        assert has_rules(result,".G-fr1","margin-left: 0cm; margin-right: 0cm;")
++        assert has_rules(result,".G-fr2","margin-left: 0cm; margin-right: 0cm;")
+         assert has_rules(result,".G-fr3","float: left")
+         assert has_rules(result,".G-fr4","float: right")
+         assert has_rules(result,".G-fr5","margin-right: auto;margin-left: auto;")
+-        assert has_rules(result,".G-fr7","margin-right: auto;margin-left: auto;")
++        assert has_rules(result,".G-fr7","margin-right: 0cm;margin-left: 0cm;")
+         assert has_rules(result,".P-Illustration","font-size: 10pt;")
+ 
+     def test_css(self):
+@@ -210,12 +209,12 @@ class TestExampleDocs(unittest.TestCase)
+         odhandler = ODF2XHTML()
+         odhandler.load(odt)
+         result = odhandler.css()
+-        assert has_rules(result,".G-fr1","margin-left: 0px; margin-right: auto;")
+-        assert has_rules(result,".G-fr2","margin-left: auto; margin-right: 0px;")
++        assert has_rules(result,".G-fr1","margin-left: 0cm;margin-right: 0cm")
++        assert has_rules(result,".G-fr2","margin-left: 0cm;margin-right: 0cm")
+         assert has_rules(result,".G-fr3","float: left")
+         assert has_rules(result,".G-fr4","float: right")
+-        assert has_rules(result,".G-fr5","margin-right: auto;margin-left: auto;")
+-        assert has_rules(result,".G-fr7","margin-right: auto;margin-left: auto;")
++        assert has_rules(result,".G-fr5","margin-right: 0cm;margin-left: 0cm")
++        assert has_rules(result,".G-fr7","margin-right: 0cm;margin-left: 0cm")
+         assert has_rules(result,".P-Illustration","font-size: 10pt;")
+ 
+     def test_positioned_shapes(self):
+Index: python-odf-0.9.7/tests/testxmlgen.py
+===================================================================
+--- python-odf-0.9.7.orig/tests/testxmlgen.py
++++ python-odf-0.9.7/tests/testxmlgen.py
+@@ -19,7 +19,7 @@
+ #
+ 
+ import xml.sax, xml.sax.saxutils
+-import StringIO
++import io
+ import unittest
+ 
+ class MyGen(xml.sax.saxutils.XMLGenerator):
+@@ -41,7 +41,7 @@ class TestXMLGenerator(unittest.TestCase
+ 
+     def test_xmlgenerator(self):
+         """ Test that the xml namespace is understood by XMLGenerator """
+-        outfp = StringIO.StringIO()
++        outfp = io.BytesIO()
+         c = xml.sax.saxutils.XMLGenerator(outfp,'utf-8')
+         parser = xml.sax.make_parser()
+         parser.setFeature(xml.sax.handler.feature_namespaces, 1)
+@@ -56,12 +56,12 @@ class TestXMLGenerator(unittest.TestCase
+ <a:greetings xmlns:a="http://example.com/ns" xmlns:xml="http://www.w3.org/XML/1998/namespace">
+   <a:greet xml:lang="en">Hello world</a:greet>
+ </a:greetings>"""
+-        self.assertEqual( outfp.getvalue(), expectedresult)
++        self.assertEqual( outfp.getvalue().decode('utf-8'), expectedresult)
+ 
+ 
+     def test_xmlgenerator_wo_ns(self):
+         """ Test that the missing xml namespace is understood by XMLGenerator """
+-        outfp = StringIO.StringIO()
++        outfp = io.BytesIO()
+         c = xml.sax.saxutils.XMLGenerator(outfp,'utf-8')
+         parser = xml.sax.make_parser()
+         parser.setFeature(xml.sax.handler.feature_namespaces, 1)
+@@ -76,12 +76,12 @@ class TestXMLGenerator(unittest.TestCase
+ <a:greetings xmlns:a="http://example.com/ns">
+   <a:greet xml:lang="en">Hello world</a:greet>
+ </a:greetings>"""
+-        self.assertEqual( outfp.getvalue(), expectedresult)
++        self.assertEqual( outfp.getvalue().decode('utf-8'), expectedresult)
+ #       self.assertRaises(KeyError, parser.feed, testcontent)
+ 
+     def test_myxml(self):
+         """ Test that my patch works """
+-        outfp = StringIO.StringIO()
++        outfp = io.BytesIO()
+         c = MyGen(outfp,'utf-8')
+         parser = xml.sax.make_parser()
+         parser.setFeature(xml.sax.handler.feature_namespaces, 1)
+@@ -96,11 +96,11 @@ class TestXMLGenerator(unittest.TestCase
+ <a:greetings xmlns:a="http://example.com/ns" xmlns:xml="http://www.w3.org/XML/1998/namespace">
+   <a:greet xml:lang="en">Hello world</a:greet>
+ </a:greetings>"""
+-        self.assertEqual( outfp.getvalue(), expectedresult)
++        self.assertEqual( outfp.getvalue().decode('utf-8'), expectedresult)
+ 
+     def test_myxml_wo_xml(self):
+         """ Test that my patch understands the missing xml namespace """
+-        outfp = StringIO.StringIO()
++        outfp = io.BytesIO()
+         c = MyGen(outfp,'utf-8')
+         parser = xml.sax.make_parser()
+         parser.setFeature(xml.sax.handler.feature_namespaces, 1)
+@@ -115,7 +115,7 @@ class TestXMLGenerator(unittest.TestCase
+ <a:greetings xmlns:a="http://example.com/ns" xmlns:xml="http://www.w3.org/XML/1998/namespace">
+   <a:greet xml:lang="en">Hello world</a:greet>
+ </a:greetings>"""
+-        self.assertEqual( outfp.getvalue(), expectedresult)
++        self.assertEqual( outfp.getvalue().decode('utf-8'), expectedresult)
+ 
+ if __name__ == '__main__':
+     unittest.main()
+Index: python-odf-0.9.7/tests/testdatastyles.py
+===================================================================
+--- python-odf-0.9.7.orig/tests/testdatastyles.py
++++ python-odf-0.9.7/tests/testdatastyles.py
+@@ -33,7 +33,7 @@ class TestDatastyles(unittest.TestCase):
+ 
+     def tearDown(self):
+         if self.saved:
+-            os.unlink("TEST.odt")
++            os.unlink("TEST.ods")
+         
+     def test_percentage(self):
+         """ Test that an automatic style can refer to a PercentageStyle as a datastylename """
+@@ -53,13 +53,13 @@ class TestDatastyles(unittest.TestCase):
+         tr.addElement(tc)
+         table.addElement(tr)
+         doc.spreadsheet.addElement(table)
+-        doc.save("TEST.odt")
++        doc.save("TEST.ods")
+         self.saved = True
+-        d = load("TEST.odt")
++        d = load("TEST.ods")
+         result = d.contentxml()
+-        self.assertNotEqual(-1, result.find(u'''<number:percentage-style'''))
+-        self.assertNotEqual(-1, result.find(u'''style:data-style-name="N11"'''))
+-        self.assertNotEqual(-1, result.find(u'''style:name="pourcent"'''))
++        self.assertNotEqual(-1, result.find('''<number:percentage-style'''))
++        self.assertNotEqual(-1, result.find('''style:data-style-name="N11"'''))
++        self.assertNotEqual(-1, result.find('''style:name="pourcent"'''))
+ 
+     def test_chart_style(self):
+         """ Test that chart:style-name reference is seen in content.xml """
+@@ -133,7 +133,7 @@ class TestDatastyles(unittest.TestCase):
+         yt.addElement(text.P(text="y_axis"))
+ 
+         result = doc.contentxml()
+-        self.assertNotEqual(-1, result.find(u'''style:family="chart"'''))
++        self.assertNotEqual(-1, result.find('''style:family="chart"'''))
+ 
+ if __name__ == '__main__':
+     unittest.main()

Added: packages/python-odf/trunk/debian/python-odf-doc.install
===================================================================
--- packages/python-odf/trunk/debian/python-odf-doc.install	                        (rev 0)
+++ packages/python-odf/trunk/debian/python-odf-doc.install	2014-10-21 09:54:57 UTC (rev 31190)
@@ -0,0 +1 @@
+api-for-odfpy.odt usr/share/doc/python-odf-doc/odt

Added: packages/python-odf/trunk/debian/python-odf.install
===================================================================
--- packages/python-odf/trunk/debian/python-odf.install	                        (rev 0)
+++ packages/python-odf/trunk/debian/python-odf.install	2014-10-21 09:54:57 UTC (rev 31190)
@@ -0,0 +1 @@
+build/lib.linux-x86_64-2.7/odf usr/lib/python2.7/dist-packages

Added: packages/python-odf/trunk/debian/python3-odf.install
===================================================================
--- packages/python-odf/trunk/debian/python3-odf.install	                        (rev 0)
+++ packages/python-odf/trunk/debian/python3-odf.install	2014-10-21 09:54:57 UTC (rev 31190)
@@ -0,0 +1,3 @@
+build/lib/odf usr/lib/python3/dist-packages
+build/scripts-3.4/* usr/bin
+usr/share/man/man1/*
\ No newline at end of file

Modified: packages/python-odf/trunk/debian/rules
===================================================================
--- packages/python-odf/trunk/debian/rules	2014-10-21 08:34:37 UTC (rev 31189)
+++ packages/python-odf/trunk/debian/rules	2014-10-21 09:54:57 UTC (rev 31190)
@@ -5,7 +5,7 @@
 PYTHON2=$(shell pyversions -vr)
 
 %:
-	dh $@ --with python2
+	dh $@ --with python2 --with python3
 
 ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
 test-python%:
@@ -18,10 +18,23 @@
 override_dh_auto_test: $(PYTHON2:%=test-python%)
 endif
 
+
+override_dh_clean:
+	# remove manfiles
+	for D in csv2ods mailodf odf2xhtml odf2mht odf2xml odfimgimport odflint odfmeta odfoutline odfuserfield xml2odf; do \
+		( cd $$D && \
+		rm -f $$D.1) \
+	done
+	# remove build space
+	rm -rf build
+	# remove generated symlinks
+	rm -f tests/odf
+	dh_clean
+
 override_dh_auto_build:
 	for D in csv2ods mailodf odf2xhtml odf2mht odf2xml odfimgimport odflint odfmeta odfoutline odfuserfield xml2odf; do \
 		( cd $$D && \
-		rm $$D.1 && \
 		$(MAKE) ) \
 	done
-	dh_auto_build
+	python setup.py build
+	python3 setup.py build




More information about the Python-modules-commits mailing list