second stage of port to Python 3.3; working hello world py33
authorrptlab
Tue, 30 Apr 2013 14:28:14 +0100
branchpy33
changeset 3723 99aa837b6703
parent 3722 29c11b905751
child 3724 8c3d733474a0
second stage of port to Python 3.3; working hello world
docs/userguide/ch5_paragraphs.py
src/reportlab/graphics/barcode/code128.py
src/reportlab/graphics/barcode/code93.py
src/reportlab/graphics/barcode/common.py
src/reportlab/graphics/barcode/usps.py
src/reportlab/graphics/charts/textlabels.py
src/reportlab/graphics/renderPDF.py
src/reportlab/graphics/renderPM.py
src/reportlab/graphics/renderPS.py
src/reportlab/graphics/renderSVG.py
src/reportlab/graphics/renderbase.py
src/reportlab/graphics/shapes.py
src/reportlab/graphics/widgetbase.py
src/reportlab/graphics/widgets/table.py
src/reportlab/lib/attrmap.py
src/reportlab/lib/colors.py
src/reportlab/lib/fontfinder.py
src/reportlab/lib/fonts.py
src/reportlab/lib/pdfencrypt.py
src/reportlab/lib/rparsexml.py
src/reportlab/lib/styles.py
src/reportlab/lib/utils.py
src/reportlab/lib/xmllib.py
src/reportlab/pdfbase/_can_cmap_data.py
src/reportlab/pdfbase/_fontdata.py
src/reportlab/pdfbase/cidfonts.py
src/reportlab/pdfbase/pdfdoc.py
src/reportlab/pdfbase/pdfform.py
src/reportlab/pdfbase/pdfmetrics.py
src/reportlab/pdfbase/pdfutils.py
src/reportlab/pdfbase/ttfonts.py
src/reportlab/pdfgen/canvas.py
src/reportlab/pdfgen/pdfimages.py
src/reportlab/pdfgen/pycanvas.py
src/reportlab/pdfgen/textobject.py
src/reportlab/platypus/doctemplate.py
src/reportlab/platypus/para.py
src/reportlab/platypus/paraparser.py
src/reportlab/platypus/tables.py
tests/test_lib_utils.py
tests/test_rl_accel.py
tools/docco/examples.py
tools/docco/graphdocpy.py
tools/docco/rl_doc_utils.py
tools/docco/t_parse.py
tools/pythonpoint/demos/examples.py
tools/pythonpoint/pythonpoint.py
tools/pythonpoint/stdparser.py
--- a/docs/userguide/ch5_paragraphs.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/docs/userguide/ch5_paragraphs.py	Tue Apr 30 14:28:14 2013 +0100
@@ -188,7 +188,7 @@
 def getAttrs(A):
     _addAttributeNames(A)
     S={}
-    for k, v in list(A.items()):
+    for k, v in A.items():
         a = v[0]
         if a not in S:
             S[a] = k
--- a/src/reportlab/graphics/barcode/code128.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/graphics/barcode/code128.py	Tue Apr 30 14:28:14 2013 +0100
@@ -223,7 +223,7 @@
         if type(value) is type(1):
             value = str(value)
             
-        for (k, v) in list(args.items()):
+        for k, v in args.items():
             setattr(self, k, v)
 
         if self.quiet:
--- a/src/reportlab/graphics/barcode/code93.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/graphics/barcode/code93.py	Tue Apr 30 14:28:14 2013 +0100
@@ -55,7 +55,7 @@
 }
 
 _charsbyval = {}
-for k, v in list(_patterns.items()):
+for k, v in _patterns.items():
     _charsbyval[v[1]] = k
 
 _extended = {
--- a/src/reportlab/graphics/barcode/common.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/graphics/barcode/common.py	Tue Apr 30 14:28:14 2013 +0100
@@ -308,7 +308,7 @@
         if type(value) == type(1):
             value = str(value)
 
-        for (k, v) in list(args.items()):
+        for k, v in args.items():
             setattr(self, k, v)
 
         if self.quiet:
@@ -433,7 +433,7 @@
         if type(value) == type(1):
             value = str(value)
 
-        for (k, v) in list(args.items()):
+        for k, v in args.items():
             setattr(self, k, v)
 
         if self.quiet:
@@ -569,7 +569,7 @@
         if type(value) == type(1):
             value = str(value)
 
-        for (k, v) in list(args.items()):
+        for k, v in args.items():
             setattr(self, k, v)
 
         if self.quiet:
@@ -689,7 +689,7 @@
         if type(value) == type(1):
             value = str(value)
 
-        for (k, v) in list(args.items()):
+        for k, v in args.items():
             setattr(self, k, v)
 
         if self.quiet:
--- a/src/reportlab/graphics/barcode/usps.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/graphics/barcode/usps.py	Tue Apr 30 14:28:14 2013 +0100
@@ -97,7 +97,7 @@
     lquiet = inch * (15.0/32.0)
     quiet = 0
     def __init__(self, value='', **args):
-        for (k, v) in list(args.items()):
+        for k, v in args.items():
             setattr(self, k, v)
 
         Barcode.__init__(self, value)
@@ -109,7 +109,7 @@
             if c in string.whitespace:
                 continue
             elif c in "abcdABCD":
-                self.validated = self.validated + string.upper(c)
+                self.validated = self.validated + c.upper()
             else:
                 self.valid = 0
 
@@ -162,7 +162,7 @@
     spaceWidth = inch * 0.0275
     def __init__(self, value='', **args):
 
-        for (k, v) in list(args.items()):
+        for k, v in args.items():
             setattr(self, k, v)
 
         Barcode.__init__(self, value)
@@ -193,7 +193,7 @@
         for c in self.validated:
             if c in string.digits:
                 self.encoded = self.encoded + c
-                check = check + string.atoi(c)
+                check = check + int(c)
             elif c == '-':
                 pass
             else:
--- a/src/reportlab/graphics/charts/textlabels.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/graphics/charts/textlabels.py	Tue Apr 30 14:28:14 2013 +0100
@@ -344,7 +344,7 @@
     def __init__(self):
         self.textAnchor = 'start'
         self.boxAnchor = 'w'
-        for a in list(self._attrMap.keys()):
+        for a in self._attrMap.keys():
             if not hasattr(self,a): setattr(self,a,None)
 
     def decorate(self,l,L):
@@ -355,7 +355,7 @@
     def __call__(self,l):
         from copy import deepcopy
         L = Label()
-        for a,v in list(self.__dict__.items()):
+        for a,v in self.__dict__.items():
             if v is None: v = getattr(l,a,None)
             setattr(L,a,v)
         self.decorate(l,L)
--- a/src/reportlab/graphics/renderPDF.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/graphics/renderPDF.py	Tue Apr 30 14:28:14 2013 +0100
@@ -18,7 +18,7 @@
 from reportlab.graphics.shapes import *
 from reportlab.pdfgen.canvas import Canvas
 from reportlab.pdfbase.pdfmetrics import stringWidth
-from reportlab.lib.utils import getStringIO
+from reportlab.lib.utils import getBytesIO
 from reportlab import rl_config
 from .renderbase import Renderer, StateTracker, getStateDelta, renderScaledDrawing
 
@@ -195,7 +195,7 @@
     def applyStateChanges(self, delta, newState):
         """This takes a set of states, and outputs the PDF operators
         needed to set those properties"""
-        for key, value in list(delta.items()):
+        for key, value in delta.items():
             if key == 'transform':
                 self._canvas.transform(value[0], value[1], value[2],
                                  value[3], value[4], value[5])
@@ -303,7 +303,7 @@
 
 def drawToString(d, msg="", showBoundary=rl_config._unset_,autoSize=1):
     "Returns a PDF as a string in memory, without touching the disk"
-    s = getStringIO()
+    s = getBytesIO()
     drawToFile(d, s, msg=msg, showBoundary=showBoundary,autoSize=autoSize)
     return s.getvalue()
 
--- a/src/reportlab/graphics/renderPM.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/graphics/renderPM.py	Tue Apr 30 14:28:14 2013 +0100
@@ -16,7 +16,7 @@
 from reportlab.graphics.renderbase import StateTracker, getStateDelta, renderScaledDrawing
 from reportlab.pdfbase.pdfmetrics import getFont, unicode2T1
 from math import sin, cos, pi, ceil
-from reportlab.lib.utils import getStringIO, open_and_read
+from reportlab.lib.utils import getBytesIO, open_and_read
 from reportlab import rl_config
 
 class RenderPMError(Exception):
@@ -274,11 +274,11 @@
         A = {'ctm':None, 'strokeWidth':None, 'strokeColor':None, 'lineCap':None, 'lineJoin':None, 'dashArray':None, 'fillColor':None}
         gs = self._gs
         fN,fS = gs.fontName, gs.fontSize
-        for k in list(A.keys()):
+        for k in A.keys():
             A[k] = getattr(gs,k)
         del gs, self._gs
         gs = self.__dict__['_gs'] = _renderPM.gstate(w,h,bg=bg)
-        for k in list(A.keys()):
+        for k in A.keys():
             setattr(self,k,A[k])
         gs.setFont(fN,fS)
 
@@ -355,7 +355,7 @@
             markfilename(fn,ext=fmt)
 
     def saveToString(self,fmt='GIF'):
-        s = getStringIO()
+        s = getBytesIO()
         self.saveToFile(s,fmt=fmt)
         return s.getvalue()
 
@@ -661,7 +661,7 @@
     c.saveToFile(fn,fmt)
 
 def drawToString(d,fmt='GIF', dpi=72, bg=0xffffff, configPIL=None, showBoundary=rl_config._unset_):
-    s = getStringIO()
+    s = getBytesIO()
     drawToFile(d,s,fmt=fmt, dpi=dpi, bg=bg, configPIL=configPIL)
     return s.getvalue()
 
--- a/src/reportlab/graphics/renderPS.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/graphics/renderPS.py	Tue Apr 30 14:28:14 2013 +0100
@@ -6,7 +6,7 @@
 
 import string, types
 from reportlab.pdfbase.pdfmetrics import getFont, stringWidth, unicode2T1 # for font info
-from reportlab.lib.utils import fp_str, getStringIO
+from reportlab.lib.utils import fp_str, getBytesIO
 from reportlab.lib.colors import black
 from reportlab.graphics.renderbase import Renderer, StateTracker, getStateDelta, renderScaledDrawing
 from reportlab.graphics.shapes import STATE_DEFAULTS
@@ -589,7 +589,7 @@
         hex_encoded = self._AsciiHexEncode(rawimage)
 
         # write in blocks of 78 chars per line
-        outstream = getStringIO(hex_encoded)
+        outstream = getBytesIO(hex_encoded)
 
         dataline = outstream.read(78)
         while dataline != "":
@@ -601,7 +601,7 @@
     # end of drawImage
     def _AsciiHexEncode(self, input):  # also based on piddlePDF
         "Helper function used by images"
-        output = getStringIO()
+        output = getBytesIO()
         for char in input:
             output.write('%02x' % ord(char))
         return output.getvalue()
@@ -659,7 +659,7 @@
         hex_encoded = self._AsciiHexEncode(rawimage)
 
         # write in blocks of 78 chars per line
-        outstream = getStringIO(hex_encoded)
+        outstream = getBytesIO(hex_encoded)
 
         dataline = outstream.read(78)
         while dataline != "":
@@ -726,7 +726,7 @@
         self._canvas._color = color
 
         #restore things we might have lost (without actually doing anything).
-        for k, v in list(rDeltas.items()):
+        for k, v in rDeltas.items():
             if k in self._restores:
                 setattr(self._canvas,self._restores[k],v)
 
@@ -816,7 +816,7 @@
     def applyStateChanges(self, delta, newState):
         """This takes a set of states, and outputs the operators
         needed to set those properties"""
-        for key, value in list(delta.items()):
+        for key, value in delta.items():
             if key == 'transform':
                 self._canvas.transform(value[0], value[1], value[2],
                                  value[3], value[4], value[5])
@@ -879,7 +879,7 @@
 
 def drawToString(d, showBoundary=rl_config.showBoundary):
     "Returns a PS as a string in memory, without touching the disk"
-    s = getStringIO()
+    s = getBytesIO()
     drawToFile(d, s, showBoundary=showBoundary)
     return s.getvalue()
 
--- a/src/reportlab/graphics/renderSVG.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/graphics/renderSVG.py	Tue Apr 30 14:28:14 2013 +0100
@@ -17,7 +17,7 @@
 from reportlab.graphics.shapes import STATE_DEFAULTS, Path, UserNode
 from reportlab.graphics.shapes import * # (only for test0)
 from reportlab import rl_config
-from reportlab.lib.utils import getStringIO, RLString
+from reportlab.lib.utils import getBytesIO, RLString
 
 from xml.dom import getDOMImplementation
 
@@ -34,7 +34,7 @@
 ### top-level user function ###
 def drawToString(d, showBoundary=rl_config.showBoundary,**kwds):
     "Returns a SVG as a string in memory, without touching the disk"
-    s = getStringIO()
+    s = getBytesIO()
     drawToFile(d, s, showBoundary=showBoundary,**kwds)
     return s.getvalue()
 
@@ -83,7 +83,7 @@
     """
 
     newNode = doc.createElement(newTag)
-    for newAttr, attr in list(attrDict.items()):
+    for newAttr, attr in attrDict.items():
         sattr =  str(attr)
         if not node:
             newNode.setAttribute(newAttr, sattr)
@@ -709,7 +709,7 @@
         self._canvas._color = color
 
         #restore things we might have lost (without actually doing anything).
-        for k, v in list(rDeltas.items()):
+        for k, v in rDeltas.items():
             if k in self._restores:
                 setattr(self._canvas,self._restores[k],v)
         self._canvas.style = style
@@ -850,7 +850,7 @@
         """This takes a set of states, and outputs the operators
         needed to set those properties"""
 
-        for key, value in list(delta.items()):
+        for key, value in delta.items():
             if key == 'transform':
                 pass
                 #self._canvas.transform(value[0], value[1], value[2], value[3], value[4], value[5])
--- a/src/reportlab/graphics/renderbase.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/graphics/renderbase.py	Tue Apr 30 14:28:14 2013 +0100
@@ -37,7 +37,7 @@
     to set the pen color to red in between. Returns the effect
     the given shape would have on the graphics state"""
     delta = {}
-    for (prop, value) in list(shape.getProperties().items()):
+    for prop, value in shape.getProperties().items():
         if prop in STATE_DEFAULTS:
             delta[prop] = value
     return delta
@@ -72,7 +72,7 @@
         through getState()"""
 
         newstate = self._combined[-1].copy()
-        for (key, value) in list(delta.items()):
+        for key, value in delta.items():
             if key == 'transform':  #do cumulative matrix
                 newstate['transform'] = delta['transform']
                 newstate['ctm'] = mmult(self._combined[-1]['ctm'], delta['transform'])
@@ -97,7 +97,7 @@
         #need to diff this against the last one in the state
         reverseDelta = {}
         #print 'pop()...'
-        for key, curValue in list(lastDelta.items()):
+        for key, curValue in lastDelta.items():
             #print '   key=%s, value=%s' % (key, curValue)
             prevValue = newState[key]
             if prevValue != curValue:
@@ -230,7 +230,7 @@
         parent.
         
         """
-        for (key, value) in list(node.__dict__.items()):
+        for key, value in node.__dict__.items():
             if isinstance(value, DerivedValue):
                 #just replace with default for key?
                 #print '    fillDerivedValues(%s)' % key
--- a/src/reportlab/graphics/shapes.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/graphics/shapes.py	Tue Apr 30 14:28:14 2013 +0100
@@ -183,7 +183,7 @@
 class _SetKeyWordArgs:
     def __init__(self, keywords={}):
         """In general properties may be supplied to the constructor."""
-        for key, value in list(keywords.items()):
+        for key, value in keywords.items():
             setattr(self, key, value)
 
 
@@ -308,7 +308,7 @@
         #for more complex objects like widgets you
         #may need to override this.
         props = {}
-        for key, value in list(self.__dict__.items()):
+        for key, value in self.__dict__.items():
             if key[0:1] != '_':
                 props[key] = value
         return props
@@ -341,10 +341,10 @@
         an informative exception."""
 
         if self._attrMap is not None:
-            for key in list(self.__dict__.keys()):
+            for key in self.__dict__.keys():
                 if key[0] != '_':
                     assert key in self._attrMap, "Unexpected attribute %s found in %s" % (key, self)
-            for (attr, metavalue) in list(self._attrMap.items()):
+            for attr, metavalue in self._attrMap.items():
                 assert hasattr(self, attr), "Missing attribute %s from %s" % (attr, self)
                 value = getattr(self, attr)
                 assert metavalue.validate(value), "Invalid value %s for attribute %s in class %s" % (value, attr, self.__class__.__name__)
@@ -474,7 +474,7 @@
         from copy import copy
         self_contents = self.contents
         if not aKeys: aKeys = list(self._attrMap.keys())
-        for (k, v) in list(self.__dict__.items()):
+        for k, v in self.__dict__.items():
             if v in self_contents:
                 pos = self_contents.index(v)
                 setattr(obj, k, obj.contents[pos])
@@ -578,7 +578,7 @@
                 v = P[n]
                 del P[n]
                 s = s + '%s,' % _repr(v,I)
-            for n,v in list(P.items()):
+            for n,v in P.items():
                 v = P[n]
                 s = s + '%s=%s,' % (n, _repr(v,I))
             return s[:-1]+')'
@@ -617,7 +617,7 @@
     kw.update(self.__dict__)
     R = {}
     n = len(pfx)
-    for k in list(kw.keys()):
+    for k in kw.keys():
         if k.startswith(pfx):
             R[k[n:]] = kw[k]
     return R
@@ -661,7 +661,7 @@
         G = _renderGroupPy(self._explode(),'self',I)
         n = 'ExplodedDrawing_' + self.__class__.__name__
         s = '#Autogenerated by ReportLab guiedit do not edit\n'
-        for m, o in list(I.items()):
+        for m, o in I.items():
             s = s + 'from %s import %s\n' % (m,string.replace(str(o)[1:-1],"'",""))
         s = s + '\nclass %s(_DrawingEditorMixin,Drawing):\n' % n
         s = s + '\tdef __init__(self,width=%s,height=%s,*args,**kw):\n' % (self.width,self.height)
--- a/src/reportlab/graphics/widgetbase.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/graphics/widgetbase.py	Tue Apr 30 14:28:14 2013 +0100
@@ -27,11 +27,11 @@
         """
 
         if self._attrMap is not None:
-            for key in list(self.__dict__.keys()):
+            for key in self.__dict__.keys():
                 if key[0] != '_':
                     msg = "Unexpected attribute %s found in %s" % (key, self)
                     assert key in self._attrMap, msg
-            for (attr, metavalue) in list(self._attrMap.items()):
+            for attr, metavalue in self._attrMap.items():
                 msg = "Missing attribute %s from %s" % (attr, self)
                 assert hasattr(self, attr), msg
                 value = getattr(self, attr)
@@ -64,14 +64,14 @@
         # expose sequence contents?
 
         props = {}
-        for name in list(self.__dict__.keys()):
+        for name in self.__dict__.keys():
             if name[0:1] != '_':
                 component = getattr(self, name)
 
                 if recur and isValidChild(component):
                     # child object, get its properties too
                     childProps = component.getProperties(recur=recur)
-                    for (childKey, childValue) in list(childProps.items()):
+                    for childKey, childValue in childProps.items():
                         #key might be something indexed like '[2].fillColor'
                         #or simple like 'fillColor'; in the former case we
                         #don't need a '.' between me and my child.
@@ -98,7 +98,7 @@
         """
 
         childPropDicts = {}
-        for (name, value) in list(propDict.items()):
+        for name, value in propDict.items():
             parts = string.split(name, '.', 1)
             if len(parts) == 1:
                 #simple attribute, set it now
@@ -111,7 +111,7 @@
                     childPropDicts[childName] = {remains: value}
 
         # now assign to children
-        for (childName, childPropDict) in list(childPropDicts.items()):
+        for childName, childPropDict in childPropDicts.items():
             child = getattr(self, childName)
             child.setProperties(childPropDict)
 
@@ -136,7 +136,7 @@
     widgets and vice versa."""
 
     def _setKeywords(self,**kw):
-        for k,v in list(kw.items()):
+        for k,v in kw.items():
             if k not in self.__dict__:
                 setattr(self,k,v)
 
@@ -273,19 +273,19 @@
         # differs from the parent
         props = {}
 
-        for (key, value) in list(self._value.getProperties(recur=recur).items()):
+        for key, value in self._value.getProperties(recur=recur).items():
             props['%s' % key] = value
 
-        for idx in list(self._children.keys()):
+        for idx in self._children.keys():
             childProps = self._children[idx].getProperties(recur=recur)
-            for (key, value) in list(childProps.items()):
+            for key, value in childProps.items():
                 if not hasattr(self,key) or getattr(self, key)!=value:
                     newKey = '[%s].%s' % (idx, key)
                     props[newKey] = value
         return props
 
     def setVector(self,**kw):
-        for name, value in list(kw.items()):
+        for name, value in kw.items():
             for i in range(len(value)):
                 setattr(self[i],name,value[i])
 
@@ -333,7 +333,7 @@
     def __init__(self, **kwargs):
         "Initialize with attributes if any."
 
-        for k, v in list(kwargs.items()):
+        for k, v in kwargs.items():
             setattr(self, k, v)
 
 
--- a/src/reportlab/graphics/widgets/table.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/graphics/widgets/table.py	Tue Apr 30 14:28:14 2013 +0100
@@ -62,7 +62,7 @@
         self.textAnchor = 'start'
 
 
-        for k, v in list(kw.items()):
+        for k, v in kw.items():
             if k in list(self.__class__._attrMap.keys()):
                 setattr(self, k, v)
                 print('setting %s = %s'%(k, v))
--- a/src/reportlab/lib/attrmap.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/lib/attrmap.py	Tue Apr 30 14:28:14 2013 +0100
@@ -28,7 +28,6 @@
 
 
 '''
-from UserDict import UserDict
 from reportlab.lib.validators import isAnything, _SequenceTypes, DerivedValue
 from reportlab import rl_config
 
@@ -50,7 +49,7 @@
         self.desc = desc
         self._initial = initial
         self._advancedUsage = advancedUsage
-        for k,v in list(kw.items()):
+        for k,v in kw.items():
             setattr(self,k,v)
 
     def __getattr__(self,name):
@@ -65,7 +64,7 @@
     def __repr__(self):
         return 'AttrMapValue(%s)' % ', '.join(['%s=%r' % i for i in self.__dict__.items()])
 
-class AttrMap(UserDict):
+class AttrMap(dict):
     def __init__(self,BASE=None,UNWANTED=[],**kw):
         data = {}
         if BASE:
@@ -79,7 +78,7 @@
                     else:
                         raise ValueError('BASE=%s has wrong kind of value' % str(B))
 
-        UserDict.__init__(self,data)
+        dict.__init__(self,data)
         self.remove(UNWANTED)
         self.data.update(kw)
 
--- a/src/reportlab/lib/colors.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/lib/colors.py	Tue Apr 30 14:28:14 2013 +0100
@@ -706,7 +706,7 @@
     if _namedColors is not None: return _namedColors
     from . import colors
     _namedColors = {}
-    for (name, value) in list(colors.__dict__.items()):
+    for name, value in colors.__dict__.items():
         if isinstance(value, Color):
             _namedColors[name] = value
 
@@ -720,7 +720,7 @@
     '''
     namedColors = getAllNamedColors()
     closest = (10, None, None)  #big number, name, color
-    for (name, color) in list(namedColors.items()):
+    for name, color in namedColors.items():
         distance = colorDistance(aColor, color)
         if distance < closest[0]:
             closest = (distance, name, color)
@@ -874,7 +874,7 @@
     assigned = {}
     while kw and progress:
         progress = 0
-        for k, v in list(kw.items()):
+        for k, v in kw.items():
             if isinstance(v,(tuple,list)):
                 c = list(map(lambda x,UNDEF=UNDEF: toColor(x,UNDEF),v))
                 if isinstance(v,tuple): c = tuple(c)
@@ -889,7 +889,7 @@
 
     if kw: raise ValueError("Can't convert\n%s" % str(kw))
     getAllNamedColors()
-    for k, c in list(assigned.items()):
+    for k, c in assigned.items():
         globals()[k] = c
         if isinstance(c,Color): _namedColors[k] = c
 
--- a/src/reportlab/lib/fontfinder.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/lib/fontfinder.py	Tue Apr 30 14:28:14 2013 +0100
@@ -105,7 +105,7 @@
     def getTag(self):
         "Return an XML tag representation"
         attrs = []
-        for (k, v) in list(self.__dict__.items()):
+        for k, v in self.__dict__.items():
             if k not in ['timeModified']:
                 if v:
                     attrs.append('%s=%s' % (k, quoteattr(str(v))))
@@ -178,7 +178,7 @@
         selected = []
         for font in self._fonts:
             OK = True
-            for (k, v) in list(kwds.items()):
+            for k, v in kwds.items():
                 if getattr(font, k, None) != v:
                     OK = False
             if OK:
--- a/src/reportlab/lib/fonts.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/lib/fonts.py	Tue Apr 30 14:28:14 2013 +0100
@@ -63,7 +63,7 @@
             }
 
 _ps2tt_map={}
-for k,v in list(_tt2ps_map.items()):
+for k,v in _tt2ps_map.items():
     if k not in _ps2tt_map:
         _ps2tt_map[v.lower()] = k
 
--- a/src/reportlab/lib/pdfencrypt.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/lib/pdfencrypt.py	Tue Apr 30 14:28:14 2013 +0100
@@ -4,13 +4,13 @@
 
 """helpers for pdf encryption/decryption"""
 
-import string, sys, os
+import sys, os
 try:
     from hashlib import md5
 except ImportError:
     from md5 import md5
 
-from reportlab.lib.utils import getStringIO
+from reportlab.lib.utils import getBytesIO
 import tempfile
 
 from reportlab.pdfgen.canvas import Canvas
@@ -176,7 +176,7 @@
         return out
 
 def hexchar(x):
-    return chr(string.atoi(x, 16))
+    return chr(int(x, 16))
 
 def hexText(text):
     "a legitimate way to show strings in PDF"
@@ -196,7 +196,7 @@
         out = out + char
     return out
 
-PadString = string.join(list(map(hexchar, string.split(string.strip(padding)))), "")
+PadString = ''.join(map(hexchar, padding.strip().split()))
 
 def encryptionkey(password, OwnerKey, Permissions, FileId1, revision=2):
     # FileId1 is first string of the fileid array
@@ -408,7 +408,7 @@
     firstPageSize = bboxInfo['PageForms0'][2:]
 
     #now make a new PDF document
-    buf = getStringIO()
+    buf = getBytesIO()
     canv = Canvas(buf, pagesize=firstPageSize)
 
     # set a standard ID while debugging
--- a/src/reportlab/lib/rparsexml.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/lib/rparsexml.py	Tue Apr 30 14:28:14 2013 +0100
@@ -382,7 +382,7 @@
     if not attdict: attdict={}
     join = string.join
     attlist = []
-    for k in list(attdict.keys()):
+    for k in attdict.keys():
         v = attdict[k]
         attlist.append("%s=%s" % (k, repr(v)))
     attributes = join(attlist, " ")
--- a/src/reportlab/lib/styles.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/lib/styles.py	Tue Apr 30 14:28:14 2013 +0100
@@ -62,7 +62,7 @@
 
     def _setKwds(self,**kw):
         #step three - copy keywords if any
-        for (key, value) in list(kw.items()):
+        for key, value in kw.items():
              self.__dict__[key] = value
 
     def __repr__(self):
@@ -73,7 +73,7 @@
         use if you have been hacking the styles.  This is
         used by __init__"""
         if self.parent:
-            for (key, value) in list(self.parent.__dict__.items()):
+            for key, value in self.parent.__dict__.items():
                 if (key not in ['name','parent']):
                     self.__dict__[key] = value
 
--- a/src/reportlab/lib/utils.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/lib/utils.py	Tue Apr 30 14:28:14 2013 +0100
@@ -5,20 +5,13 @@
 __doc__='''Gazillions of miscellaneous internal utility functions'''
 
 import os, sys, imp, time
-try:
-    from hashlib import md5
-except:
-    from md5 import md5
+import base64
+import pickle
+from io import BytesIO
+import hashlib
 from reportlab.lib.logger import warnOnce
 from .rltempfile import get_rl_tempfile, get_rl_tempdir, _rl_getuid
 
-def isSeqType(v,_st=(tuple,list)):
-    return isinstance(v,_st)
-
-if sys.hexversion<0x2030000:
-    True = 1
-    False = 0
-
 if sys.hexversion >= 0x02000000:
     def _digester(s):
         return md5(s).hexdigest()
@@ -27,6 +20,56 @@
     def _digester(s):
         return join(["%02x" % ord(x) for x in md5(s).digest()], '')
 
+isPython3 = sys.version_info[0]==3
+
+def isFunctionType(v):
+    return type(v) == type(isFunctionType)
+
+class c:
+    def m(self): pass
+
+def isMethodType(v,mt=type(c.m)):
+    return type(v) == mt
+del c
+
+def isModuleType(v):
+    return type(v) == type(sys)
+
+def isSeqType(v,_st=(tuple,list)):
+    return isinstance(v,_st)
+
+if isPython3:
+    def UniChr(v):
+        return chr(v)
+
+    def isStrType(v):
+        return isinstance(v, str)
+
+    def isBytesType(v):
+        return isinstance(v, bytes)
+
+    def isUnicodeType(v):
+        return isinstance(v, str)
+
+    def isClassType(v):
+        return isinstance(v, type)
+else:
+    def UniChr(v):
+        return unichr(v)
+
+    def isStrType(v):
+        return isinstance(v, basestring)
+
+    def isBytesType(v):
+        return isinstance(v, str)
+
+    def isUnicodeType(v):
+        return isinstance(v, unicode)
+
+    def isClassType(v):
+        import types
+        return isinstance(v, types.ClassType)
+
 def _findFiles(dirList,ext='.ttf'):
     from os.path import isfile, isdir, join as path_join
     from os import listdir
@@ -40,39 +83,34 @@
             if isfile(fn) and (not ext or fn.lower().endswith(ext)): A(fn)
     return R
 
-try:
-    _UserDict = dict
-except:
-    from UserDict import UserDict as _UserDict
-
-class CIDict(_UserDict):
+class CIDict(dict):
     def __init__(self,*args,**kwds):
         for a in args: self.update(a)
         self.update(kwds)
 
     def update(self,D):
-        for k,v in list(D.items()): self[k] = v
+        for k,v in D.items(): self[k] = v
 
     def __setitem__(self,k,v):
         try:
             k = k.lower()
         except:
             pass
-        _UserDict.__setitem__(self,k,v)
+        dict.__setitem__(self,k,v)
 
     def __getitem__(self,k):
         try:
             k = k.lower()
         except:
             pass
-        return _UserDict.__getitem__(self,k)
+        return dict.__getitem__(self,k)
 
     def __delitem__(self,k):
         try:
             k = k.lower()
         except:
             pass
-        return _UserDict.__delitem__(self,k)
+        return dict.__delitem__(self,k)
 
     def get(self,k,dv=None):
         try:
@@ -92,14 +130,14 @@
             k = k.lower()
         except:
             pass
-        return _UserDict.pop(*((self,k)+a))
+        return dict.pop(*((self,k)+a))
 
     def setdefault(self,k,*a):
         try:
             k = k.lower()
         except:
             pass
-        return _UserDict.setdefault(*((self,k)+a))
+        return dict.setdefault(*((self,k)+a))
 
 if os.name == 'mac':
     #with the Mac, we need to tag the file in a special
@@ -255,52 +293,6 @@
     def fp_str(*a):
         return _FP_STR(*a).replace(',','.')
 
-def recursiveImport(modulename, baseDir=None, noCWD=0, debug=0):
-    """Dynamically imports possible packagized module, or raises ImportError"""
-    normalize = lambda x: os.path.normcase(os.path.abspath(os.path.normpath(x)))
-    path = list(map(normalize,sys.path))
-    if baseDir:
-        if not isSeqType(baseDir):
-            tp = [baseDir]
-        else:
-            tp = [_f for _f in list(baseDir) if _f]
-        for p in tp:
-            p = normalize(p)
-            if p not in path: path.insert(0,p)
-
-    if noCWD:
-        for p in ('','.',normalize('.')):
-            while p in path:
-                if debug: print('removed "%s" from path' % p)
-                path.remove(p)
-    elif '.' not in path:
-            path.insert(0,'.')
-
-    if debug:
-        import pprint
-        pp = pprint.pprint
-        print('path=', end=' ')
-        pp(path)
-
-    #make import errors a bit more informative
-    opath = sys.path
-    try:
-        sys.path = path
-        exec('import %s\nm = %s\n' % (modulename,modulename), locals())
-        sys.path = opath
-        return m
-    except ImportError:
-        sys.path = opath
-        msg = "Could not import '%s'" % modulename
-        if baseDir:
-            msg = msg + " under %s" % baseDir
-        raise ImportError(msg)
-
-    except Exception, e:
-        msg = "Exception raised while importing '%s': %s" % (modulename, e.message)
-        raise ImportError(msg)
-        
-
 def recursiveGetAttr(obj, name):
     "Can call down into e.g. object1.object2[4].attr"
     return eval(name, obj.__dict__)
@@ -347,14 +339,11 @@
             Image = None
     haveImages = Image is not None
 
-try:
-    from io import StringIO as __StringIO
-except ImportError:
-    from io import StringIO as __StringIO
-def getStringIO(buf=None):
+def getBytesIO(buf=None):
     '''unified StringIO instance interface'''
-    return buf is not None and __StringIO(buf) or __StringIO()
-_StringIOKlass=__StringIO().__class__
+    if buf:
+        return BytesIO(buf)
+    return BytesIO()
 
 class ArgvDictValue:
     '''A type to allow clients of getArgvDict to specify a conversion function'''
@@ -371,8 +360,7 @@
         if func:
             v = func(av)
         else:
-            if isinstance(v,str):
-                if isinstance(v,str): v = v.encode('utf8')
+            if isStrType(v):
                 v = av
             elif isinstance(v,float):
                 v = float(av)
@@ -388,7 +376,7 @@
 
     A = sys.argv[1:]
     R = {}
-    for k, v in list(kw.items()):
+    for k, v in kw.items():
         if isinstance(v,ArgvDictValue):
             v, func = v.value, v.func
         else:
@@ -437,20 +425,26 @@
         name = _startswith_rl(name)
         s = __loader__.get_data(name)
         if 'b' not in mode and os.linesep!='\n': s = s.replace(os.linesep,'\n')
-        return getStringIO(s)
+        return getBytesIO(s)
 
-import urllib.request, urllib.error, urllib.parse
-def open_for_read(name,mode='b', urlopen=urllib.request.urlopen):
+try:
+    import urllib2
+    urlopen=urllib2.urlopen
+except ImportError:
+    import urllib.request
+    urlopen=urllib.request.urlopen
+
+def open_for_read(name,mode='b', urlopen=urlopen):
     '''attempt to open a file or URL for reading'''
     if hasattr(name,'read'): return name
     try:
         return open_for_read_by_name(name,mode)
     except:
         try:
-            return getStringIO(urlopen(name).read())
+            return getBytesIO(urlopen(name).read())
         except:
             raise IOError('Cannot open resource "%s"' % name)
-del urllib2
+del urlopen
 
 def open_and_read(name,mode='b'):
     return open_for_read(name,mode).read()
@@ -476,7 +470,7 @@
     if os_path_isdir(pn) or _isFSD or __loader__ is None: return os_listdir(pn)
     pn = _startswith_rl(os_path_normpath(pn))
     if not pn.endswith(os.sep): pn += os.sep
-    return [x[len(pn):] for x in list(__loader__._files.keys()) if x.startswith(pn)]
+    return [x[len(pn):] for x in __loader__._files.keys() if x.startswith(pn)]
 
 def rl_getmtime(pn,os_path_isfile=os.path.isfile,os_path_normpath=os.path.normpath,os_path_getmtime=os.path.getmtime,time_mktime=time.mktime):
     if os_path_isfile(pn) or _isFSD or __loader__ is None: return os_path_getmtime(pn)
@@ -547,7 +541,7 @@
             try:
                 from reportlab.rl_config import imageReaderFlags
                 self.fp = open_for_read(fileName,'b')
-                if isinstance(self.fp,_StringIOKlass):  imageReaderFlags=0 #avoid messing with already internal files
+                if isinstance(self.fp,BytesIO): imageReaderFlags=0 #avoid messing with already internal files
                 if imageReaderFlags>0:  #interning
                     data = self.fp.read()
                     if imageReaderFlags&2:  #autoclose
@@ -560,7 +554,7 @@
                             from rl_config import register_reset
                             register_reset(self._cache.clear)
                         data=self._cache.setdefault(md5(data).digest(),data)
-                    self.fp=getStringIO(data)
+                    self.fp=getBytesIO(data)
                 elif imageReaderFlags==-1 and isinstance(fileName,str):
                     #try Ralf Schmitt's re-opening technique of avoiding too many open files
                     self.fp.close()
@@ -587,7 +581,7 @@
     def identity(self):
         '''try to return information that will identify the instance'''
         fn = self.fileName
-        if not isinstance(fn,str):
+        if not isStrType(fn):
             fn = getattr(getattr(self,'fp',None),'name',None)
         ident = self._ident
         return '[%s@%s%s%s]' % (self.__class__.__name__,hex(id(self)),ident and (' ident=%r' % ident) or '',fn and (' filename=%r' % fn) or '')
@@ -670,7 +664,10 @@
                     palette = palette.palette
                 except:
                     palette = palette.data
-                return list(map(ord, palette[transparency:transparency+3]))
+                if isPython3:
+                    return palette[transparency:transparency+3]
+                else:
+                    return [ord(c) for c in palette[transparency:transparency+3]]
             else:
                 return None
 
@@ -730,7 +727,7 @@
         self.store = store = {}
         if capture_traceback and sys.exc_info() != (None,None,None):
             import traceback
-            s = getStringIO()
+            s = getBytesIO()
             traceback.print_exc(None,s)
             store['__traceback'] = s.getvalue()
         cwd=os.getcwd()
@@ -763,7 +760,6 @@
                         'lcwd': lcwd,
                         'lpcwd': lpcwd,
                         'byteorder': sys.byteorder,
-                        'maxint': sys.maxsize,
                         'maxint': getattr(sys,'maxunicode','????'),
                         'api_version': getattr(sys,'api_version','????'),
                         'version_info': getattr(sys,'version_info','????'),
@@ -798,7 +794,7 @@
                 except:
                     pass
         module_versions = {}
-        for n,m in list(sys.modules.items()):
+        for n,m in sys.modules.items():
             if n=='reportlab' or n=='rlextra' or n[:10]=='reportlab.' or n[:8]=='rlextra.':
                 v = [getattr(m,x,None) for x in ('__version__','__path__','__file__')]
                 if [_f for _f in v if _f]:
@@ -810,20 +806,19 @@
 
     def _add(self,D):
         payload = self.store['__payload']
-        for k, v in list(D.items()):
+        for k, v in D.items():
             payload[k] = v
 
     def add(self,**kw):
         self._add(kw)
 
     def _dump(self,f):
-        import pickle
         try:
             pos=f.tell()
             pickle.dump(self.store,f)
         except:
             S=self.store.copy()
-            ff=getStringIO()
+            ff=getBytesIO()
             for k,v in S.items():
                 try:
                     pickle.dump({k:v},ff)
@@ -840,12 +835,11 @@
             f.close()
 
     def dumps(self):
-        f = getStringIO()
+        f = getBytesIO()
         self._dump(f)
         return f.getvalue()
 
     def _load(self,f):
-        import pickle
         self.store = pickle.load(f)
 
     def load(self):
@@ -856,7 +850,7 @@
             f.close()
 
     def loads(self,s):
-        self._load(getStringIO(s))
+        self._load(getBytesIO(s))
 
     def _show_module_versions(self,k,v):
         self._writeln(k[2:])
@@ -866,7 +860,8 @@
             vk = vk0 = v[k]
             if isinstance(vk,tuple): vk0 = vk[0]
             try:
-                m = recursiveImport(k,sys.path[:],1)
+                __import__(k)
+                m = sys.modules[k]
                 d = getattr(m,'__version__',None)==vk0 and 'SAME' or 'DIFFERENT'
             except:
                 m = None
@@ -902,7 +897,8 @@
         for mn in ('_rl_accel','_renderPM','sgmlop','pyRXP','pyRXPU','_imaging','Image'):
             try:
                 A = [mn].append
-                m = recursiveImport(mn,sys.path[:],1)
+                __import__(mn)
+                m = sys.modules[mn]
                 A(m.__file__)
                 for vn in ('__version__','VERSION','_version','version'):
                     if hasattr(m,vn):
@@ -1122,14 +1118,15 @@
             e = i
             break
     if e>=0:
-        if isinstance(a,str):
-            if not isinstance(msg,str):
-                msg=msg.decode(enc)
-        else:
-            if isinstance(msg,str):
-                msg=msg.encode(enc)
+        if not isPython3:
+            if isinstance(a,unicode):
+                if not isinstance(msg,unicode):
+                    msg=msg.decode(enc)
             else:
-                msg = str(msg)
+                if isinstance(msg,unicode):
+                    msg=msg.encode(enc)
+                else:
+                    msg = str(msg)
         if isinstance(v,IOError) and getattr(v,'strerror',None):
             v.strerror = msg+'\n'+str(v.strerror)
         else:
@@ -1166,6 +1163,18 @@
     data = data.replace("&amp;lt;", "&lt;")
     return data
 
+def encode_label(args):
+    s = base64.encodestring(pickle.dumps(args)).strip()
+    if not isStrType(s):
+        s = s.decode('utf-8')
+    return s
+
+def decode_label(label):
+    if isUnicodeType(label):
+        label = label.encode('utf-8')
+    v = pickle.loads(base64.decodestring(label))
+    return v
+    
 class IdentStr(str):
     '''useful for identifying things that get split'''
     def __new__(cls,value):
--- a/src/reportlab/lib/xmllib.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/lib/xmllib.py	Tue Apr 30 14:28:14 2013 +0100
@@ -8,7 +8,6 @@
 Probably ought to be removed'''
 
 import re
-import string
 
 try:
     import sgmlop   # this works for both builtin on the path or relative
@@ -116,7 +115,7 @@
             res = ref.search(data, i)
             if res is None:
                 newdata.append(data[i:])
-                return string.join(newdata, '')
+                return ''.join(newdata)
             if data[res.end(0) - 1] != ';':
                 self.syntax_error(self.lineno,
                                   '; missing after entity/char reference')
@@ -124,9 +123,9 @@
             str = res.group(1)
             if str[0] == '#':
                 if str[1] == 'x':
-                    newdata.append(chr(string.atoi(str[2:], 16)))
+                    newdata.append(chr(int(str[2:], 16)))
                 else:
-                    newdata.append(chr(string.atoi(str[1:])))
+                    newdata.append(chr(int(str[1:])))
             else:
                 try:
                     newdata.append(self.entitydefs[str])
@@ -146,7 +145,7 @@
             if self.nomoretags:
                 data = rawdata[i:n]
                 self.handle_data(data)
-                self.lineno = self.lineno + string.count(data, '\n')
+                self.lineno = self.lineno + '\n'.count(data)
                 i = n
                 break
             res = interesting.search(rawdata, i)
@@ -157,7 +156,7 @@
             if i < j:
                 data = rawdata[i:j]
                 self.handle_data(data)
-                self.lineno = self.lineno + string.count(data, '\n')
+                self.lineno = self.lineno + '\n'.count(data)
             i = j
             if i == n: break
             if rawdata[i] == '<':
@@ -165,18 +164,18 @@
                     if self.literal:
                         data = rawdata[i]
                         self.handle_data(data)
-                        self.lineno = self.lineno + string.count(data, '\n')
+                        self.lineno = self.lineno + '\n'.count(data)
                         i = i+1
                         continue
                     k = self.parse_starttag(i)
                     if k < 0: break
-                    self.lineno = self.lineno + string.count(rawdata[i:k], '\n')
+                    self.lineno = self.lineno + '\n'.count(rawdata[i:k])
                     i = k
                     continue
                 if endtagopen.match(rawdata, i):
                     k = self.parse_endtag(i)
                     if k < 0: break
-                    self.lineno = self.lineno + string.count(rawdata[i:k], '\n')
+                    self.lineno = self.lineno + '\n'.count(rawdata[i:k])
                     i =  k
                     self.literal = 0
                     continue
@@ -184,25 +183,25 @@
                     if self.literal:
                         data = rawdata[i]
                         self.handle_data(data)
-                        self.lineno = self.lineno + string.count(data, '\n')
+                        self.lineno = self.lineno + '\n'.count(data)
                         i = i+1
                         continue
                     k = self.parse_comment(i)
                     if k < 0: break
-                    self.lineno = self.lineno + string.count(rawdata[i:k], '\n')
+                    self.lineno = self.lineno + '\n'.count(rawdata[i:k])
                     i = k
                     continue
                 if cdataopen.match(rawdata, i):
                     k = self.parse_cdata(i)
                     if k < 0: break
-                    self.lineno = self.lineno + string.count(rawdata[i:i], '\n')
+                    self.lineno = self.lineno + '\n'.count(rawdata[i:i])
                     i = k
                     continue
                 res = procopen.match(rawdata, i)
                 if res:
                     k = self.parse_proc(i, res)
                     if k < 0: break
-                    self.lineno = self.lineno + string.count(rawdata[i:k], '\n')
+                    self.lineno = self.lineno + '\n'.count(rawdata[i:k])
                     i = k
                     continue
                 res = special.match(rawdata, i)
@@ -210,11 +209,11 @@
                     if self.literal:
                         data = rawdata[i]
                         self.handle_data(data)
-                        self.lineno = self.lineno + string.count(data, '\n')
+                        self.lineno = self.lineno + '\n'.count(data)
                         i = i+1
                         continue
                     self.handle_special(res.group('special'))
-                    self.lineno = self.lineno + string.count(res.group(0), '\n')
+                    self.lineno = self.lineno + '\n'.count(res.group(0))
                     i = res.end(0)
                     continue
             elif rawdata[i] == '&':
@@ -225,7 +224,7 @@
                         self.syntax_error(self.lineno, '; missing in charref')
                         i = i-1
                     self.handle_charref(res.group('char')[:-1])
-                    self.lineno = self.lineno + string.count(res.group(0), '\n')
+                    self.lineno = self.lineno + '\n'.count(res.group(0))
                     continue
                 res = entityref.match(rawdata, i)
                 if res is not None:
@@ -234,7 +233,7 @@
                         self.syntax_error(self.lineno, '; missing in entityref')
                         i = i-1
                     self.handle_entityref(res.group('name'))
-                    self.lineno = self.lineno + string.count(res.group(0), '\n')
+                    self.lineno = self.lineno + '\n'.count(res.group(0))
                     continue
             else:
                 raise RuntimeError('neither < nor & ??')
@@ -244,7 +243,7 @@
             if not res:
                 data = rawdata[i]
                 self.handle_data(data)
-                self.lineno = self.lineno + string.count(data, '\n')
+                self.lineno = self.lineno + '\n'.count(data)
                 i = i+1
                 continue
             j = res.end(0)
@@ -253,13 +252,13 @@
             self.syntax_error(self.lineno, 'bogus < or &')
             data = res.group(0)
             self.handle_data(data)
-            self.lineno = self.lineno + string.count(data, '\n')
+            self.lineno = self.lineno + '\n'.count(data)
             i = j
         # end while
         if end and i < n:
             data = rawdata[i:n]
             self.handle_data(data)
-            self.lineno = self.lineno + string.count(data, '\n')
+            self.lineno = self.lineno + '\n'.count(data)
             i = n
         self.rawdata = rawdata[i:]
         # XXX if end: check for empty stack
@@ -424,10 +423,10 @@
     def handle_charref(self, name):
         try:
             if name[0] == 'x':
-                n = string.atoi(name[1:], 16)
+                n = int(name[1:], 16)
             else:
-                n = string.atoi(name)
-        except string.atoi_error:
+                n = int(name)
+        except int_error:
             self.unknown_charref(name)
             return
         if not 0 <= n <= 255:
@@ -530,7 +529,7 @@
             res = ref.search(data, i)
             if res is None:
                 newdata.append(data[i:])
-                return string.join(newdata, '')
+                return ''.join(newdata)
             if data[res.end(0) - 1] != ';':
                 self.syntax_error(self.lineno,
                                   '; missing after entity/char reference')
@@ -538,9 +537,9 @@
             str = res.group(1)
             if str[0] == '#':
                 if str[1] == 'x':
-                    newdata.append(chr(string.atoi(str[2:], 16)))
+                    newdata.append(chr(int(str[2:], 16)))
                 else:
-                    newdata.append(chr(string.atoi(str[1:])))
+                    newdata.append(chr(int(str[1:])))
             else:
                 try:
                     newdata.append(self.entitydefs[str])
@@ -603,10 +602,10 @@
     def handle_charref(self, name):
         try:
             if name[0] == 'x':
-                n = string.atoi(name[1:], 16)
+                n = int(name[1:], 16)
             else:
-                n = string.atoi(name)
-        except string.atoi_error:
+                n = int(name)
+        except ValueError:
             self.unknown_charref(name)
             return
         if not 0 <= n <= 255:
@@ -713,7 +712,7 @@
             print('start tag: <' + tag + '>')
         else:
             print('start tag: <' + tag, end=' ')
-            for name, value in list(attrs.items()):
+            for name, value in attrs.items():
                 print(name + '=' + '"' + value + '"', end=' ')
             print('>')
 
--- a/src/reportlab/pdfbase/_can_cmap_data.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/pdfbase/_can_cmap_data.py	Tue Apr 30 14:28:14 2013 +0100
@@ -29,7 +29,7 @@
 
     buf = []
     buf.append('widthsByUnichar = {}')
-    for (fontName, (language, encName)) in list(defaultUnicodeEncodings.items()):
+    for fontName, (language, encName) in defaultUnicodeEncodings.items():
         print('handling %s : %s : %s' % (fontName, language, encName))
 
         #this does just about all of it for us, as all the info
@@ -39,7 +39,7 @@
         widthsByCID = font.face._explicitWidths
         cmap = font.encoding._cmap
         nonStandardWidthsByUnichar = {}
-        for (codePoint, cid) in list(cmap.items()):
+        for codePoint, cid in cmap.items():
             width = widthsByCID.get(cid, 1000)
             if width != 1000:
                 nonStandardWidthsByUnichar[chr(codePoint)] = width
--- a/src/reportlab/pdfbase/_fontdata.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/pdfbase/_fontdata.py	Tue Apr 30 14:28:14 2013 +0100
@@ -17,7 +17,7 @@
     as Jython cannot handle more than 64k of bytecode in the 'top level'
     code of a Python module.  
 """
-import UserDict, os, sys
+import os, sys
 
 # mapping of name to width vector, starts empty until fonts are added
 # e.g. widths['Courier'] = [...600,600,600,...]
@@ -88,8 +88,8 @@
                 'courier-oblique': 'Courier-Oblique',
                 }
     _font2fnrMap = _font2fnrMapLinux2
-    for k, v in list(_font2fnrMap.items()):
-        if k in list(_font2fnrMapWin32.keys()):
+    for k, v in _font2fnrMap.items():
+        if k in _font2fnrMapWin32.keys():
             _font2fnrMapWin32[v.lower()] = _font2fnrMapWin32[k]
     del k, v
 else:
@@ -130,21 +130,21 @@
 standardEncodings = ('WinAnsiEncoding','MacRomanEncoding','StandardEncoding','SymbolEncoding','ZapfDingbatsEncoding','PDFDocEncoding', 'MacExpertEncoding')
 
 #this is the global mapping of standard encodings to name vectors
-class _Name2StandardEncodingMap(UserDict.UserDict):
+class _Name2StandardEncodingMap(dict):
     '''Trivial fake dictionary with some [] magic'''
     _XMap = {'winansi':'WinAnsiEncoding','macroman': 'MacRomanEncoding','standard':'StandardEncoding','symbol':'SymbolEncoding', 'zapfdingbats':'ZapfDingbatsEncoding','pdfdoc':'PDFDocEncoding', 'macexpert':'MacExpertEncoding'}
     def __setitem__(self,x,v):
         y = x.lower()
         if y[-8:]=='encoding': y = y[:-8]
         y = self._XMap[y]
-        if y in list(self.keys()): raise IndexError('Encoding %s is already set' % y)
-        self.data[y] = v
+        if y in self: raise IndexError('Encoding %s is already set' % y)
+        dict.__setitem__(self,y,v)
 
     def __getitem__(self,x):
         y = x.lower()
         if y[-8:]=='encoding': y = y[:-8]
         y = self._XMap[y]
-        return self.data[y]
+        return dict.__getitem__(self,y)
 
 encodings = _Name2StandardEncodingMap()
 
@@ -153,11 +153,22 @@
 #well under 64k.  We might well be able to ditch many of
 #these anyway now we run on Unicode.
 
-for keyname in standardEncodings:
-    modname = '_fontdata_enc_%s' % keyname.lower()[:-8]  #chop off 'Encoding'
-    module = __import__(modname, globals(), locals())
-    encodings[keyname] = getattr(module, keyname)
-    
+from reportlab.pdfbase._fontdata_enc_winansi import WinAnsiEncoding
+from reportlab.pdfbase._fontdata_enc_macroman import MacRomanEncoding
+from reportlab.pdfbase._fontdata_enc_standard import StandardEncoding
+from reportlab.pdfbase._fontdata_enc_symbol import SymbolEncoding
+from reportlab.pdfbase._fontdata_enc_zapfdingbats import ZapfDingbatsEncoding
+from reportlab.pdfbase._fontdata_enc_pdfdoc import PDFDocEncoding
+from reportlab.pdfbase._fontdata_enc_macexpert import MacExpertEncoding
+encodings.update({
+    'WinAnsiEncoding': WinAnsiEncoding,
+    'MacRomanEncoding': MacRomanEncoding,
+    'StandardEncoding': StandardEncoding,
+    'SymbolEncoding': SymbolEncoding,
+    'ZapfDingbatsEncoding': ZapfDingbatsEncoding,
+    'PDFDocEncoding': PDFDocEncoding,
+    'MacExpertEncoding': MacExpertEncoding,
+})
 
 ascent_descent = {
     'Courier': (629, -157),
@@ -177,12 +188,50 @@
     }
 
 # ditto about 64k limit - profusion of external files
-widthsByFontGlyph = {}
-for fontName in standardFonts:
-    modname = '_fontdata_widths_%s' % fontName.lower().replace('-','')
-    module = __import__(modname, globals(), locals())
-    widthsByFontGlyph[fontName] = module.widths
-
+import reportlab.pdfbase._fontdata_widths_courier
+import reportlab.pdfbase._fontdata_widths_courierbold
+import reportlab.pdfbase._fontdata_widths_courieroblique
+import reportlab.pdfbase._fontdata_widths_courierboldoblique
+import reportlab.pdfbase._fontdata_widths_helvetica
+import reportlab.pdfbase._fontdata_widths_helveticabold
+import reportlab.pdfbase._fontdata_widths_helveticaoblique
+import reportlab.pdfbase._fontdata_widths_helveticaboldoblique
+import reportlab.pdfbase._fontdata_widths_timesroman
+import reportlab.pdfbase._fontdata_widths_timesbold
+import reportlab.pdfbase._fontdata_widths_timesitalic
+import reportlab.pdfbase._fontdata_widths_timesbolditalic
+import reportlab.pdfbase._fontdata_widths_symbol
+import reportlab.pdfbase._fontdata_widths_zapfdingbats
+widthsByFontGlyph = {
+    'Courier':
+    reportlab.pdfbase._fontdata_widths_courier.widths,
+    'Courier-Bold':
+    reportlab.pdfbase._fontdata_widths_courierbold.widths,
+    'Courier-Oblique':
+    reportlab.pdfbase._fontdata_widths_courieroblique.widths,
+    'Courier-BoldOblique':
+    reportlab.pdfbase._fontdata_widths_courierboldoblique.widths,
+    'Helvetica':
+    reportlab.pdfbase._fontdata_widths_helvetica.widths,
+    'Helvetica-Bold':
+    reportlab.pdfbase._fontdata_widths_helveticabold.widths,
+    'Helvetica-Oblique':
+    reportlab.pdfbase._fontdata_widths_helveticaoblique.widths,
+    'Helvetica-BoldOblique':
+    reportlab.pdfbase._fontdata_widths_helveticaboldoblique.widths,
+    'Times-Roman':
+    reportlab.pdfbase._fontdata_widths_timesroman.widths,
+    'Times-Bold':
+    reportlab.pdfbase._fontdata_widths_timesbold.widths,
+    'Times-Italic':
+    reportlab.pdfbase._fontdata_widths_timesitalic.widths,
+    'Times-BoldItalic':
+    reportlab.pdfbase._fontdata_widths_timesbolditalic.widths,
+    'Symbol':
+    reportlab.pdfbase._fontdata_widths_symbol.widths,
+    'ZapfDingbats':
+    reportlab.pdfbase._fontdata_widths_zapfdingbats.widths,
+}
 
 
 #preserve the initial values here
--- a/src/reportlab/pdfbase/cidfonts.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/pdfbase/cidfonts.py	Tue Apr 30 14:28:14 2013 +0100
@@ -46,7 +46,7 @@
     "Converts deeply nested structure to PDFdoc dictionary/array objects"
     if type(structure) is DictType:
         newDict = {}
-        for k, v in list(structure.items()):
+        for k, v in structure.items():
             newDict[k] = structToPDF(v)
         return pdfdoc.PDFDictionary(newDict)
     elif type(structure) in (ListType, TupleType):
--- a/src/reportlab/pdfbase/pdfdoc.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/pdfbase/pdfdoc.py	Tue Apr 30 14:28:14 2013 +0100
@@ -18,21 +18,12 @@
 from reportlab.pdfbase import pdfutils
 from reportlab.pdfbase.pdfutils import LINEEND # this constant needed in both
 from reportlab import rl_config
-from reportlab.lib.utils import import_zlib, open_for_read, fp_str, _digester, makeFileName
+from reportlab.lib.utils import import_zlib, open_for_read, fp_str, makeFileName, isSeqType, isBytesType, isUnicodeType, _digester
 from reportlab.pdfbase import pdfmetrics
-try:
-    from hashlib import md5
-except ImportError:
-    from md5 import md5
+from hashlib import md5
 
 from sys import platform
-try:
-    from sys import version_info
-except: # pre-2.0
-    # may be inaccurate but will at least
-    #work in anything which seeks to format
-    # version_info into a string
-    version_info = (1,5,2,'unknown',0)
+from sys import version_info
 
 if platform[:4] == 'java' and version_info[:2] == (2, 1):
     # workaround for list()-bug in Jython 2.1 (should be fixed in 2.2)
@@ -87,8 +78,7 @@
     transparency = (1, 4),
     )
 
-from types import InstanceType
-def format(element, document, toplevel=0, InstanceType=InstanceType):
+def format(element, document, toplevel=0):
     """Indirection step for formatting.
        Ensures that document parameters alter behaviour
        of formatting for all elements.
@@ -164,12 +154,16 @@
         self._pdfVersion = pdfVersion
         # signature for creating PDF ID
         sig = self.signature = md5()
-        sig.update("a reportlab document")
+        sig.update(b"a reportlab document")
         if not self.invariant:
             cat = _getTimeStamp()
         else:
             cat = 946684800.0
-        sig.update(repr(cat)) # initialize with timestamp digest
+        cat = repr(cat)
+        import sys
+        if sys.version_info[0] == 3:
+            cat = bytes(repr(cat), 'utf-8')
+        sig.update(cat) # initialize with timestamp digest
         # mapping of internal identifier ("Page001") to PDF objectnumber and generation number (34, 0)
         self.idToObjectNumberAndVersion = {}
         # mapping of internal identifier ("Page001") to PDF object (PDFPage instance)
@@ -233,14 +227,17 @@
             myfile = 1
             filename = makeFileName(filename)
             f = open(filename, "wb")
-        f.write(self.GetPDFData(canvas))
+        data = self.GetPDFData(canvas)
+        if isUnicodeType(data):
+            data = data.encode('utf8')
+        f.write(data)
         if myfile:
             f.close()
             import os
             if os.name=='mac':
                 from reportlab.lib.utils import markfilename
                 markfilename(filename) # do platform specific file junk
-        if getattr(canvas,'_verbosity',None): print('saved', filename)
+        if getattr(canvas,'_verbosity',None): print('saved %s' % (filename,))
 
     def GetPDFData(self, canvas):
         # realize delayed fonts
@@ -268,7 +265,7 @@
         """specify that we are in a form xobject (disable page features, etc)"""
         # don't need this check anymore since going in a form pushes old context at canvas level.
         #if self.inObject not in ["form", None]:
-        #    raise ValueError, "can't go in form already in object %s" % self.inObject
+        #    raise ValueError("can't go in form already in object %s" % self.inObject)
         self.inObject = "form"
         # don't need to do anything else, I think...
 
@@ -509,7 +506,7 @@
         #print "xobjDict D", D
         return PDFDictionary(D)
 
-    def Reference(self, object, name=None, InstanceType=InstanceType):
+    def Reference(self, object, name=None):
         ### note references may "grow" during the final formatting pass: don't use d.keys()!
         # don't make references to other references, or non instances, unless they are named!
         #print"object type is ", type(object)
@@ -553,8 +550,11 @@
     def __init__(self, t):
         self.t = t
     def format(self, document):
-        result = binascii.hexlify(document.encrypt.encode(self.t))
-        return "<%s>" % result
+        t = self.t
+        if isUnicodeType(t):
+            t = t.encode('utf-8')
+        result = binascii.hexlify(document.encrypt.encode(t))
+        return b"<" + result + b">"
     def __str__(self):
         dummydoc = DummyDoc()
         return self.format(dummydoc)
@@ -604,7 +604,7 @@
     def format(self, document):
         s = self.s
         enc = getattr(self,'enc','auto')
-        if type(s) is str:
+        if (isBytesType(s)):
             if enc is 'auto':
                 try:
                     u = s.decode(s.startswith(codecs.BOM_UTF16_BE) and 'utf16' or 'utf8')
@@ -616,10 +616,9 @@
                     try:
                         s.decode('pdfdoc')
                     except:
-                        import sys
-                        print('Error in',repr(s), file=sys.stderr)
+                        sys.stderr.write('Error in %s' % (repr(s),))
                         raise
-        elif type(s) is str:
+        elif isUnicodeType(s):
             if enc is 'auto':
                 if _checkPdfdoc(s):
                     s = s.encode('pdfdoc')
@@ -645,7 +644,7 @@
                 es = es.replace('\\(','(').replace('\\)',')')
             return es
         else:
-            return '(%s)' % s
+            return b'(' + s + b')'
     def __str__(self):
         return "(%s)" % pdfutils._escape(self.s)
 
@@ -756,6 +755,8 @@
         from reportlab.lib.utils import import_zlib
         zlib = import_zlib()
         if not zlib: raise ImportError("cannot z-compress zlib unavailable")
+        if isUnicodeType(text):
+            text = text.encode('utf8')
         return zlib.compress(text)
     def decode(self, encoded):
         from reportlab.lib.utils import import_zlib
@@ -841,7 +842,7 @@
     #content = "" # test
     if content is None:
         content = teststreamcontent
-    content = string.strip(content)
+    content = content.strip()
     content = string.replace(content, "\n", LINEEND) + LINEEND
     S = PDFStream(content = content,
                     filters=rl_config.useA85 and [PDFBase85Encode,PDFZCompress] or [PDFZCompress])
@@ -940,8 +941,8 @@
         self.write(s)
         return result
     def format(self, document):
-        strings = list(map(str, self.strings)) # final conversion, in case of lazy objects
-        return string.join(strings, "")
+        strings = map(str, self.strings) # final conversion, in case of lazy objects
+        return "".join(strings)
 
 XREFFMT = '%0.10d %0.5d n'
 
@@ -987,7 +988,7 @@
             reflineend = LINEEND
         else:
             raise ValueError("bad end of line! %s" % repr(LINEEND))
-        return string.join(entries, LINEEND)
+        return LINEEND.join(entries)
 
 class PDFCrossReferenceTable:
     __PDFObject__ = True
@@ -1005,7 +1006,7 @@
         for s in self.sections:
             fs = format(s, document)
             L.append(fs)
-        return string.join(L, "")
+        return "".join(L)
 
 TRAILERFMT = ("trailer%(LINEEND)s"
               "%(dict)s%(LINEEND)s"
@@ -1045,10 +1046,9 @@
     __Defaults__ = {"Type": PDFName("Catalog"),
                 "PageMode": PDFName("UseNone"),
                 }
-    __NoDefault__ = string.split("""
+    __NoDefault__ = """
         Dests Outlines Pages Threads AcroForm Names OpenAction PageMode URI
-        ViewerPreferences PageLabels PageLayout JavaScript StructTreeRoot SpiderInfo"""
-                                 )
+        ViewerPreferences PageLabels PageLayout JavaScript StructTreeRoot SpiderInfo""".split()
     __Refs__ = __NoDefault__ # make these all into references, if present
 
     def format(self, document):
@@ -1056,7 +1056,7 @@
         defaults = self.__Defaults__
         Refs = self.__Refs__
         D = {}
-        for k in list(defaults.keys()):
+        for k in defaults.keys():
             default = defaults[k]
             v = None
             if hasattr(self, k) and getattr(self,k) is not None:
@@ -1103,7 +1103,7 @@
     # note: could implement page attribute inheritance...
     __Defaults__ = {"Type": PDFName("Pages"),
                     }
-    __NoDefault__ = string.split("Kids Count Parent")
+    __NoDefault__ = "Kids Count Parent".split()
     __Refs__ = ["Parent"]
     def __init__(self):
         self.pages = []
@@ -1129,14 +1129,11 @@
     __Defaults__ = {"Type": PDFName("Page"),
                    # "Parent": PDFObjectReference(Pages),  # no! use document.Pages
                     }
-    __NoDefault__ = string.split(""" Parent
+    __NoDefault__ = """Parent
         MediaBox Resources Contents CropBox Rotate Thumb Annots B Dur Hid Trans AA
         PieceInfo LastModified SeparationInfo ArtBox TrimBox BleedBox ID PZ
-        Trans
-    """)
-    __Refs__ = string.split("""
-        Contents Parent ID
-    """)
+        Trans""".split()
+    __Refs__ = """Contents Parent ID""".split()
     pagewidth = 595
     pageheight = 842
     stream = None
@@ -1158,9 +1155,8 @@
     def setStream(self, code):
         if self.Override_default_compilation:
             raise ValueError("overridden! must set stream explicitly")
-        from types import ListType
-        if type(code) is ListType:
-            code = string.join(code, LINEEND)+LINEEND
+        if isSeqType(code):
+            code = LINEEND.join(code)+LINEEND
         self.stream = code
 
     def setPageTransition(self, tranDict):
@@ -1175,7 +1171,7 @@
             self.Annots = None
         else:
             #print self.Annots
-            #raise ValueError, "annotations not reimplemented yet"
+            #raise ValueError("annotations not reimplemented yet")
             if not hasattr(self.Annots,'__PDFObject__'):
                 self.Annots = PDFArray(self.Annots)
         if not self.Contents:
@@ -1341,7 +1337,7 @@
 class PDFOutlines0:
     __PDFObject__ = True
     __Comment__ = "TEST OUTLINE!"
-    text = string.replace(DUMMYOUTLINE, "\n", LINEEND)
+    text = DUMMYOUTLINE.replace("\n", LINEEND)
     __RefOnly__ = 1
     def format(self, document):
         return self.text
@@ -1396,10 +1392,9 @@
 
     def addOutlineEntry(self, destinationname, level=0, title=None, closed=None):
         """destinationname of None means "close the tree" """
-        from types import IntType, TupleType
         if destinationname is None and level!=0:
             raise ValueError("close tree must have level of 0")
-        if type(level) is not IntType: raise ValueError("level must be integer, got %s" % type(level))
+        if not isinstance(level,int): raise ValueError("level must be integer, got %s" % type(level))
         if level<0: raise ValueError("negative levels not allowed")
         if title is None: title = destinationname
         currentlevel = self.currentlevel
@@ -1417,7 +1412,7 @@
             del stack[-1]
             previous = stack[-1]
             lastinprevious = previous[-1]
-            if type(lastinprevious) is TupleType:
+            if isinstance(lastinprevious,tuple):
                 (name, sectionlist) = lastinprevious
                 raise ValueError("cannot reset existing sections: " + repr(lastinprevious))
             else:
@@ -1457,12 +1452,10 @@
 
     def translateNames(self, canvas, object):
         "recursively translate tree of names into tree of destinations"
-        from types import StringType, ListType, TupleType
-        Ot = type(object)
         destinationnamestotitles = self.destinationnamestotitles
         destinationstotitles = self.destinationstotitles
         closedict = self.closedict
-        if Ot is StringType:
+        if isStrType(object):
             destination = canvas._bookmarkReference(object)
             title = object
             if object in destinationnamestotitles:
@@ -1473,11 +1466,11 @@
             if object in closedict:
                 closedict[destination] = 1 # mark destination closed
             return {object: canvas._bookmarkReference(object)} # name-->ref
-        if Ot is ListType or Ot is TupleType:
+        if isSeqType(object):
             L = []
             for o in object:
                 L.append(self.translateNames(canvas, o))
-            if Ot is TupleType:
+            if isinstance(object,tuple):
                 return tuple(L)
             return L
         # bug contributed by Benjamin Dumke <reportlab@benjamin-dumke.de>
@@ -1504,8 +1497,6 @@
         self.ready = 1
 
     def maketree(self, document, destinationtree, Parent=None, toplevel=0):
-        from types import ListType, TupleType, DictType
-        tdestinationtree = type(destinationtree)
         if toplevel:
             levelname = "Outline"
             Parent = document.Reference(document.Outlines)
@@ -1514,7 +1505,7 @@
             levelname = "Outline.%s" % self.count
             if Parent is None:
                 raise ValueError("non-top level outline elt parent must be specified")
-        if tdestinationtree is not ListType and tdestinationtree is not TupleType:
+        if not isSeqType(destinationtree):
             raise ValueError("destinationtree must be list or tuple, got %s")
         nelts = len(destinationtree)
         lastindex = nelts-1
@@ -1536,11 +1527,10 @@
             lastelt = eltobj # advance eltobj
             lastref = eltref
             elt = destinationtree[index]
-            te = type(elt)
-            if te is DictType:
+            if isinstance(elt,dict):
                 # simple leaf {name: dest}
                 leafdict = elt
-            elif te is TupleType:
+            elif isinstance(elt,tuple):
                 # leaf with subsections: ({name: ref}, subsections) XXXX should clean up (see count(...))
                 try:
                     (leafdict, subsections) = elt
@@ -1556,7 +1546,7 @@
                 raise ValueError("bad outline leaf dictionary, should have one entry "+utf8str(elt))
             eltobj.Title = destinationnamestotitles[Title]
             eltobj.Dest = Dest
-            if te is TupleType and Dest in closedict:
+            if isinstance(elt,tuple) and Dest in closedict:
                 # closed subsection, count should be negative
                 eltobj.Count = -eltobj.Count
         return (firstref, lastref)
@@ -1564,15 +1554,13 @@
 def count(tree, closedict=None):
     """utility for outline: recursively count leaves in a tuple/list tree"""
     from operator import add
-    from types import TupleType, ListType
-    tt = type(tree)
-    if tt is TupleType:
+    if isinstance(tree,tuple):
         # leaf with subsections XXXX should clean up this structural usage
         (leafdict, subsections) = tree
         [(Title, Dest)] = list(leafdict.items())
         if closedict and Dest in closedict:
             return 1 # closed tree element
-    if tt is TupleType or tt is ListType:
+    if isSeqType(tree):
         #return reduce(add, map(count, tree))
         counts = []
         for e in tree:
@@ -1617,7 +1605,7 @@
     def copy(self):
         "shallow copy - useful in pagecatchering"
         thing = self.__klass__()
-        for (k, v) in list(self.__dict__.items()):
+        for k, v in self.__dict__.items():
             setattr(thing, k, v)
         return thing
 # skipping thumbnails, etc
@@ -1632,7 +1620,7 @@
     def cvtdict(self, d, escape=1):
         """transform dict args from python form to pdf string rep as needed"""
         Rect = d["Rect"]
-        if type(Rect) is not bytes:
+        if not isStrType(Rect):
             d["Rect"] = PDFArray(Rect)
         d["Contents"] = PDFString(d["Contents"],escape)
         return d
@@ -1651,7 +1639,7 @@
                 raise ValueError("keyword argument %s missing" % name)
         d = self.cvtdict(d,escape=escape)
         permitted = self.permitted
-        for name in list(d.keys()):
+        for name in d.keys():
             if name not in permitted:
                 raise ValueError("bad annotation dictionary name %s" % name)
         return PDFDictionary(d)
@@ -1747,7 +1735,7 @@
     # gmt offset now suppported properly
     def __init__(self, invariant=rl_config.invariant, dateFormatter=None):
         if invariant:
-            now = (2000,0o1,0o1,00,00,00,0)
+            now = (2000,1,1,0,0,0,0)
             self.dhh = 0
             self.dmm = 0
         else:
@@ -1895,7 +1883,7 @@
         self.Shading = {}
         # ?by default define the basicprocs
         self.basicProcs()
-    stdprocs = list(map(PDFName, string.split("PDF Text ImageB ImageC ImageI")))
+    stdprocs = [PDFName(s) for s in "PDF Text ImageB ImageC ImageI".split()]
     dict_attributes = ("ColorSpace", "XObject", "ExtGState", "Font", "Pattern", "Properties", "Shading")
 
     def allProcs(self):
@@ -1918,10 +1906,9 @@
 
     def format(self, document):
         D = {}
-        from types import ListType, DictType
         for dname in self.dict_attributes:
             v = getattr(self, dname)
-            if type(v) is DictType:
+            if isinstance(v,dict):
                 if v:
                     dv = PDFDictionary(v)
                     D[dname] = dv
@@ -1929,7 +1916,7 @@
                 D[dname] = v
         v = self.ProcSet
         dname = "ProcSet"
-        if type(v) is ListType:
+        if isSeqType(v):
             if v:
                 dv = PDFArray(v)
                 D[dname] = dv
@@ -1949,11 +1936,11 @@
     __PDFObject__ = True
     __RefOnly__ = 1
     # note! /Name appears to be an undocumented attribute....
-    name_attributes = string.split("Type Subtype BaseFont Name")
+    name_attributes = "Type Subtype BaseFont Name".split()
     Type = "Font"
     Subtype = "Type1"
     # these attributes are assumed to already be of the right type
-    local_attributes = string.split("FirstChar LastChar Widths Encoding ToUnicode FontDescriptor")
+    local_attributes = "FirstChar LastChar Widths Encoding ToUnicode FontDescriptor".split()
     def format(self, document):
         D = {}
         for name in self.name_attributes:
@@ -2023,8 +2010,8 @@
         self.lowerx = lowerx; self.lowery=lowery; self.upperx=upperx; self.uppery=uppery
 
     def setStreamList(self, data):
-        if type(data) is list:
-            data = string.join(data, LINEEND)
+        if isSeqType(data):
+            data = LINEEND.join(data)
         self.stream = data
 
     def BBoxList(self):
@@ -2120,7 +2107,7 @@
         else:
             # it is a filename
             import os
-            ext = string.lower(os.path.splitext(source)[1])
+            ext = os.path.splitext(source)[1].lower()
             src = open_for_read(source)
             if not(ext in ('.jpg', '.jpeg') and self.loadImageFromJPEG(src)):
                 if rl_config.useA85:
@@ -2130,15 +2117,15 @@
 
     def loadImageFromA85(self,source):
         IMG=[]
-        imagedata = list(map(string.strip,pdfutils.makeA85Image(source,IMG=IMG)))
-        words = string.split(imagedata[1])
-        self.width, self.height = list(map(string.atoi,(words[1],words[3])))
+        imagedata = [s.strip() for s in pdfutils.makeA85Image(source,IMG=IMG)]
+        words = imagedata[1].split()
+        self.width, self.height = (int(words[1]),int(words[3]))
         self.colorSpace = {'/RGB':'DeviceRGB', '/G':'DeviceGray', '/CMYK':'DeviceCMYK'}[words[7]]
         self.bitsPerComponent = 8
         self._filters = 'ASCII85Decode','FlateDecode' #'A85','Fl'
         if IMG: self._checkTransparency(IMG[0])
         elif self.mask=='auto': self.mask = None
-        self.streamContent = string.join(imagedata[3:-1],'')
+        self.streamContent = ''.join(imagedata[3:-1])
 
     def loadImageFromJPEG(self,imageFile):
         try:
@@ -2170,13 +2157,14 @@
         IMG=[]
         imagedata = pdfutils.makeRawImage(source,IMG=IMG)
         words = string.split(imagedata[1])
-        self.width, self.height = list(map(string.atoi,(words[1],words[3])))
+        self.width = int(words[1])
+        self.height = int(words[3])
         self.colorSpace = {'/RGB':'DeviceRGB', '/G':'DeviceGray', '/CMYK':'DeviceCMYK'}[words[7]]
         self.bitsPerComponent = 8
         self._filters = 'FlateDecode', #'Fl'
         if IMG: self._checkTransparency(IMG[0])
         elif self.mask=='auto': self.mask = None
-        self.streamContent = string.join(imagedata[3:-1],'')
+        self.streamContent = ''.join(imagedata[3:-1])
 
     def _checkTransparency(self,im):
         if self.mask=='auto':
@@ -2228,7 +2216,7 @@
             dict["Decode"] = PDFArray([1,0,1,0,1,0,1,0])
         elif getattr(self,'_decode',None):
             dict["Decode"] = PDFArray(self._decode)
-        dict["Filter"] = PDFArray(list(map(PDFName,self._filters)))
+        dict["Filter"] = PDFArray(map(PDFName,self._filters))
         dict["Length"] = len(self.streamContent)
         if self.mask: dict["Mask"] = PDFArray(self.mask)
         if getattr(self,'smask',None): dict["SMask"] = self.smask
@@ -2297,7 +2285,7 @@
             if name not in d:
                 raise ValueError("keyword argument %s missing" % name)
         permitted = self.permitted
-        for name in list(d.keys()):
+        for name in d.keys():
             if name not in permitted:
                 raise ValueError("bad annotation dictionary name %s" % name)
         return PDFDictionary(d)
@@ -2358,7 +2346,7 @@
             if name not in d:
                 raise ValueError("keyword argument %s missing" % name)
         permitted = self.permitted
-        for name in list(d.keys()):
+        for name in d.keys():
             if name not in permitted:
                 raise ValueError("bad annotation dictionary name %s" % name)
         return PDFDictionary(d)
--- a/src/reportlab/pdfbase/pdfform.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/pdfbase/pdfform.py	Tue Apr 30 14:28:14 2013 +0100
@@ -191,7 +191,7 @@
     from reportlab.pdfbase.pdfdoc import PDFDictionary
     fontsdictionary = PDFDictionary()
     fontsdictionary.__RefOnly__ = 1
-    for (fullname, shortname) in list(FORMFONTNAMES.items()):
+    for fullname, shortname in FORMFONTNAMES.items():
         fontsdictionary[shortname] = FormFont(fullname, shortname)
     fontsdictionary["ZaDb"] = ZADB
     return fontsdictionary
--- a/src/reportlab/pdfbase/pdfmetrics.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/pdfbase/pdfmetrics.py	Tue Apr 30 14:28:14 2013 +0100
@@ -19,13 +19,12 @@
 trap attempts to access them and do it on first access.
 """
 import string, os, sys
-from types import StringType, ListType, TupleType
 from reportlab.pdfbase import _fontdata
 from reportlab.lib.logger import warnOnce
-from reportlab.lib.utils import rl_isfile, rl_glob, rl_isdir, open_and_read, open_and_readlines, findInPaths
+from reportlab.lib.utils import rl_isfile, rl_glob, rl_isdir, open_and_read, open_and_readlines, findInPaths, isSeqType, isStrType, isUnicodeType, isPython3
 from reportlab.rl_config import defaultEncoding, T1SearchPath
 from . import rl_codecs
-_notdefChar = chr(110)
+_notdefChar = b'n'
 
 rl_codecs.RL_Codecs.register()
 standardFonts = _fontdata.standardFonts
@@ -37,8 +36,6 @@
 
 def _py_unicode2T1(utext,fonts):
     '''return a list of (font,string) pairs representing the unicode text'''
-    #print 'unicode2t1(%s, %s): %s' % (utext, fonts, type(utext))
-    #if type(utext)
     R = []
     font, fonts = fonts[0], fonts[1:]
     enc = font.encName
@@ -46,7 +43,11 @@
         enc = 'UTF16'
     while utext:
         try:
-            R.append((font,utext.encode(enc)))
+            if isUnicodeType(utext):
+                s = utext.encode(enc)
+            else:
+                s = utext
+            R.append((font,s))
             break
         except UnicodeEncodeError as e:
             i0, il = e.args[2:4]
@@ -80,13 +81,14 @@
     lines = open_and_readlines(afmFileName, 'r')
     if len(lines)<=1:
         #likely to be a MAC file
-        if lines: lines = string.split(lines[0],'\r')
+        if lines: lines = lines[0].split('\r')
         if len(lines)<=1:
             raise ValueError('AFM file %s hasn\'t enough data' % afmFileName)
     topLevel = {}
     glyphLevel = []
 
-    lines = [l for l in map(string.strip, lines) if not l.lower().startswith('comment')]
+    lines = [l.strip() for l in lines]
+    lines = [l for l in lines if not l.lower().startswith('comment')]
     #pass 1 - get the widths
     inMetrics = 0  # os 'TOP', or 'CHARMETRICS'
     for line in lines:
@@ -95,22 +97,22 @@
         elif line[0:14] == 'EndCharMetrics':
             inMetrics = 0
         elif inMetrics:
-            chunks = string.split(line, ';')
-            chunks = list(map(string.strip, chunks))
+            chunks = line.split(';')
+            chunks = [chunk.strip() for chunk in chunks]
             cidChunk, widthChunk, nameChunk = chunks[0:3]
 
             # character ID
-            l, r = string.split(cidChunk)
+            l, r = cidChunk.split()
             assert l == 'C', 'bad line in font file %s' % line
-            cid = string.atoi(r)
+            cid = int(r)
 
             # width
-            l, r = string.split(widthChunk)
+            l, r = widthChunk.split()
             assert l == 'WX', 'bad line in font file %s' % line
-            width = string.atoi(r)
+            width = int(r)
 
             # name
-            l, r = string.split(nameChunk)
+            l, r = nameChunk.split()
             assert l == 'N', 'bad line in font file %s' % line
             name = r
 
@@ -126,11 +128,11 @@
         elif inHeader:
             if line[0:7] == 'Comment': pass
             try:
-                left, right = string.split(line,' ',1)
+                left, right = line.split(' ',1)
             except:
                 raise ValueError("Header information error in afm %s: line='%s'" % (afmFileName, line))
             try:
-                right = string.atoi(right)
+                right = int(right)
             except:
                 pass
             topLevel[left] = right
@@ -178,7 +180,7 @@
         return []
 
     def findT1File(self, ext='.pfb'):
-        possible_exts = (string.lower(ext), string.upper(ext))
+        possible_exts = (ext.lower(), ext.upper())
         if hasattr(self,'pfbFileName'):
             r_basename = os.path.splitext(self.pfbFileName)[0]
             for e in possible_exts:
@@ -189,14 +191,14 @@
         except:
             afm = bruteForceSearchForAFM(self.name)
             if afm:
-                if string.lower(ext) == '.pfb':
+                if ext.lower() == '.pfb':
                     for e in possible_exts:
                         pfb = os.path.splitext(afm)[0] + e
                         if rl_isfile(pfb):
                             r = pfb
                         else:
                             r = None
-                elif string.lower(ext) == '.afm':
+                elif ext.lower() == '.afm':
                     r = afm
             else:
                 r = None
@@ -251,11 +253,11 @@
             # assume based on the usual one
             self.baseEncodingName = defaultEncoding
             self.vector = _fontdata.encodings[defaultEncoding]
-        elif type(base) is StringType:
+        elif isStrType(base):
             baseEnc = getEncoding(base)
             self.baseEncodingName = baseEnc.name
             self.vector = baseEnc.vector[:]
-        elif type(base) in (ListType, TupleType):
+        elif isSeqType(base):
             self.baseEncodingName = defaultEncoding
             self.vector = base[:]
         elif isinstance(base, Encoding):
@@ -407,19 +409,19 @@
         """This is the "purist" approach to width.  The practical approach
         is to use the stringWidth function, which may be swapped in for one
         written in C."""
-        if not isinstance(text,str): text = text.decode(encoding)
+        if not isUnicodeType(text): text = text.decode(encoding)
         return sum([sum(map(f.widths.__getitem__,list(map(ord,t)))) for f, t in unicode2T1(text,[self]+self.substitutionFonts)])*0.001*size
     stringWidth = _py_stringWidth
 
     def _formatWidths(self):
         "returns a pretty block in PDF Array format to aid inspection"
-        text = '['
+        text = b'['
         for i in range(256):
-            text = text + ' ' + str(self.widths[i])
+            text = text + b' ' + bytes(str(self.widths[i]),'utf8')
             if i == 255:
-                text = text + ' ]'
+                text = text + b' ]'
             if i % 16 == 15:
-                text = text + '\n'
+                text = text + b'\n'
         return text
 
     def addObjects(self, doc):
@@ -457,20 +459,33 @@
 PFB_ASCII=chr(1)
 PFB_BINARY=chr(2)
 PFB_EOF=chr(3)
-def _pfbSegLen(p,d):
-    '''compute a pfb style length from the first 4 bytes of string d'''
-    return ((((ord(d[p+3])<<8)|ord(d[p+2])<<8)|ord(d[p+1]))<<8)|ord(d[p])
 
-def _pfbCheck(p,d,m,fn):
-    if d[p]!=PFB_MARKER or d[p+1]!=m:
-        raise ValueError('Bad pfb file\'%s\' expected chr(%d)chr(%d) at char %d, got chr(%d)chr(%d)' % (fn,ord(PFB_MARKER),ord(m),p,ord(d[p]),ord(d[p+1])))
-    if m==PFB_EOF: return
-    p = p + 2
-    l = _pfbSegLen(p,d)
-    p = p + 4
-    if p+l>len(d):
-        raise ValueError('Bad pfb file\'%s\' needed %d+%d bytes have only %d!' % (fn,p,l,len(d)))
-    return p, p+l
+if isPython3:
+    def _pfbCheck(p,d,m,fn):
+        if chr(d[p])!=PFB_MARKER or chr(d[p+1])!=m:
+            raise ValueError('Bad pfb file\'%s\' expected chr(%d)chr(%d) at char %d, got chr(%d)chr(%d)' % (fn,ord(PFB_MARKER),ord(m),p,d[p],d[p+1]))
+        if m==PFB_EOF: return
+        p = p + 2
+        l = (((((d[p+3])<<8)|(d[p+2])<<8)|(d[p+1]))<<8)|(d[p])
+        p = p + 4
+        if p+l>len(d):
+            raise ValueError('Bad pfb file\'%s\' needed %d+%d bytes have only %d!' % (fn,p,l,len(d)))
+        return p, p+l
+else:
+    def _pfbSegLen(p,d):
+        '''compute a pfb style length from the first 4 bytes of string d'''
+        return ((((ord(d[p+3])<<8)|ord(d[p+2])<<8)|ord(d[p+1]))<<8)|ord(d[p])
+
+    def _pfbCheck(p,d,m,fn):
+        if d[p]!=PFB_MARKER or d[p+1]!=m:
+            raise ValueError('Bad pfb file\'%s\' expected chr(%d)chr(%d) at char %d, got chr(%d)chr(%d)' % (fn,ord(PFB_MARKER),ord(m),p,ord(d[p]),ord(d[p+1])))
+        if m==PFB_EOF: return
+        p = p + 2
+        l = _pfbSegLen(p,d)
+        p = p + 4
+        if p+l>len(d):
+            raise ValueError('Bad pfb file\'%s\' needed %d+%d bytes have only %d!' % (fn,p,l,len(d)))
+        return p, p+l
 
 class EmbeddedType1Face(TypeFace):
     """A Type 1 font other than one of the basic 14.
@@ -526,10 +541,10 @@
         self.xHeight = topLevel.get('XHeight', 1000)
 
         strBbox = topLevel.get('FontBBox', [0,0,1000,1000])
-        tokens = string.split(strBbox)
+        tokens = strBbox.split()
         self.bbox = []
         for tok in tokens:
-            self.bbox.append(string.atoi(tok))
+            self.bbox.append(int(tok))
 
         glyphWidths = {}
         for (cid, width, name) in glyphData:
@@ -666,6 +681,7 @@
 
 def findFontAndRegister(fontName):
     '''search for and register a font given its name'''
+    assert type(fontName) is str
     #it might have a font-specific encoding e.g. Symbol
     # or Dingbats.  If not, take the default.
     face = getTypeFace(fontName)
@@ -784,7 +800,7 @@
     print('test one huge string...')
     test3widths([rawdata])
     print()
-    words = string.split(rawdata)
+    words = rawdata.split()
     print('test %d shorter strings (average length %0.2f chars)...' % (len(words), 1.0*len(rawdata)/len(words)))
     test3widths(words)
 
--- a/src/reportlab/pdfbase/pdfutils.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/pdfbase/pdfutils.py	Tue Apr 30 14:28:14 2013 +0100
@@ -6,9 +6,11 @@
 # pdfutils.py - everything to do with images, streams,
 # compression, and some constants
 
+import sys
 import os
+import binascii
 from reportlab import rl_config
-from reportlab.lib.utils import getStringIO, ImageReader
+from reportlab.lib.utils import getBytesIO, ImageReader, isStrType, isUnicodeType, isPython3
 
 LINEEND = '\015\012'
 
@@ -80,7 +82,7 @@
     if filename==cachedname:
         if cachedImageExists(filename):
             from reportlab.lib.utils import open_for_read
-            if returnInMemory: return [_f for _f in open_for_read(cachedname).read().split(LINEEND) if _f]
+            if returnInMemory: return filter(None,open_for_read(cachedname).read().split(LINEEND))
         else:
             raise IOError('No such cached image %s' % filename)
     else:
@@ -108,7 +110,7 @@
 
     import types, glob
 
-    if type(spec) is bytes:
+    if type(spec) is types.StringType:
         filelist = glob.glob(spec)
     else:  #list or tuple OK
         filelist = spec
@@ -154,26 +156,23 @@
         _escape = escapePDF
     except ImportError:
         _instanceEscapePDF=None
-        if rl_config.sys_version>='2.1':
-            _ESCAPEDICT={}
-            for c in range(0,256):
-                if c<32 or c>=127:
-                    _ESCAPEDICT[chr(c)]= '\\%03o' % c
-                elif c in (ord('\\'),ord('('),ord(')')):
-                    _ESCAPEDICT[chr(c)] = '\\'+chr(c)
-                else:
-                    _ESCAPEDICT[chr(c)] = chr(c)
-            del c
-            #Michael Hudson donated this
-            def _escape(s):
-                return ''.join(map(lambda c, d=_ESCAPEDICT: d[c],s))
-        else:
-            def _escape(s):
-                """Escapes some PDF symbols (in fact, parenthesis).
-                PDF escapes are almost like Python ones, but brackets
-                need slashes before them too. Uses Python's repr function
-                and chops off the quotes first."""
-                return repr(s)[1:-1].replace('(','\(').replace(')','\)')
+        _ESCAPEDICT={}
+        for c in range(256):
+            if c<32 or c>=127:
+                _ESCAPEDICT[c]= '\\%03o' % c
+            elif c in (ord('\\'),ord('('),ord(')')):
+                _ESCAPEDICT[c] = '\\'+chr(c)
+            else:
+                _ESCAPEDICT[c] = chr(c)
+        del c
+        #Michael Hudson donated this
+        def _escape(s):
+            r = []
+            for c in s:
+                if not type(c) is int:
+                    c = ord(c)
+                r.append(_ESCAPEDICT[c])
+            return ''.join(r)
 
 def _normalizeLineEnds(text,desired=LINEEND,unlikely='\x00\x01\x02\x03'):
     """Normalizes different line end character(s).
@@ -193,10 +192,11 @@
     This is a verbose encoding used for binary data within
     a PDF file.  One byte binary becomes two bytes of ASCII.
     Helper function used by images."""
-    output = getStringIO()
-    for char in input:
-        output.write('%02x' % ord(char))
-    output.write('>')
+    if isUnicodeType(input):
+        input = input.encode('utf-8')
+    output = getBytesIO()
+    output.write(binascii.b2a_hex(input))
+    output.write(b'>')
     return output.getvalue()
 
 
@@ -206,6 +206,8 @@
     Not used except to provide a test of the inverse function."""
 
     #strip out all whitespace
+    if not isStrType(input):
+        input = input.decode('utf-8')
     stripped = ''.join(input.split())
     assert stripped[-1] == '>', 'Invalid terminator for Ascii Hex Stream'
     stripped = stripped[:-1]  #chop off terminator
@@ -224,14 +226,20 @@
         whole_word_count, remainder_size = divmod(len(input), 4)
         cut = 4 * whole_word_count
         body, lastbit = input[0:cut], input[cut:]
+        if isPython3 and isStrType(lastbit):
+            lastbit = lastbit.encode('utf-8')
 
         out = [].append
         for i in range(whole_word_count):
             offset = i*4
-            b1 = ord(body[offset])
-            b2 = ord(body[offset+1])
-            b3 = ord(body[offset+2])
-            b4 = ord(body[offset+3])
+            b1 = body[offset]
+            b2 = body[offset+1]
+            b3 = body[offset+2]
+            b4 = body[offset+3]
+            if isStrType(b1): b1 = ord(b1)
+            if isStrType(b2): b2 = ord(b2)
+            if isStrType(b3): b3 = ord(b3)
+            if isStrType(b4): b4 = ord(b4)
 
             if b1<128:
                 num = (((((b1<<8)|b2)<<8)|b3)<<8)|b4
@@ -261,11 +269,15 @@
         #encode however many bytes we have as usual
         if remainder_size > 0:
             while len(lastbit) < 4:
-                lastbit = lastbit + '\000'
-            b1 = ord(lastbit[0])
-            b2 = ord(lastbit[1])
-            b3 = ord(lastbit[2])
-            b4 = ord(lastbit[3])
+                lastbit = lastbit + b'\000'
+            b1 = lastbit[0]
+            b2 = lastbit[1]
+            b3 = lastbit[2]
+            b4 = lastbit[3]
+            if isStrType(b1): b1 = ord(b1)
+            if isStrType(b2): b2 = ord(b2)
+            if isStrType(b3): b3 = ord(b3)
+            if isStrType(b4): b4 = ord(b4)
 
             num = 16777216 * b1 + 65536 * b2 + 256 * b3 + b4
 
--- a/src/reportlab/pdfbase/ttfonts.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/pdfbase/ttfonts.py	Tue Apr 30 14:28:14 2013 +0100
@@ -53,7 +53,7 @@
 
 import string
 from struct import pack, unpack, error as structError
-from reportlab.lib.utils import getStringIO
+from reportlab.lib.utils import getBytesIO
 from reportlab.pdfbase import pdfmetrics, pdfdoc
 from reportlab import rl_config
 
@@ -358,7 +358,7 @@
 
     def makeStream(self):
         "Finishes the generation and returns the TTF file as a string"
-        stm = getStringIO()
+        stm = getBytesIO()
         write = stm.write
 
         numTables = len(self.tables)
--- a/src/reportlab/pdfgen/canvas.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/pdfgen/canvas.py	Tue Apr 30 14:28:14 2013 +0100
@@ -12,21 +12,17 @@
 import os
 import sys
 import re
-from string import join, split, strip, atoi, replace, upper, digits
+import hashlib
+from string import digits
 import tempfile
 from math import sin, cos, tan, pi, ceil
-try:
-    from hashlib import md5
-except ImportError:
-    from md5 import md5
-
 from reportlab import rl_config
 from reportlab.pdfbase import pdfutils
 from reportlab.pdfbase import pdfdoc
 from reportlab.pdfbase import pdfmetrics
 from reportlab.pdfgen  import pdfgeom, pathobject, textobject
 from reportlab.lib.colors import black, _chooseEnforceColorSpace, Color, CMYKColor, toColor
-from reportlab.lib.utils import import_zlib, ImageReader, fp_str, _digester
+from reportlab.lib.utils import import_zlib, ImageReader, fp_str, isSeqType, isStrType, isUnicodeType, _digester
 from reportlab.lib.boxstuff import aspectRatioFix
 
 digitPat = re.compile('\d')  #used in decimal alignment
@@ -317,8 +313,8 @@
         '''
         if encrypt:
             from reportlab.lib import pdfencrypt
-            if isinstance(encrypt, str): #encrypt is the password itself
-                if isinstance(encrypt, str):
+            if isStrType(encrypt): #encrypt is the password itself
+                if isUnicodeType(encrypt):
                     encrypt = encrypt.encode('utf-8')
                 encrypt = pdfencrypt.StandardEncryption(encrypt)    #now it's the encrypt object
                 encrypt.setAllPermissions(1)
@@ -376,11 +372,10 @@
         d = self.__dict__
         d.update(state)
 
-    STATE_ATTRIBUTES = split("""
-     _x _y _fontname _fontsize _textMode _leading _currentMatrix _fillMode
+    STATE_ATTRIBUTES = """_x _y _fontname _fontsize _textMode _leading _currentMatrix _fillMode
      _fillMode _charSpace _wordSpace _horizScale _textRenderMode _rise _textLineMatrix
      _textMatrix _lineCap _lineJoin _lineDash _lineWidth _mitreLimit _fillColorObj
-     _strokeColorObj _extgstate""")
+     _strokeColorObj _extgstate""".split()
     STATE_RANGE = list(range(len(STATE_ATTRIBUTES)))
 
         #self._addStandardFonts()
@@ -912,10 +907,15 @@
                 mdata = smask.getRGBData()
             else:
                 mdata = str(mask)
+            if isUnicodeType(mdata):
+                mdata = mdata.encode('utf8')
             name = _digester(rawdata+mdata)
         else:
             #filename, use it
-            name = _digester('%s%s' % (image, mask))
+            s = '%s%s' % (image, mask)
+            if isUnicodeType(s):
+                s = s.encode('utf-8')
+            name = _digester(s)
 
         # in the pdf document, this will be prefixed with something to
         # say it is an XObject.  Does it exist yet?
@@ -1044,7 +1044,10 @@
         will error in Distiller but work on printers supporting it.
         """
         #check if we've done this one already...
-        rawName = 'PS' + md5(command).hexdigest()
+        if isUnicodeType(command):
+            rawName = 'PS' + hashlib.md5(command.encode('utf-8')).hexdigest()
+        else:
+            rawName = 'PS' + hashlib.md5(command).hexdigest()
         regName = self._doc.getXObjectName(rawName)
         psObj = self._doc.idToObject.get(regName, None)
         if not psObj:
@@ -1198,7 +1201,10 @@
         If there is current data a ShowPage is executed automatically.
         After this operation the canvas must not be used further."""
         if len(self._code): self.showPage()
-        return self._doc.GetPDFData(self)
+        s = self._doc.GetPDFData(self)
+        if isUnicodeType(s):
+            s = s.encode('utf-8')
+        return s
 
     def setPageSize(self, size):
         """accepts a 2-tuple in points for paper size for this
@@ -1254,7 +1260,7 @@
                                    a0*c+c0*d,    b0*c+d0*d,
                                    a0*e+c0*f+e0, b0*e+d0*f+f0)
         if self._code and self._code[-1][-3:]==' cm':
-            L = split(self._code[-1])
+            L = self._code[-1].split()
             a0, b0, c0, d0, e0, f0 = list(map(float,L[-7:-1]))
             s = len(L)>7 and join(L)+ ' %s cm' or '%s cm'
             self._code[-1] = s % fp_str(a0*a+c0*b,b0*a+d0*b,a0*c+c0*d,b0*c+d0*d,a0*e+c0*f+e0,b0*e+d0*f+f0)
@@ -1475,6 +1481,8 @@
 
     def drawString(self, x, y, text, mode=None):
         """Draws a string in the current text styles."""
+        if sys.version_info[0] == 3 and not isinstance(text, str):
+            text = text.decode('utf-8')
         #we could inline this for speed if needed
         t = self.beginText(x, y)
         if mode is not None: t.setTextRenderMode(mode)
@@ -1483,6 +1491,8 @@
 
     def drawRightString(self, x, y, text, mode=None):
         """Draws a string right-aligned with the x coordinate"""
+        if sys.version_info[0] == 3 and not isinstance(text, str):
+            text = text.decode('utf-8')
         width = self.stringWidth(text, self._fontname, self._fontsize)
         t = self.beginText(x - width, y)
         if mode is not None: t.setTextRenderMode(mode)
@@ -1493,6 +1503,8 @@
         """Draws a string centred on the x coordinate. 
         
         We're British, dammit, and proud of our spelling!"""
+        if sys.version_info[0] == 3 and not isinstance(text, str):
+            text = text.decode('utf-8')
         width = self.stringWidth(text, self._fontname, self._fontsize)
         t = self.beginText(x - 0.5*width, y)
         if mode is not None: t.setTextRenderMode(mode)
@@ -1628,9 +1640,9 @@
         """Two notations.  pass two numbers, or an array and phase"""
         if isinstance(array,(int,float)):
             self._code.append('[%s %s] 0 d' % (array, phase))
-        elif isinstance(array,(tuple,list)):
+        elif isSeqType(array):
             assert phase >= 0, "phase is a length in user space"
-            textarray = ' '.join(map(str, array))
+            textarray = ' '.join([str(s) for s in array])
             self._code.append('[%s] %s d' % (textarray, phase))
 
     # path stuff - the separate path object builds it
--- a/src/reportlab/pdfgen/pdfimages.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/pdfgen/pdfimages.py	Tue Apr 30 14:28:14 2013 +0100
@@ -7,13 +7,11 @@
 """
 
 import os
-import string
-from types import StringType
 import reportlab
 from reportlab import rl_config
 from reportlab.pdfbase import pdfutils
 from reportlab.pdfbase import pdfdoc
-from reportlab.lib.utils import fp_str, getStringIO
+from reportlab.lib.utils import fp_str, getBytesIO, isStrType
 from reportlab.lib.utils import import_zlib, haveImages
 from reportlab.lib.boxstuff import aspectRatioFix
 
@@ -85,7 +83,7 @@
         cachedname = os.path.splitext(image)[0] + (rl_config.useA85 and '.a85' or '.bin')
         imagedata = open(cachedname,'rb').readlines()
         #trim off newlines...
-        imagedata = list(map(string.strip, imagedata))
+        imagedata = list(map(str.strip, imagedata))
         return imagedata
 
     def PIL_imagedata(self):
@@ -129,16 +127,16 @@
             imagedata = pdfutils.cacheImageFile(image,returnInMemory=1)
         else:
             imagedata = self.cache_imagedata()
-        words = string.split(imagedata[1])
-        imgwidth = string.atoi(words[1])
-        imgheight = string.atoi(words[3])
+        words = imagedata[1].split()
+        imgwidth = int(words[1])
+        imgheight = int(words[3])
         return imagedata, imgwidth, imgheight
 
     def getImageData(self,preserveAspectRatio=False):
         "Gets data, height, width - whatever type of image"
         image = self.image
 
-        if type(image) == StringType:
+        if isStrType(image):
             self.filename = image
             if os.path.splitext(image)[1] in ['.jpg', '.JPG', '.jpeg', '.JPEG']:
                 try:
@@ -189,7 +187,7 @@
         dict['Height'] = self.height
         dict['BitsPerComponent'] = 8
         dict['ColorSpace'] = pdfdoc.PDFName(self.colorSpace)
-        content = string.join(self.imageData[3:-1], '\n') + '\n'
+        content = '\n'.join(self.imageData[3:-1]) + '\n'
         strm = pdfdoc.PDFStream(dictionary=dict, content=content)
         return strm.format(document)
 
--- a/src/reportlab/pdfgen/pycanvas.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/pdfgen/pycanvas.py	Tue Apr 30 14:28:14 2013 +0100
@@ -149,7 +149,7 @@
     arguments = ""
     for arg in args :
         arguments = arguments + ("%s, " % repr(arg))
-    for (kw, val) in list(kwargs.items()) :
+    for kw, val in kwargs.items() :
         arguments = arguments+ ("%s=%s, " % (kw, repr(val)))
     if arguments[-2:] == ", " :
         arguments = arguments[:-2]
--- a/src/reportlab/pdfgen/textobject.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/pdfgen/textobject.py	Tue Apr 30 14:28:14 2013 +0100
@@ -9,10 +9,11 @@
 Progress Reports:
 8.83, 2000-01-13, gmcm: created from pdfgen.py
 """
+import sys
 import string
 from types import *
 from reportlab.lib.colors import Color, CMYKColor, CMYKColorSep, toColor, black, white, _CMYK_black, _CMYK_white
-from reportlab.lib.utils import fp_str
+from reportlab.lib.utils import fp_str, isStrType, isPython3
 from reportlab.pdfbase import pdfmetrics
 
 class _PDFColorSetter:
@@ -78,7 +79,7 @@
                 self._code.append('%s k' % fp_str(aColor))
             else:
                 raise ValueError('Unknown color %r' % aColor)
-        elif isinstance(aColor,str):
+        elif isStrType(aColor):
             self.setFillColor(toColor(aColor))
         else:
             raise ValueError('Unknown color %r' % aColor)
@@ -114,7 +115,7 @@
                 self._code.append('%s K' % fp_str(aColor))
             else:
                 raise ValueError('Unknown color %r' % aColor)
-        elif isinstance(aColor,str):
+        elif isStrType(aColor):
             self.setStrokeColor(toColor(aColor))
         else:
             raise ValueError('Unknown color %r' % aColor)
@@ -187,7 +188,7 @@
         self._code.append('ET')
         if self._clipping:
             self._code.append('%d Tr' % (self._textRenderMode^4))
-        return string.join(self._code, ' ')
+        return ' '.join(self._code)
 
     def setTextOrigin(self, x, y):
         if self._canvas.bottomup:
@@ -224,11 +225,11 @@
         # Check if we have a previous move cursor call, and combine
         # them if possible.
         if self._code and self._code[-1][-3:]==' Td':
-            L = string.split(self._code[-1])
+            L = self._code[-1].split()
             if len(L)==3:
                 del self._code[-1]
             else:
-                self._code[-1] = string.join(L[:-4])
+                self._code[-1] = ''.join(L[:-4])
 
             # Work out the last movement
             lastDx = float(L[-3])
@@ -383,7 +384,7 @@
         else:
             #convert to T1  coding
             fc = font
-            if not isinstance(text,str):
+            if not isPython3 and not isinstance(text,unicode):
                 try:
                     text = text.decode('utf8')
                 except UnicodeDecodeError as e:
@@ -431,10 +432,10 @@
         since this may be indented, by default it trims whitespace
         off each line and from the beginning; set trim=0 to preserve
         whitespace."""
-        if isinstance(stuff,str):
-            lines = string.split(string.strip(stuff), '\n')
+        if isStrType(stuff):
+            lines = '\n'.split(stuff.strip())
             if trim==1:
-                lines = list(map(string.strip,lines))
+                lines = [s.strip() for s in lines]
         elif isinstance(stuff,(tuple,list)):
             lines = stuff
         else:
@@ -445,6 +446,6 @@
         for line in lines:
             self.textLine(line)
 
-    def __bool__(self):
+    def __nonzero__(self):
         'PDFTextObject is true if it has something done after the init'
         return self._code != ['BT']
--- a/src/reportlab/platypus/doctemplate.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/platypus/doctemplate.py	Tue Apr 30 14:28:14 2013 +0100
@@ -463,7 +463,7 @@
         self._nameSpace = dict(doc=self)
         self._lifetimes = {}
 
-        for k in list(self._initArgs.keys()):
+        for k in self._initArgs.keys():
             if k not in kw:
                 v = self._initArgs[k]
             else:
--- a/src/reportlab/platypus/para.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/platypus/para.py	Tue Apr 30 14:28:14 2013 +0100
@@ -988,13 +988,13 @@
     def __init__(self, name, parent=None, **kw):
         mydict = self.__dict__
         if parent:
-            for (a,b) in list(parent.__dict__.items()):
+            for a,b in parent.__dict__.items():
                 mydict[a]=b
-        for (a,b) in list(kw.items()):
+        for a,b in kw.items():
             mydict[a] =  b
 
     def addAttributes(self, dictionary):
-        for key in list(dictionary.keys()):
+        for key in dictionary.keys():
             value = dictionary[key]
             if value is not None:
                 if hasattr(StyleAttributeConverters, key):
@@ -1186,7 +1186,7 @@
     result = {}
     from reportlab.lib.styles import getSampleStyleSheet
     styles = getSampleStyleSheet()
-    for (stylenamekey, stylenamevalue) in list(DEFAULT_ALIASES.items()):
+    for stylenamekey, stylenamevalue in DEFAULT_ALIASES.items():
         result[stylenamekey] = styles[stylenamevalue]
     return result
 
@@ -1195,17 +1195,17 @@
     from reportlab.lib.styles import getSampleStyleSheet
     if stylesheet is not None:
         # Copy styles with the same name as aliases
-        for (stylenamekey, stylenamevalue) in list(DEFAULT_ALIASES.items()):
+        for stylenamekey, stylenamevalue in DEFAULT_ALIASES.items():
             if stylenamekey in stylesheet:
                 result[stylenamekey] = stylesheet[stylenamekey]
         # Then make aliases
-        for (stylenamekey, stylenamevalue) in list(DEFAULT_ALIASES.items()):
+        for stylenamekey, stylenamevalue in DEFAULT_ALIASES.items():
             if stylenamevalue in stylesheet:
                 result[stylenamekey] = stylesheet[stylenamevalue]
 
     styles = getSampleStyleSheet()
     # Then, fill in defaults if they were not filled yet.
-    for (stylenamekey, stylenamevalue) in list(DEFAULT_ALIASES.items()):
+    for stylenamekey, stylenamevalue in DEFAULT_ALIASES.items():
         if stylenamekey not in result and stylenamevalue in styles:
             result[stylenamekey] = styles[stylenamevalue]
     return result
@@ -1490,7 +1490,7 @@
                     L = [ "<" + tagname ]
                     a = L.append
                     if not attdict: attdict = {}
-                    for (k, v) in list(attdict.items()):
+                    for k, v in attdict.items():
                         a(" %s=%s" % (k,v))
                     if content:
                         a(">")
@@ -1915,7 +1915,6 @@
 
     def getOp(self, tuple, engine):
         from reportlab.lib.sequencer import getSequencer
-        import math
         globalsequencer = getSequencer()
         attr = self.attdict
         try:
@@ -1923,7 +1922,7 @@
         except KeyError:
             id = None
         try:
-            base = math.atoi(attr['base'])
+            base = int(attr['base'])
         except:
             base=0
         globalsequencer.reset(id, base)
@@ -1994,7 +1993,7 @@
 
 def handleSpecialCharacters(engine, text, program=None):
     from .paraparser import greeks
-    from string import whitespace, atoi, atoi_error
+    from string import whitespace
     standard={'lt':'<', 'gt':'>', 'amp':'&'}
     # add space prefix if space here
     if text[0:1] in whitespace:
@@ -2025,10 +2024,10 @@
                 if name[0]=='#':
                     try:
                         if name[1] == 'x':
-                            n = atoi(name[2:], 16)
+                            n = int(name[2:], 16)
                         else:
-                            n = atoi(name[1:])
-                    except atoi_error:
+                            n = int(name[1:])
+                    except ValueError:
                         n = -1
                     if n>=0:
                         fragment = chr(n).encode('utf8')+fragment[semi+1:]
--- a/src/reportlab/platypus/paraparser.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/platypus/paraparser.py	Tue Apr 30 14:28:14 2013 +0100
@@ -218,7 +218,7 @@
 _addAttributeNames(_linkAttrMap)
 
 def _applyAttributes(obj, attr):
-    for k, v in list(attr.items()):
+    for k, v in attr.items():
         if type(v) is TupleType and v[0]=='relative':
             #AR 20/5/2000 - remove 1.5.2-ism
             #v = v[1]+getattr(obj,k,0)
@@ -972,13 +972,13 @@
     def _pop(self,**kw):
         frag = self._stack[-1]
         del self._stack[-1]
-        for k, v in list(kw.items()):
+        for k, v in kw.items():
             assert getattr(frag,k)==v
         return frag
 
     def getAttributes(self,attr,attrMap):
         A = {}
-        for k, v in list(attr.items()):
+        for k, v in attr.items():
             if not self.caseSensitive:
                 k = string.lower(k)
             if k in list(attrMap.keys()):
--- a/src/reportlab/platypus/tables.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/platypus/tables.py	Tue Apr 30 14:28:14 2013 +0100
@@ -578,7 +578,7 @@
                     if height > availHeight:
                         #we can terminate if all spans are complete in H[:i]
                         if spanCons:
-                            msr = max([x[1] for x in list(spanCons.keys())])  #RS=[endrowspan,.....]
+                            msr = max([x[1] for x in spanCons.keys()])  #RS=[endrowspan,.....]
                             if hmax>=msr:
                                 break
             if None not in H: hmax = lim
@@ -761,7 +761,7 @@
             desiredWidths = []
             totalDesired = 0
             effectiveRemaining = remaining
-            for colNo, minimum in list(minimums.items()):
+            for colNo, minimum in minimums.items():
                 w = W[colNo]
                 if _endswith(w,'%'):
                     desired = (float(w[:-1])/percentTotal)*availWidth
@@ -821,7 +821,7 @@
                     assert adjusted >= minimum
                     W[colNo] = adjusted
         else:
-            for colNo, minimum in list(minimums.items()):
+            for colNo, minimum in minimums.items():
                 W[colNo] = minimum
         if verbose: print('new widths are:', W)
         self._argW = self._colWidths = W
@@ -986,7 +986,7 @@
                 spanRects[coord] = (x, y, width, height)
 
         for _ in hBlocks, vBlocks:
-            for value in list(_.values()):
+            for value in _.values():
                 value.sort()
         self._spanRects = spanRects
         self._vBlocks = vBlocks
@@ -998,7 +998,7 @@
             tblstyle = TableStyle(tblstyle)
         for cmd in tblstyle.getCommands():
             self._addCommand(cmd)
-        for k,v in list(tblstyle._opts.items()):
+        for k,v in tblstyle._opts.items():
             setattr(self,k,v)
         for a in ('spaceBefore','spaceAfter'):
             if not hasattr(self,a) and hasattr(tblstyle,a):
--- a/tests/test_lib_utils.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/tests/test_lib_utils.py	Tue Apr 30 14:28:14 2013 +0100
@@ -115,8 +115,8 @@
 
     def test10(self):
         "test open and read of a simple relative file"
-        from reportlab.lib.utils import open_and_read, getStringIO
-        b = getStringIO(_rel_open_and_read('../docs/images/Edit_Prefs.gif'))
+        from reportlab.lib.utils import open_and_read, getBytesIO
+        b = getBytesIO(_rel_open_and_read('../docs/images/Edit_Prefs.gif'))
         b = open_and_read(b)
 
 
--- a/tests/test_rl_accel.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/tests/test_rl_accel.py	Tue Apr 30 14:28:14 2013 +0100
@@ -119,7 +119,7 @@
             def __init__(self,**kwd):
                 self.__dict__.update(kwd)
             def __str__(self):
-                V=['%s=%r' % v for v in list(self.__dict__.items())]
+                V=['%s=%r' % v for v in self.__dict__.items()]
                 V.sort()
                 return 'ABag(%s)' % ','.join(V)
 
--- a/tools/docco/examples.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/tools/docco/examples.py	Tue Apr 30 14:28:14 2013 +0100
@@ -856,7 +856,7 @@
 Dprime = {}
 from types import StringType
 from string import strip
-for (a,b) in list(g.items()):
+for a,b in g.items():
     if a[:4]=="test" and type(b) is StringType:
         #print 'for', a
         #print b
--- a/tools/docco/graphdocpy.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/tools/docco/graphdocpy.py	Tue Apr 30 14:28:14 2013 +0100
@@ -26,9 +26,9 @@
 from reportlab.lib.pagesizes import A4
 from reportlab.lib import colors
 from reportlab.lib.enums import TA_CENTER, TA_LEFT
-from reportlab.lib.utils import getStringIO
+from reportlab.lib.utils import getBytesIO
 #from StringIO import StringIO
-#getStringIO=StringIO
+#getBytesIO=StringIO
 from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
 from reportlab.pdfgen import canvas
 from reportlab.platypus.flowables import Flowable, Spacer
@@ -470,7 +470,7 @@
         for key in keys:
             value = props[key]
 
-            f = getStringIO()
+            f = getBytesIO()
             pprint.pprint(value, f)
             value = f.getvalue()[:-1]
             valueLines = string.split(value, '\n')
@@ -654,7 +654,7 @@
             value = props[key]
 
             # Method 3
-            f = getStringIO()
+            f = getBytesIO()
             pprint.pprint(value, f)
             value = f.getvalue()[:-1]
             valueLines = string.split(value, '\n')
--- a/tools/docco/rl_doc_utils.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/tools/docco/rl_doc_utils.py	Tue Apr 30 14:28:14 2013 +0100
@@ -308,7 +308,7 @@
     def getStyleText(self, style):
         """Converts style to preformatted block of text"""
         lines = []
-        for (key, value) in list(style.__dict__.items()):
+        for key, value in style.__dict__.items():
             lines.append('%s = %s' % (key, value))
         lines.sort()
         return string.join(lines, '\n')
@@ -346,7 +346,7 @@
     def getStyleText(self, style):
         """Converts style to preformatted block of text"""
         lines = []
-        for (key, value) in list(style.__dict__.items()):
+        for key, value in style.__dict__.items():
             if key not in ('name','parent'):
                 lines.append('%s = %s' % (key, value))
         return string.join(lines, '\n')
--- a/tools/docco/t_parse.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/tools/docco/t_parse.py	Tue Apr 30 14:28:14 2013 +0100
@@ -113,7 +113,7 @@
               raise ValueError("Marks must be single characters: "+repr(mark))
        # compile the regular expressions if needed
        self.marker_dict = marker_dict = {}
-       for (mark, rgex) in list(marker_to_regex_dict.items()):
+       for mark, rgex in marker_to_regex_dict.items():
            if type(rgex) == StringType:
               rgex = re.compile(rgex)
            marker_dict[mark] = rgex
--- a/tools/pythonpoint/demos/examples.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/tools/pythonpoint/demos/examples.py	Tue Apr 30 14:28:14 2013 +0100
@@ -787,7 +787,7 @@
 Dprime = {}
 from types import StringType
 from string import strip
-for (a,b) in list(g.items()):
+for a,b in g.items()):
     if a[:4]=="test" and type(b) is StringType:
         #print 'for', a
         #print b
--- a/tools/pythonpoint/pythonpoint.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/tools/pythonpoint/pythonpoint.py	Tue Apr 30 14:28:14 2013 +0100
@@ -77,7 +77,7 @@
 from reportlab.lib import styles
 from reportlab.lib import colors
 from reportlab.lib.units import cm
-from reportlab.lib.utils import getStringIO
+from reportlab.lib.utils import getBytesIO
 from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY
 from reportlab.pdfbase import pdfmetrics
 from reportlab.pdfgen import canvas
@@ -352,7 +352,7 @@
         if self.verbose:
             print(filename)
         #canv = canvas.Canvas(filename, pagesize = pageSize)
-        outfile = getStringIO()
+        outfile = getBytesIO()
         if self.notes:
             #translate the page from landscape to portrait
             pageSize= pageSize[1], pageSize[0]
@@ -403,7 +403,7 @@
         if self.sourceFilename :
             filename = os.path.splitext(self.sourceFilename)[0] + '.pdf'
 
-        outfile = getStringIO()
+        outfile = getBytesIO()
         doc = SimpleDocTemplate(outfile, pagesize=rl_config.defaultPageSize, showBoundary=0)
         doc.leftMargin = 1*cm
         doc.rightMargin = 1*cm
--- a/tools/pythonpoint/stdparser.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/tools/pythonpoint/stdparser.py	Tue Apr 30 14:28:14 2013 +0100
@@ -786,7 +786,7 @@
     def unknown_starttag(self, tag, attrs):
         if  self._curPara:
             echo = '<%s' % tag
-            for (key, value) in list(attrs.items()):
+            for key, value in attrs.items():
                 echo = echo + ' %s="%s"' % (key, value)
             echo = echo + '>'
             self._curPara.rawtext = self._curPara.rawtext + echo