[Blends-commit] [SCM] website branch, master, updated. bb220659ec9943f6e58b0ca0a7f2d3e450223888

Akshita Jha akshita-guest at users.alioth.debian.org
Thu Jul 23 10:41:02 UTC 2015


The following commit has been merged in the master branch:
commit bb220659ec9943f6e58b0ca0a7f2d3e450223888
Author: Akshita Jha <akshita-guest at users.alioth.debian.org>
Date:   Thu Jul 23 16:04:53 2015 +0530

    Add webtools_py3 folder: Porting scripts in webtools folder from Python 2 to Python 3

diff --git a/webtools/0dependencies b/webtools_py3/0dependencies
similarity index 53%
copy from webtools/0dependencies
copy to webtools_py3/0dependencies
index 4090a73..6f0b910 100644
--- a/webtools/0dependencies
+++ b/webtools_py3/0dependencies
@@ -1,13 +1,13 @@
 # The script needs the following python modules installed:
 
 sudo apt-get install \
-    python-apt \
-    python-genshi \
-    python-markdown \
-    python-docutils \
-    python-debian \
-    python-psutil \
-    python-psycopg2
+    python3-apt \
+    python3-genshi \
+    python3-markdown \
+    python3-docutils \
+    python3-debian \
+    python3-psutil \
+    python3-psycopg2
 
 # This should be provided as patch for
 #
diff --git a/webtools/blend-get-names b/webtools_py3/blend-get-names
similarity index 100%
copy from webtools/blend-get-names
copy to webtools_py3/blend-get-names
diff --git a/webtools/blendslanguages.py b/webtools_py3/blendslanguages.py
similarity index 98%
copy from webtools/blendslanguages.py
copy to webtools_py3/blendslanguages.py
index 292b6ec..2dfac0f 100644
--- a/webtools/blendslanguages.py
+++ b/webtools_py3/blendslanguages.py
@@ -35,7 +35,7 @@ language_dict = { 'en'    : {'short':'en', 'htaccess':'en'   , 'title':'English'
                   'zh_TW' : {'short':'zh_tw', 'htaccess':'zh-TW', 'title':'Chinese (Taiwan)', 'printed':Markup('中文(正)')},
                 }
 # global languages
-_languages = language_dict.keys()
+_languages = list(language_dict.keys())
 _languages.sort()
 # make sure 'en' comes first because the first language determines the default
 languages = ['en']
diff --git a/webtools/blendsmarkdown.py b/webtools_py3/blendsmarkdown.py
similarity index 87%
copy from webtools/blendsmarkdown.py
copy to webtools_py3/blendsmarkdown.py
index a7de6f1..52c0e0c 100644
--- a/webtools/blendsmarkdown.py
+++ b/webtools_py3/blendsmarkdown.py
@@ -73,7 +73,7 @@ def render_longdesc(lines):
         try:
             LongDesc = publish_parts(MarkDownInput, writer_name='html')['body']
         except:
-            print >>stderr, "Unable to render the following prepared text:\n" + MarkDownInput
+            print("Unable to render the following prepared text:\n" + MarkDownInput, file=stderr)
             LongDesc = "Problems in rendering description using reST"
     else: # by default use Markdown
         LongDesc = markdown(MarkDownInput)
@@ -97,17 +97,17 @@ def MarkupString(string, pkg, elem, lang='en'):
         return None
     try:
         string = Markup(to_unicode(string))
-    except UnicodeDecodeError, errtxt:
-        print >> stderr, "----> %s UnicodeDecodeError in %s (lang='%s'): '%s'; ErrTxt: %s" % \
-                                    (elem, pkg, lang, 'debug-string', errtxt)
+    except UnicodeDecodeError as errtxt:
+        print("----> %s UnicodeDecodeError in %s (lang='%s'): '%s'; ErrTxt: %s" % \
+                                    (elem, pkg, lang, 'debug-string', errtxt), file=stderr)
         try:
-            string = Markup(unicode(string, 'utf-8'))
-        except TypeError, errtxt:
-            print >> stderr, "====> %s TypeError in %s (lang='%s'): '%s'; ErrTxt: %s" % \
-                                    (elem, pkg, lang, 'debug-string', errtxt)
-    except TypeError, errtxt:
-        print >> stderr, "----> %s TypeError in %s (lang='%s'): '%s'; ErrTxt: %s" % \
-                                    (elem, pkg, lang, 'debug-string', errtxt)
+            string = Markup(str(string, 'utf-8'))
+        except TypeError as errtxt:
+            print("====> %s TypeError in %s (lang='%s'): '%s'; ErrTxt: %s" % \
+                                    (elem, pkg, lang, 'debug-string', errtxt), file=stderr)
+    except TypeError as errtxt:
+        print("----> %s TypeError in %s (lang='%s'): '%s'; ErrTxt: %s" % \
+                                    (elem, pkg, lang, 'debug-string', errtxt), file=stderr)
     return string
 
 rendering_lib  = ''
diff --git a/webtools/blendstasktools.py b/webtools_py3/blendstasktools.py
similarity index 96%
copy from webtools/blendstasktools.py
copy to webtools_py3/blendstasktools.py
index 1e399c7..77a920a 100644
--- a/webtools/blendstasktools.py
+++ b/webtools_py3/blendstasktools.py
@@ -23,8 +23,8 @@ from subprocess import Popen, PIPE
 import os
 import grp
 import stat
-import urllib
-import StringIO
+import urllib.request, urllib.parse, urllib.error
+import io
 import gzip
 import bz2
 import re
@@ -159,7 +159,7 @@ pkgstatus = {'official_high' : # official package with high priority dependency
                                  'order'        : 9
                                },
              'ignore'        : # Package inside Debian which is "under observation"
-                               { 'releases'     : (releases.keys()),
+                               { 'releases'     : (list(releases.keys())),
                                  'component'    : ('main', 'contrib', 'non-free'),
                                  'dependencies' : ('Ignore', ),
                                  'fields-set'   : (),
@@ -167,7 +167,7 @@ pkgstatus = {'official_high' : # official package with high priority dependency
                                  'order'        : 10
                                },
              'avoid'         : # Package inside Debian which should not go to a install medium of the Blend
-                               { 'releases'     : (releases.keys()),
+                               { 'releases'     : (list(releases.keys())),
                                  'component'    : ('main', 'contrib', 'non-free'),
                                  'dependencies' : ('Avoid', ),
                                  'fields-set'   : (),
@@ -186,7 +186,7 @@ pkgstatus = {'official_high' : # official package with high priority dependency
 
 # http://wiki.python.org/moin/HowTo/Sorting#Sortingbykeys
 _tmplist=[]
-for key in pkgstatus.keys():
+for key in list(pkgstatus.keys()):
     _tmplist.append((key,pkgstatus[key]['order']))
 _tmpsorted = sorted(_tmplist, key=lambda x:(x[1], x[0]))
 pkgstatus_sortedkeys = []
@@ -244,7 +244,7 @@ def LockBlendsTools():
             pass
     pid = os.getpid()
     lf = open(LOCKFILE, 'w')
-    print >>lf, pid
+    print(pid, file=lf)
     lf.close()
     SetFilePermissions(LOCKFILE)
 
@@ -266,7 +266,7 @@ def GetDependencies2Use(dependencystatus=[], max_order='prospective'):
     else:
         # verify correctly given dependencies
         for pkgstat in dependencystatus:
-            if pkgstat in pkgstatus.keys():
+            if pkgstat in list(pkgstatus.keys()):
                 use_dependencystatus.append(pkgstat)
             else:
                 logger.error("Unknown dependencystatus %s" % pkgstat)
@@ -278,12 +278,12 @@ def GetDependencies2Use(dependencystatus=[], max_order='prospective'):
 # Define several prepared statements to query UDD
 try:
   conn = psycopg2.connect(host="localhost",port=PORT,user="guest",database="udd")
-except psycopg2.OperationalError, err:
+except psycopg2.OperationalError as err:
   try:
     conn = psycopg2.connect("service=udd")
-  except psycopg2.OperationalError, err:
+  except psycopg2.OperationalError as err:
     # logger not known at this state: logger.warning
-    print >>stderr, "Service=udd seems not to be installed on this host.\tMessage: %s" % (str(err))
+    print("Service=udd seems not to be installed on this host.\tMessage: %s" % (str(err)), file=stderr)
     try:
         conn = psycopg2.connect(host="localhost",port=DEFAULTPORT,user="guest",database="udd")
     except psycopg2.OperationalError:
@@ -299,12 +299,12 @@ def _execute_udd_query(query):
     try:
         curs.execute(query)
         logger.debug(query)
-    except psycopg2.ProgrammingError, err:
-        print >>stderr, "Problem with query\n%s" % (to_unicode(query))
-        print >>stderr, err
+    except psycopg2.ProgrammingError as err:
+        print("Problem with query\n%s" % (to_unicode(query)), file=stderr)
+        print(err, file=stderr)
         exit(-1)
-    except psycopg2.DataError, err:
-        print >>stderr, "%s; query was\n%s" % (err, query)
+    except psycopg2.DataError as err:
+        print("%s; query was\n%s" % (err, query), file=stderr)
 
 query = """PREPARE query_pkgs (text[],text[]) AS
         SELECT * FROM blends_query_packages($1,$2) AS (
@@ -549,24 +549,24 @@ def ReadConfig(blendname=''):
                                                     # for instance at www.debian.org or wiki.debian.org
         ret['aliothurl']   = stanza['aliothurl']    # Link to the Alioth page of the project
         ret['projectlist'] = stanza['projectlist']  # Mailinglist of the project
-        if stanza.has_key('pkglist'):
+        if 'pkglist' in stanza:
     	    ret['pkglist'] = stanza['pkglist']      # Packaging Mailinglist = Maintainer of group maintained packages
-        if stanza.has_key('logourl'):
+        if 'logourl' in stanza:
             ret['logourl'] = stanza['logourl']      # URL to logo image (might be missing
         ret['css']         = stanza['css']          # (relative) URL to CSS file
         ret['outputdir']   = stanza['outputdir']    # Dir for storing output HTML files
         ret['datadir']     = stanza['datadir']      # Dir for storing SVN information about project
         ret['vcsdir']      = stanza['vcsdir']       # Path to Blend information files at svn.debian.org
-        if stanza.has_key('advertising'):
+        if 'advertising' in stanza:
             # we have to remove the gettext _() call which was inserted into the config
             # file to enable easy input for config file editors - but the call has to
             # be made explicitely in the python code
             advertising = re.sub('_\(\W(.+)\W\)', '\\1', stanza['advertising'])
             # gettext needs to escape '"' thus we need to remove the escape character '\'
             ret['advertising'] = re.sub('\\\\"', '"', advertising)
-        if stanza.has_key('ubuntuhome'):
+        if 'ubuntuhome' in stanza:
             ret['ubuntuhome'] = stanza['ubuntuhome']
-        if stanza.has_key('projectubuntu'):
+        if 'projectubuntu' in stanza:
             ret['projectubuntu'] = stanza['projectubuntu']
 
     return ret
@@ -782,7 +782,7 @@ class DependantPackage:
             ret += ", versions: "     + str(self.version)
         if self.desc:
             ret += ", desc: "         + str(self.desc)
-        for prop in self.properties.keys():
+        for prop in list(self.properties.keys()):
             try:
                 ret += ", %s: %s" % (prop, to_unicode(str(self.properties[prop])))
             except UnicodeEncodeError:            
@@ -844,14 +844,14 @@ class DependantPackage:
                         else:
                             logger.debug("Author string changed in %s: '%s' -> '%s'", self.pkg, to_unicode(row[pub]), to_unicode(authors_string))
                             row[pub] = authors_string
-                if not self.properties.has_key('published'):
+                if 'published' not in self.properties:
                     self.properties['published'] = {}
-                if self.properties['published'].has_key(pub):
+                if pub in self.properties['published']:
                     if self.properties['published'][pub] == to_unicode(row[pub]):
                     	try:
-                           print >>rmpub, "%s: %s: Published-%s: %s" % (self.taskname, self.pkg, pub, to_unicode(row[pub]))
+                           print("%s: %s: Published-%s: %s" % (self.taskname, self.pkg, pub, to_unicode(row[pub])), file=rmpub)
             	        except UnicodeEncodeError:
-            	           print >>rmpub, "--- %s: %s: Published-%s: some duplicated value featuring encoding problems ---" % (self.taskname, self.pkg, pub)
+            	           print("--- %s: %s: Published-%s: some duplicated value featuring encoding problems ---" % (self.taskname, self.pkg, pub), file=rmpub)
             		logger.info("%s/%s: Publication-%s = %s can be removed"  % (self.taskname, self.pkg, pub, to_unicode(row[pub])))
             	    else:
             	        logger.info("%s conflicting fields Publication-%s in tasks file with value '%s' and in UDD with value '%s'" % (self.pkg, pub, self.properties['published'][pub], to_unicode(row[pub])))
@@ -944,13 +944,13 @@ class Tasks:
             td = TaskDependencies(self.blendname, task=task, tasksdir=self.tasksdir)
             pkgname = prefix + task
             translations = None
-            if metapkg_translations.has_key(pkgname):
+            if pkgname in metapkg_translations:
                 translations = metapkg_translations[pkgname]
             td.SetMetapackageInfo(pkgname, translations)
             if td.GetTaskDependencies(source):
                 self.tasks[task] = td
             else: # Kick file that is obviosely no task file from metapackage list
-                self.metapackagekeys = filter(lambda name: name != task, self.metapackagekeys)
+                self.metapackagekeys = [name for name in self.metapackagekeys if name != task]
 
         if source == 0:
             # total number popcon submissions
@@ -989,7 +989,7 @@ class Tasks:
             for dep in use_dependencystatus:
                 for tdep in tdeps.dependencies[dep]:
             	    if tdep.outdated != {}:
-                        if tdep.properties.has_key('last_uploader_simple'):
+                        if 'last_uploader_simple' in tdep.properties:
                             last_uploader = tdep.properties['last_uploader_simple']
                         else:
                             last_uploader = None
@@ -1076,14 +1076,14 @@ class Tasks:
         # otherwise
         for task in self.metapackagekeys:
             tdeps = self.tasks[task]
-            for dependency in tdeps.dependencies.keys():
+            for dependency in list(tdeps.dependencies.keys()):
                 for dep in tdeps.dependencies[dependency]:
                     if dep.properties['Enhances'] != {}:
                         logger.debug("Package %s is enhanced by:" % dep.pkg)
-                        for enh in dep.properties['Enhances'].keys():
+                        for enh in list(dep.properties['Enhances'].keys()):
                             # seek for Enhances on same page
                             found = 0
-                            for seek_dependency in tdeps.dependencies.keys():
+                            for seek_dependency in list(tdeps.dependencies.keys()):
                                 for enhdep in tdeps.dependencies[seek_dependency]:
                                     if enh == enhdep.pkg:
                                         dep.properties['Enhances'][enh] = '#'+enh
@@ -1094,7 +1094,7 @@ class Tasks:
                                     if enhtask == task:
                                         continue
                                     enhtdeps = self.tasks[enhtask]
-                                    for seek_dependency in enhtdeps.dependencies.keys():
+                                    for seek_dependency in list(enhtdeps.dependencies.keys()):
                                         for enhdep in enhtdeps.dependencies[seek_dependency]:
                                             if enh == enhdep.pkg:
                                                 dep.properties['Enhances'][enh] = './' + enhtask + '#' + enh
@@ -1111,7 +1111,7 @@ class Tasks:
         for task in self.metapackagekeys:
             ret += tab
             semikolon = ''
-            for pstatus in self.tasks[task].dependencies.keys():
+            for pstatus in list(self.tasks[task].dependencies.keys()):
                 if self.tasks[task].dependencies[pstatus] == []:
                     continue
                 ret += semikolon + pstatus + ': ['
@@ -1176,7 +1176,7 @@ class TaskDependencies:
                 try:
                     short = to_unicode(ddtptranslations['description_'+lang])
                     self.metapkg.desc[lang]['short'] = MarkupString(short, self.metapkg.pkg, 'taskShortDesc', lang)
-                except UnicodeEncodeError, err:
+                except UnicodeEncodeError as err:
                     logger.error("===> UnicodeDecodeError in metapackage %s (lang='%s'): '%s'; ErrTxt: %s" % \
                                      (self.metapkg.pkg, lang, ddtptranslations['description_'+lang], err))
                     short = to_unicode(ddtptranslations['description_'+lang],'latin1')
@@ -1184,11 +1184,11 @@ class TaskDependencies:
     
                 try:
                     self.metapkg.desc[lang]['long'] = Markup(render_longdesc(ddtptranslations['long_description_'+lang].splitlines()))
-                except UnicodeDecodeError, err:
+                except UnicodeDecodeError as err:
                     logger.error("===> UnicodeDecodeError in metapackage long %s (lang='%s'): '%s'; ErrTxt: %s" % \
                                      (self.metapkg.pkg, lang, ddtptranslations['long_description_'+lang], err))
                     self.metapkg.desc[lang]['long'] = 'UnicodeDecodeError'
-                except AttributeError, err:
+                except AttributeError as err:
                     logger.error("===> AttributeError in metapackage long %s (lang='%s'): '%s'; ErrTxt: %s" % \
                                      (self.metapkg.pkg, lang, ddtptranslations['long_description_'+lang], err))
                     self.metapkg.desc[lang]['long'] = 'Missing long description'
@@ -1262,10 +1262,10 @@ class TaskDependencies:
                     if found_description:
                         logger.error("Duplicate description entry in task %s; you probably want to use Pkg-Description field instead!" % self.task)
                     else:
-                        (short, long) = SplitDescription(stanza['description'])
+                        (short, int) = SplitDescription(stanza['description'])
                         # Markup strings to enable verbatim output of preformatted text
                         self.metapkg.desc['en']['short'] = MarkupString(short.encode('utf-8'), self.metapkg.PrintedName, 'taskShortDesc')
-                        self.metapkg.desc['en']['long']  = MarkupString(long.encode('utf-8'),  self.metapkg.PrintedName, 'taskLongDesc')
+                        self.metapkg.desc['en']['long']  = MarkupString(int.encode('utf-8'),  self.metapkg.PrintedName, 'taskLongDesc')
                         found_description = True
                     continue
                 if key == 'Meta-Depends':
@@ -1297,7 +1297,7 @@ class TaskDependencies:
                         try:
                             dep.responsible = '<a href="mailto:%s">%s</a>' % (_url, _name)
 			    dep.responsible = dep.responsible.encode('utf-8')
-                        except UnicodeDecodeError, err:
+                        except UnicodeDecodeError as err:
                             logger.error("Unicode problem when decoding name of maintainer with mail address <%s> in task %s (%s)" % (_url, self.task, err))
                     continue
 
@@ -1382,7 +1382,7 @@ class TaskDependencies:
                         if dep.properties['vcs-browser'] == HOMEPAGENONE:
                             try:
                                 dep.properties['vcs-browser'] = BrowserFromVcsURL(dep.properties['vcs-type'], dep.properties['vcs-url'])
-                            except KeyError, err:
+                            except KeyError as err:
                                 logger.error("Vcs Property missing in packages file:", dep.properties, err)
                     else:
                         logger.error("Dep not initiated before Vcs-Svn %s -> something is wrong." \
@@ -1420,7 +1420,7 @@ class TaskDependencies:
                         # There is no need to specify the Vcs-{Git,SVN} field in the tasks file but property 'vcs-type' should be set in
                         # any case - so set it here in case it was not set before.  If an apropriate field is set later it becomes
                         # overriden anyway
-                        if not dep.properties.has_key('vcs-url'):
+                        if 'vcs-url' not in dep.properties:
                             dep.properties['vcs-url'] = dep.properties['vcs-browser']
                     else:
                         logger.error("Dep not initiated before Vcs-Browser %s -> something is wrong." \
@@ -1435,7 +1435,7 @@ class TaskDependencies:
                               % (key, stanza[key.lower()]))
                 elif key == 'License':
                     if dep != None:
-                        if dep.vcs_found == 1 and dep.properties.has_key(key.lower()):
+                        if dep.vcs_found == 1 and key.lower() in dep.properties:
                             fields_obsolete.append(key)
                             continue
                         dep.properties[key.lower()]  = stanza[key.lower()]
@@ -1456,7 +1456,7 @@ class TaskDependencies:
                               % (key, stanza[key.lower()]))
                 elif key.startswith('Published-'):
                     if dep != None:
-                        if not dep.properties.has_key('published'):
+                        if 'published' not in dep.properties:
                             dep.properties['published'] = {}
                         ptype = key.replace('Published-','').lower()
                         dep.properties['published'][ptype] = to_unicode(stanza[key.lower()])
@@ -1465,7 +1465,7 @@ class TaskDependencies:
                               % (key, stanza[key.lower()]))
                 elif key == 'WNPP':
                     if dep != None:
-                        if dep.vcs_found == 1 and dep.properties.has_key(key.lower()):
+                        if dep.vcs_found == 1 and key.lower() in dep.properties:
                             fields_obsolete.append(key)
                             continue
                         wnpp = stanza['wnpp'].strip()
@@ -1492,22 +1492,22 @@ class TaskDependencies:
                     else:
                         # Only update use description from task file if not known from official package
                         if dep.desc['en'] == {}:
-                            (short, long) = SplitDescription(to_unicode(stanza['pkg-description']))
+                            (short, int) = SplitDescription(to_unicode(stanza['pkg-description']))
                             dep.desc['en']['short'] = short
-                            dep.desc['en']['long']  = long
+                            dep.desc['en']['long']  = int
                         else:
                             fields_obsolete.append(key)
                             continue
                 elif key == 'Avoid' or key == 'Ignore':
                     dep.pkgstatus = key.lower()
                 elif key == 'Remark':
-                    (short, long) = SplitDescription(stanza['remark'])
+                    (short, int) = SplitDescription(stanza['remark'])
                     if dep == None:
                         _pkg = self.metapkg.PrintedName
                     else:
                         _pkg = dep.pkg
                     remark['short'] = MarkupString(short.encode('utf-8'), _pkg, 'RemarkShort')
-                    remark['long']  = MarkupString(long.encode('utf-8'),  _pkg, 'RemarkLong')
+                    remark['long']  = MarkupString(int.encode('utf-8'),  _pkg, 'RemarkLong')
                     continue
                 else:
             	    if key not in KEYSTOIGNORE:
@@ -1528,7 +1528,7 @@ class TaskDependencies:
                 # first check those packages where some work was just done
                 for status in ['pkgvcs', 'unofficial', 'wnpp', 'prospective']:
                     for field in pkgstatus[status]['fields-set']:
-                        if dep.properties.has_key(field):
+                        if field in dep.properties:
                             if field in HOMEPAGENONEFIELDS and dep.properties[field] == HOMEPAGENONE :
                                 continue
                             dep.pkgstatus = status
@@ -1550,7 +1550,7 @@ class TaskDependencies:
         f.close()
 
         alldepends=[]
-        for status in self.dependencies.keys():
+        for status in list(self.dependencies.keys()):
             for dep in self.dependencies[status]:
                 alldepends.append(dep.pkg)
 
@@ -1568,7 +1568,7 @@ class TaskDependencies:
             for row in RowDictionaries(curs):
                 # seek for package name in list of packages mentioned in tasks file
                 found = False
-                for status in self.dependencies.keys():
+                for status in list(self.dependencies.keys()):
                     for dep in self.dependencies[status]:
                         if dep.pkg == row['package']:
                             found = True
@@ -1636,7 +1636,7 @@ class TaskDependencies:
                     taglist = []
                     for debtag in row['debtags']:
                         (tag,value) = debtag.split('::')
-                        if tagdict.has_key(tag):
+                        if tag in tagdict:
                             tagdict[tag] += ', ' + value
                         else:
                             tagdict[tag]  = value
@@ -1663,7 +1663,7 @@ class TaskDependencies:
                 if row['changed_by']:
                     try:
                         changed = to_unicode(row['changed_by'])
-                    except TypeError, err:
+                    except TypeError as err:
                         changed = None
                         logger.warning("Encoding problem for last uploader of package '%s' in task %s (%s)" % (dep.pkg, dep.taskname, err))
                     if changed:
@@ -1673,7 +1673,7 @@ class TaskDependencies:
                             dep.properties['changed_by']    = MarkupString(changed, dep.pkg, 'changed_by')
                             dep.properties['last_uploader'] = to_unicode(changed)
                             dep.properties['last_uploader_simple'] = to_unicode('%s <%s>' % (_name, _url))
-                        except UnicodeDecodeError, err:
+                        except UnicodeDecodeError as err:
                             logger.error("Encoding problem for last uploader - assume same as maintainer for package %s (%s)", dep.pkg, err)
 
                 # link to packages.debian.org search page to see overview about all
@@ -1686,7 +1686,7 @@ class TaskDependencies:
                         dep.desc[l]['short'] = MarkupString(to_unicode(row['description_'+l]), dep.pkg, 'ShortDesc')
                         if row['long_description_'+l]:
                             dep.desc[l]['long']  = Markup(render_longdesc(row['long_description_'+l].splitlines()))
-                if not dep.desc['en'].has_key('short'):
+                if 'short' not in dep.desc['en']:
                     logger.error("Dep has no English short description: %s", dep.pkg)
                     dep.desc['en']['short'] = "??? missing short description for package %s :-(" % dep.pkg
                 (_name, _url) = email.Utils.parseaddr(row['maintainer'])
@@ -1698,7 +1698,7 @@ class TaskDependencies:
                 # print dep
 
         pkgs_not_in_pool = []
-        for status in self.dependencies.keys():
+        for status in list(self.dependencies.keys()):
             for dep in self.dependencies[status]:
                 if dep.pkg not in pkgs_in_pool:
                     pkgs_not_in_pool.append(dep.pkg)
@@ -1712,7 +1712,7 @@ class TaskDependencies:
                 pkgs_in_new.append(row['package'])
                 # seek for package name in list of packages mentioned in tasks file
                 found = False
-                for status in self.dependencies.keys():
+                for status in list(self.dependencies.keys()):
                     for dep in self.dependencies[status]:
                         if dep.pkg == row['package']:
                             found = True
@@ -1744,7 +1744,7 @@ class TaskDependencies:
                 if row['changed_by']:
                     try:
                         changed = to_unicode(row['changed_by'])
-                    except TypeError, err:
+                    except TypeError as err:
                         changed = None
                         logger.warning("Encoding problem for uploader to ftpnew of package '%s' in task %s (%s)" % (dep.pkg, dep.taskname, err))
                     if changed:
@@ -1754,7 +1754,7 @@ class TaskDependencies:
                             dep.properties['changed_by']    = MarkupString(changed, dep.pkg, 'changed_by')
                             dep.properties['last_uploader'] = to_unicode(changed)
                             dep.properties['last_uploader_simple'] = to_unicode('%s <%s>' % (_name, _url))
-                        except UnicodeDecodeError, err:
+                        except UnicodeDecodeError as err:
                             logger.error("Encoding problem for last uploader - assume same as maintainer for package %s (%s)", dep.pkg, err)
 
         # Verify whether there are virtual packages which are provided by some other packages in the list of dependencies
@@ -1763,7 +1763,7 @@ class TaskDependencies:
         pkgs_virtual = []
         if curs.rowcount > 0:
             virtual_pkgs = RowDictionaries(curs)
-            for status in self.dependencies.keys():
+            for status in list(self.dependencies.keys()):
                 for dep in self.dependencies[status]:
                     if dep.pkg not in pkgs_in_pool and dep.pkg not in pkgs_in_new:
                         found = False
@@ -1779,7 +1779,7 @@ class TaskDependencies:
                                 break
 
         pkgs_not_in_pool = []
-        for status in self.dependencies.keys():
+        for status in list(self.dependencies.keys()):
             for dep in self.dependencies[status]:
                 if dep.pkg not in pkgs_in_pool and dep.pkg not in pkgs_in_new and dep.pkg not in pkgs_virtual:
                     pkgs_not_in_pool.append(dep.pkg)
@@ -1793,7 +1793,7 @@ class TaskDependencies:
                 pkgs_in_vcs.append(row['package'])
                 # seek for package name in list of packages mentioned in tasks file
                 found = False
-                for status in self.dependencies.keys():
+                for status in list(self.dependencies.keys()):
                     for dep in self.dependencies[status]:
                         if dep.pkg == row['package']:
                             found = True
@@ -1829,7 +1829,7 @@ class TaskDependencies:
                 if row['changed_by']:
                     try:
                         changed = to_unicode(row['changed_by'])
-                    except TypeError, err:
+                    except TypeError as err:
                         changed = None
                         logger.warning("Encoding problem for changelog author in Vcs of package '%s' in task %s (%s)" % (dep.pkg, dep.taskname, err))
                     if changed:
@@ -1839,11 +1839,11 @@ class TaskDependencies:
                             dep.properties['changed_by']    = MarkupString(changed, dep.pkg, 'changed_by')
                             dep.properties['last_uploader'] = to_unicode(changed)
                             dep.properties['last_uploader_simple'] = to_unicode('%s <%s>' % (_name, _url))
-                        except UnicodeDecodeError, err:
+                        except UnicodeDecodeError as err:
                             logger.error("Encoding problem for changer - assume same as maintainer for package %s (%s)", dep.pkg, err)
 
         # Verify whether packages which are neither in pool, new, vcs nor virtual have sufficient information in task file
-        for status in self.dependencies.keys():
+        for status in list(self.dependencies.keys()):
             for dep in self.dependencies[status]:
                 if dep.pkg not in pkgs_in_pool and dep.pkg not in pkgs_in_new and dep.pkg not in pkgs_virtual and (dep.pkgstatus == 'unknown' or dep.pkgstatus == 'pkgvcs'):
                     # If only Vcs fields are given than we currently do not know enough to print package information
@@ -1861,10 +1861,10 @@ class TaskDependencies:
                             logger.error("Package %s neither in pool nor new and has no description - ignored" % dep.pkg)
                 else:
                     # prevent printing WNPP of packages inside Debian
-                    if dep.properties.has_key('wnpp') and dep.pkgstatus != 'wnpp':
+                    if 'wnpp' in dep.properties and dep.pkgstatus != 'wnpp':
                         del dep.properties['wnpp']
 
-        for dependency in self.dependencies.keys():
+        for dependency in list(self.dependencies.keys()):
             self.dependencies[dependency].sort()
         return 1 # Success
 
@@ -1900,7 +1900,7 @@ class TaskDependencies:
             self.pkgstatus = 'experimental'
 
 
-        if self.properties.has_key('source'):
+        if 'source' in self.properties:
             query = "EXECUTE src_vcs ('%s')" % (self.properties['source'])
             _execute_udd_query(query)
             if curs.rowcount > 0:
@@ -1908,16 +1908,16 @@ class TaskDependencies:
                 row = RowDictionaries(curs)[0]
                 # If some information about Vcs is found in the database make sure it is ignored from tasks file
                 self.vcs_found = 1
-                for prop in row.keys():
+                for prop in list(row.keys()):
                     if row[prop]:
                         self.properties[prop] = row[prop]
-                if not self.properties.has_key('vcs-browser') or self.properties['vcs-browser'] == HOMEPAGENONE:
+                if 'vcs-browser' not in self.properties or self.properties['vcs-browser'] == HOMEPAGENONE:
                     try:
                         self.properties['vcs-browser'] = BrowserFromVcsURL(self.properties['vcs-type'], self.properties['vcs-url'])
-                    except KeyError, err:
+                    except KeyError as err:
                         logger.warning("Vcs Property missing in Database:", self.properties, err)
-                if not self.properties.has_key('vcs-type') or not self.properties['vcs-type']:
-                    if self.properties.has_key('vcs-browser') and self.properties['vcs-browser'] != HOMEPAGENONE:
+                if 'vcs-type' not in self.properties or not self.properties['vcs-type']:
+                    if 'vcs-browser' in self.properties and self.properties['vcs-browser'] != HOMEPAGENONE:
                         self.properties['vcs-type']    = VcsTypeFromBrowserURL(self.properties['vcs-browser'])
             # We are only interested in source packages (for instance for Bugs page)
             if source == 1:
@@ -1977,14 +1977,14 @@ class TaskDependencies:
                         logger.warning("Dependency with unknown status: %s (Task %s)" % (dep.pkg, dep.taskname))
 
 
-        for dependency in self.dependencies.keys():
+        for dependency in list(self.dependencies.keys()):
             self.dependencies[dependency].sort()
 
     def MarkupPreformatedStrings(self):
         # Genshi does not touch strings that are marked with "Markup()" - so just
         # mark the strings that are ready formatted
 
-        for dependency in self.dependencies.keys():
+        for dependency in list(self.dependencies.keys()):
             for dep in self.dependencies[dependency]:
                 dep.responsible         = MarkupString(dep.responsible, dep.pkg, 'responsible')
                 if dep.desc['en'] != {}:
diff --git a/webtools/blendstasktools_udd.py b/webtools_py3/blendstasktools_udd.py
similarity index 89%
copy from webtools/blendstasktools_udd.py
copy to webtools_py3/blendstasktools_udd.py
index 135f5b8..db367e9 100644
--- a/webtools/blendstasktools_udd.py
+++ b/webtools_py3/blendstasktools_udd.py
@@ -8,12 +8,12 @@ from subprocess import Popen, PIPE
 import os
 import grp
 import stat
-import urllib
-import StringIO
+import urllib.request, urllib.parse, urllib.error
+import io
 import gzip
 import bz2
 import re
-import email.Utils
+import email.utils
 
 import psycopg2
 import gettext
@@ -144,7 +144,7 @@ pkgstatus = {'official_high' : # official package with high priority dependency
                                  'order'        : 9
                                },
              'ignore'        : # Package inside Debian which is "under observation"
-                               { 'releases'     : (releases.keys()),
+                               { 'releases'     : (list(releases.keys())),
                                  'component'    : ('main', 'contrib', 'non-free'),
                                  'dependencies' : ('Ignore', ),
                                  'fields-set'   : (),
@@ -152,7 +152,7 @@ pkgstatus = {'official_high' : # official package with high priority dependency
                                  'order'        : 10
                                },
              'avoid'         : # Package inside Debian which should not go to a install medium of the Blend
-                               { 'releases'     : (releases.keys()),
+                               { 'releases'     : (list(releases.keys())),
                                  'component'    : ('main', 'contrib', 'non-free'),
                                  'dependencies' : ('Avoid', ),
                                  'fields-set'   : (),
@@ -171,7 +171,7 @@ pkgstatus = {'official_high' : # official package with high priority dependency
 
 # http://wiki.python.org/moin/HowTo/Sorting#Sortingbykeys
 _tmplist=[]
-for key in pkgstatus.keys():
+for key in list(pkgstatus.keys()):
     _tmplist.append((key,pkgstatus[key]['order']))
 _tmpsorted = sorted(_tmplist, key=lambda x:(x[1], x[0]))
 pkgstatus_sortedkeys = []
@@ -212,8 +212,8 @@ def LockBlendsTools():
     """Locking mechanism to make sure the scripts will not run in parallel
        which happened because of IO problems on udd.debian.org"""
     if not has_psutils:
-	logger.warning("Package python-psutil is missing.  No locking support available")
-	return
+	    logger.warning("Package python-psutil is missing.  No locking support available")
+	    return
     if os.path.exists(LOCKFILE):
         try:
             lf = open(LOCKFILE, 'r')
@@ -229,7 +229,7 @@ def LockBlendsTools():
             pass
     pid = os.getpid()
     lf = open(LOCKFILE, 'w')
-    print >>lf, pid
+    print(pid, file=lf)
     lf.close()
     SetFilePermissions(LOCKFILE)
 
@@ -251,7 +251,7 @@ def GetDependencies2Use(dependencystatus=[], max_order='prospective'):
     else:
         # verify correctly given dependencies
         for pkgstat in dependencystatus:
-            if pkgstat in pkgstatus.keys():
+            if pkgstat in list(pkgstatus.keys()):
                 use_dependencystatus.append(pkgstat)
             else:
                 logger.error("Unknown dependencystatus %s" % pkgstat)
@@ -262,20 +262,21 @@ def GetDependencies2Use(dependencystatus=[], max_order='prospective'):
 ###########################################################################################
 # Define several prepared statements to query UDD
 try:
-  conn = psycopg2.connect(host="localhost",port=PORT,user="guest",database="udd")
-except psycopg2.OperationalError, err:
+    conn = psycopg2.connect(host="localhost",port=PORT,user="guest",database="udd")
+    conn.set_client_encoding('utf-8')
+except psycopg2.OperationalError as err:
   try:
     conn = psycopg2.connect("service=udd")
-  except psycopg2.OperationalError, err:
+  except psycopg2.OperationalError as err:
     # logger not known at this state: logger.warning
-    print >>stderr, "Service=udd seems not to be installed on this host.\tMessage: %s" % (str(err))
+    print("Service=udd seems not to be installed on this host.\tMessage: %s" % (str(err)), file=stderr)
     try:
         conn = psycopg2.connect(host="localhost",port=DEFAULTPORT,user="guest",database="udd")
     except psycopg2.OperationalError:
-	# Hmmm, I observed a really strange behaviour on one of my machines where connecting to
-	# localhost does not work but 127.0.0.1 works fine.  No idea why ... but this should
-	# do the trick for the moment
-	conn = psycopg2.connect(host="127.0.0.1",port=DEFAULTPORT,user="guest",database="udd")
+	    # Hmmm, I observed a really strange behaviour on one of my machines where connecting to
+	    # localhost does not work but 127.0.0.1 works fine.  No idea why ... but this should
+	    # do the trick for the moment
+	    conn = psycopg2.connect(host="127.0.0.1",port=DEFAULTPORT,user="guest",database="udd")
 
 curs = conn.cursor()
 # uddlog = open('logs/uddquery.log', 'w')
@@ -284,12 +285,12 @@ def _execute_udd_query(query):
     try:
         curs.execute(query)
         logger.debug(query)
-    except psycopg2.ProgrammingError, err:
-        print >>stderr, "Problem with query\n%s" % (to_unicode(query))
-        print >>stderr, err
+    except psycopg2.ProgrammingError as err:
+        print("Problem with query\n%s" % ((query)), file=stderr)
+        print(err, file=stderr)
         exit(-1)
-    except psycopg2.DataError, err:
-        print >>stderr, "%s; query was\n%s" % (err, query)
+    except psycopg2.DataError as err:
+        print("%s; query was\n%s" % (err, query), file=stderr)
 
 
 query = """PREPARE query_pkgs (text[],text[]) AS
@@ -534,24 +535,24 @@ def ReadConfig(blendname=''):
                                                     # for instance at www.debian.org or wiki.debian.org
         ret['aliothurl']   = stanza['aliothurl']    # Link to the Alioth page of the project
         ret['projectlist'] = stanza['projectlist']  # Mailinglist of the project
-        if stanza.has_key('pkglist'):
+        if 'pkglist' in stanza:
             ret['pkglist'] = stanza['pkglist']      # Packaging Mailinglist = Maintainer of group maintained packages
-        if stanza.has_key('logourl'):
+        if 'logourl' in stanza:
             ret['logourl'] = stanza['logourl']      # URL to logo image (might be missing
         ret['css']         = stanza['css']          # (relative) URL to CSS file
         ret['outputdir']   = stanza['outputdir']    # Dir for storing output HTML files
         ret['datadir']     = stanza['datadir']      # Dir for storing SVN information about project
         ret['vcsdir']      = stanza['vcsdir']       # Path to Blend information files at svn.debian.org
-        if stanza.has_key('advertising'):
+        if 'advertising' in stanza:
             # we have to remove the gettext _() call which was inserted into the config
             # file to enable easy input for config file editors - but the call has to
             # be made explicitely in the python code
             advertising = re.sub('_\(\W(.+)\W\)', '\\1', stanza['advertising'])
             # gettext needs to escape '"' thus we need to remove the escape character '\'
             ret['advertising'] = re.sub('\\\\"', '"', advertising)
-        if stanza.has_key('ubuntuhome'):
+        if 'ubuntuhome' in stanza:
             ret['ubuntuhome'] = stanza['ubuntuhome']
-        if stanza.has_key('projectubuntu'):
+        if 'projectubuntu' in stanza:
             ret['projectubuntu'] = stanza['projectubuntu']
 
     return ret
@@ -733,9 +734,9 @@ class DependantPackage:
             ret += ", versions: "     + str(self.version)
         if self.desc:
             ret += ", desc: "         + str(self.desc)
-        for prop in self.properties.keys():
+        for prop in list(self.properties.keys()):
             try:
-                ret += ", %s: %s" % (prop, to_unicode(str(self.properties[prop])))
+                ret += ", %s: %s" % (prop, self.properties[prop])
             except UnicodeEncodeError:            
                 ret += ", %s: <UnicodeEncodeError>" % (prop)
         try:
@@ -824,6 +825,8 @@ class Tasks:
             query = "EXECUTE query_metapkg_trans('%s')" % List2PgArray(metapackages)
             _execute_udd_query(query)
             if curs.rowcount > 0:
+                #curs.execute("show client_encoding")
+                #print(curs.fetchone()[0])
                 for row in RowDictionaries(curs):
                     metapkg_translations[row['package']] = row
 
@@ -831,15 +834,16 @@ class Tasks:
             td = TaskDependencies(self.blendname, task=task)
             pkgname = prefix + task
             translations = None
-            if metapkg_translations.has_key(pkgname):
+            if pkgname in metapkg_translations:
                 translations = metapkg_translations[pkgname]
         
             td.SetMetapackageInfo(pkgname, translations)
-	    logger.debug("Task : %s " % task)	    
+            logger.debug("Task : %s " % task)	    
             if td.GetTaskDependencies(source):
                 self.tasks[task] = td
+            
             else: # Kick file that is obviously no task file from metapackage list
-                self.metapackagekeys = filter(lambda name: name != task, self.metapackagekeys)
+                self.metapackagekeys = [name for name in self.metapackagekeys if name != task]
 
         if source == 0:
             # total number popcon submissions
@@ -910,14 +914,14 @@ class Tasks:
         # otherwise
         for task in self.metapackagekeys:
             tdeps = self.tasks[task]
-            for dependency in tdeps.dependencies.keys():
+            for dependency in list(tdeps.dependencies.keys()):
                 for dep in tdeps.dependencies[dependency]:
                     if dep.properties['Enhances'] != {}:
                         logger.debug("Package %s is enhanced by:" % dep.pkg)
-                        for enh in dep.properties['Enhances'].keys():
+                        for enh in list(dep.properties['Enhances'].keys()):
                             # seek for Enhances on same page
                             found = 0
-                            for seek_dependency in tdeps.dependencies.keys():
+                            for seek_dependency in list(tdeps.dependencies.keys()):
                                 for enhdep in tdeps.dependencies[seek_dependency]:
                                     if enh == enhdep.pkg:
                                         dep.properties['Enhances'][enh] = '#'+enh
@@ -928,7 +932,7 @@ class Tasks:
                                     if enhtask == task:
                                         continue
                                     enhtdeps = self.tasks[enhtask]
-                                    for seek_dependency in enhtdeps.dependencies.keys():
+                                    for seek_dependency in list(enhtdeps.dependencies.keys()):
                                         for enhdep in enhtdeps.dependencies[seek_dependency]:
                                             if enh == enhdep.pkg:
                                                 dep.properties['Enhances'][enh] = './' + enhtask + '#' + enh
@@ -977,24 +981,24 @@ class TaskDependencies:
             if ddtptranslations['description_'+lang]:
                 self.metapkg.desc[lang] = {}
                 try:
-                    short = to_unicode(ddtptranslations['description_'+lang])
+                    short = (ddtptranslations['description_'+lang])
                     self.metapkg.desc[lang]['short'] = MarkupString(short, self.metapkg.pkg, 'taskShortDesc', lang)
 
-                except UnicodeEncodeError, err:
+                except UnicodeEncodeError as err:
                     logger.error("===> UnicodeDecodeError in metapackage %s (lang='%s'): '%s'; ErrTxt: %s" % \
                                      (self.metapkg.pkg, lang, ddtptranslations['description_'+lang], err))
-                    short = to_unicode(ddtptranslations['description_'+lang],'latin1')
+                    short = ddtptranslations['description_'+lang]
                     self.metapkg.desc[lang]['short'] = MarkupString(short, self.metapkg.pkg, 'taskShortDesc' + lang)
 
                 try:
                     self.metapkg.desc[lang]['long'] = Markup(render_longdesc(ddtptranslations['long_description_'+lang].splitlines()))
 
-                except UnicodeDecodeError, err:
+                except UnicodeDecodeError as err:
                     logger.error("===> UnicodeDecodeError in metapackage long %s (lang='%s'): '%s'; ErrTxt: %s" % \
                                      (self.metapkg.pkg, lang, ddtptranslations['long_description_'+lang], err))
                     self.metapkg.desc[lang]['long'] = 'UnicodeDecodeError'
 
-                except AttributeError, err:
+                except AttributeError as err:
                     logger.error("===> AttributeError in metapackage long %s (lang='%s'): '%s'; ErrTxt: %s" % \
                                      (self.metapkg.pkg, lang, ddtptranslations['long_description_'+lang], err))
                     self.metapkg.desc[lang]['long'] = 'Missing long description'
@@ -1006,31 +1010,31 @@ class TaskDependencies:
         if dep == None:
             return
         if dep.dep_strength == 'i' or dep.dep_strength == 'a':
-	    logger.debug("Ignore/Avoid package : %s" % dep.pkg)
+            logger.debug("Ignore/Avoid package : %s" % dep.pkg)
             return
 
-	# Solves UnicodeEncodeError because of characters present in the
+	    # Solves UnicodeEncodeError because of characters present in the
         # long description of the dependecies in 'unoficial','prospective' packages
-        try:
-       	    dep.desc['en']['long'] = dep.desc['en']['long'].encode('ascii','xmlcharrefreplace')
-        except:
-            pass
+        # try:
+        #    dep.desc['en']['long'] = dep.desc['en']['long'].encode('ascii','xmlcharrefreplace')
+        # except:
+        #    pass
 
         # Solves UnicodeEncodeError because of characters present in the
         # authors name of the dependencies in 'wnpp' packages
-	try:
-           dep.properties['published']['authors'] = dep.properties['published']['authors'].encode('ascii','xmlcharrefreplace')
-        except:
-           pass
-
-	# Solves UnicodeEncodeError because of characters present in the title of 
-	# dependencies in blends debian-science, debian-pan
-	try:
-           dep.properties['published']['title'] = dep.properties['published']['title'].encode('ascii','xmlcharrefreplace')
-        except:
-           pass
-
-	logger.debug("Appending package to list : %s" % dep.pkg)
+        # try:
+        #    dep.properties['published']['authors'] = dep.properties['published']['authors'].encode('ascii','xmlcharrefreplace')
+        # except:
+        #   pass
+
+        # Solves UnicodeEncodeError because of characters present in the title of 
+        # dependencies in blends debian-science, debian-pan
+        # try:
+        #    dep.properties['published']['title'] = dep.properties['published']['title'].encode('ascii','xmlcharrefreplace')
+        # except:
+        #    pass
+
+        logger.debug("Appending package to list : %s" % dep.pkg)
         self.dependencies[dep.pkgstatus].append(dep)
         return
 
@@ -1055,66 +1059,66 @@ class TaskDependencies:
             found = False
             for dep in dependencies:
                 if dep.pkg == row['package']:
-		    logger.debug("Package : %s" % dep.pkg)
+                    logger.debug("Package : %s" % dep.pkg)
                     found = True
                     break
 	
             # Now set the information for the package found in the database (not for prospective packages)
             # Debian Edu contains packages from main/debian-installer - that's why we use startswith here
-	    if pkg_src != 2:
+            if pkg_src != 2:
                 if row['component'].startswith('main'):
                     dep.component = 'main'
-	            if dep.dep_strength == 'd' or dep.dep_strength == 'r':
+                    if dep.dep_strength == 'd' or dep.dep_strength == 'r':
                         dep.pkgstatus = 'official_high'
                     elif dep.dep_strength == 's':
                         dep.pkgstatus = 'official_low'
-		    else:
-		        dep.pkgstatus = 'new'
+                    else:
+                        dep.pkgstatus = 'new'
                 else:
                     dep.component = row['component']
                     # If a package is not found in main its status can be maximum non-free
                     dep.pkgstatus = 'non-free'
-	    elif pkg_src == 2:
-		dep.pkgstatus = 'pkgvcs'
+            elif pkg_src == 2:
+                    dep.pkgstatus = 'pkgvcs'
             
             # if a package is released *only* in experimental decrease package status
             if 'release' in row and row['release'] == 'experimental':
-	        dep.pkgstatus = 'experimental'		
+                dep.pkgstatus = 'experimental'		
 
             if dep.dep_strength == 'i':
-		dep.pkgstatus = 'ignore'
-	    elif dep.dep_strength == 'a':
-		dep.pkgstatus = 'avoid'
+                dep.pkgstatus = 'ignore'
+            elif dep.dep_strength == 'a':
+                dep.pkgstatus = 'avoid'
 
-	    # dep.properties['license'] is already correct
+	        # dep.properties['license'] is already correct
             for prop in PROPERTIES:
                 dep.properties[prop] = row[prop]
                             
-	    type_vcs = ''
-	    if 'vcs_type' in row :
-		type_vcs = 'vcs_type'
-	    elif 'vcs-type' in row:
-		type_vcs = 'vcs-type' 
-	    if type_vcs != '':
-	        dep.properties['vcs-type'] = row[type_vcs]
-
-	    type_url = ''
-	    if 'vcs_url' in row :
-		type_url = 'vcs_url'
-	    elif 'vcs-url' in row:
-		type_url = 'vcs-url' 
-	    if type_url != '':
+            type_vcs = ''
+            if 'vcs_type' in row :
+                type_vcs = 'vcs_type'
+            elif 'vcs-type' in row:
+                type_vcs = 'vcs-type' 
+            if type_vcs != '':
+                dep.properties['vcs-type'] = row[type_vcs]
+
+            type_url = ''
+            if 'vcs_url' in row :
+                type_url = 'vcs_url'
+            elif 'vcs-url' in row:
+                type_url = 'vcs-url' 
+            if type_url != '':
                 dep.properties['vcs-url'] = row[type_url]
 
-	    type_browser = ''
-	    if 'vcs_browser' in row :
-		type_browser = 'vcs_browser'
-	    elif 'vcs-browser' in row:
-		type_browser = 'vcs-browser'
-	    if type_browser != '':
+            type_browser = ''
+            if 'vcs_browser' in row :
+                type_browser = 'vcs_browser'
+            elif 'vcs-browser' in row:
+                type_browser = 'vcs-browser'
+            if type_browser != '':
                 dep.properties['vcs-browser'] = row[type_browser]
             elif dep.properties['vcs-browser'] == HOMEPAGENONE and type_vcs != '' and type_url != '':
-                 dep.properties['vcs-browser'] = BrowserFromVcsURL(dep.properties['vcs-type'], dep.properties['vcs-url'])
+                dep.properties['vcs-browser'] = BrowserFromVcsURL(dep.properties['vcs-type'], dep.properties['vcs-url'])
 
             # enhances to be written
             # if row['enhanced']:
@@ -1124,37 +1128,37 @@ class TaskDependencies:
 
 
             if 'releases' in row:
-		for i in range(len(row['releases'])):
+                for i in range(len(row['releases'])):
                     dep.version.append({'release':row['releases'][i], 'version': row['versions'][i], 'archs':row['architectures'][i]})
             
-	    if 'vote' in row:                
+            if 'vote' in row:
                 dep.popcon['vote']   = row['vote']
-	    if 'recent' in row:
+            if 'recent' in row:
                 dep.popcon['recent'] = row['recent']
                            
             # Debtags as sorted list of dict fields
             if 'debtags' in row:
-	     if row['debtags']:
-                if dep.debtags: # there is no reasonable way that debtags was set before - so something is wrong here and a warning should be issued
-                    logger.warning("Debtags for package '%s' was just set.  A duplicated result from database query is suspected.  Please check the result!" % dep.pkg)
-                tagdict = {}
-                taglist = []
-                for debtag in row['debtags']:
-                    (tag,value) = debtag.split('::')
-                    if tagdict.has_key(tag):
-                        tagdict[tag] += ', ' + value
-                    else:
-                        tagdict[tag]  = value
-                    taglist.append(tag)
-                if taglist:
-                    taglist.sort()
+                if row['debtags']:
+                    if dep.debtags: # there is no reasonable way that debtags was set before - so something is wrong here and a warning should be issued
+                        logger.warning("Debtags for package '%s' was just set.  A duplicated result from database query is suspected.  Please check the result!" % dep.pkg)
+                    tagdict = {}
+                    taglist = []
+                    for debtag in row['debtags']:
+                        (tag,value) = debtag.split('::')
+                        if tag in tagdict:
+                            tagdict[tag] += ', ' + value
+                        else:
+                            tagdict[tag]  = value
+                        taglist.append(tag)
+                    if taglist:
+                        taglist.sort()
                                 
-                for tag in taglist:
-                    dep.debtags.append({'tag':tag, 'value':tagdict[tag]})
+                    for tag in taglist:
+                        dep.debtags.append({'tag':tag, 'value':tagdict[tag]})
 
             # screenshots
             if 'icon' in row:
-		if row['icon']:
+                if row['icon']:
                     dep.icon           = row['icon'][0]                        
                     dep.image          = row['image'][0]                        
                     dep.screenshot_url = 'http://screenshots.debian.net/package/' + dep.pkg                        
@@ -1162,7 +1166,7 @@ class TaskDependencies:
                         dep.screenshots.append({'version':row['screenshot_versions'][i], 'url':row['image'][i]})
                                 
             # it might be that the new upstream goes to experimental - this should be ignored here
-	    if 'unstable_parsed_version' in row:
+            if 'unstable_parsed_version' in row:
                 if row['unstable_parsed_version']:
                     dep.outdated['release']       = 'upstream'
                     dep.outdated['version']       = row['unstable_upstream']
@@ -1170,18 +1174,18 @@ class TaskDependencies:
 
             if row['changed_by']:
                 try:
-                    changed = to_unicode(row['changed_by'])
-                except TypeError, err:
+                    changed = row['changed_by']
+                except TypeError as err:
                     changed = None
                     logger.warning("Encoding problem for last uploader of package '%s' in task %s (%s)" % (dep.pkg, dep.taskname, err))
                 if changed:
                     try:
-                        (_name, _url) = email.Utils.parseaddr(changed)
+                        (_name, _url) = email.utils.parseaddr(changed)
                         changed = '<a href="mailto:%s">%s</a>' % (_url, _name)
                         dep.properties['changed_by']    = MarkupString(changed, dep.pkg, 'changed_by')                                
-                        dep.properties['last_uploader'] = to_unicode(changed)                                  
-                        dep.properties['last_uploader_simple'] = to_unicode('%s <%s>' % (_name, _url))
-                    except UnicodeDecodeError, err:
+                        dep.properties['last_uploader'] = (changed)                                  
+                        dep.properties['last_uploader_simple'] = ('%s <%s>' % (_name, _url))
+                    except UnicodeDecodeError as err:
                         logger.error("Encoding problem for last uploader - assume same as maintainer for package %s (%s)", dep.pkg, err)
 
            # link to packages.debian.org search page to see overview about all
@@ -1191,18 +1195,18 @@ class TaskDependencies:
             for l in languages:
                 if 'description_'+l in row and row['description_'+l] != None:
                     dep.desc[l] = {}
-                    dep.desc[l]['short'] = MarkupString(to_unicode(row['description_'+l]), dep.pkg, 'ShortDesc')
+                    dep.desc[l]['short'] = MarkupString((row['description_'+l]), dep.pkg, 'ShortDesc')
                     if row['long_description_'+l]:
                         dep.desc[l]['long']  = Markup(render_longdesc(row['long_description_'+l].splitlines()))
-                    if not dep.desc['en'].has_key('short'):
+                    if 'short' not in dep.desc['en']:
                         logger.error("Dep has no English short description: %s", dep.pkg)
                         dep.desc['en']['short'] = "??? missing short description for package %s :-(" % dep.pkg
                     
-                    (_name, _url) = email.Utils.parseaddr(row['maintainer'])
-                    dep.properties['maintainer'] = to_unicode(row['maintainer'])
-                    dep.responsible = '<a href="mailto:%s">%s</a>' % (_url, to_unicode(_name))
+                    (_name, _url) = email.utils.parseaddr(row['maintainer'])
+                    dep.properties['maintainer'] = (row['maintainer'])
+                    dep.responsible = '<a href="mailto:%s">%s</a>' % (_url, (_name))
 
-	    self._AppendDependency2List(dep)
+            self._AppendDependency2List(dep)
 
     def GetTaskDependencies(self, source=0):
         count = 0
@@ -1218,9 +1222,8 @@ class TaskDependencies:
         if curs.rowcount > 0:
             self.metapkg.PrintedName, short, long = curs.fetchone()
             # Markup strings to enable verbatim output of preformatted text
-            self.metapkg.desc['en']['short'] = MarkupString(short.encode('utf-8'), self.metapkg.PrintedName, 'taskShortDesc')
-            long = long.decode('utf-8')
-            self.metapkg.desc['en']['long']  = MarkupString(long.encode('utf-8'),  self.metapkg.PrintedName, 'taskLongDesc')
+            self.metapkg.desc['en']['short'] = MarkupString(short, self.metapkg.PrintedName, 'taskShortDesc')
+            self.metapkg.desc['en']['long']  = MarkupString(long,  self.metapkg.PrintedName, 'taskLongDesc')
 
 
         # Get the package_name, license, dependency of the official dependencies of the task
@@ -1247,7 +1250,7 @@ class TaskDependencies:
         _execute_udd_query(query)
         if curs.rowcount > 0:
             self.GetDepInfo(curs, dependencies, 1)
-	    logger.debug("Executed query for official packages for %s task" % self.task)
+            logger.debug("Executed query for official packages for %s task" % self.task)
 	
 
         # Get the package_name, license, dependency of the prospective dependencies of the task
@@ -1260,7 +1263,7 @@ class TaskDependencies:
         dependencies = []
         if curs.rowcount > 0:
             pros_info = curs.fetchall() 
-	    for each_pros in pros_info:
+            for each_pros in pros_info:
                 dep = DependantPackage(self.blendname, self.task)
                 
                 dep.pkg = each_pros[0]          # Name
@@ -1270,8 +1273,7 @@ class TaskDependencies:
                 alldepends.append(dep.pkg)
                 dependencies.append(dep)
 	
-
-	query = "SELECT DISTINCT bp.package, bp.license, b.dependency, bp.component, bp.homepage, bp.section, \
+        query = "SELECT DISTINCT bp.package, bp.license, b.dependency, bp.component, bp.homepage, bp.section, \
                         bp.source, bp.vcs_type, bp.vcs_url, bp.vcs_browser, bp.changed_by, \
                         bp.uploaders, bp.maintainer, pop.vote, pop.recent, tags.debtags, bp.description AS description_en, bp.long_description AS long_description_en\
                 FROM blends_prospectivepackages bp JOIN blends_dependencies b ON b.blend=bp.blend AND b.package=bp.package \
@@ -1289,20 +1291,20 @@ class TaskDependencies:
         _execute_udd_query(query)
         if curs.rowcount > 0:
             self.GetDepInfo(curs, dependencies, 2)
-	    logger.debug("Executed query for prospective packages for %s task" % self.task)
+            logger.debug("Executed query for prospective packages for %s task" % self.task)
 
 
         # Get information about new dependencies of the task
         query = "SELECT DISTINCT new.package FROM new_packages new JOIN blends_dependencies b ON b.package=new.package \
                 WHERE b.blend='%s' and b.task='%s' ORDER BY new.package" % (self.blendname, self.task)
         _execute_udd_query(query)
-	alldepends = []
-	dependencies = []
-	pkgs_new = []
+        alldepends = []
+        dependencies = []
+        pkgs_new = []
         if curs.rowcount > 0:
             pkgs_new = curs.fetchall()
 
-	    for each_new_pkg in pkgs_new:
+            for each_new_pkg in pkgs_new:
                 dep = DependantPackage(self.blendname, self.task)
               
                 dep.pkg = each_new_pkg[0]          # Name
@@ -1314,15 +1316,15 @@ class TaskDependencies:
         _execute_udd_query(query)
         if curs.rowcount > 0:
             self.GetDepInfo(curs, dependencies, 3)
-	    logger.debug("Executed query for new packages for %s task" % self.task)
+            logger.debug("Executed query for new packages for %s task" % self.task)
 
-	return 1
+        return 1
 
     def MarkupPreformatedStrings(self):
         # Genshi does not touch strings that are marked with "Markup()" - so just
         # mark the strings that are ready formatted
 
-        for dependency in self.dependencies.keys():
+        for dependency in list(self.dependencies.keys()):
             for dep in self.dependencies[dependency]:
                 dep.responsible         = MarkupString(dep.responsible, dep.pkg, 'responsible')
                 if dep.desc['en'] != {}:
diff --git a/webtools/blendsunicode.py b/webtools_py3/blendsunicode.py
similarity index 70%
copy from webtools/blendsunicode.py
copy to webtools_py3/blendsunicode.py
index 10b7cc7..302f251 100644
--- a/webtools/blendsunicode.py
+++ b/webtools_py3/blendsunicode.py
@@ -10,16 +10,16 @@ from sys import stderr
 
 def to_unicode(value, encoding='utf-8'):
     if isinstance(value, str):
-	try:
-	    return value.decode(encoding).encode('ascii', 'xmlcharrefreplace')
-    	except UnicodeDecodeError, err:
-    	    print >>stderr, "type(value) =", type(value), \
+        try:
+            return value.encode('ascii', 'xmlcharrefreplace')
+        except UnicodeDecodeError as err:
+            print("type(value) =", type(value), \
     	                    "; isinstance(value, str) =", isinstance(value, str), \
-    	                    ";", err
-    	    print >>stderr, value
-    	    return '???'
+    	                    ";", err, file=stderr)
+            print(value, file=stderr)
+            return '???'
     else:
-        return unicode(value)
+        return str(value)
 
 # from types import *
 #def my_unicode(str):
diff --git a/webtools/bugs.py b/webtools_py3/bugs.py
similarity index 92%
copy from webtools/bugs.py
copy to webtools_py3/bugs.py
index c0faa3b..254f499 100755
--- a/webtools/bugs.py
+++ b/webtools_py3/bugs.py
@@ -34,12 +34,12 @@ from blendsmarkdown  import MarkupString
 # Define several prepared statements to query UDD
 try:
   conn = psycopg2.connect(host="localhost",port=PORT,user="guest",database="udd")
-except psycopg2.OperationalError, err:
+except psycopg2.OperationalError as err:
   try:
     conn = psycopg2.connect("service=udd")
-  except psycopg2.OperationalError, err:
+  except psycopg2.OperationalError as err:
     # logger not known at this state: logger.warning
-    print >>stderr, "Service=udd seems not to be installed on this host.\tMessage: %s" % (str(err))
+    print("Service=udd seems not to be installed on this host.\tMessage: %s" % (str(err)), file=stderr)
     try:
         conn = psycopg2.connect(host="localhost",port=DEFAULTPORT,user="guest",database="udd")
     except psycopg2.OperationalError:
@@ -57,19 +57,19 @@ def _execute_udd_query(query):
         curs.execute(query)
         elapsed_time = time.time() - t
         if elapsed_time > SLOWQUERYREPORTLIMIT: # report what query took longer than SLOWQUERYREPORTLIMIT seconds
-            print "Time: %s\nQuery: %s" % (str(elapsed_time), query)
-    except psycopg2.ProgrammingError, err:
-        print >>stderr, "Problem with query\n%s" % (query)
-        print >>stderr, err
+            print("Time: %s\nQuery: %s" % (str(elapsed_time), query))
+    except psycopg2.ProgrammingError as err:
+        print("Problem with query\n%s" % (query), file=stderr)
+        print(err, file=stderr)
         exit(-1)
-    except psycopg2.DataError, err:
-        print >>stderr, "%s; query was\n%s" % (err, query)
+    except psycopg2.DataError as err:
+        print("%s; query was\n%s" % (err, query), file=stderr)
 
 
 def main():
 
     if len(argv) <= 1:
-        print >>stderr, "Usage: %s <Blend name>" % argv[0]
+        print("Usage: %s <Blend name>" % argv[0], file=stderr)
         exit(-1)
 
     blendname = argv[1]
@@ -178,7 +178,7 @@ def main():
                     for s in SEVERITIES:
                         bugs_data[task][status]['severities'][s] = 0
     else:
-        print >>stderr, "No tasks metadata received for Blend", blendname
+        print("No tasks metadata received for Blend", blendname, file=stderr)
         exit(1)
 
     # Fetch bugs of all Blends dependencies and store them in a dictionary
@@ -186,7 +186,7 @@ def main():
     bugs = {}
     if curs.rowcount > 0:
         for bug in RowDictionaries(curs):
-            if not bugs.has_key(bug['source']):
+            if bug['source'] not in bugs:
                 bugs[bug['source']] = {}
                 bugs[bug['source']]['severities'] = {}
                 for s in SEVERITIES:
@@ -196,7 +196,7 @@ def main():
                 bugs[bug['source']]['open'] = []
                 bugs[bug['source']]['done'] = []
             b = {}
-            for k in bug.keys():
+            for k in list(bug.keys()):
                 if k in ('source', 'status') :
                     continue
                 if k == 'title':
@@ -218,7 +218,7 @@ def main():
                 bugs[bug['source']]['nopenbugs'] += 1
                 bugs[bug['source']]['severities'][bug['severity']] += 1
     else:
-        print >>stderr, "No bug data received for Blend", blendname
+        print("No bug data received for Blend", blendname, file=stderr)
         exit(1)
 
     # Merge metadata of packages and bugs together in bugs_data dictionary, also do statistics about bugs
@@ -247,7 +247,7 @@ def main():
                         bugs_data[task][pkg['status']]['severities'][s] += bugs[pkg['source']]['severities'][s]
                         bugs_data[task]['weighttask'] += 1 * WEIGHT[s] * bugs[pkg['source']]['severities'][s]
                 else:
-                    print >>stderr, "%s: Wrong status %s in task %s for source %s" % (blendname, pkg['status'], task, pkg['source'])
+                    print("%s: Wrong status %s in task %s for source %s" % (blendname, pkg['status'], task, pkg['source']), file=stderr)
                     exit(1)
                 bugs_data[task][pkg['status']]['sources'].append(sources)
                 bugs_data[task]['nopenbugs'] += bugs[pkg['source']]['nopenbugs']
@@ -265,7 +265,7 @@ def main():
                     bugs_data[task]['done_l'].append(pkg['source'])
                     bugs_data[task]['done']['sources'].append(sources)
     else:
-        print >>stderr, "No information about buggy packages received for Blend", blendname
+        print("No information about buggy packages received for Blend", blendname, file=stderr)
         exit(1)
 
     # Define directories used
@@ -289,7 +289,7 @@ def main():
     data={}
     data['projectname'] = blendname
     data['bugs_data']   = bugs_data
-    if config.has_key('advertising') and config['advertising'] != None:
+    if 'advertising' in config and config['advertising'] != None:
         # we have to remove the gettext _() call which was inserted into the config
         # file to enable easy input for config file editors - but the call has to
         # be made explicitely in the python code
@@ -369,13 +369,13 @@ the right shows the tasks of %s.""" ) \
         f = open(blendname+'_bugs.json', 'w')
         if debug > 1:
             for task in bugs_data:
-                print >>f, "*** %s ***" % task
+                print("*** %s ***" % task, file=f)
                 for status in STATES:
-                    if bugs_data[task].has_key(status):
-                        print >>f, status
-                        print >>f, json.dumps(bugs_data[task][status])
-                print >>f
-        print >>f, json.dumps(bugs_data)
+                    if status in bugs_data[task]:
+                        print(status, file=f)
+                        print(json.dumps(bugs_data[task][status]), file=f)
+                print(file=f)
+        print(json.dumps(bugs_data), file=f)
         f.close()
         SetFilePermissions(blendname+'_bugs.json')
 
@@ -458,13 +458,13 @@ the right shows the tasks of %s.""" ) \
     	template = loader.load('bugs.xhtml')
     	f = open(outputdir + '/' + task + '.html', 'w')
     	try:
-            print >> f, template.generate(**data).render('xhtml')
-        except UnicodeDecodeError, err:
+            print(template.generate(**data).render('xhtml'), file=f)
+        except UnicodeDecodeError as err:
             fd = open('debug_'+blendname+'_bugs.json', 'w')
-            print >>fd, json.dumps(bugs_data[task])
+            print(json.dumps(bugs_data[task]), file=fd)
             fd.close()
             SetFilePermissions(outputdir + '/' + task + '.html')
-            print err
+            print(err)
     
     	f.close()
         SetFilePermissions(outputdir + '/' + task + '.html')
@@ -476,7 +476,7 @@ the right shows the tasks of %s.""" ) \
     except: # simply continue if file does not exist
     	pass
     f = open(outputfile, 'w')
-    print >> f, template.generate(**data).render('xhtml')
+    print(template.generate(**data).render('xhtml'), file=f)
     f.close()
     SetFilePermissions(outputfile)
 
diff --git a/webtools/check-all-tasks b/webtools_py3/check-all-tasks
similarity index 100%
copy from webtools/check-all-tasks
copy to webtools_py3/check-all-tasks
diff --git a/webtools/check-static-content b/webtools_py3/check-static-content
similarity index 100%
copy from webtools/check-static-content
copy to webtools_py3/check-static-content
diff --git a/webtools/ddpo_register b/webtools_py3/ddpo_register
similarity index 100%
copy from webtools/ddpo_register
copy to webtools_py3/ddpo_register
diff --git a/webtools/ddpo_register.py b/webtools_py3/ddpo_register.py
similarity index 70%
copy from webtools/ddpo_register.py
copy to webtools_py3/ddpo_register.py
index 34f65e5..322d2b9 100755
--- a/webtools/ddpo_register.py
+++ b/webtools_py3/ddpo_register.py
@@ -8,22 +8,22 @@ from sys import argv, exit, stderr
 from blendstasktools import Tasks
 
 if len(argv) <= 1:
-	print >>stderr, "Usage: %s <Blend name>\n       The <Blend name> needs a matching config file webconf/<Blend name>.conf"\
-                        % argv[0]
+	print("Usage: %s <Blend name>\n       The <Blend name> needs a matching config file webconf/<Blend name>.conf"\
+                        % argv[0], file=stderr)
 	exit(-1)
 
 tasks  = Tasks(argv[1])
 if tasks.data['pkglist'] == '':
-	print >>stderr, "Config file webconf/%s.conf is lacking pkglist field." % (argv[1])
+	print("Config file webconf/%s.conf is lacking pkglist field." % (argv[1]), file=stderr)
 	exit(-1)
 tasks.GetAllDependencies(source=1)
 packages = tasks.GetNamesOnlyDict(dependencystatus=['official_high', 'official_low', 'non-free', 'experimental'])
 
-print "user", tasks.data['pkglist']
-for task in packages.keys():
+print("user", tasks.data['pkglist'])
+for task in list(packages.keys()):
 	for pkg in packages[task]:
-		print "subscribe %s %s" % ( pkg, task )
-print "thanks"
+		print("subscribe %s %s" % ( pkg, task ))
+print("thanks")
 
 
 # Perhaps we should also send a mail to pts at qa.debian.org
diff --git a/webtools/deploy-repository b/webtools_py3/deploy-repository
similarity index 100%
copy from webtools/deploy-repository
copy to webtools_py3/deploy-repository
diff --git a/webtools/mkmo.sh b/webtools_py3/mkmo.sh
similarity index 100%
copy from webtools/mkmo.sh
copy to webtools_py3/mkmo.sh
diff --git a/webtools/mkpo.sh b/webtools_py3/mkpo.sh
similarity index 100%
copy from webtools/mkpo.sh
copy to webtools_py3/mkpo.sh
diff --git a/webtools/mkpot.sh b/webtools_py3/mkpot.sh
similarity index 100%
copy from webtools/mkpot.sh
copy to webtools_py3/mkpot.sh
diff --git a/webtools/new_upstream b/webtools_py3/new_upstream
similarity index 100%
copy from webtools/new_upstream
copy to webtools_py3/new_upstream
diff --git a/webtools/new_upstream.py b/webtools_py3/new_upstream.py
similarity index 72%
copy from webtools/new_upstream.py
copy to webtools_py3/new_upstream.py
index 0e502cf..37795bf 100755
--- a/webtools/new_upstream.py
+++ b/webtools_py3/new_upstream.py
@@ -9,38 +9,38 @@ from blendstasktools import Tasks
 from blendsunicode import to_unicode
 
 if len(argv) <= 1:
-	print >>stderr, "Usage: %s <Blend name>\n       The <Blend name> needs a matching config file webconf/<Blend name>.conf"\
-                        % argv[0]
+	print("Usage: %s <Blend name>\n       The <Blend name> needs a matching config file webconf/<Blend name>.conf"\
+                        % argv[0], file=stderr)
 	exit(-1)
 
 tasks  = Tasks(argv[1])
 if tasks.data['pkglist'] == '':
-	print >>stderr, "Config file webconf/%s.conf is lacking pkglist field." % (argv[1])
+	print("Config file webconf/%s.conf is lacking pkglist field." % (argv[1]), file=stderr)
 	exit(-1)
 tasks.GetAllDependencies(source=1)
 packages = tasks.GetUpdatablePackages(dependencystatus=['official_high', 'official_low', 'non-free', 'experimental'])
 
-for task in packages.keys():
-	print "Updatable packages in Task", task
+for task in list(packages.keys()):
+	print("Updatable packages in Task", task)
 	for pkg_v_o in packages[task]:
 		printstring = "\t%s:\n\t\tHighest version in Debian is %s\n\t\tUpstream has %s\n\t\tMaintainer is %s" % ( pkg_v_o[0] )
 		if pkg_v_o[1]:
 			printstring = printstring + "\n\t\tLast uploader was " + pkg_v_o[1]
 		try:
-			print printstring
-		except UnicodeEncodeError, err:
-			print "\t%s: (Problem printing UTF-8 data)\n\t\tHighest version in Debian is %s\n\t\tUpstream has %s\n" % \
-			    ( pkg_v_o[0][0], pkg_v_o[0][1], pkg_v_o[0][2] )
+			print(printstring)
+		except UnicodeEncodeError as err:
+			print("\t%s: (Problem printing UTF-8 data)\n\t\tHighest version in Debian is %s\n\t\tUpstream has %s\n" % \
+			    ( pkg_v_o[0][0], pkg_v_o[0][1], pkg_v_o[0][2] ))
 			try:
-				print "type(pkg_v_o[0][3]) =", type(pkg_v_o[0][3])
-				print "type(pkg_v_o[1]) =", type(pkg_v_o[1])
+				print("type(pkg_v_o[0][3]) =", type(pkg_v_o[0][3]))
+				print("type(pkg_v_o[1]) =", type(pkg_v_o[1]))
 				# maintainerfield of package gnudatalanguage which is
 				#   Gürkan Sengün <gurkan at phys.ethz.ch>
 				# breaks print for some reason I do not understand because everything should be UTF-8
 				# error is: 'ascii' codec can't encode character u'\xfc' in position 104: ordinal not in range(128)
 				# just stick to the e-mail address to do something useful ...
 				print_wo_maintainer = pkg_v_o[0][3][0] # re.sub('^.+(<.+ at .+>.*)', '\\1', pkg_v_o[0][3])
-				print "\t\tMaintainer is ... %s" % ( print_wo_maintainer )
+				print("\t\tMaintainer is ... %s" % ( print_wo_maintainer ))
 				# print print_wo_maintainer[0:80]
 				if pkg_v_o[1]:
 					printstring = printstring + "\n\t\tLast uploader was " + pkg_v_o[1]
diff --git a/webtools/po/blends-webtools.pot b/webtools_py3/po/blends-webtools.pot
similarity index 100%
copy from webtools/po/blends-webtools.pot
copy to webtools_py3/po/blends-webtools.pot
diff --git a/webtools/po/cs.po b/webtools_py3/po/cs.po
similarity index 100%
copy from webtools/po/cs.po
copy to webtools_py3/po/cs.po
diff --git a/webtools/po/da.po b/webtools_py3/po/da.po
similarity index 100%
copy from webtools/po/da.po
copy to webtools_py3/po/da.po
diff --git a/webtools/po/de.po b/webtools_py3/po/de.po
similarity index 100%
copy from webtools/po/de.po
copy to webtools_py3/po/de.po
diff --git a/webtools/po/es.po b/webtools_py3/po/es.po
similarity index 100%
copy from webtools/po/es.po
copy to webtools_py3/po/es.po
diff --git a/webtools/po/fi.po b/webtools_py3/po/fi.po
similarity index 100%
copy from webtools/po/fi.po
copy to webtools_py3/po/fi.po
diff --git a/webtools/po/fr.po b/webtools_py3/po/fr.po
similarity index 100%
copy from webtools/po/fr.po
copy to webtools_py3/po/fr.po
diff --git a/webtools/po/it.po b/webtools_py3/po/it.po
similarity index 100%
copy from webtools/po/it.po
copy to webtools_py3/po/it.po
diff --git a/webtools/po/ja.po b/webtools_py3/po/ja.po
similarity index 100%
copy from webtools/po/ja.po
copy to webtools_py3/po/ja.po
diff --git a/webtools/po/ko.po b/webtools_py3/po/ko.po
similarity index 100%
copy from webtools/po/ko.po
copy to webtools_py3/po/ko.po
diff --git a/webtools/po/nl.po b/webtools_py3/po/nl.po
similarity index 100%
copy from webtools/po/nl.po
copy to webtools_py3/po/nl.po
diff --git a/webtools/po/php-message-strings.pot b/webtools_py3/po/php-message-strings.pot
similarity index 100%
copy from webtools/po/php-message-strings.pot
copy to webtools_py3/po/php-message-strings.pot
diff --git a/webtools/po/pl.po b/webtools_py3/po/pl.po
similarity index 100%
copy from webtools/po/pl.po
copy to webtools_py3/po/pl.po
diff --git a/webtools/po/pt.po b/webtools_py3/po/pt.po
similarity index 100%
copy from webtools/po/pt.po
copy to webtools_py3/po/pt.po
diff --git a/webtools/po/ru.po b/webtools_py3/po/ru.po
similarity index 100%
copy from webtools/po/ru.po
copy to webtools_py3/po/ru.po
diff --git a/webtools/po/static.pot b/webtools_py3/po/static.pot
similarity index 100%
copy from webtools/po/static.pot
copy to webtools_py3/po/static.pot
diff --git a/webtools/po/zh_CN.po b/webtools_py3/po/zh_CN.po
similarity index 100%
copy from webtools/po/zh_CN.po
copy to webtools_py3/po/zh_CN.po
diff --git a/webtools/po/zh_TW.po b/webtools_py3/po/zh_TW.po
similarity index 100%
copy from webtools/po/zh_TW.po
copy to webtools_py3/po/zh_TW.po
diff --git a/webtools/tasks.py b/webtools_py3/tasks.py
similarity index 87%
copy from webtools/tasks.py
copy to webtools_py3/tasks.py
index adcd938..0b4b059 100755
--- a/webtools/tasks.py
+++ b/webtools_py3/tasks.py
@@ -22,8 +22,8 @@ from blendsunicode   import to_unicode
 from blendslanguages import languages, language_dict
 
 if len(argv) <= 1:
-	print >>stderr, "Usage: %s <Blend name>\n       The <Blend name> needs a matching config file webconf/<Blend name>.conf"\
-                        % argv[0]
+	print("Usage: %s <Blend name>\n       The <Blend name> needs a matching config file webconf/<Blend name>.conf"\
+                        % argv[0], file=stderr)
 	exit(-1)
 
 # LockBlendsTools() #  logger handler not defined at this moment, needs rethinking ... FIXME
@@ -77,14 +77,14 @@ try:
 except: # simply continue if file does not exist
 	pass
 htafp = open(htaccess, 'w')
-print >> htafp, "DirectoryIndex index index.html\nOptions +MultiViews"
+print("DirectoryIndex index index.html\nOptions +MultiViews", file=htafp)
 
 detect_javascript_code_re = re.compile("onmouseover=\"Tip\(\\'")
 detect_ampersand_code_re  = re.compile("href=\"http://\w+\.debian\.org/.+\?\w+=")
 
 use_dependencystatus = GetDependencies2Use()
 for lang in languages:
-	print >> htafp, "AddLanguage %s .%s" % (language_dict[lang]['htaccess'], lang)
+	print("AddLanguage %s .%s" % (language_dict[lang]['htaccess'], lang), file=htafp)
 	l10nstring[lang].install()
 	_ = l10nstring[lang].ugettext
 	data['lang']              = lang
@@ -164,7 +164,7 @@ the right shows the tasks of %s.""" ) \
 	# contain several html tags will be marked correctly
 	VERBATIM=('projectadvertising', )
 	for verbatim in VERBATIM:
-		if data.has_key(verbatim) and data[verbatim] != None:
+		if verbatim in data and data[verbatim] != None:
 			data[verbatim] = Markup(data[verbatim])
 
 	template = loader.load('tasks_idx.xhtml')
@@ -178,11 +178,10 @@ the right shows the tasks of %s.""" ) \
 		pass
 	f = open(outputfile, 'w')
 	try:
-		print >> f, template.generate(**data).render('xhtml')
-	except UnicodeDecodeError, errtxt:
-		print >> stderr, \
-		    "Some critical encoding problem occured when trying to render index for lang %s.\n%s" \
-		    % (lang, errtxt)
+		print(template.generate(**data).render('xhtml'), file=f)
+	except UnicodeDecodeError as errtxt:
+		print("Some critical encoding problem occured when trying to render index for lang %s.\n%s" \
+		    % (lang, errtxt), file=stderr)
 		
 	f.close()
 	SetFilePermissions(outputfile)
@@ -215,11 +214,11 @@ the right shows the tasks of %s.""" ) \
 			    if lang == 'en':
 				# ... but only once and not per language
 				for dep in tasks.tasks[task].dependencies[status]:
-				    print >>stderr, "Warning: Dependency with unknown status:", dep.pkg
+				    print("Warning: Dependency with unknown status:", dep.pkg, file=stderr)
 			else:
 			    data['dependencies'][task].append(status)
 			    if status in data['dependencies'][task]:
-				    if not found_status.has_key(status):
+				    if status not in found_status:
 					    found_status[status] = 1
 		# Keep the Project lists per task to be able to loop over all tasks in plain package list
 		data['projects'][task] = tasks.tasks[task].dependencies
@@ -237,18 +236,16 @@ the right shows the tasks of %s.""" ) \
 		template = loader.load('tasks.xhtml')
 		f = open(outputfile+'_tmp', "w")
 		try:
-			print >> f, template.generate(**data).render('xhtml')
-		except UnicodeEncodeError, errtxt:
-			print "Some critical encoding problem occured when trying to render task %s for lang %s.\n%s" \
-			      % (task, lang, errtxt)
-		except UnicodeDecodeError, errtxt:
-			print >> stderr, \
-                             "Some critical encoding problem occured when trying to render task %s for lang %s.\n%s" \
-			     % (task, lang, errtxt)
-		except UndefinedError, errtxt:
-			print >> stderr, \
-                             "UndefinedError while rendering task %s for lang %s.\n%s" \
-			     % (task, lang, errtxt)
+			print(template.generate(**data).render('xhtml'), file=f)
+		except UnicodeEncodeError as errtxt:
+			print("Some critical encoding problem occured when trying to render task %s for lang %s.\n%s" \
+			      % (task, lang, errtxt))
+		except UnicodeDecodeError as errtxt:
+			print("Some critical encoding problem occured when trying to render task %s for lang %s.\n%s" \
+			     % (task, lang, errtxt), file=stderr)
+		except UndefinedError as errtxt:
+			print("UndefinedError while rendering task %s for lang %s.\n%s" \
+			     % (task, lang, errtxt), file=stderr)
 		f.close()
 	        SetFilePermissions(outputfile+'_tmp')
 		# Really rude hack to get back '<' / '>' signs which actually shoul be
@@ -260,7 +257,7 @@ the right shows the tasks of %s.""" ) \
 			# the correct character packages.debian.org gets confused - so turn it back here
 			if detect_ampersand_code_re.search(line):
 				line = re.sub('%26', '&', line)
-			print >>f, line,
+			print(line, end=' ', file=f)
 		f.close()
 		tmp.close()
 		os.unlink(outputfile+'_tmp')
@@ -282,24 +279,22 @@ the right shows the tasks of %s.""" ) \
 		data['projectsintasks']     = tasks.tasks[task].dependencies
 
 	try:
-		print >> f, template.generate(**data).render('xhtml')
-	except UnicodeDecodeError, errtxt:
-		print >> stderr, \
-		    "Some critical encoding problem occured when trying to render long package list for lang %s.\n%s" \
-		    % (lang, errtxt)
-	except UndefinedError, errtxt:
-		print >> stderr, \
-		    "UndefinedError while trying to render long package list for lang %s.\n%s" \
-		    % (lang, errtxt)
+		print(template.generate(**data).render('xhtml'), file=f)
+	except UnicodeDecodeError as errtxt:
+		print("Some critical encoding problem occured when trying to render long package list for lang %s.\n%s" \
+		    % (lang, errtxt), file=stderr)
+	except UndefinedError as errtxt:
+		print("UndefinedError while trying to render long package list for lang %s.\n%s" \
+		    % (lang, errtxt), file=stderr)
 		
 	f.close()
 	SetFilePermissions(outputfile)
 
 
-print >> htafp, "LanguagePriority",
+print("LanguagePriority", end=' ', file=htafp)
 for lang in languages:
-	print >> htafp, language_dict[lang]['htaccess'] ,
-print >> htafp
+	print(language_dict[lang]['htaccess'], end=' ', file=htafp)
+print(file=htafp)
 
 htafp.close()
 SetFilePermissions(htaccess)
diff --git a/webtools_py3/tasks_udd.py b/webtools_py3/tasks_udd.py
new file mode 100755
index 0000000..e376c7f
--- /dev/null
+++ b/webtools_py3/tasks_udd.py
@@ -0,0 +1,303 @@
+#!/usr/bin/python3
+
+import apt
+import apt_pkg
+import apt_inst
+
+from sys import argv, exit, stderr
+import os
+import re
+import gettext
+
+import time
+from datetime import datetime
+from email.utils import formatdate
+
+from genshi.template import TemplateLoader
+from genshi import Markup
+from genshi.template.eval import UndefinedError
+
+from blendstasktools_udd import Tasks, GetDependencies2Use, pkgstatus, pkgstatus_sortedkeys, UnlockBlendsTools, CheckOrCreateOutputDir, SetFilePermissions
+from blendsunicode   import to_unicode
+from blendslanguages import languages, language_dict
+
+if len(argv) <= 1:
+    print("Usage: %s <Blend name>\n       The <Blend name> needs a matching config file webconf/<Blend name>.conf"\
+                        % argv[0], file=stderr)
+    exit(-1)
+
+# LockBlendsTools() #  logger handler not defined at this moment, needs rethinking ... FIXME
+tasks    = Tasks(argv[1])
+tasks.GetAllDependencies()
+packages = tasks.GetNamesOnlyDict()
+# print ("pacakges : \n", packages)
+tasks.GetAllDependentPackagesOfBlend()
+tasks.MarkupPreformatedStringsBlend()
+
+data = tasks.data
+# print("data : \n",data)
+data['tasks']            = tasks.GetTaskDescDict()
+data['taskskeys']        = tasks.metapackagekeys
+try:
+    data['popconsubmit']     = tasks.popconsubmit
+except: 
+    data['popconsubmit']     = 'unknown'
+data['languages']        = languages
+data['language_dict']    = language_dict
+# Work around the fact that it seems to be impossible to mention '&' in the template
+data['ampandworkaround'] = Markup('&force=1')
+
+# Define directories used
+current_dir  = os.path.dirname(__file__)
+locale_dir   = os.path.join(current_dir, 'locale')
+template_dir = os.path.join(current_dir, 'templates')
+
+# Initialize i18n
+domain = 'blends-webtools'
+gettext.install(domain)
+l10nstring = {}
+for lang in languages:
+	l10nstring[lang] = gettext.translation(domain, locale_dir, languages=[lang], fallback = True)
+
+# Translated strings regarding the categorising of dependencies need to
+# be translated and because I did not found a working solution to get
+# gettext working with genshi all are collected here even if the additional
+# attributes to blendstasktools.pkgstatus rather should go blendstasktools.py
+
+
+# initialize gensi
+loader = TemplateLoader([template_dir], auto_reload=True)
+
+outputdir = CheckOrCreateOutputDir(tasks.data['outputdir'],'tasks_udd')
+if outputdir == None:
+	exit(-1)
+
+t = datetime.now()
+htaccess = outputdir + '/.htaccess'
+try:
+	os.unlink(htaccess)
+except: # simply continue if file does not exist
+	pass
+htafp = open(htaccess, 'w')
+print("DirectoryIndex index index.html\nOptions +MultiViews", file=htafp)
+
+detect_javascript_code_re = re.compile("onmouseover=\"Tip\(\\'")
+detect_ampersand_code_re  = re.compile("href=\"http://\w+\.debian\.org/.+\?\w+=")
+
+use_dependencystatus = GetDependencies2Use()
+for lang in languages:
+    print("AddLanguage %s .%s" % (language_dict[lang]['htaccess'], lang), file=htafp)
+    l10nstring[lang].install()
+    # _ = l10nstring[lang].ugettext
+    data['lang']              = lang
+    data['license']           = 'License'
+    data['version']           = 'Version'
+    data['summary']           = 'Summary'
+    data['updatetimestamp']   = 'Last update:' + ' ' + formatdate(time.mktime(t.timetuple()))
+    data['nopkgavail']        = 'Debian package not available'
+    # Description of package in specific packges (same for Depends, Recommends, Suggests)
+    data['legend']            = "For a better overview of the project's availability as a Debian package, each head row has a color code according to this scheme:"
+    data['discovery']         = Markup(("""If you discover a project which looks like a good candidate for %s
+                              to you, or if you have prepared an unofficial Debian package, please do not hesitate to
+                              send a description of that project to the <a href="mailto:%s">%s mailing list</a>""") % \
+                                  (data['projectname'], data['projectlist'], data['projectname']))
+    data['description']       = ("The list to the right includes various software projects which are of some interest to the %s Project. Currently, only a few of them are available as Debian packages. It is our goal, however, to include all software in %s which can sensibly add to a high quality Debian Pure Blend.") % (data['projectname'], data['projectname'])
+    data['gtstrTasksPage']     = 'Tasks page'
+    data['gtstrProject']	   = 'Project'
+    data['gtstrThisIsAList']   = 'This is a list of the Tasks %s is made of:' % data['projectname']
+    data['langavail']          = 'This page is also available in the following languages:'
+    data['howtosetlang']       = 'How to set <a href="%s">the default document language</a>'
+    data['howtosetlang']       = Markup((data['howtosetlang'] % ('http://www.debian.org/intro/cn.%s.html' % lang)))
+    data['nohomepage']         = 'Homepage not available'
+    data['translatedesc']      = 'Translate description'
+    data['fixtranslation']     = 'Fix translated description'
+    data['popconexplanation']  = 'Popularitycontest results: number of people who use this package regularly (number of people who upgraded this package recently) out of'
+    data['tableofcontents']    = 'Table of contents'
+    data['packagelist']        = 'complete packagelist'
+    if data['advertising'] != None:
+	    # If data['advertising'] is enclosed in _() gettext tries to ask for translations of 'advertising'
+	    # which makes no sense.  That's why this is masked by an extra string variable
+	    advertising = data['advertising']
+	    # data['projectadvertising'] = _(advertising) # Hopefully translation will work this way ...
+	    # Genshi needs explicite information that it is dealing with an UTF-8 string which should not be changed
+        # advertising = _(advertising)
+	    data['projectadvertising'] = Markup((advertising))
+    else:
+        data['projectadvertising'] = None
+
+    data['packages']          = 'Packages'
+    data['idxsummary']        = ("""A %sDebian Pure Blend%s is a Debian internal project which assembles
+a set of packages that might help users to solve certain tasks of their work.  The list on
+the right shows the tasks of %s.""" ) \
+                                      % ('<a href="http://blends.alioth.debian.org/blends/">', '</a>', data['projectname'])
+    data['idxsummary']        = Markup((data['idxsummary']))
+
+    pkgstatus['official_high']['headline']    = 'Official Debian packages with high relevance'
+    # before fiddling around with unicode() read
+    # http://www.red-mercury.com/blog/eclectic-tech/python-unicode-fixing-utf-8-encoded-as-latin-1-iso-8859-1/
+    pkgstatus['official_high']['pdolinkname'] = 'Official Debian package'
+    pkgstatus['official_low'] ['headline']    = 'Official Debian packages with lower relevance'
+    pkgstatus['official_low'] ['pdolinkname'] = pkgstatus['official_high']['pdolinkname']
+    pkgstatus['non-free']     ['headline']    = 'Debian packages in contrib or non-free'
+    pkgstatus['non-free']     ['pdolinkname'] = 'Debian package in contrib/non-free'
+    pkgstatus['experimental'] ['headline']    = 'Debian packages in experimental'
+    pkgstatus['experimental'] ['pdolinkname'] = 'Debian package in experimental'
+    pkgstatus['new']          ['headline']    = 'Debian packages in New queue (hopefully available soon)'
+    pkgstatus['new']          ['pdolinkname'] = 'New Debian package'
+    pkgstatus['pkgvcs']       ['headline']    = 'Packaging has started and developers might try the packaging code in VCS'
+    pkgstatus['pkgvcs']       ['pdolinkname'] = 'Unofficial Debian package'
+    pkgstatus['unofficial']   ['headline']    = 'Unofficial packages built by somebody else'
+    pkgstatus['unofficial']   ['pdolinkname'] = pkgstatus['pkgvcs']['pdolinkname']
+    pkgstatus['prospective']  ['headline']    = 'No known packages available'
+    pkgstatus['prospective']  ['pdolinkname'] = 'Debian package not available'
+    pkgstatus['wnpp']         ['headline']    = 'No known packages available but some record of interest (WNPP bug)'
+    pkgstatus['wnpp']         ['pdolinkname'] = pkgstatus['prospective']['pdolinkname']
+    # Ignore/Avoid is only relevant for blends-dev, not webtools
+    pkgstatus['ignore']       ['headline']    = 'Should not show up here'
+    pkgstatus['prospective']  ['pdolinkname'] = ''
+    pkgstatus['avoid']        ['headline']    = 'Should not show up here'
+    pkgstatus['prospective']  ['pdolinkname'] = ''
+    pkgstatus['unknown']      ['headline']    = 'Should not show up here' # There must be a bug somewhere
+    pkgstatus['prospective']  ['pdolinkname'] = ''
+    
+    # Create the index page
+    # Make sure that strings that need to be rendered as they are because they might
+    # contain several html tags will be marked correctly
+    VERBATIM=('projectadvertising', )
+    for verbatim in VERBATIM:
+        if verbatim in data and data[verbatim] != None:
+            data[verbatim] = Markup(data[verbatim])
+
+    template = loader.load('tasks_idx.xhtml')
+
+    outputfile = outputdir + '/index'
+    if lang != 'xyz': # let 'en' be a language as any other and add suffix to file name
+        outputfile += '.' + language_dict[lang]['short'] + '.html'
+    try:
+        os.unlink(outputfile)
+    except: # simply continue if file does not exist
+	    pass
+    f = open(outputfile, 'w')
+    try:
+	    print(template.generate(**data).render('xhtml'), file=f)
+    except UnicodeDecodeError as errtxt:
+	    print("Some critical encoding problem occured when trying to render index for lang %s.\n%s" \
+		    % (lang, errtxt), file=stderr)
+		
+    f.close()
+    SetFilePermissions(outputfile)
+
+    data['dependencies'] = {}
+    data['projects']     = {}
+
+    data['headline']     = {}
+    data['pdolinkname']  = {}
+    data['maintainer']   = {}
+
+    # I18n for headlines, link description, maintainer
+    for status in use_dependencystatus:
+        data['headline'][status]   = Markup(pkgstatus[status]['headline'])
+        data['pdolinkname'][status]= Markup((pkgstatus[status]['pdolinkname']))
+        if pkgstatus[status]['order'] <= pkgstatus['experimental']['order']:
+            data['maintainer'][status] = ('Maintainer')
+        else:
+            data['maintainer'][status] = ('Responsible')
+
+    for task in data['taskskeys']:
+        data['task']               = task
+        # Keep the Dependency lists per task to be able to loop over all tasks in plain package list
+        data['dependencies'][task] = []
+        found_status = {}
+        for status in use_dependencystatus:
+            if len(tasks.tasks[task].dependencies[status]) > 0:
+                if status == 'unknown':
+                    # Just print an error message if there are packages with unknown status
+                    if lang == 'en':
+                        # ... but only once and not per language
+                        for dep in tasks.tasks[task].dependencies[status]:
+                            print("Warning: Dependency with unknown status:", dep.pkg, file=stderr)
+                else:
+                    data['dependencies'][task].append(status)
+                    if status in data['dependencies'][task]:
+                        if status not in found_status:
+                            found_status[status] = 1
+        # Keep the Project lists per task to be able to loop over all tasks in plain package list
+        data['projects'][task] = tasks.tasks[task].dependencies
+        data['othertasks']     = ("Links to other tasks")
+        data['indexlink']      = ("Index of all tasks")
+
+        outputfile = outputdir + '/' + task
+        if lang != 'xyz': # let 'en' be a language as any other and add suffix to file name
+            outputfile += '.' + language_dict[lang]['short'] + '.html'
+        try:
+            os.unlink(outputfile)
+        except: # simply continue if file does not exist
+            pass
+
+        template = loader.load('tasks.xhtml')
+        f = open(outputfile+'_tmp', "w")
+        try:
+            print(template.generate(**data).render('xhtml'), file=f)
+        except UnicodeEncodeError as errtxt:
+            print("Some critical encoding problem occured when trying to render task %s for lang %s.\n%s" \
+			      % (task, lang, errtxt))
+        except UnicodeDecodeError as errtxt:
+            print("Some critical encoding problem occured when trying to render task %s for lang %s.\n%s" \
+			     % (task, lang, errtxt), file=stderr)
+        except UndefinedError as errtxt:
+            print("UndefinedError while rendering task %s for lang %s.\n%s" \
+			     % (task, lang, errtxt), file=stderr)
+        f.close()
+        SetFilePermissions(outputfile+'_tmp')
+        # Really rude hack to get back '<' / '>' signs which actually shoul be
+        # in the output
+        tmp = open(outputfile+'_tmp', "r")
+        f   = open(outputfile, "w")
+        for line in tmp.readlines():
+            # We had to mask ampersand ('&') from Genshi but even if the browser shows
+            # the correct character packages.debian.org gets confused - so turn it back here
+            if detect_ampersand_code_re.search(line):
+                line = re.sub('%26', '&', line)
+            print(line, end=' ', file=f)
+        f.close()
+        tmp.close()
+        os.unlink(outputfile+'_tmp')
+        SetFilePermissions(outputfile)
+
+    template = loader.load('packagelist.xhtml')
+
+    outputfile = outputdir + '/packagelist'
+    if lang != 'xyz': # let 'en' be a language as any other and add suffix to file name
+        outputfile += '.' + lang + '.html'
+    try:
+        os.unlink(outputfile)
+    except: # simply continue if file does not exist
+        pass
+    f = open(outputfile, 'w')
+
+    data['projectsintasks'] = []
+    for task in data['taskskeys']:
+        data['projectsintasks']     = tasks.tasks[task].dependencies
+
+    try:
+        print(template.generate(**data).render('xhtml'), file=f)
+    except UnicodeDecodeError as errtxt:
+        print("Some critical encoding problem occured when trying to render long package list for lang %s.\n%s" \
+		    % (lang, errtxt), file=stderr)
+    except UndefinedError as errtxt:
+        print("UndefinedError while trying to render long package list for lang %s.\n%s" \
+		    % (lang, errtxt), file=stderr)
+		
+    f.close()
+    SetFilePermissions(outputfile)
+
+
+print("LanguagePriority", end=' ', file=htafp)
+for lang in languages:
+    print(language_dict[lang]['htaccess'], end=' ', file=htafp)
+print(file=htafp)
+
+htafp.close()
+SetFilePermissions(htaccess)
+
+UnlockBlendsTools()
diff --git a/webtools/templates/bugs.xhtml b/webtools_py3/templates/bugs.xhtml
similarity index 96%
copy from webtools/templates/bugs.xhtml
copy to webtools_py3/templates/bugs.xhtml
index f68499e..ef54deb 100644
--- a/webtools/templates/bugs.xhtml
+++ b/webtools_py3/templates/bugs.xhtml
@@ -5,7 +5,7 @@
       xmlns:py="http://genshi.edgewall.org/">
 <head>
 <title>$projectname ${bugs_data[task]['title'].capitalize()} bugs</title>
-<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8"/>
+<meta http-equiv="Content-Type" content="application/xhtml+xml;"/> <!--charset=UTF-8"/>-->
 <link href="/css/sentinel.css" type="text/css" rel="stylesheet"/>
 </head>
 <body>
@@ -108,7 +108,7 @@
                           <span py:otherwise=""><a href="${pkgbug['vcs_browser']}">${vcslocation}</a></span>
 			</span>
                         <span class="bugsmaintainer" id="bugsmaintainer" py:choose="">
-                          <span py:when="pkgbug.has_key('maintainer_email')"><a href="mailto:${pkgbug['maintainer_email']}">${pkgbug['maintainer_name']}</a></span>
+                          <span py:when="'maintainer_email' in pkgbug"><a href="mailto:${pkgbug['maintainer_email']}">${pkgbug['maintainer_name']}</a></span>
                           <span py:otherwise="">unknown maintainer</span>
 			</span>
 		      </div>
diff --git a/webtools/templates/bugs_idx.xhtml b/webtools_py3/templates/bugs_idx.xhtml
similarity index 96%
copy from webtools/templates/bugs_idx.xhtml
copy to webtools_py3/templates/bugs_idx.xhtml
index d9b3977..8ffcc4e 100644
--- a/webtools/templates/bugs_idx.xhtml
+++ b/webtools_py3/templates/bugs_idx.xhtml
@@ -5,7 +5,7 @@
       xmlns:py="http://genshi.edgewall.org/">
 <head>
 <title>$projectname bugs</title>
-<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8"/>
+<meta http-equiv="Content-Type" content="application/xhtml+xml;"/> <!--charset=UTF-8"/>-->
 <link href="/css/sentinel.css" type="text/css" rel="stylesheet"/>
 </head>
 <body>
diff --git a/webtools/templates/debian2ubuntu-termometer.sh b/webtools_py3/templates/debian2ubuntu-termometer.sh
similarity index 100%
copy from webtools/templates/debian2ubuntu-termometer.sh
copy to webtools_py3/templates/debian2ubuntu-termometer.sh
diff --git a/webtools/templates/packagelist.xhtml b/webtools_py3/templates/packagelist.xhtml
similarity index 89%
copy from webtools/templates/packagelist.xhtml
copy to webtools_py3/templates/packagelist.xhtml
index 14a1830..7d67352 100644
--- a/webtools/templates/packagelist.xhtml
+++ b/webtools_py3/templates/packagelist.xhtml
@@ -5,7 +5,7 @@
       xmlns:py="http://genshi.edgewall.org/">
 <head>
 <title>$projectname $packagelist</title>
-<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8"/>
+<meta http-equiv="Content-Type" content="application/xhtml+xml;" /><!--charset=UTF-8"/>-->
 <link href="/css/sentinel.css" type="text/css" rel="stylesheet"/>
 </head>
 <body>
@@ -43,11 +43,11 @@
       <py:for each="task in taskskeys">
 	<a name="${task}" id="${task}"/>
 	<h2><a href="${task}" name="${task}" id="${task}">${tasks[task].metapkg.PrintedName.capitalize()} - <span py:choose="">
-	<span py:when="tasks[task].metapkg.desc.has_key(lang)">${tasks[task].metapkg.desc[lang]['short']}</span>
+	<span py:when="lang in tasks[task].metapkg.desc">${tasks[task].metapkg.desc[lang]['short']}</span>
 	<span py:otherwise="">${tasks[task].metapkg.desc['en']['short']}</span>
 	</span></a></h2>
 	<p py:choose="">
-	  <span py:when="tasks[task].metapkg.desc.has_key(lang)">${tasks[task].metapkg.desc[lang]['long']}</span>
+	  <span py:when="lang in tasks[task].metapkg.desc">${tasks[task].metapkg.desc[lang]['long']}</span>
 	  <span py:otherwise="">${tasks[task].metapkg.desc['en']['long']}</span>
 	</p>
 	<py:for each="pstatus in dependencies[task]">
@@ -63,7 +63,7 @@
                   </span>
 		  </dt>
 		  <dd><span py:choose="">
-		    <span py:when="project.desc.has_key(lang)">${project.desc[lang]['short']}</span>
+		    <span py:when="lang in project.desc">${project.desc[lang]['short']}</span>
 		    <span py:otherwise="">${project.desc['en']['short']}</span>
 		  </span>
 		  </dd>
diff --git a/webtools/templates/tasks.xhtml b/webtools_py3/templates/tasks.xhtml
similarity index 75%
copy from webtools/templates/tasks.xhtml
copy to webtools_py3/templates/tasks.xhtml
index 35d2794..4857147 100644
--- a/webtools/templates/tasks.xhtml
+++ b/webtools_py3/templates/tasks.xhtml
@@ -5,8 +5,8 @@
       xmlns:py="http://genshi.edgewall.org/">
 <head>
 <title>$projectname ${tasks[task].metapkg.PrintedName.capitalize()} packages</title>
-<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8"/>
-<meta charset="utf-8" />
+<meta http-equiv="Content-Type" content="application/xhtml+xml;" /><!--charset=UTF-8"/>-->
+<!--<meta charset="utf-8" />-->
 <link href="/css/sentinel.css" type="text/css" rel="stylesheet"/>
 </head>
 <body>
@@ -30,11 +30,11 @@
 			<div class="row">
 				<div class="pkgname">${tasks[task].metapkg.PrintedName.capitalize()}</div>
 				<div class="pkgdesc" py:choose="">
-				  <div py:when="tasks[task].metapkg.desc.has_key(lang)">${tasks[task].metapkg.desc[lang]['short']}</div>
+				  <div py:when="lang in tasks[task].metapkg.desc">${tasks[task].metapkg.desc[lang]['short']}</div>
 				  <div py:otherwise="">${tasks[task].metapkg.desc['en']['short']}</div>
 				</div>
 				<p><span py:choose="">
-	           <span py:when="tasks[task].metapkg.desc.has_key(lang)">${tasks[task].metapkg.desc[lang]['long']}
+	           <span py:when="lang in tasks[task].metapkg.desc">${tasks[task].metapkg.desc[lang]['long']}
                      <div class="transmpkg" py:if="lang != 'en'"><a href="http://ddtp.debian.net/ddtss/index.cgi/${lang}/forexternalreview/${tasks[task].metapkg.pkg}">${fixtranslation}</a></div>
                    </span>
 	           <span py:otherwise="">${tasks[task].metapkg.desc['en']['long']}
@@ -81,10 +81,10 @@
 	   <td class="project-name">
 	     <a name="${project.pkg}" id="${project.pkg}"/>
 	     <div class="pkgname">${project.pkg.capitalize()}
-	       <span class="wnpp" py:if="project.properties.has_key('wnpp')"> - <a href="http://bugs.debian.org/${project.properties['wnpp']}">wnpp</a></span>
+	       <span class="wnpp" py:if="'wnpp' in project.properties"> - <a href="http://bugs.debian.org/${project.properties['wnpp']}">wnpp</a></span>
 	     </div>
 	     <div class="pkgdesc" py:choose="">
-	           <div py:when="project.desc.has_key(lang)">${project.desc[lang]['short']}</div>
+	           <div py:when="lang in project.desc">${project.desc[lang]['short']}</div>
 	           <div py:otherwise="">${project.desc['en']['short']}</div>
 	     </div>
 	     <div py:choose="project.properties['homepage']">
@@ -92,7 +92,7 @@
                 <span py:otherwise=""><a href="${project.properties['homepage']}">${project.properties['homepage']}</a></span>
              </div>
 	     <div py:if="project.responsible != None">${maintainer[pstatus]}:
-               ${project.responsible} <span py:if="project.properties.has_key('changed_by')">(${project.properties['changed_by']})</span>
+               ${project.responsible} <span py:if="'changed_by' in project.properties">(${project.properties['changed_by']})</span>
              </div>
 	   </td>
 	   <td py:if="project.component and project.pkgstatus != 'new' and project.pkgstatus != 'pkgvcs'" class="project-info">
@@ -139,23 +139,23 @@
              </div>
 	     <div py:if="project.properties['vcs-browser'] != '#'">
 	       <span py:choose="">
-		 <span py:when="project.properties.has_key('vcs-url')"><a href="${project.properties['vcs-browser']}" title="${project.properties['vcs-url']}">${project.properties['vcs-type']}</a></span>
+		 <span py:when="'vcs-url' in project.properties"><a href="${project.properties['vcs-browser']}" title="${project.properties['vcs-url']}">${project.properties['vcs-type']}</a></span>
 		 <span py:otherwise=""><a href="${project.properties['vcs-browser']}">${project.properties['vcs-type']}</a></span>
 	       </span>
 	     </div>
             <div py:if="lang != 'en' and project.component == 'main' and project.pkgstatus != 'new' and project.pkgstatus != 'pkgvcs'">
 	       <div py:choose="">
-	           <div class="trans" py:when="project.desc.has_key(lang)"><a href="http://ddtp.debian.net/ddtss/index.cgi/${lang}/forexternalreview/${project.pkg}">${fixtranslation}</a></div>
+	           <div class="trans" py:when="lang in project.desc"><a href="http://ddtp.debian.net/ddtss/index.cgi/${lang}/forexternalreview/${project.pkg}">${fixtranslation}</a></div>
 	           <div class="trans-missing" py:otherwise=""><a href="http://ddtp.debian.net/ddtss/index.cgi/${lang}/fetch?package=${project.pkg}">${translatedesc}</a></div>
                </div>
             </div>
-            <div class="language" py:if="project.properties.has_key('language') and project.component != 'main'">Language: ${project.properties['language']}</div>
+            <div class="language" py:if="'language' in project.properties and project.component != 'main'">Language: ${project.properties['language']}</div>
             <div py:if="project.version != [] and (project.pkgstatus == 'new' or project.pkgstatus == 'pkgvcs')">Version: ${project.version[0]}</div>
            </td>
          </tr>
          <tr>
            <td colspan="2" class="project-description"><span py:choose="">
-	           <span py:when="project.desc.has_key(lang)">${project.desc[lang]['long']}</span>
+	           <span py:when="lang in project.desc">${project.desc[lang]['long']}</span>
 	           <span py:otherwise="">${project.desc['en']['long']}</span>
 	         </span>
 	     <div class="enhanced-by" py:if="project.properties['Enhances'] != {}">
@@ -163,37 +163,37 @@
 		 <a href="${project.properties['Enhances'][enh]}">${enh}</a>
 	       </py:for>
 	     </div>
-	     <div class="registration" py:if="project.properties.has_key('registration')">
+	     <div class="registration" py:if="'registration' in project.properties">
 	       <span class="registrationlink" >Please register by following <a
 	       href="${project.properties['registration']}">this link</a></span> if you are using ${project.pkg}.
 	     </div>
 	     <div class="published"
-	     py:if="project.properties.has_key('published')">Please cite:
-	       <span class="authors" py:if="project.properties['published'].has_key('authors')">${project.properties['published']['authors']}:</span>
+	     py:if="'published' in project.properties">Please cite:
+	       <span class="authors" py:if="'authors' in project.properties['published']">${project.properties['published']['authors']}:</span>
 	       <span py:choose="">
-		 <span py:when="project.properties['published'].has_key('url')">
+		 <span py:when="'url' in project.properties['published']">
 		   <span py:choose="">
                      <span class="title"
-			   py:when="project.properties['published'].has_key('title')"><a href="${project.properties['published']['url']}">${project.properties['published']['title']}.</a></span>
+			   py:when="'title' in project.properties['published']"><a href="${project.properties['published']['url']}">${project.properties['published']['title']}.</a></span>
 		     <span py:otherwise=""><a href="${project.properties['published']['url']}">Link
 			 to publication</a></span>
 		   </span>
 		 </span>
-		 <span py:when="project.properties['published'].has_key('doi')">
+		 <span py:when="'doi' in project.properties['published']">
 		   <span py:choose="">
                      <span class="title"
-			   py:when="project.properties['published'].has_key('title')"><a href="http://dx.doi.org/${project.properties['published']['doi']}">${project.properties['published']['title']}.</a></span>
+			   py:when="'title' in project.properties['published']"><a href="http://dx.doi.org/${project.properties['published']['doi']}">${project.properties['published']['title']}.</a></span>
 		     <span py:otherwise=""><a href="http://dx.doi.org/${project.properties['published']['doi']}">Link
 			 to publication</a></span>
 		   </span>
 		 </span>
-		 <span py:otherwise=""><span class="title" py:if="project.properties['published'].has_key('title')">${project.properties['published']['title']}</span>
+		 <span py:otherwise=""><span class="title" py:if="'title' in project.properties['published']">${project.properties['published']['title']}</span>
 		 </span>
 	       </span>
-               <span py:if="project.properties['published'].has_key('pubmed')">(<a href="http://www.ncbi.nlm.nih.gov/pubmed/${project.properties['published']['pubmed']}">PubMed</a></span><span py:if="project.properties['published'].has_key('pubmed') and project.properties['published'].has_key('eprint')">,</span><span py:if="not project.properties['published'].has_key('pubmed') and project.properties['published'].has_key('eprint')">(</span><span py:if="project.properties['published'].has_key('eprint')"><a href="${project.properties['published']['eprint']}">eprint</a></span><span py:if="project.properties['published'].has_key('pubmed') or project.properties['published'].has_key('eprint')">)</span>
-	       <span class="journal" py:if="project.properties['published'].has_key('journal')">${project.properties['published']['journal']}</span>
-	       <span class="journal" py:if="project.properties['published'].has_key('volume')">${project.properties['published']['volume']}</span><span class="journal" py:if="project.properties['published'].has_key('number')">(${project.properties['published']['number']})</span><span class="journal" py:if="project.properties['published'].has_key('pages')">:${project.properties['published']['pages']}</span>
-	       <span class="year" py:if="project.properties['published'].has_key('year')">(${project.properties['published']['year']})</span>
+               <span py:if="'pubmed' in project.properties['published']">(<a href="http://www.ncbi.nlm.nih.gov/pubmed/${project.properties['published']['pubmed']}">PubMed</a></span><span py:if="'pubmed' in project.properties['published'] and 'eprint' in project.properties['published']">,</span><span py:if="'pubmed' not in project.properties['published'] and 'eprint' in project.properties['published']">(</span><span py:if="'eprint' in project.properties['published']"><a href="${project.properties['published']['eprint']}">eprint</a></span><span py:if="'pubmed' in project.properties['published'] or 'eprint' in project.properties['published']">)</span>
+	       <span class="journal" py:if="'journal' in project.properties['published']">${project.properties['published']['journal']}</span>
+	       <span class="journal" py:if="'volume' in project.properties['published']">${project.properties['published']['volume']}</span><span class="journal" py:if="'number' in project.properties['published']">(${project.properties['published']['number']})</span><span class="journal" py:if="'pages' in project.properties['published']">:${project.properties['published']['pages']}</span>
+	       <span class="year" py:if="'year' in project.properties['published']">(${project.properties['published']['year']})</span>
 	     </div>
 	   </td>
 	   <td py:if="project.component and project.pkgstatus != 'new' and project.pkgstatus != 'pkgvcs'" class="project-icon">
diff --git a/webtools/templates/tasks_idx.xhtml b/webtools_py3/templates/tasks_idx.xhtml
similarity index 87%
copy from webtools/templates/tasks_idx.xhtml
copy to webtools_py3/templates/tasks_idx.xhtml
index 6cf144f..10dcaa2 100644
--- a/webtools/templates/tasks_idx.xhtml
+++ b/webtools_py3/templates/tasks_idx.xhtml
@@ -5,7 +5,7 @@
       xmlns:py="http://genshi.edgewall.org/">
 <head>
 <title>$projectname</title>
-<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8"/>
+<meta http-equiv="Content-Type" content="application/xhtml+xml;"/> <!--charset=UTF-8"/>-->
 <link href="/css/sentinel.css" type="text/css" rel="stylesheet"/>
 </head>
 <body>
@@ -35,11 +35,11 @@
 			<dl>
                              <py:for each="task in taskskeys">
                                 <dt><a href="${task}" name="${task}" id="${task}">${tasks[task].metapkg.PrintedName.capitalize()} - <span py:choose="">
-	           <span py:when="tasks[task].metapkg.desc.has_key(lang)">${tasks[task].metapkg.desc[lang]['short']}</span>
+	           <span py:when="lang in tasks[task].metapkg.desc">${tasks[task].metapkg.desc[lang]['short']}</span>
 	           <span py:otherwise="">${tasks[task].metapkg.desc['en']['short']}</span>
                  </span></a></dt>
 				<dd><span py:choose="">
-	           <span py:when="tasks[task].metapkg.desc.has_key(lang)">${tasks[task].metapkg.desc[lang]['long']}</span>
+	           <span py:when="lang in tasks[task].metapkg.desc">${tasks[task].metapkg.desc[lang]['long']}</span>
 	           <span py:otherwise="">${tasks[task].metapkg.desc['en']['long']}</span>
                  </span></dd>
                              </py:for>
diff --git a/webtools/templates/thermometer.xhtml b/webtools_py3/templates/thermometer.xhtml
similarity index 97%
copy from webtools/templates/thermometer.xhtml
copy to webtools_py3/templates/thermometer.xhtml
index 326feec..f179313 100644
--- a/webtools/templates/thermometer.xhtml
+++ b/webtools_py3/templates/thermometer.xhtml
@@ -5,7 +5,7 @@
       xmlns:py="http://genshi.edgewall.org/">
 <head>
 <title>$projectname Thermometer</title>
-<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8"/>
+<meta http-equiv="Content-Type" content="application/xhtml+xml;" /><!--charset=UTF-8"/>-->
 <link href="/css/sentinel.css" type="text/css" rel="stylesheet"/>
 </head>
 <body>
diff --git a/webtools/templates/uthermometer.xhtml b/webtools_py3/templates/uthermometer.xhtml
similarity index 97%
copy from webtools/templates/uthermometer.xhtml
copy to webtools_py3/templates/uthermometer.xhtml
index 1c8f430..21ccee3 100644
--- a/webtools/templates/uthermometer.xhtml
+++ b/webtools_py3/templates/uthermometer.xhtml
@@ -5,7 +5,7 @@
       xmlns:py="http://genshi.edgewall.org/">
 <head>
 <title>$projectname packages in Ubuntu Thermometer</title>
-<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8"/>
+<meta http-equiv="Content-Type" content="application/xhtml+xml;"/> <!--charset=UTF-8"/>-->
 <link href="/css/sentinel.css" type="text/css" rel="stylesheet"/>
 </head>
 <body>
diff --git a/webtools/thermometer.py b/webtools_py3/thermometer.py
similarity index 94%
copy from webtools/thermometer.py
copy to webtools_py3/thermometer.py
index cbb539f..c39af16 100755
--- a/webtools/thermometer.py
+++ b/webtools_py3/thermometer.py
@@ -28,12 +28,12 @@ from blendstasktools import ReadConfig, RowDictionaries, CheckOrCreateOutputDir,
 # Define several prepared statements to query UDD
 try:
   conn = psycopg2.connect(host="localhost",port=PORT,user="guest",database="udd")
-except psycopg2.OperationalError, err:
+except psycopg2.OperationalError as err:
   try:
     conn = psycopg2.connect("service=udd")
-  except psycopg2.OperationalError, err:
+  except psycopg2.OperationalError as err:
     # logger not known at this state: logger.warning
-    print >>stderr, "Service=udd seems not to be installed on this host.\tMessage: %s" % (str(err))
+    print("Service=udd seems not to be installed on this host.\tMessage: %s" % (str(err)), file=stderr)
     try:
         conn = psycopg2.connect(host="localhost",port=DEFAULTPORT,user="guest",database="udd")
     except psycopg2.OperationalError:
@@ -48,18 +48,18 @@ curs = conn.cursor()
 def _execute_udd_query(query):
     try:
         curs.execute(query)
-    except psycopg2.ProgrammingError, err:
-        print >>stderr, "Problem with query\n%s" % (query)
-        print >>stderr, err
+    except psycopg2.ProgrammingError as err:
+        print("Problem with query\n%s" % (query), file=stderr)
+        print(err, file=stderr)
         exit(-1)
-    except psycopg2.DataError, err:
-        print >>stderr, "%s; query was\n%s" % (err, query)
+    except psycopg2.DataError as err:
+        print("%s; query was\n%s" % (err, query), file=stderr)
 
 
 def main():
 
     if len(argv) <= 1:
-        print >>stderr, "Usage: %s <Blend name>" % argv[0]
+        print("Usage: %s <Blend name>" % argv[0], file=stderr)
         exit(-1)
 
     blendname = argv[1]
@@ -74,7 +74,7 @@ def main():
         ubuntuprev1  = releasenames[1][0]
         ubuntuprev2  = releasenames[2][0]
     else:
-        print >>stderr, "Failed to obtain Ubuntu release names."
+        print("Failed to obtain Ubuntu release names.", file=stderr)
         exit(1)
 
     query = """PREPARE query_thermometer (text) AS
@@ -334,7 +334,7 @@ def main():
         #f.close()
         #SetFilePermissions(blendname+'_thermometer.json')
     else:
-        print >>stderr, "No data received for Blend", blendname
+        print("No data received for Blend", blendname, file=stderr)
         exit(1)
 
     # Define directories used
@@ -358,7 +358,7 @@ def main():
     data={}
     data['projectname'] = blendname
     data['blend_data']  = blend_data
-    if config.has_key('advertising') and config['advertising'] != None:
+    if 'advertising' in config and config['advertising'] != None:
         # we have to remove the gettext _() call which was inserted into the config
         # file to enable easy input for config file editors - but the call has to
         # be made explicitely in the python code
@@ -414,17 +414,17 @@ the right shows the tasks of %s.""" ) \
     f = open(outputfile, 'w')
     template = loader.load('thermometer.xhtml')
     try:
-         print >> f, template.generate(**data).render('xhtml')
-    except TypeError, err:
-         print >>stderr, "Problem creating thermometer.html.\tMessage: %s" % (str(err))
+         print(template.generate(**data).render('xhtml'), file=f)
+    except TypeError as err:
+         print("Problem creating thermometer.html.\tMessage: %s" % (str(err)), file=stderr)
     f.close()
     SetFilePermissions(outputfile)
     f = open(uoutputfile, 'w')
     utemplate = loader.load('uthermometer.xhtml')
     try:
-        print >> f, utemplate.generate(**data).render('xhtml')
-    except TypeError, err:
-         print >>stderr, "Problem creating uthermometer.html.\tMessage: %s" % (str(err))
+        print(utemplate.generate(**data).render('xhtml'), file=f)
+    except TypeError as err:
+         print("Problem creating uthermometer.html.\tMessage: %s" % (str(err)), file=stderr)
     f.close()
     SetFilePermissions(uoutputfile)
 
diff --git a/webtools/update-all b/webtools_py3/update-all
similarity index 100%
copy from webtools/update-all
copy to webtools_py3/update-all
diff --git a/webtools/update-all-bugs b/webtools_py3/update-all-bugs
similarity index 100%
copy from webtools/update-all-bugs
copy to webtools_py3/update-all-bugs
diff --git a/webtools/update-all-tasks b/webtools_py3/update-all-tasks
similarity index 100%
copy from webtools/update-all-tasks
copy to webtools_py3/update-all-tasks
diff --git a/webtools/update-all-thermometers b/webtools_py3/update-all-thermometers
similarity index 100%
copy from webtools/update-all-thermometers
copy to webtools_py3/update-all-thermometers
diff --git a/webtools/webconf/debian-3dprinter.conf b/webtools_py3/webconf/debian-3dprinter.conf
similarity index 100%
copy from webtools/webconf/debian-3dprinter.conf
copy to webtools_py3/webconf/debian-3dprinter.conf
diff --git a/webtools/webconf/debian-accessibility.conf b/webtools_py3/webconf/debian-accessibility.conf
similarity index 100%
copy from webtools/webconf/debian-accessibility.conf
copy to webtools_py3/webconf/debian-accessibility.conf
diff --git a/webtools/webconf/debian-edu.conf b/webtools_py3/webconf/debian-edu.conf
similarity index 100%
copy from webtools/webconf/debian-edu.conf
copy to webtools_py3/webconf/debian-edu.conf
diff --git a/webtools/webconf/debian-ezgo.conf b/webtools_py3/webconf/debian-ezgo.conf
similarity index 100%
copy from webtools/webconf/debian-ezgo.conf
copy to webtools_py3/webconf/debian-ezgo.conf
diff --git a/webtools/webconf/debian-games.conf b/webtools_py3/webconf/debian-games.conf
similarity index 100%
copy from webtools/webconf/debian-games.conf
copy to webtools_py3/webconf/debian-games.conf
diff --git a/webtools/webconf/debian-gis.conf b/webtools_py3/webconf/debian-gis.conf
similarity index 100%
copy from webtools/webconf/debian-gis.conf
copy to webtools_py3/webconf/debian-gis.conf
diff --git a/webtools/webconf/debian-hamradio.conf b/webtools_py3/webconf/debian-hamradio.conf
similarity index 100%
copy from webtools/webconf/debian-hamradio.conf
copy to webtools_py3/webconf/debian-hamradio.conf
diff --git a/webtools/webconf/debian-imaging.conf b/webtools_py3/webconf/debian-imaging.conf
similarity index 100%
copy from webtools/webconf/debian-imaging.conf
copy to webtools_py3/webconf/debian-imaging.conf
diff --git a/webtools/webconf/debian-junior.conf b/webtools_py3/webconf/debian-junior.conf
similarity index 100%
copy from webtools/webconf/debian-junior.conf
copy to webtools_py3/webconf/debian-junior.conf
diff --git a/webtools/webconf/debian-lex.conf b/webtools_py3/webconf/debian-lex.conf
similarity index 100%
copy from webtools/webconf/debian-lex.conf
copy to webtools_py3/webconf/debian-lex.conf
diff --git a/webtools/webconf/debian-med.conf b/webtools_py3/webconf/debian-med.conf
similarity index 100%
copy from webtools/webconf/debian-med.conf
copy to webtools_py3/webconf/debian-med.conf
diff --git a/webtools/webconf/debian-multimedia.conf b/webtools_py3/webconf/debian-multimedia.conf
similarity index 100%
copy from webtools/webconf/debian-multimedia.conf
copy to webtools_py3/webconf/debian-multimedia.conf
diff --git a/webtools/webconf/debian-pan.conf b/webtools_py3/webconf/debian-pan.conf
similarity index 100%
copy from webtools/webconf/debian-pan.conf
copy to webtools_py3/webconf/debian-pan.conf
diff --git a/webtools/webconf/debian-sanctuary.conf b/webtools_py3/webconf/debian-sanctuary.conf
similarity index 100%
copy from webtools/webconf/debian-sanctuary.conf
copy to webtools_py3/webconf/debian-sanctuary.conf
diff --git a/webtools/webconf/debian-science.conf b/webtools_py3/webconf/debian-science.conf
similarity index 100%
copy from webtools/webconf/debian-science.conf
copy to webtools_py3/webconf/debian-science.conf
diff --git a/webtools/webconf/debichem.conf b/webtools_py3/webconf/debichem.conf
similarity index 100%
copy from webtools/webconf/debichem.conf
copy to webtools_py3/webconf/debichem.conf
diff --git a/webtools/webconf/fun.conf b/webtools_py3/webconf/fun.conf
similarity index 100%
copy from webtools/webconf/fun.conf
copy to webtools_py3/webconf/fun.conf
diff --git a/webtools/webconf/openstudio.conf b/webtools_py3/webconf/openstudio.conf
similarity index 100%
copy from webtools/webconf/openstudio.conf
copy to webtools_py3/webconf/openstudio.conf

-- 
Static and dynamic websites for Debian Pure Blends



More information about the Blends-commit mailing list