diff --git a/salt/auth/__init__.py b/salt/auth/__init__.py index 8e403d4ff196..c4cf163a6797 100644 --- a/salt/auth/__init__.py +++ b/salt/auth/__init__.py @@ -13,7 +13,6 @@ # 5. Cache auth token with relative data opts['token_dir'] # 6. Interface to verify tokens -# Import python libs from __future__ import absolute_import, print_function, unicode_literals import collections @@ -21,8 +20,8 @@ import logging import random import time +from collections.abc import Iterable, Mapping -# Import salt libs import salt.config import salt.exceptions import salt.loader @@ -202,9 +201,9 @@ def _allow_custom_expire(self, load): if expire_override is True: return True - if isinstance(expire_override, collections.Mapping): + if isinstance(expire_override, Mapping): expire_whitelist = expire_override.get(load["eauth"], []) - if isinstance(expire_whitelist, collections.Iterable): + if isinstance(expire_whitelist, Iterable): if load.get("username") in expire_whitelist: return True diff --git a/salt/client/ssh/wrapper/grains.py b/salt/client/ssh/wrapper/grains.py index b58250af2945..d51b0001108e 100644 --- a/salt/client/ssh/wrapper/grains.py +++ b/salt/client/ssh/wrapper/grains.py @@ -3,23 +3,26 @@ Return/control aspects of the grains data """ -# Import python libs from __future__ import absolute_import, print_function -import collections import copy import math -# Import salt libs import salt.utils.data import salt.utils.dictupdate import salt.utils.json from salt.defaults import DEFAULT_TARGET_DELIM from salt.exceptions import SaltException - -# Import 3rd-party libs from salt.ext import six +try: + # Python 3 + from collections.abc import Mapping +except ImportError: + # We still allow Py2 import because this could be executed in a machine with Py2. + from collections import Mapping # pylint: disable=no-name-in-module + + # Seed the grains dict so cython will build __grains__ = {} @@ -261,15 +264,15 @@ def filter_by(lookup_dict, grain="os_family", merge=None, default="default", bas if ret is None: ret = base_values - elif isinstance(base_values, collections.Mapping): - if not isinstance(ret, collections.Mapping): + elif isinstance(base_values, Mapping): + if not isinstance(ret, Mapping): raise SaltException( "filter_by default and look-up values must both be dictionaries." ) ret = salt.utils.dictupdate.update(copy.deepcopy(base_values), ret) if merge: - if not isinstance(merge, collections.Mapping): + if not isinstance(merge, Mapping): raise SaltException("filter_by merge argument must be a dictionary.") else: if ret is None: diff --git a/salt/client/ssh/wrapper/pillar.py b/salt/client/ssh/wrapper/pillar.py index a27f1fdda744..e9caeb95d1bd 100644 --- a/salt/client/ssh/wrapper/pillar.py +++ b/salt/client/ssh/wrapper/pillar.py @@ -4,15 +4,19 @@ """ from __future__ import absolute_import, print_function -# Import python libs -import collections - # Import salt libs import salt.pillar import salt.utils.data import salt.utils.dictupdate from salt.defaults import DEFAULT_TARGET_DELIM +try: + # Python 3 + from collections.abc import Mapping +except ImportError: + # We still allow Py2 import because this could be executed in a machine with Py2. + from collections import Mapping # pylint: disable=no-name-in-module + def get(key, default="", merge=False, delimiter=DEFAULT_TARGET_DELIM): """ @@ -53,9 +57,7 @@ def get(key, default="", merge=False, delimiter=DEFAULT_TARGET_DELIM): """ if merge: ret = salt.utils.data.traverse_dict_and_list(__pillar__, key, {}, delimiter) - if isinstance(ret, collections.Mapping) and isinstance( - default, collections.Mapping - ): + if isinstance(ret, Mapping) and isinstance(default, Mapping): return salt.utils.dictupdate.update(default, ret) return salt.utils.data.traverse_dict_and_list(__pillar__, key, default, delimiter) diff --git a/salt/fileserver/__init__.py b/salt/fileserver/__init__.py index 210680b56135..95398f3a218d 100644 --- a/salt/fileserver/__init__.py +++ b/salt/fileserver/__init__.py @@ -363,9 +363,9 @@ def backends(self, back=None): if isinstance(back, Sequence): # The test suite uses an ImmutableList type (based on - # collections.Sequence) for lists, which breaks this function in + # collections.abc.Sequence) for lists, which breaks this function in # the test suite. This normalizes the value from the opts into a - # list if it is based on collections.Sequence. + # list if it is based on collections.abc.Sequence. back = list(back) ret = [] diff --git a/salt/modules/event.py b/salt/modules/event.py index 27164516e7e6..5bda0137a8cf 100644 --- a/salt/modules/event.py +++ b/salt/modules/event.py @@ -4,22 +4,19 @@ master to the minion and vice-versa. """ -# Import Python libs from __future__ import absolute_import, print_function, unicode_literals -import collections import logging import os import sys import traceback +from collections.abc import Mapping -# Import salt libs import salt.crypt import salt.payload import salt.transport.client import salt.utils.event import salt.utils.zeromq -from salt.ext import six __proxyenabled__ = ["*"] log = logging.getLogger(__name__) @@ -29,7 +26,7 @@ def _dict_subset(keys, master_dict): """ Return a dictionary of only the subset of keys/values specified in keys """ - return dict([(k, v) for k, v in six.iteritems(master_dict) if k in keys]) + return dict([(k, v) for k, v in master_dict.items() if k in keys]) def fire_master(data, tag, preload=None): @@ -237,7 +234,7 @@ def send( data_dict.update(kwargs) # Allow values in the ``data`` arg to override any of the above values. - if isinstance(data, collections.Mapping): + if isinstance(data, Mapping): data_dict.update(data) if ( diff --git a/salt/modules/grains.py b/salt/modules/grains.py index 6dd182ff2d15..99fd42bf9a57 100644 --- a/salt/modules/grains.py +++ b/salt/modules/grains.py @@ -10,7 +10,6 @@ This does **NOT** override any grains set in the minion config file. """ -# Import python libs from __future__ import absolute_import, print_function, unicode_literals import collections @@ -19,6 +18,7 @@ import operator import os import random +from collections.abc import Mapping from functools import reduce # pylint: disable=redefined-builtin import salt.utils.compat @@ -30,10 +30,6 @@ from salt.defaults import DEFAULT_TARGET_DELIM from salt.exceptions import SaltException -# Import Salt libs -from salt.ext import six -from salt.ext.six.moves import range - __proxyenabled__ = ["*"] # Seed the grains dict so cython will build @@ -163,7 +159,7 @@ def items(sanitize=False): """ if salt.utils.data.is_true(sanitize): out = dict(__grains__) - for key, func in six.iteritems(_SANITIZERS): + for key, func in _SANITIZERS.items(): if key in out: out[key] = func(out[key]) return out @@ -201,7 +197,7 @@ def item(*args, **kwargs): pass if salt.utils.data.is_true(kwargs.get("sanitize")): - for arg, func in six.iteritems(_SANITIZERS): + for arg, func in _SANITIZERS.items(): if arg in ret: ret[arg] = func(ret[arg]) return ret @@ -226,7 +222,7 @@ def setvals(grains, destructive=False, refresh_pillar=True): salt '*' grains.setvals "{'key1': 'val1', 'key2': 'val2'}" """ new_grains = grains - if not isinstance(new_grains, collections.Mapping): + if not isinstance(new_grains, Mapping): raise SaltException("setvals grains must be a dictionary.") grains = {} if os.path.isfile(__opts__["conf_file"]): @@ -265,7 +261,7 @@ def setvals(grains, destructive=False, refresh_pillar=True): return "Unable to read existing grains file: {0}".format(exc) if not isinstance(grains, dict): grains = {} - for key, val in six.iteritems(new_grains): + for key, val in new_grains.items(): if val is None and destructive is True: if key in grains: del grains[key] @@ -788,7 +784,7 @@ def equals(key, value): salt '*' grains.equals fqdn salt '*' grains.equals systemd:version 219 """ - return six.text_type(value) == six.text_type(get(key)) + return str(value) == str(get(key)) # Provide a jinja function call compatible get aliased as fetch diff --git a/salt/modules/influxdbmod.py b/salt/modules/influxdbmod.py index 8638e358c7a0..53dace02e543 100644 --- a/salt/modules/influxdbmod.py +++ b/salt/modules/influxdbmod.py @@ -31,8 +31,8 @@ import collections import logging +from collections.abc import Sequence -# Import salt libs import salt.utils.json from salt.state import STATE_INTERNAL_KEYWORDS as _STATE_INTERNAL_KEYWORDS @@ -714,7 +714,7 @@ def query(database, query, **client_args): client = _client(**client_args) _result = client.query(query, database=database) - if isinstance(_result, collections.Sequence): + if isinstance(_result, Sequence): return [ _pull_query_results(_query_result) for _query_result in _result diff --git a/salt/modules/match.py b/salt/modules/match.py index 8d4a7e090c37..367bf0262a7d 100644 --- a/salt/modules/match.py +++ b/salt/modules/match.py @@ -4,15 +4,12 @@ """ from __future__ import absolute_import, print_function, unicode_literals -import collections import copy - -# Import python libs import inspect import logging import sys +from collections.abc import Mapping -# Import salt libs import salt.loader from salt.defaults import DEFAULT_TARGET_DELIM from salt.exceptions import SaltException @@ -358,7 +355,7 @@ def filter_by( params = (key, minion_id) if minion_id else (key,) if expr_funcs[tgt_type](*params): if merge: - if not isinstance(merge, collections.Mapping): + if not isinstance(merge, Mapping): raise SaltException( "filter_by merge argument must be a dictionary." ) diff --git a/salt/netapi/rest_cherrypy/app.py b/salt/netapi/rest_cherrypy/app.py index 0192175b5075..349ac31467cf 100644 --- a/salt/netapi/rest_cherrypy/app.py +++ b/salt/netapi/rest_cherrypy/app.py @@ -576,45 +576,36 @@ .. |406| replace:: requested Content-Type not available """ -# We need a custom pylintrc here... -# pylint: disable=W0212,E1101,C0103,R0201,W0221,W0613 - -# Import Python libs from __future__ import absolute_import -import collections import functools +import io import itertools import logging import os import signal import tarfile +from collections.abc import Iterator, Mapping from multiprocessing import Pipe, Process -# Import third-party libs -# pylint: disable=import-error, 3rd-party-module-not-gated -import cherrypy - -# Import Salt libs +import cherrypy # pylint: disable=import-error,3rd-party-module-not-gated import salt import salt.auth import salt.exceptions - -# Import salt-api libs import salt.netapi import salt.utils.event import salt.utils.json import salt.utils.stringutils import salt.utils.versions import salt.utils.yaml -from salt.ext import six -from salt.ext.six import BytesIO logger = logging.getLogger(__name__) try: - from cherrypy.lib import cpstats + from cherrypy.lib import ( # pylint: disable=import-error,3rd-party-module-not-gated + cpstats, + ) except AttributeError: cpstats = None logger.warn( @@ -626,11 +617,8 @@ cpstats = None logger.warn("Import of cherrypy.cpstats failed.") -# pylint: enable=import-error, 3rd-party-module-not-gated - - -# Imports related to websocket try: + # Imports related to websocket from .tools import websockets from . import event_processor @@ -912,9 +900,7 @@ def hypermedia_handler(*args, **kwargs): out = cherrypy.response.processors[best] try: response = out(ret) - if six.PY3: - response = salt.utils.stringutils.to_bytes(response) - return response + return salt.utils.stringutils.to_bytes(response) except Exception: # pylint: disable=broad-except msg = "Could not serialize the return data from Salt." logger.debug(msg, exc_info=True) @@ -981,15 +967,12 @@ def json_processor(entity): :param entity: raw POST data """ - if six.PY2: - body = entity.fp.read() - else: - # https://github.com/cherrypy/cherrypy/pull/1572 - contents = BytesIO() - body = entity.fp.read(fp_out=contents) - contents.seek(0) - body = salt.utils.stringutils.to_unicode(contents.read()) - del contents + # https://github.com/cherrypy/cherrypy/pull/1572 + contents = io.BytesIO() + body = entity.fp.read(fp_out=contents) + contents.seek(0) + body = salt.utils.stringutils.to_unicode(contents.read()) + del contents try: cherrypy.serving.request.unserialized_data = salt.utils.json.loads(body) except ValueError: @@ -1005,14 +988,11 @@ def yaml_processor(entity): :param entity: raw POST data """ - if six.PY2: - body = entity.fp.read() - else: - # https://github.com/cherrypy/cherrypy/pull/1572 - contents = BytesIO() - body = entity.fp.read(fp_out=contents) - contents.seek(0) - body = salt.utils.stringutils.to_unicode(contents.read()) + # https://github.com/cherrypy/cherrypy/pull/1572 + contents = io.BytesIO() + body = entity.fp.read(fp_out=contents) + contents.seek(0) + body = salt.utils.stringutils.to_unicode(contents.read()) try: cherrypy.serving.request.unserialized_data = salt.utils.yaml.safe_load(body) except ValueError: @@ -1031,14 +1011,11 @@ def text_processor(entity): :param entity: raw POST data """ - if six.PY2: - body = entity.fp.read() - else: - # https://github.com/cherrypy/cherrypy/pull/1572 - contents = BytesIO() - body = entity.fp.read(fp_out=contents) - contents.seek(0) - body = salt.utils.stringutils.to_unicode(contents.read()) + # https://github.com/cherrypy/cherrypy/pull/1572 + contents = io.BytesIO() + body = entity.fp.read(fp_out=contents) + contents.seek(0) + body = salt.utils.stringutils.to_unicode(contents.read()) try: cherrypy.serving.request.unserialized_data = salt.utils.json.loads(body) except ValueError: @@ -1097,7 +1074,7 @@ def lowdata_fmt(): # if the data was sent as urlencoded, we need to make it a list. # this is a very forgiving implementation as different clients set different # headers for form encoded data (including charset or something similar) - if data and isinstance(data, collections.Mapping): + if data and isinstance(data, Mapping): # Make the 'arg' param a list if not already if "arg" in data and not isinstance( data["arg"], list @@ -1211,7 +1188,7 @@ def exec_lowstate(self, client=None, token=None): ret = self.api.run(chunk) # Sometimes Salt gives us a return and sometimes an iterator - if isinstance(ret, collections.Iterator): + if isinstance(ret, Iterator): for i in ret: yield i else: @@ -1322,7 +1299,7 @@ class Minions(LowDataAdapter): _cp_config = dict(LowDataAdapter._cp_config, **{"tools.salt_auth.on": True}) - def GET(self, mid=None): + def GET(self, mid=None): # pylint: disable=arguments-differ """ A convenience URL for getting lists of minions or getting minion details @@ -1440,7 +1417,7 @@ def POST(self, **kwargs): class Jobs(LowDataAdapter): _cp_config = dict(LowDataAdapter._cp_config, **{"tools.salt_auth.on": True}) - def GET(self, jid=None, timeout=""): + def GET(self, jid=None, timeout=""): # pylint: disable=arguments-differ """ A convenience URL for getting lists of previously run jobs or getting the return from a single job @@ -1560,7 +1537,7 @@ class Keys(LowDataAdapter): module ` functions. """ - def GET(self, mid=None): + def GET(self, mid=None): # pylint: disable=arguments-differ """ Show the list of minion keys or detail on a specific key @@ -1723,15 +1700,14 @@ def POST(self, **kwargs): priv_key_file = tarfile.TarInfo("minion.pem") priv_key_file.size = len(priv_key) - fileobj = BytesIO() + fileobj = io.BytesIO() tarball = tarfile.open(fileobj=fileobj, mode="w") - if six.PY3: - pub_key = pub_key.encode(__salt_system_encoding__) - priv_key = priv_key.encode(__salt_system_encoding__) + pub_key = pub_key.encode(__salt_system_encoding__) + priv_key = priv_key.encode(__salt_system_encoding__) - tarball.addfile(pub_key_file, BytesIO(pub_key)) - tarball.addfile(priv_key_file, BytesIO(priv_key)) + tarball.addfile(pub_key_file, io.BytesIO(pub_key)) + tarball.addfile(priv_key_file, io.BytesIO(priv_key)) tarball.close() headers = cherrypy.response.headers @@ -1944,7 +1920,7 @@ class Logout(LowDataAdapter): **{"tools.salt_auth.on": True, "tools.lowdata_fmt.on": False} ) - def POST(self): + def POST(self): # pylint: disable=arguments-differ """ Destroy the currently active session and expire the session cookie """ @@ -2856,9 +2832,7 @@ def _setattr_url_map(self): url_blacklist = [] urls = ( - (url, cls) - for url, cls in six.iteritems(self.url_map) - if url not in url_blacklist + (url, cls) for url, cls in self.url_map.items() if url not in url_blacklist ) for url, cls in urls: diff --git a/salt/returners/carbon_return.py b/salt/returners/carbon_return.py index b5c360000a02..3d31b9644926 100644 --- a/salt/returners/carbon_return.py +++ b/salt/returners/carbon_return.py @@ -80,26 +80,19 @@ salt '*' test.ping --return carbon --return_kwargs '{"skip_on_error": False}' """ - -# Import python libs from __future__ import absolute_import, print_function, unicode_literals -import collections import logging +import pickle import socket import struct import time +from collections.abc import Mapping from contextlib import contextmanager import salt.returners - -# Import salt libs import salt.utils.jid -# Import 3rd-party libs -from salt.ext import six -from salt.ext.six.moves import cPickle, map - log = logging.getLogger(__name__) # Define the module's virtual name @@ -164,7 +157,7 @@ def _send_picklemetrics(metrics): (metric_name, (timestamp, value)) for (metric_name, value, timestamp) in metrics ] - data = cPickle.dumps(metrics, -1) + data = pickle.dumps(metrics, -1) payload = struct.pack(b"!L", len(data)) + data return payload @@ -175,7 +168,7 @@ def _send_textmetrics(metrics): Format metrics for the carbon plaintext protocol """ - data = [" ".join(map(six.text_type, metric)) for metric in metrics] + [""] + data = [" ".join(map(str, metric)) for metric in metrics] + [""] return "\n".join(data) @@ -205,8 +198,8 @@ def _walk(path, value, metrics, timestamp, skip): metrics, timestamp, ) - if isinstance(value, collections.Mapping): - for key, val in six.iteritems(value): + if isinstance(value, Mapping): + for key, val in value.items(): _walk("{0}.{1}".format(path, key), val, metrics, timestamp, skip) elif isinstance(value, list): for item in value: diff --git a/salt/runners/digicertapi.py b/salt/runners/digicertapi.py index d275571f2b48..b9cd0ca0c8c4 100644 --- a/salt/runners/digicertapi.py +++ b/salt/runners/digicertapi.py @@ -37,12 +37,12 @@ """ from __future__ import absolute_import, print_function, unicode_literals -import collections import logging import os import re import subprocess import tempfile +from collections.abc import Sequence import salt.cache import salt.syspaths as syspaths @@ -51,7 +51,6 @@ import salt.utils.json from salt.exceptions import CommandExecutionError, SaltRunnerError from salt.ext import six -from salt.ext.six.moves import range try: from M2Crypto import RSA @@ -425,7 +424,7 @@ def order_certificate( if dns_names and isinstance(dns_names, six.string_types): dns_names = [dns_names] - if dns_names and not isinstance(dns_names, collections.Sequence): + if dns_names and not isinstance(dns_names, Sequence): raise SaltRunnerError( "order_certificate needs a single dns_name, or an array of dns_names." ) @@ -443,7 +442,7 @@ def order_certificate( if organization_units and isinstance(organization_units, six.string_types): organization_units = [organization_units] - if organization_units and not isinstance(organization_units, collections.Sequence): + if organization_units and not isinstance(organization_units, Sequence): raise SaltRunnerError("Organization_units is not a valid data type.") if organization_units: certificate["organization_units"] = organization_units diff --git a/salt/utils/args.py b/salt/utils/args.py index f410342f4670..9d146b726733 100644 --- a/salt/utils/args.py +++ b/salt/utils/args.py @@ -2,8 +2,6 @@ """ Functions used for CLI argument handling """ - -# Import python libs from __future__ import absolute_import, print_function, unicode_literals import copy @@ -12,24 +10,37 @@ import logging import re import shlex +from collections import namedtuple import salt.utils.data import salt.utils.jid import salt.utils.versions import salt.utils.yaml - -# Import salt libs from salt.exceptions import SaltInvocationError -from salt.ext import six -from salt.ext.six.moves import map, zip log = logging.getLogger(__name__) -if six.PY3: - KWARG_REGEX = re.compile(r"^([^\d\W][\w.-]*)=(?!=)(.*)$", re.UNICODE) -else: - KWARG_REGEX = re.compile(r"^([^\d\W][\w.-]*)=(?!=)(.*)$") +KWARG_REGEX = re.compile(r"^([^\d\W][\w.-]*)=(?!=)(.*)$", re.UNICODE) + + +def _getargspec(func): + """ + Python 3 wrapper for inspect.getargsspec + + inspect.getargsspec is deprecated and will be removed in Python 3.6. + """ + _ArgSpec = namedtuple("ArgSpec", "args varargs keywords defaults") + + args, varargs, varkw, defaults, kwonlyargs, _, ann = inspect.getfullargspec( + func + ) # pylint: disable=no-member + if kwonlyargs or ann: + raise ValueError( + "Function has keyword-only arguments or annotations" + ", use getfullargspec() API which can support them" + ) + return _ArgSpec(args, varargs, varkw, defaults) def clean_kwargs(**kwargs): @@ -47,7 +58,7 @@ def clean_kwargs(**kwargs): kwargs = __utils__['args.clean_kwargs'](**kwargs) """ ret = {} - for key, val in six.iteritems(kwargs): + for key, val in kwargs.items(): if not key.startswith("__"): ret[key] = val return ret @@ -59,9 +70,7 @@ def invalid_kwargs(invalid_kwargs, raise_exc=True): """ if invalid_kwargs: if isinstance(invalid_kwargs, dict): - new_invalid = [ - "{0}={1}".format(x, y) for x, y in six.iteritems(invalid_kwargs) - ] + new_invalid = ["{0}={1}".format(x, y) for x, y in invalid_kwargs.items()] invalid_kwargs = new_invalid msg = "The following keyword arguments are not valid: {0}".format( ", ".join(invalid_kwargs) @@ -78,19 +87,13 @@ def condition_input(args, kwargs): """ ret = [] for arg in args: - # pylint: disable=incompatible-py3-code,undefined-variable - if ( - six.PY3 - and isinstance(arg, six.integer_types) - and salt.utils.jid.is_jid(six.text_type(arg)) - ) or (six.PY2 and isinstance(arg, long)): - ret.append(six.text_type(arg)) + if isinstance(arg, int) and salt.utils.jid.is_jid(str(arg)): + ret.append(str(arg)) else: ret.append(arg) - # pylint: enable=incompatible-py3-code,undefined-variable if isinstance(kwargs, dict) and kwargs: kw_ = {"__kwarg__": True} - for key, val in six.iteritems(kwargs): + for key, val in kwargs.items(): kw_[key] = val return ret + [kw_] return ret @@ -108,7 +111,7 @@ def parse_input(args, condition=True, no_parse=None): _args = [] _kwargs = {} for arg in args: - if isinstance(arg, six.string_types): + if isinstance(arg, str): arg_name, arg_value = parse_kwarg(arg) if arg_name: _kwargs[arg_name] = ( @@ -152,7 +155,7 @@ def yamlify_arg(arg): """ yaml.safe_load the arg """ - if not isinstance(arg, six.string_types): + if not isinstance(arg, str): return arg # YAML loads empty (or all whitespace) strings as None: @@ -196,7 +199,7 @@ def yamlify_arg(arg): # Only yamlify if it parses into a non-string type, to prevent # loss of content due to # as comment character parsed_arg = salt.utils.yaml.safe_load(arg) - if isinstance(parsed_arg, six.string_types) or parsed_arg is None: + if isinstance(parsed_arg, str) or parsed_arg is None: return arg return parsed_arg if arg == "None": @@ -206,25 +209,19 @@ def yamlify_arg(arg): if isinstance(arg, dict): # dicts must be wrapped in curly braces - if isinstance( - original_arg, six.string_types - ) and not original_arg.startswith("{"): + if isinstance(original_arg, str) and not original_arg.startswith("{"): return original_arg else: return arg elif isinstance(arg, list): # lists must be wrapped in brackets - if isinstance( - original_arg, six.string_types - ) and not original_arg.startswith("["): + if isinstance(original_arg, str) and not original_arg.startswith("["): return original_arg else: return arg - elif arg is None or isinstance( - arg, (list, float, six.integer_types, six.string_types) - ): + elif arg is None or isinstance(arg, (list, float, int, str)): # yaml.safe_load will load '|' and '!' as '', don't let it do that. if arg == "" and original_arg in ("|", "!"): return original_arg @@ -245,30 +242,6 @@ def yamlify_arg(arg): return original_arg -if six.PY3: - from collections import ( - namedtuple, - ) # pylint: disable=wrong-import-position,wrong-import-order - - _ArgSpec = namedtuple("ArgSpec", "args varargs keywords defaults") - - def _getargspec(func): - """ - Python 3 wrapper for inspect.getargsspec - - inspect.getargsspec is deprecated and will be removed in Python 3.6. - """ - args, varargs, varkw, defaults, kwonlyargs, _, ann = inspect.getfullargspec( - func - ) # pylint: disable=no-member - if kwonlyargs or ann: - raise ValueError( - "Function has keyword-only arguments or annotations" - ", use getfullargspec() API which can support them" - ) - return _ArgSpec(args, varargs, varkw, defaults) - - def get_function_argspec(func, is_class_method=None): """ A small wrapper around getargspec that also supports callable classes @@ -283,34 +256,19 @@ def get_function_argspec(func, is_class_method=None): if not callable(func): raise TypeError("{0} is not a callable".format(func)) - if six.PY2: - if is_class_method is True: - aspec = inspect.getargspec(func) - del aspec.args[0] # self - elif inspect.isfunction(func): - aspec = inspect.getargspec(func) - elif inspect.ismethod(func): - aspec = inspect.getargspec(func) - del aspec.args[0] # self - elif isinstance(func, object): - aspec = inspect.getargspec(func.__call__) - del aspec.args[0] # self - else: - raise TypeError("Cannot inspect argument list for '{0}'".format(func)) + if is_class_method is True: + aspec = _getargspec(func) + del aspec.args[0] # self + elif inspect.isfunction(func): + aspec = _getargspec(func) + elif inspect.ismethod(func): + aspec = _getargspec(func) + del aspec.args[0] # self + elif isinstance(func, object): + aspec = _getargspec(func.__call__) + del aspec.args[0] # self else: - if is_class_method is True: - aspec = _getargspec(func) - del aspec.args[0] # self - elif inspect.isfunction(func): - aspec = _getargspec(func) - elif inspect.ismethod(func): - aspec = _getargspec(func) - del aspec.args[0] # self - elif isinstance(func, object): - aspec = _getargspec(func.__call__) - del aspec.args[0] # self - else: - raise TypeError("Cannot inspect argument list for '{0}'".format(func)) + raise TypeError("Cannot inspect argument list for '{0}'".format(func)) return aspec @@ -318,7 +276,7 @@ def shlex_split(s, **kwargs): """ Only split if variable is a string """ - if isinstance(s, six.string_types): + if isinstance(s, str): # On PY2, shlex.split will fail with unicode types if there are # non-ascii characters in the string. So, we need to make sure we # invoke it with a str type, and then decode the resulting string back @@ -400,7 +358,7 @@ def split_input(val, mapper=None): try: return list(map(mapper, [x.strip() for x in val.split(",")])) except AttributeError: - return list(map(mapper, [x.strip() for x in six.text_type(val).split(",")])) + return list(map(mapper, [x.strip() for x in str(val).split(",")])) def test_mode(**kwargs): @@ -412,7 +370,7 @@ def test_mode(**kwargs): # Once is_true is moved, remove this import and fix the ref below import salt.utils - for arg, value in six.iteritems(kwargs): + for arg, value in kwargs.items(): try: if arg.lower() == "test" and salt.utils.data.is_true(value): return True @@ -489,7 +447,7 @@ def format_call( if aspec.keywords: # The function accepts **kwargs, any non expected extra keyword # arguments will made available. - for key, value in six.iteritems(data): + for key, value in data.items(): if key in expected_extra_kws: continue ret["kwargs"][key] = value @@ -501,7 +459,7 @@ def format_call( # Did not return yet? Lets gather any remaining and unexpected keyword # arguments extra = {} - for key, value in six.iteritems(data): + for key, value in data.items(): if key in expected_extra_kws: continue extra[key] = copy.deepcopy(value) @@ -606,7 +564,7 @@ def prepare_kwargs(all_kwargs, class_init_kwargs): """ fun_kwargs = {} init_kwargs = {} - for karg, warg in six.iteritems(all_kwargs): + for karg, warg in all_kwargs.items(): if karg not in class_init_kwargs: if warg is not None: fun_kwargs[karg] = warg diff --git a/salt/utils/network.py b/salt/utils/network.py index cd78172337e1..fa1c29f9394c 100644 --- a/salt/utils/network.py +++ b/salt/utils/network.py @@ -4,10 +4,8 @@ Define some generic socket functions for network modules """ -# Import python libs from __future__ import absolute_import, print_function, unicode_literals -import collections import fnmatch import itertools import logging @@ -18,9 +16,9 @@ import socket import subprocess import types +from collections.abc import Mapping, Sequence from string import ascii_letters, digits -# Import salt libs import salt.utils.args import salt.utils.files import salt.utils.path @@ -29,10 +27,6 @@ import salt.utils.zeromq from salt._compat import ipaddress from salt.exceptions import SaltClientError, SaltSystemExit - -# Import 3rd-party libs -from salt.ext import six -from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin from salt.utils.decorators.jinja import jinja_filter from salt.utils.versions import LooseVersion @@ -416,7 +410,7 @@ def _ip_options(ip_obj, version, options=None): } if not options: - return six.text_type(ip_obj) # IP version already checked + return str(ip_obj) # IP version already checked options_list = [option.strip() for option in options.split(",")] @@ -427,7 +421,7 @@ def _ip_options(ip_obj, version, options=None): return None # stop at first failed test # else continue - return six.text_type(ip_obj) + return str(ip_obj) def _is_ipv(ip_addr, version, options=None): @@ -470,7 +464,7 @@ def is_ipv4_filter(ip_addr, options=None): CSV of options regarding the nature of the IP address. E.g.: loopback, multicast, private etc. """ _is_ipv4 = _is_ipv(ip_addr, 4, options=options) - return isinstance(_is_ipv4, six.string_types) + return isinstance(_is_ipv4, str) @jinja_filter("is_ipv6") @@ -488,7 +482,7 @@ def is_ipv6_filter(ip_addr, options=None): CSV of options regarding the nature of the IP address. E.g.: loopback, multicast, private etc. """ _is_ipv6 = _is_ipv(ip_addr, 6, options=options) - return isinstance(_is_ipv6, six.string_types) + return isinstance(_is_ipv6, str) def _ipv_filter(value, version, options=None): @@ -496,7 +490,7 @@ def _ipv_filter(value, version, options=None): if version not in (4, 6): return - if isinstance(value, (six.string_types, six.text_type, six.binary_type)): + if isinstance(value, (str, bytes)): return _is_ipv( value, version, options=options ) # calls is_ipv4 or is_ipv6 for `value` @@ -568,14 +562,13 @@ def ip_host(value, options=None, version=None): if not ipaddr_filter_out: return if not isinstance(value, (list, tuple, types.GeneratorType)): - return six.text_type(ipaddress.ip_interface(ipaddr_filter_out[0])) - return [six.text_type(ipaddress.ip_interface(ip_a)) for ip_a in ipaddr_filter_out] + return str(ipaddress.ip_interface(ipaddr_filter_out[0])) + return [str(ipaddress.ip_interface(ip_a)) for ip_a in ipaddr_filter_out] def _network_hosts(ip_addr_entry): return [ - six.text_type(host) - for host in ipaddress.ip_network(ip_addr_entry, strict=False).hosts() + str(host) for host in ipaddress.ip_network(ip_addr_entry, strict=False).hosts() ] @@ -1091,7 +1084,7 @@ def get_net_start(ipaddr, netmask): Return the address of the network """ net = ipaddress.ip_network("{0}/{1}".format(ipaddr, netmask), strict=False) - return six.text_type(net.network_address) + return str(net.network_address) def get_net_size(mask): @@ -1114,7 +1107,7 @@ def calc_net(ipaddr, netmask=None): if netmask is not None: ipaddr = "{0}/{1}".format(ipaddr, netmask) - return six.text_type(ipaddress.ip_network(ipaddr, strict=False)) + return str(ipaddress.ip_network(ipaddr, strict=False)) def _ipv4_to_bits(ipaddr): @@ -1219,7 +1212,7 @@ def _subnets(proto="inet", interfaces_=None): ifaces = interfaces() elif isinstance(interfaces_, list): ifaces = {} - for key, value in six.iteritems(interfaces()): + for key, value in interfaces().items(): if key in interfaces_: ifaces[key] = value else: @@ -1237,7 +1230,7 @@ def _subnets(proto="inet", interfaces_=None): log.error("Invalid proto {0} calling subnets()".format(proto)) return - for ip_info in six.itervalues(ifaces): + for ip_info in ifaces.values(): addrs = ip_info.get(proto, []) addrs.extend( [addr for addr in ip_info.get("secondary", []) if addr.get("type") == proto] @@ -1254,7 +1247,7 @@ def _subnets(proto="inet", interfaces_=None): ) if not intf.is_loopback: ret.add(intf.network) - return [six.text_type(net) for net in sorted(ret)] + return [str(net) for net in sorted(ret)] def subnets(interfaces=None): @@ -1295,7 +1288,7 @@ def _get_ips(ifaces, proto="inet"): Accepts a dict of interface data and returns a list of dictionaries """ ret = [] - for ip_info in six.itervalues(ifaces): + for ip_info in ifaces.values(): ret.extend(ip_info.get(proto, [])) ret.extend( [addr for addr in ip_info.get("secondary", []) if addr.get("type") == proto] @@ -1316,7 +1309,7 @@ def _filter_interfaces(interface=None, interface_data=None): # pylint: disable=not-an-iterable ret = { k: v - for k, v in six.iteritems(ifaces) + for k, v in ifaces.items() if any((fnmatch.fnmatch(k, pat) for pat in interface)) } # pylint: enable=not-an-iterable @@ -1339,7 +1332,7 @@ def _ip_addrs( if not addr.is_loopback or include_loopback: ret.add(addr) - return [six.text_type(addr) for addr in sorted(ret)] + return [str(addr) for addr in sorted(ret)] def ip_addrs(interface=None, include_loopback=False, interface_data=None): @@ -1386,12 +1379,12 @@ def _ip_networks( ret.add(ip_net) if not verbose: - return [six.text_type(addr) for addr in sorted(ret)] + return [str(addr) for addr in sorted(ret)] verbose_ret = { - six.text_type(x): { - "address": six.text_type(x.network_address), - "netmask": six.text_type(x.netmask), + str(x): { + "address": str(x.network_address), + "netmask": str(x.netmask), "num_addresses": x.num_addresses, "prefixlen": x.prefixlen, } @@ -2041,7 +2034,7 @@ def mac_str_to_bytes(mac_str): else: raise ValueError("Invalid MAC address") chars = (int(mac_str[s : s + 2], 16) for s in range(0, 12, 2)) - return bytes(chars) if six.PY3 else b"".join(chr(x) for x in chars) + return bytes(chars) def refresh_dns(): @@ -2199,11 +2192,11 @@ def filter_by_networks(values, networks): if networks is not None: networks = [ipaddress.ip_network(network) for network in networks] - if isinstance(values, collections.Mapping): + if isinstance(values, Mapping): return { interface: _filter(values[interface], networks) for interface in values } - elif isinstance(values, collections.Sequence): + elif isinstance(values, Sequence): return _filter(values, networks) else: raise ValueError("Do not know how to filter a {}".format(type(values))) diff --git a/salt/utils/nxos.py b/salt/utils/nxos.py index 1d520dd9cc9d..07152a9630c0 100644 --- a/salt/utils/nxos.py +++ b/salt/utils/nxos.py @@ -18,15 +18,15 @@ """ from __future__ import absolute_import, print_function, unicode_literals -# Import Python std lib import collections +import http.client import json import logging import os import re import socket +from collections.abc import Iterable -# Import salt libs import salt.utils.http from salt.exceptions import ( CommandExecutionError, @@ -34,27 +34,18 @@ NxosError, NxosRequestNotSupported, ) -from salt.ext.six.moves import zip from salt.utils.args import clean_kwargs -# Disable pylint check since httplib is not available in python3 -try: - import httplib # pylint: disable=W1699 -except ImportError: - import http.client - - httplib = http.client - log = logging.getLogger(__name__) -class UHTTPConnection(httplib.HTTPConnection): # pylint: disable=W1699 +class UHTTPConnection(http.client.HTTPConnection): """ Subclass of Python library HTTPConnection that uses a unix-domain socket. """ def __init__(self, path): - httplib.HTTPConnection.__init__(self, "localhost") + http.client.HTTPConnection.__init__(self, "localhost") self.path = path def connect(self): @@ -211,13 +202,13 @@ def parse_response(self, response, command_list): Parse NX-API JSON response from the NX-OS device. """ # Check for 500 level NX-API Server Errors - if isinstance(response, collections.Iterable) and "status" in response: + if isinstance(response, Iterable) and "status" in response: if int(response["status"]) >= 500: raise NxosError("{}".format(response)) else: raise NxosError("NX-API Request Not Supported: {}".format(response)) - if isinstance(response, collections.Iterable): + if isinstance(response, Iterable): body = response["dict"] else: body = response diff --git a/salt/wheel/__init__.py b/salt/wheel/__init__.py index 9029b6edf2e4..38792a10f6cd 100644 --- a/salt/wheel/__init__.py +++ b/salt/wheel/__init__.py @@ -2,13 +2,10 @@ """ Modules used to control the master itself """ - -# Import Python libs from __future__ import absolute_import, print_function, unicode_literals -import collections +from collections.abc import Mapping -# Import salt libs import salt.client.mixins import salt.config import salt.loader @@ -16,9 +13,6 @@ import salt.utils.error import salt.utils.zeromq -# Import 3rd-party libs -from salt.ext import six - class WheelClient( salt.client.mixins.SyncClientMixin, salt.client.mixins.AsyncClientMixin, object @@ -76,15 +70,14 @@ def master_call(self, **kwargs): if interface == "0.0.0.0": interface = "127.0.0.1" master_uri = "tcp://{}:{}".format( - salt.utils.zeromq.ip_bracket(interface), - six.text_type(self.opts["ret_port"]), + salt.utils.zeromq.ip_bracket(interface), str(self.opts["ret_port"]), ) with salt.transport.client.ReqChannel.factory( self.opts, crypt="clear", master_uri=master_uri, usage="master_call" ) as channel: ret = channel.send(load) - if isinstance(ret, collections.Mapping): + if isinstance(ret, Mapping): if "error" in ret: salt.utils.error.raise_error(**ret["error"])