diff --git a/appy/__init__.py b/appy/__init__.py
index 010ddae..7e5a5d2 100644
--- a/appy/__init__.py
+++ b/appy/__init__.py
@@ -88,7 +88,7 @@ class Hack:
'''Injects any method or attribute from p_patchClass into klass.'''
patched = []
added = []
- for name, attr in patchClass.__dict__.iteritems():
+ for name, attr in patchClass.__dict__.items():
if name.startswith('__'): continue # Ignore special methods
# Unwrap functions from static methods
if attr.__class__.__name__ == 'staticmethod':
diff --git a/appy/pod/__init__.py b/appy/pod/__init__.py
index 6759b0c..233c965 100644
--- a/appy/pod/__init__.py
+++ b/appy/pod/__init__.py
@@ -69,7 +69,7 @@ class PodError(Exception):
'<%s:date>%s%s:date><%s:p>' % \
(officeNs, dcNs, dcNs, dcNs,
time.strftime('%Y-%m-%dT%H:%M:%S'), dcNs, textNs))
- buffer.dumpContent(message)
+ buffer.dumpContent(str(message))
buffer.write('%s:p>' % textNs)
if dumpTb:
# We don't dump the traceback if it is an expression error (it is
diff --git a/appy/pod/buffers.py b/appy/pod/buffers.py
index 96ceab7..857fcaf 100644
--- a/appy/pod/buffers.py
+++ b/appy/pod/buffers.py
@@ -222,7 +222,7 @@ class FileBuffer(Buffer):
def __init__(self, env, result):
Buffer.__init__(self, env, None)
self.result = result
- self.content = file(result, 'w')
+ self.content = open(result, 'w', encoding='utf-8')
self.content.write(xmlPrologue)
# getLength is used to manage insertions into sub-buffers. But in the case
@@ -231,10 +231,7 @@ class FileBuffer(Buffer):
def getLength(self): return 0
def write(self, something):
- try:
- self.content.write(something.encode('utf-8'))
- except UnicodeDecodeError:
- self.content.write(something)
+ self.content.write(something)
def addExpression(self, expression, tiedHook=None):
# At 2013-02-06, this method was not called within the whole test suite.
@@ -674,7 +671,7 @@ class MemoryBuffer(Buffer):
# Find the start position of the deepest element to remove
deepestElem = self.action.elem.DEEPEST_TO_REMOVE
pos = self.content.find('<%s' % deepestElem.elem)
- for index in self.elements.keys():
+ for index in list(self.elements.keys()):
if index < pos: del self.elements[index]
reTagContent = re.compile('<(?P
[\w-]+):(?P[\w-]+)(.*?)>.*(?P=p):' \
diff --git a/appy/pod/elements.py b/appy/pod/elements.py
index c4daf7b..1685dfd 100644
--- a/appy/pod/elements.py
+++ b/appy/pod/elements.py
@@ -150,7 +150,7 @@ class Expression(PodElement):
if resultType == 'NoneType':
res = ''
elif resultType == 'str':
- res = res.decode('utf-8')
+ pass
elif resultType == 'unicode':
pass # Don't perform any conversion, unicode is the target type.
elif resultType == 'Px':
diff --git a/appy/pod/pod_parser.py b/appy/pod/pod_parser.py
index 720474f..9a77734 100644
--- a/appy/pod/pod_parser.py
+++ b/appy/pod/pod_parser.py
@@ -38,7 +38,7 @@ class OdInsert:
styles). OdInsert instances define such 'inserts' (what to insert and
when).'''
def __init__(self, odtChunk, elem, nsUris={}):
- self.odtChunk = odtChunk.decode('utf-8') # The odt chunk to insert
+ self.odtChunk = odtChunk # The odt chunk to insert
self.elem = elem # The p_odtChunk will be inserted just after the p_elem
# start, which must be an XmlElement instance. If more than one p_elem
# is present in the odt file, the p_odtChunk will be inserted only at
diff --git a/appy/pod/renderer.py b/appy/pod/renderer.py
index cb05aac..8f54a8c 100644
--- a/appy/pod/renderer.py
+++ b/appy/pod/renderer.py
@@ -177,8 +177,8 @@ class Renderer:
self.unzipFolder = os.path.join(self.tempFolder, 'unzip')
os.mkdir(self.unzipFolder)
info = unzip(template, self.unzipFolder, odf=True)
- self.contentXml = info['content.xml']
- self.stylesXml = info['styles.xml']
+ self.contentXml = info['content.xml'].decode('utf-8')
+ self.stylesXml = info['styles.xml'].decode('utf-8')
self.stylesManager = StylesManager(self.stylesXml)
# From LibreOffice 3.5, it is not possible anymore to dump errors into
# the resulting ods as annotations. Indeed, annotations can't reside
@@ -524,11 +524,11 @@ class Renderer:
os.path.join(self.unzipFolder, innerFile))
# Insert dynamic styles
contentXml = os.path.join(self.unzipFolder, 'content.xml')
- f = file(contentXml)
+ f = open(contentXml, 'r+', encoding='utf-8')
dynamicStyles = ''.join(self.dynamicStyles)
content = f.read().replace('', dynamicStyles)
- f.close()
- f = file(contentXml, 'w')
+ f.seek(0)
+ f.truncate(0)
f.write(content)
f.close()
# Call the user-defined "finalize" function when present
diff --git a/appy/pod/test/Tester.py b/appy/pod/test/Tester.py
index 9e0748d..fbc7c4c 100644
--- a/appy/pod/test/Tester.py
+++ b/appy/pod/test/Tester.py
@@ -94,7 +94,7 @@ class Test(appy.shared.test.Test):
raise TesterError(CONTEXT_NOT_FOUND % contextPy)
contextPkg = 'appy.pod.test.contexts.%s' % contextName
exec('import %s' % contextPkg)
- exec('context = dir(%s)' % contextPkg)
+ context = eval('dir(%s)' % contextPkg)
res = {}
for elem in context:
if not elem.startswith('__'):
@@ -149,7 +149,7 @@ class Test(appy.shared.test.Test):
zipFile = zipfile.ZipFile(odtFile)
for zippedFile in zipFile.namelist():
if zippedFile in self.interestingOdtContent:
- f = file(os.path.join(self.tempFolder,
+ f = open(os.path.join(self.tempFolder,
'%s.%s' % (filePrefix, zippedFile)), 'wb')
fileContent = zipFile.read(zippedFile)
if zippedFile == 'content.xml':
@@ -159,12 +159,10 @@ class Test(appy.shared.test.Test):
# to the other. So we remove those paths.
annotationsRemover = AnnotationsRemover(
OdfEnvironment(), self)
- annotationsRemover.parse(fileContent)
- fileContent = annotationsRemover.getResult()
- try:
- f.write(fileContent.encode('utf-8'))
- except UnicodeDecodeError:
- f.write(fileContent)
+ annotationsRemover.parse(fileContent.decode('utf-8'))
+ fileContent = annotationsRemover.getResult().encode('utf-8')
+
+ f.write(fileContent)
f.close()
zipFile.close()
diff --git a/appy/pod/xhtml2odt.py b/appy/pod/xhtml2odt.py
index 9519998..8aa6885 100644
--- a/appy/pod/xhtml2odt.py
+++ b/appy/pod/xhtml2odt.py
@@ -282,7 +282,7 @@ class HtmlTable:
decl = '<%s:style %s:name="%s.%d" %s:family="table-column">' \
'<%s:table-column-properties %s:rel-column-width="%d*"' \
'/>%s:style>' % (s, s, self.name, i, s, s, s, width, s)
- renderer.dynamicStyles.append(decl.encode('utf-8'))
+ renderer.dynamicStyles.append(decl)
# ------------------------------------------------------------------------------
class XhtmlEnvironment(XmlEnvironment):
@@ -512,7 +512,7 @@ class XhtmlEnvironment(XmlEnvironment):
sizes = table.columnContentSizes
# Insert None values if the list is too small
while (len(sizes)-1) < table.cellIndex: sizes.append(None)
- highest = max(sizes[table.cellIndex], table.cellContentSize, 5)
+ highest = max(sizes[table.cellIndex] or 0, table.cellContentSize, 5)
# Put a maximum
highest = min(highest, 100)
sizes[table.cellIndex] = highest
diff --git a/appy/shared/css.py b/appy/shared/css.py
index 57f92ab..3edf8e4 100644
--- a/appy/shared/css.py
+++ b/appy/shared/css.py
@@ -10,7 +10,7 @@ def parseStyleAttribute(value, asDict=False):
else: res = []
for attr in value.split(';'):
if not attr.strip(): continue
- name, value = attr.split(':')
+ name, value = attr.split(':', 1)
if asDict: res[name.strip()] = value.strip()
else: res.append( (name.strip(), value.strip()) )
return res
@@ -42,9 +42,9 @@ class CssStyles:
'''Analyses styles as found in p_attrs and sets, for every found style,
an attribute on self.'''
# First, parse the "style" attr if present
- if attrs.has_key('style'):
+ if 'style' in attrs.keys():
styles = parseStyleAttribute(attrs['style'], asDict=True)
- for name, value in styles.iteritems():
+ for name, value in styles.items():
if name in CssStyles.withUnit:
value = CssValue(value)
setattr(self, name.replace('-', ''), value)
@@ -52,12 +52,12 @@ class CssStyles:
# override corresponding attributes from the "styles" attributes if
# found.
for name in ('width', 'height'):
- if not hasattr(self, name) and attrs.has_key(name):
+ if not hasattr(self, name) and name in attrs.keys():
setattr(self, name, CssValue(attrs[name]))
def __repr__(self):
res = ''
# ------------------------------------------------------------------------------
diff --git a/appy/shared/csv_parser.py b/appy/shared/csv_parser.py
index 1347cc7..1a10d5f 100644
--- a/appy/shared/csv_parser.py
+++ b/appy/shared/csv_parser.py
@@ -111,15 +111,15 @@ class CsvParser:
Python type specified in p_basicType (int, float, ...).'''
if (basicType != str) and (basicType != str):
try:
- exec('res = %s' % str(value))
+ res = eval('%s' % str(value))
except SyntaxError as se:
res = None
else:
try:
- exec('res = """%s"""' % str(value))
+ res = eval('"""%s"""' % str(value))
except SyntaxError as se:
try:
- exec("res = '''%s'''" % str(value))
+ res = eval("res = '''%s'''" % str(value))
except SyntaxError as se:
res = None
return res
diff --git a/appy/shared/dav.py b/appy/shared/dav.py
index 295fc02..4d7949f 100644
--- a/appy/shared/dav.py
+++ b/appy/shared/dav.py
@@ -34,7 +34,7 @@ class FormDataEncoder:
def encode(self):
res = []
- for name, value in self.data.iteritems():
+ for name, value in self.data.items():
res.append(self.marshalValue(name, value))
return '&'.join(res)
diff --git a/appy/shared/diff.py b/appy/shared/diff.py
index a836f7a..8167a8b 100644
--- a/appy/shared/diff.py
+++ b/appy/shared/diff.py
@@ -306,16 +306,16 @@ class HtmlDiff:
else: tag = 'span'
# What message will it show in its 'title' attribute?
if not msg:
- exec('msg = self.%sMsg' % type)
+ msg = eval('self.%sMsg' % type)
# What CSS class (or, if none, tag-specific style) will be used ?
- exec('cssClass = self.%sCss' % type)
+ cssClass = eval('self.%sCss' % type)
if cssClass:
style = 'class="%s"' % cssClass
else:
- exec('style = self.%sStyle' % type)
+ style = eval('self.%sStyle' % type)
style = 'style="%s"' % style
# The 'name' attribute of the tag indicates the type of the update.
- exec('tagName = self.%sName' % type)
+ tagName = eval('self.%sName' % type)
# The idea is: if there are several lines, every line must be surrounded
# by a tag. This way, we know that a surrounding tag can't span several
# lines, which is a prerequisite for managing cumulative diffs.
diff --git a/appy/shared/ldap_connector.py b/appy/shared/ldap_connector.py
index 772853f..e4f4f4f 100644
--- a/appy/shared/ldap_connector.py
+++ b/appy/shared/ldap_connector.py
@@ -83,7 +83,7 @@ class LdapConfig:
dict of params usable for creating or updating the corresponding
Appy user.'''
res = {}
- for name, appyName in self.ldapAttributes.iteritems():
+ for name, appyName in self.ldapAttributes.items():
if not appyName: continue
# Get the name of the attribute as known in the LDAP
ldapName = getattr(self, name)
@@ -111,7 +111,7 @@ class LdapConfig:
user = tool.search1('User', noSecurity=True, login=login)
if user:
# Yes. Update it with info about him from the LDAP
- for name, value in attrs.iteritems():
+ for name, value in attrs.items():
currentValue = getattr(user, name)
if value != currentValue:
setattr(user, name, value)
diff --git a/appy/shared/test.py b/appy/shared/test.py
index d5c9863..b16f95c 100644
--- a/appy/shared/test.py
+++ b/appy/shared/test.py
@@ -69,11 +69,9 @@ class TestReport:
TestReport.instance = self
else:
raise InternalError(TEST_REPORT_SINGLETON_ERROR)
- def say(self, msg, force=False, encoding=None):
+ def say(self, msg, force=False):
if self.verbose or force:
print(msg)
- if encoding:
- self.report.write(msg.encode(encoding))
else:
self.report.write(msg)
self.report.write('\n')
diff --git a/appy/shared/utils.py b/appy/shared/utils.py
index 6a9cbf5..42e53fb 100644
--- a/appy/shared/utils.py
+++ b/appy/shared/utils.py
@@ -194,7 +194,7 @@ def flipDict(d):
'''Flips dict p_d: keys become values, values become keys. p_d is left
untouched: a new, flipped, dict is returned.'''
res = {}
- for k, v in d.iteritems(): res[v] = k
+ for k, v in d.items(): res[v] = k
return res
# ------------------------------------------------------------------------------
@@ -291,7 +291,7 @@ def normalizeString(s, usage='fileName'):
for char in s:
if char not in fileNameIgnore: res += char
elif usage.startswith('alpha'):
- exec('rex = %sRex' % usage)
+ rex = eval('%sRex' % usage)
res = ''
for char in s:
if rex.match(char): res += char
diff --git a/appy/shared/xml_parser.py b/appy/shared/xml_parser.py
index d572668..2da2bc9 100644
--- a/appy/shared/xml_parser.py
+++ b/appy/shared/xml_parser.py
@@ -222,7 +222,7 @@ class XmlParser(ContentHandler, ErrorHandler):
'''This method is called every time expat does not recognize an entity.
We provide here support for HTML entities.'''
if name in HTML_ENTITIES:
- self.characters(HTML_ENTITIES[name].decode('utf-8'))
+ self.characters(HTML_ENTITIES[name])
else:
# Put a question mark instead of raising an exception.
self.characters('?')
@@ -245,23 +245,20 @@ class XmlParser(ContentHandler, ErrorHandler):
- a file instance opened for reading. Note that in this case, this
method will close it.
'''
- try:
- from io import StringIO
- except ImportError:
- from io import StringIO
+ from io import BytesIO
self._xml = xml
self.parser.setContentHandler(self)
self.parser.setErrorHandler(self)
self.parser.setFeature(feature_external_ges, False)
inputSource = InputSource()
if source == 'string':
- inputSource.setByteStream(StringIO(xml))
+ inputSource.setByteStream(BytesIO(xml.encode('utf-8')))
else:
- if not isinstance(xml, file):
- xml = file(xml)
+ if isinstance(xml, str):
+ xml = open(xml,'rb')
inputSource.setByteStream(xml)
self.parser.parse(inputSource)
- if isinstance(xml, file): xml.close()
+ if hasattr(xml, 'close'): xml.close()
return self.res
# ------------------------------------------------------------------------------
@@ -464,7 +461,7 @@ class XmlUnmarshaller(XmlParser):
# If not, try a standard conversion
elif e.currentBasicType in self.numericTypes:
try:
- exec('value = %s' % value)
+ value = eval('%s' % value)
except SyntaxError:
raise AppyError(CONVERSION_ERROR % (
e.currentBasicType, value))
@@ -945,10 +942,10 @@ class XmlComparator:
# Perform the comparison
differ = difflib.Differ()
if self.areXml:
- f = file(self.fileNameA)
+ f = open(self.fileNameA, 'rb')
contentA = f.read()
f.close()
- f = file(self.fileNameB)
+ f = open(self.fileNameB, 'rb')
contentB = f.read()
f.close()
xmlHandler = XmlHandler(self.xmlTagsToIgnore, self.xmlAttrsToIgnore)
@@ -958,10 +955,10 @@ class XmlComparator:
xml.sax.parseString(contentB, xmlHandler)
contentB = xmlHandler.res.split('\n')
else:
- f = file(self.fileNameA)
+ f = open(self.fileNameA, 'r', encoding=encoding)
contentA = f.readlines()
f.close()
- f = file(self.fileNameB)
+ f = open(self.fileNameB, 'r', encoding=encoding)
contentB = f.readlines()
f.close()
diffResult = list(differ.compare(contentA, contentB))
@@ -975,17 +972,17 @@ class XmlComparator:
if not atLeastOneDiff:
msg = 'Difference(s) detected between files %s and %s:' % \
(self.fileNameA, self.fileNameB)
- if report: report.say(msg, encoding='utf-8')
+ if report: report.say(msg)
else: print(msg)
atLeastOneDiff = True
if not lastLinePrinted:
if report: report.say('...')
else: print('...')
if self.areXml:
- if report: report.say(line, encoding=encoding)
+ if report: report.say(line)
else: print(line)
else:
- if report: report.say(line[:-1], encoding=encoding)
+ if report: report.say(line[:-1])
else: print((line[:-1]))
lastLinePrinted = True
else: