mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
commit
092d6f9df7
6 changed files with 417 additions and 254 deletions
|
@ -511,7 +511,12 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False
|
|||
|
||||
"""
|
||||
from packaging import version
|
||||
from yunohost.hook import hook_add, hook_remove, hook_callback, hook_exec_with_script_debug_if_failure
|
||||
from yunohost.hook import (
|
||||
hook_add,
|
||||
hook_remove,
|
||||
hook_callback,
|
||||
hook_exec_with_script_debug_if_failure,
|
||||
)
|
||||
from yunohost.permission import permission_sync_to_user
|
||||
from yunohost.regenconf import manually_modified_files
|
||||
|
||||
|
@ -633,12 +638,17 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False
|
|||
# Execute the app upgrade script
|
||||
upgrade_failed = True
|
||||
try:
|
||||
upgrade_failed, failure_message_with_debug_instructions = hook_exec_with_script_debug_if_failure(
|
||||
(
|
||||
upgrade_failed,
|
||||
failure_message_with_debug_instructions,
|
||||
) = hook_exec_with_script_debug_if_failure(
|
||||
extracted_app_folder + "/scripts/upgrade",
|
||||
env=env_dict,
|
||||
operation_logger=operation_logger,
|
||||
error_message_if_script_failed=m18n.n("app_upgrade_script_failed"),
|
||||
error_message_if_failed=lambda e: m18n.n("app_upgrade_failed", app=app_instance_name, error=e)
|
||||
error_message_if_failed=lambda e: m18n.n(
|
||||
"app_upgrade_failed", app=app_instance_name, error=e
|
||||
),
|
||||
)
|
||||
finally:
|
||||
# Whatever happened (install success or failure) we check if it broke the system
|
||||
|
@ -669,7 +679,7 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False
|
|||
if upgrade_failed or broke_the_system:
|
||||
|
||||
# display this if there are remaining apps
|
||||
if apps[number + 1:]:
|
||||
if apps[number + 1 :]:
|
||||
not_upgraded_apps = apps[number:]
|
||||
logger.error(
|
||||
m18n.n(
|
||||
|
@ -785,7 +795,13 @@ def app_install(
|
|||
force -- Do not ask for confirmation when installing experimental / low-quality apps
|
||||
"""
|
||||
|
||||
from yunohost.hook import hook_add, hook_remove, hook_callback, hook_exec, hook_exec_with_script_debug_if_failure
|
||||
from yunohost.hook import (
|
||||
hook_add,
|
||||
hook_remove,
|
||||
hook_callback,
|
||||
hook_exec,
|
||||
hook_exec_with_script_debug_if_failure,
|
||||
)
|
||||
from yunohost.log import OperationLogger
|
||||
from yunohost.permission import (
|
||||
user_permission_list,
|
||||
|
@ -976,12 +992,17 @@ def app_install(
|
|||
# Execute the app install script
|
||||
install_failed = True
|
||||
try:
|
||||
install_failed, failure_message_with_debug_instructions = hook_exec_with_script_debug_if_failure(
|
||||
(
|
||||
install_failed,
|
||||
failure_message_with_debug_instructions,
|
||||
) = hook_exec_with_script_debug_if_failure(
|
||||
os.path.join(extracted_app_folder, "scripts/install"),
|
||||
env=env_dict,
|
||||
operation_logger=operation_logger,
|
||||
error_message_if_script_failed=m18n.n("app_install_script_failed"),
|
||||
error_message_if_failed=lambda e: m18n.n("app_install_failed", app=app_id, error=e)
|
||||
error_message_if_failed=lambda e: m18n.n(
|
||||
"app_install_failed", app=app_id, error=e
|
||||
),
|
||||
)
|
||||
finally:
|
||||
# If success so far, validate that app didn't break important stuff
|
||||
|
@ -1670,7 +1691,9 @@ def app_config_get(app, key="", full=False, export=False):
|
|||
Display an app configuration in classic, full or export mode
|
||||
"""
|
||||
if full and export:
|
||||
raise YunohostValidationError("You can't use --full and --export together.", raw_msg=True)
|
||||
raise YunohostValidationError(
|
||||
"You can't use --full and --export together.", raw_msg=True
|
||||
)
|
||||
|
||||
if full:
|
||||
mode = "full"
|
||||
|
|
|
@ -1496,13 +1496,18 @@ class RestoreManager:
|
|||
# Execute the app install script
|
||||
restore_failed = True
|
||||
try:
|
||||
restore_failed, failure_message_with_debug_instructions = hook_exec_with_script_debug_if_failure(
|
||||
(
|
||||
restore_failed,
|
||||
failure_message_with_debug_instructions,
|
||||
) = hook_exec_with_script_debug_if_failure(
|
||||
restore_script,
|
||||
chdir=app_backup_in_archive,
|
||||
env=env_dict,
|
||||
operation_logger=operation_logger,
|
||||
error_message_if_script_failed=m18n.n("app_restore_script_failed"),
|
||||
error_message_if_failed=lambda e: m18n.n("app_restore_failed", app=app_instance_name, error=e)
|
||||
error_message_if_failed=lambda e: m18n.n(
|
||||
"app_restore_failed", app=app_instance_name, error=e
|
||||
),
|
||||
)
|
||||
finally:
|
||||
# Cleaning temporary scripts directory
|
||||
|
|
|
@ -288,7 +288,11 @@ def service_reload_or_restart(names, test_conf=True):
|
|||
if p.returncode != 0:
|
||||
errors = out.decode().strip().split("\n")
|
||||
logger.error(
|
||||
m18n.n("service_not_reloading_because_conf_broken", name=name, errors=errors)
|
||||
m18n.n(
|
||||
"service_not_reloading_because_conf_broken",
|
||||
name=name,
|
||||
errors=errors,
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
|
|
|
@ -80,7 +80,6 @@ def legacy_app(request):
|
|||
return "legacy_app"
|
||||
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def config_app(request):
|
||||
|
||||
|
@ -168,7 +167,10 @@ def test_app_config_bind_on_file(config_app):
|
|||
def test_app_config_custom_get(config_app):
|
||||
|
||||
assert app_setting(config_app, "arg9") is None
|
||||
assert "Files in /var/www" in app_config_get(config_app, "bind.function.arg9")["ask"]["en"]
|
||||
assert (
|
||||
"Files in /var/www"
|
||||
in app_config_get(config_app, "bind.function.arg9")["ask"]["en"]
|
||||
)
|
||||
assert app_setting(config_app, "arg9") is None
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ from yunohost import domain, user
|
|||
from yunohost.utils.config import (
|
||||
parse_args_in_yunohost_format,
|
||||
PasswordQuestion,
|
||||
Question
|
||||
Question,
|
||||
)
|
||||
from yunohost.utils.error import YunohostError
|
||||
|
||||
|
@ -75,8 +75,7 @@ def test_question_string_no_input():
|
|||
]
|
||||
answers = {}
|
||||
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(os, "isatty", return_value=False):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
|
||||
|
||||
|
@ -90,8 +89,9 @@ def test_question_string_input():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_string": ("some_value", "string")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -104,8 +104,9 @@ def test_question_string_input_no_ask():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_string": ("some_value", "string")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -133,8 +134,9 @@ def test_question_string_optional_with_input():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_string": ("some_value", "string")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -149,8 +151,9 @@ def test_question_string_optional_with_empty_input():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_string": ("", "string")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value=""), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value=""), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -164,8 +167,9 @@ def test_question_string_optional_with_input_without_ask():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_string": ("some_value", "string")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -198,8 +202,11 @@ def test_question_string_input_test_ask():
|
|||
) as prompt, patch.object(os, "isatty", return_value=True):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
prompt.assert_called_with(
|
||||
message=ask_text, is_password=False, confirm=False,
|
||||
prefill='', is_multiline=False
|
||||
message=ask_text,
|
||||
is_password=False,
|
||||
confirm=False,
|
||||
prefill="",
|
||||
is_multiline=False,
|
||||
)
|
||||
|
||||
|
||||
|
@ -221,8 +228,10 @@ def test_question_string_input_test_ask_with_default():
|
|||
parse_args_in_yunohost_format(answers, questions)
|
||||
prompt.assert_called_with(
|
||||
message=ask_text,
|
||||
is_password=False, confirm=False,
|
||||
prefill=default_text, is_multiline=False
|
||||
is_password=False,
|
||||
confirm=False,
|
||||
prefill=default_text,
|
||||
is_multiline=False,
|
||||
)
|
||||
|
||||
|
||||
|
@ -243,8 +252,8 @@ def test_question_string_input_test_ask_with_example():
|
|||
Moulinette, "prompt", return_value="some_value"
|
||||
) as prompt, patch.object(os, "isatty", return_value=True):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
assert ask_text in prompt.call_args[1]['message']
|
||||
assert example_text in prompt.call_args[1]['message']
|
||||
assert ask_text in prompt.call_args[1]["message"]
|
||||
assert example_text in prompt.call_args[1]["message"]
|
||||
|
||||
|
||||
@pytest.mark.skip # we should do something with this help
|
||||
|
@ -264,8 +273,8 @@ def test_question_string_input_test_ask_with_help():
|
|||
Moulinette, "prompt", return_value="some_value"
|
||||
) as prompt, patch.object(os, "isatty", return_value=True):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
assert ask_text in prompt.call_args[1]['message']
|
||||
assert help_text in prompt.call_args[1]['message']
|
||||
assert ask_text in prompt.call_args[1]["message"]
|
||||
assert help_text in prompt.call_args[1]["message"]
|
||||
|
||||
|
||||
def test_question_string_with_choice():
|
||||
|
@ -279,8 +288,9 @@ def test_question_string_with_choice_prompt():
|
|||
questions = [{"name": "some_string", "type": "string", "choices": ["fr", "en"]}]
|
||||
answers = {"some_string": "fr"}
|
||||
expected_result = OrderedDict({"some_string": ("fr", "string")})
|
||||
with patch.object(Moulinette, "prompt", return_value="fr"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="fr"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -288,8 +298,7 @@ def test_question_string_with_choice_bad():
|
|||
questions = [{"name": "some_string", "type": "string", "choices": ["fr", "en"]}]
|
||||
answers = {"some_string": "bad"}
|
||||
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(os, "isatty", return_value=False):
|
||||
assert parse_args_in_yunohost_format(answers, questions)
|
||||
|
||||
|
||||
|
@ -305,13 +314,14 @@ def test_question_string_with_choice_ask():
|
|||
]
|
||||
answers = {}
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="ru") as prompt, \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="ru") as prompt, patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
assert ask_text in prompt.call_args[1]['message']
|
||||
assert ask_text in prompt.call_args[1]["message"]
|
||||
|
||||
for choice in choices:
|
||||
assert choice in prompt.call_args[1]['message']
|
||||
assert choice in prompt.call_args[1]["message"]
|
||||
|
||||
|
||||
def test_question_string_with_choice_default():
|
||||
|
@ -352,8 +362,7 @@ def test_question_password_no_input():
|
|||
]
|
||||
answers = {}
|
||||
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(os, "isatty", return_value=False):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
|
||||
|
||||
|
@ -366,13 +375,15 @@ def test_question_password_input():
|
|||
}
|
||||
]
|
||||
answers = {}
|
||||
Question.operation_logger = { 'data_to_redact': [] }
|
||||
Question.operation_logger = {"data_to_redact": []}
|
||||
expected_result = OrderedDict({"some_password": ("some_value", "password")})
|
||||
|
||||
Question.operation_logger = MagicMock()
|
||||
with patch.object(Question.operation_logger, "data_to_redact", create=True), \
|
||||
patch.object(Moulinette, "prompt", return_value="some_value"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(
|
||||
Question.operation_logger, "data_to_redact", create=True
|
||||
), patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -387,9 +398,11 @@ def test_question_password_input_no_ask():
|
|||
expected_result = OrderedDict({"some_password": ("some_value", "password")})
|
||||
|
||||
Question.operation_logger = MagicMock()
|
||||
with patch.object(Question.operation_logger, "data_to_redact", create=True), \
|
||||
patch.object(Moulinette, "prompt", return_value="some_value"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(
|
||||
Question.operation_logger, "data_to_redact", create=True
|
||||
), patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -405,8 +418,9 @@ def test_question_password_no_input_optional():
|
|||
expected_result = OrderedDict({"some_password": ("", "password")})
|
||||
|
||||
Question.operation_logger = MagicMock()
|
||||
with patch.object(Question.operation_logger, "data_to_redact", create=True), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with patch.object(
|
||||
Question.operation_logger, "data_to_redact", create=True
|
||||
), patch.object(os, "isatty", return_value=False):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
questions = [
|
||||
|
@ -414,8 +428,9 @@ def test_question_password_no_input_optional():
|
|||
]
|
||||
|
||||
Question.operation_logger = MagicMock()
|
||||
with patch.object(Question.operation_logger, "data_to_redact", create=True), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with patch.object(
|
||||
Question.operation_logger, "data_to_redact", create=True
|
||||
), patch.object(os, "isatty", return_value=False):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -432,9 +447,11 @@ def test_question_password_optional_with_input():
|
|||
expected_result = OrderedDict({"some_password": ("some_value", "password")})
|
||||
|
||||
Question.operation_logger = MagicMock()
|
||||
with patch.object(Question.operation_logger, "data_to_redact", create=True), \
|
||||
patch.object(Moulinette, "prompt", return_value="some_value"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(
|
||||
Question.operation_logger, "data_to_redact", create=True
|
||||
), patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -451,9 +468,11 @@ def test_question_password_optional_with_empty_input():
|
|||
expected_result = OrderedDict({"some_password": ("", "password")})
|
||||
|
||||
Question.operation_logger = MagicMock()
|
||||
with patch.object(Question.operation_logger, "data_to_redact", create=True), \
|
||||
patch.object(Moulinette, "prompt", return_value=""), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(
|
||||
Question.operation_logger, "data_to_redact", create=True
|
||||
), patch.object(Moulinette, "prompt", return_value=""), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -469,9 +488,11 @@ def test_question_password_optional_with_input_without_ask():
|
|||
expected_result = OrderedDict({"some_password": ("some_value", "password")})
|
||||
|
||||
Question.operation_logger = MagicMock()
|
||||
with patch.object(Question.operation_logger, "data_to_redact", create=True), \
|
||||
patch.object(Moulinette, "prompt", return_value="some_value"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(
|
||||
Question.operation_logger, "data_to_redact", create=True
|
||||
), patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -487,8 +508,7 @@ def test_question_password_no_input_default():
|
|||
answers = {}
|
||||
|
||||
# no default for password!
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(os, "isatty", return_value=False):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
|
||||
|
||||
|
@ -505,8 +525,7 @@ def test_question_password_no_input_example():
|
|||
answers = {"some_password": "some_value"}
|
||||
|
||||
# no example for password!
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(os, "isatty", return_value=False):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
|
||||
|
||||
|
@ -522,14 +541,20 @@ def test_question_password_input_test_ask():
|
|||
answers = {}
|
||||
|
||||
Question.operation_logger = MagicMock()
|
||||
with patch.object(Question.operation_logger, "data_to_redact", create=True), \
|
||||
patch.object(Moulinette, "prompt", return_value="some_value") as prompt, \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(
|
||||
Question.operation_logger, "data_to_redact", create=True
|
||||
), patch.object(
|
||||
Moulinette, "prompt", return_value="some_value"
|
||||
) as prompt, patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
prompt.assert_called_with(
|
||||
message=ask_text,
|
||||
is_password=True, confirm=True,
|
||||
prefill='', is_multiline=False
|
||||
is_password=True,
|
||||
confirm=True,
|
||||
prefill="",
|
||||
is_multiline=False,
|
||||
)
|
||||
|
||||
|
||||
|
@ -548,12 +573,16 @@ def test_question_password_input_test_ask_with_example():
|
|||
answers = {}
|
||||
|
||||
Question.operation_logger = MagicMock()
|
||||
with patch.object(Question.operation_logger, "data_to_redact", create=True), \
|
||||
patch.object(Moulinette, "prompt", return_value="some_value") as prompt, \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(
|
||||
Question.operation_logger, "data_to_redact", create=True
|
||||
), patch.object(
|
||||
Moulinette, "prompt", return_value="some_value"
|
||||
) as prompt, patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
assert ask_text in prompt.call_args[1]['message']
|
||||
assert example_text in prompt.call_args[1]['message']
|
||||
assert ask_text in prompt.call_args[1]["message"]
|
||||
assert example_text in prompt.call_args[1]["message"]
|
||||
|
||||
|
||||
@pytest.mark.skip # we should do something with this help
|
||||
|
@ -571,12 +600,16 @@ def test_question_password_input_test_ask_with_help():
|
|||
answers = {}
|
||||
|
||||
Question.operation_logger = MagicMock()
|
||||
with patch.object(Question.operation_logger, "data_to_redact", create=True), \
|
||||
patch.object(Moulinette, "prompt", return_value="some_value") as prompt, \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(
|
||||
Question.operation_logger, "data_to_redact", create=True
|
||||
), patch.object(
|
||||
Moulinette, "prompt", return_value="some_value"
|
||||
) as prompt, patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
assert ask_text in prompt.call_args[1]['message']
|
||||
assert help_text in prompt.call_args[1]['message']
|
||||
assert ask_text in prompt.call_args[1]["message"]
|
||||
assert help_text in prompt.call_args[1]["message"]
|
||||
|
||||
|
||||
def test_question_password_bad_chars():
|
||||
|
@ -590,8 +623,9 @@ def test_question_password_bad_chars():
|
|||
]
|
||||
|
||||
for i in PasswordQuestion.forbidden_chars:
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(
|
||||
os, "isatty", return_value=False
|
||||
):
|
||||
parse_args_in_yunohost_format({"some_password": i * 8}, questions)
|
||||
|
||||
|
||||
|
@ -605,13 +639,11 @@ def test_question_password_strong_enough():
|
|||
}
|
||||
]
|
||||
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(os, "isatty", return_value=False):
|
||||
# too short
|
||||
parse_args_in_yunohost_format({"some_password": "a"}, questions)
|
||||
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(os, "isatty", return_value=False):
|
||||
parse_args_in_yunohost_format({"some_password": "password"}, questions)
|
||||
|
||||
|
||||
|
@ -625,13 +657,11 @@ def test_question_password_optional_strong_enough():
|
|||
}
|
||||
]
|
||||
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(os, "isatty", return_value=False):
|
||||
# too short
|
||||
parse_args_in_yunohost_format({"some_password": "a"}, questions)
|
||||
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(os, "isatty", return_value=False):
|
||||
parse_args_in_yunohost_format({"some_password": "password"}, questions)
|
||||
|
||||
|
||||
|
@ -656,8 +686,7 @@ def test_question_path_no_input():
|
|||
]
|
||||
answers = {}
|
||||
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(os, "isatty", return_value=False):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
|
||||
|
||||
|
@ -672,8 +701,9 @@ def test_question_path_input():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_path": ("some_value", "path")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -687,8 +717,9 @@ def test_question_path_input_no_ask():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_path": ("some_value", "path")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -718,8 +749,9 @@ def test_question_path_optional_with_input():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_path": ("some_value", "path")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -735,8 +767,9 @@ def test_question_path_optional_with_empty_input():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_path": ("", "path")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value=""), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value=""), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -751,8 +784,9 @@ def test_question_path_optional_with_input_without_ask():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_path": ("some_value", "path")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="some_value"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -788,8 +822,10 @@ def test_question_path_input_test_ask():
|
|||
parse_args_in_yunohost_format(answers, questions)
|
||||
prompt.assert_called_with(
|
||||
message=ask_text,
|
||||
is_password=False, confirm=False,
|
||||
prefill='', is_multiline=False
|
||||
is_password=False,
|
||||
confirm=False,
|
||||
prefill="",
|
||||
is_multiline=False,
|
||||
)
|
||||
|
||||
|
||||
|
@ -812,8 +848,10 @@ def test_question_path_input_test_ask_with_default():
|
|||
parse_args_in_yunohost_format(answers, questions)
|
||||
prompt.assert_called_with(
|
||||
message=ask_text,
|
||||
is_password=False, confirm=False,
|
||||
prefill=default_text, is_multiline=False
|
||||
is_password=False,
|
||||
confirm=False,
|
||||
prefill=default_text,
|
||||
is_multiline=False,
|
||||
)
|
||||
|
||||
|
||||
|
@ -835,8 +873,8 @@ def test_question_path_input_test_ask_with_example():
|
|||
Moulinette, "prompt", return_value="some_value"
|
||||
) as prompt, patch.object(os, "isatty", return_value=True):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
assert ask_text in prompt.call_args[1]['message']
|
||||
assert example_text in prompt.call_args[1]['message']
|
||||
assert ask_text in prompt.call_args[1]["message"]
|
||||
assert example_text in prompt.call_args[1]["message"]
|
||||
|
||||
|
||||
@pytest.mark.skip # we should do something with this help
|
||||
|
@ -857,8 +895,8 @@ def test_question_path_input_test_ask_with_help():
|
|||
Moulinette, "prompt", return_value="some_value"
|
||||
) as prompt, patch.object(os, "isatty", return_value=True):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
assert ask_text in prompt.call_args[1]['message']
|
||||
assert help_text in prompt.call_args[1]['message']
|
||||
assert ask_text in prompt.call_args[1]["message"]
|
||||
assert help_text in prompt.call_args[1]["message"]
|
||||
|
||||
|
||||
def test_question_boolean():
|
||||
|
@ -906,8 +944,7 @@ def test_question_boolean_all_yes():
|
|||
== expected_result
|
||||
)
|
||||
assert (
|
||||
parse_args_in_yunohost_format({"some_boolean": 1}, questions)
|
||||
== expected_result
|
||||
parse_args_in_yunohost_format({"some_boolean": 1}, questions) == expected_result
|
||||
)
|
||||
assert (
|
||||
parse_args_in_yunohost_format({"some_boolean": True}, questions)
|
||||
|
@ -960,8 +997,7 @@ def test_question_boolean_all_no():
|
|||
== expected_result
|
||||
)
|
||||
assert (
|
||||
parse_args_in_yunohost_format({"some_boolean": 0}, questions)
|
||||
== expected_result
|
||||
parse_args_in_yunohost_format({"some_boolean": 0}, questions) == expected_result
|
||||
)
|
||||
assert (
|
||||
parse_args_in_yunohost_format({"some_boolean": False}, questions)
|
||||
|
@ -1005,8 +1041,7 @@ def test_question_boolean_bad_input():
|
|||
]
|
||||
answers = {"some_boolean": "stuff"}
|
||||
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(os, "isatty", return_value=False):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
|
||||
|
||||
|
@ -1021,13 +1056,15 @@ def test_question_boolean_input():
|
|||
answers = {}
|
||||
|
||||
expected_result = OrderedDict({"some_boolean": (1, "boolean")})
|
||||
with patch.object(Moulinette, "prompt", return_value="y"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="y"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
expected_result = OrderedDict({"some_boolean": (0, "boolean")})
|
||||
with patch.object(Moulinette, "prompt", return_value="n"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="n"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -1041,8 +1078,9 @@ def test_question_boolean_input_no_ask():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_boolean": (1, "boolean")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="y"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="y"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -1072,8 +1110,9 @@ def test_question_boolean_optional_with_input():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_boolean": (1, "boolean")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="y"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="y"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -1089,8 +1128,9 @@ def test_question_boolean_optional_with_empty_input():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_boolean": (0, "boolean")}) # default to false
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value=""), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value=""), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -1105,8 +1145,9 @@ def test_question_boolean_optional_with_input_without_ask():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_boolean": (0, "boolean")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="n"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="n"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -1150,13 +1191,16 @@ def test_question_boolean_input_test_ask():
|
|||
]
|
||||
answers = {}
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value=0) as prompt, \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value=0) as prompt, patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
prompt.assert_called_with(
|
||||
message=ask_text + " [yes | no]",
|
||||
is_password=False, confirm=False,
|
||||
prefill='no', is_multiline=False
|
||||
is_password=False,
|
||||
confirm=False,
|
||||
prefill="no",
|
||||
is_multiline=False,
|
||||
)
|
||||
|
||||
|
||||
|
@ -1173,13 +1217,16 @@ def test_question_boolean_input_test_ask_with_default():
|
|||
]
|
||||
answers = {}
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value=1) as prompt, \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value=1) as prompt, patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
prompt.assert_called_with(
|
||||
message=ask_text + " [yes | no]",
|
||||
is_password=False, confirm=False,
|
||||
prefill='yes', is_multiline=False
|
||||
is_password=False,
|
||||
confirm=False,
|
||||
prefill="yes",
|
||||
is_multiline=False,
|
||||
)
|
||||
|
||||
|
||||
|
@ -1194,9 +1241,13 @@ def test_question_domain_empty():
|
|||
expected_result = OrderedDict({"some_domain": (main_domain, "domain")})
|
||||
answers = {}
|
||||
|
||||
with patch.object(domain, "_get_maindomain", return_value="my_main_domain.com"),\
|
||||
patch.object(domain, "domain_list", return_value={"domains": [main_domain]}), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with patch.object(
|
||||
domain, "_get_maindomain", return_value="my_main_domain.com"
|
||||
), patch.object(
|
||||
domain, "domain_list", return_value={"domains": [main_domain]}
|
||||
), patch.object(
|
||||
os, "isatty", return_value=False
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -1263,8 +1314,9 @@ def test_question_domain_two_domains_wrong_answer():
|
|||
with patch.object(
|
||||
domain, "_get_maindomain", return_value=main_domain
|
||||
), patch.object(domain, "domain_list", return_value={"domains": domains}):
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(
|
||||
os, "isatty", return_value=False
|
||||
):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
|
||||
|
||||
|
@ -1284,8 +1336,11 @@ def test_question_domain_two_domains_default_no_ask():
|
|||
|
||||
with patch.object(
|
||||
domain, "_get_maindomain", return_value=main_domain
|
||||
), patch.object(domain, "domain_list", return_value={"domains": domains}), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
), patch.object(
|
||||
domain, "domain_list", return_value={"domains": domains}
|
||||
), patch.object(
|
||||
os, "isatty", return_value=False
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -1300,8 +1355,11 @@ def test_question_domain_two_domains_default():
|
|||
|
||||
with patch.object(
|
||||
domain, "_get_maindomain", return_value=main_domain
|
||||
), patch.object(domain, "domain_list", return_value={"domains": domains}), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
), patch.object(
|
||||
domain, "domain_list", return_value={"domains": domains}
|
||||
), patch.object(
|
||||
os, "isatty", return_value=False
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -1315,8 +1373,11 @@ def test_question_domain_two_domains_default_input():
|
|||
|
||||
with patch.object(
|
||||
domain, "_get_maindomain", return_value=main_domain
|
||||
), patch.object(domain, "domain_list", return_value={"domains": domains}), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
), patch.object(
|
||||
domain, "domain_list", return_value={"domains": domains}
|
||||
), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
expected_result = OrderedDict({"some_domain": (main_domain, "domain")})
|
||||
with patch.object(Moulinette, "prompt", return_value=main_domain):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
@ -1346,8 +1407,9 @@ def test_question_user_empty():
|
|||
answers = {}
|
||||
|
||||
with patch.object(user, "user_list", return_value={"users": users}):
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(
|
||||
os, "isatty", return_value=False
|
||||
):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
|
||||
|
||||
|
@ -1373,8 +1435,9 @@ def test_question_user():
|
|||
|
||||
expected_result = OrderedDict({"some_user": (username, "user")})
|
||||
|
||||
with patch.object(user, "user_list", return_value={"users": users}), \
|
||||
patch.object(user, "user_info", return_value={}):
|
||||
with patch.object(user, "user_list", return_value={"users": users}), patch.object(
|
||||
user, "user_info", return_value={}
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -1407,15 +1470,17 @@ def test_question_user_two_users():
|
|||
answers = {"some_user": other_user}
|
||||
expected_result = OrderedDict({"some_user": (other_user, "user")})
|
||||
|
||||
with patch.object(user, "user_list", return_value={"users": users}), \
|
||||
patch.object(user, "user_info", return_value={}):
|
||||
with patch.object(user, "user_list", return_value={"users": users}), patch.object(
|
||||
user, "user_info", return_value={}
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
answers = {"some_user": username}
|
||||
expected_result = OrderedDict({"some_user": (username, "user")})
|
||||
|
||||
with patch.object(user, "user_list", return_value={"users": users}), \
|
||||
patch.object(user, "user_info", return_value={}):
|
||||
with patch.object(user, "user_list", return_value={"users": users}), patch.object(
|
||||
user, "user_info", return_value={}
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -1448,8 +1513,9 @@ def test_question_user_two_users_wrong_answer():
|
|||
answers = {"some_user": "doesnt_exist.pouet"}
|
||||
|
||||
with patch.object(user, "user_list", return_value={"users": users}):
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(
|
||||
os, "isatty", return_value=False
|
||||
):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
|
||||
|
||||
|
@ -1477,8 +1543,9 @@ def test_question_user_two_users_no_default():
|
|||
answers = {}
|
||||
|
||||
with patch.object(user, "user_list", return_value={"users": users}):
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(
|
||||
os, "isatty", return_value=False
|
||||
):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
|
||||
|
||||
|
@ -1505,21 +1572,20 @@ def test_question_user_two_users_default_input():
|
|||
questions = [{"name": "some_user", "type": "user", "ask": "choose a user"}]
|
||||
answers = {}
|
||||
|
||||
with patch.object(user, "user_list", return_value={"users": users}), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(user, "user_list", return_value={"users": users}), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
with patch.object(user, "user_info", return_value={}):
|
||||
expected_result = OrderedDict({"some_user": (username, "user")})
|
||||
with patch.object(Moulinette, "prompt", return_value=username):
|
||||
assert (
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
== expected_result
|
||||
parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
)
|
||||
|
||||
expected_result = OrderedDict({"some_user": (other_user, "user")})
|
||||
with patch.object(Moulinette, "prompt", return_value=other_user):
|
||||
assert (
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
== expected_result
|
||||
parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
)
|
||||
|
||||
|
||||
|
@ -1544,8 +1610,7 @@ def test_question_number_no_input():
|
|||
]
|
||||
answers = {}
|
||||
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(os, "isatty", return_value=False):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
|
||||
|
||||
|
@ -1558,13 +1623,11 @@ def test_question_number_bad_input():
|
|||
]
|
||||
answers = {"some_number": "stuff"}
|
||||
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(os, "isatty", return_value=False):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
|
||||
answers = {"some_number": 1.5}
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(os, "isatty", return_value=False):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
|
||||
|
||||
|
@ -1579,17 +1642,20 @@ def test_question_number_input():
|
|||
answers = {}
|
||||
|
||||
expected_result = OrderedDict({"some_number": (1337, "number")})
|
||||
with patch.object(Moulinette, "prompt", return_value="1337"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="1337"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value=1337), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value=1337), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
expected_result = OrderedDict({"some_number": (0, "number")})
|
||||
with patch.object(Moulinette, "prompt", return_value="0"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="0"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -1603,8 +1669,9 @@ def test_question_number_input_no_ask():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_number": (1337, "number")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="1337"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="1337"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -1634,8 +1701,9 @@ def test_question_number_optional_with_input():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_number": (1337, "number")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="1337"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="1337"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -1650,8 +1718,9 @@ def test_question_number_optional_with_input_without_ask():
|
|||
answers = {}
|
||||
expected_result = OrderedDict({"some_number": (0, "number")})
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="0"), \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(Moulinette, "prompt", return_value="0"), patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
assert parse_args_in_yunohost_format(answers, questions) == expected_result
|
||||
|
||||
|
||||
|
@ -1680,8 +1749,7 @@ def test_question_number_bad_default():
|
|||
}
|
||||
]
|
||||
answers = {}
|
||||
with pytest.raises(YunohostError), \
|
||||
patch.object(os, "isatty", return_value=False):
|
||||
with pytest.raises(YunohostError), patch.object(os, "isatty", return_value=False):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
|
||||
|
||||
|
@ -1696,13 +1764,16 @@ def test_question_number_input_test_ask():
|
|||
]
|
||||
answers = {}
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="1111") as prompt, \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(
|
||||
Moulinette, "prompt", return_value="1111"
|
||||
) as prompt, patch.object(os, "isatty", return_value=True):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
prompt.assert_called_with(
|
||||
message=ask_text,
|
||||
is_password=False, confirm=False,
|
||||
prefill='', is_multiline=False
|
||||
is_password=False,
|
||||
confirm=False,
|
||||
prefill="",
|
||||
is_multiline=False,
|
||||
)
|
||||
|
||||
|
||||
|
@ -1719,13 +1790,16 @@ def test_question_number_input_test_ask_with_default():
|
|||
]
|
||||
answers = {}
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="1111") as prompt, \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(
|
||||
Moulinette, "prompt", return_value="1111"
|
||||
) as prompt, patch.object(os, "isatty", return_value=True):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
prompt.assert_called_with(
|
||||
message=ask_text,
|
||||
is_password=False, confirm=False,
|
||||
prefill=str(default_value), is_multiline=False
|
||||
is_password=False,
|
||||
confirm=False,
|
||||
prefill=str(default_value),
|
||||
is_multiline=False,
|
||||
)
|
||||
|
||||
|
||||
|
@ -1743,11 +1817,12 @@ def test_question_number_input_test_ask_with_example():
|
|||
]
|
||||
answers = {}
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="1111") as prompt, \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(
|
||||
Moulinette, "prompt", return_value="1111"
|
||||
) as prompt, patch.object(os, "isatty", return_value=True):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
assert ask_text in prompt.call_args[1]['message']
|
||||
assert example_value in prompt.call_args[1]['message']
|
||||
assert ask_text in prompt.call_args[1]["message"]
|
||||
assert example_value in prompt.call_args[1]["message"]
|
||||
|
||||
|
||||
@pytest.mark.skip # we should do something with this help
|
||||
|
@ -1764,18 +1839,20 @@ def test_question_number_input_test_ask_with_help():
|
|||
]
|
||||
answers = {}
|
||||
|
||||
with patch.object(Moulinette, "prompt", return_value="1111") as prompt, \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(
|
||||
Moulinette, "prompt", return_value="1111"
|
||||
) as prompt, patch.object(os, "isatty", return_value=True):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
assert ask_text in prompt.call_args[1]['message']
|
||||
assert help_value in prompt.call_args[1]['message']
|
||||
assert ask_text in prompt.call_args[1]["message"]
|
||||
assert help_value in prompt.call_args[1]["message"]
|
||||
|
||||
|
||||
def test_question_display_text():
|
||||
questions = [{"name": "some_app", "type": "display_text", "ask": "foobar"}]
|
||||
answers = {}
|
||||
|
||||
with patch.object(sys, "stdout", new_callable=StringIO) as stdout, \
|
||||
patch.object(os, "isatty", return_value=True):
|
||||
with patch.object(sys, "stdout", new_callable=StringIO) as stdout, patch.object(
|
||||
os, "isatty", return_value=True
|
||||
):
|
||||
parse_args_in_yunohost_format(answers, questions)
|
||||
assert "foobar" in stdout.getvalue()
|
||||
|
|
|
@ -98,7 +98,9 @@ class ConfigPanel:
|
|||
|
||||
return result
|
||||
|
||||
def set(self, key=None, value=None, args=None, args_file=None, operation_logger=None):
|
||||
def set(
|
||||
self, key=None, value=None, args=None, args_file=None, operation_logger=None
|
||||
):
|
||||
self.filter_key = key or ""
|
||||
|
||||
# Read config panel toml
|
||||
|
@ -108,7 +110,10 @@ class ConfigPanel:
|
|||
raise YunohostValidationError("config_no_panel")
|
||||
|
||||
if (args is not None or args_file is not None) and value is not None:
|
||||
raise YunohostValidationError("You should either provide a value, or a serie of args/args_file, but not both at the same time", raw_msg=True)
|
||||
raise YunohostValidationError(
|
||||
"You should either provide a value, or a serie of args/args_file, but not both at the same time",
|
||||
raw_msg=True,
|
||||
)
|
||||
|
||||
if self.filter_key.count(".") != 2 and value is not None:
|
||||
raise YunohostValidationError("config_cant_set_value_on_section")
|
||||
|
@ -167,7 +172,10 @@ class ConfigPanel:
|
|||
# Split filter_key
|
||||
filter_key = self.filter_key.split(".") if self.filter_key != "" else []
|
||||
if len(filter_key) > 3:
|
||||
raise YunohostError(f"The filter key {filter_key} has too many sub-levels, the max is 3.", raw_msg=True)
|
||||
raise YunohostError(
|
||||
f"The filter key {filter_key} has too many sub-levels, the max is 3.",
|
||||
raw_msg=True,
|
||||
)
|
||||
|
||||
if not os.path.exists(self.config_path):
|
||||
return None
|
||||
|
@ -190,7 +198,7 @@ class ConfigPanel:
|
|||
"default": {
|
||||
"name": "",
|
||||
"services": [],
|
||||
"actions": {"apply": {"en": "Apply"}}
|
||||
"actions": {"apply": {"en": "Apply"}},
|
||||
},
|
||||
},
|
||||
"sections": {
|
||||
|
@ -199,15 +207,34 @@ class ConfigPanel:
|
|||
"name": "",
|
||||
"services": [],
|
||||
"optional": True,
|
||||
}
|
||||
},
|
||||
},
|
||||
"options": {
|
||||
"properties": ["ask", "type", "bind", "help", "example", "default",
|
||||
"style", "icon", "placeholder", "visible",
|
||||
"optional", "choices", "yes", "no", "pattern",
|
||||
"limit", "min", "max", "step", "accept", "redact"],
|
||||
"default": {}
|
||||
}
|
||||
"properties": [
|
||||
"ask",
|
||||
"type",
|
||||
"bind",
|
||||
"help",
|
||||
"example",
|
||||
"default",
|
||||
"style",
|
||||
"icon",
|
||||
"placeholder",
|
||||
"visible",
|
||||
"optional",
|
||||
"choices",
|
||||
"yes",
|
||||
"no",
|
||||
"pattern",
|
||||
"limit",
|
||||
"min",
|
||||
"max",
|
||||
"step",
|
||||
"accept",
|
||||
"redact",
|
||||
],
|
||||
"default": {},
|
||||
},
|
||||
}
|
||||
|
||||
def convert(toml_node, node_type):
|
||||
|
@ -219,14 +246,16 @@ class ConfigPanel:
|
|||
This function detects all children nodes and put them in a list
|
||||
"""
|
||||
# Prefill the node default keys if needed
|
||||
default = format_description[node_type]['default']
|
||||
default = format_description[node_type]["default"]
|
||||
node = {key: toml_node.get(key, value) for key, value in default.items()}
|
||||
|
||||
properties = format_description[node_type]['properties']
|
||||
properties = format_description[node_type]["properties"]
|
||||
|
||||
# Define the filter_key part to use and the children type
|
||||
i = list(format_description).index(node_type)
|
||||
subnode_type = list(format_description)[i + 1] if node_type != "options" else None
|
||||
subnode_type = (
|
||||
list(format_description)[i + 1] if node_type != "options" else None
|
||||
)
|
||||
search_key = filter_key[i] if len(filter_key) > i else False
|
||||
|
||||
for key, value in toml_node.items():
|
||||
|
@ -265,10 +294,24 @@ class ConfigPanel:
|
|||
)
|
||||
|
||||
# List forbidden keywords from helpers and sections toml (to avoid conflict)
|
||||
forbidden_keywords = ["old", "app", "changed", "file_hash", "binds", "types",
|
||||
"formats", "getter", "setter", "short_setting", "type",
|
||||
"bind", "nothing_changed", "changes_validated", "result",
|
||||
"max_progression"]
|
||||
forbidden_keywords = [
|
||||
"old",
|
||||
"app",
|
||||
"changed",
|
||||
"file_hash",
|
||||
"binds",
|
||||
"types",
|
||||
"formats",
|
||||
"getter",
|
||||
"setter",
|
||||
"short_setting",
|
||||
"type",
|
||||
"bind",
|
||||
"nothing_changed",
|
||||
"changes_validated",
|
||||
"result",
|
||||
"max_progression",
|
||||
]
|
||||
forbidden_keywords += format_description["sections"]
|
||||
|
||||
for _, _, option in self._iterate():
|
||||
|
@ -282,10 +325,15 @@ class ConfigPanel:
|
|||
for _, _, option in self._iterate():
|
||||
if option["id"] not in self.values:
|
||||
allowed_empty_types = ["alert", "display_text", "markdown", "file"]
|
||||
if option["type"] in allowed_empty_types or option.get("bind") == "null":
|
||||
if (
|
||||
option["type"] in allowed_empty_types
|
||||
or option.get("bind") == "null"
|
||||
):
|
||||
continue
|
||||
else:
|
||||
raise YunohostError(f"Config panel question '{option['id']}' should be initialized with a value during install or upgrade.")
|
||||
raise YunohostError(
|
||||
f"Config panel question '{option['id']}' should be initialized with a value during install or upgrade."
|
||||
)
|
||||
value = self.values[option["name"]]
|
||||
# In general, the value is just a simple value.
|
||||
# Sometimes it could be a dict used to overwrite the option itself
|
||||
|
@ -440,14 +488,11 @@ class Question(object):
|
|||
)
|
||||
|
||||
# Apply default value
|
||||
class_default= getattr(self, "default_value", None)
|
||||
if self.value in [None, ""] and \
|
||||
(self.default is not None or class_default is not None):
|
||||
self.value = (
|
||||
class_default
|
||||
if self.default is None
|
||||
else self.default
|
||||
)
|
||||
class_default = getattr(self, "default_value", None)
|
||||
if self.value in [None, ""] and (
|
||||
self.default is not None or class_default is not None
|
||||
):
|
||||
self.value = class_default if self.default is None else self.default
|
||||
|
||||
# Normalization
|
||||
# This is done to enforce a certain formating like for boolean
|
||||
|
@ -543,30 +588,31 @@ class StringQuestion(Question):
|
|||
class EmailQuestion(StringQuestion):
|
||||
pattern = {
|
||||
"regexp": r"^.+@.+",
|
||||
"error": "config_validate_email" # i18n: config_validate_email
|
||||
"error": "config_validate_email", # i18n: config_validate_email
|
||||
}
|
||||
|
||||
|
||||
class URLQuestion(StringQuestion):
|
||||
pattern = {
|
||||
"regexp": r"^https?://.*$",
|
||||
"error": "config_validate_url" # i18n: config_validate_url
|
||||
"error": "config_validate_url", # i18n: config_validate_url
|
||||
}
|
||||
|
||||
|
||||
class DateQuestion(StringQuestion):
|
||||
pattern = {
|
||||
"regexp": r"^\d{4}-\d\d-\d\d$",
|
||||
"error": "config_validate_date" # i18n: config_validate_date
|
||||
"error": "config_validate_date", # i18n: config_validate_date
|
||||
}
|
||||
|
||||
def _prevalidate(self):
|
||||
from datetime import datetime
|
||||
|
||||
super()._prevalidate()
|
||||
|
||||
if self.value not in [None, ""]:
|
||||
try:
|
||||
datetime.strptime(self.value, '%Y-%m-%d')
|
||||
datetime.strptime(self.value, "%Y-%m-%d")
|
||||
except ValueError:
|
||||
raise YunohostValidationError("config_validate_date")
|
||||
|
||||
|
@ -574,14 +620,14 @@ class DateQuestion(StringQuestion):
|
|||
class TimeQuestion(StringQuestion):
|
||||
pattern = {
|
||||
"regexp": r"^(1[12]|0?\d):[0-5]\d$",
|
||||
"error": "config_validate_time" # i18n: config_validate_time
|
||||
"error": "config_validate_time", # i18n: config_validate_time
|
||||
}
|
||||
|
||||
|
||||
class ColorQuestion(StringQuestion):
|
||||
pattern = {
|
||||
"regexp": r"^#[ABCDEFabcdef\d]{3,6}$",
|
||||
"error": "config_validate_color" # i18n: config_validate_color
|
||||
"error": "config_validate_color", # i18n: config_validate_color
|
||||
}
|
||||
|
||||
|
||||
|
@ -732,7 +778,9 @@ class DomainQuestion(Question):
|
|||
|
||||
def _raise_invalid_answer(self):
|
||||
raise YunohostValidationError(
|
||||
"app_argument_invalid", name=self.name, error=m18n.n("domain_name_unknown", domain=self.value)
|
||||
"app_argument_invalid",
|
||||
name=self.name,
|
||||
error=m18n.n("domain_name_unknown", domain=self.value),
|
||||
)
|
||||
|
||||
|
||||
|
@ -813,7 +861,9 @@ class DisplayTextQuestion(Question):
|
|||
super().__init__(question, user_answers)
|
||||
|
||||
self.optional = True
|
||||
self.style = question.get("style", "info" if question['type'] == 'alert' else '')
|
||||
self.style = question.get(
|
||||
"style", "info" if question["type"] == "alert" else ""
|
||||
)
|
||||
|
||||
def _format_text_for_user_input_in_cli(self):
|
||||
text = _value_for_locale(self.ask)
|
||||
|
@ -875,7 +925,9 @@ class FileQuestion(Question):
|
|||
return
|
||||
|
||||
filename = self.value if isinstance(self.value, str) else self.value["filename"]
|
||||
if "." not in filename or "." + filename.split(".")[-1] not in self.accept.replace(" ", "").split(","):
|
||||
if "." not in filename or "." + filename.split(".")[
|
||||
-1
|
||||
] not in self.accept.replace(" ", "").split(","):
|
||||
raise YunohostValidationError(
|
||||
"app_argument_invalid",
|
||||
name=self.name,
|
||||
|
|
Loading…
Add table
Reference in a new issue