cloudmonkey CLI をpython3化してみる　−２

昨日はインストールまではできるようになったけど、起動できなかったので

$ cloudmonkey

```
Traceback (most recent call last):
  File "/Users/kentaro/porting/ven/bin/cloudmonkey", line 9, in <module>
    load_entry_point('cloudmonkey', 'console_scripts', 'cloudmonkey')()
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 542, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 2569, in load_entry_point
    return ep.load()
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 2229, in load
    return self.resolve()
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 2235, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/cloudmonkey.py", line 48
    except ImportError, e:
                      ^
SyntaxError: invalid syntax
```

エラーの出ているcloudmonkey.py　を変換

$ futurize --stage1 -w cloudmonkey/cloudmonkey.py

```
RefactoringTool: Skipping optional fixer: idioms
RefactoringTool: Skipping optional fixer: ws_comma
RefactoringTool: Refactored cloudmonkey/cloudmonkey.py
--- cloudmonkey/cloudmonkey.py 	(original)
+++ cloudmonkey/cloudmonkey.py 	(refactored)
@@ -17,6 +17,9 @@
 # specific language governing permissions and limitations
 # under the License.

+from __future__ import print_function
+from __future__ import absolute_import
+from functools import reduce
 try:
     import argcomplete
     import argparse
@@ -32,26 +35,26 @@
     import time
     import types

-    from cachemaker import loadcache, savecache, monkeycache, splitverbsubject
-    from config import __version__, __description__, __projecturl__
-    from config import display_types
-    from config import read_config, write_config, config_file, default_profile
+    from .cachemaker import loadcache, savecache, monkeycache, splitverbsubject
+    from .config import __version__, __description__, __projecturl__
+    from .config import display_types
+    from .config import read_config, write_config, config_file, default_profile
     from dicttoxml import dicttoxml
     from optparse import OptionParser
     from prettytable import PrettyTable
-    from printer import monkeyprint
-    from requester import monkeyrequest
-    from requester import login
-    from requester import logout
+    from .printer import monkeyprint
+    from .requester import monkeyrequest
+    from .requester import login
+    from .requester import logout
     from urlparse import urlparse
     from xml.dom.minidom import parseString
-except ImportError, e:
+except ImportError as e:
     print("Import error in %s : %s" % (__name__, e))
     import sys
     sys.exit()

 try:
-    from precache import apicache
+    from .precache import apicache
 except ImportError:
     apicache = {'count': 0, 'verbs': [], 'asyncapis': []}

@@ -63,8 +66,8 @@
     os.environ['TERM'] = 'vt100'
 try:
     import readline
-except ImportError, e:
-    print("Module readline not found, autocompletions will fail", e)
+except ImportError as e:
+    print(("Module readline not found, autocompletions will fail", e))
 else:
     import rlcompleter
     readline_doc = getattr(readline, '__doc__', '')
@@ -114,7 +117,7 @@
         try:
             if os.path.exists(self.history_file):
                 readline.read_history_file(self.history_file)
-        except IOError, e:
+        except IOError as e:
             logger.debug(u"Error: Unable to read history. " + unicode(e))
         atexit.register(readline.write_history_file, self.history_file)

@@ -148,7 +151,7 @@
     def cmdloop(self, intro=None):
         self.interpreterMode = True
         print(self.intro)
-        print "Using management server profile:", self.profile, "\n"
+        print("Using management server profile:", self.profile, "\n")
         while True:
             try:
                 super(CloudMonkeyShell, self).cmdloop(intro="")
@@ -197,7 +200,7 @@
                         args_partition = args.partition(" ")
                         cmd = self.apicache[verb][args_partition[0]]['name']
                         args = args_partition[2]
-                    except KeyError, e:
+                    except KeyError as e:
                         if default_handler:
                             default_handler(args)
                         else:
@@ -216,12 +219,12 @@
         output = u""
         try:
             for arg in args:
-                if isinstance(type(arg), types.NoneType) or not arg:
+                if isinstance(type(arg), type(None)) or not arg:
                     continue
                 if not (isinstance(arg, str) or isinstance(arg, unicode)):
                     arg = unicode(arg)
                 output += arg
-        except Exception, e:
+        except Exception as e:
             print(str(e))

         output = output.encode("utf-8")
@@ -232,7 +235,7 @@
                 sys.stderr.write(output + "\n")
                 sys.stderr.flush()
             else:
-                print output
+                print(output)

     def print_result(self, result, result_filter=[]):
         if not result or len(result) == 0:
@@ -297,7 +300,7 @@
                 if isinstance(result[0], dict):
                     keys = result[0].keys()
                     writer = csv.DictWriter(sys.stdout, keys)
-                    print ','.join(keys)
+                    print(','.join(keys))
                     for item in result:
                         row = {}
                         for k in keys:
@@ -312,7 +315,7 @@
             elif isinstance(result, dict):
                 keys = result.keys()
                 writer = csv.DictWriter(sys.stdout, keys)
-                print ','.join(keys)
+                print(','.join(keys))
                 writer.writerow(result)

         def print_result_tabular(result):
@@ -428,7 +431,7 @@
         try:
             args = args.strip()
             args.decode("utf-8")
-        except UnicodeError, ignore:
+        except UnicodeError as ignore:
             args = args.encode("utf-8")

         if self.pipe_runner(args):
@@ -444,12 +447,12 @@
         args = []
         while True:
             try:
-                next_val = lexp.next()
+                next_val = next(lexp)
                 if not next_val:
                     break
                 next_val = next_val.decode("utf-8")
                 args.append(next_val.replace(u'\x00', u''))
-            except ValueError, err:
+            except ValueError as err:
                 self.monkeyprint("Command parsing error: ", err)
                 return

@@ -600,14 +603,14 @@
                             return
                         uuids = self.update_param_cache(api, response)
                     if len(uuids) > 1:
-                        print
+                        print()
                         options = sorted(self.param_cache[api]["options"],
                                          key=lambda x: x[1])
                         for option in options:
                             uuid = option[0]
                             name = option[1]
                             if uuid.startswith(value):
-                                print uuid, name
+                                print(uuid, name)
                     autocompletions = map(lambda x: x + " ", uuids)
                     search_string = value

@@ -662,7 +665,7 @@
         allowed_blank_keys = ["username", "password", "apikey", "secretkey",
                               "domain"]
         if key not in allowed_blank_keys and not value:
-            print "Blank value of %s is not allowed" % key
+            print("Blank value of %s is not allowed" % key)
             return

         self.prompt = self.get_prompt()
@@ -671,19 +674,19 @@
             key = 'url'
             self.url = "%s://%s:%s%s" % (self.protocol, self.host,
                                          self.port, self.path)
-            print "This option has been deprecated, please set 'url' instead"
-            print "This server url will be used:", self.url
+            print("This option has been deprecated, please set 'url' instead")
+            print("This server url will be used:", self.url)
         write_config(self.get_attr, self.config_file)
         read_config(self.get_attr, self.set_attr, self.config_file)
         self.init_credential_store()
         if key.strip() == 'profile' and self.interpreterMode:
-            print "\nLoaded server profile '%s' with options:" % value
+            print("\nLoaded server profile '%s' with options:" % value)
             for option in default_profile.keys():
                 value = self.get_attr(option)
                 if option in ["password", "apikey", "secretkey"] and value:
                     value = value[:2] + "XXX" + value[4:6] + "YYY...(hidden)"
-                print "    %s = %s" % (option, value)
-            print
+                print("    %s = %s" % (option, value))
+            print()

     def complete_set(self, text, line, begidx, endidx):
         mline = line.partition(" ")[2].lstrip().partition(" ")
@@ -714,7 +717,7 @@
             session, sessionkey = login(self.url, self.username, self.password)
             self.credentials['session'] = session
             self.credentials['sessionkey'] = sessionkey
-        except Exception, e:
+        except Exception as e:
             self.monkeyprint("Error: Login failed to the server: ", unicode(e))

     def do_logout(self, args):
@@ -723,7 +726,7 @@
         """
         try:
             logout(self.url, self.credentials.get('session'))
-        except Exception, e:
+        except Exception as e:
             pass
         self.credentials['session'] = None
         self.credentials['sessionkey'] = None
@@ -775,7 +778,7 @@
                 startIdx = 1
         elif historyArg == "clear" or historyArg == "c":
             readline.clear_history()
-            print "CloudMonkey history cleared"
+            print("CloudMonkey history cleared")
             return
         elif len(historyArg) > 1 and historyArg[0] == "!" and historyArg[1:].isdigit():
             command = readline.get_history_item(long(historyArg[1:]))
RefactoringTool: Files that were modified:
RefactoringTool: cloudmonkey/cloudmonkey.py
```

すごい量だなぁ

$ futurize --stage2 -w cloudmonkey/cloudmonkey.py

```
RefactoringTool: Refactored cloudmonkey/cloudmonkey.py
--- cloudmonkey/cloudmonkey.py 	(original)
+++ cloudmonkey/cloudmonkey.py 	(refactored)
@@ -19,6 +19,13 @@

 from __future__ import print_function
 from __future__ import absolute_import
+from future import standard_library
+standard_library.install_aliases()
+from builtins import map
+from builtins import next
+from builtins import filter
+from builtins import str
+from builtins import range
 from functools import reduce
 try:
     import argcomplete
@@ -46,7 +53,7 @@
     from .requester import monkeyrequest
     from .requester import login
     from .requester import logout
-    from urlparse import urlparse
+    from urllib.parse import urlparse
     from xml.dom.minidom import parseString
 except ImportError as e:
     print("Import error in %s : %s" % (__name__, e))
@@ -109,16 +116,15 @@
         self.init_credential_store()
         logging.basicConfig(filename=self.log_file,
                             level=logging.DEBUG, format=log_fmt)
-        logger.debug("Loaded config fields:\n%s" % map(lambda x: "%s=%s" %
-                                                       (x, getattr(self, x)),
-                                                       self.config_options))
+        logger.debug("Loaded config fields:\n%s" % ["%s=%s" %
+                                                       (x, getattr(self, x)) for x in self.config_options])
         cmd.Cmd.__init__(self)

         try:
             if os.path.exists(self.history_file):
                 readline.read_history_file(self.history_file)
         except IOError as e:
-            logger.debug(u"Error: Unable to read history. " + unicode(e))
+            logger.debug(u"Error: Unable to read history. " + str(e))
         atexit.register(readline.write_history_file, self.history_file)

     def init_credential_store(self):
@@ -221,8 +227,8 @@
             for arg in args:
                 if isinstance(type(arg), type(None)) or not arg:
                     continue
-                if not (isinstance(arg, str) or isinstance(arg, unicode)):
-                    arg = unicode(arg)
+                if not (isinstance(arg, str) or isinstance(arg, str)):
+                    arg = str(arg)
                 output += arg
         except Exception as e:
             print(str(e))
@@ -249,7 +255,7 @@
             if result_filter:
                 for res in result_filter:
                     tfilter[res] = 1
-                for okey, oval in result.iteritems():
+                for okey, oval in result.items():
                     if isinstance(oval, dict):
                         for tkey in oval:
                             if tkey not in tfilter:
@@ -289,8 +295,8 @@
             if "count" in result:
                 result.pop("count")

-            if len(result.keys()) == 1:
-                item = result[result.keys()[0]]
+            if len(list(result.keys())) == 1:
+                item = result[list(result.keys())[0]]
                 if isinstance(item, list):
                     result = item
                 elif isinstance(item, dict):
@@ -298,7 +304,7 @@

             if isinstance(result, list) and len(result) > 0:
                 if isinstance(result[0], dict):
-                    keys = result[0].keys()
+                    keys = list(result[0].keys())
                     writer = csv.DictWriter(sys.stdout, keys)
                     print(','.join(keys))
                     for item in result:
@@ -307,13 +313,13 @@
                             if k not in item:
                                 row[k] = None
                             else:
-                                if type(item[k]) is unicode:
+                                if type(item[k]) is str:
                                     row[k] = item[k].encode('utf8')
                                 else:
                                     row[k] = item[k]
                         writer.writerow(row)
             elif isinstance(result, dict):
-                keys = result.keys()
+                keys = list(result.keys())
                 writer = csv.DictWriter(sys.stdout, keys)
                 print(','.join(keys))
                 writer.writerow(result)
@@ -327,8 +333,7 @@
             toprow = []
             if not result:
                 return
-            toprow = set(reduce(lambda x, y: x + y, map(lambda x: x.keys(),
-                         filter(lambda x: isinstance(x, dict), result))))
+            toprow = set(reduce(lambda x, y: x + y, [list(x.keys()) for x in [x for x in result if isinstance(x, dict)]]))
             printer = print_table(printer, toprow)
             for node in result:
                 if not node:
@@ -336,13 +341,13 @@
                 for key in toprow:
                     if key not in node:
                         node[key] = ''
-                row = map(lambda x: node[x], toprow)
+                row = [node[x] for x in toprow]
                 if printer and row:
                     printer.add_row(row)
             print_table(printer, toprow)

         def print_result_as_dict(result):
-            for key in sorted(result.keys(), key=lambda x:
+            for key in sorted(list(result.keys()), key=lambda x:
                               x not in ['id', 'count', 'name'] and x):
                 if isinstance(result[key], list):
                     self.monkeyprint(key + ":")
@@ -351,7 +356,7 @@
                     self.monkeyprint(key + ":")
                     print_result_as_dict(result[key])
                 else:
-                    value = unicode(result[key])
+                    value = str(result[key])
                     self.monkeyprint(key, " = ", value)

         def print_result_as_list(result):
@@ -404,20 +409,20 @@
         if not api:
             return
         logger.debug("Updating param cache for %s API" % api)
-        responsekey = filter(lambda x: 'response' in x, result.keys())[0]
+        responsekey = filter(lambda x: 'response' in x, list(result.keys()))[0]
         result = result[responsekey]
         options = []
         uuids = []
-        for key in result.keys():
+        for key in list(result.keys()):
             if isinstance(result[key], list):
                 for element in result[key]:
-                    if 'id' in element.keys():
-                        uuid = unicode(element['id'])
+                    if 'id' in list(element.keys()):
+                        uuid = str(element['id'])
                         name = ""
                         keyspace = ["name", "displayname",
                                     "username", "description"]
                         for name_key in keyspace:
-                            if name_key in element.keys():
+                            if name_key in list(element.keys()):
                                 name = element[name_key]
                                 break
                         options.append((uuid, name,))
@@ -462,15 +467,13 @@

         field_filter = []
         if 'filter' in args_dict:
-            field_filter = filter(lambda x: x.strip() != '',
-                                  args_dict.pop('filter').split(','))
+            field_filter = [x for x in args_dict.pop('filter').split(',') if x.strip() != '']
             field_filter = list(set(field_filter))

         missing = []
         if verb in self.apicache and subject in self.apicache[verb]:
-            missing = filter(lambda x: x not in [key.split('[')[0].lower()
-                                                 for key in args_dict],
-                             self.apicache[verb][subject]['requiredparams'])
+            missing = [x for x in self.apicache[verb][subject]['requiredparams'] if x not in [key.split('[')[0].lower()
+                                                 for key in args_dict]]

         if len(missing) > 0:
             self.monkeyprint("Missing arguments: ", ' '.join(missing))
@@ -484,13 +487,13 @@
         result = self.make_request(apiname, args_dict, isasync)

         if not result or not isinstance(result, dict):
-            if isinstance(result, unicode):
+            if isinstance(result, str):
                 result = result.decode("utf-8")
             logger.debug("Invalid command result: %s" % result)
             return

         try:
-            responsekeys = filter(lambda x: 'response' in x, result.keys())
+            responsekeys = [x for x in list(result.keys()) if 'response' in x]
             for responsekey in responsekeys:
                 self.print_result(result[responsekey], field_filter)
             if apiname.startswith("list") and "id" not in args_dict:
@@ -513,13 +516,10 @@
         search_string = ""

         if separator != " ":   # Complete verb subjects
-            autocompletions = map(lambda x: x + " ",
-                                  self.apicache[verb].keys())
+            autocompletions = [x + " " for x in list(self.apicache[verb].keys())]
             search_string = subject
         else:                  # Complete subject params
-            autocompletions = map(lambda x: x + "=",
-                                  map(lambda x: x['name'],
-                                      self.apicache[verb][subject]['params']))
+            autocompletions = [x + "=" for x in [x['name'] for x in self.apicache[verb][subject]['params']]]
             search_string = text
             if self.paramcompletion == 'true':
                 param = line[:endidx].split(" ")[-1]
@@ -528,25 +528,19 @@
                 param = param[:idx]
                 if param == "filter":
                     response_params = self.apicache[verb][subject]["response"]
-                    used = filter(lambda x: x.strip() != "",
-                                  value.split(",")[:-1])
-                    unused = map(lambda x: x['name'] + ",", filter(lambda x:
-                                 "name" in x and x["name"] not in used,
-                                 response_params))
+                    used = [x for x in value.split(",")[:-1] if x.strip() != ""]
+                    unused = [x['name'] + "," for x in [x for x in response_params if "name" in x and x["name"] not in used]]
                     last_value = value.split(",")[-1]
                     if last_value:
-                        unused = filter(lambda x: x.startswith(last_value),
-                                        unused)
+                        unused = [x for x in unused if x.startswith(last_value)]
                     suffix = ",".join(used)
                     if suffix:
                         suffix += ","
                     global normal_readline
                     if normal_readline:
-                        return filter(lambda x: x.startswith(last_value),
-                                      map(lambda x: x, unused))
+                        return [x for x in [x for x in unused] if x.startswith(last_value)]
                     else:  # OSX fix
-                        return filter(lambda x: x.startswith(value),
-                                      map(lambda x: suffix + x, unused))
+                        return [x for x in [suffix + x for x in unused] if x.startswith(value)]
                 elif len(value) < 36 and idx != -1:
                     api = None
                     logger.debug("[Paramcompl] For %s %s %s=" % (verb, subject,
@@ -574,10 +568,9 @@
                         params = self.apicache[verb][subject]['params']
                         arg = filter(lambda x: x['name'] == param, params)[0]
                         if "type" in arg and arg["type"] == "boolean":
-                            return filter(lambda x: x.startswith(value),
-                                          ["true ", "false "])
+                            return [x for x in ["true ", "false "] if x.startswith(value)]
                         related = arg['related']
-                        apis = filter(lambda x: 'list' in x, related)
+                        apis = [x for x in related if 'list' in x]
                         logger.debug("[Paramcompl] Related APIs: %s" % apis)
                         if len(apis) > 0:
                             api = apis[0]
@@ -589,7 +582,7 @@
                     uuids = []
                     cache_burst_ts = int(time.time()) - 900
                     logger.debug("Trying paramcompletion using API: %s" % api)
-                    if api in self.param_cache.keys() and \
+                    if api in list(self.param_cache.keys()) and \
                         len(self.param_cache[api]["options"]) > 0 and \
                             self.param_cache[api]["ts"] > cache_burst_ts:
                         for option in self.param_cache[api]["options"]:
@@ -611,7 +604,7 @@
                             name = option[1]
                             if uuid.startswith(value):
                                 print(uuid, name)
-                    autocompletions = map(lambda x: x + " ", uuids)
+                    autocompletions = [x + " " for x in uuids]
                     search_string = value

         if subject != "" and line.split(" ")[-1].find('=') == -1:
@@ -681,7 +674,7 @@
         self.init_credential_store()
         if key.strip() == 'profile' and self.interpreterMode:
             print("\nLoaded server profile '%s' with options:" % value)
-            for option in default_profile.keys():
+            for option in list(default_profile.keys()):
                 value = self.get_attr(option)
                 if option in ["password", "apikey", "secretkey"] and value:
                     value = value[:2] + "XXX" + value[4:6] + "YYY...(hidden)"
@@ -718,7 +711,7 @@
             self.credentials['session'] = session
             self.credentials['sessionkey'] = sessionkey
         except Exception as e:
-            self.monkeyprint("Error: Login failed to the server: ", unicode(e))
+            self.monkeyprint("Error: Login failed to the server: ", str(e))

     def do_logout(self, args):
         """
@@ -773,7 +766,7 @@
         numLen = len(str(endIdx))
         historyArg = args.split(' ')[0]
         if historyArg.isdigit():
-            startIdx = endIdx - long(historyArg)
+            startIdx = endIdx - int(historyArg)
             if startIdx < 1:
                 startIdx = 1
         elif historyArg == "clear" or historyArg == "c":
@@ -781,11 +774,11 @@
             print("CloudMonkey history cleared")
             return
         elif len(historyArg) > 1 and historyArg[0] == "!" and historyArg[1:].isdigit():
-            command = readline.get_history_item(long(historyArg[1:]))
+            command = readline.get_history_item(int(historyArg[1:]))
             readline.set_startup_hook(lambda: readline.insert_text(command))
             self.hook_count = 1
             return
-        for idx in xrange(startIdx, endIdx):
+        for idx in range(startIdx, endIdx):
             self.monkeyprint("%s %s" % (str(idx).rjust(numLen),
                                         readline.get_history_item(idx)))

RefactoringTool: Files that were modified:
RefactoringTool: cloudmonkey/cloudmonkey.py
```

$ cloudmonkey

```
Traceback (most recent call last):
  File "/Users/kentaro/porting/ven/bin/cloudmonkey", line 9, in <module>
    load_entry_point('cloudmonkey', 'console_scripts', 'cloudmonkey')()
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 542, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 2569, in load_entry_point
    return ep.load()
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 2229, in load
    return self.resolve()
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 2235, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/cloudmonkey.py", line 45, in <module>
    from .cachemaker import loadcache, savecache, monkeycache, splitverbsubject
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/cachemaker.py", line 25
    except ImportError, e:
                      ^
SyntaxError: invalid syntax
```

今度はcachemaker.py

$ futurize --stage1 -w cloudmonkey/cachemaker.py

```
RefactoringTool: Skipping optional fixer: idioms
RefactoringTool: Skipping optional fixer: ws_comma
RefactoringTool: Refactored cloudmonkey/cachemaker.py
--- cloudmonkey/cachemaker.py  	(original)
+++ cloudmonkey/cachemaker.py  	(refactored)
@@ -16,15 +16,17 @@
 # specific language governing permissions and limitations
 # under the License.

+from __future__ import print_function
+from __future__ import absolute_import
 try:
     import json
     import os
     import types

-    from config import config_fields
-except ImportError, e:
+    from .config import config_fields
+except ImportError as e:
     import sys
-    print "ImportError", e
+    print("ImportError", e)
     sys.exit(1)


@@ -73,8 +75,8 @@
     f.close()
     try:
         apicache = json.loads(data)
-    except ValueError, e:
-        print "Error processing json:", json_file, e
+    except ValueError as e:
+        print("Error processing json:", json_file, e)
         return {}
     return apicache

@@ -83,16 +85,16 @@
     """
     Feed this a dictionary of api bananas, it spits out processed cache
     """
-    if isinstance(type(apis), types.NoneType) or apis is None:
+    if isinstance(type(apis), type(None)) or apis is None:
         return {}

     responsekey = filter(lambda x: 'response' in x, apis.keys())

     if len(responsekey) == 0:
-        print "[monkeycache] Invalid dictionary, has no response"
+        print("[monkeycache] Invalid dictionary, has no response")
         return None
     if len(responsekey) != 1:
-        print "[monkeycache] Multiple responsekeys, chosing first one"
+        print("[monkeycache] Multiple responsekeys, chosing first one")

     responsekey = responsekey[0]
     verbs = set()
@@ -102,7 +104,7 @@

     apilist = getvalue(apis[responsekey], 'api')
     if apilist is None:
-        print "[monkeycache] Server response issue, no apis found"
+        print("[monkeycache] Server response issue, no apis found")

     for api in apilist:
         name = getvalue(api, 'name')
@@ -174,9 +176,9 @@

 if __name__ == "__main__":
     cache_file = config_fields['core']['cache_file']
-    print "[cachemaker] Pre-caching using user's cloudmonkey cache", cache_file
+    print("[cachemaker] Pre-caching using user's cloudmonkey cache", cache_file)
     if os.path.exists(cache_file):
         main(cache_file)
     else:
-        print "[cachemaker] Unable to cache apis, file not found", cache_file
-        print "[cachemaker] Run cloudmonkey sync to generate cache"
+        print("[cachemaker] Unable to cache apis, file not found", cache_file)
+        print("[cachemaker] Run cloudmonkey sync to generate cache")
RefactoringTool: Files that were modified:
RefactoringTool: cloudmonkey/cachemaker.py
```

$ futurize --stage2 -w cloudmonkey/cachemaker.py

```
RefactoringTool: Refactored cloudmonkey/cachemaker.py
--- cloudmonkey/cachemaker.py  	(original)
+++ cloudmonkey/cachemaker.py  	(refactored)
@@ -39,7 +39,7 @@

 def splitcsvstring(string):
     if string is not None:
-        return filter(lambda x: x.strip() != '', string.split(','))
+        return [x for x in string.split(',') if x.strip() != '']
     else:
         return []

@@ -88,7 +88,7 @@
     if isinstance(type(apis), type(None)) or apis is None:
         return {}

-    responsekey = filter(lambda x: 'response' in x, apis.keys())
+    responsekey = [x for x in list(apis.keys()) if 'response' in x]

     if len(responsekey) == 0:
         print("[monkeycache] Invalid dictionary, has no response")
RefactoringTool: Files that were modified:
RefactoringTool: cloudmonkey/cachemaker.py
```

$ cloudmonkey

```
Traceback (most recent call last):
  File "/Users/kentaro/porting/ven/bin/cloudmonkey", line 9, in <module>
    load_entry_point('cloudmonkey', 'console_scripts', 'cloudmonkey')()
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 542, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 2569, in load_entry_point
    return ep.load()
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 2229, in load
    return self.resolve()
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 2235, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/cloudmonkey.py", line 52, in <module>
    from .printer import monkeyprint
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/printer.py", line 27
    except ImportError, e:
                      ^
SyntaxError: invalid syntax
```

$ futurize --stage1 -w cloudmonkey/printer.py

```
RefactoringTool: Skipping optional fixer: idioms
RefactoringTool: Skipping optional fixer: ws_comma
RefactoringTool: Refactored cloudmonkey/printer.py
--- cloudmonkey/printer.py     	(original)
+++ cloudmonkey/printer.py     	(refactored)
@@ -16,6 +16,7 @@
 # specific language governing permissions and limitations
 # under the License.

+from __future__ import print_function
 try:
     from pygments import highlight
     from pygments.console import ansiformat
@@ -24,8 +25,8 @@
     from pygments.token import *

     import sys
-except ImportError, e:
-    print e
+except ImportError as e:
+    print(e)


 MONKEY_COLORS = {
RefactoringTool: Files that were modified:
RefactoringTool: cloudmonkey/printer.py

```

$ futurize --stage2 -w cloudmonkey/printer.py

```
RefactoringTool: No files need to be modified.
```

$ cloudmonkey

```
Traceback (most recent call last):
  File "/Users/kentaro/porting/ven/bin/cloudmonkey", line 9, in <module>
    load_entry_point('cloudmonkey', 'console_scripts', 'cloudmonkey')()
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 542, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 2569, in load_entry_point
    return ep.load()
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 2229, in load
    return self.resolve()
  File "/Users/kentaro/porting/ven/lib/python3.5/site-packages/pkg_resources/__init__.py", line 2235, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/cloudmonkey.py", line 53, in <module>
    from .requester import monkeyrequest
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/requester.py", line 36
    except ImportError, e:
                      ^
SyntaxError: invalid syntax
```

$ futurize --stage1 -w cloudmonkey/requester.py

```
RefactoringTool: Skipping optional fixer: idioms
RefactoringTool: Skipping optional fixer: ws_comma
RefactoringTool: Refactored cloudmonkey/requester.py
--- cloudmonkey/requester.py   	(original)
+++ cloudmonkey/requester.py   	(refactored)
@@ -17,6 +17,7 @@
 # specific language governing permissions and limitations
 # under the License.

+from __future__ import print_function
 try:
     import base64
     import hashlib
@@ -33,8 +34,8 @@
     from datetime import datetime, timedelta
     from requests_toolbelt import SSLAdapter
     from urllib2 import HTTPError, URLError
-except ImportError, e:
-    print "Import error in %s : %s" % (__name__, e)
+except ImportError as e:
+    print("Import error in %s : %s" % (__name__, e))
     import sys
     sys.exit()

@@ -74,7 +75,7 @@

     try:
         resp = session.post(url, params=args, verify=verifysslcert)
-    except requests.exceptions.ConnectionError, e:
+    except requests.exceptions.ConnectionError as e:
         writeError("Connection refused by server: %s" % e)
         return None, None

@@ -197,7 +198,7 @@
         try:
             return make_request_with_password(command, args, logger, url,
                                               credentials, verifysslcert)
-        except (requests.exceptions.ConnectionError, Exception), e:
+        except (requests.exceptions.ConnectionError, Exception) as e:
             return None, e

     def sign_request(params, secret_key):
@@ -231,9 +232,9 @@
         elif response.status_code != 200 and response.status_code != 401:
             error = "{0}: {1}".format(response.status_code,
                                       response.headers.get('X-Description'))
-    except requests.exceptions.ConnectionError, e:
+    except requests.exceptions.ConnectionError as e:
         return None, "Connection refused by server: %s" % e
-    except Exception, pokemon:
+    except Exception as pokemon:
         error = pokemon.message

     logger_debug(logger, "Response received: %s" % result)
@@ -263,7 +264,7 @@
     def process_json(response):
         try:
             response = json.loads(response, "utf-8")
-        except ValueError, e:
+        except ValueError as e:
             logger_debug(logger, "Error processing json: %s" % e)
             writeError("Error processing json: %s" % e)
             response = None
@@ -292,7 +293,7 @@
         while timeout > 0:
             interval = 2
             while interval > 0:
-                sys.stdout.write(u"%s\r" % cursor.next())
+                sys.stdout.write(u"%s\r" % next(cursor))
                 sys.stdout.flush()
                 time.sleep(0.1)
                 interval -= 0.1
RefactoringTool: Files that were modified:
RefactoringTool: cloudmonkey/requester.py
```

$ futurize --stage2 -w cloudmonkey/requester.py

```
RefactoringTool: Refactored cloudmonkey/requester.py
--- cloudmonkey/requester.py   	(original)
+++ cloudmonkey/requester.py   	(refactored)
@@ -18,6 +18,12 @@
 # under the License.

 from __future__ import print_function
+from future import standard_library
+standard_library.install_aliases()
+from builtins import filter
+from builtins import zip
+from builtins import next
+from builtins import str
 try:
     import base64
     import hashlib
@@ -28,12 +34,12 @@
     import ssl
     import sys
     import time
-    import urllib
-    import urllib2
+    import urllib.request, urllib.parse, urllib.error
+    import urllib.request, urllib.error, urllib.parse

     from datetime import datetime, timedelta
     from requests_toolbelt import SSLAdapter
-    from urllib2 import HTTPError, URLError
+    from urllib.error import HTTPError, URLError
 except ImportError as e:
     print("Import error in %s : %s" % (__name__, e))
     import sys
@@ -183,9 +189,9 @@
         expirationtime = datetime.utcnow() + timedelta(seconds=int(expires))
         args["expires"] = expirationtime.strftime('%Y-%m-%dT%H:%M:%S+0000')

-    for key in args.keys():
+    for key in list(args.keys()):
         value = args[key]
-        if isinstance(value, unicode):
+        if isinstance(value, str):
             value = value.encode("utf-8")
         args[key] = value
         if not key:
@@ -202,12 +208,12 @@
             return None, e

     def sign_request(params, secret_key):
-        request = zip(params.keys(), params.values())
+        request = list(zip(list(params.keys()), list(params.values())))
         request.sort(key=lambda x: x[0].lower())
         hash_str = "&".join(
             ["=".join(
                 [r[0].lower(),
-                 urllib.quote_plus(str(r[1]), safe="*").lower()
+                 urllib.parse.quote_plus(str(r[1]), safe="*").lower()
                  .replace("+", "%20").replace("%3A", ":")]
             ) for r in request]
         )
@@ -275,12 +281,12 @@
     if not response or not isinstance(response, dict):
         return response, error

-    m = list(v for v in response.keys() if 'response' in v.lower())
+    m = list(v for v in list(response.keys()) if 'response' in v.lower())
     if not m:
         return response, 'Invalid response received: %s' % response

     isasync = isasync and (asyncblock == "true" or asyncblock == "True")
-    responsekey = filter(lambda x: 'response' in x, response.keys())[0]
+    responsekey = filter(lambda x: 'response' in x, list(response.keys()))[0]

     if isasync and 'jobid' in response[responsekey]:
         jobid = response[responsekey]['jobid']
@@ -306,7 +312,7 @@
                 return response, error

             response = process_json(response)
-            responsekeys = filter(lambda x: 'response' in x, response.keys())
+            responsekeys = [x for x in list(response.keys()) if 'response' in x]

             if len(responsekeys) < 1:
                 continue
RefactoringTool: Files that were modified:
RefactoringTool: cloudmonkey/requester.py
```


$ cloudmonkey

```
☁ Apache CloudStack 🐵 cloudmonkey 5.3.3. Type help or ? to list commands.

Using management server profile: local

(local) 🐵 >
```

オオオオオオーー
ヤッタァー

起動したぁ

```
(local) 🐵 >?

Documented commands (type help <topic>):
========================================
EOF        change     disable       history  prepare    reset    start
activate   clean      disassociate  import   query      resize   stop
add        configure  enable        issue    quit       restart  suspend
api        copy       exit          ldap     reboot     restore  sync
archive    create     expunge       list     reconnect  revert   update
assign     dedicate   extract       lock     recover    revoke   upgrade
associate  delete     find          login    register   saml     upload
attach     deploy     generate      logout   release    scale
authorize  destroy    get           mark     remove     set
cancel     detach     help          migrate  replace    shell
```

helpも出力されるみたい　♪

でも設定してみるとエラーで終了

```
(local) 🐵 > set url https://comp-api.jp-e1.cloudn-service.com/client/api
(local) 🐵 > exit
Traceback (most recent call last):
  File "/Users/kentaro/porting/ven/bin/cloudmonkey", line 9, in <module>
    load_entry_point('cloudmonkey', 'console_scripts', 'cloudmonkey')()
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/cloudmonkey.py", line 920, in main
    shell.cmdloop()
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/cloudmonkey.py", line 163, in cmdloop
    super(CloudMonkeyShell, self).cmdloop(intro="")
  File "/usr/local/Cellar/python3/3.5.2_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/cmd.py", line 138, in cmdloop
    stop = self.onecmd(line)
  File "/usr/local/Cellar/python3/3.5.2_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/cmd.py", line 217, in onecmd
    return func(arg)
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/cloudmonkey.py", line 841, in do_exit
    return self.do_quit(args)
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/cloudmonkey.py", line 847, in do_quit
    self.monkeyprint("Bye!")
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/cloudmonkey.py", line 238, in monkeyprint
    monkeyprint(output)
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/printer.py", line 122, in monkeyprint
    if text.startswith("Error"):
TypeError: startswith first arg must be bytes or a tuple of bytes, not str

```

ヘルプは動いてるんだけどなぁ


```
(local) 🐵 > ? set

        Set config for cloudmonkey. For example, options can be:
        url, auth, log_file, history_file
        You may also edit your ~/.cloudmonkey_config instead of using set.

        Example:
        set url http://localhost:8080/client/api
        set prompt 🐵 cloudmonkey>
        set log_file /var/log/cloudmonkey.log
```

どこにエラーがるのかなぁ

ログには何も残ってないからファイルの書き込みかなぁ

```sh
$ ls ~/.cloudmonkey/log
```

````control
/Users/kentaro/.cloudmonkey/log
```

このあたりが怪しい？？

```control

 File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/config.py", line 141, in write_config
    config.write(cfg)
```

プロジェクトでconfig.write（）を検索しても、この１行しかないので

```control

  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/config.py", line 214, in read_config
    write_config(get_attr, config_file)
```

1行遡るとこの行らしい

```control
write_config(get_attr, config_file)
```

write_configは　config.py から来ているみたい

```py
    from .config import read_config, write_config, config_file, default_profile
```

結局　ここにたどり着くみたい
```py
TypeError: a bytes-like object is required, not 'str'
```

書き込もうとしている、ファイルがバイナリじゃないといけない？
python2 とpython3の差としてファイルの開け方に差があり、バイナリの場合は　b を追加するみたい。

```py
def write_config(get_attr, config_file):
    global config_fields, mandatory_sections
    global default_profile, default_profile_name
    config = ConfigParser()
    if os.path.exists(config_file):
        try:
            with open(config_file, 'r') as cfg:
                config.read_file(cfg)
        except IOError as e:
            print("Error: config_file not found", e)
```
を

```py
def write_config(get_attr, config_file):
    global config_fields, mandatory_sections
    global default_profile, default_profile_name
    config = ConfigParser()
    if os.path.exists(config_file):
        try:
            with open(config_file, 'rb') as cfg:
                config.read_file(cfg)
        except IOError as e:
            print("Error: config_file not found", e)
```

にしてみたところ!!!

```sh
cloudmonkey
Selected profile (local) does not exist, using default values
Missing configuration was set using default values for keys:
`asyncblock = true, history_file = /Users/kentaro/.cloudmonkey/history, profile = local, log_file = /Users/kentaro/.cloudmonkey/log, cache_file = /Users/kentaro/.cloudmonkey/cache, paramcompletion = true, prompt = 🐵 > , display = default, color = true` in /Users/kentaro/.cloudmonkey/config
☁ Apache CloudStack 🐵 cloudmonkey 5.3.3. Type help or ? to list commands.

Using management server profile: local

(local) 🐵 >
```

起動に成功　！！！

```sh
(local) 🐵 > help

Documented commands (type help <topic>):
========================================
EOF        change     disable       history  prepare    reset    start
activate   clean      disassociate  import   query      resize   stop
add        configure  enable        issue    quit       restart  suspend
api        copy       exit          ldap     reboot     restore  sync
archive    create     expunge       list     reconnect  revert   update
assign     dedicate   extract       lock     recover    revoke   upgrade
associate  delete     find          login    register   saml     upload
attach     deploy     generate      logout   release    scale
authorize  destroy    get           mark     remove     set
cancel     detach     help          migrate  replace    shell

(local) 🐵 > exit
Traceback (most recent call last):
  File "/Users/kentaro/porting/ven/bin/cloudmonkey", line 9, in <module>
    load_entry_point('cloudmonkey', 'console_scripts', 'cloudmonkey')()
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/cloudmonkey.py", line 920, in main
    shell.cmdloop()
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/cloudmonkey.py", line 163, in cmdloop
    super(CloudMonkeyShell, self).cmdloop(intro="")
  File "/usr/local/Cellar/python3/3.5.2_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/cmd.py", line 138, in cmdloop
    stop = self.onecmd(line)
  File "/usr/local/Cellar/python3/3.5.2_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/cmd.py", line 217, in onecmd
    return func(arg)
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/cloudmonkey.py", line 841, in do_exit
    return self.do_quit(args)
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/cloudmonkey.py", line 847, in do_quit
    self.monkeyprint("Bye!")
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/cloudmonkey.py", line 238, in monkeyprint
    monkeyprint(output)
  File "/Users/kentaro/porting/cloudstack-cloudmonkey/cloudmonkey/printer.py", line 122, in monkeyprint
    if text.startswith("Error"):
TypeError: startswith first arg must be bytes or a tuple of bytes, not str
```

ヘルプは表示されるけど、終了すらできないみたい...

今日はここまで