mirror of
https://github.com/YunoHost/moulinette.git
synced 2024-09-03 20:06:31 +02:00
[mod] autopep8
This commit is contained in:
parent
c0291ff479
commit
897ad08183
14 changed files with 192 additions and 163 deletions
|
@ -32,7 +32,7 @@ __all__ = [
|
|||
from moulinette.core import init_interface, MoulinetteError
|
||||
|
||||
|
||||
## Package functions
|
||||
# Package functions
|
||||
|
||||
def init(logging_config=None, **kwargs):
|
||||
"""Package initialization
|
||||
|
@ -68,7 +68,7 @@ def init(logging_config=None, **kwargs):
|
|||
sys.path.insert(0, pkg.libdir)
|
||||
|
||||
|
||||
## Easy access to interfaces
|
||||
# Easy access to interfaces
|
||||
|
||||
def api(namespaces, host='localhost', port=80, routes={},
|
||||
use_websocket=True, use_cache=True):
|
||||
|
@ -108,6 +108,7 @@ def api(namespaces, host='localhost', port=80, routes={},
|
|||
logging.getLogger(namespaces[0]).info(m18n.g('operation_interrupted'))
|
||||
return 0
|
||||
|
||||
|
||||
def cli(namespaces, args, use_cache=True, output_as=None,
|
||||
password=None, timeout=None, parser_kwargs={}):
|
||||
"""Command line interface
|
||||
|
|
|
@ -18,7 +18,7 @@ from moulinette.utils.log import start_action_logging
|
|||
logger = logging.getLogger('moulinette.actionsmap')
|
||||
|
||||
|
||||
## Extra parameters ----------------------------------------------------
|
||||
# Extra parameters ----------------------------------------------------
|
||||
|
||||
# Extra parameters definition
|
||||
|
||||
|
@ -30,26 +30,24 @@ class _ExtraParameter(object):
|
|||
implement.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, iface):
|
||||
# TODO: Add conn argument which contains authentification object
|
||||
self.iface = iface
|
||||
|
||||
|
||||
## Required variables
|
||||
# Required variables
|
||||
# Each extra parameters classes must overwrite these variables.
|
||||
|
||||
"""The extra parameter name"""
|
||||
name = None
|
||||
|
||||
|
||||
## Optional variables
|
||||
# Optional variables
|
||||
# Each extra parameters classes can overwrite these variables.
|
||||
|
||||
"""A list of interface for which the parameter doesn't apply"""
|
||||
skipped_iface = []
|
||||
|
||||
|
||||
## Virtual methods
|
||||
# Virtual methods
|
||||
# Each extra parameters classes can implement these methods.
|
||||
|
||||
def __call__(self, parameter, arg_name, arg_value):
|
||||
|
@ -82,6 +80,7 @@ class _ExtraParameter(object):
|
|||
"""
|
||||
return value
|
||||
|
||||
|
||||
class AskParameter(_ExtraParameter):
|
||||
"""
|
||||
Ask for the argument value if possible and needed.
|
||||
|
@ -91,7 +90,7 @@ class AskParameter(_ExtraParameter):
|
|||
|
||||
"""
|
||||
name = 'ask'
|
||||
skipped_iface = [ 'api' ]
|
||||
skipped_iface = ['api']
|
||||
|
||||
def __call__(self, message, arg_name, arg_value):
|
||||
if arg_value:
|
||||
|
@ -107,14 +106,15 @@ class AskParameter(_ExtraParameter):
|
|||
def validate(klass, value, arg_name):
|
||||
# Deprecated boolean or empty string
|
||||
if isinstance(value, bool) or (isinstance(value, str) and not value):
|
||||
logger.warning("expecting a string for extra parameter '%s' of " \
|
||||
logger.warning("expecting a string for extra parameter '%s' of "
|
||||
"argument '%s'", klass.name, arg_name)
|
||||
value = arg_name
|
||||
elif not isinstance(value, str):
|
||||
raise TypeError("parameter value must be a string, got %r" \
|
||||
% value)
|
||||
raise TypeError("parameter value must be a string, got %r"
|
||||
% value)
|
||||
return value
|
||||
|
||||
|
||||
class PasswordParameter(AskParameter):
|
||||
"""
|
||||
Ask for the password argument value if possible and needed.
|
||||
|
@ -135,6 +135,7 @@ class PasswordParameter(AskParameter):
|
|||
except NotImplementedError:
|
||||
return arg_value
|
||||
|
||||
|
||||
class PatternParameter(_ExtraParameter):
|
||||
"""
|
||||
Check if the argument value match a pattern.
|
||||
|
@ -172,14 +173,15 @@ class PatternParameter(_ExtraParameter):
|
|||
def validate(value, arg_name):
|
||||
# Deprecated string type
|
||||
if isinstance(value, str):
|
||||
logger.warning("expecting a list for extra parameter 'pattern' of " \
|
||||
logger.warning("expecting a list for extra parameter 'pattern' of "
|
||||
"argument '%s'", arg_name)
|
||||
value = [value, 'pattern_not_match']
|
||||
elif not isinstance(value, list) or len(value) != 2:
|
||||
raise TypeError("parameter value must be a list, got %r" \
|
||||
% value)
|
||||
raise TypeError("parameter value must be a list, got %r"
|
||||
% value)
|
||||
return value
|
||||
|
||||
|
||||
class RequiredParameter(_ExtraParameter):
|
||||
"""
|
||||
Check if a required argument is defined or not.
|
||||
|
@ -201,8 +203,8 @@ class RequiredParameter(_ExtraParameter):
|
|||
@staticmethod
|
||||
def validate(value, arg_name):
|
||||
if not isinstance(value, bool):
|
||||
raise TypeError("parameter value must be a list, got %r" \
|
||||
% value)
|
||||
raise TypeError("parameter value must be a list, got %r"
|
||||
% value)
|
||||
return value
|
||||
|
||||
"""
|
||||
|
@ -210,11 +212,12 @@ The list of available extra parameters classes. It will keep to this list
|
|||
order on argument parsing.
|
||||
|
||||
"""
|
||||
extraparameters_list = [ AskParameter, PasswordParameter, RequiredParameter,
|
||||
PatternParameter ]
|
||||
extraparameters_list = [AskParameter, PasswordParameter, RequiredParameter,
|
||||
PatternParameter]
|
||||
|
||||
# Extra parameters argument Parser
|
||||
|
||||
|
||||
class ExtraArgumentParser(object):
|
||||
"""
|
||||
Argument validator and parser for the extra parameters.
|
||||
|
@ -223,6 +226,7 @@ class ExtraArgumentParser(object):
|
|||
- iface -- The running interface
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, iface):
|
||||
self.iface = iface
|
||||
self.extra = OrderedDict()
|
||||
|
@ -255,7 +259,7 @@ class ExtraArgumentParser(object):
|
|||
# Validate parameter value
|
||||
parameters[p] = klass.validate(v, arg_name)
|
||||
except Exception as e:
|
||||
logger.error("unable to validate extra parameter '%s' " \
|
||||
logger.error("unable to validate extra parameter '%s' "
|
||||
"for argument '%s': %s", p, arg_name, e)
|
||||
raise MoulinetteError(errno.EINVAL, m18n.g('error_see_log'))
|
||||
|
||||
|
@ -320,7 +324,7 @@ class ExtraArgumentParser(object):
|
|||
return args
|
||||
|
||||
|
||||
## Main class ----------------------------------------------------------
|
||||
# Main class ----------------------------------------------------------
|
||||
|
||||
def ordered_yaml_load(stream):
|
||||
class OrderedLoader(yaml.Loader):
|
||||
|
@ -353,6 +357,7 @@ class ActionsMap(object):
|
|||
class at construction
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, parser_class, namespaces=[], use_cache=True,
|
||||
parser_kwargs={}):
|
||||
if not issubclass(parser_class, BaseActionsMapParser):
|
||||
|
@ -540,8 +545,7 @@ class ActionsMap(object):
|
|||
|
||||
return actionsmaps
|
||||
|
||||
|
||||
## Private methods
|
||||
# Private methods
|
||||
|
||||
def _construct_parser(self, actionsmaps, **kwargs):
|
||||
"""
|
||||
|
@ -557,19 +561,21 @@ class ActionsMap(object):
|
|||
An interface relevant's parser object
|
||||
|
||||
"""
|
||||
## Get extra parameters
|
||||
# Get extra parameters
|
||||
if not self.use_cache:
|
||||
validate_extra = True
|
||||
else:
|
||||
validate_extra = False
|
||||
|
||||
## Add arguments to the parser
|
||||
# Add arguments to the parser
|
||||
def _add_arguments(tid, parser, arguments):
|
||||
for argn, argp in arguments.items():
|
||||
names = top_parser.format_arg_names(str(argn),
|
||||
argp.pop('full', None))
|
||||
try: argp['type'] = eval(argp['type'])
|
||||
except: pass
|
||||
try:
|
||||
argp['type'] = eval(argp['type'])
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
extra = argp.pop('extra')
|
||||
|
@ -612,7 +618,7 @@ class ActionsMap(object):
|
|||
actions = cp.pop('actions')
|
||||
except KeyError:
|
||||
# Invalid category without actions
|
||||
logger.warning("no actions found in category '%s' in " \
|
||||
logger.warning("no actions found in category '%s' in "
|
||||
"namespace '%s'", cn, n)
|
||||
continue
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ class BaseAuthenticator(object):
|
|||
- name -- The authenticator profile name
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, name):
|
||||
self._name = name
|
||||
|
||||
|
@ -35,8 +36,7 @@ class BaseAuthenticator(object):
|
|||
"""Return the name of the authenticator instance"""
|
||||
return self._name
|
||||
|
||||
|
||||
## Virtual properties
|
||||
# Virtual properties
|
||||
# Each authenticator classes must implement these properties.
|
||||
|
||||
"""The vendor name of the authenticator"""
|
||||
|
@ -45,11 +45,10 @@ class BaseAuthenticator(object):
|
|||
@property
|
||||
def is_authenticated(self):
|
||||
"""Either the instance is authenticated or not"""
|
||||
raise NotImplementedError("derived class '%s' must override this property" % \
|
||||
self.__class__.__name__)
|
||||
raise NotImplementedError("derived class '%s' must override this property" %
|
||||
self.__class__.__name__)
|
||||
|
||||
|
||||
## Virtual methods
|
||||
# Virtual methods
|
||||
# Each authenticator classes must implement these methods.
|
||||
|
||||
def authenticate(password=None):
|
||||
|
@ -62,11 +61,10 @@ class BaseAuthenticator(object):
|
|||
- password -- A clear text password
|
||||
|
||||
"""
|
||||
raise NotImplementedError("derived class '%s' must override this method" % \
|
||||
self.__class__.__name__)
|
||||
raise NotImplementedError("derived class '%s' must override this method" %
|
||||
self.__class__.__name__)
|
||||
|
||||
|
||||
## Authentication methods
|
||||
# Authentication methods
|
||||
|
||||
def __call__(self, password=None, token=None):
|
||||
"""Attempt to authenticate
|
||||
|
@ -127,8 +125,7 @@ class BaseAuthenticator(object):
|
|||
|
||||
return self
|
||||
|
||||
|
||||
## Private methods
|
||||
# Private methods
|
||||
|
||||
def _open_sessionfile(self, session_id, mode='r'):
|
||||
"""Open a session file for this instance in given mode"""
|
||||
|
|
|
@ -28,8 +28,9 @@ class Authenticator(BaseAuthenticator):
|
|||
- user_rdn -- The user rdn to authenticate
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, name, uri, base_dn, user_rdn=None):
|
||||
logger.debug("initialize authenticator '%s' with: uri='%s', " \
|
||||
logger.debug("initialize authenticator '%s' with: uri='%s', "
|
||||
"base_dn='%s', user_rdn='%s'", name, uri, base_dn, user_rdn)
|
||||
super(Authenticator, self).__init__(name)
|
||||
|
||||
|
@ -48,8 +49,7 @@ class Authenticator(BaseAuthenticator):
|
|||
if self.con:
|
||||
self.con.unbind_s()
|
||||
|
||||
|
||||
## Implement virtual properties
|
||||
# Implement virtual properties
|
||||
|
||||
vendor = 'ldap'
|
||||
|
||||
|
@ -65,8 +65,7 @@ class Authenticator(BaseAuthenticator):
|
|||
return True
|
||||
return False
|
||||
|
||||
|
||||
## Implement virtual methods
|
||||
# Implement virtual methods
|
||||
|
||||
def authenticate(self, password):
|
||||
try:
|
||||
|
@ -83,8 +82,7 @@ class Authenticator(BaseAuthenticator):
|
|||
else:
|
||||
self.con = con
|
||||
|
||||
|
||||
## Additional LDAP methods
|
||||
# Additional LDAP methods
|
||||
# TODO: Review these methods
|
||||
|
||||
def search(self, base=None, filter='(objectClass=*)', attrs=['dn']):
|
||||
|
@ -108,7 +106,7 @@ class Authenticator(BaseAuthenticator):
|
|||
try:
|
||||
result = self.con.search_s(base, ldap.SCOPE_SUBTREE, filter, attrs)
|
||||
except:
|
||||
logger.exception("error during LDAP search operation with: base='%s', " \
|
||||
logger.exception("error during LDAP search operation with: base='%s', "
|
||||
"filter='%s', attrs=%s", base, filter, attrs)
|
||||
raise MoulinetteError(169, m18n.g('ldap_operation_error'))
|
||||
|
||||
|
@ -139,7 +137,7 @@ class Authenticator(BaseAuthenticator):
|
|||
try:
|
||||
self.con.add_s(dn, ldif)
|
||||
except:
|
||||
logger.exception("error during LDAP add operation with: rdn='%s', " \
|
||||
logger.exception("error during LDAP add operation with: rdn='%s', "
|
||||
"attr_dict=%s", rdn, attr_dict)
|
||||
raise MoulinetteError(169, m18n.g('ldap_operation_error'))
|
||||
else:
|
||||
|
@ -189,7 +187,7 @@ class Authenticator(BaseAuthenticator):
|
|||
|
||||
self.con.modify_ext_s(dn, ldif)
|
||||
except:
|
||||
logger.exception("error during LDAP update operation with: rdn='%s', " \
|
||||
logger.exception("error during LDAP update operation with: rdn='%s', "
|
||||
"attr_dict=%s, new_rdn=%s", rdn, attr_dict, new_rdn)
|
||||
raise MoulinetteError(169, m18n.g('ldap_operation_error'))
|
||||
else:
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
import errno
|
||||
|
@ -25,6 +24,7 @@ class Package(object):
|
|||
not (only for debugging)
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, _from_source=False):
|
||||
if _from_source:
|
||||
import sys
|
||||
|
@ -32,7 +32,7 @@ class Package(object):
|
|||
logger.debug('initialize Package object running from source')
|
||||
|
||||
# Retrieve source's base directory
|
||||
basedir = os.path.abspath(os.path.dirname(sys.argv[0]) +'/../')
|
||||
basedir = os.path.abspath(os.path.dirname(sys.argv[0]) + '/../')
|
||||
|
||||
# Set local directories
|
||||
self._datadir = '%s/data' % basedir
|
||||
|
@ -55,8 +55,7 @@ class Package(object):
|
|||
return
|
||||
self.__dict__[name] = value
|
||||
|
||||
|
||||
## Easy access to package directories
|
||||
# Easy access to package directories
|
||||
|
||||
@property
|
||||
def datadir(self):
|
||||
|
@ -78,8 +77,7 @@ class Package(object):
|
|||
"""Return the cache directory of the package"""
|
||||
return self._cachedir
|
||||
|
||||
|
||||
## Additional methods
|
||||
# Additional methods
|
||||
|
||||
def get_cachedir(self, subdir='', make_dir=True):
|
||||
"""Get the path to a cache directory
|
||||
|
@ -131,6 +129,7 @@ class Translator(object):
|
|||
- default_locale -- The default locale to use
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, locale_dir, default_locale='en'):
|
||||
self.locale_dir = locale_dir
|
||||
self.locale = default_locale
|
||||
|
@ -244,6 +243,7 @@ class Moulinette18n(object):
|
|||
- default_locale -- The default locale to use
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, package, default_locale='en'):
|
||||
self.default_locale = default_locale
|
||||
self.locale = default_locale
|
||||
|
@ -333,6 +333,7 @@ class MoulinetteSignals(object):
|
|||
- kwargs -- A dict of {signal: handler} to connect
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
# Initialize handlers
|
||||
for s in self.signals:
|
||||
|
@ -356,11 +357,10 @@ class MoulinetteSignals(object):
|
|||
return
|
||||
setattr(self, '_%s' % signal, self._notimplemented)
|
||||
|
||||
|
||||
## Signals definitions
|
||||
# Signals definitions
|
||||
|
||||
"""The list of available signals"""
|
||||
signals = { 'authenticate', 'prompt', 'display' }
|
||||
signals = {'authenticate', 'prompt', 'display'}
|
||||
|
||||
def authenticate(self, authenticator, help):
|
||||
"""Process the authentication
|
||||
|
@ -471,6 +471,7 @@ def init_interface(name, kwargs={}, actionsmap={}):
|
|||
|
||||
return interface(amap, **kwargs)
|
||||
|
||||
|
||||
def init_authenticator((vendor, name), kwargs={}):
|
||||
"""Return a new authenticator instance
|
||||
|
||||
|
@ -491,6 +492,7 @@ def init_authenticator((vendor, name), kwargs={}):
|
|||
else:
|
||||
return mod.Authenticator(name, **kwargs)
|
||||
|
||||
|
||||
def clean_session(session_id, profiles=[]):
|
||||
"""Clean a session cache
|
||||
|
||||
|
@ -534,6 +536,7 @@ class MoulinetteLock(object):
|
|||
lock
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, namespace, timeout=None, interval=.5):
|
||||
self.namespace = namespace
|
||||
self.timeout = timeout
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import errno
|
||||
import logging
|
||||
import argparse
|
||||
|
@ -31,6 +30,7 @@ class BaseActionsMapParser(object):
|
|||
- parent -- A parent BaseActionsMapParser derived object
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None, **kwargs):
|
||||
if parent:
|
||||
self._o = parent
|
||||
|
@ -43,15 +43,13 @@ class BaseActionsMapParser(object):
|
|||
self._global_conf = {}
|
||||
self._conf = {}
|
||||
|
||||
|
||||
## Virtual properties
|
||||
# Virtual properties
|
||||
# Each parser classes must implement these properties.
|
||||
|
||||
"""The name of the interface for which it is the parser"""
|
||||
interface = None
|
||||
|
||||
|
||||
## Virtual methods
|
||||
# Virtual methods
|
||||
# Each parser classes must implement these methods.
|
||||
|
||||
@staticmethod
|
||||
|
@ -70,8 +68,8 @@ class BaseActionsMapParser(object):
|
|||
A list of option strings
|
||||
|
||||
"""
|
||||
raise NotImplementedError("derived class '%s' must override this method" % \
|
||||
self.__class__.__name__)
|
||||
raise NotImplementedError("derived class '%s' must override this method" %
|
||||
self.__class__.__name__)
|
||||
|
||||
def add_global_parser(self, **kwargs):
|
||||
"""Add a parser for global arguments
|
||||
|
@ -82,8 +80,8 @@ class BaseActionsMapParser(object):
|
|||
An ArgumentParser based object
|
||||
|
||||
"""
|
||||
raise NotImplementedError("derived class '%s' must override this method" % \
|
||||
self.__class__.__name__)
|
||||
raise NotImplementedError("derived class '%s' must override this method" %
|
||||
self.__class__.__name__)
|
||||
|
||||
def add_category_parser(self, name, **kwargs):
|
||||
"""Add a parser for a category
|
||||
|
@ -97,8 +95,8 @@ class BaseActionsMapParser(object):
|
|||
A BaseParser based object
|
||||
|
||||
"""
|
||||
raise NotImplementedError("derived class '%s' must override this method" % \
|
||||
self.__class__.__name__)
|
||||
raise NotImplementedError("derived class '%s' must override this method" %
|
||||
self.__class__.__name__)
|
||||
|
||||
def add_action_parser(self, name, tid, **kwargs):
|
||||
"""Add a parser for an action
|
||||
|
@ -113,8 +111,8 @@ class BaseActionsMapParser(object):
|
|||
An ArgumentParser based object
|
||||
|
||||
"""
|
||||
raise NotImplementedError("derived class '%s' must override this method" % \
|
||||
self.__class__.__name__)
|
||||
raise NotImplementedError("derived class '%s' must override this method" %
|
||||
self.__class__.__name__)
|
||||
|
||||
def parse_args(self, args, **kwargs):
|
||||
"""Parse arguments
|
||||
|
@ -129,11 +127,10 @@ class BaseActionsMapParser(object):
|
|||
The populated namespace
|
||||
|
||||
"""
|
||||
raise NotImplementedError("derived class '%s' must override this method" % \
|
||||
self.__class__.__name__)
|
||||
raise NotImplementedError("derived class '%s' must override this method" %
|
||||
self.__class__.__name__)
|
||||
|
||||
|
||||
## Arguments helpers
|
||||
# Arguments helpers
|
||||
|
||||
def prepare_action_namespace(self, tid, namespace=None):
|
||||
"""Prepare the namespace for a given action"""
|
||||
|
@ -168,8 +165,7 @@ class BaseActionsMapParser(object):
|
|||
|
||||
return namespace
|
||||
|
||||
|
||||
## Configuration access
|
||||
# Configuration access
|
||||
|
||||
@property
|
||||
def global_conf(self):
|
||||
|
@ -237,7 +233,6 @@ class BaseActionsMapParser(object):
|
|||
"""
|
||||
self._o._conf[action] = self._validate_conf(configuration)
|
||||
|
||||
|
||||
def _validate_conf(self, configuration, is_global=False):
|
||||
"""Validate configuration for the parser
|
||||
|
||||
|
@ -265,7 +260,7 @@ class BaseActionsMapParser(object):
|
|||
# Store only if authentication is needed
|
||||
conf['authenticate'] = True if self.interface in ifaces else False
|
||||
else:
|
||||
logger.error("expecting 'all', 'False' or a list for " \
|
||||
logger.error("expecting 'all', 'False' or a list for "
|
||||
"configuration 'authenticate', got %r", ifaces)
|
||||
raise MoulinetteError(errno.EINVAL, m18n.g('error_see_log'))
|
||||
|
||||
|
@ -280,12 +275,12 @@ class BaseActionsMapParser(object):
|
|||
# Store needed authenticator profile
|
||||
conf['authenticator'] = self.global_conf['authenticator'][auth]
|
||||
except KeyError:
|
||||
logger.error("requesting profile '%s' which is undefined in " \
|
||||
logger.error("requesting profile '%s' which is undefined in "
|
||||
"global configuration of 'authenticator'", auth)
|
||||
raise MoulinetteError(errno.EINVAL, m18n.g('error_see_log'))
|
||||
elif is_global and isinstance(auth, dict):
|
||||
if len(auth) == 0:
|
||||
logger.warning('no profile defined in global configuration ' \
|
||||
logger.warning('no profile defined in global configuration '
|
||||
"for 'authenticator'")
|
||||
else:
|
||||
auths = {}
|
||||
|
@ -299,11 +294,11 @@ class BaseActionsMapParser(object):
|
|||
# - parameters: a dict of arguments for the
|
||||
# authenticator profile
|
||||
auths[auth_name] = ((auth_conf.get('vendor'), auth_name),
|
||||
{ 'help': auth_conf.get('help', None) },
|
||||
{'help': auth_conf.get('help', None)},
|
||||
auth_conf.get('parameters', {}))
|
||||
conf['authenticator'] = auths
|
||||
else:
|
||||
logger.error("expecting a dict of profile(s) or a profile name " \
|
||||
logger.error("expecting a dict of profile(s) or a profile name "
|
||||
"for configuration 'authenticator', got %r", auth)
|
||||
raise MoulinetteError(errno.EINVAL, m18n.g('error_see_log'))
|
||||
|
||||
|
@ -316,7 +311,7 @@ class BaseActionsMapParser(object):
|
|||
if isinstance(arg_auth, bool):
|
||||
conf['argument_auth'] = arg_auth
|
||||
else:
|
||||
logger.error("expecting a boolean for configuration " \
|
||||
logger.error("expecting a boolean for configuration "
|
||||
"'argument_auth', got %r", arg_auth)
|
||||
raise MoulinetteError(errno.EINVAL, m18n.g('error_see_log'))
|
||||
|
||||
|
@ -329,7 +324,7 @@ class BaseActionsMapParser(object):
|
|||
if isinstance(lock, bool):
|
||||
conf['lock'] = lock
|
||||
else:
|
||||
logger.error("expecting a boolean for configuration 'lock', " \
|
||||
logger.error("expecting a boolean for configuration 'lock', "
|
||||
"got %r", lock)
|
||||
raise MoulinetteError(errno.EINVAL, m18n.g('error_see_log'))
|
||||
|
||||
|
@ -369,14 +364,16 @@ class BaseInterface(object):
|
|||
|
||||
"""
|
||||
# TODO: Add common interface methods and try to standardize default ones
|
||||
|
||||
def __init__(self, actionsmap):
|
||||
raise NotImplementedError("derived class '%s' must override this method" % \
|
||||
self.__class__.__name__)
|
||||
raise NotImplementedError("derived class '%s' must override this method" %
|
||||
self.__class__.__name__)
|
||||
|
||||
|
||||
# Argument parser ------------------------------------------------------
|
||||
|
||||
class _CallbackAction(argparse.Action):
|
||||
|
||||
def __init__(self,
|
||||
option_strings,
|
||||
dest,
|
||||
|
@ -427,7 +424,7 @@ class _CallbackAction(argparse.Action):
|
|||
# Execute callback and get returned value
|
||||
value = self.callback(namespace, values, **self.callback_kwargs)
|
||||
except:
|
||||
logger.exception("cannot get value from callback method " \
|
||||
logger.exception("cannot get value from callback method "
|
||||
"'{0}'".format(self.callback_method))
|
||||
raise MoulinetteError(errno.EINVAL, m18n.g('error_see_log'))
|
||||
else:
|
||||
|
@ -437,6 +434,7 @@ class _CallbackAction(argparse.Action):
|
|||
else:
|
||||
setattr(namespace, self.dest, value)
|
||||
|
||||
|
||||
class _ExtendedSubParsersAction(argparse._SubParsersAction):
|
||||
"""Subparsers with extended properties for argparse
|
||||
|
||||
|
@ -450,6 +448,7 @@ class _ExtendedSubParsersAction(argparse._SubParsersAction):
|
|||
- deprecated_alias -- A list of deprecated command alias names
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
required = kwargs.pop('required', False)
|
||||
super(_ExtendedSubParsersAction, self).__init__(*args, **kwargs)
|
||||
|
@ -500,6 +499,7 @@ class _ExtendedSubParsersAction(argparse._SubParsersAction):
|
|||
|
||||
|
||||
class ExtendedArgumentParser(argparse.ArgumentParser):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ExtendedArgumentParser, self).__init__(*args, **kwargs)
|
||||
|
||||
|
@ -517,8 +517,10 @@ class ExtendedArgumentParser(argparse.ArgumentParser):
|
|||
c, v = queue.popleft()
|
||||
# FIXME: break dequeue if callback returns
|
||||
c.execute(namespace, v)
|
||||
try: delattr(namespace, CALLBACKS_PROP)
|
||||
except: pass
|
||||
try:
|
||||
delattr(namespace, CALLBACKS_PROP)
|
||||
except:
|
||||
pass
|
||||
|
||||
def _get_callbacks_queue(self, namespace, create=True):
|
||||
try:
|
||||
|
@ -536,7 +538,7 @@ class ExtendedArgumentParser(argparse.ArgumentParser):
|
|||
return '([-AO]*)'
|
||||
else:
|
||||
return super(ExtendedArgumentParser, self)._get_nargs_pattern(
|
||||
action)
|
||||
action)
|
||||
|
||||
def _get_values(self, action, arg_strings):
|
||||
if action.nargs == argparse.PARSER and not action.required:
|
||||
|
@ -547,5 +549,5 @@ class ExtendedArgumentParser(argparse.ArgumentParser):
|
|||
value = argparse.SUPPRESS
|
||||
else:
|
||||
value = super(ExtendedArgumentParser, self)._get_values(
|
||||
action, arg_strings)
|
||||
action, arg_strings)
|
||||
return value
|
||||
|
|
|
@ -29,11 +29,13 @@ class LogQueues(dict):
|
|||
"""Map of session id to queue."""
|
||||
pass
|
||||
|
||||
|
||||
class APIQueueHandler(log.Handler):
|
||||
"""
|
||||
A handler class which store logging records into a queue, to be used
|
||||
and retrieved from the API.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
log.Handler.__init__(self)
|
||||
self.queues = LogQueues()
|
||||
|
@ -52,6 +54,7 @@ class APIQueueHandler(log.Handler):
|
|||
# populate the new message in the queue
|
||||
sleep(0)
|
||||
|
||||
|
||||
class _HTTPArgumentParser(object):
|
||||
"""Argument parser for HTTP requests
|
||||
|
||||
|
@ -59,6 +62,7 @@ class _HTTPArgumentParser(object):
|
|||
on ExtendedArgumentParser class and implements some of its methods.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
# Initialize the ArgumentParser object
|
||||
self._parser = ExtendedArgumentParser(usage='',
|
||||
|
@ -89,7 +93,7 @@ class _HTTPArgumentParser(object):
|
|||
def parse_args(self, args={}, namespace=None):
|
||||
arg_strings = []
|
||||
|
||||
## Append an argument to the current one
|
||||
# Append an argument to the current one
|
||||
def append(arg_strings, value, option_string=None):
|
||||
if isinstance(value, bool):
|
||||
# Append the option string only
|
||||
|
@ -110,11 +114,11 @@ class _HTTPArgumentParser(object):
|
|||
if isinstance(v, str):
|
||||
arg_strings.append(v)
|
||||
else:
|
||||
logger.warning("unsupported argument value type %r " \
|
||||
logger.warning("unsupported argument value type %r "
|
||||
"in %s for option string %s", v, value,
|
||||
option_string)
|
||||
else:
|
||||
logger.warning("unsupported argument type %r for option " \
|
||||
logger.warning("unsupported argument type %r for option "
|
||||
"string %s", value, option_string)
|
||||
|
||||
return arg_strings
|
||||
|
@ -138,6 +142,7 @@ class _HTTPArgumentParser(object):
|
|||
# TODO: Raise a proper exception
|
||||
raise MoulinetteError(1, message)
|
||||
|
||||
|
||||
class _ActionsMapPlugin(object):
|
||||
"""Actions map Bottle Plugin
|
||||
|
||||
|
@ -174,7 +179,7 @@ class _ActionsMapPlugin(object):
|
|||
- app -- The application instance
|
||||
|
||||
"""
|
||||
## Login wrapper
|
||||
# Login wrapper
|
||||
def _login(callback):
|
||||
def wrapper():
|
||||
kwargs = {}
|
||||
|
@ -189,7 +194,7 @@ class _ActionsMapPlugin(object):
|
|||
return callback(**kwargs)
|
||||
return wrapper
|
||||
|
||||
## Logout wrapper
|
||||
# Logout wrapper
|
||||
def _logout(callback):
|
||||
def wrapper():
|
||||
kwargs = {}
|
||||
|
@ -258,8 +263,7 @@ class _ActionsMapPlugin(object):
|
|||
return callback((request.method, context.rule), params)
|
||||
return wrapper
|
||||
|
||||
|
||||
## Routes callbacks
|
||||
# Routes callbacks
|
||||
|
||||
def login(self, password, profile='default'):
|
||||
"""Log in to an authenticator profile
|
||||
|
@ -290,8 +294,10 @@ class _ActionsMapPlugin(object):
|
|||
auth(password, token=(s_id, s_hash))
|
||||
except MoulinetteError as e:
|
||||
if len(s_hashes) > 0:
|
||||
try: self.logout(profile)
|
||||
except: pass
|
||||
try:
|
||||
self.logout(profile)
|
||||
except:
|
||||
pass
|
||||
raise error_to_response(e)
|
||||
else:
|
||||
# Update dicts with new values
|
||||
|
@ -359,7 +365,7 @@ class _ActionsMapPlugin(object):
|
|||
else:
|
||||
try:
|
||||
# Send the message
|
||||
wsock.send(json_encode({ style: message }))
|
||||
wsock.send(json_encode({style: message}))
|
||||
except WebSocketError:
|
||||
break
|
||||
sleep(0)
|
||||
|
@ -391,8 +397,7 @@ class _ActionsMapPlugin(object):
|
|||
else:
|
||||
queue.put(StopIteration)
|
||||
|
||||
|
||||
## Signals handlers
|
||||
# Signals handlers
|
||||
|
||||
def _do_authenticate(self, authenticator, help):
|
||||
"""Process the authentication
|
||||
|
@ -438,25 +443,35 @@ class _ActionsMapPlugin(object):
|
|||
# HTTP Responses -------------------------------------------------------
|
||||
|
||||
class HTTPOKResponse(HTTPResponse):
|
||||
|
||||
def __init__(self, output=''):
|
||||
super(HTTPOKResponse, self).__init__(output, 200)
|
||||
|
||||
|
||||
class HTTPBadRequestResponse(HTTPResponse):
|
||||
|
||||
def __init__(self, output=''):
|
||||
super(HTTPBadRequestResponse, self).__init__(output, 400)
|
||||
|
||||
|
||||
class HTTPUnauthorizedResponse(HTTPResponse):
|
||||
|
||||
def __init__(self, output=''):
|
||||
super(HTTPUnauthorizedResponse, self).__init__(output, 401)
|
||||
|
||||
|
||||
class HTTPForbiddenResponse(HTTPResponse):
|
||||
|
||||
def __init__(self, output=''):
|
||||
super(HTTPForbiddenResponse, self).__init__(output, 403)
|
||||
|
||||
|
||||
class HTTPErrorResponse(HTTPResponse):
|
||||
|
||||
def __init__(self, output=''):
|
||||
super(HTTPErrorResponse, self).__init__(output, 500)
|
||||
|
||||
|
||||
def error_to_response(error):
|
||||
"""Convert a MoulinetteError to relevant HTTP response."""
|
||||
if error.errno == errno.EPERM:
|
||||
|
@ -464,18 +479,19 @@ def error_to_response(error):
|
|||
elif error.errno == errno.EACCES:
|
||||
return HTTPUnauthorizedResponse(error.strerror)
|
||||
# Client-side error
|
||||
elif error.errno in [ errno.ENOENT, errno.ESRCH, errno.ENXIO, errno.EEXIST,
|
||||
errno.ENODEV, errno.EINVAL, errno.ENOPKG, errno.EDESTADDRREQ ]:
|
||||
elif error.errno in [errno.ENOENT, errno.ESRCH, errno.ENXIO, errno.EEXIST,
|
||||
errno.ENODEV, errno.EINVAL, errno.ENOPKG, errno.EDESTADDRREQ]:
|
||||
return HTTPBadRequestResponse(error.strerror)
|
||||
# Server-side error
|
||||
elif error.errno in [ errno.EIO, errno.EBUSY, errno.ENODATA, errno.EINTR,
|
||||
errno.ENETUNREACH ]:
|
||||
elif error.errno in [errno.EIO, errno.EBUSY, errno.ENODATA, errno.EINTR,
|
||||
errno.ENETUNREACH]:
|
||||
return HTTPErrorResponse(error.strerror)
|
||||
else:
|
||||
logger.debug('unknown relevant response for error [%s] %s',
|
||||
error.errno, error.strerror)
|
||||
return HTTPErrorResponse(error.strerror)
|
||||
|
||||
|
||||
def format_for_response(content):
|
||||
"""Format the resulted content of a request for the HTTP response."""
|
||||
if request.method == 'POST':
|
||||
|
@ -503,10 +519,11 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
the arguments is represented by a ExtendedArgumentParser object.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None, **kwargs):
|
||||
super(ActionsMapParser, self).__init__(parent)
|
||||
|
||||
self._parsers = {} # dict({(method, path): _HTTPArgumentParser})
|
||||
self._parsers = {} # dict({(method, path): _HTTPArgumentParser})
|
||||
self._route_re = re.compile(r'(GET|POST|PUT|DELETE) (/\S+)')
|
||||
|
||||
@property
|
||||
|
@ -514,13 +531,11 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
"""Get current routes"""
|
||||
return self._parsers.keys()
|
||||
|
||||
|
||||
## Implement virtual properties
|
||||
# Implement virtual properties
|
||||
|
||||
interface = 'api'
|
||||
|
||||
|
||||
## Implement virtual methods
|
||||
# Implement virtual methods
|
||||
|
||||
@staticmethod
|
||||
def format_arg_names(name, full):
|
||||
|
@ -559,7 +574,7 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
try:
|
||||
keys.append(self._extract_route(r))
|
||||
except ValueError as e:
|
||||
logger.warning("cannot add api route '%s' for " \
|
||||
logger.warning("cannot add api route '%s' for "
|
||||
"action %s: %s", r, tid, e)
|
||||
continue
|
||||
if len(keys) == 0:
|
||||
|
@ -613,8 +628,7 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
parser.dequeue_callbacks(ret)
|
||||
return ret
|
||||
|
||||
|
||||
## Private methods
|
||||
# Private methods
|
||||
|
||||
def _extract_route(self, string):
|
||||
"""Extract action route from a string
|
||||
|
@ -652,6 +666,7 @@ class Interface(BaseInterface):
|
|||
registered logging handlers
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, actionsmap, routes={}, use_websocket=True,
|
||||
log_queues=None):
|
||||
self.use_websocket = use_websocket
|
||||
|
@ -665,14 +680,14 @@ class Interface(BaseInterface):
|
|||
# TODO: Return OK to 'OPTIONS' xhr requests (l173)
|
||||
app = Bottle(autojson=True)
|
||||
|
||||
## Wrapper which sets proper header
|
||||
# Wrapper which sets proper header
|
||||
def apiheader(callback):
|
||||
def wrapper(*args, **kwargs):
|
||||
response.set_header('Access-Control-Allow-Origin', '*')
|
||||
return callback(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
## Attempt to retrieve and set locale
|
||||
# Attempt to retrieve and set locale
|
||||
def api18n(callback):
|
||||
try:
|
||||
locale = request.params.pop('locale')
|
||||
|
@ -729,8 +744,7 @@ class Interface(BaseInterface):
|
|||
m18n.g('server_already_running'))
|
||||
raise MoulinetteError(errno.EIO, m18n.g('error_see_log'))
|
||||
|
||||
|
||||
## Routes handlers
|
||||
# Routes handlers
|
||||
|
||||
def doc(self, category=None):
|
||||
"""
|
||||
|
|
|
@ -26,15 +26,16 @@ CLI_COLOR_TEMPLATE = '\033[{:d}m\033[1m'
|
|||
END_CLI_COLOR = '\033[m'
|
||||
|
||||
colors_codes = {
|
||||
'red' : CLI_COLOR_TEMPLATE.format(31),
|
||||
'green' : CLI_COLOR_TEMPLATE.format(32),
|
||||
'red': CLI_COLOR_TEMPLATE.format(31),
|
||||
'green': CLI_COLOR_TEMPLATE.format(32),
|
||||
'yellow': CLI_COLOR_TEMPLATE.format(33),
|
||||
'blue' : CLI_COLOR_TEMPLATE.format(34),
|
||||
'blue': CLI_COLOR_TEMPLATE.format(34),
|
||||
'purple': CLI_COLOR_TEMPLATE.format(35),
|
||||
'cyan' : CLI_COLOR_TEMPLATE.format(36),
|
||||
'white' : CLI_COLOR_TEMPLATE.format(37),
|
||||
'cyan': CLI_COLOR_TEMPLATE.format(36),
|
||||
'white': CLI_COLOR_TEMPLATE.format(37),
|
||||
}
|
||||
|
||||
|
||||
def colorize(astr, color):
|
||||
"""Colorize a string
|
||||
|
||||
|
@ -50,6 +51,7 @@ def colorize(astr, color):
|
|||
else:
|
||||
return astr
|
||||
|
||||
|
||||
def plain_print_dict(d, depth=0):
|
||||
"""Print in a plain way a dictionary recursively
|
||||
|
||||
|
@ -79,16 +81,17 @@ def plain_print_dict(d, depth=0):
|
|||
d = list(d)
|
||||
if isinstance(d, list):
|
||||
for v in d:
|
||||
plain_print_dict(v, depth+1)
|
||||
plain_print_dict(v, depth + 1)
|
||||
elif isinstance(d, dict):
|
||||
for k,v in d.items():
|
||||
print("{}{}".format("#" * (depth+1), k))
|
||||
plain_print_dict(v, depth+1)
|
||||
for k, v in d.items():
|
||||
print("{}{}".format("#" * (depth + 1), k))
|
||||
plain_print_dict(v, depth + 1)
|
||||
else:
|
||||
if isinstance(d, unicode):
|
||||
d = d.encode('utf-8')
|
||||
print(d)
|
||||
|
||||
|
||||
def pretty_print_dict(d, depth=0):
|
||||
"""Print in a pretty way a dictionary recursively
|
||||
|
||||
|
@ -111,23 +114,24 @@ def pretty_print_dict(d, depth=0):
|
|||
v = v[0]
|
||||
if isinstance(v, dict):
|
||||
print("{:s}{}: ".format(" " * depth, k))
|
||||
pretty_print_dict(v, depth+1)
|
||||
pretty_print_dict(v, depth + 1)
|
||||
elif isinstance(v, list):
|
||||
print("{:s}{}: ".format(" " * depth, k))
|
||||
for key, value in enumerate(v):
|
||||
if isinstance(value, tuple):
|
||||
pretty_print_dict({value[0]: value[1]}, depth+1)
|
||||
pretty_print_dict({value[0]: value[1]}, depth + 1)
|
||||
elif isinstance(value, dict):
|
||||
pretty_print_dict({key: value}, depth+1)
|
||||
pretty_print_dict({key: value}, depth + 1)
|
||||
else:
|
||||
if isinstance(value, unicode):
|
||||
value = value.encode('utf-8')
|
||||
print("{:s}- {}".format(" " * (depth+1), value))
|
||||
print("{:s}- {}".format(" " * (depth + 1), value))
|
||||
else:
|
||||
if isinstance(v, unicode):
|
||||
v = v.encode('utf-8')
|
||||
print("{:s}{}: {}".format(" " * depth, k, v))
|
||||
|
||||
|
||||
def get_locale():
|
||||
"""Return current user locale"""
|
||||
lang = locale.getdefaultlocale()[0]
|
||||
|
@ -155,13 +159,13 @@ class TTYHandler(log.StreamHandler):
|
|||
|
||||
"""
|
||||
LEVELS_COLOR = {
|
||||
log.NOTSET : 'white',
|
||||
log.DEBUG : 'white',
|
||||
log.INFO : 'cyan',
|
||||
log.SUCCESS : 'green',
|
||||
log.WARNING : 'yellow',
|
||||
log.ERROR : 'red',
|
||||
log.CRITICAL : 'red',
|
||||
log.NOTSET: 'white',
|
||||
log.DEBUG: 'white',
|
||||
log.INFO: 'cyan',
|
||||
log.SUCCESS: 'green',
|
||||
log.WARNING: 'yellow',
|
||||
log.ERROR: 'red',
|
||||
log.CRITICAL: 'red',
|
||||
}
|
||||
|
||||
def __init__(self, message_key='fmessage'):
|
||||
|
@ -216,6 +220,7 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
be take into account but not parsed
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None, parser=None, subparser_kwargs=None,
|
||||
top_parser=None, **kwargs):
|
||||
super(ActionsMapParser, self).__init__(parent)
|
||||
|
@ -234,13 +239,11 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
action.dest = SUPPRESS
|
||||
glob._add_action(action)
|
||||
|
||||
|
||||
## Implement virtual properties
|
||||
# Implement virtual properties
|
||||
|
||||
interface = 'cli'
|
||||
|
||||
|
||||
## Implement virtual methods
|
||||
# Implement virtual methods
|
||||
|
||||
@staticmethod
|
||||
def format_arg_names(name, full):
|
||||
|
@ -251,7 +254,7 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
def add_global_parser(self, **kwargs):
|
||||
if not self._global_parser:
|
||||
self._global_parser = self._parser.add_argument_group(
|
||||
"global arguments")
|
||||
"global arguments")
|
||||
return self._global_parser
|
||||
|
||||
def add_category_parser(self, name, category_help=None, **kwargs):
|
||||
|
@ -266,7 +269,7 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
"""
|
||||
parser = self._subparsers.add_parser(name, help=category_help, **kwargs)
|
||||
return self.__class__(self, parser, {
|
||||
'title': "actions", 'required': True
|
||||
'title': "actions", 'required': True
|
||||
})
|
||||
|
||||
def add_action_parser(self, name, tid, action_help=None, deprecated=False,
|
||||
|
@ -310,6 +313,7 @@ class Interface(BaseInterface):
|
|||
- actionsmap -- The ActionsMap instance to connect to
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, actionsmap):
|
||||
# Set user locale
|
||||
m18n.set_locale(get_locale())
|
||||
|
@ -347,7 +351,7 @@ class Interface(BaseInterface):
|
|||
# Set handler for authentication
|
||||
if password:
|
||||
msignals.set_handler('authenticate',
|
||||
lambda a,h: a(password=password))
|
||||
lambda a, h: a(password=password))
|
||||
|
||||
try:
|
||||
ret = self.actionsmap.process(args, timeout=timeout)
|
||||
|
@ -370,8 +374,7 @@ class Interface(BaseInterface):
|
|||
else:
|
||||
print(ret)
|
||||
|
||||
|
||||
## Signals handlers
|
||||
# Signals handlers
|
||||
|
||||
def _do_authenticate(self, authenticator, help):
|
||||
"""Process the authentication
|
||||
|
|
|
@ -2,7 +2,6 @@ import os
|
|||
import errno
|
||||
import shutil
|
||||
from pwd import getpwnam
|
||||
from grp import getgrnam
|
||||
|
||||
from moulinette.core import MoulinetteError
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import os
|
||||
import logging
|
||||
from logging import *
|
||||
from logging import addLevelName, setLoggerClass, Logger, getLogger
|
||||
|
||||
|
||||
# Global configuration and functions -----------------------------------
|
||||
|
@ -31,6 +31,7 @@ DEFAULT_LOGGING = {
|
|||
},
|
||||
}
|
||||
|
||||
|
||||
def configure_logging(logging_config=None):
|
||||
"""Configure logging with default and optionally given configuration
|
||||
|
||||
|
@ -49,6 +50,7 @@ def configure_logging(logging_config=None):
|
|||
if logging_config:
|
||||
dictConfig(logging_config)
|
||||
|
||||
|
||||
def getHandlersByClass(classinfo, limit=0):
|
||||
"""Retrieve registered handlers of a given class."""
|
||||
handlers = []
|
||||
|
@ -59,7 +61,7 @@ def getHandlersByClass(classinfo, limit=0):
|
|||
return o
|
||||
handlers.append(o)
|
||||
if limit != 0 and len(handlers) > limit:
|
||||
return handlers[:limit-1]
|
||||
return handlers[:limit - 1]
|
||||
return handlers
|
||||
|
||||
|
||||
|
@ -111,9 +113,11 @@ class MoulinetteLogger(Logger):
|
|||
pid = os.getpid()
|
||||
action_id = 0
|
||||
|
||||
|
||||
def _get_action_id():
|
||||
return '%d.%d' % (pid, action_id)
|
||||
|
||||
|
||||
def start_action_logging():
|
||||
"""Configure logging for a new action
|
||||
|
||||
|
@ -126,6 +130,7 @@ def start_action_logging():
|
|||
|
||||
return _get_action_id()
|
||||
|
||||
|
||||
def getActionLogger(name=None, logger=None, action_id=None):
|
||||
"""Get the logger adapter for an action
|
||||
|
||||
|
@ -133,7 +138,7 @@ def getActionLogger(name=None, logger=None, action_id=None):
|
|||
optionally for a given action id, retrieving it if necessary.
|
||||
|
||||
Either a name or a logger must be specified.
|
||||
|
||||
|
||||
"""
|
||||
if not name and not logger:
|
||||
raise ValueError('Either a name or a logger must be specified')
|
||||
|
@ -152,6 +157,7 @@ class ActionFilter(object):
|
|||
message formatted for the action or just the original one.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, message_key='fmessage', strict=False):
|
||||
self.message_key = message_key
|
||||
self.strict = strict
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
import time
|
||||
import subprocess
|
||||
try:
|
||||
from pipes import quote # Python2 & Python3 <= 3.2
|
||||
except ImportError:
|
||||
from shlex import quote # Python3 >= 3.3
|
||||
|
||||
from .stream import async_file_reading
|
||||
|
||||
|
@ -145,17 +141,17 @@ def check_commands(cmds, raise_on_error=False, callback=None,
|
|||
raise CalledProcessError(r, c, o)
|
||||
else:
|
||||
# Continue commands execution
|
||||
callback = lambda r,c,o: True
|
||||
callback = lambda r, c, o: True
|
||||
elif not callable(callback):
|
||||
raise ValueError('callback argument must be callable')
|
||||
|
||||
# Manage stderr
|
||||
if separate_stderr:
|
||||
_stderr = subprocess.PIPE
|
||||
_get_output = lambda o,e: (o,e)
|
||||
_get_output = lambda o, e: (o, e)
|
||||
else:
|
||||
_stderr = subprocess.STDOUT
|
||||
_get_output = lambda o,e: o
|
||||
_get_output = lambda o, e: o
|
||||
|
||||
# Iterate over commands
|
||||
for cmd in cmds:
|
||||
|
|
|
@ -16,11 +16,12 @@ class JSONExtendedEncoder(JSONEncoder):
|
|||
- set: converted into list
|
||||
|
||||
"""
|
||||
|
||||
def default(self, o):
|
||||
"""Return a serializable object"""
|
||||
# Convert compatible containers into list
|
||||
if isinstance(o, set) or (
|
||||
hasattr(o, '__iter__') and hasattr(o, 'next')):
|
||||
hasattr(o, '__iter__') and hasattr(o, 'next')):
|
||||
return list(o)
|
||||
|
||||
# Return the repr for object that json can't encode
|
||||
|
|
|
@ -14,6 +14,7 @@ class AsynchronousFileReader(Process):
|
|||
http://stefaanlippens.net/python-asynchronous-subprocess-pipe-reading
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, fd, queue):
|
||||
assert hasattr(queue, 'put')
|
||||
assert hasattr(queue, 'empty')
|
||||
|
@ -48,6 +49,7 @@ def consume_queue(queue, callback):
|
|||
break
|
||||
callback(line)
|
||||
|
||||
|
||||
def async_file_reading(fd, callback):
|
||||
"""Helper which instantiate and run an AsynchronousFileReader."""
|
||||
queue = SimpleQueue()
|
||||
|
|
|
@ -38,6 +38,7 @@ def search(pattern, text, count=0, flags=0):
|
|||
return match[0]
|
||||
return match
|
||||
|
||||
|
||||
def searchf(pattern, path, count=0, flags=re.MULTILINE):
|
||||
"""Search for pattern in a file
|
||||
|
||||
|
|
Loading…
Reference in a new issue