From 0ef97bc974bf68662c7bbf479f34eb76fa989c7c Mon Sep 17 00:00:00 2001 From: Reto Trappitsch Date: Fri, 22 Mar 2024 13:47:19 +0100 Subject: [PATCH 1/2] Propose already set values when initialized is triggered again --- src/box/config.py | 10 ++++-- src/box/initialization.py | 51 +++++++++++++++++++++++----- tests/cli/test_cli_initialization.py | 40 ++++++++++++++++++++++ tests/func/test_initialization.py | 6 ++-- 4 files changed, 93 insertions(+), 14 deletions(-) diff --git a/src/box/config.py b/src/box/config.py index 74d6722..e320256 100644 --- a/src/box/config.py +++ b/src/box/config.py @@ -1,5 +1,6 @@ # Parse the pyproject.toml file +from collections import OrderedDict from pathlib import Path from typing import Any, Dict, Union @@ -70,7 +71,7 @@ def optional_pyapp_variables(self) -> Dict: return {} @property - def possible_app_entries(self) -> Dict: + def possible_app_entries(self) -> OrderedDict: """Return [project.gui-scripts] or [project.scripts] entry if available. If no entry is available, return None. If more than one entry available, @@ -78,7 +79,11 @@ def possible_app_entries(self) -> Dict: :return: A list of possible entry points or None. """ - possible_entries = {} + possible_entries = OrderedDict() + try: + possible_entries["current-default"] = {"current": self.app_entry} + except KeyError: + pass try: possible_entries["gui-scripts"] = self._project["gui-scripts"] except KeyError: @@ -87,6 +92,7 @@ def possible_app_entries(self) -> Dict: possible_entries["scripts"] = self._project["scripts"] except KeyError: pass + print(possible_entries) return possible_entries @property diff --git a/src/box/initialization.py b/src/box/initialization.py index 439f2ea..b5eadf9 100644 --- a/src/box/initialization.py +++ b/src/box/initialization.py @@ -64,6 +64,7 @@ def initialize(self): def _set_app_entry(self): """Set the app entry for the project.""" possible_entries = self.pyproj.possible_app_entries + # create a list of possible entries options = [] sup_keys = possible_entries.keys() # outside keys @@ -111,6 +112,12 @@ def query_app_entry(query_txt, opts: List) -> None: def _set_app_entry_type(self): """Set the app entry type for the PyApp packaging. Defaults to `spec`.""" + default_entry_type = "spec" + try: + default_entry_type = self.pyproj.app_entry_type + except KeyError: + pass + if self._app_entry_type: if self._app_entry_type.lower() not in ut.PYAPP_APP_ENTRY_TYPES: raise click.ClickException( @@ -121,12 +128,12 @@ def _set_app_entry_type(self): entry_type = self._app_entry_type.lower() else: if self._quiet: - entry_type = "spec" + entry_type = default_entry_type else: entry_type = click.prompt( "Choose an entry type for the project in PyApp.", type=click.Choice(ut.PYAPP_APP_ENTRY_TYPES), - default="spec", + default=default_entry_type, ) pyproject_writer("entry_type", entry_type) @@ -135,16 +142,22 @@ def _set_builder(self): """Set the builder for the project (defaults to rye).""" possible_builders = PackageApp().builders + default_builder = "rye" + try: + default_builder = self.pyproj.builder + except KeyError: + pass + if self._builder: builder = self._builder else: if self._quiet: - builder = "rye" + builder = default_builder else: builder = click.prompt( "Choose a builder tool for the project.", type=click.Choice(possible_builders), - default="rye", + default=default_builder, ) pyproject_writer("builder", builder) @@ -153,16 +166,21 @@ def _set_builder(self): def _set_optional_deps(self): """Set optional dependencies for the project (if any).""" + if (tmp := self.pyproj.optional_dependencies) is not None: + default_optional_deps = tmp + else: + default_optional_deps = "" + if self._optional_deps: opt_deps = self._optional_deps else: if self._quiet: - opt_deps = "" + opt_deps = default_optional_deps else: opt_deps = click.prompt( "Provide any optional dependencies for the project.", type=str, - default="", + default=default_optional_deps, ) if opt_deps != "": @@ -170,6 +188,14 @@ def _set_optional_deps(self): def _set_optional_pyapp_variables(self): """Set optional environmental variables for PyApp.""" + default_opt_vars = "" + try: + tmp = self.pyproj.optional_pyapp_variables + for key, value in tmp.items(): + default_opt_vars += f"{key} {value} " + except KeyError: + pass + opt_vars = None if self._opt_paypp_vars: opt_vars = self._opt_paypp_vars @@ -178,11 +204,13 @@ def _set_optional_pyapp_variables(self): "Please enter optional PyApp variables to set. " "Example: `PYAPP_SKIP_INSTALL 1 PYAPP_FULL_ISOLATION 1", type=str, - default="", + default=default_opt_vars, ) if opt_vars == "": opt_vars = None + else: + opt_vars = None if default_opt_vars == "" else default_opt_vars if opt_vars: opt_vars = opt_vars.split() @@ -215,16 +243,21 @@ def _set_python_version(self): Ask the user what python version to use. If none is provided (or quiet), set the default to the latest python version. """ + if (tmp := self.pyproj.python_version) is not None: + default_py_version = tmp + else: + default_py_version = ut.PYAPP_PYTHON_VERSIONS[-1] + if self._python_version: py_version = self._python_version else: if self._quiet: - py_version = ut.PYAPP_PYTHON_VERSIONS[-1] + py_version = default_py_version else: py_version = click.prompt( "Choose a python version for packaging the project with PyApp.", type=click.Choice(ut.PYAPP_PYTHON_VERSIONS), - default=ut.PYAPP_PYTHON_VERSIONS[-1], + default=default_py_version, ) pyproject_writer("python_version", py_version) diff --git a/tests/cli/test_cli_initialization.py b/tests/cli/test_cli_initialization.py index 23039c7..d980f05 100644 --- a/tests/cli/test_cli_initialization.py +++ b/tests/cli/test_cli_initialization.py @@ -119,6 +119,46 @@ def test_initialize_with_options(rye_project_no_box): assert pyproj.optional_pyapp_variables == {"PYAPP_FULL_ISOLATION": "1"} +def test_initialize_project_again(rye_project_no_box): + """Initialization of a previous project sets defaults from previous config.""" + builder = "build" + entry_point = "myapp:entry" + entry_type = "module" + optional_deps = "gui" + py_version = "3.8" + pyapp_vars = "PYAPP_FULL_ISOLATION 1" + + runner = CliRunner() + runner.invoke( + cli, + [ + "init", + "-e", + entry_point, + "-et", + entry_type, + "-py", + py_version, + "-opt", + optional_deps, + "-b", + builder, + "--opt-pyapp-vars", + pyapp_vars, + ], + ) + + # now re-initialize with quiet and assure that the same options are set + runner.invoke(cli, ["init", "-q"]) + + pyproj = PyProjectParser() + assert pyproj.builder == builder + assert pyproj.python_version == py_version + assert pyproj.optional_dependencies == optional_deps + assert pyproj.app_entry == entry_point + assert pyproj.app_entry_type == entry_type + + def test_initialize_project_quiet(rye_project_no_box): """Initialize a new project quietly.""" runner = CliRunner() diff --git a/tests/func/test_initialization.py b/tests/func/test_initialization.py index 0af43b3..9f60276 100644 --- a/tests/func/test_initialization.py +++ b/tests/func/test_initialization.py @@ -7,16 +7,16 @@ from box.initialization import InitializeProject -def test_app_entry(rye_project): +def test_app_entry(rye_project_no_box): """Set the configuration in `pyproject.toml` to rye.""" init = InitializeProject(quiet=True) init.initialize() pyproj = PyProjectParser() - assert pyproj.app_entry == f"{rye_project.name}:run" + assert pyproj.app_entry == f"{rye_project_no_box.name}:run" -def test_set_builder(rye_project): +def test_set_builder(rye_project_no_box): """Set the configuration in `pyproject.toml` to rye.""" init = InitializeProject(quiet=True) init.initialize() From 00c85c3201433dee135a267a988125028cee4e08 Mon Sep 17 00:00:00 2001 From: Reto Trappitsch Date: Fri, 22 Mar 2024 13:49:42 +0100 Subject: [PATCH 2/2] update docs --- docs/guide.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/guide.md b/docs/guide.md index 77b6421..4c93c5e 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -36,6 +36,10 @@ If you provided all the answers, your project should have been successfully init To still specify variables, just set them using the arguments discussed in the table above. And if you are happy with all the defaults, you should be good to do. +!!! note + If you re-initalize a project, `box` will use the already set values as proposed default values. + If you re-initialize in quiet mode and just give one new option, all other options will stay the same. + ## Packaging To package your project, simply run: