mirror of
https://github.com/YunoHost/moulinette.git
synced 2024-09-03 20:06:31 +02:00
Merge branch 'dev' into bullseye
This commit is contained in:
commit
35351696ac
21 changed files with 94 additions and 71 deletions
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
![Version](https://img.shields.io/github/v/tag/yunohost/moulinette?label=version&sort=semver)
|
![Version](https://img.shields.io/github/v/tag/yunohost/moulinette?label=version&sort=semver)
|
||||||
[![Tests status](https://github.com/YunoHost/moulinette/actions/workflows/tox.yml/badge.svg)](https://github.com/YunoHost/moulinette/actions/workflows/tox.yml)
|
[![Tests status](https://github.com/YunoHost/moulinette/actions/workflows/tox.yml/badge.svg)](https://github.com/YunoHost/moulinette/actions/workflows/tox.yml)
|
||||||
|
[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/YunoHost/moulinette.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/YunoHost/moulinette/context:python)
|
||||||
[![GitHub license](https://img.shields.io/github/license/YunoHost/moulinette)](https://github.com/YunoHost/moulinette/blob/dev/LICENSE)
|
[![GitHub license](https://img.shields.io/github/license/YunoHost/moulinette)](https://github.com/YunoHost/moulinette/blob/dev/LICENSE)
|
||||||
|
|
||||||
|
|
||||||
|
|
9
debian/changelog
vendored
9
debian/changelog
vendored
|
@ -4,6 +4,15 @@ moulinette (11.0.0~alpha) unstable; urgency=low
|
||||||
|
|
||||||
-- Alexandre Aubin <alex.aubin@mailoo.org> Fri, 05 Feb 2021 00:02:38 +0100
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Fri, 05 Feb 2021 00:02:38 +0100
|
||||||
|
|
||||||
|
moulinette (4.3.3) stable; urgency=low
|
||||||
|
|
||||||
|
- [enh] quality: Apply pyupgrade ([#312](https://github.com/YunoHost/moulinette/pull/312))
|
||||||
|
- [i18n] Translations updated for Czech, German, Portuguese
|
||||||
|
|
||||||
|
Thanks to all contributors <3 ! (Bram, Christian Wehrli, maique madeira, Radek S, Valentin von Guttenberg)
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 29 Dec 2021 01:08:10 +0100
|
||||||
|
|
||||||
moulinette (4.3.2.2) stable; urgency=low
|
moulinette (4.3.2.2) stable; urgency=low
|
||||||
|
|
||||||
Aaaaaand typoed 'testing' instead of 'stable' in previous changelog
|
Aaaaaand typoed 'testing' instead of 'stable' in previous changelog
|
||||||
|
|
|
@ -34,7 +34,7 @@ ldapsearch -x -b 'dc=nodomain' | \\
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
class Element(object):
|
class Element:
|
||||||
"""Represents an LDIF entry."""
|
"""Represents an LDIF entry."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -109,7 +109,7 @@ class Element(object):
|
||||||
|
|
||||||
return TABLE_TEMPLATE % (self.index, '\n '.join(_format(self.attributes)), self.edge(dnmap))
|
return TABLE_TEMPLATE % (self.index, '\n '.join(_format(self.attributes)), self.edge(dnmap))
|
||||||
|
|
||||||
class Converter(object):
|
class Converter:
|
||||||
"""An LDIF to DOT converter."""
|
"""An LDIF to DOT converter."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
"download_unknown_error": "Chyba při stahování dat z {url}: {error}",
|
"download_unknown_error": "Chyba při stahování dat z {url}: {error}",
|
||||||
"download_timeout": "{url} příliš dlouho neodpovídá, akce přerušena.",
|
"download_timeout": "{url} příliš dlouho neodpovídá, akce přerušena.",
|
||||||
"download_ssl_error": "SSL chyba při spojení s {url}",
|
"download_ssl_error": "SSL chyba při spojení s {url}",
|
||||||
"invalid_url": "Špatný odkaz {url} (je vůbec dostupný?)",
|
"invalid_url": "Špatný odkaz {url} (je vůbec dostupný?).",
|
||||||
"error_changing_file_permissions": "Chyba při nastavování oprávnění pro {path}: {error}",
|
"error_changing_file_permissions": "Chyba při nastavování oprávnění pro {path}: {error}",
|
||||||
"error_removing": "Chyba při přesunu {path}: {error}",
|
"error_removing": "Chyba při přesunu {path}: {error}",
|
||||||
"error_writing_file": "Chyba při zápisu souboru/ů {file}: {error}",
|
"error_writing_file": "Chyba při zápisu souboru/ů {file}: {error}",
|
||||||
|
@ -42,5 +42,6 @@
|
||||||
"deprecated_command": "'{prog} {command}' je zastaralý a bude odebrán v budoucích verzích",
|
"deprecated_command": "'{prog} {command}' je zastaralý a bude odebrán v budoucích verzích",
|
||||||
"confirm": "Potvrdit {prompt}",
|
"confirm": "Potvrdit {prompt}",
|
||||||
"authentication_required": "Vyžadováno ověření",
|
"authentication_required": "Vyžadováno ověření",
|
||||||
"argument_required": "Je vyžadován argument '{argument}'"
|
"argument_required": "Je vyžadován argument '{argument}'",
|
||||||
|
"edit_text_question": "{}. Upravit tento text? [yN]: "
|
||||||
}
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
"authentication_required": "Anmeldung erforderlich",
|
"authentication_required": "Anmeldung erforderlich",
|
||||||
"confirm": "Bestätige {prompt}",
|
"confirm": "Bestätige {prompt}",
|
||||||
"error": "Fehler:",
|
"error": "Fehler:",
|
||||||
"file_not_exist": "Datei ist nicht vorhanden: '{path}'",
|
"file_not_exist": "Datei ist nicht vorhanden: '{path}'",
|
||||||
"folder_exists": "Ordner existiert bereits: '{path}'",
|
"folder_exists": "Ordner existiert bereits: '{path}'",
|
||||||
"instance_already_running": "Es läuft bereits eine YunoHost-Operation. Bitte warte, bis sie fertig ist, bevor du eine weitere startest.",
|
"instance_already_running": "Es läuft bereits eine YunoHost-Operation. Bitte warte, bis sie fertig ist, bevor du eine weitere startest.",
|
||||||
"invalid_argument": "Argument ungültig '{argument}': {error}",
|
"invalid_argument": "Argument ungültig '{argument}': {error}",
|
||||||
|
@ -42,5 +42,6 @@
|
||||||
"error_changing_file_permissions": "Fehler beim Ändern der Berechtigungen für {path}: {error}",
|
"error_changing_file_permissions": "Fehler beim Ändern der Berechtigungen für {path}: {error}",
|
||||||
"error_removing": "Fehler beim Entfernen {path}: {error}",
|
"error_removing": "Fehler beim Entfernen {path}: {error}",
|
||||||
"error_writing_file": "Fehler beim Schreiben von Datei {file}: {error}",
|
"error_writing_file": "Fehler beim Schreiben von Datei {file}: {error}",
|
||||||
"corrupted_toml": "Beschädigtes TOML gelesen von {ressource} (reason: {error})"
|
"corrupted_toml": "Beschädigtes TOML gelesen von {ressource} (reason: {error})",
|
||||||
|
"edit_text_question": "{}. Diesen Text bearbeiten? [yN]: "
|
||||||
}
|
}
|
|
@ -42,5 +42,6 @@
|
||||||
"warn_the_user_about_waiting_lock_again": "Ainda esperando...",
|
"warn_the_user_about_waiting_lock_again": "Ainda esperando...",
|
||||||
"warn_the_user_about_waiting_lock": "Outro comando YunoHost está sendo executado agora, estamos aguardando o término antes de executar este",
|
"warn_the_user_about_waiting_lock": "Outro comando YunoHost está sendo executado agora, estamos aguardando o término antes de executar este",
|
||||||
"corrupted_toml": "TOML corrompido lido em {ressource} (motivo: {error})",
|
"corrupted_toml": "TOML corrompido lido em {ressource} (motivo: {error})",
|
||||||
"info": "Informações:"
|
"info": "Informações:",
|
||||||
|
"edit_text_question": "{}. Editar este texto ? [yN]: "
|
||||||
}
|
}
|
|
@ -30,7 +30,7 @@ __all__ = ["init", "api", "cli", "m18n", "MoulinetteError", "Moulinette"]
|
||||||
m18n = Moulinette18n()
|
m18n = Moulinette18n()
|
||||||
|
|
||||||
|
|
||||||
class classproperty(object):
|
class classproperty:
|
||||||
def __init__(self, f):
|
def __init__(self, f):
|
||||||
self.f = f
|
self.f = f
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ logger = logging.getLogger("moulinette.actionsmap")
|
||||||
# Extra parameters definition
|
# Extra parameters definition
|
||||||
|
|
||||||
|
|
||||||
class _ExtraParameter(object):
|
class _ExtraParameter:
|
||||||
"""
|
"""
|
||||||
Argument parser for an extra parameter.
|
Argument parser for an extra parameter.
|
||||||
|
|
||||||
|
@ -260,7 +260,7 @@ extraparameters_list = [
|
||||||
# Extra parameters argument Parser
|
# Extra parameters argument Parser
|
||||||
|
|
||||||
|
|
||||||
class ExtraArgumentParser(object):
|
class ExtraArgumentParser:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Argument validator and parser for the extra parameters.
|
Argument validator and parser for the extra parameters.
|
||||||
|
@ -372,7 +372,7 @@ class ExtraArgumentParser(object):
|
||||||
# Main class ----------------------------------------------------------
|
# Main class ----------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
class ActionsMap(object):
|
class ActionsMap:
|
||||||
|
|
||||||
"""Validate and process actions defined into an actions map
|
"""Validate and process actions defined into an actions map
|
||||||
|
|
||||||
|
@ -462,7 +462,7 @@ class ActionsMap(object):
|
||||||
auth_method = self.default_authentication
|
auth_method = self.default_authentication
|
||||||
|
|
||||||
# Load and initialize the authenticator module
|
# Load and initialize the authenticator module
|
||||||
auth_module = "%s.authenticators.%s" % (self.namespace, auth_method)
|
auth_module = f"{self.namespace}.authenticators.{auth_method}"
|
||||||
logger.debug(f"Loading auth module {auth_module}")
|
logger.debug(f"Loading auth module {auth_module}")
|
||||||
try:
|
try:
|
||||||
mod = import_module(auth_module)
|
mod = import_module(auth_module)
|
||||||
|
@ -515,12 +515,12 @@ class ActionsMap(object):
|
||||||
# Retrieve action information
|
# Retrieve action information
|
||||||
if len(tid) == 4:
|
if len(tid) == 4:
|
||||||
namespace, category, subcategory, action = tid
|
namespace, category, subcategory, action = tid
|
||||||
func_name = "%s_%s_%s" % (
|
func_name = "{}_{}_{}".format(
|
||||||
category,
|
category,
|
||||||
subcategory.replace("-", "_"),
|
subcategory.replace("-", "_"),
|
||||||
action.replace("-", "_"),
|
action.replace("-", "_"),
|
||||||
)
|
)
|
||||||
full_action_name = "%s.%s.%s.%s" % (
|
full_action_name = "{}.{}.{}.{}".format(
|
||||||
namespace,
|
namespace,
|
||||||
category,
|
category,
|
||||||
subcategory,
|
subcategory,
|
||||||
|
@ -530,22 +530,22 @@ class ActionsMap(object):
|
||||||
assert len(tid) == 3
|
assert len(tid) == 3
|
||||||
namespace, category, action = tid
|
namespace, category, action = tid
|
||||||
subcategory = None
|
subcategory = None
|
||||||
func_name = "%s_%s" % (category, action.replace("-", "_"))
|
func_name = "{}_{}".format(category, action.replace("-", "_"))
|
||||||
full_action_name = "%s.%s.%s" % (namespace, category, action)
|
full_action_name = "{}.{}.{}".format(namespace, category, action)
|
||||||
|
|
||||||
# Lock the moulinette for the namespace
|
# Lock the moulinette for the namespace
|
||||||
with MoulinetteLock(namespace, timeout):
|
with MoulinetteLock(namespace, timeout):
|
||||||
start = time()
|
start = time()
|
||||||
try:
|
try:
|
||||||
mod = __import__(
|
mod = __import__(
|
||||||
"%s.%s" % (namespace, category),
|
"{}.{}".format(namespace, category),
|
||||||
globals=globals(),
|
globals=globals(),
|
||||||
level=0,
|
level=0,
|
||||||
fromlist=[func_name],
|
fromlist=[func_name],
|
||||||
)
|
)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"loading python module %s took %.3fs",
|
"loading python module %s took %.3fs",
|
||||||
"%s.%s" % (namespace, category),
|
"{}.{}".format(namespace, category),
|
||||||
time() - start,
|
time() - start,
|
||||||
)
|
)
|
||||||
func = getattr(mod, func_name)
|
func = getattr(mod, func_name)
|
||||||
|
@ -553,7 +553,7 @@ class ActionsMap(object):
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
error_message = "unable to load function %s.%s because: %s" % (
|
error_message = "unable to load function {}.{} because: {}".format(
|
||||||
namespace,
|
namespace,
|
||||||
func_name,
|
func_name,
|
||||||
e,
|
e,
|
||||||
|
|
|
@ -10,7 +10,7 @@ logger = logging.getLogger("moulinette.authenticator")
|
||||||
# Base Class -----------------------------------------------------------
|
# Base Class -----------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
class BaseAuthenticator(object):
|
class BaseAuthenticator:
|
||||||
|
|
||||||
"""Authenticator base representation
|
"""Authenticator base representation
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ def during_unittests_run():
|
||||||
# Internationalization -------------------------------------------------
|
# Internationalization -------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
class Translator(object):
|
class Translator:
|
||||||
|
|
||||||
"""Internationalization class
|
"""Internationalization class
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ class Translator(object):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class Moulinette18n(object):
|
class Moulinette18n:
|
||||||
|
|
||||||
"""Internationalization service for the moulinette
|
"""Internationalization service for the moulinette
|
||||||
|
|
||||||
|
@ -197,7 +197,6 @@ class Moulinette18n(object):
|
||||||
self._global = Translator(global_locale_dir, default_locale)
|
self._global = Translator(global_locale_dir, default_locale)
|
||||||
|
|
||||||
def set_locales_dir(self, locales_dir):
|
def set_locales_dir(self, locales_dir):
|
||||||
|
|
||||||
self.translator = Translator(locales_dir, self.default_locale)
|
self.translator = Translator(locales_dir, self.default_locale)
|
||||||
|
|
||||||
def set_locale(self, locale):
|
def set_locale(self, locale):
|
||||||
|
@ -273,7 +272,7 @@ class MoulinetteAuthenticationError(MoulinetteError):
|
||||||
http_code = 401
|
http_code = 401
|
||||||
|
|
||||||
|
|
||||||
class MoulinetteLock(object):
|
class MoulinetteLock:
|
||||||
|
|
||||||
"""Locker for a moulinette instance
|
"""Locker for a moulinette instance
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ CALLBACKS_PROP = "_callbacks"
|
||||||
# Base Class -----------------------------------------------------------
|
# Base Class -----------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
class BaseActionsMapParser(object):
|
class BaseActionsMapParser:
|
||||||
|
|
||||||
"""Actions map's base Parser
|
"""Actions map's base Parser
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ class _CallbackAction(argparse.Action):
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
raise ValueError("unable to import method {0}".format(self.callback_method))
|
raise ValueError("unable to import method {}".format(self.callback_method))
|
||||||
self._callback = func
|
self._callback = func
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
|
@ -224,9 +224,8 @@ class _CallbackAction(argparse.Action):
|
||||||
# Execute callback and get returned value
|
# Execute callback and get returned value
|
||||||
value = self.callback(namespace, values, **self.callback_kwargs)
|
value = self.callback(namespace, values, **self.callback_kwargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_message = (
|
error_message = "cannot get value from callback method " "'{}': {}".format(
|
||||||
"cannot get value from callback method "
|
self.callback_method, e
|
||||||
"'{0}': {1}".format(self.callback_method, e)
|
|
||||||
)
|
)
|
||||||
logger.exception(error_message)
|
logger.exception(error_message)
|
||||||
raise MoulinetteError(error_message, raw_msg=True)
|
raise MoulinetteError(error_message, raw_msg=True)
|
||||||
|
@ -332,7 +331,7 @@ class ExtendedArgumentParser(argparse.ArgumentParser):
|
||||||
c.execute(namespace, v)
|
c.execute(namespace, v)
|
||||||
try:
|
try:
|
||||||
delattr(namespace, CALLBACKS_PROP)
|
delattr(namespace, CALLBACKS_PROP)
|
||||||
except:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _get_callbacks_queue(self, namespace, create=True):
|
def _get_callbacks_queue(self, namespace, create=True):
|
||||||
|
@ -562,7 +561,7 @@ class PositionalsFirstHelpFormatter(argparse.HelpFormatter):
|
||||||
usage = "\n".join(lines)
|
usage = "\n".join(lines)
|
||||||
|
|
||||||
# prefix with 'usage:'
|
# prefix with 'usage:'
|
||||||
return "%s%s\n\n" % (prefix, usage)
|
return "{}{}\n\n".format(prefix, usage)
|
||||||
|
|
||||||
|
|
||||||
class JSONExtendedEncoder(JSONEncoder):
|
class JSONExtendedEncoder(JSONEncoder):
|
||||||
|
|
|
@ -38,9 +38,7 @@ logger = log.getLogger("moulinette.interface.api")
|
||||||
# We define a global variable to manage in a dirty way the upload...
|
# We define a global variable to manage in a dirty way the upload...
|
||||||
UPLOAD_DIR = None
|
UPLOAD_DIR = None
|
||||||
|
|
||||||
CSRF_TYPES = set(
|
CSRF_TYPES = {"text/plain", "application/x-www-form-urlencoded", "multipart/form-data"}
|
||||||
["text/plain", "application/x-www-form-urlencoded", "multipart/form-data"]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def is_csrf():
|
def is_csrf():
|
||||||
|
@ -101,7 +99,7 @@ class APIQueueHandler(logging.Handler):
|
||||||
sleep(0)
|
sleep(0)
|
||||||
|
|
||||||
|
|
||||||
class _HTTPArgumentParser(object):
|
class _HTTPArgumentParser:
|
||||||
|
|
||||||
"""Argument parser for HTTP requests
|
"""Argument parser for HTTP requests
|
||||||
|
|
||||||
|
@ -239,6 +237,7 @@ class Session:
|
||||||
secret = random_ascii()
|
secret = random_ascii()
|
||||||
cookie_name = None # This is later set to the actionsmap name
|
cookie_name = None # This is later set to the actionsmap name
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def set_infos(infos):
|
def set_infos(infos):
|
||||||
|
|
||||||
assert isinstance(infos, dict)
|
assert isinstance(infos, dict)
|
||||||
|
@ -252,6 +251,7 @@ class Session:
|
||||||
# samesite="strict", # Bottle 0.12 doesn't support samesite, to be added in next versions
|
# samesite="strict", # Bottle 0.12 doesn't support samesite, to be added in next versions
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def get_infos(raise_if_no_session_exists=True):
|
def get_infos(raise_if_no_session_exists=True):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -275,7 +275,7 @@ class Session:
|
||||||
response.delete_cookie(f"session.{Session.cookie_name}")
|
response.delete_cookie(f"session.{Session.cookie_name}")
|
||||||
|
|
||||||
|
|
||||||
class _ActionsMapPlugin(object):
|
class _ActionsMapPlugin:
|
||||||
|
|
||||||
"""Actions map Bottle Plugin
|
"""Actions map Bottle Plugin
|
||||||
|
|
||||||
|
@ -667,24 +667,29 @@ class ActionsMapParser(BaseActionsMapParser):
|
||||||
# Retrieve the tid for the route
|
# Retrieve the tid for the route
|
||||||
_, parser = self._parsers[route]
|
_, parser = self._parsers[route]
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
error_message = "no argument parser found for route '%s': %s" % (route, e)
|
error_message = "no argument parser found for route '{}': {}".format(
|
||||||
|
route, e
|
||||||
|
)
|
||||||
logger.error(error_message)
|
logger.error(error_message)
|
||||||
raise MoulinetteValidationError(error_message, raw_msg=True)
|
raise MoulinetteValidationError(error_message, raw_msg=True)
|
||||||
|
|
||||||
return parser.authentication
|
return parser.authentication
|
||||||
|
|
||||||
def parse_args(self, args, route, **kwargs):
|
def parse_args(self, args, **kwargs):
|
||||||
"""Parse arguments
|
"""Parse arguments
|
||||||
|
|
||||||
Keyword arguments:
|
Keyword arguments:
|
||||||
- route -- The action route as a 2-tuple (method, path)
|
- route -- The action route as a 2-tuple (method, path)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
route = kwargs["route"]
|
||||||
try:
|
try:
|
||||||
# Retrieve the parser for the route
|
# Retrieve the parser for the route
|
||||||
_, parser = self._parsers[route]
|
_, parser = self._parsers[route]
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
error_message = "no argument parser found for route '%s': %s" % (route, e)
|
error_message = "no argument parser found for route '{}': {}".format(
|
||||||
|
route, e
|
||||||
|
)
|
||||||
logger.error(error_message)
|
logger.error(error_message)
|
||||||
raise MoulinetteValidationError(error_message, raw_msg=True)
|
raise MoulinetteValidationError(error_message, raw_msg=True)
|
||||||
ret = argparse.Namespace()
|
ret = argparse.Namespace()
|
||||||
|
|
|
@ -251,7 +251,7 @@ class TTYHandler(logging.StreamHandler):
|
||||||
# add translated level name before message
|
# add translated level name before message
|
||||||
level = "%s " % m18n.g(record.levelname.lower())
|
level = "%s " % m18n.g(record.levelname.lower())
|
||||||
color = self.LEVELS_COLOR.get(record.levelno, "white")
|
color = self.LEVELS_COLOR.get(record.levelno, "white")
|
||||||
msg = "{0}{1}{2}{3}".format(colors_codes[color], level, END_CLI_COLOR, msg)
|
msg = "{}{}{}{}".format(colors_codes[color], level, END_CLI_COLOR, msg)
|
||||||
if self.formatter:
|
if self.formatter:
|
||||||
# use user-defined formatter
|
# use user-defined formatter
|
||||||
record.__dict__[self.message_key] = msg
|
record.__dict__[self.message_key] = msg
|
||||||
|
@ -403,7 +403,7 @@ class ActionsMapParser(BaseActionsMapParser):
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_message = "unable to parse arguments '%s' because: %s" % (
|
error_message = "unable to parse arguments '{}' because: {}".format(
|
||||||
" ".join(args),
|
" ".join(args),
|
||||||
e,
|
e,
|
||||||
)
|
)
|
||||||
|
@ -435,7 +435,7 @@ class ActionsMapParser(BaseActionsMapParser):
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_message = "unable to parse arguments '%s' because: %s" % (
|
error_message = "unable to parse arguments '{}' because: {}".format(
|
||||||
" ".join(args),
|
" ".join(args),
|
||||||
e,
|
e,
|
||||||
)
|
)
|
||||||
|
|
|
@ -24,7 +24,7 @@ def read_file(file_path, file_mode="r"):
|
||||||
"""
|
"""
|
||||||
assert isinstance(
|
assert isinstance(
|
||||||
file_path, str
|
file_path, str
|
||||||
), "Error: file_path '%s' should be a string but is of type '%s' instead" % (
|
), "Error: file_path '{}' should be a string but is of type '{}' instead".format(
|
||||||
file_path,
|
file_path,
|
||||||
type(file_path),
|
type(file_path),
|
||||||
)
|
)
|
||||||
|
@ -121,7 +121,7 @@ def write_to_file(file_path, data, file_mode="w"):
|
||||||
"""
|
"""
|
||||||
assert (
|
assert (
|
||||||
isinstance(data, str) or isinstance(data, bytes) or isinstance(data, list)
|
isinstance(data, str) or isinstance(data, bytes) or isinstance(data, list)
|
||||||
), "Error: data '%s' should be either a string or a list but is of type '%s'" % (
|
), "Error: data '{}' should be either a string or a list but is of type '{}'".format(
|
||||||
data,
|
data,
|
||||||
type(data),
|
type(data),
|
||||||
)
|
)
|
||||||
|
@ -130,7 +130,7 @@ def write_to_file(file_path, data, file_mode="w"):
|
||||||
)
|
)
|
||||||
assert os.path.isdir(
|
assert os.path.isdir(
|
||||||
os.path.dirname(file_path)
|
os.path.dirname(file_path)
|
||||||
), "Error: the path ('%s') base dir ('%s') is not a dir" % (
|
), "Error: the path ('{}') base dir ('{}') is not a dir".format(
|
||||||
file_path,
|
file_path,
|
||||||
os.path.dirname(file_path),
|
os.path.dirname(file_path),
|
||||||
)
|
)
|
||||||
|
@ -140,7 +140,7 @@ def write_to_file(file_path, data, file_mode="w"):
|
||||||
for element in data:
|
for element in data:
|
||||||
assert isinstance(
|
assert isinstance(
|
||||||
element, str
|
element, str
|
||||||
), "Error: element '%s' should be a string but is of type '%s' instead" % (
|
), "Error: element '{}' should be a string but is of type '{}' instead".format(
|
||||||
element,
|
element,
|
||||||
type(element),
|
type(element),
|
||||||
)
|
)
|
||||||
|
@ -179,13 +179,13 @@ def write_to_json(file_path, data, sort_keys=False, indent=None):
|
||||||
# Assumptions
|
# Assumptions
|
||||||
assert isinstance(
|
assert isinstance(
|
||||||
file_path, str
|
file_path, str
|
||||||
), "Error: file_path '%s' should be a string but is of type '%s' instead" % (
|
), "Error: file_path '{}' should be a string but is of type '{}' instead".format(
|
||||||
file_path,
|
file_path,
|
||||||
type(file_path),
|
type(file_path),
|
||||||
)
|
)
|
||||||
assert isinstance(data, dict) or isinstance(
|
assert isinstance(data, dict) or isinstance(
|
||||||
data, list
|
data, list
|
||||||
), "Error: data '%s' should be a dict or a list but is of type '%s' instead" % (
|
), "Error: data '{}' should be a dict or a list but is of type '{}' instead".format(
|
||||||
data,
|
data,
|
||||||
type(data),
|
type(data),
|
||||||
)
|
)
|
||||||
|
@ -194,7 +194,7 @@ def write_to_json(file_path, data, sort_keys=False, indent=None):
|
||||||
)
|
)
|
||||||
assert os.path.isdir(
|
assert os.path.isdir(
|
||||||
os.path.dirname(file_path)
|
os.path.dirname(file_path)
|
||||||
), "Error: the path ('%s') base dir ('%s') is not a dir" % (
|
), "Error: the path ('{}') base dir ('{}') is not a dir".format(
|
||||||
file_path,
|
file_path,
|
||||||
os.path.dirname(file_path),
|
os.path.dirname(file_path),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import os
|
import os
|
||||||
import logging
|
|
||||||
|
|
||||||
# import all constants because other modules try to import them from this
|
# import all constants because other modules try to import them from this
|
||||||
# module because SUCCESS is defined in this module
|
# module because SUCCESS is defined in this module
|
||||||
|
@ -70,8 +69,11 @@ def configure_logging(logging_config=None):
|
||||||
|
|
||||||
def getHandlersByClass(classinfo, limit=0):
|
def getHandlersByClass(classinfo, limit=0):
|
||||||
"""Retrieve registered handlers of a given class."""
|
"""Retrieve registered handlers of a given class."""
|
||||||
|
|
||||||
|
from logging import _handlers
|
||||||
|
|
||||||
handlers = []
|
handlers = []
|
||||||
for ref in logging._handlers.itervaluerefs():
|
for ref in _handlers.itervaluerefs():
|
||||||
o = ref()
|
o = ref()
|
||||||
if o is not None and isinstance(o, classinfo):
|
if o is not None and isinstance(o, classinfo):
|
||||||
if limit == 1:
|
if limit == 1:
|
||||||
|
@ -102,14 +104,17 @@ class MoulinetteLogger(Logger):
|
||||||
|
|
||||||
def findCaller(self, *args):
|
def findCaller(self, *args):
|
||||||
"""Override findCaller method to consider this source file."""
|
"""Override findCaller method to consider this source file."""
|
||||||
f = logging.currentframe()
|
|
||||||
|
from logging import currentframe, _srcfile
|
||||||
|
|
||||||
|
f = currentframe()
|
||||||
if f is not None:
|
if f is not None:
|
||||||
f = f.f_back
|
f = f.f_back
|
||||||
rv = "(unknown file)", 0, "(unknown function)"
|
rv = "(unknown file)", 0, "(unknown function)"
|
||||||
while hasattr(f, "f_code"):
|
while hasattr(f, "f_code"):
|
||||||
co = f.f_code
|
co = f.f_code
|
||||||
filename = os.path.normcase(co.co_filename)
|
filename = os.path.normcase(co.co_filename)
|
||||||
if filename == logging._srcfile or filename == __file__:
|
if filename == _srcfile or filename == __file__:
|
||||||
f = f.f_back
|
f = f.f_back
|
||||||
continue
|
continue
|
||||||
rv = (co.co_filename, f.f_lineno, co.co_name)
|
rv = (co.co_filename, f.f_lineno, co.co_name)
|
||||||
|
@ -167,7 +172,7 @@ def getActionLogger(name=None, logger=None, action_id=None):
|
||||||
return logger
|
return logger
|
||||||
|
|
||||||
|
|
||||||
class ActionFilter(object):
|
class ActionFilter:
|
||||||
|
|
||||||
"""Extend log record for an optionnal action
|
"""Extend log record for an optionnal action
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ def searchf(pattern, path, count=0, flags=re.MULTILINE):
|
||||||
def prependlines(text, prepend):
|
def prependlines(text, prepend):
|
||||||
"""Prepend a string to each line of a text"""
|
"""Prepend a string to each line of a text"""
|
||||||
lines = text.splitlines(True)
|
lines = text.splitlines(True)
|
||||||
return "%s%s" % (prepend, prepend.join(lines))
|
return "{}{}".format(prepend, prepend.join(lines))
|
||||||
|
|
||||||
|
|
||||||
# Randomize ------------------------------------------------------------
|
# Randomize ------------------------------------------------------------
|
||||||
|
|
|
@ -31,7 +31,7 @@ def patch_translate(moulinette):
|
||||||
|
|
||||||
def logging_configuration(moulinette):
|
def logging_configuration(moulinette):
|
||||||
"""Configure logging to use the custom logger."""
|
"""Configure logging to use the custom logger."""
|
||||||
handlers = set(["tty", "api"])
|
handlers = {"tty", "api"}
|
||||||
root_handlers = set(handlers)
|
root_handlers = set(handlers)
|
||||||
|
|
||||||
level = "INFO"
|
level = "INFO"
|
||||||
|
|
|
@ -192,10 +192,12 @@ def test_extra_argument_parser_add_argument_bad_arg(iface):
|
||||||
with pytest.raises(MoulinetteError) as exception:
|
with pytest.raises(MoulinetteError) as exception:
|
||||||
extra_argument_parse.add_argument("_global", "foo", {"ask": 1})
|
extra_argument_parse.add_argument("_global", "foo", {"ask": 1})
|
||||||
|
|
||||||
expected_msg = "unable to validate extra parameter '%s' for argument '%s': %s" % (
|
expected_msg = (
|
||||||
"ask",
|
"unable to validate extra parameter '{}' for argument '{}': {}".format(
|
||||||
"foo",
|
"ask",
|
||||||
"parameter value must be a string, got 1",
|
"foo",
|
||||||
|
"parameter value must be a string, got 1",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
assert expected_msg in str(exception)
|
assert expected_msg in str(exception)
|
||||||
|
|
||||||
|
@ -266,7 +268,7 @@ def test_actions_map_import_error(mocker):
|
||||||
with pytest.raises(MoulinetteError) as exception:
|
with pytest.raises(MoulinetteError) as exception:
|
||||||
amap.process({}, timeout=30, route=("GET", "/test-auth/none"))
|
amap.process({}, timeout=30, route=("GET", "/test-auth/none"))
|
||||||
|
|
||||||
expected_msg = "unable to load function % s.%s because: %s" % (
|
expected_msg = "unable to load function {}.{} because: {}".format(
|
||||||
"moulitest",
|
"moulitest",
|
||||||
"testauth_none",
|
"testauth_none",
|
||||||
"Yoloswag",
|
"Yoloswag",
|
||||||
|
|
|
@ -26,10 +26,10 @@ def find_inconsistencies(locale_file):
|
||||||
# Then we check that every "{stuff}" (for python's .format())
|
# Then we check that every "{stuff}" (for python's .format())
|
||||||
# should also be in the translated string, otherwise the .format
|
# should also be in the translated string, otherwise the .format
|
||||||
# will trigger an exception!
|
# will trigger an exception!
|
||||||
subkeys_in_ref = set(k[0] for k in re.findall(r"{(\w+)(:\w)?}", string))
|
subkeys_in_ref = {k[0] for k in re.findall(r"{(\w+)(:\w)?}", string)}
|
||||||
subkeys_in_this_locale = set(
|
subkeys_in_this_locale = {
|
||||||
k[0] for k in re.findall(r"{(\w+)(:\w)?}", this_locale[key])
|
k[0] for k in re.findall(r"{(\w+)(:\w)?}", this_locale[key])
|
||||||
)
|
}
|
||||||
|
|
||||||
if any(k not in subkeys_in_ref for k in subkeys_in_this_locale):
|
if any(k not in subkeys_in_ref for k in subkeys_in_this_locale):
|
||||||
yield """\n
|
yield """\n
|
||||||
|
|
|
@ -5,7 +5,7 @@ from moulinette.interfaces import JSONExtendedEncoder
|
||||||
def test_json_extended_encoder(caplog):
|
def test_json_extended_encoder(caplog):
|
||||||
encoder = JSONExtendedEncoder()
|
encoder = JSONExtendedEncoder()
|
||||||
|
|
||||||
assert encoder.default(set([1, 2, 3])) == [1, 2, 3]
|
assert encoder.default({1, 2, 3}) == [1, 2, 3]
|
||||||
|
|
||||||
assert encoder.default(dt(1917, 3, 8)) == "1917-03-08T00:00:00+00:00"
|
assert encoder.default(dt(1917, 3, 8)) == "1917-03-08T00:00:00+00:00"
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,10 @@ def find_inconsistencies(locale_file):
|
||||||
# Then we check that every "{stuff}" (for python's .format())
|
# Then we check that every "{stuff}" (for python's .format())
|
||||||
# should also be in the translated string, otherwise the .format
|
# should also be in the translated string, otherwise the .format
|
||||||
# will trigger an exception!
|
# will trigger an exception!
|
||||||
subkeys_in_ref = set(k[0] for k in re.findall(r"{(\w+)(:\w)?}", string))
|
subkeys_in_ref = {k[0] for k in re.findall(r"{(\w+)(:\w)?}", string)}
|
||||||
subkeys_in_this_locale = set(
|
subkeys_in_this_locale = {
|
||||||
k[0] for k in re.findall(r"{(\w+)(:\w)?}", this_locale[key])
|
k[0] for k in re.findall(r"{(\w+)(:\w)?}", this_locale[key])
|
||||||
)
|
}
|
||||||
|
|
||||||
if any(k not in subkeys_in_ref for k in subkeys_in_this_locale):
|
if any(k not in subkeys_in_ref for k in subkeys_in_this_locale):
|
||||||
yield """\n
|
yield """\n
|
||||||
|
|
Loading…
Reference in a new issue