diff options
26 files changed, 104 insertions, 172 deletions
| diff --git a/cloudinit/config/cc_chef.py b/cloudinit/config/cc_chef.py index 0ad6b7f1..01d61fa1 100644 --- a/cloudinit/config/cc_chef.py +++ b/cloudinit/config/cc_chef.py @@ -79,8 +79,6 @@ from cloudinit import templater  from cloudinit import url_helper  from cloudinit import util -import six -  RUBY_VERSION_DEFAULT = "1.8"  CHEF_DIRS = tuple([ @@ -273,7 +271,7 @@ def run_chef(chef_cfg, log):          cmd_args = chef_cfg['exec_arguments']          if isinstance(cmd_args, (list, tuple)):              cmd.extend(cmd_args) -        elif isinstance(cmd_args, six.string_types): +        elif isinstance(cmd_args, str):              cmd.append(cmd_args)          else:              log.warning("Unknown type %s provided for chef" diff --git a/cloudinit/config/cc_mcollective.py b/cloudinit/config/cc_mcollective.py index d5f63f5f..351183f1 100644 --- a/cloudinit/config/cc_mcollective.py +++ b/cloudinit/config/cc_mcollective.py @@ -49,9 +49,7 @@ private certificates for mcollective. Their values will be written to  """  import errno - -import six -from six import BytesIO +import io  # Used since this can maintain comments  # and doesn't need a top level section @@ -73,7 +71,7 @@ def configure(config, server_cfg=SERVER_CFG,      # original file in order to be able to mix the rest up.      try:          old_contents = util.load_file(server_cfg, quiet=False, decode=False) -        mcollective_config = ConfigObj(BytesIO(old_contents)) +        mcollective_config = ConfigObj(io.BytesIO(old_contents))      except IOError as e:          if e.errno != errno.ENOENT:              raise @@ -93,7 +91,7 @@ def configure(config, server_cfg=SERVER_CFG,                  'plugin.ssl_server_private'] = pricert_file              mcollective_config['securityprovider'] = 'ssl'          else: -            if isinstance(cfg, six.string_types): +            if isinstance(cfg, str):                  # Just set it in the 'main' section                  mcollective_config[cfg_name] = cfg              elif isinstance(cfg, (dict)): @@ -119,7 +117,7 @@ def configure(config, server_cfg=SERVER_CFG,              raise      # Now we got the whole (new) file, write to disk... -    contents = BytesIO() +    contents = io.BytesIO()      mcollective_config.write(contents)      util.write_file(server_cfg, contents.getvalue(), mode=0o644) diff --git a/cloudinit/config/cc_ntp.py b/cloudinit/config/cc_ntp.py index 9e074bda..5498bbaa 100644 --- a/cloudinit/config/cc_ntp.py +++ b/cloudinit/config/cc_ntp.py @@ -6,19 +6,17 @@  """NTP: enable and configure ntp""" -from cloudinit.config.schema import ( -    get_schema_doc, validate_cloudconfig_schema) +import copy +import os +from textwrap import dedent +  from cloudinit import log as logging -from cloudinit.settings import PER_INSTANCE  from cloudinit import temp_utils  from cloudinit import templater  from cloudinit import type_utils  from cloudinit import util - -import copy -import os -import six -from textwrap import dedent +from cloudinit.config.schema import get_schema_doc, validate_cloudconfig_schema +from cloudinit.settings import PER_INSTANCE  LOG = logging.getLogger(__name__) @@ -460,7 +458,7 @@ def supplemental_schema_validation(ntp_config):      for key, value in sorted(ntp_config.items()):          keypath = 'ntp:config:' + key          if key == 'confpath': -            if not all([value, isinstance(value, six.string_types)]): +            if not all([value, isinstance(value, str)]):                  errors.append(                      'Expected a config file path {keypath}.'                      ' Found ({value})'.format(keypath=keypath, value=value)) @@ -472,11 +470,11 @@ def supplemental_schema_validation(ntp_config):          elif key in ('template', 'template_name'):              if value is None:  # Either template or template_name can be none                  continue -            if not isinstance(value, six.string_types): +            if not isinstance(value, str):                  errors.append(                      'Expected a string type for {keypath}.'                      ' Found ({value})'.format(keypath=keypath, value=value)) -        elif not isinstance(value, six.string_types): +        elif not isinstance(value, str):              errors.append(                  'Expected a string type for {keypath}.'                  ' Found ({value})'.format(keypath=keypath, value=value)) diff --git a/cloudinit/config/cc_power_state_change.py b/cloudinit/config/cc_power_state_change.py index 43a479cf..3e81a3c7 100644 --- a/cloudinit/config/cc_power_state_change.py +++ b/cloudinit/config/cc_power_state_change.py @@ -49,16 +49,15 @@ key returns 0.          condition: <true/false/command>  """ -from cloudinit.settings import PER_INSTANCE -from cloudinit import util -  import errno  import os  import re -import six  import subprocess  import time +from cloudinit.settings import PER_INSTANCE +from cloudinit import util +  frequency = PER_INSTANCE  EXIT_FAIL = 254 @@ -183,7 +182,7 @@ def load_power_state(cfg):                           pstate['timeout'])      condition = pstate.get("condition", True) -    if not isinstance(condition, six.string_types + (list, bool)): +    if not isinstance(condition, (str, list, bool)):          raise TypeError("condition type %s invalid. must be list, bool, str")      return (args, timeout, condition) diff --git a/cloudinit/config/cc_rsyslog.py b/cloudinit/config/cc_rsyslog.py index ff211f65..5df0137d 100644 --- a/cloudinit/config/cc_rsyslog.py +++ b/cloudinit/config/cc_rsyslog.py @@ -180,7 +180,6 @@ config entries. Legacy to new mappings are as follows:  import os  import re -import six  from cloudinit import log as logging  from cloudinit import util @@ -233,9 +232,9 @@ def load_config(cfg):      fillup = (          (KEYNAME_CONFIGS, [], list), -        (KEYNAME_DIR, DEF_DIR, six.string_types), -        (KEYNAME_FILENAME, DEF_FILENAME, six.string_types), -        (KEYNAME_RELOAD, DEF_RELOAD, six.string_types + (list,)), +        (KEYNAME_DIR, DEF_DIR, str), +        (KEYNAME_FILENAME, DEF_FILENAME, str), +        (KEYNAME_RELOAD, DEF_RELOAD, (str, list)),          (KEYNAME_REMOTES, DEF_REMOTES, dict))      for key, default, vtypes in fillup: diff --git a/cloudinit/config/cc_ubuntu_advantage.py b/cloudinit/config/cc_ubuntu_advantage.py index f846e9a5..8b6d2a1a 100644 --- a/cloudinit/config/cc_ubuntu_advantage.py +++ b/cloudinit/config/cc_ubuntu_advantage.py @@ -4,8 +4,6 @@  from textwrap import dedent -import six -  from cloudinit.config.schema import (      get_schema_doc, validate_cloudconfig_schema)  from cloudinit import log as logging @@ -98,7 +96,7 @@ def configure_ua(token=None, enable=None):      if enable is None:          enable = [] -    elif isinstance(enable, six.string_types): +    elif isinstance(enable, str):          LOG.warning('ubuntu_advantage: enable should be a list, not'                      ' a string; treating as a single enable')          enable = [enable] diff --git a/cloudinit/config/cc_write_files.py b/cloudinit/config/cc_write_files.py index 0b6546e2..bd87e9e5 100644 --- a/cloudinit/config/cc_write_files.py +++ b/cloudinit/config/cc_write_files.py @@ -57,7 +57,6 @@ binary gzip data can be specified and will be decoded before being written.  import base64  import os -import six  from cloudinit import log as logging  from cloudinit.settings import PER_INSTANCE @@ -126,7 +125,7 @@ def decode_perms(perm, default):      if perm is None:          return default      try: -        if isinstance(perm, six.integer_types + (float,)): +        if isinstance(perm, (int, float)):              # Just 'downcast' it (if a float)              return int(perm)          else: diff --git a/cloudinit/config/cc_yum_add_repo.py b/cloudinit/config/cc_yum_add_repo.py index 3b354a7d..3673166a 100644 --- a/cloudinit/config/cc_yum_add_repo.py +++ b/cloudinit/config/cc_yum_add_repo.py @@ -30,13 +30,9 @@ entry, the config entry will be skipped.              # any repository configuration options (see man yum.conf)  """ +import io  import os - -try: -    from configparser import ConfigParser -except ImportError: -    from ConfigParser import ConfigParser -import six +from configparser import ConfigParser  from cloudinit import util @@ -57,7 +53,7 @@ def _format_repo_value(val):          # Can handle 'lists' in certain cases          # See: https://linux.die.net/man/5/yum.conf          return "\n".join([_format_repo_value(v) for v in val]) -    if not isinstance(val, six.string_types): +    if not isinstance(val, str):          return str(val)      return val @@ -72,7 +68,7 @@ def _format_repository_config(repo_id, repo_config):          # For now assume that people using this know          # the format of yum and don't verify keys/values further          to_be.set(repo_id, k, _format_repo_value(v)) -    to_be_stream = six.StringIO() +    to_be_stream = io.StringIO()      to_be.write(to_be_stream)      to_be_stream.seek(0)      lines = to_be_stream.readlines() diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py index cdce26f2..92598a2d 100755 --- a/cloudinit/distros/__init__.py +++ b/cloudinit/distros/__init__.py @@ -9,13 +9,11 @@  #  # This file is part of cloud-init. See LICENSE file for license information. -import six -from six import StringIO -  import abc  import os  import re  import stat +from io import StringIO  from cloudinit import importer  from cloudinit import log as logging @@ -53,8 +51,7 @@ _EC2_AZ_RE = re.compile('^[a-z][a-z]-(?:[a-z]+-)+[0-9][a-z]$')  PREFERRED_NTP_CLIENTS = ['chrony', 'systemd-timesyncd', 'ntp', 'ntpdate'] -@six.add_metaclass(abc.ABCMeta) -class Distro(object): +class Distro(metaclass=abc.ABCMeta):      usr_lib_exec = "/usr/lib"      hosts_fn = "/etc/hosts" @@ -429,7 +426,7 @@ class Distro(object):          # support kwargs having groups=[list] or groups="g1,g2"          groups = kwargs.get('groups')          if groups: -            if isinstance(groups, six.string_types): +            if isinstance(groups, str):                  groups = groups.split(",")              # remove any white spaces in group names, most likely @@ -544,7 +541,7 @@ class Distro(object):          if 'ssh_authorized_keys' in kwargs:              # Try to handle this in a smart manner.              keys = kwargs['ssh_authorized_keys'] -            if isinstance(keys, six.string_types): +            if isinstance(keys, str):                  keys = [keys]              elif isinstance(keys, dict):                  keys = list(keys.values()) @@ -668,7 +665,7 @@ class Distro(object):          if isinstance(rules, (list, tuple)):              for rule in rules:                  lines.append("%s %s" % (user, rule)) -        elif isinstance(rules, six.string_types): +        elif isinstance(rules, str):              lines.append("%s %s" % (user, rules))          else:              msg = "Can not create sudoers rule addition with type %r" diff --git a/cloudinit/distros/freebsd.py b/cloudinit/distros/freebsd.py index 40e435e7..026d1142 100644 --- a/cloudinit/distros/freebsd.py +++ b/cloudinit/distros/freebsd.py @@ -5,10 +5,8 @@  # This file is part of cloud-init. See LICENSE file for license information.  import os -import six -from six import StringIO -  import re +from io import StringIO  from cloudinit import distros  from cloudinit import helpers @@ -108,8 +106,7 @@ class Distro(distros.Distro):          }          for key, val in kwargs.items(): -            if (key in pw_useradd_opts and val and -               isinstance(val, six.string_types)): +            if key in pw_useradd_opts and val and isinstance(val, str):                  pw_useradd_cmd.extend([pw_useradd_opts[key], val])              elif key in pw_useradd_flags and val: diff --git a/cloudinit/distros/parsers/sys_conf.py b/cloudinit/distros/parsers/sys_conf.py index 44df17de..dee4c551 100644 --- a/cloudinit/distros/parsers/sys_conf.py +++ b/cloudinit/distros/parsers/sys_conf.py @@ -4,11 +4,9 @@  #  # This file is part of cloud-init. See LICENSE file for license information. -import six -from six import StringIO -  import pipes  import re +from io import StringIO  # This library is used to parse/write  # out the various sysconfig files edited (best attempt effort) @@ -65,7 +63,7 @@ class SysConf(configobj.ConfigObj):          return out_contents.getvalue()      def _quote(self, value, multiline=False): -        if not isinstance(value, six.string_types): +        if not isinstance(value, str):              raise ValueError('Value "%s" is not a string' % (value))          if len(value) == 0:              return '' diff --git a/cloudinit/distros/ug_util.py b/cloudinit/distros/ug_util.py index 9378dd78..08446a95 100755 --- a/cloudinit/distros/ug_util.py +++ b/cloudinit/distros/ug_util.py @@ -9,8 +9,6 @@  #  # This file is part of cloud-init. See LICENSE file for license information. -import six -  from cloudinit import log as logging  from cloudinit import type_utils  from cloudinit import util @@ -29,7 +27,7 @@ LOG = logging.getLogger(__name__)  # is the standard form used in the rest  # of cloud-init  def _normalize_groups(grp_cfg): -    if isinstance(grp_cfg, six.string_types): +    if isinstance(grp_cfg, str):          grp_cfg = grp_cfg.strip().split(",")      if isinstance(grp_cfg, list):          c_grp_cfg = {} @@ -39,7 +37,7 @@ def _normalize_groups(grp_cfg):                      if k not in c_grp_cfg:                          if isinstance(v, list):                              c_grp_cfg[k] = list(v) -                        elif isinstance(v, six.string_types): +                        elif isinstance(v, str):                              c_grp_cfg[k] = [v]                          else:                              raise TypeError("Bad group member type %s" % @@ -47,12 +45,12 @@ def _normalize_groups(grp_cfg):                      else:                          if isinstance(v, list):                              c_grp_cfg[k].extend(v) -                        elif isinstance(v, six.string_types): +                        elif isinstance(v, str):                              c_grp_cfg[k].append(v)                          else:                              raise TypeError("Bad group member type %s" %                                              type_utils.obj_name(v)) -            elif isinstance(i, six.string_types): +            elif isinstance(i, str):                  if i not in c_grp_cfg:                      c_grp_cfg[i] = []              else: @@ -89,7 +87,7 @@ def _normalize_users(u_cfg, def_user_cfg=None):      if isinstance(u_cfg, dict):          ad_ucfg = []          for (k, v) in u_cfg.items(): -            if isinstance(v, (bool, int, float) + six.string_types): +            if isinstance(v, (bool, int, float, str)):                  if util.is_true(v):                      ad_ucfg.append(str(k))              elif isinstance(v, dict): @@ -99,12 +97,12 @@ def _normalize_users(u_cfg, def_user_cfg=None):                  raise TypeError(("Unmappable user value type %s"                                   " for key %s") % (type_utils.obj_name(v), k))          u_cfg = ad_ucfg -    elif isinstance(u_cfg, six.string_types): +    elif isinstance(u_cfg, str):          u_cfg = util.uniq_merge_sorted(u_cfg)      users = {}      for user_config in u_cfg: -        if isinstance(user_config, (list,) + six.string_types): +        if isinstance(user_config, (list, str)):              for u in util.uniq_merge(user_config):                  if u and u not in users:                      users[u] = {} @@ -209,7 +207,7 @@ def normalize_users_groups(cfg, distro):          old_user = cfg['user']          # Translate it into the format that is more useful          # going forward -        if isinstance(old_user, six.string_types): +        if isinstance(old_user, str):              old_user = {                  'name': old_user,              } @@ -238,7 +236,7 @@ def normalize_users_groups(cfg, distro):      default_user_config = util.mergemanydict([old_user, distro_user_config])      base_users = cfg.get('users', []) -    if not isinstance(base_users, (list, dict) + six.string_types): +    if not isinstance(base_users, (list, dict, str)):          LOG.warning(("Format for 'users' key must be a comma separated string"                       " or a dictionary or a list and not %s"),                      type_utils.obj_name(base_users)) @@ -252,7 +250,7 @@ def normalize_users_groups(cfg, distro):              base_users.append({'name': 'default'})          elif isinstance(base_users, dict):              base_users['default'] = dict(base_users).get('default', True) -        elif isinstance(base_users, six.string_types): +        elif isinstance(base_users, str):              # Just append it on to be re-parsed later              base_users += ",default" diff --git a/cloudinit/net/network_state.py b/cloudinit/net/network_state.py index 9b126100..63d6e291 100644 --- a/cloudinit/net/network_state.py +++ b/cloudinit/net/network_state.py @@ -10,8 +10,6 @@ import logging  import socket  import struct -import six -  from cloudinit import safeyaml  from cloudinit import util @@ -186,7 +184,7 @@ class NetworkState(object):      def iter_interfaces(self, filter_func=None):          ifaces = self._network_state.get('interfaces', {}) -        for iface in six.itervalues(ifaces): +        for iface in ifaces.values():              if filter_func is None:                  yield iface              else: @@ -220,8 +218,7 @@ class NetworkState(object):              ) -@six.add_metaclass(CommandHandlerMeta) -class NetworkStateInterpreter(object): +class NetworkStateInterpreter(metaclass=CommandHandlerMeta):      initial_network_state = {          'interfaces': {}, @@ -970,7 +967,7 @@ def ipv4_mask_to_net_prefix(mask):      """      if isinstance(mask, int):          return mask -    if isinstance(mask, six.string_types): +    if isinstance(mask, str):          try:              return int(mask)          except ValueError: @@ -997,7 +994,7 @@ def ipv6_mask_to_net_prefix(mask):      if isinstance(mask, int):          return mask -    if isinstance(mask, six.string_types): +    if isinstance(mask, str):          try:              return int(mask)          except ValueError: diff --git a/cloudinit/net/renderer.py b/cloudinit/net/renderer.py index 5f32e90f..2a61a7a8 100644 --- a/cloudinit/net/renderer.py +++ b/cloudinit/net/renderer.py @@ -6,7 +6,7 @@  # This file is part of cloud-init. See LICENSE file for license information.  import abc -import six +import io  from .network_state import parse_net_config_data  from .udev import generate_udev_rule @@ -34,7 +34,7 @@ class Renderer(object):          """Given state, emit udev rules to map mac to ifname."""          # TODO(harlowja): this seems shared between eni renderer and          # this, so move it to a shared location. -        content = six.StringIO() +        content = io.StringIO()          for iface in network_state.iter_interfaces(filter_by_physical):              # for physical interfaces write out a persist net udev rule              if 'name' in iface and iface.get('mac_address'): diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py index 3e06af01..07668d3e 100644 --- a/cloudinit/net/sysconfig.py +++ b/cloudinit/net/sysconfig.py @@ -1,16 +1,15 @@  # This file is part of cloud-init. See LICENSE file for license information. +import io  import os  import re -import six +from configobj import ConfigObj -from cloudinit.distros.parsers import networkmanager_conf -from cloudinit.distros.parsers import resolv_conf  from cloudinit import log as logging  from cloudinit import util - -from configobj import ConfigObj +from cloudinit.distros.parsers import networkmanager_conf +from cloudinit.distros.parsers import resolv_conf  from . import renderer  from .network_state import ( @@ -96,7 +95,7 @@ class ConfigMap(object):          return len(self._conf)      def to_string(self): -        buf = six.StringIO() +        buf = io.StringIO()          buf.write(_make_header())          if self._conf:              buf.write("\n") @@ -104,7 +103,7 @@ class ConfigMap(object):              value = self._conf[key]              if isinstance(value, bool):                  value = self._bool_map[value] -            if not isinstance(value, six.string_types): +            if not isinstance(value, str):                  value = str(value)              buf.write("%s=%s\n" % (key, _quote_value(value)))          return buf.getvalue() @@ -150,7 +149,7 @@ class Route(ConfigMap):          # only accept ipv4 and ipv6          if proto not in ['ipv4', 'ipv6']:              raise ValueError("Unknown protocol '%s'" % (str(proto))) -        buf = six.StringIO() +        buf = io.StringIO()          buf.write(_make_header())          if self._conf:              buf.write("\n") diff --git a/cloudinit/sources/tests/test_init.py b/cloudinit/sources/tests/test_init.py index 9698261b..f73b37ed 100644 --- a/cloudinit/sources/tests/test_init.py +++ b/cloudinit/sources/tests/test_init.py @@ -3,7 +3,6 @@  import copy  import inspect  import os -import six  import stat  from cloudinit.event import EventType @@ -13,7 +12,7 @@ from cloudinit.sources import (      EXPERIMENTAL_TEXT, INSTANCE_JSON_FILE, INSTANCE_JSON_SENSITIVE_FILE,      METADATA_UNKNOWN, REDACT_SENSITIVE_VALUE, UNSET, DataSource,      canonical_cloud_id, redact_sensitive_keys) -from cloudinit.tests.helpers import CiTestCase, skipIf, mock +from cloudinit.tests.helpers import CiTestCase, mock  from cloudinit.user_data import UserDataProcessor  from cloudinit import util @@ -422,7 +421,6 @@ class TestDataSource(CiTestCase):              {'network_json': 'is good'},              instance_data['ds']['network_json']) -    @skipIf(not six.PY3, "json serialization on <= py2.7 handles bytes")      def test_get_data_base64encodes_unserializable_bytes(self):          """On py3, get_data base64encodes any unserializable content."""          tmp = self.tmp_dir() @@ -440,35 +438,6 @@ class TestDataSource(CiTestCase):              {'key1': 'val1', 'key2': {'key2.1': 'EjM='}},              instance_json['ds']['meta_data']) -    @skipIf(not six.PY2, "json serialization on <= py2.7 handles bytes") -    def test_get_data_handles_bytes_values(self): -        """On py2 get_data handles bytes values without having to b64encode.""" -        tmp = self.tmp_dir() -        datasource = DataSourceTestSubclassNet( -            self.sys_cfg, self.distro, Paths({'run_dir': tmp}), -            custom_metadata={'key1': 'val1', 'key2': {'key2.1': b'\x123'}}) -        self.assertTrue(datasource.get_data()) -        json_file = self.tmp_path(INSTANCE_JSON_FILE, tmp) -        content = util.load_file(json_file) -        instance_json = util.load_json(content) -        self.assertEqual([], instance_json['base64_encoded_keys']) -        self.assertEqual( -            {'key1': 'val1', 'key2': {'key2.1': '\x123'}}, -            instance_json['ds']['meta_data']) - -    @skipIf(not six.PY2, "Only python2 hits UnicodeDecodeErrors on non-utf8") -    def test_non_utf8_encoding_gets_b64encoded(self): -        """When non-utf-8 values exist in py2 instance-data is b64encoded.""" -        tmp = self.tmp_dir() -        datasource = DataSourceTestSubclassNet( -            self.sys_cfg, self.distro, Paths({'run_dir': tmp}), -            custom_metadata={'key1': 'val1', 'key2': {'key2.1': b'ab\xaadef'}}) -        self.assertTrue(datasource.get_data()) -        json_file = self.tmp_path(INSTANCE_JSON_FILE, tmp) -        instance_json = util.load_json(util.load_file(json_file)) -        key21_value = instance_json['ds']['meta_data']['key2']['key2.1'] -        self.assertEqual('ci-b64:' + util.b64e(b'ab\xaadef'), key21_value) -      def test_get_hostname_subclass_support(self):          """Validate get_hostname signature on all subclasses of DataSource."""          # Use inspect.getfullargspec when we drop py2.6 and py2.7 diff --git a/cloudinit/sources/tests/test_oracle.py b/cloudinit/sources/tests/test_oracle.py index 85b6db97..6c551fcb 100644 --- a/cloudinit/sources/tests/test_oracle.py +++ b/cloudinit/sources/tests/test_oracle.py @@ -13,7 +13,6 @@ import httpretty  import json  import mock  import os -import six  import uuid  DS_PATH = "cloudinit.sources.DataSourceOracle" @@ -334,7 +333,7 @@ class TestReadMetaData(test_helpers.HttprettyTestCase):          for k, v in data.items():              httpretty.register_uri(                  httpretty.GET, self.mdurl + MD_VER + "/" + k, -                v if not isinstance(v, six.text_type) else v.encode('utf-8')) +                v if not isinstance(v, str) else v.encode('utf-8'))      def test_broken_no_sys_uuid(self, m_read_system_uuid):          """Datasource requires ability to read system_uuid and true return.""" diff --git a/cloudinit/stages.py b/cloudinit/stages.py index 71f3a49e..db8ba64c 100644 --- a/cloudinit/stages.py +++ b/cloudinit/stages.py @@ -6,11 +6,9 @@  import copy  import os +import pickle  import sys -import six -from six.moves import cPickle as pickle -  from cloudinit.settings import (      FREQUENCIES, CLOUD_CONFIG, PER_INSTANCE, RUN_CLOUD_CONFIG) @@ -758,7 +756,7 @@ class Modules(object):          for item in cfg_mods:              if not item:                  continue -            if isinstance(item, six.string_types): +            if isinstance(item, str):                  module_list.append({                      'mod': item.strip(),                  }) diff --git a/cloudinit/tests/helpers.py b/cloudinit/tests/helpers.py index 4dad2afd..0220648d 100644 --- a/cloudinit/tests/helpers.py +++ b/cloudinit/tests/helpers.py @@ -4,6 +4,7 @@ from __future__ import print_function  import functools  import httpretty +import io  import logging  import os  import random @@ -14,7 +15,6 @@ import tempfile  import time  import mock -import six  import unittest2  from unittest2.util import strclass @@ -72,7 +72,7 @@ def retarget_many_wrapper(new_base, am, old_func):              # Python 3 some of these now accept file-descriptors (integers).              # That breaks rebase_path() so in lieu of a better solution, just              # don't rebase if we get a fd. -            if isinstance(path, six.string_types): +            if isinstance(path, str):                  n_args[i] = rebase_path(path, new_base)          return old_func(*n_args, **kwds)      return wrapper @@ -149,7 +149,7 @@ class CiTestCase(TestCase):          if self.with_logs:              # Create a log handler so unit tests can search expected logs.              self.logger = logging.getLogger() -            self.logs = six.StringIO() +            self.logs = io.StringIO()              formatter = logging.Formatter('%(levelname)s: %(message)s')              handler = logging.StreamHandler(self.logs)              handler.setFormatter(formatter) @@ -166,7 +166,7 @@ class CiTestCase(TestCase):          else:              cmd = args[0] -        if not isinstance(cmd, six.string_types): +        if not isinstance(cmd, str):              cmd = cmd[0]          pass_through = False          if not isinstance(self.allowed_subp, (list, bool)): @@ -346,8 +346,9 @@ class FilesystemMockingTestCase(ResourceUsingTestCase):      def patchOpen(self, new_root):          trap_func = retarget_many_wrapper(new_root, 1, open) -        name = 'builtins.open' if six.PY3 else '__builtin__.open' -        self.patched_funcs.enter_context(mock.patch(name, trap_func)) +        self.patched_funcs.enter_context( +            mock.patch('builtins.open', trap_func) +        )      def patchStdoutAndStderr(self, stdout=None, stderr=None):          if stdout is not None: @@ -420,7 +421,7 @@ def populate_dir(path, files):          p = os.path.sep.join([path, name])          util.ensure_dir(os.path.dirname(p))          with open(p, "wb") as fp: -            if isinstance(content, six.binary_type): +            if isinstance(content, bytes):                  fp.write(content)              else:                  fp.write(content.encode('utf-8')) diff --git a/tests/unittests/test_cli.py b/tests/unittests/test_cli.py index d283f136..e57c15d1 100644 --- a/tests/unittests/test_cli.py +++ b/tests/unittests/test_cli.py @@ -1,8 +1,8 @@  # This file is part of cloud-init. See LICENSE file for license information. -from collections import namedtuple  import os -import six +import io +from collections import namedtuple  from cloudinit.cmd import main as cli  from cloudinit.tests import helpers as test_helpers @@ -18,7 +18,7 @@ class TestCLI(test_helpers.FilesystemMockingTestCase):      def setUp(self):          super(TestCLI, self).setUp() -        self.stderr = six.StringIO() +        self.stderr = io.StringIO()          self.patchStdoutAndStderr(stderr=self.stderr)      def _call_main(self, sysv_args=None): @@ -147,7 +147,7 @@ class TestCLI(test_helpers.FilesystemMockingTestCase):      def test_conditional_subcommands_from_entry_point_sys_argv(self):          """Subcommands from entry-point are properly parsed from sys.argv.""" -        stdout = six.StringIO() +        stdout = io.StringIO()          self.patchStdoutAndStderr(stdout=stdout)          expected_errors = [ @@ -178,7 +178,7 @@ class TestCLI(test_helpers.FilesystemMockingTestCase):      def test_collect_logs_subcommand_parser(self):          """The subcommand cloud-init collect-logs calls the subparser."""          # Provide -h param to collect-logs to avoid having to mock behavior. -        stdout = six.StringIO() +        stdout = io.StringIO()          self.patchStdoutAndStderr(stdout=stdout)          self._call_main(['cloud-init', 'collect-logs', '-h'])          self.assertIn('usage: cloud-init collect-log', stdout.getvalue()) @@ -186,7 +186,7 @@ class TestCLI(test_helpers.FilesystemMockingTestCase):      def test_clean_subcommand_parser(self):          """The subcommand cloud-init clean calls the subparser."""          # Provide -h param to clean to avoid having to mock behavior. -        stdout = six.StringIO() +        stdout = io.StringIO()          self.patchStdoutAndStderr(stdout=stdout)          self._call_main(['cloud-init', 'clean', '-h'])          self.assertIn('usage: cloud-init clean', stdout.getvalue()) @@ -194,7 +194,7 @@ class TestCLI(test_helpers.FilesystemMockingTestCase):      def test_status_subcommand_parser(self):          """The subcommand cloud-init status calls the subparser."""          # Provide -h param to clean to avoid having to mock behavior. -        stdout = six.StringIO() +        stdout = io.StringIO()          self.patchStdoutAndStderr(stdout=stdout)          self._call_main(['cloud-init', 'status', '-h'])          self.assertIn('usage: cloud-init status', stdout.getvalue()) @@ -219,7 +219,7 @@ class TestCLI(test_helpers.FilesystemMockingTestCase):      def test_wb_devel_schema_subcommand_doc_content(self):          """Validate that doc content is sane from known examples.""" -        stdout = six.StringIO() +        stdout = io.StringIO()          self.patchStdoutAndStderr(stdout=stdout)          self._call_main(['cloud-init', 'devel', 'schema', '--doc'])          expected_doc_sections = [ diff --git a/tests/unittests/test_datasource/test_smartos.py b/tests/unittests/test_datasource/test_smartos.py index d5b1c29c..62084de5 100644 --- a/tests/unittests/test_datasource/test_smartos.py +++ b/tests/unittests/test_datasource/test_smartos.py @@ -33,8 +33,6 @@ from cloudinit.sources.DataSourceSmartOS import (      identify_file)  from cloudinit.event import EventType -import six -  from cloudinit import helpers as c_helpers  from cloudinit.util import (      b64e, subp, ProcessExecutionError, which, write_file) @@ -798,7 +796,7 @@ class TestJoyentMetadataClient(FilesystemMockingTestCase):          return self.serial.write.call_args[0][0]      def test_get_metadata_writes_bytes(self): -        self.assertIsInstance(self._get_written_line(), six.binary_type) +        self.assertIsInstance(self._get_written_line(), bytes)      def test_get_metadata_line_starts_with_v2(self):          foo = self._get_written_line() diff --git a/tests/unittests/test_handler/test_handler_chef.py b/tests/unittests/test_handler/test_handler_chef.py index f4311268..2dab3a54 100644 --- a/tests/unittests/test_handler/test_handler_chef.py +++ b/tests/unittests/test_handler/test_handler_chef.py @@ -4,7 +4,6 @@ import httpretty  import json  import logging  import os -import six  from cloudinit import cloud  from cloudinit.config import cc_chef @@ -178,7 +177,7 @@ class TestChef(FilesystemMockingTestCase):                  continue              # the value from the cfg overrides that in the default              val = cfg['chef'].get(k, v) -            if isinstance(val, six.string_types): +            if isinstance(val, str):                  self.assertIn(val, c)          c = util.load_file(cc_chef.CHEF_FB_PATH)          self.assertEqual({}, json.loads(c)) diff --git a/tests/unittests/test_handler/test_handler_write_files.py b/tests/unittests/test_handler/test_handler_write_files.py index bc8756ca..ed0a4da2 100644 --- a/tests/unittests/test_handler/test_handler_write_files.py +++ b/tests/unittests/test_handler/test_handler_write_files.py @@ -1,17 +1,16 @@  # This file is part of cloud-init. See LICENSE file for license information. -from cloudinit.config.cc_write_files import write_files, decode_perms -from cloudinit import log as logging -from cloudinit import util - -from cloudinit.tests.helpers import CiTestCase, FilesystemMockingTestCase -  import base64  import gzip +import io  import shutil -import six  import tempfile +from cloudinit import log as logging +from cloudinit import util +from cloudinit.config.cc_write_files import write_files, decode_perms +from cloudinit.tests.helpers import CiTestCase, FilesystemMockingTestCase +  LOG = logging.getLogger(__name__)  YAML_TEXT = """ @@ -138,7 +137,7 @@ class TestDecodePerms(CiTestCase):  def _gzip_bytes(data): -    buf = six.BytesIO() +    buf = io.BytesIO()      fp = None      try:          fp = gzip.GzipFile(fileobj=buf, mode="wb") diff --git a/tests/unittests/test_log.py b/tests/unittests/test_log.py index cd6296d6..e069a487 100644 --- a/tests/unittests/test_log.py +++ b/tests/unittests/test_log.py @@ -2,14 +2,15 @@  """Tests for cloudinit.log """ -from cloudinit.analyze.dump import CLOUD_INIT_ASCTIME_FMT -from cloudinit import log as ci_logging -from cloudinit.tests.helpers import CiTestCase  import datetime +import io  import logging -import six  import time +from cloudinit import log as ci_logging +from cloudinit.analyze.dump import CLOUD_INIT_ASCTIME_FMT +from cloudinit.tests.helpers import CiTestCase +  class TestCloudInitLogger(CiTestCase): @@ -18,7 +19,7 @@ class TestCloudInitLogger(CiTestCase):          # of sys.stderr, we'll plug in a StringIO() object so we can see          # what gets logged          logging.Formatter.converter = time.gmtime -        self.ci_logs = six.StringIO() +        self.ci_logs = io.StringIO()          self.ci_root = logging.getLogger()          console = logging.StreamHandler(self.ci_logs)          console.setFormatter(logging.Formatter(ci_logging.DEF_CON_FORMAT)) diff --git a/tests/unittests/test_merging.py b/tests/unittests/test_merging.py index 3a5072c7..10871bcf 100644 --- a/tests/unittests/test_merging.py +++ b/tests/unittests/test_merging.py @@ -13,13 +13,11 @@ import glob  import os  import random  import re -import six  import string  SOURCE_PAT = "source*.*yaml"  EXPECTED_PAT = "expected%s.yaml" -TYPES = [dict, str, list, tuple, None] -TYPES.extend(six.integer_types) +TYPES = [dict, str, list, tuple, None, int]  def _old_mergedict(src, cand): @@ -85,7 +83,7 @@ def _make_dict(current_depth, max_depth, rand):                      pass              if t in [tuple]:                  base = tuple(base) -    elif t in six.integer_types: +    elif t in [int]:          base = rand.randint(0, 2 ** 8)      elif t in [str]:          base = _random_str(rand) diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py index 0e71db82..75a3f0b4 100644 --- a/tests/unittests/test_util.py +++ b/tests/unittests/test_util.py @@ -2,16 +2,15 @@  from __future__ import print_function +import io +import json  import logging  import os  import re  import shutil  import stat -import tempfile - -import json -import six  import sys +import tempfile  import yaml  from cloudinit import importer, util @@ -320,7 +319,7 @@ class TestLoadYaml(helpers.CiTestCase):      def test_python_unicode(self):          # complex type of python/unicode is explicitly allowed -        myobj = {'1': six.text_type("FOOBAR")} +        myobj = {'1': "FOOBAR"}          safe_yaml = yaml.dump(myobj)          self.assertEqual(util.load_yaml(blob=safe_yaml,                                          default=self.mydefault), @@ -663,8 +662,8 @@ class TestMultiLog(helpers.FilesystemMockingTestCase):          self.patchOS(self.root)          self.patchUtils(self.root)          self.patchOpen(self.root) -        self.stdout = six.StringIO() -        self.stderr = six.StringIO() +        self.stdout = io.StringIO() +        self.stderr = io.StringIO()          self.patchStdoutAndStderr(self.stdout, self.stderr)      def test_stderr_used_by_default(self): @@ -879,8 +878,8 @@ class TestSubp(helpers.CiTestCase):          """Raised exc should have stderr, stdout as string if no decode."""          with self.assertRaises(util.ProcessExecutionError) as cm:              util.subp([BOGUS_COMMAND], decode=True) -        self.assertTrue(isinstance(cm.exception.stdout, six.string_types)) -        self.assertTrue(isinstance(cm.exception.stderr, six.string_types)) +        self.assertTrue(isinstance(cm.exception.stdout, str)) +        self.assertTrue(isinstance(cm.exception.stderr, str))      def test_bunch_of_slashes_in_path(self):          self.assertEqual("/target/my/path/", | 
