add python3 suppport based on 2to3 script

This commit is contained in:
Stefan Klug 2015-10-27 21:10:24 +01:00
parent caef0e85d0
commit 4f91a30fec
68 changed files with 597 additions and 576 deletions

View file

@ -22,26 +22,27 @@ class Object:
'''At every place we need an object, but without any requirement on its '''At every place we need an object, but without any requirement on its
class (methods, attributes,...) we will use this minimalist class.''' class (methods, attributes,...) we will use this minimalist class.'''
def __init__(self, **fields): def __init__(self, **fields):
for k, v in fields.iteritems(): for k, v in fields.items():
setattr(self, k, v) setattr(self, k, v)
def __repr__(self): def __repr__(self):
res = u'<Object ' res = '<Object '
for attrName, attrValue in self.__dict__.iteritems(): for attrName, attrValue in self.__dict__.items():
v = attrValue v = attrValue
if hasattr(v, '__repr__'): if hasattr(v, '__repr__'):
v = v.__repr__() v = v.__repr__()
try: try:
res += u'%s=%s ' % (attrName, v) res += '%s=%s ' % (attrName, v)
except UnicodeDecodeError: except UnicodeDecodeError:
res += u'%s=<encoding problem> ' % attrName res += '%s=<encoding problem> ' % attrName
res = res.strip() + '>' res = res.strip() + '>'
return res.encode('utf-8') return res.encode('utf-8')
def __nonzero__(self): return bool(self.__dict__) def __bool__(self):
return bool(self.__dict__)
def get(self, name, default=None): return getattr(self, name, default) def get(self, name, default=None): return getattr(self, name, default)
def __getitem__(self, k): return getattr(self, k) def __getitem__(self, k): return getattr(self, k)
def update(self, other): def update(self, other):
'''Includes information from p_other into p_self''' '''Includes information from p_other into p_self.'''
for k, v in other.__dict__.iteritems(): for k, v in other.__dict__.items():
setattr(self, k, v) setattr(self, k, v)
def clone(self): def clone(self):
res = Object() res = Object()
@ -59,11 +60,11 @@ class Hack:
"_base_<initial_method_name>_". In the patched method, one may use "_base_<initial_method_name>_". In the patched method, one may use
Hack.base to call the base method. If p_method is static, you must Hack.base to call the base method. If p_method is static, you must
specify its class in p_klass.''' specify its class in p_klass.'''
# Get the class on which the surgery will take place # Get the class on which the surgery will take place.
isStatic = klass isStatic = klass
klass = klass or method.im_class klass = klass or method.__self__.__class__
# On this class, store m_method under its "base" name # On this class, store m_method under its "base" name.
name = isStatic and method.func_name or method.im_func.__name__ name = isStatic and method.__name__ or method.__func__.__name__
baseName = '_base_%s_' % name baseName = '_base_%s_' % name
if isStatic: if isStatic:
# If "staticmethod" isn't called hereafter, the static functions # If "staticmethod" isn't called hereafter, the static functions
@ -78,8 +79,8 @@ class Hack:
'''Allows to call the base (replaced) method. If p_method is static, '''Allows to call the base (replaced) method. If p_method is static,
you must specify its p_klass.''' you must specify its p_klass.'''
isStatic = klass isStatic = klass
klass = klass or method.im_class klass = klass or method.__self__.__class__
name = isStatic and method.func_name or method.im_func.__name__ name = isStatic and method.__name__ or method.__func__.__name__
return getattr(klass, '_base_%s_' % name) return getattr(klass, '_base_%s_' % name)
@staticmethod @staticmethod
@ -87,7 +88,7 @@ class Hack:
'''Injects any method or attribute from p_patchClass into klass.''' '''Injects any method or attribute from p_patchClass into klass.'''
patched = [] patched = []
added = [] added = []
for name, attr in patchClass.__dict__.items(): for name, attr in patchClass.__dict__.iteritems():
if name.startswith('__'): continue # Ignore special methods if name.startswith('__'): continue # Ignore special methods
# Unwrap functions from static methods # Unwrap functions from static methods
if attr.__class__.__name__ == 'staticmethod': if attr.__class__.__name__ == 'staticmethod':

View file

@ -73,10 +73,10 @@ class AskSap:
# Return info about a given function. # Return info about a given function.
info = sap.getFunctionInfo(sapElement) info = sap.getFunctionInfo(sapElement)
prefix = 'Function' prefix = 'Function'
print('%s: %s' % (prefix, sapElement)) print(('%s: %s' % (prefix, sapElement)))
print(info) print(info)
sap.disconnect() sap.disconnect()
except SapError, se: except SapError as se:
sys.stderr.write(str(se)) sys.stderr.write(str(se))
sys.stderr.write('\n') sys.stderr.write('\n')
sys.exit(ERROR_CODE) sys.exit(ERROR_CODE)

View file

@ -4,7 +4,7 @@ from optparse import OptionParser
import ZODB.FileStorage import ZODB.FileStorage
import ZODB.serialize import ZODB.serialize
from DateTime import DateTime from DateTime import DateTime
from StringIO import StringIO from io import StringIO
folderName = os.path.dirname(__file__) folderName = os.path.dirname(__file__)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -87,9 +87,9 @@ class ZodbBackuper:
w('Try to create backup folder for logs "%s"...' % \ w('Try to create backup folder for logs "%s"...' % \
self.logsBackupFolder) self.logsBackupFolder)
os.mkdir(self.logsBackupFolder) os.mkdir(self.logsBackupFolder)
except IOError, ioe: except IOError as ioe:
w(folderCreateError % str(ioe)) w(folderCreateError % str(ioe))
except OSError, oe: except OSError as oe:
w(folderCreateError % str(oe)) w(folderCreateError % str(oe))
if os.path.exists(self.logsBackupFolder): if os.path.exists(self.logsBackupFolder):
# Ok, we can make the backup of the log files. # Ok, we can make the backup of the log files.
@ -175,7 +175,7 @@ class ZodbBackuper:
except smtplib.SMTPException, sme: except smtplib.SMTPException, sme:
w('Error while contacting SMTP server %s (%s).' % \ w('Error while contacting SMTP server %s (%s).' % \
(self.options.smtpServer, str(se))) (self.options.smtpServer, str(se)))
except socket.error, se: except socket.error as se:
w('Could not connect to SMTP server %s (%s).' % \ w('Could not connect to SMTP server %s (%s).' % \
(self.options.smtpServer, str(se))) (self.options.smtpServer, str(se)))
@ -191,12 +191,12 @@ class ZodbBackuper:
for fileName in os.listdir(self.tempFolder): for fileName in os.listdir(self.tempFolder):
ext = os.path.splitext(fileName)[1] ext = os.path.splitext(fileName)[1]
if ext in self.toRemoveExts: if ext in self.toRemoveExts:
exec '%sCount += 1' % ext[1:] exec('%sCount += 1' % ext[1:])
fullFileName = os.path.join(self.tempFolder, fileName) fullFileName = os.path.join(self.tempFolder, fileName)
#w('Removing "%s"...' % fullFileName) #w('Removing "%s"...' % fullFileName)
try: try:
os.remove(fullFileName) os.remove(fullFileName)
except OSError, oe: except OSError as oe:
w('Could not remove "%s" (%s).' % (fullFileName, str(oe))) w('Could not remove "%s" (%s).' % (fullFileName, str(oe)))
w('%d .pdf, %d .doc, %d .rtf and %d .odt file(s) removed.' % \ w('%d .pdf, %d .doc, %d .rtf and %d .odt file(s) removed.' % \
(pdfCount, docCount, rtfCount, odtCount)) (pdfCount, docCount, rtfCount, odtCount))
@ -268,7 +268,7 @@ class ZodbBackuper:
if self.emails: if self.emails:
self.sendEmails() self.sendEmails()
self.logFile.close() self.logFile.close()
print(self.logMem.getvalue()) print((self.logMem.getvalue()))
self.logMem.close() self.logMem.close()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -302,7 +302,7 @@ class ZodbBackupScript:
f.write('Hello.') f.write('Hello.')
f.close() f.close()
os.remove(fileName) os.remove(fileName)
except OSError, oe: except OSError as oe:
raise BackupError('I do not have the right to write in ' \ raise BackupError('I do not have the right to write in ' \
'folder "%s".' % args[1]) 'folder "%s".' % args[1])
# Check temp folder # Check temp folder
@ -401,7 +401,7 @@ class ZodbBackupScript:
self.checkArgs(options, args) self.checkArgs(options, args)
backuper = ZodbBackuper(args[0], args[1], options) backuper = ZodbBackuper(args[0], args[1], options)
backuper.run() backuper.run()
except BackupError, be: except BackupError as be:
sys.stderr.write(str(be) + '\nRun the script without any ' \ sys.stderr.write(str(be) + '\nRun the script without any ' \
'argument for getting help.\n') 'argument for getting help.\n')
sys.exit(ERROR_CODE) sys.exit(ERROR_CODE)

View file

@ -21,7 +21,7 @@ class LdapTester:
def __init__(self): def __init__(self):
# Get params from shell args. # Get params from shell args.
if len(sys.argv) != 8: if len(sys.argv) != 8:
print(LdapTester.__doc__) print((LdapTester.__doc__))
sys.exit(0) sys.exit(0)
s = self s = self
s.uri,s.login,s.password,s.base,s.attrs,s.filter,s.scope = sys.argv[1:] s.uri,s.login,s.password,s.base,s.attrs,s.filter,s.scope = sys.argv[1:]
@ -33,15 +33,15 @@ class LdapTester:
def test(self): def test(self):
# Connect the the LDAP # Connect the the LDAP
print('Connecting to... %s' % self.uri) print(('Connecting to... %s' % self.uri))
connector = LdapConnector(self.uri) connector = LdapConnector(self.uri)
success, msg = connector.connect(self.login, self.password) success, msg = connector.connect(self.login, self.password)
if not success: return if not success: return
# Perform the query. # Perform the query.
print ('Querying %s...' % self.base) print(('Querying %s...' % self.base))
res = connector.search(self.base, self.scope, self.filter, res = connector.search(self.base, self.scope, self.filter,
self.attributes) self.attributes)
print('Got %d results' % len(res)) print(('Got %d results' % len(res)))
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
if __name__ == '__main__': LdapTester().test() if __name__ == '__main__': LdapTester().test()

View file

@ -110,12 +110,12 @@ class EggifyScript:
eggFullName = j(self.eggFolder, self.eggName) eggFullName = j(self.eggFolder, self.eggName)
if os.path.exists(eggFullName): if os.path.exists(eggFullName):
os.remove(eggFullName) os.remove(eggFullName)
print('Existing "%s" was removed.' % eggFullName) print(('Existing "%s" was removed.' % eggFullName))
# Create a temp folder where to store the egg # Create a temp folder where to store the egg
eggTempFolder = os.path.splitext(eggFullName)[0] eggTempFolder = os.path.splitext(eggFullName)[0]
if os.path.exists(eggTempFolder): if os.path.exists(eggTempFolder):
FolderDeleter.delete(eggTempFolder) FolderDeleter.delete(eggTempFolder)
print('Removed "%s" that was in my way.' % eggTempFolder) print(('Removed "%s" that was in my way.' % eggTempFolder))
os.mkdir(eggTempFolder) os.mkdir(eggTempFolder)
# Create the "Products" sub-folder if we must wrap the package in this # Create the "Products" sub-folder if we must wrap the package in this
# namespace # namespace
@ -170,7 +170,7 @@ class EggifyScript:
try: try:
self.checkArgs(options, args) self.checkArgs(options, args)
self.eggify() self.eggify()
except EggifierError, ee: except EggifierError as ee:
sys.stderr.write(str(ee) + '\nRun eggify.py -h for getting help.\n') sys.stderr.write(str(ee) + '\nRun eggify.py -h for getting help.\n')
sys.exit(ERROR_CODE) sys.exit(ERROR_CODE)

View file

@ -41,7 +41,7 @@ class GeneratorScript:
sys.exit(ERROR_CODE) sys.exit(ERROR_CODE)
# Check existence of application # Check existence of application
if not os.path.exists(args[0]): if not os.path.exists(args[0]):
print(APP_NOT_FOUND % args[0]) print((APP_NOT_FOUND % args[0]))
sys.exit(ERROR_CODE) sys.exit(ERROR_CODE)
# Convert app path to an absolute path # Convert app path to an absolute path
args[0] = os.path.abspath(args[0]) args[0] = os.path.abspath(args[0])
@ -55,8 +55,8 @@ class GeneratorScript:
(options, args) = optParser.parse_args() (options, args) = optParser.parse_args()
try: try:
self.manageArgs(optParser, options, args) self.manageArgs(optParser, options, args)
print('Appy version: %s' % appy.version.verbose) print(('Appy version: %s' % appy.version.verbose))
print('Generating Zope product in %s/zope...' % args[0]) print(('Generating Zope product in %s/zope...' % args[0]))
ZopeGenerator(args[0], options).run() ZopeGenerator(args[0], options).run()
# Give the user some statistics about its code # Give the user some statistics about its code
LinesCounter(args[0], excludes=['%szope' % os.sep]).run() LinesCounter(args[0], excludes=['%szope' % os.sep]).run()
@ -71,7 +71,7 @@ class GeneratorScript:
f.close() f.close()
version = version[:version.find('build')-1] version = version[:version.find('build')-1]
Debianizer(app, appDir, appVersion=version).run() Debianizer(app, appDir, appVersion=version).run()
except GeneratorError, ge: except GeneratorError as ge:
sys.stderr.write(str(ge)) sys.stderr.write(str(ge))
sys.stderr.write('\n') sys.stderr.write('\n')
optParser.print_help() optParser.print_help()

View file

@ -82,6 +82,6 @@ else:
targetObject = getattr(targetObject, elem) targetObject = getattr(targetObject, elem)
# Execute the method on the target object # Execute the method on the target object
if args: args = args.split('*') if args: args = args.split('*')
exec 'targetObject.%s(*args)' % toolMethod exec('targetObject.%s(*args)' % toolMethod)
transaction.commit() transaction.commit()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -106,17 +106,17 @@ class ZopeInstanceCreator:
f = file('bin/zopectl', 'w') f = file('bin/zopectl', 'w')
f.write(zopeCtl % self.instancePath) f.write(zopeCtl % self.instancePath)
f.close() f.close()
os.chmod('bin/zopectl', 0744) # Make it executable by owner. os.chmod('bin/zopectl', 0o744) # Make it executable by owner.
# Create bin/runzope # Create bin/runzope
f = file('bin/runzope', 'w') f = file('bin/runzope', 'w')
f.write(runZope % self.instancePath) f.write(runZope % self.instancePath)
f.close() f.close()
os.chmod('bin/runzope', 0744) # Make it executable by owner. os.chmod('bin/runzope', 0o744) # Make it executable by owner.
# Create bin/startoo # Create bin/startoo
f = file('bin/startoo', 'w') f = file('bin/startoo', 'w')
f.write(ooStart) f.write(ooStart)
f.close() f.close()
os.chmod('bin/startoo', 0744) # Make it executable by owner. os.chmod('bin/startoo', 0o744) # Make it executable by owner.
# Create etc/zope.conf # Create etc/zope.conf
os.mkdir('etc') os.mkdir('etc')
f = file('etc/zope.conf', 'w') f = file('etc/zope.conf', 'w')
@ -138,10 +138,10 @@ class ZopeInstanceCreator:
password = binascii.b2a_base64(sha('admin').digest())[:-1] password = binascii.b2a_base64(sha('admin').digest())[:-1]
f.write('admin:{SHA}%s\n' % password) f.write('admin:{SHA}%s\n' % password)
f.close() f.close()
os.chmod('inituser', 0644) os.chmod('inituser', 0o644)
# User "zope" must own this instance # User "zope" must own this instance
os.system('chown -R zope %s' % self.instancePath) os.system('chown -R zope %s' % self.instancePath)
print('Zope instance created in %s.' % self.instancePath) print(('Zope instance created in %s.' % self.instancePath))
os.chdir(curdir) os.chdir(curdir)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -229,7 +229,7 @@ class NewScript:
j = os.path.join j = os.path.join
# As eggs have been deleted, versions of components are lost. Reify # As eggs have been deleted, versions of components are lost. Reify
# them from p_versions. # them from p_versions.
dVersions = ['"%s":"%s"' % (n, v) for n, v in versions.iteritems()] dVersions = ['"%s":"%s"' % (n, v) for n, v in versions.items()]
sVersions = 'appyVersions = {' + ','.join(dVersions) + '}' sVersions = 'appyVersions = {' + ','.join(dVersions) + '}'
codeFile = "%s/pkg_resources.py" % self.libFolder codeFile = "%s/pkg_resources.py" % self.libFolder
f = file(codeFile) f = file(codeFile)
@ -326,7 +326,7 @@ class NewScript:
action = 'Copying' action = 'Copying'
if linksForProducts: if linksForProducts:
action = 'Symlinking' action = 'Symlinking'
print('%s Plone stuff in the Zope instance...' % action) print(('%s Plone stuff in the Zope instance...' % action))
if self.ploneVersion in ('plone25', 'plone30'): if self.ploneVersion in ('plone25', 'plone30'):
self.installPlone25or30Stuff(linksForProducts) self.installPlone25or30Stuff(linksForProducts)
elif self.ploneVersion in ('plone3x', 'plone4'): elif self.ploneVersion in ('plone3x', 'plone4'):
@ -379,11 +379,11 @@ class NewScript:
try: try:
self.manageArgs(args) self.manageArgs(args)
if self.ploneVersion != 'zope': if self.ploneVersion != 'zope':
print('Creating new %s instance...' % self.ploneVersion) print(('Creating new %s instance...' % self.ploneVersion))
self.createInstance(linksForProducts) self.createInstance(linksForProducts)
else: else:
ZopeInstanceCreator(self.instancePath).run() ZopeInstanceCreator(self.instancePath).run()
except NewError, ne: except NewError as ne:
optParser.print_help() optParser.print_help()
sys.stderr.write(str(ne)) sys.stderr.write(str(ne))
sys.stderr.write('\n') sys.stderr.write('\n')

View file

@ -52,7 +52,7 @@ class OdfGrep:
# Run "grep" in this folder # Run "grep" in this folder
match = self.callGrep(tempFolder) match = self.callGrep(tempFolder)
if match: if match:
print('Found in %s' % fileName) print(('Found in %s' % fileName))
FolderDeleter.delete(tempFolder) FolderDeleter.delete(tempFolder)
def run(self): def run(self):
@ -65,7 +65,7 @@ class OdfGrep:
if os.path.splitext(name)[1] in self.toUnzip: if os.path.splitext(name)[1] in self.toUnzip:
self.grepFile(os.path.join(dir, name)) self.grepFile(os.path.join(dir, name))
else: else:
print('%s does not exist.' % self.fileOrFolder) print(('%s does not exist.' % self.fileOrFolder))
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
if __name__ == '__main__': if __name__ == '__main__':

View file

@ -85,8 +85,8 @@ class FtpFolder:
def clean(self, site): def clean(self, site):
'''Cleans this folder''' '''Cleans this folder'''
# First, clean subFolders if they exist # First, clean subFolders if they exist
print('Cleaning %s %d subFolders' % \ print(('Cleaning %s %d subFolders' % \
(self.getFullName(), len(self.subFolders))) (self.getFullName(), len(self.subFolders))))
for subFolder in self.subFolders: for subFolder in self.subFolders:
subFolder.clean(site) subFolder.clean(site)
# Remove the subFolder # Remove the subFolder
@ -95,7 +95,7 @@ class FtpFolder:
for f in self.files: for f in self.files:
fileName = '%s/%s' % (self.getFullName(), f) fileName = '%s/%s' % (self.getFullName(), f)
site.delete(fileName) site.delete(fileName)
print('%s removed.' % fileName) print(('%s removed.' % fileName))
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class AppySite: class AppySite:
@ -148,11 +148,11 @@ class AppySite:
fileExt = os.path.splitext(fileName)[1] fileExt = os.path.splitext(fileName)[1]
if fileExt in self.textExtensions: if fileExt in self.textExtensions:
# Make a transfer in text mode # Make a transfer in text mode
print('Transfer file %s (text mode)' % fileName) print(('Transfer file %s (text mode)' % fileName))
self.site.storlines(cmd, localFile) self.site.storlines(cmd, localFile)
else: else:
# Make a transfer in binary mode # Make a transfer in binary mode
print('Transfer file %s (binary mode)' % fileName) print(('Transfer file %s (binary mode)' % fileName))
self.site.storbinary(cmd, localFile) self.site.storbinary(cmd, localFile)
def publish(self): def publish(self):
@ -257,7 +257,7 @@ class Publisher:
yesNo = '[Y/n]' yesNo = '[Y/n]'
else: else:
yesNo = '[y/N]' yesNo = '[y/N]'
print(question + ' ' + yesNo + ' ') print((question + ' ' + yesNo + ' '))
response = sys.stdin.readline().strip().lower() response = sys.stdin.readline().strip().lower()
res = False res = False
if response in ('y', 'yes'): if response in ('y', 'yes'):
@ -274,7 +274,7 @@ class Publisher:
def executeCommand(self, cmd): def executeCommand(self, cmd):
'''Executes the system command p_cmd.''' '''Executes the system command p_cmd.'''
print('Executing %s...' % cmd) print(('Executing %s...' % cmd))
os.system(cmd) os.system(cmd)
distExcluded = ('appy/doc', 'appy/temp', 'appy/versions', 'appy/gen/test') distExcluded = ('appy/doc', 'appy/temp', 'appy/versions', 'appy/gen/test')
@ -340,7 +340,7 @@ class Publisher:
newZipRelease, default='yes'): newZipRelease, default='yes'):
print('Publication canceled.') print('Publication canceled.')
sys.exit(1) sys.exit(1)
print('Removing obsolete %s...' % newZipRelease) print(('Removing obsolete %s...' % newZipRelease))
os.remove(newZipRelease) os.remove(newZipRelease)
zipFile = zipfile.ZipFile(newZipRelease, 'w', zipfile.ZIP_DEFLATED) zipFile = zipfile.ZipFile(newZipRelease, 'w', zipfile.ZIP_DEFLATED)
curdir = os.getcwd() curdir = os.getcwd()
@ -474,7 +474,7 @@ class Publisher:
if minimalist: if minimalist:
FolderDeleter.delete('%s/pod/test' % genSrcFolder) FolderDeleter.delete('%s/pod/test' % genSrcFolder)
# Write the appy version into the code itself (in appy/version.py)''' # Write the appy version into the code itself (in appy/version.py)'''
print('Publishing version %s...' % self.versionShort) print(('Publishing version %s...' % self.versionShort))
# Dump version info in appy/version.py # Dump version info in appy/version.py
f = file('%s/version.py' % genSrcFolder, 'w') f = file('%s/version.py' % genSrcFolder, 'w')
f.write('short = "%s"\n' % self.versionShort) f.write('short = "%s"\n' % self.versionShort)
@ -495,7 +495,7 @@ class Publisher:
Cleaner().run(verbose=False) Cleaner().run(verbose=False)
# Perform a small analysis on the Appy code # Perform a small analysis on the Appy code
LinesCounter(appy).run() LinesCounter(appy).run()
print('Generating site in %s...' % self.genFolder) print(('Generating site in %s...' % self.genFolder))
minimalist = self.askQuestion('Minimalist (shipped without tests)?', minimalist = self.askQuestion('Minimalist (shipped without tests)?',
default='no') default='no')
self.prepareGenFolder(minimalist) self.prepareGenFolder(minimalist)

View file

@ -21,10 +21,10 @@ class ZodbRestorer:
datePart = '-D %s' % self.restoreDate datePart = '-D %s' % self.restoreDate
repozoCmd = '%s %s -Rv -r %s %s -o %s' % (self.python, repozoCmd = '%s %s -Rv -r %s %s -o %s' % (self.python,
self.repozo, self.backupFolder, datePart, self.storageLocation) self.repozo, self.backupFolder, datePart, self.storageLocation)
print('Executing %s...' % repozoCmd) print(('Executing %s...' % repozoCmd))
os.system(repozoCmd) os.system(repozoCmd)
stopTime = time.time() stopTime = time.time()
print('Done in %d minute(s).' % ((stopTime-startTime)/60)) print(('Done in %d minute(s).' % ((stopTime-startTime)/60)))
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class ZodbRestoreScript: class ZodbRestoreScript:
@ -56,7 +56,7 @@ class ZodbRestoreScript:
f.write('Hello.') f.write('Hello.')
f.close() f.close()
os.remove(args[0]) os.remove(args[0])
except OSError, oe: except OSError as oe:
raise RestoreError('I do not have the right to write file ' \ raise RestoreError('I do not have the right to write file ' \
'"%s".' % args[0]) '"%s".' % args[0])
@ -81,7 +81,7 @@ class ZodbRestoreScript:
self.checkArgs(options, args) self.checkArgs(options, args)
backuper = ZodbRestorer(args[0], args[1], options) backuper = ZodbRestorer(args[0], args[1], options)
backuper.run() backuper.run()
except RestoreError, be: except RestoreError as be:
sys.stderr.write(str(be)) sys.stderr.write(str(be))
sys.stderr.write('\n') sys.stderr.write('\n')
optParser.print_help() optParser.print_help()

View file

@ -8,29 +8,29 @@ class Zipper:
def __init__(self): def __init__(self):
self.zipFileName = '%s/Desktop/appy.zip' % os.environ['HOME'] self.zipFileName = '%s/Desktop/appy.zip' % os.environ['HOME']
def createZipFile(self): def createZipFile(self):
print('Creating %s...' % self.zipFileName) print(('Creating %s...' % self.zipFileName))
zipFile = zipfile.ZipFile(self.zipFileName, 'w', zipfile.ZIP_DEFLATED) zipFile = zipfile.ZipFile(self.zipFileName, 'w', zipfile.ZIP_DEFLATED)
for dir, dirnames, filenames in os.walk(appyPath): for dir, dirnames, filenames in os.walk(appyPath):
for f in filenames: for f in filenames:
fileName = os.path.join(dir, f) fileName = os.path.join(dir, f)
arcName = fileName[fileName.find('appy/'):] arcName = fileName[fileName.find('appy/'):]
print('Adding %s' % fileName) print(('Adding %s' % fileName))
zipFile.write(fileName, arcName) zipFile.write(fileName, arcName)
zipFile.close() zipFile.close()
def run(self): def run(self):
# Where to put the zip file ? # Where to put the zip file ?
print("Where do you want to put appy.zip ? [Default is %s] " % \ print(("Where do you want to put appy.zip ? [Default is %s] " % \
os.path.dirname(self.zipFileName)) os.path.dirname(self.zipFileName)))
response = sys.stdin.readline().strip() response = sys.stdin.readline().strip()
if response: if response:
if os.path.exists(response) and os.path.isdir(response): if os.path.exists(response) and os.path.isdir(response):
self.zipFileName = '%s/appy.zip' % response self.zipFileName = '%s/appy.zip' % response
else: else:
print('%s is not a folder.' % response) print(('%s is not a folder.' % response))
sys.exit(1) sys.exit(1)
if os.path.exists(self.zipFileName): if os.path.exists(self.zipFileName):
print('Removing existing %s...' % self.zipFileName) print(('Removing existing %s...' % self.zipFileName))
os.remove(self.zipFileName) os.remove(self.zipFileName)
Cleaner().run(verbose=False) Cleaner().run(verbose=False)
self.createZipFile() self.createZipFile()

View file

@ -21,9 +21,9 @@ from appy.gen.layout import Table, defaultFieldLayouts
from appy.gen import utils as gutils from appy.gen import utils as gutils
from appy.px import Px from appy.px import Px
from appy.shared import utils as sutils from appy.shared import utils as sutils
from group import Group from .group import Group
from search import Search from .page import Page
from page import Page import collections
# In this file, names "list" and "dict" refer to sub-modules. To use Python # In this file, names "list" and "dict" refer to sub-modules. To use Python
# builtin types, use __builtins__['list'] and __builtins__['dict'] # builtin types, use __builtins__['list'] and __builtins__['dict']
@ -370,7 +370,7 @@ class Field:
labelName = name labelName = name
trPrefix = None trPrefix = None
if self.label: if self.label:
if isinstance(self.label, basestring): trPrefix = self.label if isinstance(self.label, str): trPrefix = self.label
else: # It is a tuple (trPrefix, name) else: # It is a tuple (trPrefix, name)
if self.label[1]: labelName = self.label[1] if self.label[1]: labelName = self.label[1]
if self.label[0]: trPrefix = self.label[0] if self.label[0]: trPrefix = self.label[0]
@ -382,16 +382,16 @@ class Field:
self.helpId = self.labelId + '_help' self.helpId = self.labelId + '_help'
# Determine read and write permissions for this field # Determine read and write permissions for this field
rp = self.specificReadPermission rp = self.specificReadPermission
if rp and not isinstance(rp, basestring): if rp and not isinstance(rp, str):
self.readPermission = '%s: Read %s %s' % (appName, prefix, name) self.readPermission = '%s: Read %s %s' % (appName, prefix, name)
elif rp and isinstance(rp, basestring): elif rp and isinstance(rp, str):
self.readPermission = rp self.readPermission = rp
else: else:
self.readPermission = 'read' self.readPermission = 'read'
wp = self.specificWritePermission wp = self.specificWritePermission
if wp and not isinstance(wp, basestring): if wp and not isinstance(wp, str):
self.writePermission = '%s: Write %s %s' % (appName, prefix, name) self.writePermission = '%s: Write %s %s' % (appName, prefix, name)
elif wp and isinstance(wp, basestring): elif wp and isinstance(wp, str):
self.writePermission = wp self.writePermission = wp
else: else:
self.writePermission = 'write' self.writePermission = 'write'
@ -442,7 +442,7 @@ class Field:
self.readPermission self.readPermission
if not obj.allows(perm): return if not obj.allows(perm): return
# Evaluate self.show # Evaluate self.show
if callable(self.show): if isinstance(self.show, collections.Callable):
res = self.callMethod(obj, self.show) res = self.callMethod(obj, self.show)
else: else:
res = self.show res = self.show
@ -480,7 +480,7 @@ class Field:
if not masterData: return True if not masterData: return True
else: else:
master, masterValue = masterData master, masterValue = masterData
if masterValue and callable(masterValue): return True if masterValue and isinstance(masterValue, collections.Callable): return True
reqValue = master.getRequestValue(obj) reqValue = master.getRequestValue(obj)
# reqValue can be a list or not # reqValue can be a list or not
if type(reqValue) not in sutils.sequenceTypes: if type(reqValue) not in sutils.sequenceTypes:
@ -496,8 +496,8 @@ class Field:
if isinstance(mapping, __builtins__['dict']): if isinstance(mapping, __builtins__['dict']):
# Is it a dict like {'label':..., 'descr':...}, or is it directly a # Is it a dict like {'label':..., 'descr':...}, or is it directly a
# dict with a mapping? # dict with a mapping?
for k, v in mapping.iteritems(): for k, v in mapping.items():
if (k not in self.labelTypes) or isinstance(v, basestring): if (k not in self.labelTypes) or isinstance(v, str):
# It is already a mapping # It is already a mapping
return {'label':mapping, 'descr':mapping, 'help':mapping} return {'label':mapping, 'descr':mapping, 'help':mapping}
# If we are here, we have {'label':..., 'descr':...}. Complete # If we are here, we have {'label':..., 'descr':...}. Complete
@ -520,7 +520,7 @@ class Field:
areDefault = True areDefault = True
layouts = self.computeDefaultLayouts() layouts = self.computeDefaultLayouts()
else: else:
if isinstance(layouts, basestring): if isinstance(layouts, str):
# The user specified a single layoutString (the "edit" one) # The user specified a single layoutString (the "edit" one)
layouts = {'edit': layouts} layouts = {'edit': layouts}
elif isinstance(layouts, Table): elif isinstance(layouts, Table):
@ -541,8 +541,8 @@ class Field:
# We have now a dict of layouts in p_layouts. Ensure now that a Table # We have now a dict of layouts in p_layouts. Ensure now that a Table
# instance is created for every layout (=value from the dict). Indeed, # instance is created for every layout (=value from the dict). Indeed,
# a layout could have been expressed as a simple layout string. # a layout could have been expressed as a simple layout string.
for layoutType in layouts.iterkeys(): for layoutType in layouts.keys():
if isinstance(layouts[layoutType], basestring): if isinstance(layouts[layoutType], str):
layouts[layoutType] = Table(layouts[layoutType]) layouts[layoutType] = Table(layouts[layoutType])
# Derive "view", "search" and "cell" layouts from the "edit" layout # Derive "view", "search" and "cell" layouts from the "edit" layout
# when relevant. # when relevant.
@ -566,11 +566,11 @@ class Field:
if areDefault and not self.group and \ if areDefault and not self.group and \
not ((self.type == 'String') and (self.format == self.XHTML)) and \ not ((self.type == 'String') and (self.format == self.XHTML)) and \
not (self.type == 'Ref'): not (self.type == 'Ref'):
for layoutType in layouts.iterkeys(): for layoutType in layouts.keys():
layouts[layoutType].width = '' layouts[layoutType].width = ''
# Remove letters "r" from the layouts if the field is not required. # Remove letters "r" from the layouts if the field is not required.
if not self.required: if not self.required:
for layoutType in layouts.iterkeys(): for layoutType in layouts.keys():
layouts[layoutType].removeElement('r') layouts[layoutType].removeElement('r')
# Derive some boolean values from the layouts. # Derive some boolean values from the layouts.
self.hasLabel = self.hasLayoutElement('l', layouts) self.hasLabel = self.hasLayoutElement('l', layouts)
@ -597,7 +597,7 @@ class Field:
def hasLayoutElement(self, element, layouts): def hasLayoutElement(self, element, layouts):
'''This method returns True if the given layout p_element can be found '''This method returns True if the given layout p_element can be found
at least once among the various p_layouts defined for this field.''' at least once among the various p_layouts defined for this field.'''
for layout in layouts.itervalues(): for layout in layouts.values():
if element in layout.layoutString: return True if element in layout.layoutString: return True
return False return False
@ -610,7 +610,7 @@ class Field:
'''Gets, as a string, the layouts as could have been specified as input '''Gets, as a string, the layouts as could have been specified as input
value for the Field constructor.''' value for the Field constructor.'''
res = '{' res = '{'
for k, v in self.layouts.iteritems(): for k, v in self.layouts.items():
res += '"%s":"%s",' % (k, v.layoutString) res += '"%s":"%s",' % (k, v.layoutString)
res += '}' res += '}'
return res return res
@ -650,7 +650,7 @@ class Field:
if self.isEmptyValue(obj, value): if self.isEmptyValue(obj, value):
# If there is no value, get the default value if any: return # If there is no value, get the default value if any: return
# self.default, of self.default() if it is a method. # self.default, of self.default() if it is a method.
if callable(self.default): if isinstance(self.default, collections.Callable):
try: try:
# Caching a default value can lead to problems. For example, # Caching a default value can lead to problems. For example,
# the process of creating an object from another one, or # the process of creating an object from another one, or
@ -660,7 +660,7 @@ class Field:
# but it they depend on values set at (b), and are cached # but it they depend on values set at (b), and are cached
# and indexed, (c) will get the wrong, cached value. # and indexed, (c) will get the wrong, cached value.
return self.callMethod(obj, self.default, cache=False) return self.callMethod(obj, self.default, cache=False)
except Exception, e: except Exception as e:
# Already logged. Here I do not raise the exception, # Already logged. Here I do not raise the exception,
# because it can be raised as the result of reindexing # because it can be raised as the result of reindexing
# the object in situations that are not foreseen by # the object in situations that are not foreseen by
@ -723,12 +723,13 @@ class Field:
# Start by getting the field value on p_obj # Start by getting the field value on p_obj
res = self.getValue(obj) res = self.getValue(obj)
# Zope catalog does not like unicode strings # Zope catalog does not like unicode strings
if isinstance(res, unicode): res = res.encode('utf-8') if isinstance(value, str):
res = value.encode('utf-8')
if forSearch and (res != None): if forSearch and (res != None):
if type(res) in sutils.sequenceTypes: if type(res) in sutils.sequenceTypes:
vals = [] vals = []
for v in res: for v in res:
if isinstance(v, unicode): vals.append(v.encode('utf-8')) if isinstance(v, str): vals.append(v.encode('utf-8'))
else: vals.append(str(v)) else: vals.append(str(v))
res = ' '.join(vals) res = ' '.join(vals)
else: else:
@ -824,7 +825,7 @@ class Field:
this field is the slave of another field.''' this field is the slave of another field.'''
if not self.master: return '' if not self.master: return ''
res = 'slave*%s*' % self.masterName res = 'slave*%s*' % self.masterName
if not callable(self.masterValue): if not isinstance(self.masterValue, collections.Callable):
res += '*'.join(self.masterValue) res += '*'.join(self.masterValue)
else: else:
res += '+' res += '+'
@ -866,7 +867,7 @@ class Field:
def securityCheck(self, obj, value): def securityCheck(self, obj, value):
'''This method performs some security checks on the p_value that '''This method performs some security checks on the p_value that
represents user input.''' represents user input.'''
if not isinstance(value, basestring): return if not isinstance(value, str): return
# Search Javascript code in the value (prevent XSS attacks). # Search Javascript code in the value (prevent XSS attacks).
if '<script' in value: if '<script' in value:
obj.log('Detected Javascript in user input.', type='error') obj.log('Detected Javascript in user input.', type='error')
@ -900,14 +901,14 @@ class Field:
# It is a custom function: execute it # It is a custom function: execute it
try: try:
validValue = self.validator(obj, value) validValue = self.validator(obj, value)
if isinstance(validValue, basestring) and validValue: if isinstance(validValue, str) and validValue:
# Validation failed; and p_validValue contains an error # Validation failed; and p_validValue contains an error
# message. # message.
return validValue return validValue
else: else:
if not validValue: if not validValue:
return obj.translate('field_invalid') return obj.translate('field_invalid')
except Exception, e: except Exception as e:
return str(e) return str(e)
except: except:
return obj.translate('field_invalid') return obj.translate('field_invalid')
@ -931,7 +932,7 @@ class Field:
obj = obj.appy() obj = obj.appy()
try: try:
return gutils.callMethod(obj, method, cache=cache) return gutils.callMethod(obj, method, cache=cache)
except TypeError, te: except TypeError as te:
# Try a version of the method that would accept self as an # Try a version of the method that would accept self as an
# additional parameter. In this case, we do not try to cache the # additional parameter. In this case, we do not try to cache the
# value (we do not call gutils.callMethod), because the value may # value (we do not call gutils.callMethod), because the value may
@ -939,11 +940,11 @@ class Field:
tb = sutils.Traceback.get() tb = sutils.Traceback.get()
try: try:
return method(obj, self) return method(obj, self)
except Exception, e: except Exception as e:
obj.log(tb, type='error') obj.log(tb, type='error')
# Raise the initial error. # Raise the initial error.
raise te raise te
except Exception, e: except Exception as e:
obj.log(sutils.Traceback.get(), type='error') obj.log(sutils.Traceback.get(), type='error')
raise e raise e
@ -951,7 +952,7 @@ class Field:
'''Gets the value of attribue p_name on p_self, which can be a simple '''Gets the value of attribue p_name on p_self, which can be a simple
value or the result of a method call on p_obj.''' value or the result of a method call on p_obj.'''
res = getattr(self, name) res = getattr(self, name)
if not callable(res): return res if not isinstance(res, collections.Callable): return res
return self.callMethod(obj, res) return self.callMethod(obj, res)
def process(self, obj): def process(self, obj):

View file

@ -123,7 +123,7 @@ class Boolean(Field):
def getStorableValue(self, obj, value): def getStorableValue(self, obj, value):
if not self.isEmptyValue(obj, value): if not self.isEmptyValue(obj, value):
exec 'res = %s' % value exec('res = %s' % value)
return res return res
def isTrue(self, obj, dbValue): def isTrue(self, obj, dbValue):
@ -131,7 +131,7 @@ class Boolean(Field):
not?''' not?'''
rq = obj.REQUEST rq = obj.REQUEST
# Get the value we must compare (from request or from database) # Get the value we must compare (from request or from database)
if rq.has_key(self.name): if self.name in rq:
return rq.get(self.name) in ('True', 1, '1') return rq.get(self.name) in ('True', 1, '1')
return dbValue return dbValue
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -1263,20 +1263,20 @@ class Calendar(Field):
maxDay = (maxYear, maxDate.month(), maxDate.day()) maxDay = (maxYear, maxDate.month(), maxDate.day())
# Browse years # Browse years
years = getattr(obj, self.name) years = getattr(obj, self.name)
for year in years.keys(): for year in list(years.keys()):
# Don't take this year into account if outside interval # Don't take this year into account if outside interval
if minDate and (year < minYear): continue if minDate and (year < minYear): continue
if maxDate and (year > maxYear): continue if maxDate and (year > maxYear): continue
months = years[year] months = years[year]
# Browse this year's months # Browse this year's months
for month in months.keys(): for month in list(months.keys()):
# Don't take this month into account if outside interval # Don't take this month into account if outside interval
thisMonth = (year, month) thisMonth = (year, month)
if minDate and (thisMonth < minMonth): continue if minDate and (thisMonth < minMonth): continue
if maxDate and (thisMonth > maxMonth): continue if maxDate and (thisMonth > maxMonth): continue
days = months[month] days = months[month]
# Browse this month's days # Browse this month's days
for day in days.keys(): for day in list(days.keys()):
# Don't take this day into account if outside interval # Don't take this day into account if outside interval
thisDay = (year, month, day) thisDay = (year, month, day)
if minDate and (thisDay < minDay): continue if minDate and (thisDay < minDay): continue

View file

@ -47,7 +47,7 @@ class Computed(Field):
# the user interface while m_method computes the value stored in the # the user interface while m_method computes the value stored in the
# catalog. # catalog.
self.formatMethod = formatMethod self.formatMethod = formatMethod
if isinstance(self.method, basestring): if isinstance(self.method, str):
# A legacy macro identifier. Raise an exception # A legacy macro identifier. Raise an exception
raise Exception(self.WRONG_METHOD % self.method) raise Exception(self.WRONG_METHOD % self.method)
# Does field computation produce plain text or XHTML? # Does field computation produce plain text or XHTML?
@ -99,6 +99,6 @@ class Computed(Field):
res = self.formatMethod(obj, value) res = self.formatMethod(obj, value)
else: else:
res = value res = value
if not isinstance(res, basestring): res = str(res) if not isinstance(res, str): res = str(res)
return res return res
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -219,7 +219,7 @@ class Date(Field):
def getSelectableYears(self): def getSelectableYears(self):
'''Gets the list of years one may select for this field.''' '''Gets the list of years one may select for this field.'''
res = range(self.startYear, self.endYear + 1) res = list(range(self.startYear, self.endYear + 1))
if self.reverseYears: res.reverse() if self.reverseYears: res.reverse()
return res return res
@ -227,7 +227,7 @@ class Date(Field):
DateTime = obj.getProductConfig().DateTime DateTime = obj.getProductConfig().DateTime
try: try:
value = DateTime(value) value = DateTime(value)
except DateTime.DateError, ValueError: except DateTime.DateError as ValueError:
return obj.translate('bad_date') return obj.translate('bad_date')
def getFormattedValue(self, obj, value, layoutType='view', def getFormattedValue(self, obj, value, layoutType='view',
@ -278,7 +278,7 @@ class Date(Field):
# Get the value we must compare (from request or from database) # Get the value we must compare (from request or from database)
rq = obj.REQUEST rq = obj.REQUEST
partName = '%s_%s' % (self.name, fieldPart) partName = '%s_%s' % (self.name, fieldPart)
if rq.has_key(partName): if partName in rq:
compValue = rq.get(partName) compValue = rq.get(partName)
if compValue.isdigit(): if compValue.isdigit():
compValue = int(compValue) compValue = int(compValue)

View file

@ -108,7 +108,7 @@ class FileInfo:
'''Removes the file from the filesystem.''' '''Removes the file from the filesystem.'''
try: try:
os.remove(osPathJoin(dbFolder, self.fsPath, self.fsName)) os.remove(osPathJoin(dbFolder, self.fsPath, self.fsName))
except Exception, e: except Exception as e:
# If the current ZODB transaction is re-triggered, the file may # If the current ZODB transaction is re-triggered, the file may
# already have been deleted. # already have been deleted.
pass pass
@ -207,10 +207,10 @@ class FileInfo:
if fileObj.data.__class__.__name__ == 'Pdata': if fileObj.data.__class__.__name__ == 'Pdata':
# The file content is splitted in several chunks # The file content is splitted in several chunks
f.write(fileObj.data.data) f.write(fileObj.data.data)
nextPart = fileObj.data.next nextPart = fileObj.data.__next__
while nextPart: while nextPart:
f.write(nextPart.data) f.write(nextPart.data)
nextPart = nextPart.next nextPart = nextPart.__next__
else: else:
# Only one chunk # Only one chunk
f.write(fileObj.data) f.write(fileObj.data)
@ -393,7 +393,7 @@ class File(Field):
def validateValue(self, obj, value): def validateValue(self, obj, value):
form = obj.REQUEST.form form = obj.REQUEST.form
action = '%s_delete' % self.name action = '%s_delete' % self.name
if (not value or not value.filename) and form.has_key(action) and \ if (not value or not value.filename) and action in form and \
not form[action]: not form[action]:
# If this key is present but empty, it means that the user selected # If this key is present but empty, it means that the user selected
# "replace the file with a new one". So in this case he must provide # "replace the file with a new one". So in this case he must provide
@ -450,7 +450,7 @@ class File(Field):
# Case c # Case c
fileInfo = (value.name, value.content, value.mimeType) fileInfo = (value.name, value.content, value.mimeType)
info.writeFile(self.name, fileInfo, dbFolder) info.writeFile(self.name, fileInfo, dbFolder)
elif isinstance(value, basestring): elif isinstance(value, str):
# Case d # Case d
info.copyFile(self.name, value, dbFolder) info.copyFile(self.name, value, dbFolder)
elif isinstance(value, FileInfo): elif isinstance(value, FileInfo):

View file

@ -40,7 +40,7 @@ class Group:
# which will be used for HTML param "width". # which will be used for HTML param "width".
if wide == True: if wide == True:
self.wide = '100%' self.wide = '100%'
elif isinstance(wide, basestring): elif isinstance(wide, str):
self.wide = wide self.wide = wide
else: else:
self.wide = '' self.wide = ''
@ -106,7 +106,7 @@ class Group:
can be a string or a Group instance; this method returns always a can be a string or a Group instance; this method returns always a
Group instance.''' Group instance.'''
res = groupData res = groupData
if res and isinstance(res, basestring): if res and isinstance(res, str):
# Group data is given as a string. 2 more possibilities: # Group data is given as a string. 2 more possibilities:
# (a) groupData is simply the name of the group; # (a) groupData is simply the name of the group;
# (b) groupData is of the form <groupName>_<numberOfColumns>. # (b) groupData is of the form <groupName>_<numberOfColumns>.
@ -336,7 +336,7 @@ class UiGroup:
# All p_group attributes become self attributes. This is required # All p_group attributes become self attributes. This is required
# because a UiGroup, in some PXs, must behave like a Field (ie, have # because a UiGroup, in some PXs, must behave like a Field (ie, have
# the same attributes, like "master". # the same attributes, like "master".
for name, value in group.__dict__.iteritems(): for name, value in group.__dict__.items():
if not name.startswith('_'): if not name.startswith('_'):
setattr(self, name, value) setattr(self, name, value)
self.group = group self.group = group
@ -346,7 +346,7 @@ class UiGroup:
labelName = self.name labelName = self.name
prefix = className prefix = className
if group.label: if group.label:
if isinstance(group.label, basestring): prefix = group.label if isinstance(group.label, str): prefix = group.label
else: # It is a tuple (className, name) else: # It is a tuple (className, name)
if group.label[1]: labelName = group.label[1] if group.label[1]: labelName = group.label[1]
if group.label[0]: prefix = group.label[0] if group.label[0]: prefix = group.label[0]

View file

@ -60,7 +60,7 @@ class Integer(Field):
height, maxChars, colspan, master, masterValue, focus, height, maxChars, colspan, master, masterValue, focus,
historized, mapping, label, sdefault, scolspan, swidth, historized, mapping, label, sdefault, scolspan, swidth,
sheight, persist, view, xml) sheight, persist, view, xml)
self.pythonType = long self.pythonType = int
def validateValue(self, obj, value): def validateValue(self, obj, value):
try: try:

View file

@ -132,7 +132,7 @@ class List(Field):
name = requestName or self.name # A List may be into another List (?) name = requestName or self.name # A List may be into another List (?)
prefix = name + '*' + self.fields[0][0] + '*' prefix = name + '*' + self.fields[0][0] + '*'
res = {} res = {}
for key in request.keys(): for key in list(request.keys()):
if not key.startswith(prefix): continue if not key.startswith(prefix): continue
# I have found a row. Gets its index. # I have found a row. Gets its index.
row = Object() row = Object()
@ -145,7 +145,7 @@ class List(Field):
setattr(row, subName, v) setattr(row, subName, v)
res[rowIndex] = row res[rowIndex] = row
# Produce a sorted list # Produce a sorted list
keys = res.keys() keys = list(res.keys())
keys.sort() keys.sort()
res = [res[key] for key in keys] res = [res[key] for key in keys]
# I store in the request this computed value. This way, when individual # I store in the request this computed value. This way, when individual

View file

@ -83,13 +83,13 @@ class Ogone(Field):
# Create a new dict by removing p_keysToIgnore from p_values, and by # Create a new dict by removing p_keysToIgnore from p_values, and by
# upperizing all keys. # upperizing all keys.
shaRes = {} shaRes = {}
for k, v in values.iteritems(): for k, v in values.items():
if k in keysToIgnore: continue if k in keysToIgnore: continue
# Ogone: we must not include empty values. # Ogone: we must not include empty values.
if (v == None) or (v == ''): continue if (v == None) or (v == ''): continue
shaRes[k.upper()] = v shaRes[k.upper()] = v
# Create a sorted list of keys # Create a sorted list of keys
keys = shaRes.keys() keys = list(shaRes.keys())
keys.sort() keys.sort()
shaList = [] shaList = []
for k in keys: for k in keys:
@ -127,7 +127,7 @@ class Ogone(Field):
# Ogone's response. # Ogone's response.
res['paramplus'] = 'name=%s' % self.name res['paramplus'] = 'name=%s' % self.name
# Ensure every value is a str # Ensure every value is a str
for k in res.iterkeys(): for k in res.keys():
if not isinstance(res[k], str): if not isinstance(res[k], str):
res[k] = str(res[k]) res[k] = str(res[k])
# Compute a SHA-1 key as required by Ogone and add it to the res # Compute a SHA-1 key as required by Ogone and add it to the res
@ -154,7 +154,7 @@ class Ogone(Field):
'administrator has been contacted.') 'administrator has been contacted.')
# Create a nice object from the form. # Create a nice object from the form.
response = Object() response = Object()
for k, v in obj.REQUEST.form.iteritems(): for k, v in obj.REQUEST.form.items():
setattr(response, k, v) setattr(response, k, v)
# Call the field method that handles the response received from Ogone. # Call the field method that handles the response received from Ogone.
url = self.responseMethod(obj.appy(), response) url = self.responseMethod(obj.appy(), response)

View file

@ -16,6 +16,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from appy import Object from appy import Object
import collections
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class Page: class Page:
@ -53,7 +54,7 @@ class Page:
(c) a Page instance. (c) a Page instance.
This method returns always a Page instance.''' This method returns always a Page instance.'''
res = pageData res = pageData
if res and isinstance(res, basestring): if res and isinstance(res, str):
# Page data is given as a string. # Page data is given as a string.
pageElems = pageData.rsplit('_', 1) pageElems = pageData.rsplit('_', 1)
if len(pageElems) == 1: # We have case (a) if len(pageElems) == 1: # We have case (a)

View file

@ -16,7 +16,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import time, os, os.path import time, os, os.path
from file import FileInfo from .file import FileInfo
from appy import Object from appy import Object
from appy.fields import Field from appy.fields import Field
from appy.px import Px from appy.px import Px
@ -25,6 +25,7 @@ from appy.gen import utils as gutils
from appy.pod import PodError from appy.pod import PodError
from appy.pod.renderer import Renderer from appy.pod.renderer import Renderer
from appy.shared import utils as sutils from appy.shared import utils as sutils
import collections
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class Mailing: class Mailing:
@ -170,7 +171,7 @@ class Pod(Field):
# of your app will be referred as "Test.odt" in self.template. If it is # of your app will be referred as "Test.odt" in self.template. If it is
# stored within sub-folder "pod", it will be referred as "pod/Test.odt". # stored within sub-folder "pod", it will be referred as "pod/Test.odt".
if not template: raise Exception(Pod.NO_TEMPLATE) if not template: raise Exception(Pod.NO_TEMPLATE)
if isinstance(template, basestring): if isinstance(template, str):
self.template = [template] self.template = [template]
elif isinstance(template, tuple): elif isinstance(template, tuple):
self.template = list(template) self.template = list(template)
@ -396,7 +397,7 @@ class Pod(Field):
formats = self.showTemplate(obj, template) formats = self.showTemplate(obj, template)
if not formats: continue if not formats: continue
elif isinstance(formats, bool): formats = self.formats elif isinstance(formats, bool): formats = self.formats
elif isinstance(formats, basestring): formats = (formats,) elif isinstance(formats, str): formats = (formats,)
res.append(Object(template=template, formats=formats, res.append(Object(template=template, formats=formats,
freezeFormats=self.getFreezeFormats(obj, template))) freezeFormats=self.getFreezeFormats(obj, template)))
return res return res
@ -525,7 +526,7 @@ class Pod(Field):
templatePath = self.getTemplatePath(diskFolder, template) templatePath = self.getTemplatePath(diskFolder, template)
# Get or compute the specific POD context # Get or compute the specific POD context
specificContext = None specificContext = None
if callable(self.context): if isinstance(self.context, collections.Callable):
specificContext = self.callMethod(obj, self.context) specificContext = self.callMethod(obj, self.context)
else: else:
specificContext = self.context specificContext = self.context
@ -544,7 +545,7 @@ class Pod(Field):
# Retrieve query params # Retrieve query params
cmd = ', '.join(Pod.queryParams) cmd = ', '.join(Pod.queryParams)
cmd += " = queryData.split(';')" cmd += " = queryData.split(';')"
exec cmd exec(cmd)
# (re-)execute the query, but without any limit on the number of # (re-)execute the query, but without any limit on the number of
# results; return Appy objects. # results; return Appy objects.
objs = tool.o.executeQuery(obj.o.portal_type, searchName=search, objs = tool.o.executeQuery(obj.o.portal_type, searchName=search,
@ -559,7 +560,7 @@ class Pod(Field):
# when generating frozen documents). # when generating frozen documents).
if '_checked' not in podContext: podContext['_checked'] = Object() if '_checked' not in podContext: podContext['_checked'] = Object()
# Define a potential global styles mapping # Define a potential global styles mapping
if callable(self.stylesMapping): if isinstance(self.stylesMapping, collections.Callable):
stylesMapping = self.callMethod(obj, self.stylesMapping) stylesMapping = self.callMethod(obj, self.stylesMapping)
else: else:
stylesMapping = self.stylesMapping stylesMapping = self.stylesMapping
@ -575,7 +576,7 @@ class Pod(Field):
try: try:
renderer = Renderer(**rendererParams) renderer = Renderer(**rendererParams)
renderer.run() renderer.run()
except PodError, pe: except PodError as pe:
if not os.path.exists(result): if not os.path.exists(result):
# In some (most?) cases, when OO returns an error, the result is # In some (most?) cases, when OO returns an error, the result is
# nevertheless generated. # nevertheless generated.
@ -643,7 +644,7 @@ class Pod(Field):
# Generate the document # Generate the document
doc = self.getValue(obj, template=template, format=format, doc = self.getValue(obj, template=template, format=format,
result=result) result=result)
if isinstance(doc, basestring): if isinstance(doc, str):
# An error occurred, the document was not generated. # An error occurred, the document was not generated.
obj.log(self.FREEZE_ERROR % (format, self.name, doc), obj.log(self.FREEZE_ERROR % (format, self.name, doc),
type='error') type='error')
@ -658,7 +659,7 @@ class Pod(Field):
obj.log('freeze: overwriting %s...' % result) obj.log('freeze: overwriting %s...' % result)
doc = self.getValue(obj, template=template, format='odt', doc = self.getValue(obj, template=template, format='odt',
result=result) result=result)
if isinstance(doc, basestring): if isinstance(doc, str):
self.log(self.FREEZE_ERROR % ('odt', self.name, doc), self.log(self.FREEZE_ERROR % ('odt', self.name, doc),
type='error') type='error')
raise Exception(self.FREEZE_FATAL_ERROR) raise Exception(self.FREEZE_FATAL_ERROR)
@ -762,7 +763,7 @@ class Pod(Field):
res = self.getValue(obj, template=template, format=format, res = self.getValue(obj, template=template, format=format,
queryData=rq.get('queryData'), queryData=rq.get('queryData'),
customContext=self.getCustomContext(obj, rq)) customContext=self.getCustomContext(obj, rq))
if isinstance(res, basestring): if isinstance(res, str):
# An error has occurred, and p_res contains the error message # An error has occurred, and p_res contains the error message
obj.say(res) obj.say(res)
return tool.goto(rq.get('HTTP_REFERER')) return tool.goto(rq.get('HTTP_REFERER'))

View file

@ -23,6 +23,7 @@ from appy.px import Px
from appy.gen.layout import Table from appy.gen.layout import Table
from appy.gen import utils as gutils from appy.gen import utils as gutils
from appy.shared import utils as sutils from appy.shared import utils as sutils
import collections
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class Ref(Field): class Ref(Field):
@ -826,7 +827,7 @@ class Ref(Field):
# If this field is an ajax-updatable slave, no need to compute # If this field is an ajax-updatable slave, no need to compute
# possible values: it will be overridden by method self.masterValue # possible values: it will be overridden by method self.masterValue
# by a subsequent ajax request (=the "if" statement above). # by a subsequent ajax request (=the "if" statement above).
if self.masterValue and callable(self.masterValue): if self.masterValue and isinstance(self.masterValue, collections.Callable):
objects = [] objects = []
else: else:
if not self.select: if not self.select:
@ -921,7 +922,7 @@ class Ref(Field):
res = self.getAttribute(obj, 'numbered') res = self.getAttribute(obj, 'numbered')
if not res: return res if not res: return res
# Returns the column width. # Returns the column width.
if not isinstance(res, basestring): return '15px' if not isinstance(res, str): return '15px'
return res return res
def getMenuUrl(self, zobj, tied): def getMenuUrl(self, zobj, tied):
@ -996,14 +997,14 @@ class Ref(Field):
# Also ensure that multiplicities are enforced. # Also ensure that multiplicities are enforced.
if not value: if not value:
nbOfRefs = 0 nbOfRefs = 0
elif isinstance(value, basestring): elif isinstance(value, str):
nbOfRefs = 1 nbOfRefs = 1
else: else:
nbOfRefs = len(value) nbOfRefs = len(value)
minRef = self.multiplicity[0] minRef = self.multiplicity[0]
maxRef = self.multiplicity[1] maxRef = self.multiplicity[1]
if maxRef == None: if maxRef == None:
maxRef = sys.maxint maxRef = sys.maxsize
if nbOfRefs < minRef: if nbOfRefs < minRef:
return obj.translate('min_ref_violated') return obj.translate('min_ref_violated')
elif nbOfRefs > maxRef: elif nbOfRefs > maxRef:
@ -1119,7 +1120,7 @@ class Ref(Field):
if type(objects) not in sutils.sequenceTypes: objects = [objects] if type(objects) not in sutils.sequenceTypes: objects = [objects]
tool = obj.getTool() tool = obj.getTool()
for i in range(len(objects)): for i in range(len(objects)):
if isinstance(objects[i], basestring): if isinstance(objects[i], str):
# We have an UID here # We have an UID here
objects[i] = tool.getObject(objects[i], appy=True) objects[i] = tool.getObject(objects[i], appy=True)
else: else:

View file

@ -19,7 +19,7 @@ from appy.px import Px
from appy.gen import utils as gutils from appy.gen import utils as gutils
from appy.gen.indexer import defaultIndexes from appy.gen.indexer import defaultIndexes
from appy.shared import utils as sutils from appy.shared import utils as sutils
from group import Group from .group import Group
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class Search: class Search:
@ -85,12 +85,12 @@ class Search:
(fieldName == 'SearchableText'): (fieldName == 'SearchableText'):
# For TextIndex indexes. We must split p_fieldValue into keywords. # For TextIndex indexes. We must split p_fieldValue into keywords.
res = gutils.Keywords(fieldValue).get() res = gutils.Keywords(fieldValue).get()
elif isinstance(fieldValue, basestring) and fieldValue.endswith('*'): elif isinstance(fieldValue, str) and fieldValue.endswith('*'):
v = fieldValue[:-1] v = fieldValue[:-1]
# Warning: 'z' is higher than 'Z'! # Warning: 'z' is higher than 'Z'!
res = {'query':(v,v+'z'), 'range':'min:max'} res = {'query':(v,v+'z'), 'range':'min:max'}
elif type(fieldValue) in sutils.sequenceTypes: elif type(fieldValue) in sutils.sequenceTypes:
if fieldValue and isinstance(fieldValue[0], basestring): if fieldValue and isinstance(fieldValue[0], str):
# We have a list of string values (ie: we need to # We have a list of string values (ie: we need to
# search v1 or v2 or...) # search v1 or v2 or...)
res = fieldValue res = fieldValue
@ -118,7 +118,7 @@ class Search:
sortBy and sortOrder (and not "resolve" them to Zope's sort_on and sortBy and sortOrder (and not "resolve" them to Zope's sort_on and
sort_order).''' sort_order).'''
# Put search criteria in p_criteria # Put search criteria in p_criteria
for name, value in self.fields.iteritems(): for name, value in self.fields.items():
# Management of searches restricted to objects linked through a # Management of searches restricted to objects linked through a
# Ref field: not implemented yet. # Ref field: not implemented yet.
if name == '_ref': continue if name == '_ref': continue

View file

@ -25,6 +25,7 @@ from appy.shared.data import countries
from appy.shared.xml_parser import XhtmlCleaner from appy.shared.xml_parser import XhtmlCleaner
from appy.shared.diff import HtmlDiff from appy.shared.diff import HtmlDiff
from appy.shared import utils as sutils from appy.shared import utils as sutils
import collections
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
digit = re.compile('[0-9]') digit = re.compile('[0-9]')
@ -471,7 +472,7 @@ class String(Field):
res = True res = True
if type(self.validator) in (list, tuple): if type(self.validator) in (list, tuple):
for elem in self.validator: for elem in self.validator:
if not isinstance(elem, basestring): if not isinstance(elem, str):
res = False res = False
break break
else: else:
@ -533,7 +534,7 @@ class String(Field):
if not value: if not value:
if self.isMultiValued(): return emptyTuple if self.isMultiValued(): return emptyTuple
else: return value else: return value
if isinstance(value, basestring) and self.isMultiValued(): if isinstance(value, str) and self.isMultiValued():
value = [value] value = [value]
elif isinstance(value, tuple): elif isinstance(value, tuple):
value = list(value) value = list(value)
@ -602,8 +603,7 @@ class String(Field):
identifies the language-specific part we will work on.''' identifies the language-specific part we will work on.'''
res = None res = None
lastEvent = None lastEvent = None
name = language and ('%s-%s' % (self.name, language)) or self.name for event in obj.workflow_history.values()[0]:
for event in obj.workflow_history['appy']:
if event['action'] != '_datachange_': continue if event['action'] != '_datachange_': continue
if name not in event['changes']: continue if name not in event['changes']: continue
if res == None: if res == None:
@ -660,7 +660,7 @@ class String(Field):
res = obj.formatText(res, format='html') res = obj.formatText(res, format='html')
# If value starts with a carriage return, add a space; else, it will # If value starts with a carriage return, add a space; else, it will
# be ignored. # be ignored.
if isinstance(res, basestring) and \ if isinstance(res, str) and \
(res.startswith('\n') or res.startswith('\r\n')): res = ' ' + res (res.startswith('\n') or res.startswith('\r\n')): res = ' ' + res
return res return res
@ -774,7 +774,7 @@ class String(Field):
# If this field is an ajax-updatable slave, no need to compute # If this field is an ajax-updatable slave, no need to compute
# possible values: it will be overridden by method self.masterValue # possible values: it will be overridden by method self.masterValue
# by a subsequent ajax request (=the "if" statement above). # by a subsequent ajax request (=the "if" statement above).
if self.masterValue and callable(self.masterValue) and \ if self.masterValue and isinstance(self.masterValue, collections.Callable) and \
not ignoreMasterValues: return [] not ignoreMasterValues: return []
if isinstance(self.validator, Selection): if isinstance(self.validator, Selection):
# We need to call self.methodName for getting the (dynamic) # We need to call self.methodName for getting the (dynamic)
@ -808,9 +808,9 @@ class String(Field):
obj = brains[0].getObject() obj = brains[0].getObject()
# Do we need to call the method on the object or on the wrapper? # Do we need to call the method on the object or on the wrapper?
if methodName.startswith('_appy_'): if methodName.startswith('_appy_'):
exec 'res = obj.%s(*args)' % methodName exec('res = obj.%s(*args)' % methodName)
else: else:
exec 'res = obj.appy().%s(*args)' % methodName exec('res = obj.appy().%s(*args)' % methodName)
if not withTranslations: res = [v[0] for v in res] if not withTranslations: res = [v[0] for v in res]
elif isinstance(res, list): res = res[:] elif isinstance(res, list): res = res[:]
else: else:
@ -847,7 +847,7 @@ class String(Field):
elif self.isSelect: elif self.isSelect:
# Check that the value is among possible values # Check that the value is among possible values
possibleValues = self.getPossibleValues(obj,ignoreMasterValues=True) possibleValues = self.getPossibleValues(obj,ignoreMasterValues=True)
if isinstance(value, basestring): if isinstance(value, str):
error = value not in possibleValues error = value not in possibleValues
else: else:
error = False error = False
@ -872,7 +872,7 @@ class String(Field):
return value return value
def getUnilingualStorableValue(self, obj, value): def getUnilingualStorableValue(self, obj, value):
isString = isinstance(value, basestring) isString = isinstance(value, str)
isEmpty = Field.isEmptyValue(self, obj, value) isEmpty = Field.isEmptyValue(self, obj, value)
# Apply transform if required # Apply transform if required
if isString and not isEmpty and (self.transform != 'none'): if isString and not isEmpty and (self.transform != 'none'):
@ -1021,7 +1021,7 @@ class String(Field):
if self.allowImageUpload: if self.allowImageUpload:
ckAttrs['filebrowserUploadUrl'] = '%s/upload' % obj.absolute_url() ckAttrs['filebrowserUploadUrl'] = '%s/upload' % obj.absolute_url()
ck = [] ck = []
for k, v in ckAttrs.iteritems(): for k, v in ckAttrs.items():
if isinstance(v, int): sv = str(v) if isinstance(v, int): sv = str(v)
if isinstance(v, bool): sv = str(v).lower() if isinstance(v, bool): sv = str(v).lower()
else: sv = '"%s"' % v else: sv = '"%s"' % v
@ -1059,7 +1059,7 @@ class String(Field):
name containing a row number from a field within a list field.''' name containing a row number from a field within a list field.'''
rq = obj.REQUEST rq = obj.REQUEST
# Get the value we must compare (from request or from database) # Get the value we must compare (from request or from database)
if rq.has_key(fieldName): if fieldName in rq:
compValue = rq.get(fieldName) compValue = rq.get(fieldName)
else: else:
compValue = dbValue compValue = dbValue

View file

@ -14,10 +14,12 @@
# You should have received a copy of the GNU General Public License along with # You should have received a copy of the GNU General Public License along with
# Appy. If not, see <http://www.gnu.org/licenses/>. # Appy. If not, see <http://www.gnu.org/licenses/>.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import types, string import types
from group import Group import .string
from .group import Group
from appy.px import Px from appy.px import Px
from appy.gen.utils import User from appy.gen.utils import User
import collections
# Default Appy permissions ----------------------------------------------------- # Default Appy permissions -----------------------------------------------------
r, w, d = ('read', 'write', 'delete') r, w, d = ('read', 'write', 'delete')
@ -73,7 +75,7 @@ class State:
exists, or creates a Role instance, puts it in self.usedRoles and exists, or creates a Role instance, puts it in self.usedRoles and
returns it else. If it is a Role instance, the method stores it in returns it else. If it is a Role instance, the method stores it in
self.usedRoles if it is not in it yet and returns it.''' self.usedRoles if it is not in it yet and returns it.'''
if isinstance(role, basestring): if isinstance(role, str):
if role in self.usedRoles: if role in self.usedRoles:
return self.usedRoles[role] return self.usedRoles[role]
else: else:
@ -88,24 +90,24 @@ class State:
def standardizeRoles(self): def standardizeRoles(self):
'''This method converts, within self.permissions, every role to a '''This method converts, within self.permissions, every role to a
Role instance. Every used role is stored in self.usedRoles.''' Role instance. Every used role is stored in self.usedRoles.'''
for permission, roles in self.permissions.iteritems(): for permission, roles in self.permissions.items():
if not roles: continue # Nobody may have this permission if not roles: continue # Nobody may have this permission
if isinstance(roles, basestring) or isinstance(roles, Role): if isinstance(roles, str) or isinstance(roles, Role):
self.permissions[permission] = [self.getRole(roles)] self.permissions[permission] = [self.getRole(roles)]
elif isinstance(roles, list): elif isinstance(roles, list):
for i in range(len(roles)): roles[i] = self.getRole(roles[i]) for i in range(len(roles)): roles[i] = self.getRole(roles[i])
else: # A tuple else: # A tuple
self.permissions[permission] = [self.getRole(r) for r in roles] self.permissions[permission] = [self.getRole(r) for r in roles]
def getUsedRoles(self): return self.usedRoles.values() def getUsedRoles(self): return list(self.usedRoles.values())
def addRoles(self, roleNames, permissions=()): def addRoles(self, roleNames, permissions=()):
'''Adds p_roleNames in self.permissions. If p_permissions is specified, '''Adds p_roleNames in self.permissions. If p_permissions is specified,
roles are added to those permissions only. Else, roles are added for roles are added to those permissions only. Else, roles are added for
every permission within self.permissions.''' every permission within self.permissions.'''
if isinstance(roleNames, basestring): roleNames = (roleNames,) if isinstance(roleNames, str): roleNames = (roleNames,)
if isinstance(permissions, basestring): permissions = (permissions,) if isinstance(permissions, str): permissions = (permissions,)
for perm, roles in self.permissions.iteritems(): for perm, roles in self.permissions.items():
if permissions and (perm not in permissions): continue if permissions and (perm not in permissions): continue
for roleName in roleNames: for roleName in roleNames:
# Do nothing if p_roleName is already almong roles. # Do nothing if p_roleName is already almong roles.
@ -124,9 +126,9 @@ class State:
'''Removes p_roleNames within dict self.permissions. If p_permissions is '''Removes p_roleNames within dict self.permissions. If p_permissions is
specified, removal is restricted to those permissions. Else, removal specified, removal is restricted to those permissions. Else, removal
occurs throughout the whole dict self.permissions.''' occurs throughout the whole dict self.permissions.'''
if isinstance(roleNames, basestring): roleNames = (roleNames,) if isinstance(roleNames, str): roleNames = (roleNames,)
if isinstance(permissions, basestring): permissions = (permissions,) if isinstance(permissions, str): permissions = (permissions,)
for perm, roles in self.permissions.iteritems(): for perm, roles in self.permissions.items():
if permissions and (perm not in permissions): continue if permissions and (perm not in permissions): continue
for roleName in roleNames: for roleName in roleNames:
# Remove this role if present in roles for this permission. # Remove this role if present in roles for this permission.
@ -138,9 +140,9 @@ class State:
def setRoles(self, roleNames, permissions=()): def setRoles(self, roleNames, permissions=()):
'''Sets p_rolesNames for p_permissions if not empty, for every '''Sets p_rolesNames for p_permissions if not empty, for every
permission in self.permissions else.''' permission in self.permissions else.'''
if isinstance(roleNames, basestring): roleNames = (roleNames,) if isinstance(roleNames, str): roleNames = (roleNames,)
if isinstance(permissions, basestring): permissions = (permissions,) if isinstance(permissions, str): permissions = (permissions,)
for perm in self.permissions.iterkeys(): for perm in self.permissions.keys():
if permissions and (perm not in permissions): continue if permissions and (perm not in permissions): continue
roles = self.permissions[perm] = [] roles = self.permissions[perm] = []
for roleName in roleNames: for roleName in roleNames:
@ -150,8 +152,8 @@ class State:
'''Replaces p_oldRoleName by p_newRoleName. If p_permissions is '''Replaces p_oldRoleName by p_newRoleName. If p_permissions is
specified, the replacement is restricted to those permissions. Else, specified, the replacement is restricted to those permissions. Else,
replacements apply to the whole dict self.permissions.''' replacements apply to the whole dict self.permissions.'''
if isinstance(permissions, basestring): permissions = (permissions,) if isinstance(permissions, str): permissions = (permissions,)
for perm, roles in self.permissions.iteritems(): for perm, roles in self.permissions.items():
if permissions and (perm not in permissions): continue if permissions and (perm not in permissions): continue
# Find and delete p_oldRoleName # Find and delete p_oldRoleName
for role in roles: for role in roles:
@ -170,7 +172,7 @@ class State:
worklflow, this method will always return True (I mean: in this case, worklflow, this method will always return True (I mean: in this case,
having an isolated state does not mean the state has been having an isolated state does not mean the state has been
deactivated).''' deactivated).'''
for tr in wf.__dict__.itervalues(): for tr in wf.__dict__.values():
if not isinstance(tr, Transition): continue if not isinstance(tr, Transition): continue
if not tr.hasState(self, True): continue if not tr.hasState(self, True): continue
# Transition "tr" has this state as start state. If the end state is # Transition "tr" has this state as start state. If the end state is
@ -200,7 +202,7 @@ class Transition:
# be useful for "undo" transitions, for example. # be useful for "undo" transitions, for example.
self.states = self.standardiseStates(states) self.states = self.standardiseStates(states)
self.condition = condition self.condition = condition
if isinstance(condition, basestring): if isinstance(condition, str):
# The condition specifies the name of a role. # The condition specifies the name of a role.
self.condition = Role(condition) self.condition = Role(condition)
self.action = action self.action = action
@ -276,7 +278,7 @@ class Transition:
def isShowable(self, workflow, obj): def isShowable(self, workflow, obj):
'''Is this transition showable?''' '''Is this transition showable?'''
if callable(self.show): if isinstance(self.show, collections.Callable):
return self.show(workflow, obj.appy()) return self.show(workflow, obj.appy())
else: else:
return self.show return self.show
@ -330,7 +332,7 @@ class Transition:
for condition in self.condition: for condition in self.condition:
# "Unwrap" role names from Role instances # "Unwrap" role names from Role instances
if isinstance(condition, Role): condition = condition.name if isinstance(condition, Role): condition = condition.name
if isinstance(condition, basestring): # It is a role if isinstance(condition, str): # It is a role
if hasRole == None: if hasRole == None:
hasRole = False hasRole = False
if user.has_role(condition, obj): if user.has_role(condition, obj):
@ -450,7 +452,7 @@ class Transition:
transition = getattr(workflow, transition) transition = getattr(workflow, transition)
# Browse all transitions and find the one starting at p_transition's end # Browse all transitions and find the one starting at p_transition's end
# state and coming back to p_transition's start state. # state and coming back to p_transition's start state.
for trName, tr in workflow.__dict__.iteritems(): for trName, tr in workflow.__dict__.items():
if not isinstance(tr, Transition) or (tr == transition): continue if not isinstance(tr, Transition) or (tr == transition): continue
if transition.isSingle(): if transition.isSingle():
if tr.hasState(transition.states[1], True) and \ if tr.hasState(transition.states[1], True) and \

View file

@ -5,9 +5,9 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import types, copy import types, copy
import appy.gen as gen import appy.gen as gen
import po from . import po
from model import ModelClass from .model import ModelClass
from utils import produceNiceMessage, getClassName from .utils import produceNiceMessage, getClassName
TABS = 4 # Number of blanks in a Python indentation. TABS = 4 # Number of blanks in a Python indentation.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -130,7 +130,7 @@ class ClassDescriptor(Descriptor):
def isAbstract(self): def isAbstract(self):
'''Is self.klass abstract?''' '''Is self.klass abstract?'''
res = False res = False
if self.klass.__dict__.has_key('abstract'): if 'abstract' in self.klass.__dict__:
res = self.klass.__dict__['abstract'] res = self.klass.__dict__['abstract']
return res return res
@ -139,7 +139,7 @@ class ClassDescriptor(Descriptor):
concept into the application. For example, creating instances concept into the application. For example, creating instances
of such classes will be easy from the user interface.''' of such classes will be easy from the user interface.'''
res = False res = False
if self.klass.__dict__.has_key('root'): if 'root' in self.klass.__dict__:
res = self.klass.__dict__['root'] res = self.klass.__dict__['root']
return res return res
@ -150,7 +150,7 @@ class ClassDescriptor(Descriptor):
theClass = self.klass theClass = self.klass
if klass: if klass:
theClass = klass theClass = klass
if theClass.__dict__.has_key('folder'): if 'folder' in theClass.__dict__:
res = theClass.__dict__['folder'] res = theClass.__dict__['folder']
else: else:
if theClass.__bases__: if theClass.__bases__:
@ -176,14 +176,14 @@ class ClassDescriptor(Descriptor):
def getCreateMean(self, type='Import'): def getCreateMean(self, type='Import'):
'''Returns the mean for this class that corresponds to p_type, or '''Returns the mean for this class that corresponds to p_type, or
None if the class does not support this create mean.''' None if the class does not support this create mean.'''
if not self.klass.__dict__.has_key('create'): return if 'create' not in self.klass.__dict__: return
else: else:
means = self.klass.create means = self.klass.create
if not means: return if not means: return
if not isinstance(means, tuple) and not isinstance(means, list): if not isinstance(means, tuple) and not isinstance(means, list):
means = [means] means = [means]
for mean in means: for mean in means:
exec 'found = isinstance(mean, %s)' % type exec('found = isinstance(mean, %s)' % type)
if found: return mean if found: return mean
@staticmethod @staticmethod
@ -192,7 +192,7 @@ class ClassDescriptor(Descriptor):
p_tool is given, we are at execution time (not a generation time), p_tool is given, we are at execution time (not a generation time),
and we may potentially execute search.show methods that allow to and we may potentially execute search.show methods that allow to
conditionnaly include a search or not.''' conditionnaly include a search or not.'''
if klass.__dict__.has_key('search'): if 'search' in klass.__dict__:
searches = klass.__dict__['search'] searches = klass.__dict__['search']
if not tool: return searches if not tool: return searches
# Evaluate attributes "show" for every search. # Evaluate attributes "show" for every search.
@ -229,10 +229,10 @@ class ClassDescriptor(Descriptor):
def addField(self, fieldName, fieldType): def addField(self, fieldName, fieldType):
'''Adds a new field to the Tool.''' '''Adds a new field to the Tool.'''
exec "self.modelClass.%s = fieldType" % fieldName exec("self.modelClass.%s = fieldType" % fieldName)
if fieldName in self.modelClass._appy_attributes: if fieldName in self.modelClass._appy_attributes:
print('Warning, field "%s" is already existing on class "%s"' % \ print(('Warning, field "%s" is already existing on class "%s"' % \
(fieldName, self.modelClass.__name__)) (fieldName, self.modelClass.__name__)))
return return
self.modelClass._appy_attributes.append(fieldName) self.modelClass._appy_attributes.append(fieldName)
self.orderedAttributes.append(fieldName) self.orderedAttributes.append(fieldName)
@ -488,9 +488,9 @@ class TranslationClassDescriptor(ClassDescriptor):
maxLine = 100 # We suppose a line is 100 characters long. maxLine = 100 # We suppose a line is 100 characters long.
width = 0 width = 0
height = 0 height = 0
for fileName, poFile in i18nFiles.iteritems(): for fileName, poFile in i18nFiles.items():
if not fileName.startswith('%s-' % appName) or \ if not fileName.startswith('%s-' % appName) or \
not i18nFiles[fileName].messagesDict.has_key(messageId): messageId not in i18nFiles[fileName].messagesDict:
# In this case this is not one of our Appy-managed translation # In this case this is not one of our Appy-managed translation
# files. # files.
continue continue

View file

@ -3,10 +3,11 @@ import os, os.path, re, sys, parser, symbol, token, types
import appy, appy.pod.renderer import appy, appy.pod.renderer
from appy.shared.utils import FolderDeleter from appy.shared.utils import FolderDeleter
import appy.gen as gen import appy.gen as gen
import po from . import po
from descriptors import * from .descriptors import *
from utils import getClassName from .utils import getClassName
from model import ModelClass, User, Group, Tool, Translation, Page from .model import ModelClass, User, Group, Tool, Translation, Page
import collections
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class GeneratorError(Exception): pass class GeneratorError(Exception): pass
@ -160,7 +161,7 @@ class Generator:
appy.fields.Field, it will be considered a gen-class. If p_klass appy.fields.Field, it will be considered a gen-class. If p_klass
declares at least one static attribute that is a appy.gen.State, declares at least one static attribute that is a appy.gen.State,
it will be considered a gen-workflow.''' it will be considered a gen-workflow.'''
for attr in klass.__dict__.itervalues(): for attr in klass.__dict__.values():
if isinstance(attr, gen.Field): return 'class' if isinstance(attr, gen.Field): return 'class'
elif isinstance(attr, gen.State): return 'workflow' elif isinstance(attr, gen.State): return 'workflow'
@ -173,11 +174,11 @@ class Generator:
self.totalNumberOfTests += 1 self.totalNumberOfTests += 1
res = True res = True
# Count also docstring in methods # Count also docstring in methods
if type(moduleOrClass) == types.ClassType: if type(moduleOrClass) == type:
for name, elem in moduleOrClass.__dict__.iteritems(): for name, elem in moduleOrClass.__dict__.items():
if type(elem) in (staticmethod, classmethod): if type(elem) in (staticmethod, classmethod):
elem = elem.__get__(name) elem = elem.__get__(name)
if callable(elem) and (type(elem) != types.ClassType) and \ if isinstance(elem, collections.Callable) and (type(elem) != type) and \
hasattr(elem, '__doc__') and elem.__doc__ and \ hasattr(elem, '__doc__') and elem.__doc__ and \
(elem.__doc__.find('>>>') != -1): (elem.__doc__.find('>>>') != -1):
res = True res = True
@ -198,8 +199,8 @@ class Generator:
self.modulesWithTests.add(module.__name__) self.modulesWithTests.add(module.__name__)
classType = type(Generator) classType = type(Generator)
# Find all classes in this module # Find all classes in this module
for name in module.__dict__.keys(): for name in list(module.__dict__.keys()):
exec 'moduleElem = module.%s' % name exec('moduleElem = module.%s' % name)
# Ignore non-classes module elements or classes that were imported # Ignore non-classes module elements or classes that were imported
# from other modules. # from other modules.
if (type(moduleElem) != classType) or \ if (type(moduleElem) != classType) or \
@ -213,7 +214,7 @@ class Generator:
# Collect non-parsable attrs = back references added # Collect non-parsable attrs = back references added
# programmatically # programmatically
moreAttrs = [] moreAttrs = []
for eName, eValue in moduleElem.__dict__.iteritems(): for eName, eValue in moduleElem.__dict__.items():
if isinstance(eValue, gen.Field) and (eName not in attrs): if isinstance(eValue, gen.Field) and (eName not in attrs):
moreAttrs.append(eName) moreAttrs.append(eName)
# Sort them in alphabetical order: else, order would be random # Sort them in alphabetical order: else, order would be random
@ -257,7 +258,7 @@ class Generator:
# What is the name of the application ? # What is the name of the application ?
appName = os.path.basename(self.application) appName = os.path.basename(self.application)
# Get the app-specific config if any # Get the app-specific config if any
exec 'import %s as appModule' % appName exec('import %s as appModule' % appName)
if hasattr (appModule, 'Config'): if hasattr (appModule, 'Config'):
self.config = appModule.Config self.config = appModule.Config
if not issubclass(self.config, gen.Config): if not issubclass(self.config, gen.Config):
@ -273,7 +274,7 @@ class Generator:
# Ignore non Python files # Ignore non Python files
if not fileName.endswith('.py'): continue if not fileName.endswith('.py'): continue
moduleName = '%s.%s' % (appName, os.path.splitext(fileName)[0]) moduleName = '%s.%s' % (appName, os.path.splitext(fileName)[0])
exec 'import %s' % moduleName exec('import %s' % moduleName)
modules.append(eval(moduleName)) modules.append(eval(moduleName))
# Parse imported modules # Parse imported modules
for module in modules: for module in modules:
@ -321,7 +322,7 @@ class Generator:
fileContent = f.read() fileContent = f.read()
f.close() f.close()
if not fileName.endswith('.png'): if not fileName.endswith('.png'):
for rKey, rValue in replacements.iteritems(): for rKey, rValue in replacements.items():
fileContent = fileContent.replace( fileContent = fileContent.replace(
'<!%s!>' % rKey, str(rValue)) '<!%s!>' % rKey, str(rValue))
f = file(resultPath, 'w') f = file(resultPath, 'w')
@ -343,7 +344,7 @@ class Generator:
msg = '' msg = ''
if self.totalNumberOfTests: if self.totalNumberOfTests:
msg = ' (number of tests found: %d)' % self.totalNumberOfTests msg = ' (number of tests found: %d)' % self.totalNumberOfTests
print('Done%s.' % msg) print(('Done%s.' % msg))
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class ZopeGenerator(Generator): class ZopeGenerator(Generator):
@ -413,7 +414,7 @@ class ZopeGenerator(Generator):
f.close() f.close()
# Generate i18n pot file # Generate i18n pot file
potFileName = '%s.pot' % self.applicationName potFileName = '%s.pot' % self.applicationName
if self.i18nFiles.has_key(potFileName): if potFileName in self.i18nFiles:
potFile = self.i18nFiles[potFileName] potFile = self.i18nFiles[potFileName]
else: else:
fullName = os.path.join(self.application, 'tr', potFileName) fullName = os.path.join(self.application, 'tr', potFileName)
@ -427,14 +428,14 @@ class ZopeGenerator(Generator):
self.options.i18nClean, keepExistingOrder=False) self.options.i18nClean, keepExistingOrder=False)
potFile.generate() potFile.generate()
if removedLabels: if removedLabels:
print('Warning: %d messages were removed from translation ' \ print(('Warning: %d messages were removed from translation ' \
'files: %s' % (len(removedLabels), str(removedLabels))) 'files: %s' % (len(removedLabels), str(removedLabels))))
# Generate i18n po files # Generate i18n po files
for language in self.config.languages: for language in self.config.languages:
# I must generate (or update) a po file for the language(s) # I must generate (or update) a po file for the language(s)
# specified in the configuration. # specified in the configuration.
poFileName = potFile.getPoFileName(language) poFileName = potFile.getPoFileName(language)
if self.i18nFiles.has_key(poFileName): if poFileName in self.i18nFiles:
poFile = self.i18nFiles[poFileName] poFile = self.i18nFiles[poFileName]
else: else:
fullName = os.path.join(self.application, 'tr', poFileName) fullName = os.path.join(self.application, 'tr', poFileName)
@ -501,7 +502,7 @@ class ZopeGenerator(Generator):
for role in creators: for role in creators:
if role.name not in allRoles: if role.name not in allRoles:
allRoles[role.name] = role allRoles[role.name] = role
res = allRoles.values() res = list(allRoles.values())
# Filter the result according to parameters # Filter the result according to parameters
for p in ('appy', 'local', 'grantable'): for p in ('appy', 'local', 'grantable'):
if eval(p) != None: if eval(p) != None:
@ -621,12 +622,12 @@ class ZopeGenerator(Generator):
else: else:
# If a child of this class is already present, we must insert # If a child of this class is already present, we must insert
# this klass before it. # this klass before it.
lowestChildIndex = sys.maxint lowestChildIndex = sys.maxsize
for resClass in resClasses: for resClass in resClasses:
if klass in resClass.__bases__: if klass in resClass.__bases__:
lowestChildIndex = min(lowestChildIndex, lowestChildIndex = min(lowestChildIndex,
resClasses.index(resClass)) resClasses.index(resClass))
if lowestChildIndex != sys.maxint: if lowestChildIndex != sys.maxsize:
res.insert(lowestChildIndex, classDescr) res.insert(lowestChildIndex, classDescr)
resClasses.insert(lowestChildIndex, klass) resClasses.insert(lowestChildIndex, klass)
else: else:
@ -745,7 +746,7 @@ class ZopeGenerator(Generator):
'''Is called each time an Appy class is found in the application, for '''Is called each time an Appy class is found in the application, for
generating the corresponding Archetype class.''' generating the corresponding Archetype class.'''
k = classDescr.klass k = classDescr.klass
print('Generating %s.%s (gen-class)...' % (k.__module__, k.__name__)) print(('Generating %s.%s (gen-class)...' % (k.__module__, k.__name__)))
# Determine base Zope class # Determine base Zope class
isFolder = classDescr.isFolder() isFolder = classDescr.isFolder()
baseClass = isFolder and 'Folder' or 'SimpleItem' baseClass = isFolder and 'Folder' or 'SimpleItem'
@ -772,7 +773,7 @@ class ZopeGenerator(Generator):
'''This method creates the i18n labels related to the workflow described '''This method creates the i18n labels related to the workflow described
by p_wfDescr.''' by p_wfDescr.'''
k = wfDescr.klass k = wfDescr.klass
print('Generating %s.%s (gen-workflow)...' % (k.__module__, k.__name__)) print(('Generating %s.%s (gen-workflow)...' % (k.__module__, k.__name__)))
# Identify workflow name # Identify workflow name
wfName = WorkflowDescriptor.getWorkflowName(wfDescr.klass) wfName = WorkflowDescriptor.getWorkflowName(wfDescr.klass)
# Add i18n messages for states # Add i18n messages for states

View file

@ -33,7 +33,7 @@ def updateIndexes(installer, indexInfo):
'''This function updates the indexes defined in the catalog.''' '''This function updates the indexes defined in the catalog.'''
catalog = installer.app.catalog catalog = installer.app.catalog
logger = installer.logger logger = installer.logger
for indexName, indexType in indexInfo.iteritems(): for indexName, indexType in indexInfo.items():
indexRealType = indexType indexRealType = indexType
if indexType in ('XhtmlIndex', 'TextIndex', 'ListIndex'): if indexType in ('XhtmlIndex', 'TextIndex', 'ListIndex'):
indexRealType = 'ZCTextIndex' indexRealType = 'ZCTextIndex'

View file

@ -43,7 +43,7 @@ class FakeZCatalog:
def onDelSession(sessionObject, container): def onDelSession(sessionObject, container):
'''This function is called when a session expires.''' '''This function is called when a session expires.'''
rq = container.REQUEST rq = container.REQUEST
if rq.cookies.has_key('_appy_') and rq.cookies.has_key('_ZopeId') and \ if '_appy_' in rq.cookies and '_ZopeId' in rq.cookies and \
(rq['_ZopeId'] == sessionObject.token): (rq['_ZopeId'] == sessionObject.token):
# The request comes from a guy whose session has expired. # The request comes from a guy whose session has expired.
resp = rq.RESPONSE resp = rq.RESPONSE
@ -155,7 +155,7 @@ class ZopeInstaller:
# Create or update Appy-wide indexes and field-related indexes # Create or update Appy-wide indexes and field-related indexes
indexInfo = defaultIndexes.copy() indexInfo = defaultIndexes.copy()
tool = self.app.config tool = self.app.config
for className in self.config.attributes.iterkeys(): for className in self.config.attributes.keys():
wrapperClass = tool.getAppyClass(className, wrapper=True) wrapperClass = tool.getAppyClass(className, wrapper=True)
indexInfo.update(wrapperClass.getIndexes(includeDefaults=False)) indexInfo.update(wrapperClass.getIndexes(includeDefaults=False))
updateIndexes(self, indexInfo) updateIndexes(self, indexInfo)
@ -196,7 +196,7 @@ class ZopeInstaller:
if hasattr(appyTool, 'beforeInstall'): appyTool.beforeInstall() if hasattr(appyTool, 'beforeInstall'): appyTool.beforeInstall()
# Create the default users if they do not exist. # Create the default users if they do not exist.
for login, roles in self.defaultUsers.iteritems(): for login, roles in self.defaultUsers.items():
if not appyTool.count('User', noSecurity=True, login=login): if not appyTool.count('User', noSecurity=True, login=login):
appyTool.create('users', noSecurity=True, id=login, login=login, appyTool.create('users', noSecurity=True, id=login, login=login,
password3=login, password4=login, password3=login, password4=login,
@ -277,7 +277,7 @@ class ZopeInstaller:
name = klass.__name__ name = klass.__name__
module = klass.__module__ module = klass.__module__
wrapper = klass.wrapperClass wrapper = klass.wrapperClass
exec 'from %s import manage_add%s as ctor' % (module, name) exec('from %s import manage_add%s as ctor' % (module, name))
self.zopeContext.registerClass(meta_type=name, self.zopeContext.registerClass(meta_type=name,
constructors = (ctor,), permission = None) constructors = (ctor,), permission = None)
# Create workflow prototypical instances in __instance__ attributes # Create workflow prototypical instances in __instance__ attributes
@ -316,7 +316,7 @@ class ZopeInstaller:
# Post-initialise every Appy type # Post-initialise every Appy type
for baseClass in klass.wrapperClass.__bases__: for baseClass in klass.wrapperClass.__bases__:
if baseClass.__name__ == 'AbstractWrapper': continue if baseClass.__name__ == 'AbstractWrapper': continue
for name, appyType in baseClass.__dict__.iteritems(): for name, appyType in baseClass.__dict__.items():
if not isinstance(appyType, gen.Field) or \ if not isinstance(appyType, gen.Field) or \
(isinstance(appyType, gen.Ref) and appyType.isBack): (isinstance(appyType, gen.Ref) and appyType.isBack):
continue # Back refs are initialised within fw refs continue # Back refs are initialised within fw refs

View file

@ -39,9 +39,9 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
rowDelimiters = {'-':'middle', '=':'top', '_':'bottom'} rowDelimiters = {'-':'middle', '=':'top', '_':'bottom'}
rowDelms = ''.join(rowDelimiters.keys()) rowDelms = ''.join(list(rowDelimiters.keys()))
cellDelimiters = {'|': 'center', ';': 'left', '!': 'right'} cellDelimiters = {'|': 'center', ';': 'left', '!': 'right'}
cellDelms = ''.join(cellDelimiters.keys()) cellDelms = ''.join(list(cellDelimiters.keys()))
pxDict = { pxDict = {
# Page-related elements # Page-related elements
@ -138,7 +138,7 @@ class Table:
# Initialise simple params, either from the true params, either from # Initialise simple params, either from the true params, either from
# the p_other Table instance. # the p_other Table instance.
for param in Table.simpleParams: for param in Table.simpleParams:
exec 'self.%s = %s%s' % (param, source, param) exec('self.%s = %s%s' % (param, source, param))
# The following attribute will store a special Row instance used for # The following attribute will store a special Row instance used for
# defining column properties. # defining column properties.
self.headerRow = None self.headerRow = None

View file

@ -120,10 +120,10 @@ def sendMail(config, to, subject, body, attachments=None, log=None):
if res and log: if res and log:
log('could not send mail to some recipients. %s' % str(res), log('could not send mail to some recipients. %s' % str(res),
type='warning') type='warning')
except smtplib.SMTPException, e: except smtplib.SMTPException as e:
if log: if log:
log('%s: mail sending failed (%s)' % (config, str(e)), type='error') log('%s: mail sending failed (%s)' % (config, str(e)), type='error')
except socket.error, se: except socket.error as se:
if log: if log:
log('%s: mail sending failed (%s)' % (config, str(se)),type='error') log('%s: mail sending failed (%s)' % (config, str(se)),type='error')
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -38,10 +38,10 @@ class Migrator:
if frozen.data.__class__.__name__ == 'Pdata': if frozen.data.__class__.__name__ == 'Pdata':
# The file content is splitted in several chunks. # The file content is splitted in several chunks.
f.write(frozen.data.data) f.write(frozen.data.data)
nextPart = frozen.data.next nextPart = frozen.data.__next__
while nextPart: while nextPart:
f.write(nextPart.data) f.write(nextPart.data)
nextPart = nextPart.next nextPart = nextPart.__next__
else: else:
# Only one chunk # Only one chunk
f.write(frozen.data) f.write(frozen.data)

View file

@ -13,18 +13,18 @@ class TestMixin:
'''Returns the list of sub-modules of p_app that are non-empty.''' '''Returns the list of sub-modules of p_app that are non-empty.'''
res = [] res = []
try: try:
exec 'import %s' % moduleName exec('import %s' % moduleName)
exec 'moduleObj = %s' % moduleName exec('moduleObj = %s' % moduleName)
moduleFile = moduleObj.__file__ moduleFile = moduleObj.__file__
if moduleFile.endswith('.pyc'): if moduleFile.endswith('.pyc'):
moduleFile = moduleFile[:-1] moduleFile = moduleFile[:-1]
except ImportError, ie: except ImportError as ie:
return res return res
except SyntaxError, se: except SyntaxError as se:
return res return res
# Include the module if not empty. "Emptyness" is determined by the # Include the module if not empty. "Emptyness" is determined by the
# absence of names beginning with other chars than "__". # absence of names beginning with other chars than "__".
for elem in moduleObj.__dict__.iterkeys(): for elem in moduleObj.__dict__.keys():
if not elem.startswith('__'): if not elem.startswith('__'):
res.append(moduleObj) res.append(moduleObj)
break break
@ -66,10 +66,10 @@ def afterTest(test):
'''Is executed after every test.''' '''Is executed after every test.'''
g = test.globs g = test.globs
appName = g['tool'].o.getAppName() appName = g['tool'].o.getAppName()
exec 'from Products.%s import cov, covFolder, totalNumberOfTests, ' \ exec('from Products.%s import cov, covFolder, totalNumberOfTests, ' \
'countTest' % appName 'countTest' % appName)
countTest() countTest()
exec 'from Products.%s import numberOfExecutedTests' % appName exec('from Products.%s import numberOfExecutedTests' % appName)
if cov and (numberOfExecutedTests == totalNumberOfTests): if cov and (numberOfExecutedTests == totalNumberOfTests):
cov.stop() cov.stop()
appModules = test.getNonEmptySubModules(appName) appModules = test.getNonEmptySubModules(appName)

View file

@ -13,6 +13,7 @@ from appy.shared import mimeTypes
from appy.shared import utils as sutils from appy.shared import utils as sutils
from appy.shared.data import languages from appy.shared.data import languages
from appy.shared.ldap_connector import LdapConnector from appy.shared.ldap_connector import LdapConnector
import collections
try: try:
from AccessControl.ZopeSecurityPolicy import _noroles from AccessControl.ZopeSecurityPolicy import _noroles
except ImportError: except ImportError:
@ -36,7 +37,7 @@ class ToolMixin(BaseMixin):
p_metaTypeOrAppyType.''' p_metaTypeOrAppyType.'''
appName = self.getProductConfig().PROJECTNAME appName = self.getProductConfig().PROJECTNAME
res = metaTypeOrAppyClass res = metaTypeOrAppyClass
if not isinstance(metaTypeOrAppyClass, basestring): if not isinstance(metaTypeOrAppyClass, str):
res = gutils.getClassName(metaTypeOrAppyClass, appName) res = gutils.getClassName(metaTypeOrAppyClass, appName)
if res.find('_wrappers') != -1: if res.find('_wrappers') != -1:
elems = res.split('_') elems = res.split('_')
@ -439,7 +440,7 @@ class ToolMixin(BaseMixin):
def quote(self, s, escapeWithEntity=True): def quote(self, s, escapeWithEntity=True):
'''Returns the quoted version of p_s.''' '''Returns the quoted version of p_s.'''
if not isinstance(s, basestring): s = str(s) if not isinstance(s, str): s = str(s)
repl = escapeWithEntity and '&apos;' or "\\'" repl = escapeWithEntity and '&apos;' or "\\'"
s = s.replace('\r\n', '').replace('\n', '').replace("'", repl) s = s.replace('\r\n', '').replace('\n', '').replace("'", repl)
return "'%s'" % s return "'%s'" % s
@ -452,7 +453,7 @@ class ToolMixin(BaseMixin):
def getZopeClass(self, name): def getZopeClass(self, name):
'''Returns the Zope class whose name is p_name.''' '''Returns the Zope class whose name is p_name.'''
exec 'from Products.%s.%s import %s as C'% (self.getAppName(),name,name) exec('from Products.%s.%s import %s as C'% (self.getAppName(),name,name))
return C return C
def getAppyClass(self, zopeName, wrapper=False): def getAppyClass(self, zopeName, wrapper=False):
@ -476,12 +477,12 @@ class ToolMixin(BaseMixin):
'''Gets the different ways objects of p_klass can be created (currently: '''Gets the different ways objects of p_klass can be created (currently:
via a web form or programmatically only). Result is a list.''' via a web form or programmatically only). Result is a list.'''
res = [] res = []
if not klass.__dict__.has_key('create'): if 'create' not in klass.__dict__:
return ['form'] return ['form']
else: else:
means = klass.create means = klass.create
if means: if means:
if isinstance(means, basestring): res = [means] if isinstance(means, str): res = [means]
else: res = means else: res = means
return res return res
@ -511,7 +512,7 @@ class ToolMixin(BaseMixin):
else: else:
creators = self.getProductConfig().appConfig.defaultCreators creators = self.getProductConfig().appConfig.defaultCreators
# Resolve case (3): if "creators" is a method, execute it. # Resolve case (3): if "creators" is a method, execute it.
if callable(creators): creators = creators(self.appy()) if isinstance(creators, collections.Callable): creators = creators(self.appy())
# Resolve case (2) # Resolve case (2)
if isinstance(creators, bool) or not creators: return creators if isinstance(creators, bool) or not creators: return creators
# Resolve case (1): checks whether the user has at least one of the # Resolve case (1): checks whether the user has at least one of the
@ -595,7 +596,7 @@ class ToolMixin(BaseMixin):
rq = self.REQUEST rq = self.REQUEST
# Store the search criteria in the session # Store the search criteria in the session
criteria = self._getDefaultSearchCriteria() criteria = self._getDefaultSearchCriteria()
for name in rq.form.keys(): for name in list(rq.form.keys()):
if name.startswith('w_') and not self._searchValueIsEmpty(name): if name.startswith('w_') and not self._searchValueIsEmpty(name):
hasStar = name.find('*') != -1 hasStar = name.find('*') != -1
fieldName = not hasStar and name[2:] or name[2:name.find('*')] fieldName = not hasStar and name[2:] or name[2:name.find('*')]
@ -609,17 +610,17 @@ class ToolMixin(BaseMixin):
# The type of the value is encoded after char "*". # The type of the value is encoded after char "*".
name, type = name.split('*') name, type = name.split('*')
if type == 'bool': if type == 'bool':
exec 'value = %s' % value exec('value = %s' % value)
elif type in ('int', 'float'): elif type in ('int', 'float'):
# Get the "from" value # Get the "from" value
if not value: value = None if not value: value = None
else: else:
exec 'value = %s(value)' % type exec('value = %s(value)' % type)
# Get the "to" value # Get the "to" value
toValue = rq.form['%s_to' % name[2:]].strip() toValue = rq.form['%s_to' % name[2:]].strip()
if not toValue: toValue = None if not toValue: toValue = None
else: else:
exec 'toValue = %s(toValue)' % type exec('toValue = %s(toValue)' % type)
value = (value, toValue) value = (value, toValue)
elif type == 'date': elif type == 'date':
prefix = name[2:] prefix = name[2:]
@ -640,8 +641,8 @@ class ToolMixin(BaseMixin):
if len(type) > 6: if len(type) > 6:
transform = type.split('-')[1] transform = type.split('-')[1]
if (transform != 'none') and value: if (transform != 'none') and value:
exec 'value = value.%s()' % \ exec('value = value.%s()' % \
self.transformMethods[transform] self.transformMethods[transform])
if isinstance(value, list): if isinstance(value, list):
# It is a list of values. Check if we have an operator for # It is a list of values. Check if we have an operator for
# the field, to see if we make an "and" or "or" for all # the field, to see if we make an "and" or "or" for all
@ -697,7 +698,7 @@ class ToolMixin(BaseMixin):
it among search criteria in the session.''' it among search criteria in the session.'''
if not refInfo and (self.REQUEST.get('search', None) == 'customSearch'): if not refInfo and (self.REQUEST.get('search', None) == 'customSearch'):
criteria = self.REQUEST.SESSION.get('searchCriteria', None) criteria = self.REQUEST.SESSION.get('searchCriteria', None)
if criteria and criteria.has_key('_ref'): refInfo = criteria['_ref'] if criteria and '_ref' in criteria: refInfo = criteria['_ref']
if not refInfo: return None, None if not refInfo: return None, None
objectUid, fieldName = refInfo.split(':') objectUid, fieldName = refInfo.split(':')
obj = self.getObject(objectUid) obj = self.getObject(objectUid)
@ -856,7 +857,7 @@ class ToolMixin(BaseMixin):
try: try:
creds = creds.split(' ')[-1] creds = creds.split(' ')[-1]
login, password = base64.decodestring(creds).split(':', 1) login, password = base64.decodestring(creds).split(':', 1)
except Exception, e: except Exception as e:
pass pass
# b. Identify the user from the authentication cookie. # b. Identify the user from the authentication cookie.
if not login: if not login:
@ -968,7 +969,7 @@ class ToolMixin(BaseMixin):
# Invalidate the user session. # Invalidate the user session.
try: try:
sdm = self.session_data_manager sdm = self.session_data_manager
except AttributeError, ae: except AttributeError as ae:
# When ran in test mode, session_data_manager is not there. # When ran in test mode, session_data_manager is not there.
sdm = None sdm = None
if sdm: if sdm:
@ -977,7 +978,7 @@ class ToolMixin(BaseMixin):
session.invalidate() session.invalidate()
self.log('logged out.') self.log('logged out.')
# Remove user from variable "loggedUsers" # Remove user from variable "loggedUsers"
if self.loggedUsers.has_key(userId): del self.loggedUsers[userId] if userId in self.loggedUsers: del self.loggedUsers[userId]
return self.goto(self.getApp().absolute_url()) return self.goto(self.getApp().absolute_url())
# This dict stores, for every logged user, the date/time of its last access # This dict stores, for every logged user, the date/time of its last access
@ -1247,7 +1248,7 @@ class ToolMixin(BaseMixin):
if hasattr(klass, 'popup'): if hasattr(klass, 'popup'):
res.target = 'appyIFrame' res.target = 'appyIFrame'
d = klass.popup d = klass.popup
if isinstance(d, basestring): if isinstance(d, str):
# Width only # Width only
params = d[:-2] params = d[:-2]
else: else:

View file

@ -3,7 +3,7 @@
- mixins/ToolMixin is mixed in with the generated application Tool class.''' - mixins/ToolMixin is mixed in with the generated application Tool class.'''
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import os, os.path, re, sys, types, urllib, cgi import os, os.path, re, sys, types, urllib.request, urllib.parse, urllib.error, cgi
from appy import Object from appy import Object
from appy.px import Px from appy.px import Px
from appy.fields.workflow import UiTransition from appy.fields.workflow import UiTransition
@ -15,6 +15,7 @@ from appy.shared import utils as sutils
from appy.shared.data import rtlLanguages from appy.shared.data import rtlLanguages
from appy.shared.xml_parser import XmlMarshaller, XmlUnmarshaller from appy.shared.xml_parser import XmlMarshaller, XmlUnmarshaller
from appy.shared.diff import HtmlDiff from appy.shared.diff import HtmlDiff
import collections
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
NUMBERED_ID = re.compile('.+\d{4}$') NUMBERED_ID = re.compile('.+\d{4}$')
@ -371,9 +372,9 @@ class BaseMixin:
# p_errors object. Within this object, for every error message that is # p_errors object. Within this object, for every error message that is
# not a string, we replace it with the standard validation error for the # not a string, we replace it with the standard validation error for the
# corresponding field. # corresponding field.
for key, value in errors.__dict__.iteritems(): for key, value in errors.__dict__.items():
resValue = value resValue = value
if not isinstance(resValue, basestring): if not isinstance(resValue, str):
resValue = self.translate('field_invalid') resValue = self.translate('field_invalid')
setattr(errors, key, resValue) setattr(errors, key, resValue)
return msg return msg
@ -419,7 +420,7 @@ class BaseMixin:
# Trigger field-specific validation # Trigger field-specific validation
self.intraFieldValidation(errors, values) self.intraFieldValidation(errors, values)
if errors.__dict__: if errors.__dict__:
for k,v in errors.__dict__.iteritems(): rq.set('%s_error' % k, v) for k,v in errors.__dict__.items(): rq.set('%s_error' % k, v)
self.say(errorMessage) self.say(errorMessage)
return self.gotoEdit() return self.gotoEdit()
@ -427,7 +428,7 @@ class BaseMixin:
msg = self.interFieldValidation(errors, values) msg = self.interFieldValidation(errors, values)
if not msg: msg = errorMessage if not msg: msg = errorMessage
if errors.__dict__: if errors.__dict__:
for k,v in errors.__dict__.iteritems(): rq.set('%s_error' % k, v) for k,v in errors.__dict__.items(): rq.set('%s_error' % k, v)
self.say(msg) self.say(msg)
return self.gotoEdit() return self.gotoEdit()
@ -506,7 +507,7 @@ class BaseMixin:
# Get the list of indexes that apply on this object. Else, Zope # Get the list of indexes that apply on this object. Else, Zope
# will reindex all indexes defined in the catalog, and through # will reindex all indexes defined in the catalog, and through
# acquisition, wrong methods can be called on wrong objects. # acquisition, wrong methods can be called on wrong objects.
iNames = self.wrapperClass.getIndexes().keys() iNames = list(self.wrapperClass.getIndexes().keys())
catalog.catalog_object(self, path, idxs=iNames) catalog.catalog_object(self, path, idxs=iNames)
def xml(self, action=None): def xml(self, action=None):
@ -529,14 +530,14 @@ class BaseMixin:
elif isinstance(methodRes, file): elif isinstance(methodRes, file):
res = methodRes.read() res = methodRes.read()
methodRes.close() methodRes.close()
elif isinstance(methodRes, basestring) and \ elif isinstance(methodRes, str) and \
methodRes.startswith('<?xml'): # Already XML methodRes.startswith('<?xml'): # Already XML
return methodRes return methodRes
else: else:
marshaller = XmlMarshaller() marshaller = XmlMarshaller()
oType = isinstance(methodRes, Object) and 'popo' or 'appy' oType = isinstance(methodRes, Object) and 'popo' or 'appy'
res = marshaller.marshall(methodRes, objectType=oType) res = marshaller.marshall(methodRes, objectType=oType)
except Exception, e: except Exception as e:
tb = sutils.Traceback.get() tb = sutils.Traceback.get()
res = XmlMarshaller(rootTag='exception').marshall(tb) res = XmlMarshaller(rootTag='exception').marshall(tb)
self.log(tb, type='error') self.log(tb, type='error')
@ -548,7 +549,7 @@ class BaseMixin:
'''Prints a p_msg in the user interface. p_logLevel may be "info", '''Prints a p_msg in the user interface. p_logLevel may be "info",
"warning" or "error".''' "warning" or "error".'''
rq = self.REQUEST rq = self.REQUEST
if 'messages' not in rq.SESSION.keys(): if 'messages' not in list(rq.SESSION.keys()):
plist = self.getProductConfig().PersistentList plist = self.getProductConfig().PersistentList
messages = rq.SESSION['messages'] = plist() messages = rq.SESSION['messages'] = plist()
else: else:
@ -619,7 +620,7 @@ class BaseMixin:
For a multilingual string field, p_changes can contain a key for For a multilingual string field, p_changes can contain a key for
every language, of the form <field name>-<language>.''' every language, of the form <field name>-<language>.'''
# Add to the p_changes dict the field labels # Add to the p_changes dict the field labels
for name in changes.keys(): for name in list(changes.keys()):
# "name" can contain the language for multilingual fields. # "name" can contain the language for multilingual fields.
if '-' in name: if '-' in name:
fieldName, lg = name.split('-') fieldName, lg = name.split('-')
@ -646,7 +647,7 @@ class BaseMixin:
historized fields, while p_self already contains the (potentially) historized fields, while p_self already contains the (potentially)
modified values.''' modified values.'''
# Remove from previousData all values that were not changed # Remove from previousData all values that were not changed
for name in previousData.keys(): for name in list(previousData.keys()):
field = self.getAppyType(name) field = self.getAppyType(name)
prev = previousData[name] prev = previousData[name]
curr = field.getValue(self) curr = field.getValue(self)
@ -655,7 +656,7 @@ class BaseMixin:
((prev == '') and (curr == None)): ((prev == '') and (curr == None)):
del previousData[name] del previousData[name]
continue continue
except UnicodeDecodeError, ude: except UnicodeDecodeError as ude:
# The string comparisons above may imply silent encoding-related # The string comparisons above may imply silent encoding-related
# conversions that may produce this exception. # conversions that may produce this exception.
continue continue
@ -743,15 +744,15 @@ class BaseMixin:
else: else:
klass = self.appy().klass klass = self.appy().klass
moduleName = klass.__module__ moduleName = klass.__module__
exec 'import %s' % moduleName exec('import %s' % moduleName)
exec 'reload(%s)' % moduleName exec('reload(%s)' % moduleName)
exec 'res = %s.%s' % (moduleName, klass.__name__) exec('res = %s.%s' % (moduleName, klass.__name__))
# More manipulations may have occurred in m_update # More manipulations may have occurred in m_update
if hasattr(res, 'update'): if hasattr(res, 'update'):
parentName= res.__bases__[-1].__name__ parentName= res.__bases__[-1].__name__
moduleName= 'Products.%s.wrappers' % self.getTool().getAppName() moduleName= 'Products.%s.wrappers' % self.getTool().getAppName()
exec 'import %s' % moduleName exec('import %s' % moduleName)
exec 'parent = %s.%s' % (moduleName, parentName) exec('parent = %s.%s' % (moduleName, parentName))
res.update(parent) res.update(parent)
return res return res
@ -839,15 +840,15 @@ class BaseMixin:
req = self.REQUEST req = self.REQUEST
for field in self.getAllAppyTypes(): for field in self.getAllAppyTypes():
if field.page.name != pageName: continue if field.page.name != pageName: continue
if field.masterValue and callable(field.masterValue): if field.masterValue and isinstance(field.masterValue, collections.Callable):
# We have a slave field that is updated via ajax requests. # We have a slave field that is updated via ajax requests.
name = field.name name = field.name
# Remember the request value for this field if present. # Remember the request value for this field if present.
if req.has_key(name) and req[name]: if name in req and req[name]:
requestValues[name] = req[name] requestValues[name] = req[name]
# Remember the validation error for this field if present. # Remember the validation error for this field if present.
errorKey = '%s_error' % name errorKey = '%s_error' % name
if req.has_key(errorKey): if errorKey in req:
errors[name] = req[errorKey] errors[name] = req[errorKey]
return sutils.getStringDict(requestValues), sutils.getStringDict(errors) return sutils.getStringDict(requestValues), sutils.getStringDict(errors)
@ -899,7 +900,7 @@ class BaseMixin:
del phases[res[i].name] del phases[res[i].name]
del res[i] del res[i]
# Compute next/previous phases of every phase # Compute next/previous phases of every phase
for ph in phases.itervalues(): for ph in phases.values():
ph.computeNextPrevious(res) ph.computeNextPrevious(res)
ph.totalNbOfPhases = len(res) ph.totalNbOfPhases = len(res)
# Restrict the result to the current phase if required # Restrict the result to the current phase if required
@ -1208,7 +1209,7 @@ class BaseMixin:
# fields' old values by their formatted counterparts. # fields' old values by their formatted counterparts.
event = history[i].copy() event = history[i].copy()
event['changes'] = {} event['changes'] = {}
for name, oldValue in history[i]['changes'].iteritems(): for name, oldValue in history[i]['changes'].items():
# "name" can specify a language-specific part in a # "name" can specify a language-specific part in a
# multilingual field. "oldValue" is a tuple # multilingual field. "oldValue" is a tuple
# (value, fieldName). # (value, fieldName).
@ -1455,7 +1456,7 @@ class BaseMixin:
# Add users or groups having, locally, this role on this object. # Add users or groups having, locally, this role on this object.
localRoles = getattr(self.aq_base, '__ac_local_roles__', None) localRoles = getattr(self.aq_base, '__ac_local_roles__', None)
if not localRoles: return res if not localRoles: return res
for id, roles in localRoles.iteritems(): for id, roles in localRoles.items():
for role in roles: for role in roles:
if role in res: if role in res:
usr = 'user:%s' % id usr = 'user:%s' % id
@ -1465,7 +1466,7 @@ class BaseMixin:
def showState(self): def showState(self):
'''Must I show self's current state ?''' '''Must I show self's current state ?'''
stateShow = self.State(name=False).show stateShow = self.State(name=False).show
if callable(stateShow): if isinstance(stateShow, collections.Callable):
return stateShow(self.getWorkflow(), self.appy()) return stateShow(self.getWorkflow(), self.appy())
return stateShow return stateShow
@ -1479,7 +1480,7 @@ class BaseMixin:
if not hasattr(klass, 'showTransitions'): return (layoutType=='view') if not hasattr(klass, 'showTransitions'): return (layoutType=='view')
showValue = klass.showTransitions showValue = klass.showTransitions
# This value can be a single value or a tuple/list of values. # This value can be a single value or a tuple/list of values.
if isinstance(showValue, basestring): return layoutType == showValue if isinstance(showValue, str): return layoutType == showValue
return layoutType in showValue return layoutType in showValue
getUrlDefaults = {'page':True, 'nav':True} getUrlDefaults = {'page':True, 'nav':True}
@ -1524,8 +1525,8 @@ class BaseMixin:
if 'nav' not in kwargs: kwargs['nav'] = True if 'nav' not in kwargs: kwargs['nav'] = True
# Create URL parameters from kwargs # Create URL parameters from kwargs
params = [] params = []
for name, value in kwargs.iteritems(): for name, value in kwargs.items():
if isinstance(value, basestring): if isinstance(value, str):
params.append('%s=%s' % (name, value)) params.append('%s=%s' % (name, value))
elif self.REQUEST.get(name, ''): elif self.REQUEST.get(name, ''):
params.append('%s=%s' % (name, self.REQUEST[name])) params.append('%s=%s' % (name, self.REQUEST[name]))
@ -1601,7 +1602,7 @@ class BaseMixin:
# Find the name of the method to call. # Find the name of the method to call.
methodName = rq.QUERY_STRING.split('=')[1] methodName = rq.QUERY_STRING.split('=')[1]
return self.xml(action=methodName) return self.xml(action=methodName)
elif rq.has_key('do'): elif 'do' in rq:
# The user wants to call a method on this object and get its result # The user wants to call a method on this object and get its result
# as XML. # as XML.
return self.xml(action=rq['do']) return self.xml(action=rq['do'])
@ -1672,7 +1673,7 @@ class BaseMixin:
if field.type != 'group': if field.type != 'group':
fieldMapping = field.mapping[label] fieldMapping = field.mapping[label]
if fieldMapping: if fieldMapping:
if callable(fieldMapping): if isinstance(fieldMapping, collections.Callable):
fieldMapping = field.callMethod(self, fieldMapping) fieldMapping = field.callMethod(self, fieldMapping)
mapping.update(fieldMapping) mapping.update(fieldMapping)
label = getattr(field, '%sId' % label) label = getattr(field, '%sId' % label)
@ -1697,15 +1698,15 @@ class BaseMixin:
# Perform replacements, according to p_format. # Perform replacements, according to p_format.
res = self.formatText(res, format) res = self.formatText(res, format)
# Perform variable replacements # Perform variable replacements
for name, repl in mapping.iteritems(): for name, repl in mapping.items():
if not isinstance(repl, basestring): repl = str(repl) if not isinstance(repl, str): repl = str(repl)
res = res.replace('${%s}' % name, repl) res = res.replace('${%s}' % name, repl)
return res return res
def getPageLayout(self, layoutType): def getPageLayout(self, layoutType):
'''Returns the layout corresponding to p_layoutType for p_self.''' '''Returns the layout corresponding to p_layoutType for p_self.'''
res = self.wrapperClass.getPageLayouts()[layoutType] res = self.wrapperClass.getPageLayouts()[layoutType]
if isinstance(res, basestring): res = Table(res) if isinstance(res, str): res = Table(res)
return res return res
def download(self, name=None): def download(self, name=None):

View file

@ -5,6 +5,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import types import types
import appy.gen as gen import appy.gen as gen
import collections
# Prototypical instances of every type ----------------------------------------- # Prototypical instances of every type -----------------------------------------
class Protos: class Protos:
@ -49,7 +50,7 @@ class ModelClass:
'''This method returns the code declaration for p_appyType.''' '''This method returns the code declaration for p_appyType.'''
typeArgs = '' typeArgs = ''
proto = Protos.get(appyType) proto = Protos.get(appyType)
for name, value in appyType.__dict__.iteritems(): for name, value in appyType.__dict__.items():
# Some attrs can't be given to the constructor # Some attrs can't be given to the constructor
if name in Protos.notInit: continue if name in Protos.notInit: continue
# If the given value corresponds to the default value, don't give it # If the given value corresponds to the default value, don't give it
@ -74,7 +75,7 @@ class ModelClass:
# defined. So we initialize it to None. The post-init of the # defined. So we initialize it to None. The post-init of the
# field must be done manually in wrappers.py. # field must be done manually in wrappers.py.
value = 'None' value = 'None'
elif isinstance(value, basestring): elif isinstance(value, str):
value = '"%s"' % value value = '"%s"' % value
elif isinstance(value, gen.Ref): elif isinstance(value, gen.Ref):
if not value.isBack: continue if not value.isBack: continue
@ -91,10 +92,10 @@ class ModelClass:
value = 'Grp("%s")' % value.name value = 'Grp("%s")' % value.name
elif isinstance(value, gen.Page): elif isinstance(value, gen.Page):
value = 'pges["%s"]' % value.name value = 'pges["%s"]' % value.name
elif callable(value): elif isinstance(value, collections.Callable):
className = wrapperName className = wrapperName
if (appyType.type == 'Ref') and appyType.isBack: if (appyType.type == 'Ref') and appyType.isBack:
className = value.im_class.__name__ className = value.__self__.__class__.__name__
value = '%s.%s' % (className, value.__name__) value = '%s.%s' % (className, value.__name__)
typeArgs += '%s=%s,' % (name, value) typeArgs += '%s=%s,' % (name, value)
return '%s(%s)' % (appyType.__class__.__name__, typeArgs) return '%s(%s)' % (appyType.__class__.__name__, typeArgs)
@ -118,17 +119,17 @@ class ModelClass:
pages = {} pages = {}
layouts = [] layouts = []
for name in klass._appy_attributes: for name in klass._appy_attributes:
exec 'appyType = klass.%s' % name exec('appyType = klass.%s' % name)
if appyType.page.name not in pages: if appyType.page.name not in pages:
pages[appyType.page.name] = appyType.page pages[appyType.page.name] = appyType.page
res += ' pges = {' res += ' pges = {'
for page in pages.itervalues(): for page in pages.values():
# Determine page "show" attributes # Determine page "show" attributes
pShow = '' pShow = ''
for attr in ('',) + page.subElements: for attr in ('',) + page.subElements:
attrName = 'show%s' % attr.capitalize() attrName = 'show%s' % attr.capitalize()
pageShow = getattr(page, attrName) pageShow = getattr(page, attrName)
if isinstance(pageShow, basestring): pageShow='"%s"' % pageShow if isinstance(pageShow, str): pageShow='"%s"' % pageShow
elif callable(pageShow): elif callable(pageShow):
pageShow = '%s.%s' % (wrapperName, pageShow.__name__) pageShow = '%s.%s' % (wrapperName, pageShow.__name__)
if pageShow != True: if pageShow != True:
@ -142,7 +143,7 @@ class ModelClass:
res += '}\n' res += '}\n'
# Secondly, dump every (not Ref.isBack) attribute # Secondly, dump every (not Ref.isBack) attribute
for name in klass._appy_attributes: for name in klass._appy_attributes:
exec 'appyType = klass.%s' % name exec('appyType = klass.%s' % name)
if (appyType.type == 'Ref') and appyType.isBack: continue if (appyType.type == 'Ref') and appyType.isBack: continue
typeBody = klass._appy_getTypeBody(appyType, wrapperName) typeBody = klass._appy_getTypeBody(appyType, wrapperName)
res += ' %s=%s\n' % (name, typeBody) res += ' %s=%s\n' % (name, typeBody)
@ -305,12 +306,12 @@ class Tool(ModelClass):
@classmethod @classmethod
def _appy_clean(klass): def _appy_clean(klass):
toClean = [] toClean = []
for k, v in klass.__dict__.iteritems(): for k, v in klass.__dict__.items():
if not k.startswith('__') and (not k.startswith('_appy_')): if not k.startswith('__') and (not k.startswith('_appy_')):
if k not in defaultToolFields: if k not in defaultToolFields:
toClean.append(k) toClean.append(k)
for k in toClean: for k in toClean:
exec 'del klass.%s' % k exec('del klass.%s' % k)
klass._appy_attributes = list(defaultToolFields) klass._appy_attributes = list(defaultToolFields)
klass.folder = True klass.folder = True
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -1,6 +1,6 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import os, re, time, copy import os, re, time, copy
from utils import produceNiceMessage from .utils import produceNiceMessage
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
poHeader = '''msgid "" poHeader = '''msgid ""
@ -213,7 +213,7 @@ class PoFile:
if keepExistingOrder: if keepExistingOrder:
# Update existing messages and add inexistent messages to the end. # Update existing messages and add inexistent messages to the end.
for newMsg in newMessages: for newMsg in newMessages:
if self.messagesDict.has_key(newMsg.id): if newMsg.id in self.messagesDict:
msg = self.messagesDict[newMsg.id] msg = self.messagesDict[newMsg.id]
else: else:
msg = self.addMessage(newMsg) msg = self.addMessage(newMsg)
@ -224,7 +224,7 @@ class PoFile:
notNewMessages = [m for m in self.messages if m.id not in newIds] notNewMessages = [m for m in self.messages if m.id not in newIds]
del self.messages[:] del self.messages[:]
for newMsg in newMessages: for newMsg in newMessages:
if self.messagesDict.has_key(newMsg.id): if newMsg.id in self.messagesDict:
msg = self.messagesDict[newMsg.id] msg = self.messagesDict[newMsg.id]
self.messages.append(msg) self.messages.append(msg)
else: else:
@ -240,7 +240,7 @@ class PoFile:
fb = '' fb = ''
if not self.isPot: if not self.isPot:
# I must add fallbacks # I must add fallbacks
if fallbacks.has_key(self.language): if self.language in fallbacks:
fb = '"X-is-fallback-for: %s\\n"' % fallbacks[self.language] fb = '"X-is-fallback-for: %s\\n"' % fallbacks[self.language]
f.write(poHeader % (self.applicationName, creationTime, f.write(poHeader % (self.applicationName, creationTime,
self.language, self.language, self.domain, fb)) self.language, self.language, self.domain, fb))

View file

@ -1,7 +1,8 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import re, os, os.path, base64, urllib import re, os, os.path, base64, urllib.request, urllib.parse, urllib.error
from appy.px import Px from appy.px import Px
from appy.shared import utils as sutils from appy.shared import utils as sutils
import collections
# Function for creating a Zope object ------------------------------------------ # Function for creating a Zope object ------------------------------------------
def createObject(folder, id, className, appName, wf=True, noSecurity=False): def createObject(folder, id, className, appName, wf=True, noSecurity=False):
@ -10,8 +11,8 @@ def createObject(folder, id, className, appName, wf=True, noSecurity=False):
creation of the config object), computing workflow-related info is not creation of the config object), computing workflow-related info is not
possible at this time. This is why this function can be called with possible at this time. This is why this function can be called with
p_wf=False.''' p_wf=False.'''
exec 'from Products.%s.%s import %s as ZopeClass' % \ exec('from Products.%s.%s import %s as ZopeClass' % \
(appName, className, className) (appName, className, className))
# Get the tool. It may not be present yet, maybe are we creating it now. # Get the tool. It may not be present yet, maybe are we creating it now.
if folder.meta_type.endswith('Folder'): if folder.meta_type.endswith('Folder'):
# p_folder is a standard Zope (temp) folder. # p_folder is a standard Zope (temp) folder.
@ -178,7 +179,7 @@ def callMethod(obj, method, klass=None, cache=True):
if methodType == 'staticmethod': if methodType == 'staticmethod':
method = method.__get__(klass) method = method.__get__(klass)
elif methodType == 'instancemethod': elif methodType == 'instancemethod':
method = method.im_func method = method.__func__
# Call the method if cache is not needed # Call the method if cache is not needed
if not cache: return method(obj) if not cache: return method(obj)
# If first arg of method is named "tool" instead of the traditional "self", # If first arg of method is named "tool" instead of the traditional "self",
@ -187,7 +188,7 @@ def callMethod(obj, method, klass=None, cache=True):
# Every method call, even on different instances, will be cached in a unique # Every method call, even on different instances, will be cached in a unique
# key. # key.
cheat = False cheat = False
if not klass and (method.func_code.co_varnames[0] == 'tool'): if not klass and (method.__code__.co_varnames[0] == 'tool'):
prefix = obj.klass.__name__ prefix = obj.klass.__name__
obj = obj.tool obj = obj.tool
cheat = True cheat = True
@ -200,7 +201,7 @@ def callMethod(obj, method, klass=None, cache=True):
else: else:
prefix = obj.uid prefix = obj.uid
# Second part of the key: p_method name # Second part of the key: p_method name
key = '%s:%s' % (prefix, method.func_name) key = '%s:%s' % (prefix, method.__name__)
# Return the cached value if present in the method cache. # Return the cached value if present in the method cache.
if key in rq.methodCache: if key in rq.methodCache:
return rq.methodCache[key] return rq.methodCache[key]
@ -216,20 +217,20 @@ def readCookie(request):
(None, None).''' (None, None).'''
cookie = request.get('_appy_', None) cookie = request.get('_appy_', None)
if not cookie: return None, None if not cookie: return None, None
cookieValue = base64.decodestring(urllib.unquote(cookie)) cookieValue = base64.decodestring(urllib.parse.unquote(cookie))
if ':' in cookieValue: return cookieValue.split(':') if ':' in cookieValue: return cookieValue.split(':')
return None, None return None, None
def writeCookie(login, password, request): def writeCookie(login, password, request):
'''Encode p_login and p_password into the cookie set in the p_request.''' '''Encode p_login and p_password into the cookie set in the p_request.'''
cookieValue = base64.encodestring('%s:%s' % (login, password)).rstrip() cookieValue = base64.encodestring('%s:%s' % (login, password)).rstrip()
cookieValue = urllib.quote(cookieValue) cookieValue = urllib.parse.quote(cookieValue)
request.RESPONSE.setCookie('_appy_', cookieValue, path='/') request.RESPONSE.setCookie('_appy_', cookieValue, path='/')
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
def initMasterValue(v): def initMasterValue(v):
'''Standardizes p_v as a list of strings, excepted if p_v is a method.''' '''Standardizes p_v as a list of strings, excepted if p_v is a method.'''
if callable(v): return v if isinstance(v, collections.Callable): return v
if not isinstance(v, bool) and not v: res = [] if not isinstance(v, bool) and not v: res = []
elif type(v) not in sutils.sequenceTypes: res = [v] elif type(v) not in sutils.sequenceTypes: res = [v]
else: res = v else: res = v
@ -243,7 +244,7 @@ class No:
instead. When creating such an instance, you can specify an error instead. When creating such an instance, you can specify an error
message.''' message.'''
def __init__(self, msg): self.msg = msg def __init__(self, msg): self.msg = msg
def __nonzero__(self): return False def __bool__(self): return False
def __repr__(self): return '<No: %s>' % self.msg def __repr__(self): return '<No: %s>' % self.msg
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -424,7 +424,7 @@ class ToolWrapper(AbstractWrapper):
'<tr><th></th><th>%s</th></tr>' % \ '<tr><th></th><th>%s</th></tr>' % \
self.translate('last_user_access') self.translate('last_user_access')
rows = [] rows = []
for userId, lastAccess in self.o.loggedUsers.items(): for userId, lastAccess in list(self.o.loggedUsers.items()):
user = self.search1('User', noSecurity=True, login=userId) user = self.search1('User', noSecurity=True, login=userId)
if not user: continue # Could have been deleted in the meanwhile if not user: continue # Could have been deleted in the meanwhile
fmt = '%s (%s)' % (self.dateFormat, self.hourFormat) fmt = '%s (%s)' % (self.dateFormat, self.hourFormat)
@ -515,7 +515,7 @@ class ToolWrapper(AbstractWrapper):
failed += subFailed failed += subFailed
try: try:
startObject.reindex() startObject.reindex()
except Exception, e: except Exception as e:
failed.append(startObject) failed.append(startObject)
return nb, failed return nb, failed

View file

@ -343,7 +343,7 @@ class UserWrapper(AbstractWrapper):
if not localRoles: return res if not localRoles: return res
# Gets the logins of this user and all its groups. # Gets the logins of this user and all its groups.
logins = self.getLogins() logins = self.getLogins()
for login, roles in localRoles.iteritems(): for login, roles in localRoles.items():
# Ignore logins not corresponding to this user. # Ignore logins not corresponding to this user.
if login not in logins: continue if login not in logins: continue
for role in roles: for role in roles:
@ -388,7 +388,7 @@ class UserWrapper(AbstractWrapper):
if not localRoles: return if not localRoles: return
# Gets the logins of this user and all its groups. # Gets the logins of this user and all its groups.
userLogins = self.getLogins() userLogins = self.getLogins()
for login, roles in localRoles.iteritems(): for login, roles in localRoles.items():
# Ignore logins not corresponding to this user. # Ignore logins not corresponding to this user.
if login not in userLogins: continue if login not in userLogins: continue
for role in roles: for role in roles:

View file

@ -861,7 +861,7 @@ class AbstractWrapper(object):
if len(self.__class__.__bases__) > 1: if len(self.__class__.__bases__) > 1:
# There is a custom user class # There is a custom user class
custom = self.__class__.__bases__[-1] custom = self.__class__.__bases__[-1]
if custom.__dict__.has_key(methodName): if methodName in custom.__dict__:
return custom.__dict__[methodName] return custom.__dict__[methodName]
def _callCustom(self, methodName, *args, **kwargs): def _callCustom(self, methodName, *args, **kwargs):
@ -973,7 +973,7 @@ class AbstractWrapper(object):
present, will not be called; any other defined method will not be present, will not be called; any other defined method will not be
called neither (ie, Ref.insert, Ref.beforeLink, Ref.afterLink...). called neither (ie, Ref.insert, Ref.beforeLink, Ref.afterLink...).
''' '''
isField = isinstance(fieldNameOrClass, basestring) isField = isinstance(fieldNameOrClass, str)
tool = self.tool.o tool = self.tool.o
# Determine the class of the object to create # Determine the class of the object to create
if isField: if isField:
@ -984,7 +984,7 @@ class AbstractWrapper(object):
klass = fieldNameOrClass klass = fieldNameOrClass
portalType = tool.getPortalType(klass) portalType = tool.getPortalType(klass)
# Determine object id # Determine object id
if kwargs.has_key('id'): if 'id' in kwargs:
objId = kwargs['id'] objId = kwargs['id']
del kwargs['id'] del kwargs['id']
else: else:
@ -1002,7 +1002,7 @@ class AbstractWrapper(object):
noSecurity=noSecurity) noSecurity=noSecurity)
appyObj = zopeObj.appy() appyObj = zopeObj.appy()
# Set object attributes # Set object attributes
for attrName, attrValue in kwargs.iteritems(): for attrName, attrValue in kwargs.items():
try: try:
setattr(appyObj, attrName, attrValue) setattr(appyObj, attrName, attrValue)
except AttributeError, ae: except AttributeError, ae:
@ -1183,8 +1183,8 @@ class AbstractWrapper(object):
# Get the Appy object from the brain # Get the Appy object from the brain
if noSecurity: method = '_unrestrictedGetObject' if noSecurity: method = '_unrestrictedGetObject'
else: method = 'getObject' else: method = 'getObject'
exec 'obj = brain.%s().appy()' % method exec('obj = brain.%s().appy()' % method)
exec expression exec(expression)
return ctx return ctx
def reindex(self, fields=None, unindex=False): def reindex(self, fields=None, unindex=False):
@ -1249,7 +1249,7 @@ class AbstractWrapper(object):
else: else:
return xml return xml
elif format == 'csv': elif format == 'csv':
if isinstance(at, basestring): if isinstance(at, str):
marshaller = CsvMarshaller(include=include, exclude=exclude) marshaller = CsvMarshaller(include=include, exclude=exclude)
return marshaller.marshall(self) return marshaller.marshall(self)
else: else:

View file

@ -101,7 +101,7 @@ class BufferAction:
try: try:
res = self._evalExpr(expr, context) res = self._evalExpr(expr, context)
error = False error = False
except Exception, e: except Exception as e:
res = None res = None
errorMessage = EVAL_ERROR % (expr, self.getExceptionLine(e)) errorMessage = EVAL_ERROR % (expr, self.getExceptionLine(e))
self.manageError(result, context, errorMessage) self.manageError(result, context, errorMessage)
@ -134,7 +134,7 @@ class BufferAction:
error = False error = False
try: try:
feRes = eval(self.fromExpr, context) feRes = eval(self.fromExpr, context)
except Exception, e: except Exception as e:
msg = FROM_EVAL_ERROR% (self.fromExpr, self.getExceptionLine(e)) msg = FROM_EVAL_ERROR% (self.fromExpr, self.getExceptionLine(e))
self.manageError(result, context, msg) self.manageError(result, context, msg)
error = True error = True
@ -240,7 +240,7 @@ class ForAction(BufferAction):
return return
# Remember variable hidden by iter if any # Remember variable hidden by iter if any
hasHiddenVariable = False hasHiddenVariable = False
if context.has_key(self.iter): if self.iter in context:
hiddenVariable = context[self.iter] hiddenVariable = context[self.iter]
hasHiddenVariable = True hasHiddenVariable = True
# In the case of cells, initialize some values # In the case of cells, initialize some values

View file

@ -80,15 +80,15 @@ NULL_ACTION_ERROR = 'There was a problem with this action. Possible causes: ' \
class BufferIterator: class BufferIterator:
def __init__(self, buffer): def __init__(self, buffer):
self.buffer = buffer self.buffer = buffer
self.remainingSubBufferIndexes = self.buffer.subBuffers.keys() self.remainingSubBufferIndexes = list(self.buffer.subBuffers.keys())
self.remainingElemIndexes = self.buffer.elements.keys() self.remainingElemIndexes = list(self.buffer.elements.keys())
self.remainingSubBufferIndexes.sort() self.remainingSubBufferIndexes.sort()
self.remainingElemIndexes.sort() self.remainingElemIndexes.sort()
def hasNext(self): def hasNext(self):
return self.remainingSubBufferIndexes or self.remainingElemIndexes return self.remainingSubBufferIndexes or self.remainingElemIndexes
def next(self): def __next__(self):
nextSubBufferIndex = None nextSubBufferIndex = None
if self.remainingSubBufferIndexes: if self.remainingSubBufferIndexes:
nextSubBufferIndex = self.remainingSubBufferIndexes[0] nextSubBufferIndex = self.remainingSubBufferIndexes[0]
@ -131,7 +131,7 @@ class Buffer:
return subBuffer return subBuffer
def removeLastSubBuffer(self): def removeLastSubBuffer(self):
subBufferIndexes = self.subBuffers.keys() subBufferIndexes = list(self.subBuffers.keys())
subBufferIndexes.sort() subBufferIndexes.sort()
lastIndex = subBufferIndexes.pop() lastIndex = subBufferIndexes.pop()
del self.subBuffers[lastIndex] del self.subBuffers[lastIndex]
@ -176,7 +176,7 @@ class Buffer:
self.write('<%s' % elem) self.write('<%s' % elem)
# Some table elements must be patched (pod only) # Some table elements must be patched (pod only)
if self.pod: self.patchTableElement(elem, attrs) if self.pod: self.patchTableElement(elem, attrs)
for name, value in attrs.items(): for name, value in list(attrs.items()):
if ignoreAttrs and (name in ignoreAttrs): continue if ignoreAttrs and (name in ignoreAttrs): continue
if renamedAttrs and (name in renamedAttrs): name=renamedAttrs[name] if renamedAttrs and (name in renamedAttrs): name=renamedAttrs[name]
# If the value begins with ':', it is a Python expression. Else, # If the value begins with ':', it is a Python expression. Else,
@ -244,7 +244,7 @@ class FileBuffer(Buffer):
res, escape = expr.evaluate(self.env.context) res, escape = expr.evaluate(self.env.context)
if escape: self.dumpContent(res) if escape: self.dumpContent(res)
else: self.write(res) else: self.write(res)
except Exception, e: except Exception as e:
if not self.env.raiseOnError: if not self.env.raiseOnError:
PodError.dump(self, EVAL_EXPR_ERROR % (expression, e), PodError.dump(self, EVAL_EXPR_ERROR % (expression, e),
dumpTb=False) dumpTb=False)
@ -271,7 +271,7 @@ class MemoryBuffer(Buffer):
def __init__(self, env, parent): def __init__(self, env, parent):
Buffer.__init__(self, env, parent) Buffer.__init__(self, env, parent)
self.content = u'' self.content = ''
self.elements = {} self.elements = {}
self.action = None self.action = None
@ -297,7 +297,7 @@ class MemoryBuffer(Buffer):
def getIndex(self, podElemName): def getIndex(self, podElemName):
res = -1 res = -1
for index, podElem in self.elements.iteritems(): for index, podElem in self.elements.items():
if podElem.__class__.__name__.lower() == podElemName: if podElem.__class__.__name__.lower() == podElemName:
if index > res: if index > res:
res = index res = index
@ -305,7 +305,7 @@ class MemoryBuffer(Buffer):
def getMainElement(self): def getMainElement(self):
res = None res = None
if self.elements.has_key(0): if 0 in self.elements:
res = self.elements[0] res = self.elements[0]
return res return res
@ -317,7 +317,7 @@ class MemoryBuffer(Buffer):
if elem != mainElem: return if elem != mainElem: return
# elem is the same as the main elem. But is it really the main elem, or # elem is the same as the main elem. But is it really the main elem, or
# the same elem, found deeper in the buffer? # the same elem, found deeper in the buffer?
for index, iElem in self.elements.iteritems(): for index, iElem in self.elements.items():
foundElem = None foundElem = None
if hasattr(iElem, 'OD'): if hasattr(iElem, 'OD'):
if iElem.OD: if iElem.OD:
@ -331,7 +331,7 @@ class MemoryBuffer(Buffer):
def unreferenceElement(self, elem): def unreferenceElement(self, elem):
# Find last occurrence of this element # Find last occurrence of this element
elemIndex = -1 elemIndex = -1
for index, iElem in self.elements.iteritems(): for index, iElem in self.elements.items():
foundElem = None foundElem = None
if hasattr(iElem, 'OD'): if hasattr(iElem, 'OD'):
# A POD element # A POD element
@ -347,7 +347,7 @@ class MemoryBuffer(Buffer):
def pushSubBuffer(self, subBuffer): def pushSubBuffer(self, subBuffer):
'''Sets p_subBuffer at the very end of the buffer.''' '''Sets p_subBuffer at the very end of the buffer.'''
subIndex = None subIndex = None
for index, aSubBuffer in self.subBuffers.iteritems(): for index, aSubBuffer in self.subBuffers.items():
if aSubBuffer == subBuffer: if aSubBuffer == subBuffer:
subIndex = index subIndex = index
break break
@ -356,7 +356,7 @@ class MemoryBuffer(Buffer):
# in the parent (if it is a temp buffer generated from a cut) # in the parent (if it is a temp buffer generated from a cut)
del self.subBuffers[subIndex] del self.subBuffers[subIndex]
self.subBuffers[self.getLength()] = subBuffer self.subBuffers[self.getLength()] = subBuffer
self.content += u' ' self.content += ' '
def transferAllContent(self): def transferAllContent(self):
'''Transfer all content to parent.''' '''Transfer all content to parent.'''
@ -370,10 +370,10 @@ class MemoryBuffer(Buffer):
oldParentLength = self.parent.getLength() oldParentLength = self.parent.getLength()
self.parent.write(self.content) self.parent.write(self.content)
# Transfer elements # Transfer elements
for index, podElem in self.elements.iteritems(): for index, podElem in self.elements.items():
self.parent.elements[oldParentLength + index] = podElem self.parent.elements[oldParentLength + index] = podElem
# Transfer sub-buffers # Transfer sub-buffers
for index, buf in self.subBuffers.iteritems(): for index, buf in self.subBuffers.items():
self.parent.subBuffers[oldParentLength + index] = buf self.parent.subBuffers[oldParentLength + index] = buf
# Empty the buffer # Empty the buffer
MemoryBuffer.__init__(self, self.env, self.parent) MemoryBuffer.__init__(self, self.env, self.parent)
@ -391,7 +391,7 @@ class MemoryBuffer(Buffer):
elem.colIndex = elem.tableInfo.curColIndex elem.colIndex = elem.tableInfo.curColIndex
if elem == 'x': if elem == 'x':
# See comment on similar statement in the method below. # See comment on similar statement in the method below.
self.content += u' ' self.content += ' '
def addExpression(self, expression, tiedHook=None): def addExpression(self, expression, tiedHook=None):
# Create the POD expression # Create the POD expression
@ -400,20 +400,20 @@ class MemoryBuffer(Buffer):
self.elements[self.getLength()] = expr self.elements[self.getLength()] = expr
# To be sure that an expr and an elem can't be found at the same index # To be sure that an expr and an elem can't be found at the same index
# in the buffer. # in the buffer.
self.content += u' ' self.content += ' '
def addAttributes(self): def addAttributes(self):
'''pod-only: adds an Attributes instance into this buffer.''' '''pod-only: adds an Attributes instance into this buffer.'''
attrs = Attributes(self.env) attrs = Attributes(self.env)
self.elements[self.getLength()] = attrs self.elements[self.getLength()] = attrs
self.content += u' ' self.content += ' '
return attrs return attrs
def addAttribute(self, name, expr): def addAttribute(self, name, expr):
'''px-only: adds an Attribute instance into this buffer.''' '''px-only: adds an Attribute instance into this buffer.'''
attr = Attribute(name, expr) attr = Attribute(name, expr)
self.elements[self.getLength()] = attr self.elements[self.getLength()] = attr
self.content += u' ' self.content += ' '
return attr return attr
def _getVariables(self, expr): def _getVariables(self, expr):
@ -453,7 +453,7 @@ class MemoryBuffer(Buffer):
raise ParsingError( raise ParsingError(
ELEMENT_NOT_FOUND % (podElem, str([ ELEMENT_NOT_FOUND % (podElem, str([
e.__class__.__name__.lower() \ e.__class__.__name__.lower() \
for e in self.elements.values()]))) for e in list(self.elements.values())])))
podElem = self.elements[indexPodElem] podElem = self.elements[indexPodElem]
# Check the 'from' clause # Check the 'from' clause
fromClause = None fromClause = None
@ -471,7 +471,7 @@ class MemoryBuffer(Buffer):
self.env.ifActions.append(self.action) self.env.ifActions.append(self.action)
if self.action.name: if self.action.name:
# We must register this action as a named action # We must register this action as a named action
if self.env.namedIfActions.has_key(self.action.name): if self.action.name in self.env.namedIfActions:
raise ParsingError(DUPLICATE_NAMED_IF) raise ParsingError(DUPLICATE_NAMED_IF)
self.env.namedIfActions[self.action.name] = self.action self.env.namedIfActions[self.action.name] = self.action
elif actionType == 'else': elif actionType == 'else':
@ -480,7 +480,7 @@ class MemoryBuffer(Buffer):
# Does the "else" action reference a named "if" action? # Does the "else" action reference a named "if" action?
ifReference = subExpr.strip() ifReference = subExpr.strip()
if ifReference: if ifReference:
if not self.env.namedIfActions.has_key(ifReference): if ifReference not in self.env.namedIfActions:
raise ParsingError(ELSE_WITHOUT_NAMED_IF % ifReference) raise ParsingError(ELSE_WITHOUT_NAMED_IF % ifReference)
linkedIfAction = self.env.namedIfActions[ifReference] linkedIfAction = self.env.namedIfActions[ifReference]
# This "else" action "consumes" the "if" action: this way, # This "else" action "consumes" the "if" action: this way,
@ -510,7 +510,7 @@ class MemoryBuffer(Buffer):
self.action = NullAction(statementName, self, None, podElem, self.action = NullAction(statementName, self, None, podElem,
None, source, fromClause) None, source, fromClause)
res = indexPodElem res = indexPodElem
except ParsingError, ppe: except ParsingError as ppe:
PodError.dump(self, ppe, removeFirstLine=True) PodError.dump(self, ppe, removeFirstLine=True)
return res return res
@ -552,7 +552,7 @@ class MemoryBuffer(Buffer):
elementsToDelete = [] elementsToDelete = []
mustShift = False mustShift = False
while iter.hasNext(): while iter.hasNext():
itemIndex, item = iter.next() itemIndex, item = next(iter)
if keepFirstPart: if keepFirstPart:
if itemIndex >= index: if itemIndex >= index:
newIndex = itemIndex-index newIndex = itemIndex-index
@ -580,11 +580,11 @@ class MemoryBuffer(Buffer):
del self.subBuffers[subIndex] del self.subBuffers[subIndex]
if mustShift: if mustShift:
elements = {} elements = {}
for elemIndex, elem in self.elements.iteritems(): for elemIndex, elem in self.elements.items():
elements[elemIndex-index] = elem elements[elemIndex-index] = elem
self.elements = elements self.elements = elements
subBuffers = {} subBuffers = {}
for subIndex, buf in self.subBuffers.iteritems(): for subIndex, buf in self.subBuffers.items():
subBuffers[subIndex-index] = buf subBuffers[subIndex-index] = buf
self.subBuffers = subBuffers self.subBuffers = subBuffers
# Manage content # Manage content
@ -598,7 +598,7 @@ class MemoryBuffer(Buffer):
def getElementIndexes(self, expressions=True): def getElementIndexes(self, expressions=True):
res = [] res = []
for index, elem in self.elements.iteritems(): for index, elem in self.elements.items():
condition = isinstance(elem, Expression) or \ condition = isinstance(elem, Expression) or \
isinstance(elem, Attributes) isinstance(elem, Attributes)
if not expressions: if not expressions:
@ -696,7 +696,7 @@ class MemoryBuffer(Buffer):
iter = BufferIterator(self) iter = BufferIterator(self)
currentIndex = self.getStartIndex(removeMainElems) currentIndex = self.getStartIndex(removeMainElems)
while iter.hasNext(): while iter.hasNext():
index, evalEntry = iter.next() index, evalEntry = next(iter)
result.write(self.content[currentIndex:index]) result.write(self.content[currentIndex:index])
currentIndex = index + 1 currentIndex = index + 1
if isinstance(evalEntry, Expression): if isinstance(evalEntry, Expression):
@ -708,7 +708,7 @@ class MemoryBuffer(Buffer):
# This exception has already been treated (see the # This exception has already been treated (see the
# "except" block below). Simply re-raise it when needed. # "except" block below). Simply re-raise it when needed.
if self.env.raiseOnError: raise e if self.env.raiseOnError: raise e
except Exception, e: except Exception as e:
if not self.env.raiseOnError: if not self.env.raiseOnError:
PodError.dump(result, EVAL_EXPR_ERROR % ( PodError.dump(result, EVAL_EXPR_ERROR % (
evalEntry.expr, e)) evalEntry.expr, e))
@ -729,5 +729,5 @@ class MemoryBuffer(Buffer):
def clean(self): def clean(self):
'''Cleans the buffer content.''' '''Cleans the buffer content.'''
self.content = u'' self.content = ''
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -109,7 +109,7 @@ class Converter:
res = res[self.inputType] res = res[self.inputType]
else: else:
raise ConverterError(BAD_RESULT_TYPE % (self.resultType, raise ConverterError(BAD_RESULT_TYPE % (self.resultType,
FILE_TYPES.keys())) list(FILE_TYPES.keys())))
return res return res
def getResultUrl(self): def getResultUrl(self):
@ -275,7 +275,7 @@ class ConverterScript:
' %s.\n' \ ' %s.\n' \
' "python" should be a UNO-enabled Python interpreter (ie the ' \ ' "python" should be a UNO-enabled Python interpreter (ie the ' \
' one which is included in the LibreOffice distribution).' % \ ' one which is included in the LibreOffice distribution).' % \
str(FILE_TYPES.keys()) str(list(FILE_TYPES.keys()))
def run(self): def run(self):
optParser = OptionParser(usage=ConverterScript.usage) optParser = OptionParser(usage=ConverterScript.usage)
optParser.add_option("-p", "--port", dest="port", optParser.add_option("-p", "--port", dest="port",

View file

@ -17,7 +17,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import os, os.path, time, shutil, struct, random, urlparse import os, os.path, time, shutil, struct, random, urllib.parse
from appy.pod import PodError from appy.pod import PodError
from appy.pod.odf_parser import OdfEnvironment from appy.pod.odf_parser import OdfEnvironment
from appy.shared import mimeTypesExts from appy.shared import mimeTypesExts
@ -53,7 +53,7 @@ class DocImporter:
if at and not at.startswith('http') and not os.path.isfile(at): if at and not at.startswith('http') and not os.path.isfile(at):
raise PodError(FILE_NOT_FOUND % at) raise PodError(FILE_NOT_FOUND % at)
self.format = format self.format = format
self.res = u'' self.res = ''
self.renderer = renderer self.renderer = renderer
self.ns = renderer.currentParser.env.namespaces self.ns = renderer.currentParser.env.namespaces
# Unpack some useful namespaces # Unpack some useful namespaces
@ -285,7 +285,7 @@ class ImageImporter(DocImporter):
def moveFile(self, at, importPath): def moveFile(self, at, importPath):
'''Copies file at p_at into the ODT file at p_importPath.''' '''Copies file at p_at into the ODT file at p_importPath.'''
# Has this image already been imported ? # Has this image already been imported ?
for imagePath, imageAt in self.fileNames.iteritems(): for imagePath, imageAt in self.fileNames.items():
if imageAt == at: if imageAt == at:
# Yes! # Yes!
i = importPath.rfind(self.pictFolder) + 1 i = importPath.rfind(self.pictFolder) + 1
@ -327,7 +327,7 @@ class ImageImporter(DocImporter):
# The imageResolver is a Zope application. From it, we will # The imageResolver is a Zope application. From it, we will
# retrieve the object on which the image is stored and get # retrieve the object on which the image is stored and get
# the file to download. # the file to download.
urlParts = urlparse.urlsplit(at) urlParts = urllib.parse.urlsplit(at)
path = urlParts[2][1:].split('/')[:-1] path = urlParts[2][1:].split('/')[:-1]
try: try:
obj = imageResolver.unrestrictedTraverse(path) obj = imageResolver.unrestrictedTraverse(path)

View file

@ -148,7 +148,7 @@ class Expression(PodElement):
# pod/px result. # pod/px result.
resultType = res.__class__.__name__ resultType = res.__class__.__name__
if resultType == 'NoneType': if resultType == 'NoneType':
res = u'' res = ''
elif resultType == 'str': elif resultType == 'str':
res = res.decode('utf-8') res = res.decode('utf-8')
elif resultType == 'unicode': elif resultType == 'unicode':
@ -160,7 +160,7 @@ class Expression(PodElement):
# Force escapeXml to False. # Force escapeXml to False.
escapeXml = False escapeXml = False
else: else:
res = unicode(res) res = str(res)
return res, escapeXml return res, escapeXml
class Attributes(PodElement): class Attributes(PodElement):
@ -199,7 +199,7 @@ class Attributes(PodElement):
try: try:
self.tiedExpression.evaluate(context) self.tiedExpression.evaluate(context)
self.tiedExpression.evaluated = True self.tiedExpression.evaluated = True
except Exception, e: except Exception as e:
# Don't set "evaluated" to True. This way, when the buffer will # Don't set "evaluated" to True. This way, when the buffer will
# evaluate the expression directly, we will really evaluate it, so # evaluate the expression directly, we will really evaluate it, so
# the error will be dumped into the pod result. # the error will be dumped into the pod result.
@ -208,7 +208,7 @@ class Attributes(PodElement):
self.computeAttributes(self.tiedExpression) self.computeAttributes(self.tiedExpression)
# Now, self.attrs has been populated. Transform it into a string. # Now, self.attrs has been populated. Transform it into a string.
res = '' res = ''
for name, value in self.attrs.iteritems(): for name, value in self.attrs.items():
res += ' %s=%s' % (name, quoteattr(value)) res += ' %s=%s' % (name, quoteattr(value))
return res return res

View file

@ -50,7 +50,7 @@ class OdInsert:
def resolve(self, namespaces): def resolve(self, namespaces):
'''Replaces all unresolved namespaces in p_odtChunk, thanks to the dict '''Replaces all unresolved namespaces in p_odtChunk, thanks to the dict
of p_namespaces.''' of p_namespaces.'''
for nsName, nsUri in self.nsUris.iteritems(): for nsName, nsUri in self.nsUris.items():
self.odtChunk = re.sub('@%s@' % nsName, namespaces[nsUri], self.odtChunk = re.sub('@%s@' % nsName, namespaces[nsUri],
self.odtChunk) self.odtChunk)
return self.odtChunk return self.odtChunk
@ -126,14 +126,14 @@ class PodEnvironment(OdfEnvironment):
res = {} res = {}
for insert in self.inserts: for insert in self.inserts:
elemName = insert.elem.getFullName(self.namespaces) elemName = insert.elem.getFullName(self.namespaces)
if not res.has_key(elemName): if elemName not in res:
res[elemName] = insert res[elemName] = insert
return res return res
def manageInserts(self): def manageInserts(self):
'''We just dumped the start of an elem. Here we will insert any odt '''We just dumped the start of an elem. Here we will insert any odt
chunk if needed.''' chunk if needed.'''
if self.inserts.has_key(self.currentElem.elem): if self.currentElem.elem in self.inserts:
insert = self.inserts[self.currentElem.elem] insert = self.inserts[self.currentElem.elem]
self.currentBuffer.write(insert.resolve(self.namespaces)) self.currentBuffer.write(insert.resolve(self.namespaces))
# The insert is destroyed after single use # The insert is destroyed after single use
@ -160,12 +160,12 @@ class PodEnvironment(OdfEnvironment):
elif elem == Cell.OD.elem: elif elem == Cell.OD.elem:
colspan = 1 colspan = 1
attrSpan = self.tags['number-columns-spanned'] attrSpan = self.tags['number-columns-spanned']
if self.currentElem.attrs.has_key(attrSpan): if attrSpan in self.currentElem.attrs:
colspan = int(self.currentElem.attrs[attrSpan]) colspan = int(self.currentElem.attrs[attrSpan])
self.getTable().curColIndex += colspan self.getTable().curColIndex += colspan
elif elem == self.tags['table-column']: elif elem == self.tags['table-column']:
attrs = self.currentElem.attrs attrs = self.currentElem.attrs
if attrs.has_key(self.tags['number-columns-repeated']): if self.tags['number-columns-repeated'] in attrs:
self.getTable().nbOfColumns += int( self.getTable().nbOfColumns += int(
attrs[self.tags['number-columns-repeated']]) attrs[self.tags['number-columns-repeated']])
else: else:
@ -254,8 +254,8 @@ class PodParser(OdfParser):
e.state = e.READING_EXPRESSION e.state = e.READING_EXPRESSION
e.exprHasStyle = False e.exprHasStyle = False
elif (elem == e.tags['table-cell']) and \ elif (elem == e.tags['table-cell']) and \
attrs.has_key(e.tags['formula']) and \ e.tags['formula'] in attrs and \
attrs.has_key(e.tags['value-type']) and \ e.tags['value-type'] in attrs and \
(attrs[e.tags['value-type']] == 'string') and \ (attrs[e.tags['value-type']] == 'string') and \
attrs[e.tags['formula']].startswith('of:="'): attrs[e.tags['formula']].startswith('of:="'):
# In an ODS template, any cell containing a formula of type "string" # In an ODS template, any cell containing a formula of type "string"

View file

@ -18,7 +18,11 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import zipfile, shutil, xml.sax, os, os.path, re, mimetypes, time import zipfile, shutil, xml.sax, os, os.path, re, mimetypes, time
from UserDict import UserDict #python3 compat
try:
from UserDict import UserDict
except ImportError:
from collections import UserDict
import appy.pod import appy.pod
from appy.pod import PodError from appy.pod import PodError
from appy.shared import mimeTypes, mimeTypesExts from appy.shared import mimeTypes, mimeTypesExts
@ -80,7 +84,7 @@ CONTENT_POD_FONTS = '<@style@:font-face @style@:name="PodStarSymbol" ' \
'@svg@:font-family="StarSymbol"/>' '@svg@:font-family="StarSymbol"/>'
# Default text styles added by pod in styles.xml # Default text styles added by pod in styles.xml
f = file('%s/styles.in.styles.xml' % os.path.dirname(appy.pod.__file__)) f = open('%s/styles.in.styles.xml' % os.path.dirname(appy.pod.__file__))
STYLES_POD_STYLES = f.read() STYLES_POD_STYLES = f.read()
f.close() f.close()
@ -263,7 +267,7 @@ class Renderer:
imageFormats = ('png', 'jpeg', 'jpg', 'gif', 'svg') imageFormats = ('png', 'jpeg', 'jpg', 'gif', 'svg')
ooFormats = ('odt',) ooFormats = ('odt',)
convertibleFormats = FILE_TYPES.keys() convertibleFormats = list(FILE_TYPES.keys())
def importDocument(self, content=None, at=None, format=None, def importDocument(self, content=None, at=None, format=None,
anchor='as-char', wrapInPara=True, size=None, anchor='as-char', wrapInPara=True, size=None,
sizeUnit='cm', style=None, sizeUnit='cm', style=None,
@ -309,7 +313,7 @@ class Renderer:
format = os.path.splitext(at)[1][1:] format = os.path.splitext(at)[1][1:]
else: else:
# If format is a mimeType, convert it to an extension # If format is a mimeType, convert it to an extension
if mimeTypesExts.has_key(format): if format in mimeTypesExts:
format = mimeTypesExts[format] format = mimeTypesExts[format]
isImage = False isImage = False
isOdt = False isOdt = False
@ -370,9 +374,9 @@ class Renderer:
f = open(self.result, 'w') f = open(self.result, 'w')
f.write('Hello') f.write('Hello')
f.close() f.close()
except OSError, oe: except OSError as oe:
raise PodError(CANT_WRITE_RESULT % (self.result, oe)) raise PodError(CANT_WRITE_RESULT % (self.result, oe))
except IOError, ie: except IOError as ie:
raise PodError(CANT_WRITE_RESULT % (self.result, ie)) raise PodError(CANT_WRITE_RESULT % (self.result, ie))
self.result = os.path.abspath(self.result) self.result = os.path.abspath(self.result)
os.remove(self.result) os.remove(self.result)
@ -381,7 +385,7 @@ class Renderer:
self.tempFolder = '%s.%f' % (absResult, time.time()) self.tempFolder = '%s.%f' % (absResult, time.time())
try: try:
os.mkdir(self.tempFolder) os.mkdir(self.tempFolder)
except OSError, oe: except OSError as oe:
raise PodError(CANT_WRITE_TEMP_FOLDER % (self.result, oe)) raise PodError(CANT_WRITE_TEMP_FOLDER % (self.result, oe))
def patchManifest(self): def patchManifest(self):
@ -390,7 +394,7 @@ class Renderer:
if self.fileNames: if self.fileNames:
j = os.path.join j = os.path.join
toInsert = '' toInsert = ''
for fileName in self.fileNames.iterkeys(): for fileName in self.fileNames.keys():
if fileName.endswith('.svg'): if fileName.endswith('.svg'):
fileName = os.path.splitext(fileName)[0] + '.png' fileName = os.path.splitext(fileName)[0] + '.png'
mimeType = mimetypes.guess_type(fileName)[0] mimeType = mimetypes.guess_type(fileName)[0]
@ -442,7 +446,7 @@ class Renderer:
if 'span[font-style=italic]' not in stylesMapping: if 'span[font-style=italic]' not in stylesMapping:
stylesMapping['span[font-style=italic]'] = 'podItalic' stylesMapping['span[font-style=italic]'] = 'podItalic'
self.stylesManager.stylesMapping = stylesMapping self.stylesManager.stylesMapping = stylesMapping
except PodError, po: except PodError as po:
self.contentParser.env.currentBuffer.content.close() self.contentParser.env.currentBuffer.content.close()
self.stylesParser.env.currentBuffer.content.close() self.stylesParser.env.currentBuffer.content.close()
if os.path.exists(self.tempFolder): if os.path.exists(self.tempFolder):
@ -454,14 +458,14 @@ class Renderer:
loOutput = '' loOutput = ''
try: try:
if (not isinstance(self.ooPort, int)) and \ if (not isinstance(self.ooPort, int)) and \
(not isinstance(self.ooPort, long)): (not isinstance(self.ooPort, int)):
raise PodError(BAD_OO_PORT % str(self.ooPort)) raise PodError(BAD_OO_PORT % str(self.ooPort))
try: try:
from appy.pod.converter import Converter, ConverterError from appy.pod.converter import Converter, ConverterError
try: try:
Converter(resultName, resultType, self.ooPort, Converter(resultName, resultType, self.ooPort,
self.stylesTemplate).run() self.stylesTemplate).run()
except ConverterError, ce: except ConverterError as ce:
raise PodError(CONVERT_ERROR % str(ce)) raise PodError(CONVERT_ERROR % str(ce))
except ImportError: except ImportError:
# I do not have UNO. So try to launch a UNO-enabled Python # I do not have UNO. So try to launch a UNO-enabled Python
@ -485,13 +489,13 @@ class Renderer:
self.ooPort) self.ooPort)
if self.stylesTemplate: cmd += ' -t%s' % self.stylesTemplate if self.stylesTemplate: cmd += ' -t%s' % self.stylesTemplate
loOutput = executeCommand(cmd) loOutput = executeCommand(cmd)
except PodError, pe: except PodError as pe:
# When trying to call LO in server mode for producing ODT or ODS # When trying to call LO in server mode for producing ODT or ODS
# (=forceOoCall=True), if an error occurs we have nevertheless # (=forceOoCall=True), if an error occurs we have nevertheless
# an ODT or ODS to return to the user. So we produce a warning # an ODT or ODS to return to the user. So we produce a warning
# instead of raising an error. # instead of raising an error.
if (resultType in self.templateTypes) and self.forceOoCall: if (resultType in self.templateTypes) and self.forceOoCall:
print(WARNING_INCOMPLETE_OD % str(pe)) print((WARNING_INCOMPLETE_OD % str(pe)))
else: else:
raise pe raise pe
return loOutput return loOutput
@ -501,7 +505,7 @@ class Renderer:
(ods or odt). If self.template is a string, it is a file name and we (ods or odt). If self.template is a string, it is a file name and we
simply get its extension. Else, it is a binary file in a StringIO simply get its extension. Else, it is a binary file in a StringIO
instance, and we seek the mime type from the first bytes.''' instance, and we seek the mime type from the first bytes.'''
if isinstance(self.template, basestring): if isinstance(self.template, str):
res = os.path.splitext(self.template)[1][1:] res = os.path.splitext(self.template)[1][1:]
else: else:
# A StringIO instance # A StringIO instance
@ -534,8 +538,8 @@ class Renderer:
if self.finalizeFunction: if self.finalizeFunction:
try: try:
self.finalizeFunction(self.unzipFolder) self.finalizeFunction(self.unzipFolder)
except Exception, e: except Exception as e:
print(WARNING_FINALIZE_ERROR % str(e)) print((WARNING_FINALIZE_ERROR % str(e)))
# Re-zip the result, first as an OpenDocument file of the same type as # Re-zip the result, first as an OpenDocument file of the same type as
# the POD template (odt, ods...) # the POD template (odt, ods...)
resultExt = self.getTemplateType() resultExt = self.getTemplateType()

View file

@ -18,7 +18,12 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import re, os.path import re, os.path
from UserDict import UserDict #python3 compat
try:
from UserDict import UserDict
except ImportError:
from collections import UserDict
import appy.pod import appy.pod
from appy.pod import * from appy.pod import *
from appy.pod.odf_parser import OdfEnvironment, OdfParser from appy.pod.odf_parser import OdfEnvironment, OdfParser
@ -93,7 +98,7 @@ class Styles(UserDict):
'''Tries to find a style which has level p_level. Returns None if no '''Tries to find a style which has level p_level. Returns None if no
such style exists.''' such style exists.'''
res = None res = None
for style in self.itervalues(): for style in self.values():
if (style.family == 'paragraph') and (style.outlineLevel == level): if (style.family == 'paragraph') and (style.outlineLevel == level):
res = style res = style
break break
@ -102,7 +107,7 @@ class Styles(UserDict):
'''Gets the style that has this p_displayName. Returns None if not '''Gets the style that has this p_displayName. Returns None if not
found.''' found.'''
res = None res = None
for style in self.itervalues(): for style in self.values():
if style.displayName == displayName: if style.displayName == displayName:
res = style res = style
break break
@ -111,9 +116,9 @@ class Styles(UserDict):
'''Returns a list of all the styles of the given p_stylesType.''' '''Returns a list of all the styles of the given p_stylesType.'''
res = [] res = []
if stylesType == 'all': if stylesType == 'all':
res = self.values() res = list(self.values())
else: else:
for style in self.itervalues(): for style in self.values():
if (style.family == stylesType) and style.displayName: if (style.family == stylesType) and style.displayName:
res.append(style) res.append(style)
return res return res
@ -145,22 +150,22 @@ class StylesParser(OdfParser):
displayNameAttr = '%s:display-name' % e.ns(e.NS_STYLE) displayNameAttr = '%s:display-name' % e.ns(e.NS_STYLE)
# Create the style # Create the style
style = Style(name=attrs[nameAttr], family=attrs[familyAttr]) style = Style(name=attrs[nameAttr], family=attrs[familyAttr])
if attrs.has_key(classAttr): if classAttr in attrs:
style.styleClass = attrs[classAttr] style.styleClass = attrs[classAttr]
if attrs.has_key(displayNameAttr): if displayNameAttr in attrs:
style.displayName = attrs[displayNameAttr] style.displayName = attrs[displayNameAttr]
# Record this style in the environment # Record this style in the environment
e.styles[style.name] = style e.styles[style.name] = style
e.currentStyle = style e.currentStyle = style
levelKey = '%s:default-outline-level' % e.ns(e.NS_STYLE) levelKey = '%s:default-outline-level' % e.ns(e.NS_STYLE)
if attrs.has_key(levelKey) and attrs[levelKey].strip(): if levelKey in attrs and attrs[levelKey].strip():
style.outlineLevel = int(attrs[levelKey]) style.outlineLevel = int(attrs[levelKey])
else: else:
if e.state == PARSING_STYLE: if e.state == PARSING_STYLE:
# I am parsing tags within the style. # I am parsing tags within the style.
if elem == ('%s:text-properties' % e.ns(e.NS_STYLE)): if elem == ('%s:text-properties' % e.ns(e.NS_STYLE)):
fontSizeKey = '%s:font-size' % e.ns(e.NS_FO) fontSizeKey = '%s:font-size' % e.ns(e.NS_FO)
if attrs.has_key(fontSizeKey): if fontSizeKey in attrs:
e.currentStyle.setFontSize(attrs[fontSizeKey]) e.currentStyle.setFontSize(attrs[fontSizeKey])
def endElement(self, elem): def endElement(self, elem):
e = OdfParser.endElement(self, elem) e = OdfParser.endElement(self, elem)
@ -250,14 +255,14 @@ class StylesManager:
if not isinstance(stylesMapping, dict) and \ if not isinstance(stylesMapping, dict) and \
not isinstance(stylesMapping, UserDict): not isinstance(stylesMapping, UserDict):
raise PodError(MAPPING_NOT_DICT) raise PodError(MAPPING_NOT_DICT)
for xhtmlStyleName, odtStyleName in stylesMapping.iteritems(): for xhtmlStyleName, odtStyleName in stylesMapping.items():
if not isinstance(xhtmlStyleName, basestring): if not isinstance(xhtmlStyleName, str):
raise PodError(MAPPING_ELEM_NOT_STRING) raise PodError(MAPPING_ELEM_NOT_STRING)
if (xhtmlStyleName == 'h*') and \ if (xhtmlStyleName == 'h*') and \
not isinstance(odtStyleName, int): not isinstance(odtStyleName, int):
raise PodError(MAPPING_OUTLINE_DELTA_NOT_INT) raise PodError(MAPPING_OUTLINE_DELTA_NOT_INT)
if (xhtmlStyleName != 'h*') and \ if (xhtmlStyleName != 'h*') and \
not isinstance(odtStyleName, basestring): not isinstance(odtStyleName, str):
raise PodError(MAPPING_ELEM_NOT_STRING) raise PodError(MAPPING_ELEM_NOT_STRING)
if (xhtmlStyleName != 'h*') and \ if (xhtmlStyleName != 'h*') and \
((not xhtmlStyleName) or (not odtStyleName)): ((not xhtmlStyleName) or (not odtStyleName)):
@ -278,7 +283,7 @@ class StylesManager:
if xhtmlStyleName != 'h*': if xhtmlStyleName != 'h*':
odtStyle = self.styles.getStyle(odtStyleName) odtStyle = self.styles.getStyle(odtStyleName)
if not odtStyle: if not odtStyle:
if self.podSpecificStyles.has_key(odtStyleName): if odtStyleName in self.podSpecificStyles:
odtStyle = self.podSpecificStyles[odtStyleName] odtStyle = self.podSpecificStyles[odtStyleName]
else: else:
raise PodError(STYLE_NOT_FOUND % odtStyleName) raise PodError(STYLE_NOT_FOUND % odtStyleName)
@ -311,7 +316,7 @@ class StylesManager:
This method returns True if p_attrs contains the winning (name,value) This method returns True if p_attrs contains the winning (name,value)
pairs that match those in p_matchingAttrs. Note that ALL attrs in pairs that match those in p_matchingAttrs. Note that ALL attrs in
p_matchingAttrs must be present in p_attrs.''' p_matchingAttrs must be present in p_attrs.'''
for name, value in matchingAttrs.iteritems(): for name, value in matchingAttrs.items():
if name not in attrs: return if name not in attrs: return
if value != attrs[name]: return if value != attrs[name]: return
return True return True
@ -356,29 +361,29 @@ class StylesManager:
''' '''
res = None res = None
cssStyleName = None cssStyleName = None
if attrs and attrs.has_key('class'): if attrs and 'class' in attrs:
cssStyleName = attrs['class'] cssStyleName = attrs['class']
if classValue: if classValue:
cssStyleName = classValue cssStyleName = classValue
# (1) # (1)
if localStylesMapping.has_key(cssStyleName): if cssStyleName in localStylesMapping:
res = localStylesMapping[cssStyleName] res = localStylesMapping[cssStyleName]
# (2) # (2)
if (not res) and localStylesMapping.has_key(elem): if (not res) and elem in localStylesMapping:
styles = localStylesMapping[elem] styles = localStylesMapping[elem]
res = self.getStyleFromMapping(elem, attrs, styles) res = self.getStyleFromMapping(elem, attrs, styles)
# (3) # (3)
if (not res) and self.stylesMapping.has_key(cssStyleName): if (not res) and cssStyleName in self.stylesMapping:
res = self.stylesMapping[cssStyleName] res = self.stylesMapping[cssStyleName]
# (4) # (4)
if (not res) and self.stylesMapping.has_key(elem): if (not res) and elem in self.stylesMapping:
styles = self.stylesMapping[elem] styles = self.stylesMapping[elem]
res = self.getStyleFromMapping(elem, attrs, styles) res = self.getStyleFromMapping(elem, attrs, styles)
# (5) # (5)
if (not res) and self.styles.has_key(cssStyleName): if (not res) and cssStyleName in self.styles:
res = self.styles[cssStyleName] res = self.styles[cssStyleName]
# (6) # (6)
if (not res) and self.podSpecificStyles.has_key(cssStyleName): if (not res) and cssStyleName in self.podSpecificStyles:
res = self.podSpecificStyles[cssStyleName] res = self.podSpecificStyles[cssStyleName]
# (7) # (7)
if not res: if not res:
@ -386,9 +391,9 @@ class StylesManager:
if elem in XHTML_HEADINGS: if elem in XHTML_HEADINGS:
# Is there a delta that must be taken into account ? # Is there a delta that must be taken into account ?
outlineDelta = 0 outlineDelta = 0
if localStylesMapping.has_key('h*'): if 'h*' in localStylesMapping:
outlineDelta += localStylesMapping['h*'] outlineDelta += localStylesMapping['h*']
elif self.stylesMapping.has_key('h*'): elif 'h*' in self.stylesMapping:
outlineDelta += self.stylesMapping['h*'] outlineDelta += self.stylesMapping['h*']
outlineLevel = int(elem[1]) + outlineDelta outlineLevel = int(elem[1]) + outlineDelta
# Normalize the outline level # Normalize the outline level

View file

@ -38,7 +38,7 @@ class AnnotationsRemover(OdfParser):
machine-specific info, like absolute paths to the python files, etc.''' machine-specific info, like absolute paths to the python files, etc.'''
def __init__(self, env, caller): def __init__(self, env, caller):
OdfParser.__init__(self, env, caller) OdfParser.__init__(self, env, caller)
self.res = u'' self.res = ''
self.inAnnotation = False # Are we parsing an annotation ? self.inAnnotation = False # Are we parsing an annotation ?
self.textEncountered = False # Within an annotation, have we already self.textEncountered = False # Within an annotation, have we already
# met a text ? # met a text ?
@ -58,7 +58,7 @@ class AnnotationsRemover(OdfParser):
self.ignore = True self.ignore = True
if not self.ignore: if not self.ignore:
self.res += '<%s' % elem self.res += '<%s' % elem
for attrName, attrValue in attrs.items(): for attrName, attrValue in list(attrs.items()):
self.res += ' %s="%s"' % (attrName, attrValue) self.res += ' %s="%s"' % (attrName, attrValue)
self.res += '>' self.res += '>'
def endElement(self, elem): def endElement(self, elem):
@ -93,12 +93,12 @@ class Test(appy.shared.test.Test):
if not os.path.exists(contextPy): if not os.path.exists(contextPy):
raise TesterError(CONTEXT_NOT_FOUND % contextPy) raise TesterError(CONTEXT_NOT_FOUND % contextPy)
contextPkg = 'appy.pod.test.contexts.%s' % contextName contextPkg = 'appy.pod.test.contexts.%s' % contextName
exec 'import %s' % contextPkg exec('import %s' % contextPkg)
exec 'context = dir(%s)' % contextPkg exec('context = dir(%s)' % contextPkg)
res = {} res = {}
for elem in context: for elem in context:
if not elem.startswith('__'): if not elem.startswith('__'):
exec 'res[elem] = %s.%s' % (contextPkg, elem) exec('res[elem] = %s.%s' % (contextPkg, elem))
return res return res
def do(self): def do(self):

View file

@ -1,6 +1,6 @@
class Student: class Student:
def __init__(self, **kwargs): def __init__(self, **kwargs):
for k, v in kwargs.iteritems(): for k, v in kwargs.items():
setattr(self, k, v) setattr(self, k, v)
students = [ students = [

View file

@ -47,7 +47,7 @@ class HtmlElement:
# but for a strange reason those attrs are back to None (probably for # but for a strange reason those attrs are back to None (probably for
# performance reasons they become inaccessible after a while). # performance reasons they become inaccessible after a while).
self.classAttr = None self.classAttr = None
if attrs.has_key('class'): if 'class' in attrs:
self.classAttr = attrs['class'] self.classAttr = attrs['class']
self.tagsToReopen = [] # When the HTML element corresponding to self self.tagsToReopen = [] # When the HTML element corresponding to self
# is completely dumped, if there was a problem related to tags # is completely dumped, if there was a problem related to tags
@ -58,7 +58,7 @@ class HtmlElement:
# to self, we may need to close other tags (ie closing a paragraph # to self, we may need to close other tags (ie closing a paragraph
# before closing a cell). This list contains HtmlElement instances. # before closing a cell). This list contains HtmlElement instances.
self.elemType = self.elem self.elemType = self.elem
if self.elemTypes.has_key(self.elem): if self.elem in self.elemTypes:
self.elemType = self.elemTypes[self.elem] self.elemType = self.elemTypes[self.elem]
# If a conflict occurs on this element, we will note it. # If a conflict occurs on this element, we will note it.
self.isConflictual = False self.isConflictual = False
@ -71,7 +71,7 @@ class HtmlElement:
def getOdfTag(self, env): def getOdfTag(self, env):
'''Gets the raw ODF tag that corresponds to me''' '''Gets the raw ODF tag that corresponds to me'''
res = '' res = ''
if HTML_2_ODT.has_key(self.elem): if self.elem in HTML_2_ODT:
res += '%s:%s' % (env.textNs, HTML_2_ODT[self.elem]) res += '%s:%s' % (env.textNs, HTML_2_ODT[self.elem])
elif self.elem == 'a': elif self.elem == 'a':
res += '%s:a' % env.textNs res += '%s:a' % env.textNs
@ -216,8 +216,8 @@ class HtmlTable:
elems = str(time.time()).split('.') elems = str(time.time()).split('.')
self.name= 'AppyTable%s%s%d' % (elems[0],elems[1],random.randint(1,100)) self.name= 'AppyTable%s%s%d' % (elems[0],elems[1],random.randint(1,100))
self.styleNs = env.ns[OdfEnvironment.NS_STYLE] self.styleNs = env.ns[OdfEnvironment.NS_STYLE]
self.res = u'' # The sub-buffer self.res = '' # The sub-buffer
self.tempRes = u'' # The temporary sub-buffer, into which we will self.tempRes = '' # The temporary sub-buffer, into which we will
# dump all table sub-elements, until we encounter the end of the first # dump all table sub-elements, until we encounter the end of the first
# row. Then, we will know how much columns are defined in the table; # row. Then, we will know how much columns are defined in the table;
# we will dump columns declarations into self.res and dump self.tempRes # we will dump columns declarations into self.res and dump self.tempRes
@ -294,8 +294,8 @@ class XhtmlEnvironment(XmlEnvironment):
XmlEnvironment.__init__(self) XmlEnvironment.__init__(self)
self.renderer = renderer self.renderer = renderer
self.ns = renderer.currentParser.env.namespaces self.ns = renderer.currentParser.env.namespaces
self.res = u'' self.res = ''
self.currentContent = u'' self.currentContent = ''
self.currentElements = [] # Stack of currently walked elements self.currentElements = [] # Stack of currently walked elements
self.currentLists = [] # Stack of currently walked lists (ul or ol) self.currentLists = [] # Stack of currently walked lists (ul or ol)
self.currentTables = [] # Stack of currently walked tables self.currentTables = [] # Stack of currently walked tables
@ -349,7 +349,7 @@ class XhtmlEnvironment(XmlEnvironment):
# Dump and reinitialize the current content # Dump and reinitialize the current content
contentSize = len(self.currentContent) contentSize = len(self.currentContent)
self.dumpString(escapeXml(self.currentContent)) self.dumpString(escapeXml(self.currentContent))
self.currentContent = u'' self.currentContent = ''
# If we are within a table cell, update the total size of cell content # If we are within a table cell, update the total size of cell content
if not contentSize: return if not contentSize: return
if self.currentTables and self.currentTables[-1].inCell: if self.currentTables and self.currentTables[-1].inCell:
@ -363,7 +363,7 @@ class XhtmlEnvironment(XmlEnvironment):
styleName = None styleName = None
if odtStyle: if odtStyle:
styleName = odtStyle.name styleName = odtStyle.name
elif DEFAULT_ODT_STYLES.has_key(htmlElem.elem): elif htmlElem.elem in DEFAULT_ODT_STYLES:
styleName = DEFAULT_ODT_STYLES[htmlElem.elem] styleName = DEFAULT_ODT_STYLES[htmlElem.elem]
res = '' res = ''
if styleName: if styleName:
@ -458,7 +458,7 @@ class XhtmlEnvironment(XmlEnvironment):
elif elem in TABLE_CELL_TAGS: elif elem in TABLE_CELL_TAGS:
# Determine colspan # Determine colspan
colspan = 1 colspan = 1
if attrs.has_key('colspan'): colspan = int(attrs['colspan']) if 'colspan' in attrs: colspan = int(attrs['colspan'])
table = self.currentTables[-1] table = self.currentTables[-1]
table.inCell = colspan table.inCell = colspan
table.cellIndex += colspan table.cellIndex += colspan
@ -503,7 +503,7 @@ class XhtmlEnvironment(XmlEnvironment):
table.res+= '<%s:table-column %s:style-name="%s.%d"/>' % \ table.res+= '<%s:table-column %s:style-name="%s.%d"/>' % \
(self.tableNs, self.tableNs, table.name, i) (self.tableNs, self.tableNs, table.name, i)
table.res += table.tempRes table.res += table.tempRes
table.tempRes = u'' table.tempRes = ''
elif elem in TABLE_CELL_TAGS: elif elem in TABLE_CELL_TAGS:
# Update attr "columnContentSizes" of the currently parsed table, # Update attr "columnContentSizes" of the currently parsed table,
# excepted if the cell spans several columns. # excepted if the cell spans several columns.
@ -535,7 +535,7 @@ class XhtmlParser(XmlParser):
resAttrs = attrs resAttrs = attrs
if attrs: if attrs:
resAttrs = {} resAttrs = {}
for attrName in attrs.keys(): for attrName in list(attrs.keys()):
resAttrs[attrName.lower()] = attrs[attrName] resAttrs[attrName.lower()] = attrs[attrName]
if attrs == None: if attrs == None:
return resElem return resElem
@ -548,11 +548,11 @@ class XhtmlParser(XmlParser):
currentElem = e.onElementStart(elem, attrs) currentElem = e.onElementStart(elem, attrs)
odfTag = currentElem.getOdfTag(e) odfTag = currentElem.getOdfTag(e)
if HTML_2_ODT.has_key(elem): if elem in HTML_2_ODT:
e.dumpStyledElement(currentElem, odfTag, attrs) e.dumpStyledElement(currentElem, odfTag, attrs)
elif elem == 'a': elif elem == 'a':
e.dumpString('<%s %s:type="simple"' % (odfTag, e.linkNs)) e.dumpString('<%s %s:type="simple"' % (odfTag, e.linkNs))
if attrs.has_key('href'): if 'href' in attrs:
e.dumpString(' %s:href="%s"' % (e.linkNs, e.dumpString(' %s:href="%s"' % (e.linkNs,
escapeXml(attrs['href']))) escapeXml(attrs['href'])))
e.dumpString('>') e.dumpString('>')
@ -577,13 +577,13 @@ class XhtmlParser(XmlParser):
elif elem in TABLE_CELL_TAGS: elif elem in TABLE_CELL_TAGS:
e.dumpString('<%s %s:style-name="%s"' % \ e.dumpString('<%s %s:style-name="%s"' % \
(odfTag, e.tableNs, DEFAULT_ODT_STYLES[elem])) (odfTag, e.tableNs, DEFAULT_ODT_STYLES[elem]))
if attrs.has_key('colspan'): if 'colspan' in attrs:
e.dumpString(' %s:number-columns-spanned="%s"' % \ e.dumpString(' %s:number-columns-spanned="%s"' % \
(e.tableNs, attrs['colspan'])) (e.tableNs, attrs['colspan']))
e.dumpString('>') e.dumpString('>')
elif elem == 'img': elif elem == 'img':
style = None style = None
if attrs.has_key('style'): style = attrs['style'] if 'style' in attrs: style = attrs['style']
imgCode = e.renderer.importDocument(at=attrs['src'], imgCode = e.renderer.importDocument(at=attrs['src'],
wrapInPara=False, style=style) wrapInPara=False, style=style)
e.dumpString(imgCode) e.dumpString(imgCode)

View file

@ -4,7 +4,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import xml.sax import xml.sax
from px_parser import PxParser, PxEnvironment from .px_parser import PxParser, PxEnvironment
from appy.pod.buffers import MemoryBuffer from appy.pod.buffers import MemoryBuffer
from appy.shared.xml_parser import xmlPrologue, xhtmlPrologue from appy.shared.xml_parser import xmlPrologue, xhtmlPrologue
@ -18,7 +18,7 @@ class Px:
xhtmlPrologue = xhtmlPrologue xhtmlPrologue = xhtmlPrologue
def __init__(self, content, isFileName=False, partial=True, def __init__(self, content, isFileName=False, partial=True,
template=None, hook=None, prologue=None, unicode=True): template=None, hook=None, prologue=None, str=True):
'''p_content is the PX code, as a string, or a file name if p_isFileName '''p_content is the PX code, as a string, or a file name if p_isFileName
is True. If this code represents a complete XML file, p_partial is is True. If this code represents a complete XML file, p_partial is
False. Else, we must surround p_content with a root tag to be able False. Else, we must surround p_content with a root tag to be able
@ -49,7 +49,7 @@ class Px:
# Is there some (XML, XHTML...) prologue to dump? # Is there some (XML, XHTML...) prologue to dump?
self.prologue = prologue self.prologue = prologue
# Will the result be unicode or str? # Will the result be unicode or str?
self.unicode = unicode self.str = str
self.parse() self.parse()
def parse(self): def parse(self):
@ -64,7 +64,7 @@ class Px:
# produce a tree of memory buffers. # produce a tree of memory buffers.
try: try:
self.parser.parse(self.content) self.parser.parse(self.content)
except xml.sax.SAXParseException, spe: except xml.sax.SAXParseException as spe:
self.completeErrorMessage(spe) self.completeErrorMessage(spe)
raise spe raise spe
@ -110,7 +110,7 @@ class Px:
res = result.content res = result.content
if self.prologue: if self.prologue:
res = self.prologue + res res = self.prologue + res
if not self.unicode: if not self.str:
res = res.encode('utf-8') res = res.encode('utf-8')
return res return res

View file

@ -66,7 +66,7 @@ class PxParser(XmlParser):
# See if we have a PX attribute among p_attrs. # See if we have a PX attribute among p_attrs.
found = False found = False
for name in self.pxAttributes: for name in self.pxAttributes:
if attrs.has_key(name): if name in attrs:
if not found: if not found:
# This is the first PX attr we find. # This is the first PX attr we find.
# Create a sub-buffer with an action. # Create a sub-buffer with an action.
@ -87,7 +87,7 @@ class PxParser(XmlParser):
hook = None hook = None
ignorableAttrs = self.pxAttributes ignorableAttrs = self.pxAttributes
for name in self.noDumpTags: for name in self.noDumpTags:
if attrs.has_key(name) and attrs[name].startswith(':'): if name in attrs and attrs[name].startswith(':'):
hook = (name, attrs[name][1:]) hook = (name, attrs[name][1:])
ignorableAttrs += (name,) ignorableAttrs += (name,)
break break

View file

@ -50,12 +50,12 @@ class UnicodeBuffer:
self.buffer = [] self.buffer = []
def write(self, s): def write(self, s):
if s == None: return if s == None: return
if isinstance(s, unicode): if isinstance(s, str):
self.buffer.append(s) self.buffer.append(s)
elif isinstance(s, str): elif isinstance(s, str):
self.buffer.append(s.decode('utf-8')) self.buffer.append(s.decode('utf-8'))
else: else:
self.buffer.append(unicode(s)) self.buffer.append(str(s))
def getValue(self): def getValue(self):
return u''.join(self.buffer) return ''.join(self.buffer)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -109,18 +109,18 @@ class CsvParser:
def convertValue(self, value, basicType): def convertValue(self, value, basicType):
'''Converts the atomic p_value which is a string into some other atomic '''Converts the atomic p_value which is a string into some other atomic
Python type specified in p_basicType (int, float, ...).''' Python type specified in p_basicType (int, float, ...).'''
if (basicType != str) and (basicType != unicode): if (basicType != str) and (basicType != str):
try: try:
exec 'res = %s' % str(value) exec('res = %s' % str(value))
except SyntaxError, se: except SyntaxError as se:
res = None res = None
else: else:
try: try:
exec 'res = """%s"""' % str(value) exec('res = """%s"""' % str(value))
except SyntaxError, se: except SyntaxError as se:
try: try:
exec "res = '''%s'''" % str(value) exec("res = '''%s'''" % str(value))
except SyntaxError, se: except SyntaxError as se:
res = None res = None
return res return res
@ -183,7 +183,7 @@ class CsvParser:
self.res.append(lineObject) self.res.append(lineObject)
f.close() f.close()
# The second pass resolves the p_references if any # The second pass resolves the p_references if any
for attrName, refInfo in self.references.iteritems(): for attrName, refInfo in self.references.items():
if attrName in self.attributes: if attrName in self.attributes:
# Replace ID with real object from p_references # Replace ID with real object from p_references
for obj in self.res: for obj in self.res:
@ -228,7 +228,7 @@ class CsvMarshaller:
def marshallValue(self, field, value): def marshallValue(self, field, value):
'''Produces a version of p_value that can be dumped in a CSV file.''' '''Produces a version of p_value that can be dumped in a CSV file.'''
if isinstance(value, basestring): if isinstance(value, str):
# Format the string as a one-line CSV-ready value # Format the string as a one-line CSV-ready value
res = self.marshallString(value) res = self.marshallString(value)
elif type(value) in sequenceTypes: elif type(value) in sequenceTypes:

View file

@ -1,6 +1,6 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import os, re, httplib, sys, stat, urlparse, time, socket, xml.sax import os, re, http.client, sys, stat, urllib.parse, time, socket, xml.sax
import urllib from urllib.parse import quote
from StringIO import StringIO from StringIO import StringIO
from mimetypes import guess_type from mimetypes import guess_type
from base64 import encodestring from base64 import encodestring
@ -19,12 +19,12 @@ class FormDataEncoder:
def marshalValue(self, name, value): def marshalValue(self, name, value):
if isinstance(value, basestring): if isinstance(value, basestring):
return '%s=%s' % (name, urllib.quote(str(value))) return '%s=%s' % (name, quote(str(value)))
elif isinstance(value, float): elif isinstance(value, float):
return '%s:float=%s' % (name, value) return '%s:float=%s' % (name, value)
elif isinstance(value, int): elif isinstance(value, int):
return '%s:int=%s' % (name, value) return '%s:int=%s' % (name, value)
elif isinstance(value, long): elif isinstance(value, int):
res = '%s:long=%s' % (name, value) res = '%s:long=%s' % (name, value)
if res[-1] == 'L': if res[-1] == 'L':
res = res[:-1] res = res[:-1]
@ -101,8 +101,8 @@ class HttpResponse:
redirect the user to if self.code is 302, or will unmarshall XML redirect the user to if self.code is 302, or will unmarshall XML
data into Python objects.''' data into Python objects.'''
if self.code == 302: if self.code == 302:
return urlparse.urlparse(self.headers['location'])[2] return urllib.parse.urlparse(self.headers['location'])[2]
elif self.headers.has_key('content-type'): elif 'content-type' in self.headers:
contentType = self.extractContentType(self.headers['content-type']) contentType = self.extractContentType(self.headers['content-type'])
for xmlHeader in self.xmlHeaders: for xmlHeader in self.xmlHeaders:
if contentType.startswith(xmlHeader): if contentType.startswith(xmlHeader):
@ -116,7 +116,7 @@ class HttpResponse:
raise ResourceError('Distant server exception: ' \ raise ResourceError('Distant server exception: ' \
'%s' % res) '%s' % res)
return res return res
except xml.sax.SAXParseException, se: except xml.sax.SAXParseException as se:
raise ResourceError('Invalid XML response (%s)'%str(se)) raise ResourceError('Invalid XML response (%s)'%str(se))
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -158,7 +158,7 @@ class Resource:
def updateHeaders(self, headers): def updateHeaders(self, headers):
# Add credentials if present # Add credentials if present
if not (self.username and self.password): return if not (self.username and self.password): return
if headers.has_key('Authorization'): return if 'Authorization' in headers: return
credentials = '%s:%s' % (self.username, self.password) credentials = '%s:%s' % (self.username, self.password)
credentials = credentials.replace('\012', '') credentials = credentials.replace('\012', '')
headers['Authorization'] = "Basic %s" % encodestring(credentials) headers['Authorization'] = "Basic %s" % encodestring(credentials)
@ -170,19 +170,19 @@ class Resource:
def send(self, method, uri, body=None, headers={}, bodyType=None): def send(self, method, uri, body=None, headers={}, bodyType=None):
'''Sends a HTTP request with p_method, for p_uri.''' '''Sends a HTTP request with p_method, for p_uri.'''
conn = httplib.HTTPConnection(self.host, self.port) conn = http.client.HTTPConnection(self.host, self.port)
try: try:
conn.connect() conn.connect()
except socket.gaierror, sge: except socket.gaierror as sge:
raise ResourceError('Check your Internet connection (%s)'% str(sge)) raise ResourceError('Check your Internet connection (%s)'% str(sge))
except socket.error, se: except socket.error as se:
raise ResourceError('Connection error (%s)' % str(se)) raise ResourceError('Connection error (%s)' % str(se))
# Tell what kind of HTTP request it will be. # Tell what kind of HTTP request it will be.
conn.putrequest(method, uri, skip_host=True) conn.putrequest(method, uri, skip_host=True)
# Add HTTP headers # Add HTTP headers
self.updateHeaders(headers) self.updateHeaders(headers)
if self.headers: headers.update(self.headers) if self.headers: headers.update(self.headers)
for n, v in headers.items(): conn.putheader(n, v) for n, v in list(headers.items()): conn.putheader(n, v)
conn.endheaders() conn.endheaders()
# Add HTTP body # Add HTTP body
if body: if body:

View file

@ -250,7 +250,7 @@ class HtmlDiff:
deleteStyle = 'color: red; text-decoration: line-through; cursor: help' deleteStyle = 'color: red; text-decoration: line-through; cursor: help'
def __init__(self, old, new, def __init__(self, old, new,
insertMsg=u'Inserted text', deleteMsg=u'Deleted text', insertMsg='Inserted text', deleteMsg='Deleted text',
insertCss=None, deleteCss=None, insertName='insert', insertCss=None, deleteCss=None, insertName='insert',
deleteName='delete', diffRatio=0.7): deleteName='delete', diffRatio=0.7):
# p_old and p_new are strings containing chunks of HTML. If they are not # p_old and p_new are strings containing chunks of HTML. If they are not
@ -306,24 +306,24 @@ class HtmlDiff:
else: tag = 'span' else: tag = 'span'
# What message will it show in its 'title' attribute? # What message will it show in its 'title' attribute?
if not msg: if not msg:
exec 'msg = self.%sMsg' % type exec('msg = self.%sMsg' % type)
# What CSS class (or, if none, tag-specific style) will be used ? # What CSS class (or, if none, tag-specific style) will be used ?
exec 'cssClass = self.%sCss' % type exec('cssClass = self.%sCss' % type)
if cssClass: if cssClass:
style = 'class="%s"' % cssClass style = 'class="%s"' % cssClass
else: else:
exec 'style = self.%sStyle' % type exec('style = self.%sStyle' % type)
style = 'style="%s"' % style style = 'style="%s"' % style
# The 'name' attribute of the tag indicates the type of the update. # The 'name' attribute of the tag indicates the type of the update.
exec 'tagName = self.%sName' % type exec('tagName = self.%sName' % type)
# The idea is: if there are several lines, every line must be surrounded # 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 # by a tag. This way, we know that a surrounding tag can't span several
# lines, which is a prerequisite for managing cumulative diffs. # lines, which is a prerequisite for managing cumulative diffs.
if sep == ' ': if sep == ' ':
if not isinstance(seq, basestring): if not isinstance(seq, str):
seq = sep.join(seq) seq = sep.join(seq)
sep = '' sep = ''
if isinstance(seq, basestring): if isinstance(seq, str):
return '%s<%s name="%s" %s title="%s">%s</%s>%s' % \ return '%s<%s name="%s" %s title="%s">%s</%s>%s' % \
(sep, tag, tagName, style, msg, seq, tag, sep) (sep, tag, tagName, style, msg, seq, tag, sep)
else: else:
@ -592,7 +592,7 @@ class HtmlDiff:
try: try:
merger = Merger(lineA, add, previousDiffsA, self) merger = Merger(lineA, add, previousDiffsA, self)
add = merger.merge() add = merger.merge()
except Merger.MergeError, e: except Merger.MergeError as e:
# The merge algorithm has made a burn out. Simplify and # The merge algorithm has made a burn out. Simplify and
# consider lineA has having been completely deleted and # consider lineA has having been completely deleted and
# lineB has completely inserted. # lineB has completely inserted.

View file

@ -239,14 +239,14 @@ class LdapConnector:
self.server = ldap.initialize(self.serverUri) self.server = ldap.initialize(self.serverUri)
self.server.simple_bind_s(login, password) self.server.simple_bind_s(login, password)
return True, None return True, None
except AttributeError, ae: except AttributeError as ae:
# When the ldap module is not there, trying to catch ldap.LDAPError # When the ldap module is not there, trying to catch ldap.LDAPError
# will raise an error. # will raise an error.
message = str(ae) message = str(ae)
self.log('Ldap connect error with login %s (%s).' % \ self.log('Ldap connect error with login %s (%s).' % \
(login, message)) (login, message))
return False, message return False, message
except ldap.LDAPError, le: except ldap.LDAPError as le:
message = str(le) message = str(le)
self.log('%s: connect error with login %s (%s).' % \ self.log('%s: connect error with login %s (%s).' % \
(self.serverUri, login, message)) (self.serverUri, login, message))
@ -275,7 +275,7 @@ class LdapConnector:
timeout=self.timeout) timeout=self.timeout)
except ldap.TIMEOUT: except ldap.TIMEOUT:
pass pass
except ldap.LDAPError, le: except ldap.LDAPError as le:
self.log('LDAP query error %s: %s' % \ self.log('LDAP query error %s: %s' % \
(le.__class__.__name__, str(le))) (le.__class__.__name__, str(le)))
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -160,20 +160,20 @@ class Debianizer:
name = '%s/%sctl' % (binFolder, self.appNameLower) name = '%s/%sctl' % (binFolder, self.appNameLower)
f = file(name, 'w') f = file(name, 'w')
f.write(appCtl % self.appNameLower) f.write(appCtl % self.appNameLower)
os.chmod(name, 0744) # Make it executable by owner. os.chmod(name, 0o744) # Make it executable by owner.
f.close() f.close()
# <app>run # <app>run
name = '%s/%srun' % (binFolder, self.appNameLower) name = '%s/%srun' % (binFolder, self.appNameLower)
f = file(name, 'w') f = file(name, 'w')
f.write(appRun % self.appNameLower) f.write(appRun % self.appNameLower)
os.chmod(name, 0744) # Make it executable by owner. os.chmod(name, 0o744) # Make it executable by owner.
f.close() f.close()
# startoo # startoo
name = '%s/startoo' % binFolder name = '%s/startoo' % binFolder
f = file(name, 'w') f = file(name, 'w')
f.write(ooStart) f.write(ooStart)
f.close() f.close()
os.chmod(name, 0744) # Make it executable by owner. os.chmod(name, 0o744) # Make it executable by owner.
# /var/lib/<app> (will store Data.fs, lock files, etc) # /var/lib/<app> (will store Data.fs, lock files, etc)
varLibFolder = j(debFolder, 'var', 'lib', self.appNameLower) varLibFolder = j(debFolder, 'var', 'lib', self.appNameLower)
os.makedirs(varLibFolder) os.makedirs(varLibFolder)
@ -208,7 +208,7 @@ class Debianizer:
'application.' % n, '%sctl start' % n, 'application.' % n, '%sctl start' % n,
'%sctl restart' % n, '%sctl stop' % n)) '%sctl restart' % n, '%sctl stop' % n))
f.close() f.close()
os.chmod(name, 0744) # Make it executable by owner. os.chmod(name, 0o744) # Make it executable by owner.
# /etc/init.d/oo (start OpenOffice at boot time) # /etc/init.d/oo (start OpenOffice at boot time)
name = '%s/oo' % initdFolder name = '%s/oo' % initdFolder
f = file(name, 'w') f = file(name, 'w')
@ -216,7 +216,7 @@ class Debianizer:
'startoo', 'startoo', "#Can't stop OO.")) 'startoo', 'startoo', "#Can't stop OO."))
f.write('\n') f.write('\n')
f.close() f.close()
os.chmod(name, 0744) # Make it executable by owner. os.chmod(name, 0o744) # Make it executable by owner.
# Get the size of the app, in Kb. # Get the size of the app, in Kb.
os.chdir(tempFolder) os.chdir(tempFolder)
cmd = subprocess.Popen(['du', '-b', '-s', 'debian'], cmd = subprocess.Popen(['du', '-b', '-s', 'debian'],

View file

@ -25,8 +25,8 @@
be strictly greater than 1.''' be strictly greater than 1.'''
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
import re, sys, UserList, UserDict import re, sys, collections, UserDict
from StringIO import StringIO from io import StringIO
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
class ParserError(Exception): pass class ParserError(Exception): pass
@ -69,7 +69,7 @@ LIST_VALUE_ERROR = 'Value "%s" is malformed: within it, %s. You should check ' \
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
class Type: class Type:
basicTypes = {'f': float, 'i':int, 'g':long, 'b':bool} basicTypes = {'f': float, 'i':int, 'g':int, 'b':bool}
separators = ['-', ';', ',', ':'] separators = ['-', ';', ',', ':']
def __init__(self, typeDecl): def __init__(self, typeDecl):
self.basicType = None # The python basic type self.basicType = None # The python basic type
@ -85,12 +85,12 @@ class Type:
self.listNumber += 1 self.listNumber += 1
else: else:
# Get the basic type # Get the basic type
if not (char in Type.basicTypes.keys()): if not (char in list(Type.basicTypes.keys())):
raise TypeError(BASIC_TYPE_ERROR % char) raise TypeError(BASIC_TYPE_ERROR % char)
self.basicType = Type.basicTypes[char] self.basicType = Type.basicTypes[char]
break break
if not self.basicType: if not self.basicType:
self.basicType = unicode self.basicType = str
def convertBasicValue(self, value): def convertBasicValue(self, value):
try: try:
return self.basicType(value.strip()) return self.basicType(value.strip())
@ -136,7 +136,7 @@ class Type:
elif not resIsComplete: elif not resIsComplete:
try: try:
res = self.convertListItem(value, separators) res = self.convertListItem(value, separators)
except TypeError, te: except TypeError as te:
raise TypeError(LIST_VALUE_ERROR % (value, te, self.name)) raise TypeError(LIST_VALUE_ERROR % (value, te, self.name))
return res return res
def convertListItem(self, stringItem, remainingSeps): def convertListItem(self, stringItem, remainingSeps):
@ -161,9 +161,9 @@ class Type:
return self.name return self.name
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
class Table(UserList.UserList): class Table(collections.UserList):
def __init__(self): def __init__(self):
UserList.UserList.__init__(self) collections.UserList.__init__(self)
self.name = None self.name = None
self.parent = None self.parent = None
self.parentRow = None self.parentRow = None
@ -213,7 +213,7 @@ class TableRow(UserDict.UserDict):
via the parent table self.table.''' via the parent table self.table.'''
keyError = False keyError = False
t = self.table t = self.table
if self.has_key(key): if key in self:
res = UserDict.UserDict.__getitem__(self, key) res = UserDict.UserDict.__getitem__(self, key)
else: else:
# Get the parent row # Get the parent row
@ -259,9 +259,9 @@ class TableRow(UserDict.UserDict):
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
class NameResolver: class NameResolver:
def resolveNames(self, tables): def resolveNames(self, tables):
for tableName, table in tables.iteritems(): for tableName, table in tables.items():
if table.parent: if table.parent:
if not tables.has_key(table.parent): if table.parent not in tables:
raise ParserError(PARENT_NOT_FOUND % raise ParserError(PARENT_NOT_FOUND %
(table.parent, table.name)) (table.parent, table.name))
table.parent = tables[table.parent] table.parent = tables[table.parent]
@ -330,10 +330,10 @@ class TableParser:
def manageSpecialChar(self): def manageSpecialChar(self):
specialChar = int(self.specialCharBuffer) specialChar = int(self.specialCharBuffer)
self.specialCharBuffer = '' self.specialCharBuffer = ''
if self.specialChars.has_key(specialChar): if specialChar in self.specialChars:
self.contentBuffer.write(self.specialChars[specialChar]) self.contentBuffer.write(self.specialChars[specialChar])
else: else:
print('Warning: char %d not known.' % specialChar) print(('Warning: char %d not known.' % specialChar))
self.state = TableParser.READING_CONTENT self.state = TableParser.READING_CONTENT
def bufferize(self, char): def bufferize(self, char):
if self.state == TableParser.READING_CONTROL_WORD: if self.state == TableParser.READING_CONTROL_WORD:
@ -403,7 +403,7 @@ class TableParser:
columnNames.append(name.strip()) columnNames.append(name.strip())
try: try:
columnTypes.append(Type(typeDecl.strip())) columnTypes.append(Type(typeDecl.strip()))
except TypeError, te: except TypeError as te:
raise ParserError(TYPE_ERROR % raise ParserError(TYPE_ERROR %
(header, self.currentTableName, te)) (header, self.currentTableName, te))
else: else:
@ -449,7 +449,7 @@ class TableParser:
if columnType: if columnType:
try: try:
columnValue = columnType.convertValue(columnValue) columnValue = columnType.convertValue(columnValue)
except TypeError, te: except TypeError as te:
raise ParserError(VALUE_ERROR % raise ParserError(VALUE_ERROR %
(columnName, self.currentTableName, (columnName, self.currentTableName,
te)) te))
@ -496,7 +496,7 @@ class RtfTablesParser:
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
if __name__ =='__main__': if __name__ =='__main__':
tables = RtfTablesParser("Tests.rtf").parse() tables = RtfTablesParser("Tests.rtf").parse()
for key, item in tables.iteritems(): for key, item in tables.items():
print('Table %s' % key) print(('Table %s' % key))
print(item) print(item)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------

View file

@ -74,7 +74,7 @@ class Sap:
try: try:
self.sap = pysap.Rfc_connection(conn_string = params) self.sap = pysap.Rfc_connection(conn_string = params)
self.sap.open() self.sap.open()
except pysap.BaseSapRfcError, se: except pysap.BaseSapRfcError as se:
# Put in the error message the connection string without the # Put in the error message the connection string without the
# password. # password.
connNoPasswd = params[:params.index('PASSWD')] + 'PASSWD=********' connNoPasswd = params[:params.index('PASSWD')] + 'PASSWD=********'
@ -84,7 +84,7 @@ class Sap:
'''Create a struct corresponding to SAP/C structure definition '''Create a struct corresponding to SAP/C structure definition
p_structDef and fills it with dict p_userData.''' p_structDef and fills it with dict p_userData.'''
res = structDef() res = structDef()
for name, value in userData.iteritems(): for name, value in userData.items():
if name not in structDef._sfield_names_: if name not in structDef._sfield_names_:
raise SapError(SAP_STRUCT_ELEM_NOT_FOUND % (paramName, name)) raise SapError(SAP_STRUCT_ELEM_NOT_FOUND % (paramName, name))
sapType = structDef._sfield_sap_types_[name] sapType = structDef._sfield_sap_types_[name]
@ -93,7 +93,7 @@ class Sap:
sType = '%s%d' % (sapType[0], sapType[1]) sType = '%s%d' % (sapType[0], sapType[1])
# "None" value is tolerated. # "None" value is tolerated.
if value == None: value = '' if value == None: value = ''
if not isinstance(value, basestring): if not isinstance(value, str):
raise SapError( raise SapError(
SAP_STRING_REQUIRED % (name, paramName, sType)) SAP_STRING_REQUIRED % (name, paramName, sType))
if len(value) > sapType[1]: if len(value) > sapType[1]:
@ -113,7 +113,7 @@ class Sap:
functionName = self.functionName functionName = self.functionName
function = self.sap.get_interface(functionName) function = self.sap.get_interface(functionName)
# Specify the parameters # Specify the parameters
for name, value in params.iteritems(): for name, value in params.items():
if type(value) == dict: if type(value) == dict:
# The param corresponds to a SAP/C "struct" # The param corresponds to a SAP/C "struct"
v = self.createStructure( v = self.createStructure(
@ -140,7 +140,7 @@ class Sap:
function[name] = v function[name] = v
# Call the function # Call the function
function() function()
except pysap.BaseSapRfcError, se: except pysap.BaseSapRfcError as se:
raise SapError(SAP_FUNCTION_ERROR % (functionName, str(se))) raise SapError(SAP_FUNCTION_ERROR % (functionName, str(se)))
return SapResult(function) return SapResult(function)
@ -198,10 +198,10 @@ class Sap:
self.sap.get_structure(typeName) self.sap.get_structure(typeName)
res += '%s\n%s\n\n' % \ res += '%s\n%s\n\n' % \
(typeName, self.getTypeInfo(typeName)) (typeName, self.getTypeInfo(typeName))
except pysap.BaseSapRfcError, ee: except pysap.BaseSapRfcError as ee:
pass pass
return res return res
except pysap.BaseSapRfcError, se: except pysap.BaseSapRfcError as se:
if se.value == 'FU_NOT_FOUND': if se.value == 'FU_NOT_FOUND':
raise SapError(SAP_FUNCTION_NOT_FOUND % (functionName)) raise SapError(SAP_FUNCTION_NOT_FOUND % (functionName))
else: else:
@ -229,6 +229,6 @@ class Sap:
'''Disconnects from SAP.''' '''Disconnects from SAP.'''
try: try:
self.sap.close() self.sap.close()
except pysap.BaseSapRfcError, se: except pysap.BaseSapRfcError as se:
raise SapError(SAP_DISCONNECT_ERROR % str(se)) raise SapError(SAP_DISCONNECT_ERROR % str(se))
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -177,7 +177,7 @@ class Tester:
(not isinstance(flavours, tuple)): (not isinstance(flavours, tuple)):
raise TesterError(FLAVOURS_NOT_LIST) raise TesterError(FLAVOURS_NOT_LIST)
for flavour in flavours: for flavour in flavours:
if not isinstance(flavour, basestring): if not isinstance(flavour, str):
raise TesterError(FLAVOUR_NOT_STRING) raise TesterError(FLAVOUR_NOT_STRING)
self.flavours = flavours self.flavours = flavours
self.flavour = None self.flavour = None
@ -198,7 +198,7 @@ class Tester:
if self.flavour: if self.flavour:
ext = '.%s' % self.flavour ext = '.%s' % self.flavour
configTableName = 'Configuration%s' % ext configTableName = 'Configuration%s' % ext
if self.tables.has_key(configTableName): if configTableName in self.tables:
self.config = self.tables[configTableName].asDict() self.config = self.tables[configTableName].asDict()
self.tempFolder = os.path.join(self.testFolder, 'temp') self.tempFolder = os.path.join(self.testFolder, 'temp')
if os.path.exists(self.tempFolder): if os.path.exists(self.tempFolder):
@ -249,11 +249,11 @@ class Tester:
self.report.say('Test successful.\n') self.report.say('Test successful.\n')
self.nbOfSuccesses += 1 self.nbOfSuccesses += 1
def run(self): def run(self):
assert self.tables.has_key('TestSuites'), \ assert 'TestSuites' in self.tables, \
TesterError(MAIN_TABLE_NOT_FOUND % self.testPlan) TesterError(MAIN_TABLE_NOT_FOUND % self.testPlan)
for testSuite in self.tables['TestSuites']: for testSuite in self.tables['TestSuites']:
if (not testSuite.has_key('Name')) or \ if ('Name' not in testSuite) or \
(not testSuite.has_key('Description')): ('Description' not in testSuite):
raise TesterError(MAIN_TABLE_MALFORMED) raise TesterError(MAIN_TABLE_MALFORMED)
if testSuite['Name'].startswith('_'): if testSuite['Name'].startswith('_'):
tsName = testSuite['Name'][1:] tsName = testSuite['Name'][1:]
@ -261,8 +261,8 @@ class Tester:
else: else:
tsName = testSuite['Name'] tsName = testSuite['Name']
tsIgnored = False tsIgnored = False
assert self.tables.has_key('%s.descriptions' % tsName) \ assert '%s.descriptions' % tsName in self.tables \
and self.tables.has_key('%s.data' % tsName), \ and '%s.data' % tsName in self.tables, \
TesterError(TEST_SUITE_NOT_FOUND % (tsName, tsName)) TesterError(TEST_SUITE_NOT_FOUND % (tsName, tsName))
assert len(self.tables['%s.descriptions' % tsName]) == \ assert len(self.tables['%s.descriptions' % tsName]) == \
len(self.tables['%s.data' % tsName]), \ len(self.tables['%s.data' % tsName]), \

View file

@ -44,7 +44,7 @@ class FolderDeleter:
dirName = os.path.dirname(dirName) dirName = os.path.dirname(dirName)
else: else:
break break
except OSError, oe: except OSError:
break break
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -53,7 +53,7 @@ def cleanFolder(folder, exts=extsToClean, folders=(), verbose=False):
'''This function allows to remove, in p_folder and subfolders, any file '''This function allows to remove, in p_folder and subfolders, any file
whose extension is in p_exts, and any folder whose name is in whose extension is in p_exts, and any folder whose name is in
p_folders.''' p_folders.'''
if verbose: print('Cleaning folder %s...' % folder) if verbose: print(('Cleaning folder %s...' % folder))
# Remove files with an extension listed in p_exts # Remove files with an extension listed in p_exts
if exts: if exts:
for root, dirs, files in os.walk(folder): for root, dirs, files in os.walk(folder):
@ -61,7 +61,7 @@ def cleanFolder(folder, exts=extsToClean, folders=(), verbose=False):
ext = os.path.splitext(fileName)[1] ext = os.path.splitext(fileName)[1]
if (ext in exts) or ext.endswith('~'): if (ext in exts) or ext.endswith('~'):
fileToRemove = os.path.join(root, fileName) fileToRemove = os.path.join(root, fileName)
if verbose: print('Removing file %s...' % fileToRemove) if verbose: print(('Removing file %s...' % fileToRemove))
os.remove(fileToRemove) os.remove(fileToRemove)
# Remove folders whose names are in p_folders. # Remove folders whose names are in p_folders.
if folders: if folders:
@ -69,7 +69,7 @@ def cleanFolder(folder, exts=extsToClean, folders=(), verbose=False):
for folderName in dirs: for folderName in dirs:
if folderName in folders: if folderName in folders:
toDelete = os.path.join(root, folderName) toDelete = os.path.join(root, folderName)
if verbose: print('Removing folder %s...' % toDelete) if verbose: print(('Removing folder %s...' % toDelete))
FolderDeleter.delete(toDelete) FolderDeleter.delete(toDelete)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -142,14 +142,14 @@ def copyData(data, target, targetMethod, type='string', encoding=None,
dump(encodeData(chunk, encoding)) dump(encodeData(chunk, encoding))
elif type == 'zope': elif type == 'zope':
# A OFS.Image.File instance can be split into several chunks # A OFS.Image.File instance can be split into several chunks
if isinstance(data.data, basestring): # One chunk if isinstance(data.data, str): # One chunk
dump(encodeData(data.data, encoding)) dump(encodeData(data.data, encoding))
else: else:
# Several chunks # Several chunks
data = data.data data = data.data
while data is not None: while data is not None:
dump(encodeData(data.data, encoding)) dump(encodeData(data.data, encoding))
data = data.next data = data.__next__
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
def splitList(l, sub): def splitList(l, sub):
@ -222,12 +222,12 @@ def getOsTempFolder():
tmp = '/tmp' tmp = '/tmp'
if os.path.exists(tmp) and os.path.isdir(tmp): if os.path.exists(tmp) and os.path.isdir(tmp):
res = tmp res = tmp
elif os.environ.has_key('TMP'): elif 'TMP' in os.environ:
res = os.environ['TMP'] res = os.environ['TMP']
elif os.environ.has_key('TEMP'): elif 'TEMP' in os.environ:
res = os.environ['TEMP'] res = os.environ['TEMP']
else: else:
raise "Sorry, I can't find a temp folder on your machine." raise Exception("Sorry, I can't find a temp folder on your machine.")
return res return res
def getTempFileName(prefix='', extension=''): def getTempFileName(prefix='', extension=''):
@ -273,10 +273,10 @@ def normalizeString(s, usage='fileName'):
except UnicodeDecodeError: except UnicodeDecodeError:
# Another encoding may be in use # Another encoding may be in use
s = s.decode('latin-1') s = s.decode('latin-1')
elif not isinstance(s, unicode): s = unicode(s) elif not isinstance(s, str): s = str(s)
# For extracted text, replace any unwanted char with a blank # For extracted text, replace any unwanted char with a blank
if usage == 'extractedText': if usage == 'extractedText':
res = u'' res = ''
for char in s: for char in s:
if char not in extractIgnore: res += char if char not in extractIgnore: res += char
else: res += ' ' else: res += ' '
@ -291,7 +291,7 @@ def normalizeString(s, usage='fileName'):
for char in s: for char in s:
if char not in fileNameIgnore: res += char if char not in fileNameIgnore: res += char
elif usage.startswith('alpha'): elif usage.startswith('alpha'):
exec 'rex = %sRex' % usage exec('rex = %sRex' % usage)
res = '' res = ''
for char in s: for char in s:
if rex.match(char): res += char if rex.match(char): res += char
@ -319,7 +319,7 @@ def keepDigits(s):
def getStringDict(d): def getStringDict(d):
'''Gets the string literal corresponding to dict p_d.''' '''Gets the string literal corresponding to dict p_d.'''
res = [] res = []
for k, v in d.iteritems(): for k, v in d.items():
if type(v) not in sequenceTypes: if type(v) not in sequenceTypes:
if not isinstance(k, basestring): k = str(k) if not isinstance(k, basestring): k = str(k)
if not isinstance(v, basestring): v = str(v) if not isinstance(v, basestring): v = str(v)
@ -386,7 +386,7 @@ def formatNumber(n, sep=',', precision=2, tsep=' '):
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
def lower(s): def lower(s):
'''French-accents-aware variant of string.lower.''' '''French-accents-aware variant of string.lower.'''
isUnicode = isinstance(s, unicode) isUnicode = isinstance(s, str)
if not isUnicode: s = s.decode('utf-8') if not isUnicode: s = s.decode('utf-8')
res = s.lower() res = s.lower()
if not isUnicode: res = res.encode('utf-8') if not isUnicode: res = res.encode('utf-8')
@ -394,14 +394,14 @@ def lower(s):
def upper(s): def upper(s):
'''French-accents-aware variant of string.upper.''' '''French-accents-aware variant of string.upper.'''
isUnicode = isinstance(s, unicode) isUnicode = isinstance(s, str)
if not isUnicode: s = s.decode('utf-8') if not isUnicode: s = s.decode('utf-8')
res = s.upper() res = s.upper()
if not isUnicode: res = res.encode('utf-8') if not isUnicode: res = res.encode('utf-8')
return res return res
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
typeLetters = {'b': bool, 'i': int, 'j': long, 'f':float, 's':str, 'u':unicode, typeLetters = {'b': bool, 'i': int, 'j': int, 'f':float, 's':str, 'u':str,
'l': list, 'd': dict} 'l': list, 'd': dict}
caExts = {'py': ('.py', '.vpy', '.cpy'), 'xml': ('.pt', '.cpt', '.xml')} caExts = {'py': ('.py', '.vpy', '.cpy'), 'xml': ('.pt', '.cpt', '.xml')}
@ -506,8 +506,8 @@ class CodeAnalysis:
if not lines: return if not lines: return
commentRate = (self.commentLines / float(lines)) * 100.0 commentRate = (self.commentLines / float(lines)) * 100.0
blankRate = (self.emptyLines / float(lines)) * 100.0 blankRate = (self.emptyLines / float(lines)) * 100.0
print('%s: %d files, %d lines (%.0f%% comments, %.0f%% blank)' % \ print(('%s: %d files, %d lines (%.0f%% comments, %.0f%% blank)' % \
(self.name, self.numberOfFiles, lines, commentRate, blankRate)) (self.name, self.numberOfFiles, lines, commentRate, blankRate)))
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
class LinesCounter: class LinesCounter:
@ -516,7 +516,7 @@ class LinesCounter:
'%stemp' % os.sep) '%stemp' % os.sep)
def __init__(self, folderOrModule, excludes=None): def __init__(self, folderOrModule, excludes=None):
if isinstance(folderOrModule, basestring): if isinstance(folderOrModule, str):
# It is the path of some folder # It is the path of some folder
self.folder = folderOrModule self.folder = folderOrModule
else: else:
@ -624,10 +624,10 @@ class FileWrapper:
if self.content.__class__.__name__ == 'Pdata': if self.content.__class__.__name__ == 'Pdata':
# The file content is splitted in several chunks. # The file content is splitted in several chunks.
f.write(self.content.data) f.write(self.content.data)
nextPart = self.content.next nextPart = self.content.__next__
while nextPart: while nextPart:
f.write(nextPart.data) f.write(nextPart.data)
nextPart = nextPart.next nextPart = nextPart.__next__
else: else:
# Only one chunk # Only one chunk
f.write(self.content) f.write(self.content)

View file

@ -66,9 +66,9 @@ HTML_ENTITIES = {
'euro':'', 'nbsp':' ', "rsquo":"'", "lsquo":"'", "ldquo":"'", 'euro':'', 'nbsp':' ', "rsquo":"'", "lsquo":"'", "ldquo":"'",
"rdquo":"'", 'ndash': '', 'mdash': '', 'oelig':'oe', 'quot': "'", "rdquo":"'", 'ndash': '', 'mdash': '', 'oelig':'oe', 'quot': "'",
'mu': 'µ'} 'mu': 'µ'}
import htmlentitydefs import html.entities
for k, v in htmlentitydefs.entitydefs.iteritems(): for k, v in html.entities.entitydefs.items():
if not HTML_ENTITIES.has_key(k) and not XML_ENTITIES.has_key(k): if k not in HTML_ENTITIES and k not in XML_ENTITIES:
HTML_ENTITIES[k] = '' HTML_ENTITIES[k] = ''
def escapeXml(s, format='xml', nsText='text'): def escapeXml(s, format='xml', nsText='text'):
@ -77,13 +77,13 @@ def escapeXml(s, format='xml', nsText='text'):
their ODF counterparts. In this case, it is needed to give the name of their ODF counterparts. In this case, it is needed to give the name of
the "text" namespace (p_nsText) as defined in the ODF document where the the "text" namespace (p_nsText) as defined in the ODF document where the
line breaks and tabs must be inserted.''' line breaks and tabs must be inserted.'''
if isinstance(s, unicode): if isinstance(s, str):
res = u'' res = ''
else: else:
res = '' res = ''
odf = format == 'odf' odf = format == 'odf'
for c in s: for c in s:
if XML_SPECIAL_CHARS_NO_APOS.has_key(c): if c in XML_SPECIAL_CHARS_NO_APOS:
# We do not escape 'apos': there is no particular need for that. # We do not escape 'apos': there is no particular need for that.
res += XML_SPECIAL_CHARS_NO_APOS[c] res += XML_SPECIAL_CHARS_NO_APOS[c]
elif odf and (c == '\n'): elif odf and (c == '\n'):
@ -99,12 +99,12 @@ def escapeXml(s, format='xml', nsText='text'):
def escapeXhtml(s): def escapeXhtml(s):
'''Return p_s, whose XHTML special chars and carriage return chars have '''Return p_s, whose XHTML special chars and carriage return chars have
been replaced with corresponding XHTML entities.''' been replaced with corresponding XHTML entities.'''
if isinstance(s, unicode): if isinstance(s, str):
res = u'' res = ''
else: else:
res = '' res = ''
for c in s: for c in s:
if XML_SPECIAL_CHARS_NO_APOS.has_key(c): if c in XML_SPECIAL_CHARS_NO_APOS:
res += XML_SPECIAL_CHARS_NO_APOS[c] res += XML_SPECIAL_CHARS_NO_APOS[c]
elif c == '\n': elif c == '\n':
res += '<br/>' res += '<br/>'
@ -144,7 +144,7 @@ class XmlElement:
res = self.elem res = self.elem
if self.attrs: if self.attrs:
res += '(' res += '('
for attrName, attrValue in self.attrs.items(): for attrName, attrValue in list(self.attrs.items()):
res += '%s="%s"' % (attrName, attrValue) res += '%s="%s"' % (attrName, attrValue)
res += ')' res += ')'
return res return res
@ -167,7 +167,7 @@ class XmlEnvironment:
self.parser = None self.parser = None
def manageNamespaces(self, attrs): def manageNamespaces(self, attrs):
'''Manages namespaces definitions encountered in p_attrs.''' '''Manages namespaces definitions encountered in p_attrs.'''
for attrName, attrValue in attrs.items(): for attrName, attrValue in list(attrs.items()):
if attrName.startswith('xmlns:'): if attrName.startswith('xmlns:'):
self.namespaces[attrValue] = attrName[6:] self.namespaces[attrValue] = attrName[6:]
def ns(self, nsUri): def ns(self, nsUri):
@ -221,7 +221,7 @@ class XmlParser(ContentHandler, ErrorHandler):
def skippedEntity(self, name): def skippedEntity(self, name):
'''This method is called every time expat does not recognize an entity. '''This method is called every time expat does not recognize an entity.
We provide here support for HTML entities.''' We provide here support for HTML entities.'''
if HTML_ENTITIES.has_key(name): if name in HTML_ENTITIES:
self.characters(HTML_ENTITIES[name].decode('utf-8')) self.characters(HTML_ENTITIES[name].decode('utf-8'))
else: else:
# Put a question mark instead of raising an exception. # Put a question mark instead of raising an exception.
@ -230,10 +230,10 @@ class XmlParser(ContentHandler, ErrorHandler):
# ErrorHandler methods --------------------------------------------------- # ErrorHandler methods ---------------------------------------------------
def error(self, error): def error(self, error):
if self.raiseOnError: raise error if self.raiseOnError: raise error
else: print('SAX error %s' % str(error)) else: print(('SAX error %s' % str(error)))
def fatalError(self, error): def fatalError(self, error):
if self.raiseOnError: raise error if self.raiseOnError: raise error
else: print('SAX fatal error %s' % str(error)) else: print(('SAX fatal error %s' % str(error)))
def warning(self, error): pass def warning(self, error): pass
def parse(self, xml, source='string'): def parse(self, xml, source='string'):
@ -246,9 +246,9 @@ class XmlParser(ContentHandler, ErrorHandler):
method will close it. method will close it.
''' '''
try: try:
from cStringIO import StringIO from io import StringIO
except ImportError: except ImportError:
from StringIO import StringIO from io import StringIO
self._xml = xml self._xml = xml
self.parser.setContentHandler(self) self.parser.setContentHandler(self)
self.parser.setErrorHandler(self) self.parser.setErrorHandler(self)
@ -333,7 +333,7 @@ class XmlUnmarshaller(XmlParser):
def convertAttrs(self, attrs): def convertAttrs(self, attrs):
'''Converts XML attrs to a dict.''' '''Converts XML attrs to a dict.'''
res = {} res = {}
for k, v in attrs.items(): for k, v in list(attrs.items()):
if ':' in k: # An attr prefixed with a namespace. Remove this. if ':' in k: # An attr prefixed with a namespace. Remove this.
k = k.split(':')[-1] k = k.split(':')[-1]
res[str(k)] = self.encode(v) res[str(k)] = self.encode(v)
@ -362,9 +362,9 @@ class XmlUnmarshaller(XmlParser):
e = XmlParser.startElement(self, elem, attrs) e = XmlParser.startElement(self, elem, attrs)
# Determine the type of the element. # Determine the type of the element.
elemType = 'unicode' # Default value elemType = 'unicode' # Default value
if attrs.has_key('type'): if 'type' in attrs:
elemType = attrs['type'] elemType = attrs['type']
elif self.tagTypes.has_key(elem): elif elem in self.tagTypes:
elemType = self.tagTypes[elem] elemType = self.tagTypes[elem]
if elemType in self.containerTags: if elemType in self.containerTags:
# I must create a new container object. # I must create a new container object.
@ -375,9 +375,9 @@ class XmlUnmarshaller(XmlParser):
elif elemType == 'dict': newObject = {} elif elemType == 'dict': newObject = {}
elif elemType == 'file': elif elemType == 'file':
newObject = UnmarshalledFile() newObject = UnmarshalledFile()
if attrs.has_key('name'): if 'name' in attrs:
newObject.name = self.encode(attrs['name']) newObject.name = self.encode(attrs['name'])
if attrs.has_key('mimeType'): if 'mimeType' in attrs:
newObject.mimeType = self.encode(attrs['mimeType']) newObject.mimeType = self.encode(attrs['mimeType'])
else: newObject = Object(**self.convertAttrs(attrs)) else: newObject = Object(**self.convertAttrs(attrs))
# Store the value on the last container, or on the root object. # Store the value on the last container, or on the root object.
@ -454,17 +454,17 @@ class XmlUnmarshaller(XmlParser):
if not value: value = None if not value: value = None
else: else:
# If we have a custom converter for values of this type, use it. # If we have a custom converter for values of this type, use it.
if self.conversionFunctions.has_key(e.currentBasicType): if e.currentBasicType in self.conversionFunctions:
try: try:
value = self.conversionFunctions[e.currentBasicType]( value = self.conversionFunctions[e.currentBasicType](
value) value)
except Exception, err: except Exception as err:
raise AppyError(CUSTOM_CONVERSION_ERROR % ( raise AppyError(CUSTOM_CONVERSION_ERROR % (
e.currentBasicType, value, str(err))) e.currentBasicType, value, str(err)))
# If not, try a standard conversion # If not, try a standard conversion
elif e.currentBasicType in self.numericTypes: elif e.currentBasicType in self.numericTypes:
try: try:
exec 'value = %s' % value exec('value = %s' % value)
except SyntaxError: except SyntaxError:
raise AppyError(CONVERSION_ERROR % ( raise AppyError(CONVERSION_ERROR % (
e.currentBasicType, value)) e.currentBasicType, value))
@ -578,7 +578,7 @@ class XmlMarshaller:
tagName = self.getTagName(self.rootElementName) tagName = self.getTagName(self.rootElementName)
res.write('<'); res.write(tagName) res.write('<'); res.write(tagName)
# Dumps namespace definitions if any # Dumps namespace definitions if any
for prefix, url in self.namespaces.iteritems(): for prefix, url in self.namespaces.items():
if not prefix: if not prefix:
pre = 'xmlns' # The default namespace pre = 'xmlns' # The default namespace
else: else:
@ -597,7 +597,7 @@ class XmlMarshaller:
s = s.decode('utf-8') s = s.decode('utf-8')
# Replace special chars by XML entities # Replace special chars by XML entities
for c in s: for c in s:
if self.xmlEntities.has_key(c): if c in self.xmlEntities:
res.write(self.xmlEntities[c]) res.write(self.xmlEntities[c])
else: else:
res.write(c) res.write(c)
@ -617,13 +617,13 @@ class XmlMarshaller:
# There will be several parts. # There will be several parts.
w(v.data.data.encode('base64')) w(v.data.data.encode('base64'))
# Write subsequent parts # Write subsequent parts
nextPart = v.data.next nextPart = v.data.__next__
nextPartNb = 2 nextPartNb = 2
while nextPart: while nextPart:
w('</%s>' % partTag) # Close the previous part w('</%s>' % partTag) # Close the previous part
w('<%s type="base64" number="%d">' % (partTag, nextPartNb)) w('<%s type="base64" number="%d">' % (partTag, nextPartNb))
w(nextPart.data.encode('base64')) w(nextPart.data.encode('base64'))
nextPart = nextPart.next nextPart = nextPart.__next__
nextPartNb += 1 nextPartNb += 1
else: else:
w(v.data.encode('base64')) w(v.data.encode('base64'))
@ -654,7 +654,7 @@ class XmlMarshaller:
def dumpDict(self, res, v): def dumpDict(self, res, v):
'''Dumps the XML version of dict p_v.''' '''Dumps the XML version of dict p_v.'''
for key, value in v.iteritems(): for key, value in v.items():
res.write('<entry type="object">') res.write('<entry type="object">')
self.dumpField(res, 'k', key) self.dumpField(res, 'k', key)
self.dumpField(res, 'v', value) self.dumpField(res, 'v', value)
@ -681,7 +681,7 @@ class XmlMarshaller:
# The previous condition must be checked before this one because # The previous condition must be checked before this one because
# referred objects may be stored in lists or tuples, too. # referred objects may be stored in lists or tuples, too.
for elem in value: self.dumpField(res, 'e', elem) for elem in value: self.dumpField(res, 'e', elem)
elif isinstance(value, basestring): self.dumpString(res, value) elif isinstance(value, str): self.dumpString(res, value)
elif isinstance(value, bool): res.write(self.trueFalse[value]) elif isinstance(value, bool): res.write(self.trueFalse[value])
elif fieldType == 'object': elif fieldType == 'object':
if hasattr(value, 'absolute_url'): if hasattr(value, 'absolute_url'):
@ -689,7 +689,7 @@ class XmlMarshaller:
res.write(value.absolute_url()) res.write(value.absolute_url())
else: else:
# Dump the entire object content # Dump the entire object content
for k, v in value.__dict__.iteritems(): for k, v in value.__dict__.items():
if not k.startswith('__'): if not k.startswith('__'):
self.dumpField(res, k, v) self.dumpField(res, k, v)
# Maybe we could add a parameter to the marshaller to know how # Maybe we could add a parameter to the marshaller to know how
@ -771,7 +771,7 @@ class XmlMarshaller:
rootTagName = self.dumpRootTag(res, instance) rootTagName = self.dumpRootTag(res, instance)
# Dump the fields of this root object # Dump the fields of this root object
if objectType == 'popo': if objectType == 'popo':
for fieldName, fieldValue in instance.__dict__.iteritems(): for fieldName, fieldValue in instance.__dict__.items():
mustDump = False mustDump = False
if fieldName in self.fieldsToExclude: if fieldName in self.fieldsToExclude:
mustDump = False mustDump = False
@ -823,11 +823,11 @@ class XmlMarshaller:
histTag = self.getTagName('history') histTag = self.getTagName('history')
eventTag = self.getTagName('event') eventTag = self.getTagName('event')
res.write('<%s type="list">' % histTag) res.write('<%s type="list">' % histTag)
key = instance.workflow_history.keys()[0] key = list(instance.workflow_history.keys())[0]
history = instance.workflow_history[key] history = instance.workflow_history[key]
for event in history: for event in history:
res.write('<%s type="object">' % eventTag) res.write('<%s type="object">' % eventTag)
for k, v in event.iteritems(): for k, v in event.items():
self.dumpField(res, k, v) self.dumpField(res, k, v)
res.write('</%s>' % eventTag) res.write('</%s>' % eventTag)
res.write('</%s>' % histTag) res.write('</%s>' % histTag)
@ -856,7 +856,7 @@ class XmlHandler(ContentHandler):
(like dates) from a file that need to be compared to another file.''' (like dates) from a file that need to be compared to another file.'''
def __init__(self, xmlTagsToIgnore, xmlAttrsToIgnore): def __init__(self, xmlTagsToIgnore, xmlAttrsToIgnore):
ContentHandler.__init__(self) ContentHandler.__init__(self)
self.res = unicode(xmlPrologue) self.res = str(xmlPrologue)
self.namespaces = {} # ~{s_namespaceUri:s_namespaceName}~ self.namespaces = {} # ~{s_namespaceUri:s_namespaceName}~
self.indentLevel = -1 self.indentLevel = -1
self.tabWidth = 3 self.tabWidth = 3
@ -891,7 +891,7 @@ class XmlHandler(ContentHandler):
self.res += '\n' + (' ' * self.indentLevel * self.tabWidth) self.res += '\n' + (' ' * self.indentLevel * self.tabWidth)
def manageNamespaces(self, attrs): def manageNamespaces(self, attrs):
'''Manage namespaces definitions encountered in attrs''' '''Manage namespaces definitions encountered in attrs'''
for attrName, attrValue in attrs.items(): for attrName, attrValue in list(attrs.items()):
if attrName.startswith('xmlns:'): if attrName.startswith('xmlns:'):
self.namespaces[attrValue] = attrName[6:] self.namespaces[attrValue] = attrName[6:]
def ns(self, nsUri): def ns(self, nsUri):
@ -906,7 +906,7 @@ class XmlHandler(ContentHandler):
self.indentLevel += 1 self.indentLevel += 1
self.dumpSpaces() self.dumpSpaces()
self.res += '<%s' % elem self.res += '<%s' % elem
attrsNames = attrs.keys() attrsNames = list(attrs.keys())
attrsNames.sort() attrsNames.sort()
for attrToIgnore in self.attrsToIgnore: for attrToIgnore in self.attrsToIgnore:
if attrToIgnore in attrsNames: if attrToIgnore in attrsNames:
@ -986,7 +986,7 @@ class XmlComparator:
else: print(line) else: print(line)
else: else:
if report: report.say(line[:-1], encoding=encoding) if report: report.say(line[:-1], encoding=encoding)
else: print(line[:-1]) else: print((line[:-1]))
lastLinePrinted = True lastLinePrinted = True
else: else:
lastLinePrinted = False lastLinePrinted = False
@ -1061,7 +1061,7 @@ class XhtmlCleaner(XmlParser):
self.env.ignoreContent = False self.env.ignoreContent = False
try: try:
res = self.parse('<x>%s</x>' % s).encode('utf-8') res = self.parse('<x>%s</x>' % s).encode('utf-8')
except SAXParseException, e: except SAXParseException as e:
raise self.Error(str(e)) raise self.Error(str(e))
return res return res
@ -1106,7 +1106,7 @@ class XhtmlCleaner(XmlParser):
prefix = '' prefix = ''
res = '%s<%s' % (prefix, elem) res = '%s<%s' % (prefix, elem)
# Include the found attributes, excepted those that must be ignored. # Include the found attributes, excepted those that must be ignored.
for name, value in attrs.items(): for name, value in list(attrs.items()):
if not self.keepStyles: if not self.keepStyles:
if name in self.attrsToIgnore: continue if name in self.attrsToIgnore: continue
elif name == 'style': elif name == 'style':
@ -1115,7 +1115,7 @@ class XhtmlCleaner(XmlParser):
res += ' %s="%s"' % (name, value) res += ' %s="%s"' % (name, value)
# Include additional attributes if required. # Include additional attributes if required.
if elem in self.attrsToAdd: if elem in self.attrsToAdd:
for name, value in self.attrsToAdd[elem].iteritems(): for name, value in self.attrsToAdd[elem].items():
res += ' %s="%s"' % (name, value) res += ' %s="%s"' % (name, value)
# Close the tag if it is a no-end tag # Close the tag if it is a no-end tag
if elem in self.noEndTags: if elem in self.noEndTags:
@ -1163,7 +1163,7 @@ class XhtmlCleaner(XmlParser):
# I give here to lstrip an explicit list of what is to be considered # I give here to lstrip an explicit list of what is to be considered
# as blank chars, because I do not want unicode NBSP chars to be in # as blank chars, because I do not want unicode NBSP chars to be in
# this list. # this list.
toAdd = content.lstrip(u' \n\r\t') toAdd = content.lstrip(' \n\r\t')
else: else:
toAdd = content toAdd = content
# Re-transform XML special chars to entities. # Re-transform XML special chars to entities.