- py3k compatibility by replacing 'basestring'

- add 'salt._compat' module
This commit is contained in:
L.C. Rees 2012-05-30 14:46:09 -06:00
parent 1d2c0364f4
commit 38f6c2030d
21 changed files with 228 additions and 51 deletions

155
salt/_compat.py Normal file
View File

@ -0,0 +1,155 @@
import sys
import types
try:
import cPickle as pickle
except ImportError:
import pickle
# True if we are running on Python 3.
PY3 = sys.version_info[0] == 3
if PY3:
string_types = str,
integer_types = int,
class_types = type,
text_type = str
binary_type = bytes
long = int
else:
string_types = basestring,
integer_types = (int, long)
class_types = (type, types.ClassType)
text_type = unicode
binary_type = str
long = long
if PY3:
range = range
else:
range = xrange
if PY3:
def callable(obj):
return any('__call__' in klass.__dict__ for klass in type(obj).__mro__)
else:
callable = callable
def text_(s, encoding='latin-1', errors='strict'):
""" If ``s`` is an instance of ``binary_type``, return
``s.decode(encoding, errors)``, otherwise return ``s``"""
if isinstance(s, binary_type):
return s.decode(encoding, errors)
return s
def bytes_(s, encoding='latin-1', errors='strict'):
""" If ``s`` is an instance of ``text_type``, return
``s.encode(encoding, errors)``, otherwise return ``s``"""
if isinstance(s, text_type):
return s.encode(encoding, errors)
return s
if PY3:
def ascii_native_(s):
if isinstance(s, text_type):
s = s.encode('ascii')
return str(s, 'ascii', 'strict')
else:
def ascii_native_(s):
if isinstance(s, text_type):
s = s.encode('ascii')
return str(s)
ascii_native_.__doc__ = """
Python 3: If ``s`` is an instance of ``text_type``, return
``s.encode('ascii')``, otherwise return ``str(s, 'ascii', 'strict')``
Python 2: If ``s`` is an instance of ``text_type``, return
``s.encode('ascii')``, otherwise return ``str(s)``
"""
if PY3:
def native_(s, encoding='latin-1', errors='strict'):
""" If ``s`` is an instance of ``text_type``, return
``s``, otherwise return ``str(s, encoding, errors)``"""
if isinstance(s, text_type):
return s
return str(s, encoding, errors)
else:
def native_(s, encoding='latin-1', errors='strict'):
""" If ``s`` is an instance of ``text_type``, return
``s.encode(encoding, errors)``, otherwise return ``str(s)``"""
if isinstance(s, text_type):
return s.encode(encoding, errors)
return str(s)
native_.__doc__ = """
Python 3: If ``s`` is an instance of ``text_type``, return ``s``, otherwise
return ``str(s, encoding, errors)``
Python 2: If ``s`` is an instance of ``text_type``, return
``s.encode(encoding, errors)``, otherwise return ``str(s)``
"""
if PY3:
from urllib import parse
from urllib.error import URLError
import http.server as BaseHTTPServer
from urllib.error import HTTPError
urlparse = parse
from urllib.parse import quote as url_quote
from urllib.parse import quote_plus as url_quote_plus
from urllib.parse import unquote as url_unquote
from urllib.parse import urlencode as url_encode
from urllib.request import urlopen as url_open
url_unquote_text = url_unquote
url_unquote_native = url_unquote
else:
from urlparse import urlparse
import BaseHTTPServer
from urllib2 import HTTPError, URLError
from urllib import quote as url_quote
from urllib import quote_plus as url_quote_plus
from urllib import unquote as url_unquote
from urllib import urlencode as url_encode
from urllib2 import urlopen as url_open
def url_unquote_text(v, encoding='utf-8', errors='replace'):
v = url_unquote(v)
return v.decode(encoding, errors)
def url_unquote_native(v, encoding='utf-8', errors='replace'):
return native_(url_unquote_text(v, encoding, errors))
if PY3:
def iteritems_(d):
return d.items()
def itervalues_(d):
return d.values()
def iterkeys_(d):
return d.keys()
else:
def iteritems_(d):
return d.iteritems()
def itervalues_(d):
return d.itervalues()
def iterkeys_(d):
return d.iterkeys()
if PY3:
zip = zip
else:
from future_builtins import zip
if PY3:
from io import StringIO
else:
from StringIO import StringIO

View File

@ -13,6 +13,7 @@ import salt
import salt.utils
import salt.loader
import salt.minion
from salt._compat import string_types
# Custom exceptions
from salt.exceptions import CommandExecutionError, CommandNotFoundError
@ -55,7 +56,7 @@ class Caller(object):
sys.exit(1)
if hasattr(self.minion.functions[fun], '__outputter__'):
oput = self.minion.functions[fun].__outputter__
if isinstance(oput, basestring):
if isinstance(oput, string_types):
ret['out'] = oput
return ret

View File

@ -26,6 +26,7 @@ import salt.crypt
import salt.loader
import salt.utils
import salt.payload
from salt._compat import string_types
from salt.utils.debug import enable_sigusr1_handler
log = logging.getLogger(__name__)
@ -68,7 +69,7 @@ def detect_kwargs(func, args, data=None):
_args = []
kwargs = {}
for arg in args:
if isinstance(arg, basestring):
if isinstance(arg, string_types):
if '=' in arg:
comps = arg.split('=')
if has_kwargs:
@ -226,7 +227,7 @@ class Minion(object):
Override this method if you wish to handle the decoded data
differently.
'''
if isinstance(data['fun'], basestring):
if isinstance(data['fun'], string_types):
if data['fun'] == 'sys.reload_modules':
self.functions, self.returners = self.__load_modules()
@ -265,7 +266,7 @@ class Minion(object):
arg = eval(data['arg'][ind])
if isinstance(arg, bool):
data['arg'][ind] = str(data['arg'][ind])
elif isinstance(arg, (dict, int, list, basestring)):
elif isinstance(arg, (dict, int, list, string_types)):
data['arg'][ind] = arg
else:
data['arg'][ind] = str(data['arg'][ind])
@ -326,7 +327,7 @@ class Minion(object):
arg = eval(data['arg'][ind][index])
if isinstance(arg, bool):
data['arg'][ind][index] = str(data['arg'][ind][index])
elif isinstance(arg, (dict, int, list, basestring)):
elif isinstance(arg, (dict, int, list, string_types)):
data['arg'][ind][index] = arg
else:
data['arg'][ind][index] = str(data['arg'][ind][index])
@ -394,7 +395,7 @@ class Minion(object):
try:
if hasattr(self.functions[ret['fun']], '__outputter__'):
oput = self.functions[ret['fun']].__outputter__
if isinstance(oput, basestring):
if isinstance(oput, string_types):
load['out'] = oput
except KeyError:
pass
@ -402,7 +403,7 @@ class Minion(object):
data = self.serial.dumps(payload)
socket.send(data)
ret_val = self.serial.loads(socket.recv())
if isinstance(ret_val, basestring) and not ret_val:
if isinstance(ret_val, string_types) and not ret_val:
# The master AES key has changed, reauth
self.authenticate()
payload['load'] = self.crypticle.dumps(load)
@ -655,7 +656,7 @@ class Matcher(object):
'''
Determines if this host is on the list
'''
if isinstance(tgt, basestring):
if isinstance(tgt, string_types):
tgt = tgt.split(',')
return bool(self.opts['id'] in tgt)
@ -740,7 +741,7 @@ class Matcher(object):
'''
Runs the compound target check
'''
if not isinstance(tgt, basestring):
if not isinstance(tgt, string_types):
log.debug('Compound target received that is not a string')
return False
ref = {'G': 'grain',

View File

@ -4,6 +4,7 @@ Module for viewing and modifying sysctl parameters
import re
import os
from salt._compat import string_types
from salt.exceptions import CommandExecutionError
__outputter__ = {
@ -116,11 +117,11 @@ def persist(name, value, config='/etc/sysctl.conf'):
# other sysctl with whitespace in it consistently uses 1 tab. Lets
# allow our users to put a space or tab between multi-value sysctls
# and have salt not try to set it every single time.
if isinstance(comps[1], basestring) and ' ' in comps[1]:
if isinstance(comps[1], string_types) and ' ' in comps[1]:
comps[1] = re.sub('\s+', '\t', comps[1])
# Do the same thing for the value 'just in case'
if isinstance(value, basestring) and ' ' in value:
if isinstance(value, string_types) and ' ' in value:
value = re.sub('\s+', '\t', value)
if len(comps) < 2:

View File

@ -5,6 +5,8 @@ Salt module to manage unix mounts and the fstab file
import logging
import os
from salt._compat import string_types
# Set up logger
log = logging.getLogger(__name__)
@ -194,7 +196,7 @@ def mount(name, device, mkmnt=False, fstype='', opts='defaults'):
salt '*' mount.mount /mnt/foo /dev/sdz1 True
'''
if isinstance(opts, basestring):
if isinstance(opts, string_types):
opts = opts.split(',')
if not os.path.exists(name) and mkmnt:
os.makedirs(name)
@ -217,7 +219,7 @@ def remount(name, device, mkmnt=False, fstype='', opts='defaults'):
salt '*' mount.remount /mnt/foo /dev/sdz1 True
'''
if isinstance(opts, basestring):
if isinstance(opts, string_types):
opts = opts.split(',')
mnts = active()
if name in mnts:

View File

@ -7,6 +7,7 @@ import ast
import salt.crypt
import salt.payload
from salt._compat import string_types
def _get_socket():
@ -56,7 +57,7 @@ def _publish(
if isinstance(ast.literal_eval(arg), dict):
arg = [arg,]
except:
if isinstance(arg, basestring):
if isinstance(arg, string_types):
arg = arg.split(',')
auth = salt.crypt.SAuth(__opts__)
@ -129,7 +130,7 @@ def runner(fun, arg=None):
if isinstance(ast.literal_eval(arg), dict):
arg = [arg,]
except:
if isinstance(arg, basestring):
if isinstance(arg, string_types):
arg = arg.split(',')
auth = salt.crypt.SAuth(__opts__)

View File

@ -6,6 +6,8 @@ import grp
import os
import pwd
from salt._compat import string_types
def __virtual__():
'''
@ -29,7 +31,7 @@ def add(name,
salt '*' user.add name <uid> <gid> <groups> <home> <shell>
'''
if isinstance(groups, basestring):
if isinstance(groups, string_types):
groups = groups.split(',')
cmd = 'pw useradd '
if shell:
@ -172,7 +174,7 @@ def chgroups(name, groups, append=False):
salt '*' user.chgroups foo wheel,root True
'''
if isinstance(groups, basestring):
if isinstance(groups, string_types):
groups = groups.split(',')
ugrps = set(list_groups(name))
if ugrps == set(groups):

View File

@ -12,6 +12,7 @@ import logging
# Import Salt libs
import salt.payload
from salt._compat import string_types
log = logging.getLogger(__name__)
@ -19,7 +20,7 @@ def _sync(form, env):
'''
Sync the given directory in the given environment
'''
if isinstance(env, basestring):
if isinstance(env, string_types):
env = env.split(',')
ret = []
remote = set()

View File

@ -6,6 +6,7 @@ import os
# Import salt libs
import salt.utils
from salt._compat import string_types
__selinux_fs_path__ = None
@ -65,7 +66,7 @@ def setenforce(mode):
salt '*' selinux.setenforce enforcing
'''
if isinstance(mode, basestring):
if isinstance(mode, string_types):
if mode.lower() == 'enforcing':
mode = '1'
elif mode.lower() == 'permissive':

View File

@ -66,6 +66,7 @@ import os
# Import Salt libs
import salt.utils
from salt._compat import string_types
#sane defaults
__opts__ = {'solr.cores': [],
@ -113,7 +114,7 @@ def _get_none_or_value(value):
elif not value:
return value
# if it's a string, and it's not empty check for none
elif isinstance(value, basestring):
elif isinstance(value, string_types):
if value.lower() == 'none':
return None
return value

View File

@ -8,7 +8,7 @@ import os
# Import Salt libs
import salt.state
from salt._compat import string_types
__outputter__ = {
'highstate': 'highstate',
@ -101,7 +101,7 @@ def sls(mods, env='base', test=None, **kwargs):
opts['test'] = test
salt.utils.daemonize_if(opts, **kwargs)
st_ = salt.state.HighState(opts)
if isinstance(mods, basestring):
if isinstance(mods, string_types):
mods = mods.split(',')
high, errors = st_.render_highstate({env: mods})
if errors:

View File

@ -4,6 +4,7 @@ Manage users with the useradd command
import grp
import pwd
from salt._compat import string_types
def __virtual__():
@ -41,7 +42,7 @@ def add(name,
salt '*' user.add name <uid> <gid> <groups> <home> <shell>
'''
if isinstance(groups, basestring):
if isinstance(groups, string_types):
groups = groups.split(',')
cmd = 'useradd '
if shell:
@ -211,7 +212,7 @@ def chgroups(name, groups, append=False):
salt '*' user.chgroups foo wheel,root True
'''
if isinstance(groups, basestring):
if isinstance(groups, string_types):
groups = groups.split(',')
ugrps = set(list_groups(name))
if ugrps == set(groups):

View File

@ -4,6 +4,9 @@ Manage Windows users with the net user command
NOTE: This currently only works with local user accounts, not domain accounts
'''
from salt._compat import string_types
def __virtual__():
'''
Set the user module if the kernel is Windows
@ -142,7 +145,7 @@ def chgroups(name, groups, append=False):
salt '*' user.chgroups foo wheel,root True
'''
if isinstance(groups, basestring):
if isinstance(groups, string_types):
groups = groups.split(',')
ugrps = set(list_groups(name))
if ugrps == set(groups):

View File

@ -16,6 +16,7 @@ except:
# Import Salt libs
import salt.utils
from salt._compat import string_types
from salt.exceptions import SaltException
__all__ = ('get_outputter',)
@ -130,7 +131,7 @@ class HighStateOutputter(Outputter):
))
changes = ' Changes: '
for key in ret['changes']:
if isinstance(ret['changes'][key], basestring):
if isinstance(ret['changes'][key], string_types):
changes += (key + ': ' + ret['changes'][key] +
'\n ')
elif isinstance(ret['changes'][key], dict):

View File

@ -4,7 +4,7 @@ encrypted keys to general payload dynamics and packaging, these happen
in here
'''
import pickle
from salt._compat import pickle
try:
# Attempt to import msgpack

View File

@ -14,7 +14,7 @@ import salt.loader
import salt.fileclient
import salt.minion
import salt.crypt
from salt._compat import string_types
from salt.template import compile_template
# Import third party libs
@ -32,7 +32,7 @@ def hiera(conf, grains=None):
grains = {}
cmd = 'hiera {0}'.format(conf)
for key, val in grains.items():
if isinstance(val, basestring):
if isinstance(val, string_types):
cmd += ' {0}={1}'.format(key, val)
out = subprocess.Popen(
cmd,
@ -235,7 +235,7 @@ class Pillar(object):
for comp in top[env][tgt]:
if isinstance(comp, dict):
matches.append(comp)
if isinstance(comp, basestring):
if isinstance(comp, string_types):
states.add(comp)
top[env][tgt] = matches
top[env][tgt].extend(list(states))
@ -270,7 +270,7 @@ class Pillar(object):
if env not in matches:
matches[env] = []
for item in data:
if isinstance(item, basestring):
if isinstance(item, string_types):
matches[env].append(item)
ext_matches = self.client.ext_nodes()
for env in ext_matches:

View File

@ -9,6 +9,7 @@ import os
import salt.client
import salt.payload
import salt.utils
from salt._compat import string_types
from salt.exceptions import SaltException
# Import Third party libs
@ -83,7 +84,7 @@ def lookup_jid(jid):
# Determine the proper output method and run it
get_outputter = salt.output.get_outputter
if isinstance(ret, (list, dict, basestring)) and out:
if isinstance(ret, (list, dict, string_types)) and out:
printout = get_outputter(out)
# Pretty print any salt exceptions
elif isinstance(ret, SaltException):

View File

@ -29,6 +29,7 @@ import salt.loader
import salt.minion
import salt.pillar
import salt.fileclient
from salt._compat import string_types
from salt.template import (
compile_template,
@ -128,7 +129,7 @@ def format_log(ret):
msg = 'No changes made for {0[name]}'.format(ret)
elif isinstance(chg, dict):
if 'diff' in chg:
if isinstance(chg['diff'], basestring):
if isinstance(chg['diff'], string_types):
msg = 'File changed:\n{0}'.format(
chg['diff'])
if isinstance(chg[chg.keys()[0]], dict):
@ -293,7 +294,7 @@ class State(object):
errors.append('Missing "fun" data')
if 'name' not in data:
errors.append('Missing "name" data')
if not isinstance(data['name'], basestring):
if not isinstance(data['name'], string_types):
err = ('The name {0} in sls {1} is not formed as a '
'string but is a {2}').format(
data['name'], data['__sls__'], type(data['name']))
@ -372,7 +373,7 @@ class State(object):
for name, body in high.items():
if name.startswith('__'):
continue
if not isinstance(name, basestring):
if not isinstance(name, string_types):
err = ('The name {0} in sls {1} is not formed as a '
'string but is a {2}').format(
name, body['__sls__'], type(name))
@ -394,7 +395,7 @@ class State(object):
if '.' in state:
fun += 1
for arg in body[state]:
if isinstance(arg, basestring):
if isinstance(arg, string_types):
fun += 1
if ' ' in arg.strip():
errors.append(('The function "{0}" in state '
@ -578,7 +579,7 @@ class State(object):
chunk['__env__'] = body['__env__']
chunk['__id__'] = name
for arg in run:
if isinstance(arg, basestring):
if isinstance(arg, string_types):
funcs.add(arg)
continue
if isinstance(arg, dict):
@ -630,8 +631,8 @@ class State(object):
for arg in run:
update = False
for hind in range(len(high[name][state])):
if isinstance(arg, basestring) and \
isinstance(high[name][state][hind], basestring):
if isinstance(arg, string_types) and \
isinstance(high[name][state][hind], string_types):
# replacing the function, replace the index
high[name][state].pop(hind)
high[name][state].insert(hind, arg)
@ -1160,7 +1161,7 @@ class BaseHighState(object):
for comp in top[env][tgt]:
if isinstance(comp, dict):
matches.append(comp)
if isinstance(comp, basestring):
if isinstance(comp, string_types):
states.add(comp)
top[env][tgt] = matches
top[env][tgt].extend(list(states))
@ -1178,7 +1179,7 @@ class BaseHighState(object):
for env, matches in tops.items():
if env == 'include':
continue
if not isinstance(env, basestring):
if not isinstance(env, string_types):
err = ('Environment {0} in top file is not formed as a '
'string').format(env)
errors.append(err)
@ -1201,7 +1202,7 @@ class BaseHighState(object):
)
)
errors.append(err)
elif isinstance(slsmod, basestring):
elif isinstance(slsmod, string_types):
# This is a sls module
if not slsmod:
err = ('Environment {0} contains an empty sls '
@ -1239,7 +1240,7 @@ class BaseHighState(object):
if env not in matches:
matches[env] = []
for item in data:
if isinstance(item, basestring):
if isinstance(item, string_types):
matches[env].append(item)
ext_matches = self.client.ext_nodes()
for env in ext_matches:
@ -1335,7 +1336,7 @@ class BaseHighState(object):
if name == '__extend__':
continue
if isinstance(state[name], basestring):
if isinstance(state[name], string_types):
# Is this is a short state, it needs to be padded
if '.' in state[name]:
comps = state[name].split('.')

View File

@ -88,6 +88,7 @@ import copy
# Import Salt libs
import salt.utils.templates
from salt._compat import string_types
logger = logging.getLogger(__name__)
@ -244,7 +245,7 @@ def _source_list(source, source_hash, env):
source = single_src
source_hash = single_hash
break
elif isinstance(single, basestring):
elif isinstance(single, string_types):
if single in mfiles:
source = single
break
@ -1253,7 +1254,7 @@ def recurse(name,
The permissions mode to set any files created
include_empty
Set this to True if empty directories should also be created
Set this to True if empty directories should also be created
(default is False)
'''
ret = {'name': name,
@ -1338,7 +1339,7 @@ def recurse(name,
keep.add(dest)
if os.path.isdir(fn_) and include_empty:
#create empty dir
os.mkdir(dest,dir_mode)
os.mkdir(dest, dir_mode)
else:
# The destination file is not present, make it
# FIXME: no metadata (ownership, permissions) available
@ -1554,7 +1555,7 @@ def append(name, text):
if not check_res:
return _error(ret, check_msg)
if isinstance(text, basestring):
if isinstance(text, string_types):
text = (text,)
for chunk in text:

View File

@ -16,6 +16,8 @@ Mount any type of mountable filesystem with the mounted function:
- defaults
'''
from salt._compat import string_types
def mounted(
name,
@ -71,7 +73,7 @@ def mounted(
# Make sure that opts is correct, it can be a list or a comma delimited
# string
if isinstance(opts, basestring):
if isinstance(opts, string_types):
opts = opts.split(',')
# Get the active data
@ -84,7 +86,7 @@ def mounted(
'be').format(name)
return ret
out = __salt__['mount.mount'](name, device, mkmnt, fstype, opts)
if isinstance(out, basestring):
if isinstance(out, string_types):
# Failed to remount, the state has failed!
ret['comment'] = out
ret['result'] = False

View File

@ -6,6 +6,7 @@ import os
import tempfile
import salt.utils
from salt._compat import string_types
def compile_template(template, renderers, default, env='', sls=''):
@ -14,7 +15,7 @@ def compile_template(template, renderers, default, env='', sls=''):
derived from the template.
'''
# Template was specified incorrectly
if not isinstance(template, basestring):
if not isinstance(template, string_types):
return {}
# Template does not exists
if not os.path.isfile(template):