[PATCH 2/2] Make aap more Python 3.x forward compatible

Leandro Lucarella <[email protected]> Mon, 6 Apr 2009 11:19:01 -0300
Newsgroups gmane.comp.tools.aap.devel
Message-ID <[email protected]>
From: Leandro Lucarella <[email protected]>

This patch changes 2 things:
1) Try to use html or HTMLParser module first, then use htmllib module
2) Use the "in" operator instead of the "has_key()" method
---
 Action.py      |   34 +++++++++++++++++-----------------
 Args.py        |    2 +-
 Cache.py       |   10 +++++-----
 Commands.py    |   46 +++++++++++++++++++++++-----------------------
 CopyMove.py    |    2 +-
 DoArgs.py      |   12 ++++++------
 DoBuild.py     |   26 +++++++++++++-------------
 DoRead.py      |    2 +-
 Filetype.py    |   14 +++++++-------
 Node.py        |   12 ++++++------
 Port.py        |   14 +++++++-------
 RecPython.py   |   40 +++++++++++++++++++++++++++-------------
 Remote.py      |    6 +++---
 Rule.py        |    4 ++--
 Scope.py       |   54 +++++++++++++++++++++++++++---------------------------
 Sign.py        |   38 +++++++++++++++++++-------------------
 Util.py        |   14 +++++++-------
 VersCont.py    |   12 ++++++------
 VersContCvs.py |    8 ++++----
 Work.py        |   18 +++++++++---------
 aap            |    2 +-
 import_re.py   |    2 +-
 22 files changed, 193 insertions(+), 179 deletions(-)

diff --git a/Action.py b/Action.py
index 94191f8..179be4b 100644
--- a/Action.py
+++ b/Action.py
@@ -134,7 +134,7 @@ def action_add_to_dict(action, act):
     Add action object "act" to the dictionary of actions.
     """
     global _action_dict
-    if not _action_dict.has_key(action):
+    if not action in _action_dict:
         _action_dict[action] = []
     _action_dict[action].append(act)
 
@@ -215,7 +215,7 @@ def get_ftypes(action, in_types, intype = None, outtype = None):
     If "outtype" given this output type must be supported.
     """
     retval = []
-    if _action_dict.has_key(action):
+    if action in _action_dict:
         for act in _action_dict[action]:
             if in_types:
                 l = act.get_in_types(outtype = outtype)
@@ -245,7 +245,7 @@ def action_get_list():
         retval[action] = {}
         for act in _action_dict[action]:
             for intype in act.get_in_types():
-                if not retval[action].has_key(intype):
+                if intype not in retval[action]:
                     retval[action][intype] = {}
                 for outtype in act.get_out_types():
                     retval[action][intype][outtype] = act
@@ -258,18 +258,18 @@ def action_ftype(recdict, action, dict):
     Decide what filetype to use for "action" for the file specified with
     dictionary "dict".
     """
-    if dict.has_key("filetype"):
+    if "filetype" in dict:
         return dict["filetype"]
 
     from Work import getwork
     fname = dict["name"]
     node = getwork(recdict).find_node(fname)
-    if node and node.attributes.has_key("filetype"):
+    if node and "filetype" in node.attributes:
         return node.attributes["filetype"]
 
     # A ":program", ":produce" etc. adds a "filetypehint" attribute that has a
     # lower priority than a "filetype" attribute the user specifies.
-    if dict.has_key("filetypehint"):
+    if "filetypehint" in dict:
         return dict["filetypehint"]
 
     # For viewing a remote file the filetype doesn't really matter, need to
@@ -290,7 +290,7 @@ def has_action(recdict, action, dict):
     Return non-zero if "action" is defined for the file specified with "dict".
     Does not use the default.
     """
-    if not _action_dict.has_key(action):
+    if action not in _action_dict:
         return 0
     intype = action_ftype(recdict, action, dict)
     for act in _action_dict[action]:
@@ -301,7 +301,7 @@ def has_action(recdict, action, dict):
 
 def find_depend_action(ftype):
     """Find the depend action for a source file with type "ftype"."""
-    if not _action_dict.has_key("depend"):
+    if not "depend" in _action_dict:
         return None
 
     found_act = None
@@ -433,7 +433,7 @@ def action_run(recdict, args):
        When the "filetype" attribute isn't specified, detect it from args[1].
        Returns None for success, an error message for failure."""
     action = args[0]["name"]
-    if not _action_dict.has_key(action):
+    if action not in _action_dict:
         return _("Unknown action: %s") % action
 
     in_ftype = action_ftype(recdict, action, args[1])
@@ -445,9 +445,9 @@ def action_run(recdict, args):
 
     out_ftype = args[0].get("filetype")
     if not out_ftype:
-        if args[0].has_key("target"):
+        if "target" in args[0]:
             t = args[0]["target"]
-        elif recdict.has_key("target"):
+        elif "target" in recdict:
             t = recdict["target"]
         else:
             t = None
@@ -515,7 +515,7 @@ def action_run(recdict, args):
         get_vars_from_attr(s, new_recdict)
 
     # Also use "var_" and "add_" attributes from the target.
-    if new_recdict.has_key("target"):
+    if "target" in new_recdict:
         for d in str2dictlist([], new_recdict["target"]):
             get_vars_from_attr(d, new_recdict)
 
@@ -564,13 +564,13 @@ def action_expand_do(recdict, commands, targetlist, sourcelist):
             # The action is the first argument.
             action = args[0]["name"]
 
-            if _action_dict.has_key(action):
+            if action in _action_dict:
                 # Guess the input filetype to be used:
                 # 1. an explicitly defined filetype after the action.
                 # 2. if the first filename doesn't contain a $, get the
                 #    filetype from it.
                 # 3. use the filetype from the first source item
-                if args[1].has_key("filetype"):
+                if "filetype" in args[1]:
                     in_ftype = args[1]["filetype"]
                 elif not '$' in args[1]["name"]:
                     in_ftype = action_ftype(recdict, action, args[1])
@@ -594,12 +594,12 @@ def action_expand_do(recdict, commands, targetlist, sourcelist):
                             args[0]["target"], Expand(1, Expand.quote_aap)))[0]
                 except:
                     target = targetlist[0]
-                if recdict.has_key("target"):
+                if "target" in recdict:
                     if tt is None:
                         del recdict["target"]
                     else:
                         recdict["target"] = tt
-                if target.has_key("filetype"):
+                if "filetype" in target:
                     out_ftype = target["filetype"]
                 elif not '$' in target["name"]:
                     out_ftype = action_ftype(recdict, action, target)
@@ -622,7 +622,7 @@ def action_expand_do(recdict, commands, targetlist, sourcelist):
                         cmd = act.commands
                     # Check if this action isn't used recursively.
                     key = action + '@' + in_ftype + '@' + out_ftype
-                    if (exp_action_end.has_key(key)
+                    if (key in exp_action_end
                                              and exp_action_end[key] > do):
                         # :do command starts before expanded commands.
                         act = None
diff --git a/Args.py b/Args.py
index 5c79cd3..4db8e76 100644
--- a/Args.py
+++ b/Args.py
@@ -28,7 +28,7 @@ class Args:
         self.targets = []
 
     def has_option(self, name):
-        return self.options.has_key(name)
+        return name in self.options
 
     def printit(self):
         """print the contents of the attributes (for debugging)"""
diff --git a/Cache.py b/Cache.py
index f603b57..fe50eab 100644
--- a/Cache.py
+++ b/Cache.py
@@ -111,7 +111,7 @@ def cache_read(recdict, fname, rcache, lock):
         except:
             # Some error in this line, skip it.
             continue
-        if rcache.has_key(url):
+        if url in rcache:
             # URL already exists.  Only use new entry when it's newer.
             rc = rcache[url]
             if rtime > rc.rtime or ltime > rc.ltime:
@@ -142,7 +142,7 @@ def index_write_newest(recdict, fname, f, use_cache, check_cache):
             # it does have an entry which is not written but our entry is
             # newer.
             else:
-                if check_cache.has_key(url) and not check_cache[url].gone:
+                if url in check_cache and not check_cache[url].gone:
                     ck = check_cache[url]
                 else:
                     ck = None
@@ -324,13 +324,13 @@ def fill_cache(recdict):
     # $CACHEPATH and the current directory.  Avoids expanding items in
     # $CACHEPATH to absolute paths each time.
     check = get_var_val_int(recdict, "CACHEPATH") + '>' + os.getcwd()
-    if not cache_val_read.has_key(check):
+    if check not in cache_val_read:
         cache_val_read[check] = 1
 
         # Read the cache index files for all entries in $CACHEPATH
         for n in cache_dirlist(recdict):
             index = os.path.join(os.path.abspath(n), index_fname)
-            if not cache_indexes.has_key(index):
+            if index not in cache_indexes:
                 cache_read(recdict, index, cache, 1)
 
 
@@ -347,7 +347,7 @@ def dump_cache(recdict):
 
 def cache_lookup(recdict, name, cache_update_str = None):
     """Lookup URL "name" in the cache.  Return the Cache object if found."""
-    if cache.has_key(name):
+    if name in cache:
         ent = cache[name]
 
         # if the entry was updated this session, it's always accepted.
diff --git a/Commands.py b/Commands.py
index cc4612a..74a10d2 100644
--- a/Commands.py
+++ b/Commands.py
@@ -58,7 +58,7 @@ def get_args(line_nr, recdict, arg, options = None, exp_attr = 1):
     # Move options from attrdict to optiondict.  Translate aliases.
     if options:
         for k in attrdict.keys():
-            if options.has_key(k):
+            if k in options:
                 optiondict[options[k]] = attrdict[k]
                 del attrdict[k]
 
@@ -349,10 +349,10 @@ def aap_program(line_nr, recdict, arg, type = "program"):
             varname = ba[4:]
             for source in sourcelist:
                 # Source-level var_ attributes take precedence
-                if source.has_key("var_"+varname):
+                if "var_"+varname in source:
                     continue
                 # Prepend build attribute
-                if source.has_key("add_"+varname):
+                if "add_"+varname in source:
                     if ba.startswith("add_"):
                         source[ba] = value + " " + source[ba]
                     else:
@@ -362,7 +362,7 @@ def aap_program(line_nr, recdict, arg, type = "program"):
                     source[ba] = value
         else:
             for source in sourcelist:
-                if not source.has_key(ba):
+                if ba not in source:
                     source[ba] = value
 
     # ":produce abc" needs to declare "abc" as a filetype.
@@ -450,7 +450,7 @@ def aap_lib(line_nr, recdict, arg):
 def aap_ltlib(line_nr, recdict, arg):
     """Add a libtool library built from sources."""
     # We automatically import the libtool module.
-    if not getwork(recdict).module_already_read.has_key("libtool"):
+    if "libtool" not in getwork(recdict).module_already_read:
         aap_import(line_nr, recdict, "libtool")
     aap_program(line_nr, recdict, arg, type = "ltlib")
 
@@ -1114,7 +1114,7 @@ def aap_syseval(line_nr, recdict, raw_arg, pipein = None):
             cmd = cmd + (' < %s' % tmpin)
 
         tmpout = tempfname()
-        if attrdict.has_key("stderr"):
+        if "stderr" in attrdict:
             cmd = cmd + ' 2>&1'
         cmd = cmd + (' > %s' % tmpout)
 
@@ -1258,7 +1258,7 @@ def aap_child_and_exe(line_nr, recdict, arg, child):
 
     force_fetch = Global.cmd_args.has_option("fetch-recipe")
     if ((force_fetch or not os.path.exists(name))
-            and varlist[0].has_key("fetch")):
+            and "fetch" in varlist[0]):
         # Need to create a node to fetch it.
         # Ignore errors, a check for existence is below.
         # Use a cached file when no forced fetch.
@@ -1267,7 +1267,7 @@ def aap_child_and_exe(line_nr, recdict, arg, child):
         fetch_nodelist(rpstack, recdict, [ node ], not force_fetch)
 
     if not os.path.exists(name):
-        if varlist[0].has_key("fetch"):
+        if "fetch" in varlist[0]:
             recipe_error(rpstack, _('Cannot download recipe "%s"') % name)
         else:
             recipe_error(rpstack, _('Recipe "%s" does not exist') % name)
@@ -1483,7 +1483,7 @@ def aap_assign(line_nr, recdict, name, arg, dollar, extra):
     rd, scope, varname = get_scope_recdict(rpstack, recdict, name, 1)
 
     # Skip the whole assignment for "var ?= val" if var was already set.
-    if extra != '?' or not rd.has_key(varname):
+    if extra != '?' or varname not in rd:
         if dollar != '$':
             # Expand variables in "arg".
             val = expand(line_nr, recdict, arg, Expand(1, Expand.quote_aap))
@@ -1491,7 +1491,7 @@ def aap_assign(line_nr, recdict, name, arg, dollar, extra):
             val = arg
 
         import types
-        if rd.has_key(varname):
+        if varname in rd:
             v = rd.get(varname)
             from Scope import RecipeDict
             if isinstance(v, types.DictType) or isinstance(v, RecipeDict):
@@ -1889,7 +1889,7 @@ def aap_shell(line_nr, recdict, cmds, async = -1):
 
     cmd = expand(line_nr, recdict, cmds, Expand(0, Expand.quote_shell))
 
-    if recdict.has_key("target"):
+    if "target" in recdict:
         msg_extra(recdict, _('Shell commands for updating "%s":')
                                                            % recdict["target"])
 
@@ -1933,7 +1933,7 @@ def aap_sysdepend(line_nr, recdict, arg):
     cmd = expand(line_nr, recdict, arg[i:], Expand(0, Expand.quote_shell))
     from RecPython import redir_system
 
-    if attrdict.has_key("srcpath"):
+    if "srcpath" in attrdict:
         # Use the specified search path.
         searchpath = attrdict.get("srcpath")
     else:
@@ -2495,11 +2495,11 @@ def aap_include(line_nr, recdict, arg):
     # Fetch the recipe when invoked with the "-R" argument.
     if ((Global.cmd_args.has_option("fetch-recipe")
             or not os.path.exists(recname))
-                and args[0].has_key("fetch")):
+                and "fetch" in args[0]):
         # Use the original recipe name, without the directory of "-I dir" added.
         fetchname = args[0]["name"]
         fullname = full_fname(fetchname)
-        if not recipe_fetched.has_key(fullname):
+        if fullname not in recipe_fetched:
             from VersCont import fetch_nodelist
 
             # Create a node for the recipe and fetch it.
@@ -2539,7 +2539,7 @@ def aap_import(line_nr, recdict, arg):
     name = args[0]["name"]
 
     # Import only imports a given module once.
-    if work.module_already_read.has_key(name):
+    if name in work.module_already_read:
         msg_extra(recdict, _('Skipping module already imported: %s"') % name)
         return
     work.module_already_read[name] = 1
@@ -2638,7 +2638,7 @@ def maydo_recipe_cmd(rpstack):
 
     # Skip when this recipe was already updated.
     recname = full_fname(rpstack[-1].name)
-    if recipe_fetched.has_key(recname):
+    if recname in recipe_fetched:
         return 0
 
     return 1
@@ -2663,7 +2663,7 @@ def aap_recipe(line_nr, recdict, arg):
     msg_info(recdict, _('Updating recipe "%s"') % short_name)
 
     orgdict, i = get_attrdict(rpstack, recdict, arg, 0, 1)
-    if not orgdict.has_key("fetch"):
+    if "fetch" not in orgdict:
         recipe_error(rpstack, _(":recipe requires a fetch attribute"))
     # TODO: warning for trailing characters?
 
@@ -2679,7 +2679,7 @@ def aap_recipe(line_nr, recdict, arg):
         # recipe.
         start_recdict = recdict["_start_recdict"]
         for k in recdict.keys():
-            if not start_recdict.has_key(k):
+            if k not in start_recdict:
                 del recdict[k]
         for k in start_recdict.keys():
             recdict[k] = start_recdict[k]
@@ -2816,8 +2816,8 @@ def do_fetch_all(rpstack, recdict, attrdict):
         # - it has an "fetch" attribute
         # - the node doesn't exist yet
         # - it does exist and the "constant" attribute isn't set
-        if ((node.attributes.has_key("fetch")
-                    or node.attributes.has_key("commit"))
+        if (("fetch" in node.attributes
+                    or "commit" in node.attributes)
                 and node.may_fetch()):
             node.set_attributes(attrdict)
             nodelist.append(node)
@@ -2849,8 +2849,8 @@ def do_verscont_all(rpstack, recdict, action, attrdict):
     # Loop over all nodes.
     nodelist = []
     for node in work.nodes.values():
-        if (node.attributes.has_key("commit")
-                and (action != "add" or node.attributes.has_key("tag"))):
+        if ("commit" in node.attributes
+                and (action != "add" or "tag" in node.attributes)):
             node.set_attributes(attrdict)
             nodelist.append(node)
 
@@ -2929,7 +2929,7 @@ def do_publish_all(rpstack, recdict, attrdict):
     # Loop over all nodes.
     nodelist = []
     for node in work.nodes.values():
-        if node.attributes.has_key("publish"):
+        if "publish" in node.attributes:
             node.set_attributes(attrdict)
             nodelist.append(node)
 
diff --git a/CopyMove.py b/CopyMove.py
index 51bec19..49a8744 100644
--- a/CopyMove.py
+++ b/CopyMove.py
@@ -501,7 +501,7 @@ def remote_copy_move(rpstack, recdict, copy, from_items, to_item,
                         if flist:
                             # Remove the "keepdir" attribute, the directory
                             # name is already in "destpath" now.
-                            if optiondict.has_key("keepdir"):
+                            if "keepdir" in optiondict:
                                 opt = optiondict.copy()
                                 del opt["keepdir"]
                             else:
diff --git a/DoArgs.py b/DoArgs.py
index fca2d2d..8918e03 100644
--- a/DoArgs.py
+++ b/DoArgs.py
@@ -371,7 +371,7 @@ def doargs(argv):
                     if not arg:
                         arg = 1
                     if o.append:
-                        if args.options.has_key(o.name):
+                        if o.name in args.options:
                             args.options[o.name].append(arg)
                         else:
                             args.options[o.name] = [ arg ]
@@ -379,7 +379,7 @@ def doargs(argv):
                         args.options[o.name] = arg
 
             # Did we encounter "--"?
-            if not args.options.has_key("end"):
+            if "end" not in args.options:
                 n = len(prev_argv) - len(argv)
                 if n > 0 and prev_argv[n - 1] == "--":
                     args.options["end"] = 1
@@ -392,7 +392,7 @@ def doargs(argv):
             while argv:
                 if argv[0] == '-':
                     raise UserError, _("Invalid argument: - (reading from stdin not implemented yet)")
-                elif argv[0][0] == '-' and not args.options.has_key("end"):
+                elif argv[0][0] == '-' and "end" not in args.options:
                     break
                 elif '=' in argv[0]:
                     name, value = string.split(argv[0], '=', 1)
@@ -401,7 +401,7 @@ def doargs(argv):
                     args.targets.append(argv[0])
                     # Using a "refresh", "fetch" or "update" target implies the
                     # --fetch-recipe option, unless --nofetch-recipe was used.
-                    if (not args.options.has_key("nofetch-recipe")
+                    if ("nofetch-recipe" not in args.options
                         and (argv[0] == "refresh"
                             or argv[0] == "fetch"
                             or argv[0] == "update")):
@@ -414,7 +414,7 @@ def doargs(argv):
 def local_arg():
     """Return non-zero  if the "-l" or "--local" argument was given.  zero
        string otherwise."""
-    if Global.cmd_args.options.has_key("local"):
+    if "local" in Global.cmd_args.options:
         return 1
     return 0
 
@@ -456,7 +456,7 @@ def copy_global_options(cmd_args_from, cmd_args_to):
                         "verbose",
                         ]
     for k in cmd_args_from.options.keys():
-        if k in global_options and not cmd_args_to.options.has_key(k):
+        if k in global_options and k not in cmd_args_to.options:
             cmd_args_to.options[k] = cmd_args_from.options[k]
 
 # vim: set sw=4 et sts=4 tw=79 fo+=l:
diff --git a/DoBuild.py b/DoBuild.py
index 534f48e..4ec5aa7 100644
--- a/DoBuild.py
+++ b/DoBuild.py
@@ -273,7 +273,7 @@ def autodep_update(work, recdict, scope_recdict, src_dict,
     # If "target" starts with (part of) $BDIR set the depdir attribute
     # to use it for the auto-dependency file.  Useful if some variant
     # isn't used for the directory.
-    if not node.attributes.has_key("depdir"):
+    if "depdir" not in node.attributes:
         bdir = locate_bdir(target.get_name(), remove = 0)
         if bdir:
             node.attributes["depdir"] = bdir
@@ -327,7 +327,7 @@ def expand_srcpath(recdict, isabs, name, dict):
     The "srcpath" attribute in "dict" overrules $SRCPATH.
     """
     if not isabs:
-        if dict.has_key("srcpath"):
+        if "srcpath" in dict:
             from Dictlist import str2dictlist
             srcpath = str2dictlist([], dict["srcpath"])
         else:
@@ -427,7 +427,7 @@ def dictlist_update(dictlist, work, recdict, scope_recdict,
         # However, need to add the directory for a child recipe.
         src = src_dict["name"]
         src_isabs = os.path.isabs(src)
-        if not src_isabs and src_dict.has_key("_node"):
+        if not src_isabs and "_node" in src_dict:
             src = src_dict["_node"].short_name()
 
         names = expand_srcpath(recdict,
@@ -496,7 +496,7 @@ def check_need_update(recdict, update, src_dict, target, rootname = None):
     # to be able to remember them).
     if target.status != Node.builderror and not update.outdated(target):
         virtual = 0
-        if src_dict.has_key("_node"):
+        if "_node" in src_dict:
             node = src_dict["_node"]
             src_name = node.get_name()
             virtual = node.attributes.get("virtual")
@@ -514,7 +514,7 @@ def check_need_update(recdict, update, src_dict, target, rootname = None):
             update.source = src_name
         else:
             alt_dict = None
-            if src_dict.has_key("_node"):
+            if "_node" in src_dict:
                 alt_dict = src_dict["_node"].attributes
             check = check_name(recdict, src_name, src_dict, alt_dict)
             if check == "newer":
@@ -628,12 +628,12 @@ def buildcheck_update(recdict, checkstring, dep, target, update, level):
                                                  commands, xp, skip_errors = 1)
     check_str = expand(line_nr, recdict, checkstring, xp, skip_errors = 1)
     del recdict["commands"]
-    if recdict.has_key("xcommands"):
+    if "xcommands" in recdict:
         del recdict["xcommands"]
 
     for k in saved + save_attr.keys():
         if save[k] is None:
-            if recdict.has_key(k):
+            if k in recdict:
                 del recdict[k]
         else:
             recdict[k] = save[k]
@@ -993,7 +993,7 @@ def target_update(work, recdict, target, toplevel = 0, force = 0, level = None):
             #    If the target doesn't exist and has the "fetch" attribute, try
             #    fetching it.  This may use a cached file.
             if (not os.path.exists(target_name)
-                                     and target.attributes.has_key("fetch")):
+                                     and "fetch" in target.attributes):
                 fetch_nodelist(target.rpstack(), recdict, [ target ], 1)
             if target.attributes.get("virtual"):
                 msg_depend(recdict,
@@ -1143,7 +1143,7 @@ def target_update(work, recdict, target, toplevel = 0, force = 0, level = None):
 
     # restore "virtual" attribute
     if save_virtual is None:
-        if target.attributes.has_key("virtual"):
+        if "virtual" in target.attributes:
             del target.attributes["virtual"]
     else:
         target.attributes["virtual"] = save_virtual
@@ -1164,7 +1164,7 @@ def dictlist2depnodelist(work, dictlist):
     nl = []
     for item in dictlist:
         # for a dependency we know the node, need to find it for a rule 
-        if item.has_key("_node"):
+        if "_node" in item:
             n = item["_node"]
         else:
             n = work.get_node(item["name"], 1)
@@ -1219,7 +1219,7 @@ def may_exec_depend(recdict, dep, update, target, src_list_list, level,
 
     # If a "buildcheck" attribute is defined for the build commands, check
     # if it has changed.  Otherwise check if the build commands changed.
-    if dep.build_attr.has_key("buildcheck"):
+    if "buildcheck" in dep.build_attr:
         buildcheck = dep.build_attr["buildcheck"]
     else:
         buildcheck = "$xcommands"
@@ -1292,7 +1292,7 @@ def may_exec_depend(recdict, dep, update, target, src_list_list, level,
         # executed at all.
         for trg in dep.targetlist:
             # Can there be a target without a node???
-            if not trg.has_key("_node"):
+            if "_node" not in trg:
                 continue
             node = trg["_node"]
             # Skip standard virtual targets, they are always rebuild
@@ -1419,7 +1419,7 @@ def build_autodepend(work, recdict, stype, source, source_dict, level):
 
     # If the autodepend used the {recursive} attribute, need to carry this over
     # to the source node.
-    if action.attributes.has_key("recursive"):
+    if "recursive" in action.attributes:
         source.autodep_recursive = action.attributes["recursive"]
     else:
         source.autodep_recursive = 0
diff --git a/DoRead.py b/DoRead.py
index d5c5925..03e00e1 100644
--- a/DoRead.py
+++ b/DoRead.py
@@ -61,7 +61,7 @@ def read_recipe(rpstack, recdict, sname, toplevel, optional = 0, reread = 0):
     ":include" command inside build commands.
     """
     name = full_fname(sname)
-    if not reread and recipe_active.has_key(name):
+    if not reread and name in recipe_active:
         msg_warning(recdict,
                          _('Skipping recipe already being read: "%s"') % sname)
     else:
diff --git a/Filetype.py b/Filetype.py
index 9f61730..c39f7f6 100755
--- a/Filetype.py
+++ b/Filetype.py
@@ -1337,7 +1337,7 @@ class DetectError(Exception):
 def ft_known(type):
     """Return True when "type" is a known filetype."""
     __init__()
-    return _filetype_dict.has_key(type)
+    return type in _filetype_dict
 
 def ft_declare(type):
     """Delcare "type" to be a known filetype."""
@@ -1568,7 +1568,7 @@ def _add_suffix(suf, type):
        detection done on the rest.
        When "type" is "remove" an existing detection for "suf" is removed."""
     if type == 'remove':
-        if _suffix_dict.has_key(suf):
+        if suf in _suffix_dict:
             del _suffix_dict[suf]
     else:
         _suffix_dict[suf] = type
@@ -1667,7 +1667,7 @@ def _exec_py(fname, item, ignore):
     exec_recdict["fname_base"] = os.path.basename(fname)
     exec_recdict["ft_detect"] = ft_detect
     exec_recdict["ignore"] = ignore
-    if exec_recdict.has_key("type"):
+    if "type" in exec_recdict:
         del exec_recdict["type"]
 
     item.compile()
@@ -1678,7 +1678,7 @@ def _exec_py(fname, item, ignore):
     except StandardError, e:
         raise DetectError, _(item.error_msg) + str(e)
 
-    if exec_recdict.has_key("type"):
+    if "type" in exec_recdict:
         return exec_recdict["type"]
     return None
 
@@ -1687,7 +1687,7 @@ def ft_detect(fname, ignore = 0, recdict = None):
     """Detect the file type for file "fname".
        Returns the type as a string or None."""
     # return quickly when already detected before
-    if _cache_dict[ignore].has_key(fname):
+    if fname in _cache_dict[ignore]:
         return _cache_dict[ignore][fname]
 
     if os.path.isdir(fname):
@@ -1724,7 +1724,7 @@ def ft_detect(fname, ignore = 0, recdict = None):
     i = string.find(bn, ".")
     while i > 0 and i + 1 < len(bn):
         # Found a dot that's not the first or last character.
-        if _suffix_dict.has_key(bn[i + 1:]):
+        if bn[i + 1:] in _suffix_dict:
             ft = _suffix_dict[bn[i + 1:]]
             if ft == "ignore" and ignore:
                 # remove an ignored extension and detect with that
@@ -1846,7 +1846,7 @@ if __name__ == '__main__':
 
     # Check specified directories for *.afd files and read specified files.
     for item in items:
-        if item.has_key("dir"):
+        if "dir" in item:
             ft_check_dir(item["dir"])
         else:
             try:
diff --git a/Node.py b/Node.py
index f16f17a..64ab49c 100644
--- a/Node.py
+++ b/Node.py
@@ -184,10 +184,10 @@ class Node:
     def get_sign_fname(self):
         """Get the file name to use for the signatures of this node.
            When using a directory, append "sign_fname"."""
-        if self.attributes.has_key("signfile"):
+        if "signfile" in self.attributes:
             return os.path.abspath(os.path.expanduser(
                                                   self.attributes["signfile"]))
-        if self.attributes.has_key("signdirectory"):
+        if "signdirectory" in self.attributes:
             adir = os.path.abspath(os.path.expanduser(
                                              self.attributes["signdirectory"]))
         elif self.name_relative and not self.attributes.get("virtual"):
@@ -238,7 +238,7 @@ class Node:
         """Set attributes for a node from "dictlist".  Skip "name" and items
         that start with an underscore."""
         for k in dictlist.keys():
-            if k == "virtual" and self.attributes.has_key(k):
+            if k == "virtual" and k in self.attributes:
                 # The "virtual" attribute is never reset
                 self.attributes[k] = (self.attributes[k] or dictlist[k])
             elif k != "name" and k[0] != '_':
@@ -251,12 +251,12 @@ class Node:
         for attr in ["virtual", "remember", "directory", "filetype", "force",
                        "constant", "fetch", "commit", "publish", "signfile",
                        "depdir"]:
-            if dictlist.has_key(attr) and dictlist[attr]:
+            if attr in dictlist and dictlist[attr]:
                 self.attributes[attr] = dictlist[attr]
 
     def get_cache_update(self):
         """Get the cache_update attribute.  Return None if it's not set."""
-        if self.attributes.has_key("cache_update"):
+        if "cache_update" in self.attributes:
             return self.attributes["cache_update"]
         return None
 
@@ -265,7 +265,7 @@ class Node:
            specified with set_attributes() return the value used (mode value
            for creation)."""
         # A specified attribute overrules everything
-        if self.attributes.has_key("directory"):
+        if "directory" in self.attributes:
             return self.attributes["directory"]
         # A virtual target can't be a directory
         if self.attributes.get("virtual"):
diff --git a/Port.py b/Port.py
index b96b2a4..55c0e40 100644
--- a/Port.py
+++ b/Port.py
@@ -140,7 +140,7 @@ def add_port_defaults(work):
 
     for name in ["PORTVERSION", "PORTCOMMENT", "PORTDESCR"]:
         if not get_var_val_int(work.recdict, name):
-            if work.recdict["_no"].has_key(name):
+            if name in work.recdict["_no"]:
                 recipe_error([], _('Empty variable "%s"') % name)
             else:
                 recipe_error([], _('Missing variable "%s"') % name)
@@ -722,7 +722,7 @@ def port_fetch(recdict):
 
             # Get each module from CVS.
             for f in modules:
-                if f.has_key("cvsroot"):
+                if "cvsroot" in f:
                     root = f["cvsroot"]
                 else:
                     root = cvsroot
@@ -770,7 +770,7 @@ def port_fetch(recdict):
 
             # Let the "distdir" attribute overrule the default directory.
             fn = os.path.basename(f["name"])
-            if f.has_key("distdir"):
+            if "distdir" in f:
                 fname = os.path.join(f["distdir"], fn)
             else:
                 fname = os.path.join(destdir, fn)
@@ -786,7 +786,7 @@ def port_fetch(recdict):
             # Make the fetch attribute include the full path of the file to
             # download.
             n = work.get_node(fname, 0, f)
-            if f.has_key("fetch"):
+            if "fetch" in f:
                 rf = f["fetch"]
             else:
                 rf = master_fetch
@@ -836,7 +836,7 @@ def port_extract(recdict):
     distdir = os.path.abspath(get_var_val_int(recdict, "DISTDIR"))
     for x in archlist:
         fn = os.path.basename(x["name"])
-        if x.has_key("distdir"):
+        if "distdir" in x:
             x["name"] = os.path.abspath(os.path.join(x["distdir"], fn))
         else:
             x["name"] = os.path.join(distdir, fn)
@@ -848,7 +848,7 @@ def port_extract(recdict):
         for f in archlist:
             # change to "extractdir"
             # Make path absolute now, before changing directories.
-            if f.has_key("extractdir"):
+            if "extractdir" in f:
                 adir = os.path.join(wrkdir, f["extractdir"])
             else:
                 adir = wrkdir
@@ -879,7 +879,7 @@ def port_patch(recdict):
     patchdistdir = os.path.abspath(get_var_val_int(recdict, "PATCHDISTDIR"))
     for x in patchlist:
         fn = os.path.basename(x["name"])
-        if x.has_key("distdir"):
+        if "distdir" in x:
             x["name"] = os.path.abspath(os.path.join(x["distdir"], fn))
         else:
             x["name"] = os.path.join(patchdistdir, fn)
diff --git a/RecPython.py b/RecPython.py
index 39170b4..8531733 100644
--- a/RecPython.py
+++ b/RecPython.py
@@ -188,7 +188,7 @@ def childdir(arg):
     recipe.
     """
     recdict = Global.globals
-    if not recdict.has_key("CHILDDIR"):
+    if "CHILDDIR" not in recdict:
         msg_error(recdict, _("Using childdir() at the top level"))
         return ''
     return relativedir(arg, "CHILDDIR")
@@ -199,7 +199,7 @@ def parentdir(arg):
     directory, assuming it is relative to the parent recipe.
     """
     recdict = Global.globals
-    if not recdict.has_key("PARENTDIR"):
+    if "PARENTDIR" not in recdict:
         msg_error(recdict, _("Using parentdir() at the top level"))
         return ''
     return relativedir(arg, "PARENTDIR")
@@ -264,9 +264,9 @@ def srcitem2obj(recdict, name, attrdict = {}, sufname = "OBJSUF", auto = 1):
     variables.
     """
     node = getwork(recdict).find_node(name)
-    if attrdict.has_key("var_BDIR"):
+    if "var_BDIR" in attrdict:
         bdir = attrdict["var_BDIR"]
-    elif node and node.attributes.has_key("var_BDIR"):
+    elif node and "var_BDIR" in node.attributes:
         bdir = node.attributes["var_BDIR"]
     else:
         bdir = get_var_val_int(recdict, "BDIR")
@@ -284,7 +284,7 @@ def srcitem2obj(recdict, name, attrdict = {}, sufname = "OBJSUF", auto = 1):
 
     name = os.path.join(bdir, name)
 
-    if attrdict.has_key("suffix"):
+    if "suffix" in attrdict:
         # Use the suffix attribute if it exists.
         objsuf = attrdict["suffix"]
     elif sufname:
@@ -311,10 +311,10 @@ def srcitem2obj(recdict, name, attrdict = {}, sufname = "OBJSUF", auto = 1):
         else:
             l = [ sufname ]
         for sn in l:
-            if attrdict.has_key("var_" + sn):
+            if "var_" + sn in attrdict:
                 objsuf = attrdict["var_" + sn]
                 break
-            if node and node.attributes.has_key("var_" + sn):
+            if node and "var_" + sn in node.attributes:
                 objsuf = node.attributes["var_" + sn]
                 break
             objsuf = get_var_val_int(recdict, sn)
@@ -331,7 +331,7 @@ def srcitem2obj(recdict, name, attrdict = {}, sufname = "OBJSUF", auto = 1):
     else:
         n = name + objsuf
 
-    if attrdict.has_key("prefix"):
+    if "prefix" in attrdict:
         n = os.path.join(os.path.dirname(n),
                                       attrdict["prefix"] + os.path.basename(n))
     return n
@@ -399,7 +399,7 @@ def program_path(name, path = None, pathext = None, skip = None):
     # Decide on the list of directories to examine.
     if not path is None:
         envpath = path
-    elif os.environ.has_key('PATH'):
+    elif 'PATH' in os.environ:
         envpath = os.environ['PATH']
     else:
         envpath = os.defpath
@@ -656,6 +656,10 @@ def define_action(action, primary, commands, attr = {},
     Define an action.
     """
     from RecPos import RecPos
+    try:
+        from functools import reduce # Python 3.0
+    except:
+        pass
 
     # TODO: is there a way to put a line number in rpstack?
     recdict = Global.globals
@@ -849,7 +853,17 @@ def ask_prefix(name):
 
 
 # This must be here instead of inside get_html_images() for Python 1.5.
-import htmllib
+try:
+    import html # >= Python 3.0
+except ImportError: # Backward compatibility (< Python 3.0)
+    try:
+        import HTMLParser
+        class html:
+            parser = HTMLParser.HTMLParser
+    except ImportError: # More backward compatibility (< Python 2.2)
+        import htmllib
+        class html:
+            parser = htmllib.HTMLParser
 
 def get_html_images(files, add_dir = 1):
     """
@@ -857,9 +871,9 @@ def get_html_images(files, add_dir = 1):
     Only relative file names are supported, because a relative file name means
     the file can be found when testing locally.
     """
-    class ImgHTMLParser(htmllib.HTMLParser):
+    class ImgHTMLParser(html.parser):
         def __init__(self, formatter, verbose=0):
-            htmllib.HTMLParser.__init__(self, formatter, verbose)
+            html.parser.__init__(self, formatter, verbose)
             self.img_list = []      # list of images so far
         def set_dir(self, dir):
             self.img_dir = dir      # dir of image file
@@ -1070,7 +1084,7 @@ def _scan_c_file(recdict, fname, scanned, local, localpathlist, globalpathlist):
                                 if not fn:
                                     fn = search_target(getwork(recdict),
                                                                 pathlist, name)
-                                if fn and not scanned.has_key(fn):
+                                if fn and fn not in scanned:
                                     scanned[fn] = not local
 
     except IOError:
diff --git a/Remote.py b/Remote.py
index a856d8a..a6d3467 100644
--- a/Remote.py
+++ b/Remote.py
@@ -101,9 +101,9 @@ def get_header_date(headers):
     """Get the date from a MIME header.  Returns zero when not available."""
     from rfc822 import parsedate
 
-    if headers.has_key("Last-Modified"):
+    if "Last-Modified" in headers:
         return time.mktime(parsedate(headers["Last-Modified"]))
-    if headers.has_key("Date"):
+    if "Date" in headers:
         return time.mktime(parsedate(headers["Date"]))
     # When a file does exist but has no timestamp return 1, so that it's
     # different from a file that does not exist.
@@ -310,7 +310,7 @@ def download_file(recdict, url_dl, node, use_cache):
             return 0
         return 1
 
-    if url_dl.has_key("cache_update"):
+    if "cache_update" in url_dl:
         cu = url_dl["cache_update"]
     else:
         cu = None
diff --git a/Rule.py b/Rule.py
index bde0934..01e36ae 100644
--- a/Rule.py
+++ b/Rule.py
@@ -64,7 +64,7 @@ def _trymatch(rpstack, name, name_short, patlist):
         # If the pattern has the "virtual" attribute, use the short name
         # (if it's already known the name is a virtual item, "name" already is
         # the short name).
-        elif t.has_key("virtual") and t["virtual"]:
+        elif "virtual" in t and t["virtual"]:
             s = name_short
             str_len = len(name_short)
         else:
@@ -104,7 +104,7 @@ def _trymatch(rpstack, name, name_short, patlist):
             continue
 
         # TODO: use a regexp pattern to match with
-        if t.has_key("skip") and t["skip"] == name:
+        if "skip" in t and t["skip"] == name:
             continue
 
         # When matching with the tail, return the directory of the short name,
diff --git a/Scope.py b/Scope.py
index 2470235..42c6046 100644
--- a/Scope.py
+++ b/Scope.py
@@ -89,14 +89,14 @@ class NoScopeDict:
 
     def __getattr__(self, key):
         # 1: local scope
-        if self.data.has_key(key):
+        if key in self.data:
             return self.data[key]
 
         # Remember we read the variable from a non-local scope.
         # self.read_from_callstack[key] = 1
 
         # 2: _up scope (callstack)
-        if self.data.has_key("_up") and self.data["_up"].has_key(key):
+        if "_up" in self.data and key in self.data["_up"]:
             return self.data["_up"][key]
 
         # Generate an error as if reading from the local scope.
@@ -111,19 +111,19 @@ class NoScopeDict:
         self.data[key] = value
 
     def has_key(self, key):
-        return (self.data.has_key(key)
-               or (self.data.has_key("_up") and self.data["_up"].has_key(key)))
+        return (key in self.data
+               or ("_up" in self.data and key in self.data["_up"]))
 
     def get(self, key, f = None):
-        if self.data.has_key(key):
+        if key in self.data:
             return self.data[key]
-        if self.data.has_key("_up") and self.data["_up"].has_key(key):
+        if "_up" in self.data and key in self.data["_up"]:
             return self.data["_up"][key]
         return f
 
     def keys(self):
         l = self.data.keys()
-        if self.data.has_key("_up"):
+        if "_up" in self.data:
             l.extend(self.data["_up"].keys())
 
         # Remove duplicates: two scopes can hold the same variable but we will
@@ -147,7 +147,7 @@ class NoScopeDict:
 
     def __str__(self):
         s = str(self.data)
-        if self.data.has_key("_up"):
+        if "_up" in self.data:
             s = s + "; _up stack: " + str(self.data["_up"])
         return s
 
@@ -165,7 +165,7 @@ class NoScopeDict:
 
     def __contains__(self, key):
         return (self.data.__contains__(key)
-                or (self.data.has_key("_up")
+                or ("_up" in self.data
                     and self.data["_up"].__contains__(key)))
 
     def items(self):
@@ -209,20 +209,20 @@ class CallstackDict:
 
     def __getattr__(self, key):
         for d in self.stack:
-            if d.has_key(key):
+            if key in d:
                 return d[key]
         raise AttributeError, _("Variable not found in _up scope: %s") % str(key)
 
     def __setattr__(self, key, value):
         for d in self.stack:
-            if d.has_key(key):
+            if key in d:
                 d[key] = value
                 return
         raise AttributeError, _("Variable not found in _up scope: %s") % str(key)
 
     def __setitem__(self, key, value):
         for d in self.stack:
-            if d.has_key(key):
+            if key in d:
                 d[key] = value
                 return
         raise AttributeError, _("Variable not found in _up scope: %s") % str(key)
@@ -244,7 +244,7 @@ class CallstackDict:
 
     def has_key(self, key):
         for d in self.stack:
-            if d.has_key(key):
+            if key in d:
                 return 1
         return 0
 
@@ -256,7 +256,7 @@ class CallstackDict:
 
     def get(self, key, f = None):
         for d in self.stack:
-            if d.has_key(key):
+            if key in d:
                 return d[key]
         return f
 
@@ -361,16 +361,16 @@ def find_recdict(recdict, name):
     nord = recdict.get("_no")
     if not nord:
         # simple recdict, can't use scopes
-        if recdict.has_key(name):
+        if name in recdict:
             return recdict
         return None
 
     # use the _no scope
-    if nord.data.has_key(name):
+    if name in nord.data:
         return nord.data
-    if nord.data.has_key("_up"):
+    if "_up" in nord.data:
         for rd in nord.data["_up"].stack:
-            if rd.has_key(name):
+            if name in rd:
                 return rd
     return None
 
@@ -426,12 +426,12 @@ def get_build_recdict(recdict, buildrecdict, rpstack = None,
         else:
             # For a dependency the tree of the invoker is not used.
             new_recdict["_tree"] = buildrecdict["_tree"]
-        if buildrecdict.has_key("_parent"):
+        if "_parent" in buildrecdict:
             new_recdict["_parent"] = buildrecdict["_parent"]
         new_recdict["_rpstack"] = buildrecdict["_rpstack"]
 
         # Add the invoking scope to the "_stack" scope.
-        if recdict.has_key("_stack"):
+        if "_stack" in recdict:
             stack = [ recdict ] + recdict["_stack"].stack
             new_recdict["_caller"] = recdict
         else:
@@ -453,12 +453,12 @@ def get_build_recdict(recdict, buildrecdict, rpstack = None,
         new_recdict["_tree"] = CallstackDict([ new_recdict ]
                                                       + recdict["_tree"].stack)
         # The "_stack" scope doesn't change.
-        if recdict.has_key("_stack"):
+        if "_stack" in recdict:
             new_recdict["_stack"] = recdict["_stack"]
 
         # The "_up" scope is "_stack" plus "_tree" plus "_conf", but exclude
         # the recipe itself.
-        if recdict.has_key("_stack"):
+        if "_stack" in recdict:
             new_recdict["_up"] = CallstackDict(new_recdict["_stack"].stack
                                                + recdict["_tree"].stack
                                                + [ recdict["_conf"] ])
@@ -504,10 +504,10 @@ def check_user_scope(recdict, name):
     value as a dictionary and fail then.
     Return None if it is OK, an error message otherwise.
     """
-    if recdict.has_key("_up"):
+    if "_up" in recdict:
         for d in recdict["_up"].stack:
-            if d.has_key(name):
-                if d.has_key("recipe_name"):
+            if name in d:
+                if "recipe_name" in d:
                     if d["recipe_name"] == "toplevel":
                         where = "at the toplevel"
                     else:
@@ -535,7 +535,7 @@ def add_user_scope(recdict, name, dict):
 
     # Add the user scope to the callstack and recipe tree scopes, so that it is
     # available when leaving the current scope.
-    if recdict.has_key("_up"):
+    if "_up" in recdict:
         for d in recdict["_up"].stack:
             d[name] = dict
 
@@ -594,7 +594,7 @@ def rule_in_tree(rule_recdict, target_recdict):
         return 1            # that was easy!
 
     # Check the _tree scope for rules.
-    if target_recdict.has_key("_tree"):
+    if "_tree" in target_recdict:
         for rd in target_recdict["_tree"].stack:
             if rd["_recipe"] is rule_recdict["_recipe"]:
                 return 1
diff --git a/Sign.py b/Sign.py
index 378e236..501f835 100644
--- a/Sign.py
+++ b/Sign.py
@@ -76,7 +76,7 @@ def get_sign_file(recdict, target, update):
     """Get the sign file that is used for "target" if it wasn't done already.
        When "update" is non-zero, mark the file needs writing."""
     fname = fname_fold(target.get_sign_fname())
-    if not sign_files.has_key(fname):
+    if fname not in sign_files:
         sign_files[fname] = update
         sign_read(recdict, fname)
     elif update:
@@ -207,7 +207,7 @@ def sign_write(recdict, fname):
         # if it is available.
         for c in old.keys():
             if c != "signfile":
-                if new and new.has_key(c):
+                if new and c in new:
                     val = new[c]
                 else:
                     val = old[c]
@@ -217,7 +217,7 @@ def sign_write(recdict, fname):
         # value.
         if new:
             for c in new.keys():
-                if c != "signfile" and not old.has_key(c):
+                if c != "signfile" and c not in old:
                     f.write("%s=%s\033" % (sign_reduce_name(basedir, c),
                                                                        new[c]))
 
@@ -230,7 +230,7 @@ def sign_write(recdict, fname):
         # When the item is in upd_signatures, use the directory specified
         # there, otherwise use the directory of old_signatures.
         for s in old_signatures.keys():
-            if upd_signatures.has_key(s):
+            if s in upd_signatures:
                 if upd_signatures[s]["signfile"] != fname:
                     continue
                 new = upd_signatures[s]
@@ -244,7 +244,7 @@ def sign_write(recdict, fname):
         # Go over all updated signatures, write only the ones for which there
         # is no old signature.
         for s in upd_signatures.keys():
-            if (not old_signatures.has_key(s)
+            if (s not in old_signatures
                                    and upd_signatures[s]["signfile"] == fname):
                 write_sign_line(f, basedir, s, upd_signatures[s], None)
 
@@ -417,10 +417,10 @@ def _sign_lookup(signatures, name, key):
     Get the "key" signature for item "name" from dictionary "signatures".
     "name" must have gone through fname_fold().
     """
-    if not signatures.has_key(name):
+    if name not in signatures:
         return ''
     s = signatures[name]
-    if not s.has_key(key):
+    if key not in s:
         return ''
     return s[key]
 
@@ -447,8 +447,8 @@ def get_new_sign(recdict, name, check, force = 0):
     name = fname_fold(name)
     if (not force
             and skip_commands()
-            and new_signatures.has_key(name)
-            and new_signatures[name].has_key("cleared")):
+            and name in new_signatures
+            and "cleared" in new_signatures[name]):
         return "cleared"
 
     key = check
@@ -467,7 +467,7 @@ def get_new_sign(recdict, name, check, force = 0):
             res = "unknown"
 
         # Store the new signature to avoid recomputing it many times.
-        if not new_signatures.has_key(name):
+        if name not in new_signatures:
             new_signatures[name] = {}
         new_signatures[name][key] = res
 
@@ -478,9 +478,9 @@ def sign_clear_target(recdict, target):
        for "target".  sign_updated() should be called next for each source."""
     get_sign_file(recdict, target, 1)
     target_name = fname_fold(target.get_name())
-    if old_signatures.has_key(target_name):
+    if target_name in old_signatures:
         del old_signatures[target_name]
-    if upd_signatures.has_key(target_name):
+    if target_name in upd_signatures:
         del upd_signatures[target_name]
 
 
@@ -488,7 +488,7 @@ def sign_clear_file(fname, recursive):
     """Called to clear signatures for a file "fname".
        Used for ":changed" and "--changed=FILE"."""
     chd_signatures[full_fname(fname)] = recursive
-    if upd_signatures.has_key(fname):
+    if fname in upd_signatures:
         del upd_signatures[fname]
 
 
@@ -508,7 +508,7 @@ def _sign_upd_sign(recdict, target, key, value):
     """Update signature for node "target" with "key" to "value"."""
     get_sign_file(recdict, target, 1)
     target_name = fname_fold(target.get_name())
-    if not upd_signatures.has_key(target_name):
+    if target_name not in upd_signatures:
         upd_signatures[target_name] = {"signfile":
                                            fname_fold(target.get_sign_fname())}
     upd_signatures[target_name][key] = value
@@ -543,7 +543,7 @@ def get_old_sign(recdict, name, check, target, rootname = None):
        If it doesn't exist an empty string is returned."""
     # Check if this file was marked as changed.
     name = fname_fold(name)
-    if chd_signatures.has_key(name):
+    if name in chd_signatures:
         return "changed"
 
     # May need to read the sign file for this target.
@@ -568,8 +568,8 @@ def get_old_sign(recdict, name, check, target, rootname = None):
         for name in sigdict.keys():
             if (len(name) > rootname_len
                     and name[:rootname_len] == rootname
-                    and sigdict[name].has_key(key)
-                    and sigdict[name].has_key(timekey)
+                    and key in sigdict[name]
+                    and timekey in sigdict[name]
                     and float(sigdict[name][timekey]) > newtime):
                 ret = sigdict[name][key]
                 newtime = float(sigdict[name][timekey])
@@ -580,9 +580,9 @@ def get_old_sign(recdict, name, check, target, rootname = None):
 def check_name(recdict, name, itemdict, altdict = None):
     """Return the check name to be used for item "name" with dictlist
        "itemdict".  Also use "altdict" if given (attributes of the node)."""
-    if itemdict.has_key("check"):
+    if "check" in itemdict:
         check = itemdict["check"]
-    elif altdict and altdict.has_key("check"):
+    elif altdict and "check" in altdict:
         check = altdict["check"]
     else:
         # TODO: make mapping from name or filetype to check configurable
diff --git a/Util.py b/Util.py
index e7c8cde..2593719 100644
--- a/Util.py
+++ b/Util.py
@@ -31,7 +31,7 @@ def i18n_init():
 
     # If already done return quickly.
     import __builtin__
-    if __builtin__.__dict__.has_key("_"):
+    if "_" in __builtin__.__dict__:
         return
 
     # Set the locale to the users default.
@@ -333,7 +333,7 @@ def get_var_val_int(recdict, name):
     the "_up" scope.  Do not use the "_no" scope to avoid setting the flag
     that the variable was read before set.
     """
-    if recdict.has_key(name):
+    if name in recdict:
         return recdict[name]
     return get_var_val(0, recdict, "_up", name)
 
@@ -635,7 +635,7 @@ def shorten_dictlist(dictlist):
         new_item = {}
         for k in item.keys():
             if k == "name":
-                if item.has_key("_node") and k == "name":
+                if "_node" in item and k == "name":
                     new_item[k] = shorten_name(item["_node"].get_name(), adir)
                 else:
                     new_item[k] = shorten_name(item[k], adir)
@@ -1071,9 +1071,9 @@ def async_system(rpstack, recdict, cmd):
 
 def get_shell_name():
     """Get the name of the shell to use (either command.com or cmd.exe)."""
-    if os.environ.has_key("SHELL"):
+    if "SHELL" in os.environ:
         shell = os.environ["SHELL"]
-    elif os.environ.has_key("COMSPEC"):
+    elif "COMSPEC" in os.environ:
         shell = os.environ["COMSPEC"]
     else:
         from RecPython import program_path
@@ -1203,7 +1203,7 @@ compiled_re = {}
 
 def cre_match(regexp, text):
     """Call re.match while caching the compiled regexp."""
-    if compiled_re.has_key(regexp):
+    if regexp in compiled_re:
         cre = compiled_re[regexp]
     else:
         cre = re.compile(regexp)
@@ -1212,7 +1212,7 @@ def cre_match(regexp, text):
 
 def cre_search(regexp, text):
     """Call re.search while caching the compiled regexp."""
-    if compiled_re.has_key(regexp):
+    if regexp in compiled_re:
         cre = compiled_re[regexp]
     else:
         cre = re.compile(regexp)
diff --git a/VersCont.py b/VersCont.py
index 2a5eec9..71465ef 100644
--- a/VersCont.py
+++ b/VersCont.py
@@ -127,7 +127,7 @@ def handle_nodelist(rpstack, recdict, nodelist, use_cache, action, attrnames):
             # empty.
             nx_attr = ''
             for n in attrnames:
-                if node.attributes.has_key(n):
+                if n in node.attributes:
                     nx_attr = node.attributes[n]
                     if nx_attr:
                         attrname = n
@@ -233,9 +233,9 @@ def publish_nodelist(rpstack, recdict, nodelist, msg):
                           _('Published file does not exist: "%s"') % node_name)
             continue
 
-        if node.attributes.has_key("publish"):
+        if "publish" in node.attributes:
             s = node.attributes["publish"]
-        elif node.attributes.has_key("commit"):
+        elif "commit" in node.attributes:
             s = node.attributes["commit"]
         else:
             s = ''
@@ -341,7 +341,7 @@ def verscont_remove_add(rpstack, recdict, dir, recursive, action):
        "dir" is a dictionary for the directory and its attributes.
        Enter directories recursively when "recursive" is non-zero.
        """
-    if not dir.has_key("commit"):
+    if "commit" not in dir:
         recipe_error(rpstack, _("no commit attribute for %s") % dir["name"])
 
     from Dictlist import str2dictlist
@@ -377,7 +377,7 @@ def verscont_remove_add(rpstack, recdict, dir, recursive, action):
         # Remove: Loop over all items found in the VCS.
         for item in alist:
             node = work.find_node(item)
-            if not node or not node.attributes.has_key("commit"):
+            if not node or "commit" not in node.attributes:
                 if not node:
                     node = Node(item)
                 if skip_commands():
@@ -396,7 +396,7 @@ def verscont_remove_add(rpstack, recdict, dir, recursive, action):
         #  - the node does not appear in the list from the VCS
         dirname_len = len(dirname)
         for node in work.nodes.values():
-            if (node.attributes.has_key("commit")
+            if ("commit" in node.attributes
                     and len(node.absname) > dirname_len
                     and ((recursive
                             and node.absname[:dirname_len] == dirname
diff --git a/VersContCvs.py b/VersContCvs.py
index 1f47026..ea042a2 100644
--- a/VersContCvs.py
+++ b/VersContCvs.py
@@ -71,7 +71,7 @@ def cvs_command(recdict, server, url_dict, nodelist, action):
             thislist = []
             for node in todolist[:]:
                 # Use the specified "tag" attribute for tagging.
-                if not node.attributes.has_key("tag"):
+                if "tag" not in node.attributes:
                     msg_error(recdict, _('tag attribute missing for "%s"')
                                                            % node.short_name())
                     failed.extend(todolist)
@@ -186,7 +186,7 @@ def cvs_command_node(recdict, serverarg, url_dict, node, action):
     # Change to the directory where "path" + "node.name" is valid.
     if action == "checkout":
         cvspath = ''
-        if url_dict.has_key("path"):
+        if "path" in url_dict:
             # Use the specified "path" attribute.
             cvspath = url_dict["path"]
             dir_for_path = node.recipe_dir
@@ -238,9 +238,9 @@ def cvs_command_node(recdict, serverarg, url_dict, node, action):
 
     # Use the specified "logentry" attribute for a log message.
     # Only used for "commit" (also for add and remove).
-    if url_dict.has_key("logentry"):
+    if "logentry" in url_dict:
         logentry = url_dict["logentry"]
-    elif node.attributes.has_key("logentry"):
+    elif "logentry" in node.attributes:
         logentry = node.attributes["logentry"]
     else:
         logentry = get_var_val_int(recdict, "LOGENTRY")
diff --git a/Work.py b/Work.py
index 1349bb8..2bcb624 100644
--- a/Work.py
+++ b/Work.py
@@ -245,14 +245,14 @@ class Work:
         if absname:
             findname = absname
             for i in r:
-                if self.absnodes.has_key(findname):
+                if findname in self.absnodes:
                     return self.absnodes[findname]
                 if i:
                     findname = fname_fold(absname)
 
         for i in r:
             findname = name
-            if self.nodes.has_key(findname):
+            if findname in self.nodes:
                 n = self.nodes[findname]
                 if n.attributes.get("virtual"):
                     return n
@@ -264,7 +264,7 @@ class Work:
         if absname and use_alias:
             findname = absname
             for i in r:
-                if self.aliasnodes.has_key(findname):
+                if findname in self.aliasnodes:
                     return self.aliasnodes[findname]
                 if i:
                     findname = fname_fold(absname)
@@ -341,7 +341,7 @@ class Work:
             node = self.find_node(item["name"])
             if node:
                 for k in node.attributes.keys():
-                    if not item.has_key(k):
+                    if k not in item:
                         item[k] = node.attributes[k]
 
 
@@ -362,7 +362,7 @@ class Work:
         """
         for in_ftype in route.typelist[0]:
             for out_ftype in route.typelist[-1]:
-                if not self.routes.has_key(in_ftype):
+                if in_ftype not in self.routes:
                     self.routes[in_ftype] = {}
                 self.routes[in_ftype][out_ftype] = route
 
@@ -392,11 +392,11 @@ class Work:
             for d in self.dependencies:
                 for t in d.targetlist:
                     comment = ''
-                    if t.has_key("comment"):
+                    if "comment" in t:
                         comment = t["comment"]
                     else:
                         node = self.find_node(t["name"])
-                        if node and node.attributes.has_key("comment"):
+                        if node and "comment" in node.attributes:
                             comment = node.attributes["comment"]
                     n = t["name"]
                     if comment:
@@ -417,10 +417,10 @@ class Work:
 def assert_attribute(recdict, dict, attrname):
     """Check if dictlist "dict" has an entry for attribute "attrname".
        If not, obtain it from any node that has this attribute."""
-    if dict.has_key(attrname):
+    if attrname in dict:
         return
     for node in getwork(recdict).nodes.values():
-        if node.attributes.has_key(attrname):
+        if attrname in node.attributes:
             msg_extra(recdict, _('Using %s attribute from node "%s"')
                                                        % (attrname, node.name))
             dict[attrname] = node.attributes[attrname]
diff --git a/aap b/aap
index 5662037..9336f94 100755
--- a/aap
+++ b/aap
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/python2.6 -3
 # Part of the A-A-P recipe executive: The main program.
 
 # Copyright (C) 2002-2003 Stichting NLnet Labs
diff --git a/import_re.py b/import_re.py
index ff1f71e..f22e608 100644
--- a/import_re.py
+++ b/import_re.py
@@ -13,7 +13,7 @@
 
 # If already done return quickly.
 import __builtin__
-if not __builtin__.__dict__.has_key("re"):
+if  not "re" in __builtin__.__dict__:
 
     import sys
 
-- 
1.6.2.1


------------------------------------------------------------------------------