From 379e445e98353532722aeb854f16ba2bd32f8c61 Mon Sep 17 00:00:00 2001 From: Lucas Biaggi Date: Wed, 10 Jan 2024 14:41:55 +0000 Subject: [PATCH 1/2] Create an option to load a settings.py file from cli --- doorstop/cli/main.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/doorstop/cli/main.py b/doorstop/cli/main.py index 5b92b7c1a..05e2ff28c 100644 --- a/doorstop/cli/main.py +++ b/doorstop/cli/main.py @@ -7,6 +7,8 @@ import argparse import os import sys +from pathlib import Path +from types import ModuleType from doorstop import common, settings from doorstop.cli import commands, utilities @@ -49,6 +51,15 @@ def main(args=None): # pylint: disable=R0915 help="use a custom port for the server", default=settings.SERVER_PORT, ) + + server.add_argument( + "--settings", + metavar="SETTINGS_FILE.py", + help="""Use a doorstop settings file instead of options arguments + NOTE: doorstop will ignore options passed from the cli""", + default=None, + type=str, + ) server.add_argument( "-f", "--force", @@ -169,7 +180,21 @@ def main(args=None): # pylint: disable=R0915 utilities.configure_logging(args.verbose) # Configure settings - utilities.configure_settings(args) + if args.settings: + file_settings = common.import_path_as_module(Path(args.settings)) + # get overridden setting list + custom_settings = ( + x + for x in dir(file_settings) + if not x.startswith("_") + and not isinstance(getattr(file_settings, x), ModuleType) + ) + for i in custom_settings: + # if they are valid set them + if hasattr(settings, i): + setattr(settings, i, getattr(file_settings, i)) + else: + utilities.configure_settings(args) # Run the program function = commands.get(args.command) From 4f1b757b9fd224ec3224a5e006bb719fc5a2b323 Mon Sep 17 00:00:00 2001 From: Lucas Biaggi Date: Thu, 21 Mar 2024 03:52:46 +0000 Subject: [PATCH 2/2] Tests related to loading settings from a given file --- doorstop/cli/tests/files/settings_modified.py | 65 +++++++++++++++++++ doorstop/cli/tests/test_main.py | 11 +++- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 doorstop/cli/tests/files/settings_modified.py diff --git a/doorstop/cli/tests/files/settings_modified.py b/doorstop/cli/tests/files/settings_modified.py new file mode 100644 index 000000000..1656321b3 --- /dev/null +++ b/doorstop/cli/tests/files/settings_modified.py @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: LGPL-3.0-only + +"""Settings for the Doorstop package.""" + +import logging +import os + +# Logging settings +DEFAULT_LOGGING_FORMAT = "%(message)s" +LEVELED_LOGGING_FORMAT = "%(levelname)s: %(message)s" +VERBOSE_LOGGING_FORMAT = "[%(levelname)-8s] %(message)s" +VERBOSE2_LOGGING_FORMAT = "[%(levelname)-8s] (%(name)s @%(lineno)4d) %(message)s" +QUIET_LOGGING_LEVEL = logging.WARNING +TIMED_LOGGING_FORMAT = "%(asctime)s" + " " + VERBOSE_LOGGING_FORMAT +DEFAULT_LOGGING_LEVEL = logging.WARNING +VERBOSE_LOGGING_LEVEL = logging.INFO +VERBOSE2_LOGGING_LEVEL = logging.DEBUG +VERBOSE3_LOGGING_LEVEL = logging.DEBUG - 1 + +# Value constants +SEP_CHARS = "-_." # valid prefix/number separators +SKIP_EXTS = [".yml", ".csv", ".tsv"] # extensions skipped in reference search +RESERVED_WORDS = ["all"] # keywords that cannot be used for prefixes +PLACEHOLDER = "..." # placeholder for new item UIDs on export/import +PLACEHOLDER_COUNT = 1 # number of placeholders to include on export + +# Formatting settings +MAX_LINE_LENGTH = 20 # line length to trigger multiline on extended attributes + +# Validation settings +REFORMAT = True # reformat item files during validation +REORDER = False # reorder document levels during validation +CHECK_LEVELS = True # validate document levels during validation +CHECK_REF = True # validate external file references +CHECK_CHILD_LINKS = True # validate reverse links +CHECK_CHILD_LINKS_STRICT = False # require child (reverse) links from every document +CHECK_SUSPECT_LINKS = True # check stamps on links +CHECK_REVIEW_STATUS = True # check stamps on items +WARN_ALL = False # display info-level issues as warnings +ERROR_ALL = False # display warning-level issues as errors + +# Review settings +REVIEW_NEW_ITEMS = True # automatically review new items during validation + +# Stamping settings +STAMP_NEW_LINKS = True # automatically stamp links upon creation + +# Publishing settings +PUBLISH_CHILD_LINKS = True # include child links when publishing +PUBLISH_BODY_LEVELS = True # include levels on non-header items +PUBLISH_HEADING_LEVELS = True # include levels on header items +ENABLE_HEADERS = True # use headers if defined +WRITE_LINESEPERATOR = os.linesep + +# Version control settings +ADDREMOVE_FILES = True # automatically add/remove new/changed files + +# Caching settings +CACHE_ITEMS = True # cache items in documents and trees +CACHE_DOCUMENTS = True # cache documents in trees +CACHE_PATHS = True # cache file/directory paths and contents + +# Server settings +SERVER_HOST = None # '' = server not specified, None = no server in use +SERVER_PORT = 7867 diff --git a/doorstop/cli/tests/test_main.py b/doorstop/cli/tests/test_main.py index ab304cb5b..4c061ceb7 100644 --- a/doorstop/cli/tests/test_main.py +++ b/doorstop/cli/tests/test_main.py @@ -9,7 +9,7 @@ from doorstop import settings from doorstop.cli import main -from doorstop.cli.tests import SettingsTestCase +from doorstop.cli.tests import FILES, SettingsTestCase class TestMain(SettingsTestCase): @@ -84,3 +84,12 @@ def test_main(self): spec.loader.exec_module(runpy) # Assert self.assertIsNotNone(runpy) + + @patch("doorstop.cli.commands.run", Mock()) + def test_run_modified_settings_through_file(self): + """Verify --settings has override settings.""" + main.main(args=["--settings", f"{FILES}/settings_modified.py"]) + self.assertEqual(settings.MAX_LINE_LENGTH, 20) + # rollback to the original value to not impact an item test + settings.MAX_LINE_LENGTH = 79 + self.assertEqual(settings.MAX_LINE_LENGTH, 79)