summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorClemmitt Sigler2020-10-20 06:47:28 -0400
committerClemmitt Sigler2020-10-20 06:47:28 -0400
commitcecc21a096c28dc07576e98e4eb1c3db216485c4 (patch)
treecacce04db7728ad960607f763b9c8dc4fccc5934
downloadaur-cecc21a096c28dc07576e98e4eb1c3db216485c4.tar.gz
Initial commit to AUR
-rw-r--r--.SRCINFO26
-rw-r--r--PKGBUILD51
-rw-r--r--pyfltk_python3.patch860
-rw-r--r--pyfltk_remove_percent_format.patch955
-rw-r--r--pyfltk_swig_silence_warnings.patch11
5 files changed, 1903 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..9f162a26cf5d
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,26 @@
+pkgbase = python-pyfltk-svn
+ pkgdesc = A Python wrapper for the Fast Light Tool Kit library
+ pkgver = r532
+ pkgrel = 1
+ url = http://pyfltk.sourceforge.net/
+ arch = x86_64
+ license = LGPL
+ makedepends = swig>=3.0.12
+ makedepends = python-setuptools
+ makedepends = subversion
+ depends = fltk>=1.3.5
+ depends = python>=3.7
+ depends = glu
+ provides = python-pyfltk
+ conflicts = python-pyfltk
+ source = svn://svn.code.sf.net/p/pyfltk/code/trunk
+ source = pyfltk_swig_silence_warnings.patch
+ source = pyfltk_python3.patch
+ source = pyfltk_remove_percent_format.patch
+ sha1sums = SKIP
+ sha1sums = 11aa48bcdc21b77e4ea53f986352d85eedf2a900
+ sha1sums = 8c88777b373d7a72f4a0cdbb264f4371931dbb7b
+ sha1sums = a105e1ca3592c880634503c9faa558bcc21a6636
+
+pkgname = python-pyfltk-svn
+
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..99d4ce82d8a6
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,51 @@
+# Maintainer: Kozec (kozec-at-kozec-dot-com)
+# Contributor: TDY <tdy@gmx.com>
+# Contributor: rabyte <rabyte*gmail>
+# Contributor: LukenShiro <lukenshiro@ngi.it>
+
+pkgname=python-pyfltk-svn
+_fullpkgname=${pkgname%-svn}
+_pkgname=${_fullpkgname#python-}
+pkgver=r532
+pkgrel=1
+pkgdesc="A Python wrapper for the Fast Light Tool Kit library"
+arch=('x86_64')
+url="http://pyfltk.sourceforge.net/"
+license=('LGPL')
+depends=('fltk>=1.3.5' 'python>=3.7' 'glu')
+makedepends=('swig>=3.0.12' 'python-setuptools' 'subversion')
+provides=("${_fullpkgname}")
+conflicts=("${_fullpkgname}")
+source=("svn://svn.code.sf.net/p/pyfltk/code/trunk"
+ "pyfltk_swig_silence_warnings.patch"
+ "pyfltk_python3.patch"
+ "pyfltk_remove_percent_format.patch")
+sha1sums=('SKIP'
+ '11aa48bcdc21b77e4ea53f986352d85eedf2a900'
+ '8c88777b373d7a72f4a0cdbb264f4371931dbb7b'
+ 'a105e1ca3592c880634503c9faa558bcc21a6636')
+
+pkgver() {
+ cd "$srcdir/trunk"
+ printf "r%s" "$(svnversion | tr -d 'A-z')"
+}
+
+prepare() {
+ cd "$srcdir/trunk/$_pkgname"
+ patch -p3 -i "${srcdir}/pyfltk_swig_silence_warnings.patch"
+ patch -p3 -i "${srcdir}/pyfltk_python3.patch"
+ patch -p3 -i "${srcdir}/pyfltk_remove_percent_format.patch"
+}
+
+build() {
+ cd "$srcdir/trunk/$_pkgname/python"
+ python MakeSwig.py
+}
+
+package() {
+ cd "$srcdir/trunk/$_pkgname/util"
+ python setup.py install --root="${pkgdir}/" --optimize=1
+
+ cd "$srcdir/trunk/$_pkgname"
+ python setup.py install --root="${pkgdir}/" --optimize=1
+}
diff --git a/pyfltk_python3.patch b/pyfltk_python3.patch
new file mode 100644
index 000000000000..ea68621bc04f
--- /dev/null
+++ b/pyfltk_python3.patch
@@ -0,0 +1,860 @@
+--- a/trunk/pyfltk/python/MakeSwig.py 2020-10-16 13:17:11.787141444 -0400
++++ b/trunk/pyfltk/python/MakeSwig.py 2020-10-16 18:58:04.580305746 -0400
+@@ -32,6 +32,7 @@
+ #print(result)
+ if len(result) > 0:
+ p_inc = map(lambda x: x.strip(), result[0].split(' '))
++# p_inc = [x.strip() for x in result[0].split(' ')]
+ for item in p_inc:
+ #if string.find(item, '-I') == 0:
+ if item.find('-I') == 0:
+--- a/trunk/pyfltk/python/updateInits.py 2020-10-08 13:22:56.982973535 -0400
++++ b/trunk/pyfltk/python/updateInits.py 2020-10-16 11:46:38.496560571 -0400
+@@ -65,7 +65,7 @@
+
+ ifl = open(in_file, 'r')
+ for line in ifl.readlines():
+- exec line
++ exec(line)
+
+ # write the footer
+ ofl.write("}\n")
+--- a/trunk/pyfltk/setup.py 2020-10-08 13:22:56.136300686 -0400
++++ b/trunk/pyfltk/setup.py 2020-10-16 20:24:04.518331788 -0400
+@@ -197,6 +197,7 @@
+ print("No compile flags found!")
+ else:
+ inc_list = map(lambda x: x.strip(), result[0].split(' '))
++# inc_list = [x.strip() for x in result[0].split(' ')]
+
+ for inc in inc_list:
+ if inc[:2] == '-I':
+@@ -211,6 +212,7 @@
+ print("No link flags found!")
+ else:
+ lib_list = map(lambda x: x.strip(), result[0].split(' '))
++# lib_list = [x.strip() for x in result[0].split(' ')]
+
+ for lib in lib_list:
+ if lib[:2] == '-l':
+--- a/trunk/pyfltk/test/PyAppWithGUI/app.py 2020-10-08 13:22:56.166300905 -0400
++++ b/trunk/pyfltk/test/PyAppWithGUI/app.py 2020-10-10 11:43:29.933237150 -0400
+@@ -7,7 +7,7 @@
+ import sys
+
+ def theBrowserCallback( ptr ):
+- print "selected:"+str(gui.theBrowser.text(gui.theBrowser.value()))
++ print("selected:"+str(gui.theBrowser.text(gui.theBrowser.value())))
+
+ def theOKCallback(ptr):
+ sys.exit()
+--- a/trunk/pyfltk/test/arc.py 2020-10-08 13:22:56.146300759 -0400
++++ b/trunk/pyfltk/test/arc.py 2020-10-10 12:53:59.901605322 -0400
+@@ -71,14 +71,14 @@
+ fl_pop_matrix()
+ fl_pop_clip()
+ except:
+- print('uncaught!', sys.exc_type, sys.exc_value)
++ print('uncaught!', sys.exc_info()[0], sys.exc_info()[1])
+ return None
+
+
+
+ def slider_cb(ptr, v):
+ global d
+- args[long(v)] = ptr.value()
++ args[int(v)] = ptr.value()
+ d.redraw()
+
+
+--- a/trunk/pyfltk/test/cube.py 2020-10-08 13:22:56.156300832 -0400
++++ b/trunk/pyfltk/test/cube.py 2020-10-10 14:31:04.535282880 -0400
+@@ -74,7 +74,7 @@
+ gl_draw("Cube: flat", -4.5, -4.5)
+ glEnable(GL_DEPTH_TEST)
+ except:
+- print("Exception: ", sys.exc_type, sys.exc_value)
++ print("Exception: ", sys.exc_info()[0], sys.exc_info()[1])
+
+ # the cube definition
+ v0 = [0.0, 0.0, 0.0]
+--- a/trunk/pyfltk/test/subwindow.py 2020-10-08 13:22:56.146300759 -0400
++++ b/trunk/pyfltk/test/subwindow.py 2020-10-10 14:49:51.137075639 -0400
+@@ -50,7 +50,7 @@
+ self.color(FL_RED)
+ self.redraw()
+ except:
+- print('uncaught!', sys.exc_type, sys.exc_value)
++ print('uncaught!', sys.exc_info()[0], sys.exc_info()[1])
+ return 1
+ elif e == FL_LEAVE:
+ try:
+@@ -58,7 +58,7 @@
+ self.color(FL_GRAY)
+ self.redraw()
+ except:
+- print('uncaught!', sys.exc_type, sys.exc_value)
++ print('uncaught!', sys.exc_info()[0], sys.exc_info()[1])
+ return 1
+ else:
+ return 0
+--- a/trunk/pyfltk/test/tree.py 2020-10-08 13:22:56.156300832 -0400
++++ b/trunk/pyfltk/test/tree.py 2020-10-16 21:16:41.245394864 -0400
+@@ -551,10 +551,10 @@
+
+
+ def cb_loaddb_button(loaddb_button, tree):
+- filename = fl_file_chooser("Select a Preferences style Database", "Preferences(*.prefs)", long(0))
++ filename = fl_file_chooser("Select a Preferences style Database", "Preferences(*.prefs)", int(0))
+ if len(filename) > 0:
+ tree.clear()
+- prefs = Fl_Preferences(filename, long(0), long(0))
++ prefs = Fl_Preferences(filename, int(0), int(0))
+ tree.load(prefs)
+ tree.redraw()
+
+@@ -565,7 +565,7 @@
+ tree.insert_above(item, "AaaAaa")
+ tree.insert_above(item, "BbbBbb")
+ tree.insert_above(item, "CccCcc")
+- item = item.next()
++ item = next(item)
+ tree.redraw()
+
+ def cb_rebuildtree_button(rebuildtree_button, tree):
+@@ -607,7 +607,7 @@
+ break
+ item = tree.first()
+ else:
+- item = item.next()
++ item = next(item)
+ tree.redraw()
+
+ def cb_clearall_button(clearall_button, tree):
+--- a/trunk/pyfltk/util/flconvert/Code_py.py 2020-10-08 13:22:59.012988363 -0400
++++ b/trunk/pyfltk/util/flconvert/Code_py.py 2020-10-16 22:25:34.274178386 -0400
+@@ -204,13 +204,13 @@
+ def getGlobalNamesFromObject(self, obj, funcName):
+ # returns list of global (name, type, functionNameWhereDeclared) tuples
+ globalNames = []
+- if obj.has_key('name') and obj['name'] != '':
+- if obj['options'].has_key('classDef'):
++ if 'name' in obj and obj['name'] != '':
++ if 'classDef' in obj['options']:
+ objType = obj['options']['classDef']
+ else:
+ objType = obj['class']
+ globalNames.append( (obj['name'], objType, funcName) )
+- if obj.has_key('objects'):
++ if 'objects' in obj:
+ for subObj in obj['objects']:
+ globalNames = globalNames + \
+ self.getGlobalNamesFromObject(subObj, funcName)
+@@ -221,12 +221,12 @@
+ # returns list of 'extra code' lines that are import statements
+ # present in the object or its children
+ importStatements = []
+- if obj['options'].has_key('codeDef'):
++ if 'codeDef' in obj['options']:
+ codeDefs = obj['options']['codeDef']
+ for lineOfCode in codeDefs:
+ if self.importStatementRegex.match(lineOfCode):
+ importStatements.append( (lineOfCode, funcName) )
+- if obj.has_key('objects'):
++ if 'objects' in obj:
+ for subObj in obj['objects']:
+ importStatements = importStatements + \
+ self.getImportsFromObject(subObj, funcName)
+@@ -245,7 +245,7 @@
+
+
+ def doClass(self, aClass, tabLevel):
+- if aClass.has_key('base'):
++ if 'base' in aClass:
+ self.out.write(ts(tabLevel)+"class %s(%s):\n\n" \
+ %(aClass['name'], aClass['base']))
+ else:
+@@ -370,9 +370,9 @@
+ }
+
+
+- for key in opts.keys():
+- if self.binaryOptionSet.has_key(key):
+- if optionValueFix.has_key(opts[key]):
++ for key in iter(opts):
++ if key in self.binaryOptionSet:
++ if opts[key] in optionValueFix:
+ tags["value"]=optionValueFix[opts[key]]
+ else:
+ tags["value"]=opts[key]
+@@ -392,7 +392,7 @@
+ # are replaced by these values
+ tags = { "name":name, "value":"TheNode'sAttribute" }
+
+- if self.binaryOptionSet.has_key("resizable") and "resizable" in opts.keys():
++ if "resizable" in self.binaryOptionSet and "resizable" in opts:
+ tags["value"]=opts["resizable"]
+ self.out.write( ts(tabLevel)+"Fl_Group.current()." + self.binaryOptionSet["resizable"]%tags+"\n")
+
+@@ -417,7 +417,7 @@
+ opts = obj['options']
+ name = self.getObjectName( obj, childLevel, childNumber )
+
+- if opts.has_key('classDef'):
++ if 'classDef' in opts:
+ type = opts['classDef']
+ else:
+ type = obj['class']
+@@ -426,7 +426,7 @@
+ #this may change the object's class
+ # guard to avoid spurious comments
+ typeDefProcessed=0
+- if opts.has_key('typeDef'):
++ if 'typeDef' in opts:
+ try:
+ newtype = typeDefMappings[type][opts['typeDef']][0]
+ if newtype != "":
+@@ -443,7 +443,7 @@
+ xywh = opts['xywhDef']
+ constructorParams = "%s, %s, %s, %s"%(xywh[0], xywh[1],
+ xywh[2], xywh[3])
+- if opts.has_key('labelDef'):
++ if 'labelDef' in opts:
+ # take care of multiline labels
+ constructorParams = '%s, """%s"""'%(constructorParams, opts['labelDef'])
+
+@@ -452,7 +452,7 @@
+
+ #handle the special cases of types in the class options section
+ #add the 'type' call if needed - becuase not all are subclasses
+- if opts.has_key('typeDef') and typeDefProcessed==0:
++ if 'typeDef' in opts and typeDefProcessed==0:
+ try:
+ typeCall = typeDefMappings[type][opts['typeDef']][1]
+ if typeCall != "":
+@@ -471,7 +471,7 @@
+ #self.out.write( ts(tabLevel)+name+".thisown = 0\n")
+
+ #recurse and process child objects
+- if obj.has_key('objects'):
++ if 'objects' in obj:
+ #for o in obj['objects']:
+ # self.doObject(o, tabLevel)
+ for i in range(0, len(obj['objects']), 1):
+@@ -483,7 +483,7 @@
+
+
+ #generate 'extra code' if it is not some form of import statement
+- if opts.has_key("codeDef"):
++ if "codeDef" in opts:
+ codeDefs = opts["codeDef"]
+ for lineOfCode in codeDefs:
+ if (not self.importStatementRegex.match(lineOfCode)):
+@@ -528,8 +528,8 @@
+ xywh = opts['xywhDef']
+ constructorParams = "%s, %s, %s, %s"%(xywh[0], xywh[1],
+ xywh[2], xywh[3])
+- if opts.has_key('labelDef'):
+- constructorParams = '%s, "%s"'%(constructorParams, opts['labelDef'])
++ if 'labelDef' in opts:
++ constructorParams = '%s, """%s"""'%(constructorParams, opts['labelDef'])
+
+ #self.out.write( ts(tabLevel)+name+" = "+type+"("+constructorParams+")\n")
+ self.out.write( ts(tabLevel)+self.attribsPrefix+name+" = "+type+"("+constructorParams+")\n")
+@@ -540,7 +540,7 @@
+ #self.out.write( ts(tabLevel)+name+".thisown = 0\n")
+
+ # generate call to set the menu
+- if obj.has_key('objects') and len(obj['objects'])>0:
++ if 'objects' in obj and len(obj['objects'])>0:
+ #self.out.write("\n"+ts(tabLevel)+"# *hack alert*\n")
+ #self.out.write(ts(tabLevel)+"setMenu( "+name+", (\n")
+ #self.out.write(ts(tabLevel)+name+".copy( (\n")
+@@ -566,12 +566,12 @@
+ # for use in a call to setMenu
+ opts = o['options']
+ label = opts['labelDef']
+- if opts.has_key('shortcutDef'):
++ if 'shortcutDef' in opts:
+ accel = opts['shortcutDef']
+ else:
+ accel = '0'
+
+- if opts.has_key('callbackDef'):
++ if 'callbackDef' in opts:
+ callback = opts['callbackDef']
+ else:
+ callback = '0'
+@@ -579,21 +579,21 @@
+ #handle menu item modifiers
+ #- yes, these hard-coded constants are bad
+ flags = 0
+- if opts.has_key('deactivate'):
++ if 'deactivate' in opts:
+ flags = flags + 1
+- if opts.has_key('value'):
++ if 'value' in opts:
+ flags = flags + 4
+- if opts.has_key('hide'):
++ if 'hide' in opts:
+ flags = flags + 16
+ if o['class'].lower()=='submenu':
+ flags = flags + 64
+- if opts.has_key('divider'):
++ if 'divider' in opts:
+ flags = flags + 128
+
+ self.out.write('%s("%s", %s, %s, 0, %d), \n'%( prefix, label,
+ accel, callback, flags) )
+
+- if o.has_key('objects'):
++ if 'objects' in o:
+ for childObject in o['objects']:
+ self.__dumpMenuSubObject(childObject, prefix+ts(1))
+ self.out.write(prefix+ts(1)+"(None, ),\n")
+@@ -602,13 +602,13 @@
+
+ if __name__ == '__main__':
+
+- from FlScanner import FlScanner
+- from FlParser import FlParser
+- from FlPreProcessor import FlPreProcessor
+- from FlParseTreeConverter import FlParseTreeConverter
+- import cStringIO
+- from util import *
+- from FlParseTreeConverter import dumpAstTree
++ from .FlScanner import FlScanner
++ from .FlParser import FlParser
++ from .FlPreProcessor import FlPreProcessor
++ from .FlParseTreeConverter import FlParseTreeConverter
++ import io
++ from .util import *
++ from .FlParseTreeConverter import dumpAstTree
+
+ try:
+ import sys
+@@ -618,25 +618,25 @@
+ f = open(filename)
+ input = f.read()
+
+- tempFile = cStringIO.StringIO()
++ tempFile = io.StringIO()
+
+ preProcessor = FlPreProcessor()
+ preProcessor.tokenize(input, tempFile)
+ input = tempFile.getvalue()
+
+- print "PreProcesssed:\n"+input
+- print
++ print("PreProcesssed:\n"+input)
++ print()
+ scanner = FlScanner()
+ tokens = scanner.tokenize(input)
+
+ dumpSequence(tokens, "Tokens:")
+
+- print
+- print "About to Parse."
++ print()
++ print("About to Parse.")
+ parser = FlParser()
+ parseTree = parser.parse(tokens)
+
+- print "\n\nParse Tree:"
++ print("\n\nParse Tree:")
+ dumpAstTree(parseTree)
+
+ ptc = FlParseTreeConverter(parseTree)
+--- a/trunk/pyfltk/util/flconvert/DumpTree.py 2020-10-08 13:22:59.176322890 -0400
++++ b/trunk/pyfltk/util/flconvert/DumpTree.py 2020-10-08 16:37:23.666516695 -0400
+@@ -1,7 +1,7 @@
+-from token import Token
+-from ast import AST
++from .token import Token
++from .ast import AST
+ #from generic import GenericASTTraversal
+-from spark import GenericASTTraversal
++from .spark import GenericASTTraversal
+
+ class PyCodeGenerator(GenericASTTraversal):
+ def __init__(self, ast):
+@@ -23,8 +23,8 @@
+ def dump(s):
+ sys.stdout.write(s)
+
+- from FlScanner import FlScanner
+- from FlParser import FlParser
++ from .FlScanner import FlScanner
++ from .FlParser import FlParser
+ #filename = sys.argv[1]
+ filename = "test.fl"
+ f = open(filename)
+--- a/trunk/pyfltk/util/flconvert/FlParseTreeConverter.py 2020-10-08 13:22:59.172989532 -0400
++++ b/trunk/pyfltk/util/flconvert/FlParseTreeConverter.py 2020-10-16 10:55:08.692791676 -0400
+@@ -6,21 +6,21 @@
+ # Last Modified: 1999:06:10 15:35:33
+ #
+
+-from ast import AST
++from .ast import AST
+ #from generic import GenericASTTraversal
+-from spark import GenericASTTraversal
++from .spark import GenericASTTraversal
+ #from util import *
+ #from flconvert import *
+
+
+ def dn(l,n):
+ if (l!=""):
+- print l+":"
+- for i in xrange(0, len(n), 1):
++ print(l+":")
++ for i in range(0, len(n), 1):
+ try:
+- print " %d:%s = %s"%(i, n[i].type, str(n[i].attr))
++ print(" %d:%s = %s"%(i, n[i].type, str(n[i].attr)))
+ except:
+- print " %d:%s"%(i, n[i].type)
++ print(" %d:%s"%(i, n[i].type))
+
+
+
+@@ -91,7 +91,7 @@
+
+ def n_ld1_exit(self, node):
+ #dn("n_ld1", node)
+- print "n_ld1_exit"
++ print("n_ld1_exit")
+ node.attr = ""
+ for n in node:
+ if hasattr(n, "attr"):
+@@ -393,10 +393,10 @@
+ def dump(s):
+ sys.stdout.write(s)
+
+- from FlScanner import FlScanner
+- from FlParser import FlParser
+- from FlPreProcessor import FlPreProcessor
+- import cStringIO
++ from .FlScanner import FlScanner
++ from .FlParser import FlParser
++ from .FlPreProcessor import FlPreProcessor
++ import io
+
+ try:
+ filename = sys.argv[1]
+@@ -405,7 +405,7 @@
+ f = open(filename)
+ input = f.read()
+
+- tempFile = cStringIO.StringIO()
++ tempFile = io.StringIO()
+
+ preProcessor = FlPreProcessor()
+ preProcessor.tokenize(input, tempFile)
+@@ -424,10 +424,10 @@
+ #print str(defs)
+ #print
+ #dumpTree(defs)
+- print len(codeGen.defStack)
++ print(len(codeGen.defStack))
+
+ def dd(ddef, sp):
+- print sp + str(ddef)
++ print(sp + str(ddef))
+
+ for d in codeGen.defStack:
+ dd(d,"")
+--- a/trunk/pyfltk/util/flconvert/FlParser.py 2020-10-08 13:22:59.172989532 -0400
++++ b/trunk/pyfltk/util/flconvert/FlParser.py 2020-10-08 16:37:24.823195919 -0400
+@@ -2,9 +2,9 @@
+
+ #from generic import GenericParser
+ #from token import Token
+-from ast import AST
++from .ast import AST
+ #from generic import GenericASTBuilder
+-from spark import GenericASTBuilder
++from .spark import GenericASTBuilder
+ #
+ #from flconvert import *
+
+--- a/trunk/pyfltk/util/flconvert/FlPreProcessor.py 2020-10-08 13:22:59.176322890 -0400
++++ b/trunk/pyfltk/util/flconvert/FlPreProcessor.py 2020-10-08 16:37:25.243200479 -0400
+@@ -3,7 +3,7 @@
+ #
+ #from flconvert import *
+ #from generic import GenericScanner
+-from spark import GenericScanner
++from .spark import GenericScanner
+ import re
+
+ codeDefRegex = re.compile("code[0-4]?$")
+--- a/trunk/pyfltk/util/flconvert/FlScanner.py 2020-10-08 13:22:59.009655005 -0400
++++ b/trunk/pyfltk/util/flconvert/FlScanner.py 2020-10-08 16:37:25.669871778 -0400
+@@ -4,8 +4,8 @@
+ #from token import Token
+ #from flconvert import *
+ #from generic import GenericScanner
+-from spark import GenericScanner
+-from token import Token
++from .spark import GenericScanner
++from .token import Token
+
+ import re
+
+@@ -91,6 +91,6 @@
+ import sys
+ filename = sys.argv[1]
+ f = open(filename)
+- print scan(f)
++ print(scan(f))
+
+
+--- a/trunk/pyfltk/util/flconvert/__init__.py 2020-10-08 13:22:59.176322890 -0400
++++ b/trunk/pyfltk/util/flconvert/__init__.py 2020-10-08 16:37:26.076542860 -0400
+@@ -1,10 +1,10 @@
+-from ast import *
+-from spark import *
+-from token import *
+-from util import *
+-from Code_py import *
+-from FlParseTreeConverter import *
+-from FlParser import *
+-from FlPreProcessor import *
+-from FlScanner import *
++from .ast import *
++from .spark import *
++from .token import *
++from .util import *
++from .Code_py import *
++from .FlParseTreeConverter import *
++from .FlParser import *
++from .FlPreProcessor import *
++from .FlScanner import *
+
+--- a/trunk/pyfltk/util/flconvert/spark.py 2020-10-08 13:22:59.176322890 -0400
++++ b/trunk/pyfltk/util/flconvert/spark.py 2020-10-16 12:17:47.771154797 -0400
+@@ -31,7 +31,7 @@
+ for b in c.__bases__:
+ classlist.append(b)
+ for name in dir(c):
+- if not namedict.has_key(name):
++ if name not in namedict:
+ namelist.append(name)
+ namedict[name] = 1
+ return namelist
+@@ -42,7 +42,7 @@
+ self.re = re.compile(pattern, re.VERBOSE)
+
+ self.index2func = {}
+- for name, number in self.re.groupindex.items():
++ for name, number in iter(self.re.groupindex.items()):
+ self.index2func[number-1] = getattr(self, 't_' + name)
+
+ def makeRE(self, name):
+@@ -60,7 +60,7 @@
+ return string.join(rv, '|')
+
+ def error(self, s, pos):
+- print "Lexical error at position %s" % pos
++ print("Lexical error at position %s" % pos)
+ raise SystemExit
+
+ def tokenize(self, s):
+@@ -73,7 +73,7 @@
+
+ groups = m.groups()
+ for i in range(len(groups)):
+- if groups[i] and self.index2func.has_key(i):
++ if groups[i] and i in self.index2func:
+ self.index2func[i](groups[i])
+ pos = m.end()
+
+@@ -114,7 +114,7 @@
+
+ rule, fn = self.preprocess(rule, func)
+
+- if self.rules.has_key(lhs):
++ if lhs in self.rules:
+ self.rules[lhs].append(rule)
+ else:
+ self.rules[lhs] = [ rule ]
+@@ -145,9 +145,9 @@
+ union = {}
+ self.first = {}
+
+- for rulelist in self.rules.values():
++ for rulelist in iter(self.rules.values()):
+ for lhs, rhs in rulelist:
+- if not self.first.has_key(lhs):
++ if lhs not in self.first:
+ self.first[lhs] = {}
+
+ if len(rhs) == 0:
+@@ -155,14 +155,14 @@
+ continue
+
+ sym = rhs[0]
+- if not self.rules.has_key(sym):
++ if sym not in self.rules:
+ self.first[lhs][sym] = 1
+ else:
+ union[(sym, lhs)] = 1
+ changes = 1
+ while changes:
+ changes = 0
+- for src, dest in union.keys():
++ for src, dest in iter(union):
+ destlen = len(self.first[dest])
+ self.first[dest].update(self.first[src])
+ if len(self.first[dest]) != destlen:
+@@ -179,7 +179,7 @@
+ return None
+
+ def error(self, token):
+- print "Syntax error at or near `%s' token" % token
++ print("Syntax error at or near `%s' token" % token)
+ raise SystemExit
+
+ def parse(self, tokens):
+@@ -190,7 +190,7 @@
+ if self.ruleschanged:
+ self.makeFIRST()
+
+- for i in xrange(len(tokens)):
++ for i in range(len(tokens)):
+ states[i+1] = []
+
+ if states[i] == []:
+@@ -201,7 +201,7 @@
+
+ if i < len(tokens)-1 or states[i+1] != [(self.startRule, 2, 0)]:
+ del tokens[-1]
+- _dumptokens(tokens, states)
++ _dumptokens(tokens, states)
+ self.error(tokens[i-1])
+ rv = self.buildTree(tokens, tree, ((self.startRule, 2, 0), i+1))
+ del tokens[-1]
+@@ -246,7 +246,7 @@
+ #
+ # A -> a . B (predictor)
+ #
+- if self.rules.has_key(nextSym):
++ if nextSym in self.rules:
+ #
+ # Work on completer step some more; for rules
+ # with empty RHS, the "parent state" is the
+@@ -254,7 +254,7 @@
+ # so the Earley items the completer step needs
+ # may not all be present when it runs.
+ #
+- if needsCompletion.has_key(nextSym):
++ if nextSym in needsCompletion:
+ new = (rule, pos+1, parent)
+ olditem_i = needsCompletion[nextSym]
+ if new not in state:
+@@ -266,7 +266,7 @@
+ #
+ # Has this been predicted already?
+ #
+- if predicted.has_key(nextSym):
++ if nextSym in predicted:
+ continue
+ predicted[nextSym] = 1
+
+@@ -290,15 +290,15 @@
+ state.append(new)
+ continue
+ prhs0 = prhs[0]
+- if not self.rules.has_key(prhs0):
++ if prhs0 not in self.rules:
+ if prhs0 != ttype:
+ continue
+ else:
+ state.append(new)
+ continue
+ first = self.first[prhs0]
+- if not first.has_key(None) and \
+- not first.has_key(ttype):
++ if None not in first and \
++ ttype not in first:
+ continue
+ state.append(new)
+ continue
+@@ -311,7 +311,7 @@
+ #
+ prhs = prule[1]
+ if len(prhs) > 0 and \
+- not self.rules.has_key(prhs[0]) and \
++ prhs[0] not in self.rules and \
+ token != prhs[0]:
+ continue
+ state.append((prule, 0, i))
+@@ -333,7 +333,7 @@
+
+ while pos > 0:
+ want = ((rule, pos, parent), state)
+- if not tree.has_key(want):
++ if want not in tree:
+ #
+ # Since pos > 0, it didn't come from closure,
+ # and if it isn't in tree[], then there must
+@@ -389,7 +389,8 @@
+ sortlist.append((len(rhs), name))
+ name2index[name] = i
+ sortlist.sort()
+- list = map(lambda (a,b): b, sortlist)
++ list = list(map(lambda itm: itm[1], sortlist))
++# list = [a_b[1] for a_b in sortlist]
+ return children[name2index[self.resolve(list)]]
+
+ def resolve(self, list):
+@@ -554,22 +555,22 @@
+
+ def _dump(tokens, states):
+ for i in range(len(states)):
+- print 'state', i
++ print('state', i)
+ for (lhs, rhs), pos, parent in states[i]:
+- print '\t', lhs, '::=',
+- print string.join(rhs[:pos]),
+- print '.',
+- print string.join(rhs[pos:]),
+- print ',', parent
++ print('\t', lhs, '::=', end=' ')
++ print(string.join(rhs[:pos]), end=' ')
++ print('.', end=' ')
++ print(string.join(rhs[pos:]), end=' ')
++ print(',', parent)
+ if i < len(tokens):
+- print
+- print 'token', str(tokens[i])
+- print
++ print()
++ print('token', str(tokens[i]))
++ print()
+
+ #fewer messages
+ def _dumptokens(tokens, states):
+ for i in range(len(states)):
+- print 'state', i
++ print('state', i)
+ if i < len(tokens):
+- print 'token', str(tokens[i])
++ print('token', str(tokens[i]))
+
+--- a/trunk/pyfltk/util/flconvert/util.py 2020-10-08 13:22:59.179656247 -0400
++++ b/trunk/pyfltk/util/flconvert/util.py 2020-10-10 09:34:59.513132739 -0400
+@@ -4,7 +4,7 @@
+ s = s + ", " + str(node.attr) + ")"
+ else:
+ s = s + ")"
+- print s
++ print(s)
+ for n in node:
+ dumpAstTree(n, depth + " ")
+
+@@ -16,47 +16,47 @@
+ dumpFunc(func)
+
+ def dumpFunc(func):
+- print "Function: " + func['name']
++ print("Function: " + func['name'])
+ t = makeBlanks(1)
+- print t + "Input Paramaters:"
++ print(t + "Input Paramaters:")
+ for i in func['inputParams']:
+- print makeBlanks(2)+str(i)
+- print t + "Options:"
++ print(makeBlanks(2)+str(i))
++ print(t + "Options:")
+ for i in func['options']:
+- print makeBlanks(2)+str(i)
+- print t + "Functions Child Objects:"
++ print(makeBlanks(2)+str(i))
++ print(t + "Functions Child Objects:")
+ for i in func['objects']:
+ dumpObject( 2, i)
+
+ def dumpObject(depth, obj):
+ t = makeBlanks(depth)
+- print t + "Object:"
+- for i in obj.keys():
++ print(t + "Object:")
++ for i in iter(obj):
+ if i == "options":
+- print makeBlanks(depth+1)+"Options:"
++ print(makeBlanks(depth+1)+"Options:")
+ opts = obj[i]
+- for o in opts.keys():
+- print makeBlanks(depth+2)+o+" : "+str(opts[o])
++ for o in iter(opts):
++ print(makeBlanks(depth+2)+o+" : "+str(opts[o]))
+ else:
+ if i == 'objects':
+- print makeBlanks(depth+1)+"Child Objects:"
++ print(makeBlanks(depth+1)+"Child Objects:")
+ for o in obj[i]:
+ dumpObject(depth+2, o)
+ else:
+- print makeBlanks(depth+1)+i+" : "+str(obj[i])
++ print(makeBlanks(depth+1)+i+" : "+str(obj[i]))
+
+
+ def dumpSequence(sequence, label=""):
+- print label
++ print(label)
+ for s in sequence:
+- print str(s)
+- print
++ print(str(s))
++ print()
+
+
+
+ def makeBlanks(depth):
+ r = ""
+- for i in xrange(0, depth, 1):
++ for i in range(0, depth, 1):
+ r = r + " "
+ return r
+
+--- a/trunk/pyfltk/util/generateFLTKList.py 2020-10-08 13:22:59.186322963 -0400
++++ b/trunk/pyfltk/util/generateFLTKList.py 2020-10-10 09:08:24.351803955 -0400
+@@ -70,7 +70,7 @@
+
+ def printClassAndChildren(c, spacing=""):
+ """ pretty prints a class and its children """
+- print spacing+c.name
++ print(spacing+c.name)
+ for ch in c.children:
+ printClassAndChildren(ch, spacing+" ")
+
+@@ -94,19 +94,19 @@
+ if (__name__=="__main__"):
+ import sys
+ if (len(sys.argv) != 2):
+- print
+- print "usage: "+sys.argv[0]+" <path to FLTK headers>"
+- print
+- print " ex: "+sys.argv[0]+" /usr/local/include/FL"
+- print
++ print()
++ print("usage: "+sys.argv[0]+" <path to FLTK headers>")
++ print()
++ print(" ex: "+sys.argv[0]+" /usr/local/include/FL")
++ print()
+ else:
+ classList = {}
+ lines = generateListFromHeaders(sys.argv[1])
+ parseLines(lines, classList)
+
+- for key in classList.keys():
++ for key in iter(classList):
+ c = classList[key]
+ if (not c.parent):
+ printClassAndChildren(c)
+- print
++ print()
+
diff --git a/pyfltk_remove_percent_format.patch b/pyfltk_remove_percent_format.patch
new file mode 100644
index 000000000000..dc603c40d8d8
--- /dev/null
+++ b/pyfltk_remove_percent_format.patch
@@ -0,0 +1,955 @@
+--- a/trunk/pyfltk/python/MakeSwig.py 2020-10-16 18:58:04.580305746 -0400
++++ b/trunk/pyfltk/python/MakeSwig.py 2020-10-16 14:16:12.694560622 -0400
+@@ -22,7 +22,7 @@
+ include = ['-I/usr/include']
+ try:
+ fltk_dir = os.environ['FLTK_HOME']
+- include.insert(0, "-I%s"%fltk_dir)
++ include.insert(0, f"-I{fltk_dir}")
+ except:
+ print("Using default location for FLTK!")
+ if is_msys_mingw():
+@@ -48,7 +48,7 @@
+ versionIdentifier = ""
+ if sys.version >= "3.0":
+ versionIdentifier = "-DPYTHON3 -py3"
+- cmd_line = "swig -w302 -w312 -w325 -w362 -w389 -w401 -w473 -w509 -I../swig %s -DFL_EXPORT -DPYTHON %s -c++ -python -shadow -fastdispatch -o fltk_wrap.cpp ../swig/fltk.i "%(add_incl, versionIdentifier)
++ cmd_line = f"swig -w302 -w312 -w325 -w362 -w389 -w401 -w473 -w509 -I../swig {add_incl} -DFL_EXPORT -DPYTHON {versionIdentifier} -c++ -python -shadow -fastdispatch -o fltk_wrap.cpp ../swig/fltk.i "
+ # command line for swig-1.3.27
+ # cmd_line = "swig -w312 -w451 -w473 -I../swig %s -DFL_EXPORT -DPYTHON -c++ -python -shadow -modern -dirprot -o fltk_wrap.cpp ../swig/fltk.i "%add_incl
+ if is_msys_mingw():
+@@ -62,13 +62,13 @@
+ tmpf = open(tmpfn, "w+b")
+ tmpf.write(cmd_line)
+ tmpf.close()
+- r = os.system("sh %s" % tmpfn)
++ r = os.system(f"sh {tmpfn}")
+
+ os.remove(tmpfn)
+ if r != 0:
+- raise DistutilsExecError("command '%s' failed with exit status :%d: command was :%s:. " % (cmd[0], r, cmpl))
++ raise DistutilsExecError(f"command '{cmd[0]}' failed with exit status :{r}: command was :{cmpl}:. ")
+
+- print("return value of the command is :%s:" % r)
++ print(f"return value of the command is :{r}:")
+ else:
+ print(cmd_line)
+ os.system(cmd_line)
+--- a/trunk/pyfltk/python/updateInits.py 2020-10-16 11:46:38.496560571 -0400
++++ b/trunk/pyfltk/python/updateInits.py 2020-10-08 19:15:34.799056263 -0400
+@@ -15,46 +15,46 @@
+
+ def mapInit_Old(name, owns, virtual):
+ # constructor
+- line1 = "_swig_setattr(self, %s, 'this', apply(_fltk.new_%s, args))" % (name, name)
+- line2 = "_swig_setattr(self, %s, 'thisown', %d)" % (name, owns)
++ line1 = f"_swig_setattr(self, {name}, 'this', apply(_fltk.new_{name}, args))"
++ line2 = f"_swig_setattr(self, {name}, 'thisown', {owns})"
+ # only for virtual classes
+ if virtual != 0:
+ line3 = "self.registerSelf(self)"
+
+ # prepare the output
+- ofl.write("# override the implementation of the %s wrapper\n" % name)
+- ofl.write("def __%sInit(self,*args):\n" % name)
+- ofl.write(" %s\n" % line1)
+- ofl.write(" %s\n" % line2)
++ ofl.write(f"# override the implementation of the {name} wrapper\n")
++ ofl.write(f"def __{name}Init(self,*args):\n")
++ ofl.write(f" {line1}\n")
++ ofl.write(f" {line2}\n")
+ if virtual != 0:
+- ofl.write(" %s\n" % line3)
+- ofl.write("%s.__init__ = __%sInit\n" % (name, name))
+- ofl.write("# end of the %s wrapper\n\n" % name)
++ ofl.write(f" {line3}\n")
++ ofl.write(f"{name}.__init__ = __{name}Init\n")
++ ofl.write(f"# end of the {name} wrapper\n\n")
+
+ def mapInit(name, owns, virtual):
+ lines = []
+ # constructor
+ # only for director classes
+ if virtual == 2:
+- lines.append("if self.__class__ == %s:"%name)
++ lines.append(f"if self.__class__ == {name}:")
+ lines.append(" args = (None,) + args")
+ lines.append("else:")
+ lines.append(" args = (self,) + args")
+- lines.append("newobj = _fltk.new_%s(*args)"%name)
++ lines.append(f"newobj = _fltk.new_{name}(*args)")
+ lines.append("self.this = newobj.this")
+- lines.append("self.thisown = %d"%owns)
++ lines.append(f"self.thisown = {owns}")
+ lines.append("del newobj.thisown")
+ # only for virtual classes
+ if virtual == 1:
+ lines.append("self.registerSelf(self)")
+
+ # prepare the output
+- ofl.write("# override the implementation of the %s wrapper\n" % name)
+- ofl.write("def __%sInit(self,*args):\n" % name)
++ ofl.write(f"# override the implementation of the {name} wrapper\n")
++ ofl.write(f"def __{name}Init(self,*args):\n")
+ for line in lines:
+- ofl.write(" %s\n" % line)
+- ofl.write("%s.__init__ = __%sInit\n" % (name, name))
+- ofl.write("# end of the %s wrapper\n\n" % name)
++ ofl.write(f" {line}\n")
++ ofl.write(f"{name}.__init__ = __{name}Init\n")
++ ofl.write(f"# end of the {name} wrapper\n\n")
+
+
+ if __name__ == '__main__':
+--- a/trunk/pyfltk/setup.py 2020-10-16 20:24:04.518331788 -0400
++++ b/trunk/pyfltk/setup.py 2020-10-14 11:05:22.555152377 -0400
+@@ -108,7 +108,7 @@
+ lib_dir_list = [fltk_lib_dir, '/usr/lib']
+ lib_list = ["fltk"]
+ elif sys.platform in ['freebsd4','freebsd5','freebsd6','freebsd7', 'sunos5']:
+- print("Building for: %s"%sys.platform)
++ print(f"Building for: {sys.platform}")
+ def_list = [('UNIX', '1')]
+ lib_dir_list = [fltk_lib_dir,'/usr/X11R6/lib','/usr/lib']
+ lib_list = ["fltk"]
+@@ -168,21 +168,21 @@
+ if isVerbose:
+ print("Checking fltk-config using FLTK_HOME")
+ fltk_dir = os.environ['FLTK_HOME']
+- ver_cmd = "sh %s/fltk-config --version"%fltk_dir
+- inc_cmd = "sh %s/fltk-config --cxxflags %s"%(fltk_dir, var_string)
+- #lib_cmd = "sh %s/fltk-config --use-gl --use-glut --use-images --use-forms --ldflags"%fltk_dir
+- lib_cmd = "sh %s/fltk-config --ldflags %s"%(fltk_dir, var_string)
++ ver_cmd = f"sh {fltk_dir}/fltk-config --version"
++ inc_cmd = f"sh {fltk_dir}/fltk-config --cxxflags {var_string}"
++ #lib_cmd = f"sh {fltk_dir}/fltk-config --use-gl --use-glut --use-images --use-forms --ldflags"
++ lib_cmd = f"sh {fltk_dir}/fltk-config --ldflags {var_string}"
+ except:
+ if isVerbose:
+ print("Checking fltk-config using default installation")
+ if is_msys_mingw():
+ ver_cmd = "sh fltk-config --version"
+- inc_cmd = "sh fltk-config --cxxflags %s"%var_string
+- lib_cmd = "sh fltk-config --ldflags %s"%var_string
++ inc_cmd = f"sh fltk-config --cxxflags {var_string}"
++ lib_cmd = f"sh fltk-config --ldflags {var_string}"
+ else:
+ ver_cmd = "fltk-config --version"
+- inc_cmd = "fltk-config --cxxflags %s"%var_string
+- lib_cmd = "fltk-config --ldflags %s"%var_string
++ inc_cmd = f"fltk-config --cxxflags {var_string}"
++ lib_cmd = f"fltk-config --ldflags {var_string}"
+
+ # version
+ result = os.popen(ver_cmd).readlines()
+--- a/trunk/pyfltk/test/tree.py 2020-10-16 21:16:41.245394864 -0400
++++ b/trunk/pyfltk/test/tree.py 2020-10-10 13:25:51.489642495 -0400
+@@ -57,7 +57,7 @@
+ return "???"
+
+ def Button_CB(w):
+- print("'%s' button pushed\n"%w.label())
++ print(f"'{w.label()}' button pushed\n")
+
+ def RebuildTree(tree):
+ global but, grp
+@@ -132,7 +132,7 @@
+ # Add 500 items in numerical order
+ tree.sortorder(FL_TREE_SORT_NONE);
+ for t in range(500):
+- s = "500 Items/item %04d"%t
++ s = f"500 Items/item {t:04d}"
+ tree.add(s)
+
+ tree.close("500 Items") # close the 500 items by default
+@@ -150,13 +150,9 @@
+
+ item = tree.callback_item()
+ if item:
+- print("TREE CALLBACK: label='%s' userdata=%ld reason=%s\n"%(
+- item.label(),
+- data,
+- reason_as_name(tree.callback_reason())))
++ print(f"TREE CALLBACK: label='{item.label()}' userdata={data} reason={reason_as_name(tree.callback_reason())}\n")
+ else:
+- print("TREE CALLBACK: reason=%s item=(no item -- probably multiple items were changed at once)\n"%(
+- reason_as_name(tree.callback_reason())))
++ print(f"TREE CALLBACK: reason={reason_as_name(tree.callback_reason())} item=(no item -- probably multiple items were changed at once)\n")
+
+
+ def cb_margintop_slider(margintop_slider, tree):
+@@ -596,7 +592,7 @@
+ msg = item.label()
+ if msg == None or msg == "":
+ msg = "???"
+- print("\t%s\n"%msg)
++ print(f"\t{msg}\n")
+ item = tree.next_selected_item(item)
+
+ def cb_clearselected_button(clearselected_button, tree):
+--- a/trunk/pyfltk/util/flconvert/Code_py.py 2020-10-16 22:25:34.274178386 -0400
++++ b/trunk/pyfltk/util/flconvert/Code_py.py 2020-10-16 22:07:23.494578365 -0400
+@@ -167,7 +167,7 @@
+ self.out.write("# global object names\n")
+ for od in self.getGlobalNames():
+ # (name, type, func)
+- self.out.write("%s = None # type '%s' from '%s()'\n"%od)
++ self.out.write(f"{od[0]} = None # type '{od[1]}' from '{od[2]}()'\n")
+ self.out.write("\n\n")
+
+ #generate the function defs
+@@ -240,25 +240,24 @@
+ # the level of the objects nesting within the function
+ name = obj['name']
+ if (name == ''):
+- name = "o_%d_%d"%(childLevel, childNumber)
++ name = f"o_{childLevel}_{childNumber}"
+ return name
+
+
+ def doClass(self, aClass, tabLevel):
+ if 'base' in aClass:
+- self.out.write(ts(tabLevel)+"class %s(%s):\n\n" \
+- %(aClass['name'], aClass['base']))
++ self.out.write(ts(tabLevel)+f"class {aClass['name']}({aClass['base']}):\n\n")
+ else:
+- self.out.write(ts(tabLevel)+"class %s:\n\n"%(aClass['name']))
++ self.out.write(ts(tabLevel)+f"class {aClass['name']}:\n\n")
+
+ for member in aClass['objects']:
+ self.handlers[member['def_type']]( member, tabLevel+1)
+
+- self.out.write("# end of class %s\n\n"%(aClass['name']))
++ self.out.write(f"# end of class {aClass['name']}\n\n")
+
+
+ def doDeclaration(self, decl, tabLevel):
+- self.out.write("%s%s\n\n"%(ts(tabLevel),decl['code'][1:-1]))
++ self.out.write(f"{ts(tabLevel)}{decl['code'][1:-1]}\n\n")
+
+ def doFunction(self, func, tabLevel):
+ # write Python code for the given function
+@@ -274,7 +273,7 @@
+ if (inputParams != ''):
+ inputParams = inputParams + ", "
+ inputParams = inputParams + ip[0]
+- self.out.write("%sdef %s(%s):\n"%(ts(tabLevel), name, inputParams))
++ self.out.write(f"{ts(tabLevel)}def {name}({inputParams}):\n")
+
+ #write any global declarations
+ # DM - support class attrib generation option
+@@ -441,11 +440,10 @@
+
+
+ xywh = opts['xywhDef']
+- constructorParams = "%s, %s, %s, %s"%(xywh[0], xywh[1],
+- xywh[2], xywh[3])
++ constructorParams = f"{xywh[0]}, {xywh[1]}, {xywh[2]}, {xywh[3]}"
+ if 'labelDef' in opts:
+ # take care of multiline labels
+- constructorParams = '%s, """%s"""'%(constructorParams, opts['labelDef'])
++ constructorParams = '{0}, """{1}"""'.format(constructorParams, opts['labelDef'])
+
+ self.out.write( ts(tabLevel)+self.attribsPrefix+name+" = " + type + \
+ "("+constructorParams+")\n")
+@@ -526,10 +524,9 @@
+ name = self.getObjectName( obj, childLevel, childNumber)
+ type = obj['class']
+ xywh = opts['xywhDef']
+- constructorParams = "%s, %s, %s, %s"%(xywh[0], xywh[1],
+- xywh[2], xywh[3])
++ constructorParams = f"{xywh[0]}, {xywh[1]}, {xywh[2]}, {xywh[3]}"
+ if 'labelDef' in opts:
+- constructorParams = '%s, """%s"""'%(constructorParams, opts['labelDef'])
++ constructorParams = '{0}, """{1}"""'.format(constructorParams, opts['labelDef'])
+
+ #self.out.write( ts(tabLevel)+name+" = "+type+"("+constructorParams+")\n")
+ self.out.write( ts(tabLevel)+self.attribsPrefix+name+" = "+type+"("+constructorParams+")\n")
+@@ -590,8 +587,7 @@
+ if 'divider' in opts:
+ flags = flags + 128
+
+- self.out.write('%s("%s", %s, %s, 0, %d), \n'%( prefix, label,
+- accel, callback, flags) )
++ self.out.write(f'{prefix}("{label}", {accel}, {callback}, 0, {flags}), \n')
+
+ if 'objects' in o:
+ for childObject in o['objects']:
+--- a/trunk/pyfltk/util/flconvert/DumpTree.py 2020-10-08 16:37:23.666516695 -0400
++++ b/trunk/pyfltk/util/flconvert/DumpTree.py 2020-10-16 22:32:46.581564651 -0400
+@@ -8,9 +8,9 @@
+ GenericASTTraversal.__init__(self, ast)
+
+ def default(self, node):
+- dump("%20s"%node.type)
++ dump(f"{node.type:20s}")
+ try:
+- dump(" (%s)"%str(node.attr))
++ dump(f" ({str(node.attr)})")
+ except:
+ pass
+ dump("\n")
+--- a/trunk/pyfltk/util/flconvert/FlParseTreeConverter.py 2020-10-16 10:55:08.692791676 -0400
++++ b/trunk/pyfltk/util/flconvert/FlParseTreeConverter.py 2020-10-10 09:30:08.891716020 -0400
+@@ -18,9 +18,9 @@
+ print(l+":")
+ for i in range(0, len(n), 1):
+ try:
+- print(" %d:%s = %s"%(i, n[i].type, str(n[i].attr)))
++ print(f" {i}:{n[i].type} = {str(n[i].attr)}")
+ except:
+- print(" %d:%s"%(i, n[i].type))
++ print(f" {i}:{n[i].type}")
+
+
+
+--- a/trunk/pyfltk/util/flconvert/spark.py 2020-10-16 12:17:47.771154797 -0400
++++ b/trunk/pyfltk/util/flconvert/spark.py 2020-10-12 15:11:08.369355150 -0400
+@@ -47,7 +47,7 @@
+
+ def makeRE(self, name):
+ doc = getattr(self, name).__doc__
+- rv = '(?P<%s>%s)' % (name[2:], doc)
++ rv = f'(?P<{name[2:]}>{doc})'
+ return rv
+
+ def reflect(self):
+@@ -60,7 +60,7 @@
+ return string.join(rv, '|')
+
+ def error(self, s, pos):
+- print("Lexical error at position %s" % pos)
++ print(f"Lexical error at position {pos}")
+ raise SystemExit
+
+ def tokenize(self, s):
+@@ -179,7 +179,7 @@
+ return None
+
+ def error(self, token):
+- print("Syntax error at or near `%s' token" % token)
++ print(f"Syntax error at or near `{token}' token")
+ raise SystemExit
+
+ def parse(self, tokens):
+--- a/trunk/pyfltk/distutils_mod.py 2020-10-08 13:22:56.989640251 -0400
++++ b/trunk/pyfltk/distutils_mod.py 2020-10-08 18:38:59.008664942 -0400
+@@ -29,7 +29,7 @@
+ """
+ self.verbose = 1
+ if self.verbose:
+- print("cmd :%s:" % cmd)
++ print(f"cmd :{cmd}:")
+
+ cmpl = " ".join(cmd)
+ cmpl = cmpl.replace("\\", "/")
+@@ -38,7 +38,7 @@
+ #cmpl = cmpl.replace("gcc", "gcc -g ")
+
+ if self.verbose:
+- print("cmpl is :%s:" % cmpl)
++ print(f"cmpl is :{cmpl}:")
+
+ if not self.dry_run:
+ import tempfile
+@@ -46,14 +46,14 @@
+ tmpf = open(tmpfn, "w+b")
+ tmpf.write(cmpl.encode('ASCII'))
+ tmpf.close()
+- r = os.system("sh %s" % tmpfn)
++ r = os.system(f"sh {tmpfn}")
+
+ os.remove(tmpfn)
+ if r != 0:
+- raise DistutilsExecError("command '%s' failed with exit status :%d: command was :%s:. " % (cmd[0], r, cmpl))
++ raise DistutilsExecError(f"command '{cmd[0]}' failed with exit status :{r}: command was :{cmpl}:. ")
+
+ if self.verbose:
+- print("return value of the compile command is :%s:" % r)
++ print(f"return value of the compile command is :{r}:")
+
+
+
+--- a/trunk/pyfltk/test/DragAndDrop.py 2020-10-08 13:22:56.156300832 -0400
++++ b/trunk/pyfltk/test/DragAndDrop.py 2020-10-10 12:23:11.743965957 -0400
+@@ -46,10 +46,10 @@
+ print("FL_DND_LEAVE ", self.text_string)
+ return 1
+ elif event == FL_DND_DRAG:
+- print("FL_DND_DRAG %c (%d, %d)"%(self.text_string, Fl.event_x(), Fl.event_y()))
++ print(f"FL_DND_DRAG {self.text_string} ({Fl.event_x()}, {Fl.event_y()})")
+ return 1
+ elif event == FL_DND_RELEASE:
+- print("FL_DND_RELEASE %c (%d, %d)"%(self.text_string, Fl.event_x(), Fl.event_y()))
++ print(f"FL_DND_RELEASE {self.text_string} ({Fl.event_x()}, {Fl.event_y()})")
+ return 1
+ elif event == FL_PUSH:
+ print("PREPUSH ", self.text_string)
+@@ -61,7 +61,7 @@
+ cl = Fl.event_text()
+ ln = Fl.event_length()
+ print("PASTE ", self.text_string)
+- print(" text = %s, length = %d"%(cl, ln))
++ print(f" text = {cl}, length = {ln}")
+ return 1
+ else:
+ return 0
+--- a/trunk/pyfltk/test/TextEditor.py 2020-10-08 13:22:56.139634043 -0400
++++ b/trunk/pyfltk/test/TextEditor.py 2020-10-10 12:02:35.677517874 -0400
+@@ -37,7 +37,7 @@
+ def onFileQuit(ptr, data):
+ #menuItem = Fl_Menu_ItemPtr(ptr)
+ menuItem = ptr
+- print('onFileQuit(%s, "%s")'%(str(menuItem), str(data)))
++ print(f'onFileQuit({str(menuItem)}, "{str(data)}")')
+ import sys # code
+ sys.exit(0) # code
+
+@@ -45,7 +45,7 @@
+ def onFileSave(ptr , data):
+ #menuItem = Fl_Menu_ItemPtr(ptr)
+ menuItem = ptr
+- print('onFileSave(%s, "%s")'%(str(menuItem), str(data)))
++ print(f'onFileSave({str(menuItem)}, "{str(data)}")')
+
+ textEditor = data
+ print(textEditor.buffer().text())
+--- a/trunk/pyfltk/test/browser.py 2020-10-08 13:22:56.152967474 -0400
++++ b/trunk/pyfltk/test/browser.py 2020-10-10 10:44:08.820254311 -0400
+@@ -68,7 +68,7 @@
+
+ def b_cb(ptr):
+ #print "callback, selection = %d, event_clicks = <not yet wrapped>"%(ptr.value())
+- print("callback, selection = %d, event_clicks = %d"%(ptr.value(),Fl.event_clicks()))
++ print(f"callback, selection = {ptr.value()}, event_clicks = {Fl.event_clicks()}")
+
+ def show_cb(ptr):
+ if field.value() == '':
+--- a/trunk/pyfltk/test/check_browser.py 2020-10-08 13:22:56.139634043 -0400
++++ b/trunk/pyfltk/test/check_browser.py 2020-10-10 14:43:38.548190562 -0400
+@@ -35,7 +35,7 @@
+ def checkBrowserCallback(ptr):
+ #cb = Fl_Check_BrowserPtr(ptr) # code
+ cb = ptr
+- print("contains %d items"%cb.nitems())
++ print(f"contains {cb.nitems()} items")
+ for i in range(1, cb.nitems()+1): # code
+ if cb.checked(i): # code
+ print(cb.text(i)+" is checked")
+--- a/trunk/pyfltk/test/editor.py 2020-10-08 13:22:56.159634189 -0400
++++ b/trunk/pyfltk/test/editor.py 2020-10-09 16:43:49.521666023 -0400
+@@ -247,7 +247,7 @@
+ else:
+ r = textbuf.insertfile(newfile, ipos)
+ if r != 0:
+- fl_alert("Error reading from file %s."%newfile)
++ fl_alert(f"Error reading from file {newfile}.")
+ else:
+ if insert == 0:
+ filename = newfile
+@@ -257,7 +257,7 @@
+ def save_file(newfile):
+ global changed, filename
+ if textbuf.savefile(newfile) != 0:
+- fl_alert("Error writing to file %s."%newfile)
++ fl_alert(f"Error writing to file {newfile}.")
+ else:
+ filename = newfile
+ changed = False
+@@ -294,7 +294,7 @@
+ editor.editor.insert_position(pos+len(editor.search))
+ editor.editor.show_insert_position()
+ else:
+- fl_alert("No occurrences of %s found!"%editor.search)
++ fl_alert(f"No occurrences of {editor.search} found!")
+
+ def set_title(win):
+ global filename, title
+@@ -385,7 +385,7 @@
+ editor.editor.insert_position(pos+len(replace))
+ editor.editor.show_insert_position()
+ else:
+- fl_alert("No occurrences of %s found!"%find)
++ fl_alert(f"No occurrences of {find} found!")
+
+ def replall_cb(widget, editor):
+ find = editor.replace_find.value()
+@@ -414,9 +414,9 @@
+ times += 1
+
+ if times > 0:
+- fl_message("Replaced %d occurrences."%times)
++ fl_message(f"Replaced {times} occurrences.")
+ else:
+- fl_alert("No occurrences of %s found!"%find)
++ fl_alert(f"No occurrences of {find} found!")
+
+ def replcan_cb(widget, editor):
+ editor.replace_dlg.hide()
+--- a/trunk/pyfltk/test/fltk_threads.py 2020-10-08 13:22:56.149634116 -0400
++++ b/trunk/pyfltk/test/fltk_threads.py 2020-10-10 11:13:53.353368290 -0400
+@@ -68,7 +68,7 @@
+
+ #callbacks:
+ def newProcessCB(self,widget):
+- t = MyThread('Thread %d\n'%self.id)
++ t = MyThread(f'Thread {self.id}\n')
+ self.id += 1
+ t.start()
+ self.ThreadList.append(t)
+--- a/trunk/pyfltk/test/freeze/hello.py 2020-10-08 13:22:56.262968277 -0400
++++ b/trunk/pyfltk/test/freeze/hello.py 2020-10-08 20:40:35.997654327 -0400
+@@ -20,7 +20,7 @@
+
+ def onHelloWorldButton(ptr):
+ import sys # code
+- print "onHelloWorldButton(%s)"%str(ptr) # code
++ print(f"onHelloWorldButton({str(ptr)})") # code
+ sys.exit(0) # code
+
+
+--- a/trunk/pyfltk/test/handle_events.py 2020-10-08 13:22:56.156300832 -0400
++++ b/trunk/pyfltk/test/handle_events.py 2020-10-10 12:38:13.463057943 -0400
+@@ -61,7 +61,7 @@
+ return 1
+ elif event == FL_RELEASE:
+ print("FL_RELEASE")
+- print("Button = %d" % Fl.event_button())
++ print(f"Button = {Fl.event_button()}")
+ if highlight != 0:
+ highlight = 0
+ self.redraw()
+@@ -98,7 +98,7 @@
+ return None
+
+ def resize(self, X, Y, W, H):
+- print("Resizing: %d, %d, %d, %d\n"%(X,Y,W,H))
++ print(f"Resizing: {X}, {Y}, {W}, {H}\n")
+ #Fl_Widget.resize(self, X, Y, W, H)
+
+
+--- a/trunk/pyfltk/test/hello.py 2020-10-08 13:22:56.146300759 -0400
++++ b/trunk/pyfltk/test/hello.py 2020-10-10 12:58:17.355483253 -0400
+@@ -31,7 +31,7 @@
+
+ def theCancelButtonCallback(ptr, data):
+ print("type = ", type(ptr))
+- print("theCancelButtonCallback(%s)"%str(data))
++ print(f"theCancelButtonCallback({str(data)})")
+ print("Tooltip: ", ptr.tooltip())
+
+ window = Fl_Window(100, 100, 200, 90)
+--- a/trunk/pyfltk/test/hello_utf8.py 2020-10-08 13:22:56.142967401 -0400
++++ b/trunk/pyfltk/test/hello_utf8.py 2020-10-10 11:27:51.376432932 -0400
+@@ -35,7 +35,7 @@
+
+ def theCancelButtonCallback(ptr, data):
+ print("type = ", type(ptr))
+- print("theCancelButtonCallback(%s)"%str(data))
++ print(f"theCancelButtonCallback({str(data)})")
+ print("Tooltip: ", ptr.tooltip())
+
+ window = Fl_Window(100, 100, 200, 90)
+--- a/trunk/pyfltk/test/idle.py 2020-10-08 13:22:56.152967474 -0400
++++ b/trunk/pyfltk/test/idle.py 2020-10-08 20:48:43.929136605 -0400
+@@ -34,7 +34,7 @@
+ def anIdleCallback(data):
+ global timesCalled
+ timesCalled = timesCalled + 1
+- print("idle data=%d times called=%d"%(data,timesCalled))
++ print(f"idle data={data} times called={timesCalled}")
+
+ docb = 0
+ def theCancelButtonCallback(ptr):
+--- a/trunk/pyfltk/test/listSelect.py 2020-10-08 13:22:56.152967474 -0400
++++ b/trunk/pyfltk/test/listSelect.py 2020-10-09 16:44:27.641771102 -0400
+@@ -61,7 +61,7 @@
+ ls = ListSelect( 0, 0, 420, 300, " From:", " To:");
+
+ for t in range(0, 30, 1):
+- ls.getTopBrowser().add("Item #%d"%t)
++ ls.getTopBrowser().add(f"Item #{t}")
+
+ window.resizable(window.this)
+ window.end()
+--- a/trunk/pyfltk/test/logo.py 2020-10-08 13:22:56.152967474 -0400
++++ b/trunk/pyfltk/test/logo.py 2020-10-10 12:41:17.053406574 -0400
+@@ -31,7 +31,7 @@
+
+ def theCancelButtonCallback(ptr, data):
+ print("type = ", type(ptr))
+- print("theCancelButtonCallback(%s)"%str(data))
++ print(f"theCancelButtonCallback({str(data)})")
+ print("Tooltip: ", ptr.tooltip())
+
+ def createButton(x, y, w, h, label):
+--- a/trunk/pyfltk/test/logo_gleam.py 2020-10-08 13:22:56.146300759 -0400
++++ b/trunk/pyfltk/test/logo_gleam.py 2020-10-10 13:10:45.187133398 -0400
+@@ -31,7 +31,7 @@
+
+ def theCancelButtonCallback(ptr, data):
+ print("type = ", type(ptr))
+- print("theCancelButtonCallback(%s)"%str(data))
++ print(f"theCancelButtonCallback({str(data)})")
+ print("Tooltip: ", ptr.tooltip())
+
+ def createButton(x, y, w, h, label):
+--- a/trunk/pyfltk/test/menu.py 2020-10-08 13:22:56.142967401 -0400
++++ b/trunk/pyfltk/test/menu.py 2020-10-08 20:58:05.410496482 -0400
+@@ -35,7 +35,7 @@
+ def onFileQuit(ptr, data):
+ #menuItem = Fl_Menu_ItemPtr(ptr)
+ menuItem = ptr
+- print('onFileQuit(%s, "%s")'%(str(menuItem), str(data)))
++ print(f'onFileQuit({str(menuItem)}, "{str(data)}")')
+ import sys # code
+ sys.exit(0) # code
+
+--- a/trunk/pyfltk/test/menubar.py 2020-10-08 13:22:56.149634116 -0400
++++ b/trunk/pyfltk/test/menubar.py 2020-10-10 13:08:36.376842433 -0400
+@@ -40,7 +40,7 @@
+ print("menu.mvalue()=NULL")
+ else:
+ if (m.shortcut()):
+- print("%s - %s" % ( m.label(), fl_shortcut_label(m.shortcut()) ))
++ print(f"{m.label()} - {fl_shortcut_label(m.shortcut())}")
+ else:
+ print(m.label())
+
+@@ -96,7 +96,7 @@
+ menus[0].parent().redraw()
+
+ for i in range(0, 99, 1):
+- hugemenu.append( nm("item %d"%i) )
++ hugemenu.append( nm(f"item {i}") )
+
+ window = Fl_Window(0,0, WIDTH, 400)
+
+--- a/trunk/pyfltk/test/message.py 2020-10-08 13:22:56.156300832 -0400
++++ b/trunk/pyfltk/test/message.py 2020-10-10 13:52:56.441473112 -0400
+@@ -33,13 +33,13 @@
+ fl_alert("Quantum fluctuations in the space-time continuim detected, "
+ "you have %f seconds to comply."% 10.0)
+
+-print("fl_ask returned %d"%fl_ask("Do you really want to %s?"%"continue"))
++print(f"fl_ask returned {fl_ask('Do you really want to continue?')}")
+
+-print("fl_choice returned %d"%fl_choice("Choose one of the following:","choice0","choice1","choice2"))
++print(f"fl_choice returned {fl_choice('Choose one of the following:', 'choice0', 'choice1', 'choice2')}")
+
+ r = fl_input("Please enter a string for input:", "this is the default value")
+-print("fl_input returned \"%s\""%str(r))
++print(f"fl_input returned \"{str(r)}\"")
+
+ r = fl_password("Enter password:", "123")
+-print("fl_password returned \"%s\""%str(r))
++print(f"fl_password returned \"{str(r)}\"")
+
+--- a/trunk/pyfltk/test/message_de.py 2020-10-08 13:22:56.149634116 -0400
++++ b/trunk/pyfltk/test/message_de.py 2020-10-10 14:03:20.650118376 -0400
+@@ -38,13 +38,13 @@
+ fl_alert("Quantum fluctuations in the space-time continuim detected, "
+ "you have %f seconds to comply."% 10.0)
+
+-print("fl_ask returned %d"%fl_ask("Do you really want to %s?"%"continue"))
++print(f"fl_ask returned {fl_ask('Do you really want to continue?')}")
+
+-print("fl_choice returned %d"%fl_choice("Choose one of the following:","choice0","choice1","choice2"))
++print(f"fl_choice returned {fl_choice('Choose one of the following:', 'choice0', 'choice1', 'choice2')}")
+
+ r = fl_input("Please enter a string for input:", "this is the default value")
+-print("fl_input returned \"%s\""%str(r))
++print(f"fl_input returned \"{str(r)}\"")
+
+ r = fl_password("Enter password:", "123")
+-print("fl_password returned \"%s\""%str(r))
++print(f"fl_password returned \"{str(r)}\"")
+
+--- a/trunk/pyfltk/test/postioner.py 2020-10-08 13:22:56.142967401 -0400
++++ b/trunk/pyfltk/test/postioner.py 2020-10-09 16:58:56.594297723 -0400
+@@ -39,7 +39,7 @@
+
+
+ def thePosCallback(ptr):
+- theDisplay.value("%3.3f, %3.3f"%(thePos.xvalue(), thePos.yvalue())) # code
++ theDisplay.value(f"{thePos.xvalue():3.3f}, {thePos.yvalue():3.3f}") # code
+
+
+ def main():
+--- a/trunk/pyfltk/test/simple_table.py 2020-10-08 13:22:56.156300832 -0400
++++ b/trunk/pyfltk/test/simple_table.py 2020-10-10 13:36:18.481582445 -0400
+@@ -42,7 +42,7 @@
+ fl_font(FL_HELVETICA, 12) # font used by all headers
+ return None
+ elif context==self.CONTEXT_CELL:
+- s = "%d"%self.data[R][C]
++ s = f"{self.data[R][C]}"
+ fl_push_clip(X,Y,W,H)
+ fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, self.row_header_color())
+ fl_color(FL_BLACK)
+--- a/trunk/pyfltk/test/sudoku.py 2020-10-08 13:22:56.142967401 -0400
++++ b/trunk/pyfltk/test/sudoku.py 2020-10-09 17:02:43.064993929 -0400
+@@ -404,7 +404,7 @@
+ for i in range(9):
+ for j in range(9):
+ cell = self.grid_cells[i][j]
+- name = "value%d.%d"%(i,j)
++ name = f"value{i}.{j}"
+ val = 0
+ (status, val) = self.prefs.get(name, 0)
+ if status == 0:
+@@ -412,7 +412,7 @@
+ break
+ self.grid_values[i][j] = val
+
+- name = "state%d.%d"%(i,j)
++ name = f"state{i}.{j}"
+ (status, val) = self.prefs.get(name, 0)
+ cell.readonly(val)
+ if val != 0:
+@@ -422,7 +422,7 @@
+ solved = False
+
+ for k in range(8):
+- name = "test%d%d.%d"%(k, i, j)
++ name = f"test{k}{i}.{j}"
+ (status, val) = self.prefs.get(name, 0)
+ cell.test_value(k, val)
+
+@@ -611,17 +611,17 @@
+ for i in range(9):
+ for j in range(9):
+ cell = self.grid_cells[i][j]
+- name = "value%d.%d"%(i,j)
++ name = f"value{i}.{j}"
+ self.prefs.set(name, self.grid_values[i][j])
+
+- name = "state%d.%d"%(i, j)
++ name = f"state{i}.{j}"
+ self.prefs.set(name, cell.value())
+
+- name = "readonly%d.%d"%(i, j)
++ name = f"readonly{i}.{j}"
+ self.prefs.set(name, cell.readonly())
+
+ for k in range(8):
+- name = "test%d%d.%d"%(k, i, j)
++ name = f"test{k}{i}.{j}"
+ self.prefs.set(name, cell.test_value(k))
+
+ def set_title(self):
+--- a/trunk/pyfltk/test/table.py 2020-10-08 13:22:56.156300832 -0400
++++ b/trunk/pyfltk/test/table.py 2020-10-08 21:52:31.201008633 -0400
+@@ -31,7 +31,7 @@
+
+
+ def button_cb(w, data):
+- print("BUTTON: %s"%w.label())
++ print(f"BUTTON: {w.label()}")
+
+ class WidgetTable(Fl_Table_Row):
+ def __init__(self, x, y, w, h, l=""):
+@@ -45,7 +45,7 @@
+ self.end()
+
+ def draw_cell(self, context, R, C, X, Y, W, H):
+- s="%d/%d"%(R,C) # text for each cell
++ s=f"{R}/{C}" # text for each cell
+
+ if context==self.CONTEXT_STARTPAGE:
+ fl_font(FL_HELVETICA, 12) # font used by all headers
+@@ -64,7 +64,7 @@
+ self.init_sizes()
+ return None
+ elif context==self.CONTEXT_ROW_HEADER:
+- s1="Row %d"%R
++ s1=f"Row {R}"
+ fl_push_clip(X,Y,W,H)
+ fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, self.row_header_color())
+ fl_color(FL_BLACK)
+@@ -72,7 +72,7 @@
+ fl_pop_clip()
+ return None
+ elif context==self.CONTEXT_COL_HEADER:
+- s1="Column %d"%C
++ s1=f"Column {C}"
+ fl_push_clip(X, Y, W, H)
+ fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, self.col_header_color())
+ fl_color(FL_BLACK)
+@@ -99,11 +99,11 @@
+ #(status, X, Y, W, H)=self.find_cell(self.CONTEXT_TABLE, r, c, X, Y, W, H)
+
+ if c&1:
+- s="%d.%d"%(r,c)
++ s=f"{r}.{c}"
+ inp = Fl_Input(X,Y,W,H)
+ inp.value(s)
+ else:
+- s1="%d/%d"%(r,c)
++ s1=f"{r}/{c}"
+ butt = Fl_Light_Button(X,Y,W,H,s1)
+ self.s_list.append(s1)
+ butt.align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE)
+@@ -121,7 +121,7 @@
+ Fl_Table_Row.__init__(self, x, y, w, h, l)
+
+ def draw_cell(self, context, R, C, X, Y, W, H):
+- s="%d/%d"%(R,C) # text for each cell
++ s=f"{R}/{C}" # text for each cell
+
+ if context==self.CONTEXT_STARTPAGE:
+ fl_font(FL_HELVETICA, 16)
+@@ -158,7 +158,7 @@
+
+ def table_cb(o, data):
+ table = data
+- print("%s callback: row=%d col=%d, context=%d, event=%d, clicks=%d"%(table.label(),table.callback_row(),table.callback_col(),table.callback_context(),Fl.event(), Fl.event_clicks()))
++ print(f"{table.label()} callback: row={table.callback_row()} col={table.callback_col()}, context={table.callback_context()}, event={Fl.event()}, clicks={Fl.event_clicks()}")
+
+ if __name__=='__main__':
+ win1 = Fl_Window(940, 500, "widgettable")
+--- a/trunk/pyfltk/test/timeout.py 2020-10-08 13:22:56.149634116 -0400
++++ b/trunk/pyfltk/test/timeout.py 2020-10-08 21:53:52.488010236 -0400
+@@ -32,7 +32,7 @@
+
+ def timeoutCallback(data):
+ global numTimeoutsCalled
+- print("timeoutCallback(%s)"%str(data))
++ print(f"timeoutCallback({str(data)})")
+ Fl.repeat_timeout( 2.0, timeoutCallback, numTimeoutsCalled)
+ numTimeoutsCalled = numTimeoutsCalled + 1
+ if numTimeoutsCalled == 5:
+--- a/trunk/pyfltk/test/tree_demo.py 2020-10-08 13:22:56.152967474 -0400
++++ b/trunk/pyfltk/test/tree_demo.py 2020-10-08 22:31:23.253006805 -0400
+@@ -462,7 +462,7 @@
+ """
+ """
+ def on_select(self, node):
+- print("on_select: node=%s" % node.title)
++ print(f"on_select: node={node.title}")
+
+ print("creating window")
+ win = fltk.Fl_Window(xWin, yWin, wWin, hWin, "Fl_Tree demo")
+@@ -474,25 +474,25 @@
+ def on_promote(ev):
+ node = tree.valuenode()
+ if node:
+- print("promote: %s" % node.title)
++ print(f"promote: {node.title}")
+ node.promote()
+
+ def on_demote(ev):
+ node = tree.valuenode()
+ if node:
+- print("demote: %s" % node.title)
++ print(f"demote: {node.title}")
+ node.demote()
+
+ def on_moveup(ev):
+ node = tree.valuenode()
+ if node:
+- print("moveup: %s" % node.title)
++ print(f"moveup: {node.title}")
+ node.moveup()
+
+ def on_movedown(ev):
+ node = tree.valuenode()
+ if node:
+- print("movedown: %s" % node.title)
++ print(f"movedown: {node.title}")
+ node.movedown()
+
+ but_promote = fltk.Fl_Button(xButs, 20, 20, 20, "@<-")
+@@ -517,13 +517,13 @@
+ # add stuff to root node
+ if 1:
+ for i in range(3):
+- node = tree.append("item-%s" % i)
++ node = tree.append(f"item-{i}")
+ if 1:
+ for j in range(3):
+- subnode = node.append("item-%s%s" % (i, j))
++ subnode = node.append(f"item-{i}{j}")
+ if 0:
+ for k in range(2):
+- subnode.append("item-%s%s%s" % (i,j,k))
++ subnode.append(f"item-{i}{j}{k}")
+
+ print("entering main loop")
+ fltk.Fl.run()
+--- a/trunk/pyfltk/test/tty.py 2020-10-08 13:22:56.146300759 -0400
++++ b/trunk/pyfltk/test/tty.py 2020-10-10 14:13:42.192064370 -0400
+@@ -90,17 +90,17 @@
+ bytes = "waitpid(): no child process\n"
+ else:
+ if os.WIFEXITED(status):
+- bytes = "Exit=%d\n"%os.WEXITSTATUS(status)
++ bytes = f"Exit={os.WEXITSTATUS(status)}\n"
+ os.close(fd)
+ Fl.remove_fd(fd)
+ G_pids[t] = -1
+ elif os.WIFSIGNALED(status):
+- bytes = "Killed with %d\n"%os.WTERMSIG(status)
++ bytes = f"Killed with {os.WTERMSIG(status)}\n"
+ os.close(fd)
+ Fl.remove_fd(fd)
+ G_pids[t] = -1
+ elif os.WIFSTOPPED(status):
+- bytes = "Stopped with %d\n"%os.WSTOPSIG(status)
++ bytes = f"Stopped with {os.WSTOPSIG(status)}\n"
+
+ G_buff[t].append(bytes)
+ else: # DATA
+--- a/trunk/pyfltk/test/utf8.py 2020-10-08 13:22:56.146300759 -0400
++++ b/trunk/pyfltk/test/utf8.py 2020-10-08 22:57:10.030697161 -0400
+@@ -148,10 +148,10 @@
+ i = i+1
+ buf = ""
+ if j < size_count and i == size_array[j]:
+- buf = "@b%d"%i
++ buf = f"@b{i}"
+ j = j+1
+ else:
+- buf = "%d"%i
++ buf = f"{i}"
+
+ sizeobj.add(buf)
+
+@@ -164,7 +164,7 @@
+ if size_array[i] <= pickedsize:
+ w = i
+
+- buf = "@b%d"%size_array[i]
++ buf = f"@b{size_array[i]}"
+ sizeobj.add(buf)
+ sizeobj.value(w+1)
+ # force selection of nearest valid size, then redraw
+@@ -191,8 +191,8 @@
+ else:
+ font_idx = font_idx-1
+ name, font_type = Fl.get_font_name(font_idx)
+- print("idx %d\nUser name :%s:"%( font_idx, name))
+- print("FLTK name :%s:"%( Fl.get_font(font_idx)))
++ print(f"idx {font_idx}\nUser name :{name}:")
++ print(f"FLTK name :{Fl.get_font(font_idx)}:")
+
+ Fl.set_font(extra_font, font_idx)
+
+@@ -250,7 +250,7 @@
+ prefix = prefix+"@i"
+ buf = prefix+"@."+name
+ else:
+- buf="@F%d@.%s"%(font_idx, name)
++ buf=f"@F{font_idx}@.{name}"
+ fontobj.add(buf)
+
+ fontobj.topline(i_was)
+@@ -515,7 +515,7 @@
+ o = o+1
+ i = i+1
+ buf = buf+'\0'
+- bu = "0x%04lX"%(y * 16)
++ bu = f"0x{(y * 16):04X}"
+ b = Fl_Input(200,(y-off)*25,60,25)
+ b.value(bu)
+ b = Fl_Input(260,(y-off)*25,400,25)
diff --git a/pyfltk_swig_silence_warnings.patch b/pyfltk_swig_silence_warnings.patch
new file mode 100644
index 000000000000..5d8d765cd59d
--- /dev/null
+++ b/pyfltk_swig_silence_warnings.patch
@@ -0,0 +1,11 @@
+--- a/trunk/pyfltk/python/MakeSwig.py 2020-10-08 13:22:56.982973535 -0400
++++ b/trunk/pyfltk/python/MakeSwig.py 2020-10-16 13:17:11.787141444 -0400
+@@ -47,7 +47,7 @@
+ versionIdentifier = ""
+ if sys.version >= "3.0":
+ versionIdentifier = "-DPYTHON3 -py3"
+- cmd_line = "swig -w312 -w451 -w473 -I../swig %s -DFL_EXPORT -DPYTHON %s -c++ -python -shadow -modern -fastdispatch -o fltk_wrap.cpp ../swig/fltk.i "%(add_incl, versionIdentifier)
++ cmd_line = "swig -w302 -w312 -w325 -w362 -w389 -w401 -w473 -w509 -I../swig %s -DFL_EXPORT -DPYTHON %s -c++ -python -shadow -fastdispatch -o fltk_wrap.cpp ../swig/fltk.i "%(add_incl, versionIdentifier)
+ # command line for swig-1.3.27
+ # cmd_line = "swig -w312 -w451 -w473 -I../swig %s -DFL_EXPORT -DPYTHON -c++ -python -shadow -modern -dirprot -o fltk_wrap.cpp ../swig/fltk.i "%add_incl
+ if is_msys_mingw():