From 6aca3677bcb62cf099ac2f7360bcce359e6b9085 Mon Sep 17 00:00:00 2001 From: Gordon Shotwell Date: Wed, 3 Jan 2024 10:20:37 -0400 Subject: [PATCH 01/11] Add directory flag Closes ##956 --- shiny/_main.py | 13 +++++- shiny/_template_utils.py | 78 ++++++++++++++++++------------- tests/pytest/test_shiny_create.py | 39 ++++++++++++++++ 3 files changed, 95 insertions(+), 35 deletions(-) create mode 100644 tests/pytest/test_shiny_create.py diff --git a/shiny/_main.py b/shiny/_main.py index 9a9dc659d..019a9ddb0 100644 --- a/shiny/_main.py +++ b/shiny/_main.py @@ -513,18 +513,27 @@ def try_import_module(module: str) -> Optional[types.ModuleType]: "-g", help="The GitHub URL of the template sub-directory. For example https://github.com/posit-dev/py-shiny-templates/tree/main/dashboard", ) +@click.option( + "--directory", + "-d", + help="The destination directory, you will be prompted if this is not provided.", +) def create( template: Optional[str] = None, mode: Optional[str] = None, github: Optional[str] = None, + directory: Optional[str | Path] = None, ) -> None: from ._template_utils import template_query, use_git_template + if isinstance(directory, str): + directory = Path(directory) + if github is not None: - use_git_template(github, mode) + use_git_template(github, mode, directory) return - template_query(template, mode) + template_query(template, mode, directory) @main.command( diff --git a/shiny/_template_utils.py b/shiny/_template_utils.py index e2fb4e9b4..c25e82794 100644 --- a/shiny/_template_utils.py +++ b/shiny/_template_utils.py @@ -40,7 +40,11 @@ def choice_from_dict(choice_dict: dict[str, str]) -> list[Choice]: return [Choice(title=key, value=value) for key, value in choice_dict.items()] -def template_query(question_state: Optional[str] = None, mode: Optional[str] = None): +def template_query( + question_state: Optional[str] = None, + mode: Optional[str] = None, + dest_dir: Optional[Path | None] = None, +): """ This will initiate a CLI query which will ask the user which template they would like. If called without arguments this function will start from the top level and ask which @@ -69,12 +73,12 @@ def template_query(question_state: Optional[str] = None, mode: Optional[str] = N if template is None or template == "cancel": sys.exit(1) elif template == "js-component": - js_component_questions() + js_component_questions(dest_dir=dest_dir) return elif template in package_template_choices.values(): - js_component_questions(template) + js_component_questions(template, dest_dir=dest_dir) else: - app_template_questions(template, mode) + app_template_questions(template, mode, dest_dir=dest_dir) def download_and_extract_zip(url: str, temp_dir: Path): @@ -92,7 +96,9 @@ def download_and_extract_zip(url: str, temp_dir: Path): zip_file.extractall(temp_dir) -def use_git_template(url: str, mode: Optional[str] = None): +def use_git_template( + url: str, mode: Optional[str] = None, dest_dir: Optional[Path] = None +): # Github requires that we download the whole repository, so we need to # download and unzip the repo, then navigate to the subdirectory. @@ -116,13 +122,14 @@ def use_git_template(url: str, mode: Optional[str] = None): directory = repo_name + "-" + branch_name path = temp_dir / directory / subdirectory - return app_template_questions(mode=mode, template_dir=path) + return app_template_questions(mode=mode, template_dir=path, dest_dir=dest_dir) def app_template_questions( template: Optional[str] = None, mode: Optional[str] = None, template_dir: Optional[Path] = None, + dest_dir: Optional[Path] = None, ): if template_dir is None: if template is None: @@ -154,20 +161,10 @@ def app_template_questions( template_query() return - appdir = questionary.path( - "Enter destination directory:", - default=build_path_string(""), - only_directories=True, - ).ask() - - if appdir is None: - sys.exit(1) - - if appdir == ".": - appdir = build_path_string(template_dir.name) + dest_dir = directory_prompt(template_dir, dest_dir) app_dir = copy_template_files( - Path(appdir), + dest_dir, template_dir=template_dir, express_available=express_available, mode=mode, @@ -177,7 +174,9 @@ def app_template_questions( print(f"Next steps open and edit the app file: {app_dir}/app.py") -def js_component_questions(component_type: Optional[str] = None): +def js_component_questions( + component_type: Optional[str] = None, dest_dir: Optional[Path | None] = None +): """ Hand question branch for the custom js templates. This should handle the entire rest of the question flow and is responsible for placing files etc. Currently it repeats @@ -212,23 +211,15 @@ def js_component_questions(component_type: Optional[str] = None): if component_name is None: sys.exit(1) - appdir = questionary.path( - "Enter destination directory:", - default=build_path_string(component_name), - only_directories=True, - ).ask() - - if appdir is None: - sys.exit(1) + template_dir = ( + Path(__file__).parent / "templates/package-templates" / component_type + ) - if appdir == ".": - appdir = build_path_string(component_type) + dest_dir = directory_prompt(template_dir, dest_dir) app_dir = copy_template_files( - Path(appdir), - template_dir=Path(__file__).parent - / "templates/package-templates" - / component_type, + dest_dir, + template_dir=template_dir, express_available=False, mode=None, ) @@ -245,6 +236,27 @@ def js_component_questions(component_type: Optional[str] = None): print("- Open and run the example app in the `example-app` directory") +def directory_prompt( + template_dir: Path, dest_dir: Optional[Path | str | None] = None +) -> Path: + if dest_dir is not None: + return Path(dest_dir) + + app_dir = questionary.path( + "Enter destination directory:", + default=build_path_string(""), + only_directories=True, + ).ask() + + if app_dir is None: + sys.exit(1) + + if app_dir == ".": + app_dir = build_path_string(template_dir.name) + + return Path(app_dir) + + def build_path_string(*path: str): """ Build a path string that is valid for the current OS diff --git a/tests/pytest/test_shiny_create.py b/tests/pytest/test_shiny_create.py new file mode 100644 index 000000000..bb45a8285 --- /dev/null +++ b/tests/pytest/test_shiny_create.py @@ -0,0 +1,39 @@ +import os +import shutil +import subprocess +import tempfile + +import pytest + + +def subprocess_create(app_template: str, mode: str): + dest_dir = tempfile.mkdtemp() + cmd = [ + "shiny", + "create", + "--template", + app_template, + "--mode", + mode, + "--directory", + dest_dir, + ] + + subprocess.run(cmd) + assert os.path.isdir(dest_dir) + assert os.path.isfile(f"{dest_dir}/app.py") + + with pytest.raises(subprocess.CalledProcessError): + subprocess.run(cmd, check=True) + + shutil.rmtree(dest_dir) + + +@pytest.mark.parametrize("app_template", ["basic-app", "dashboard", "multi-page"]) +def test_create_core(app_template: str): + subprocess_create(app_template, "core") + + +@pytest.mark.parametrize("app_template", ["basic-app"]) +def test_create_express(app_template: str): + subprocess_create(app_template, "express") From ab339a80b106edf33896533590bdac2c43bd9cbc Mon Sep 17 00:00:00 2001 From: Gordon Shotwell Date: Wed, 3 Jan 2024 10:32:20 -0400 Subject: [PATCH 02/11] Add pip installation commands Closes #957 --- shiny/_template_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/shiny/_template_utils.py b/shiny/_template_utils.py index c25e82794..99dd78053 100644 --- a/shiny/_template_utils.py +++ b/shiny/_template_utils.py @@ -172,6 +172,7 @@ def app_template_questions( print(f"Created Shiny app at {app_dir}") print(f"Next steps open and edit the app file: {app_dir}/app.py") + print("You may need to install packages with: `pip install -r requirements.txt`") def js_component_questions( From 2666e3ae15363afad96a6f0e1ba5a84db6146d7b Mon Sep 17 00:00:00 2001 From: Gordon Shotwell Date: Wed, 3 Jan 2024 10:34:16 -0400 Subject: [PATCH 03/11] Update Shiny create README instructions Closes #960 --- README.md | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 3411b50c2..346c408ad 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -Shiny for Python -================ +# Shiny for Python [![Release](https://img.shields.io/github/v/release/rstudio/py-shiny)](https://img.shields.io/github/v/release/rstudio/py-shiny) [![Build status](https://img.shields.io/github/actions/workflow/status/rstudio/py-shiny/pytest.yaml?branch=main)](https://img.shields.io/github/actions/workflow/status/rstudio/py-shiny/pytest.yaml?branch=main) @@ -10,13 +9,13 @@ Shiny for Python is the best way to build fast, beautiful web applications in Py To learn more about Shiny see the [Shiny for Python website](https://shiny.posit.co/py/). If you're new to the framework we recommend these resources: -- How [Shiny is different](https://posit.co/blog/why-shiny-for-python/) from Dash and Streamlit. +- How [Shiny is different](https://posit.co/blog/why-shiny-for-python/) from Dash and Streamlit. -- How [reactive programming](https://shiny.posit.co/py/docs/reactive-programming.html) can help you build better applications. +- How [reactive programming](https://shiny.posit.co/py/docs/reactive-programming.html) can help you build better applications. -- How to [use modules](https://shiny.posit.co/py/docs/workflow-modules.html) to efficiently develop large applications. +- How to [use modules](https://shiny.posit.co/py/docs/workflow-modules.html) to efficiently develop large applications. -- Hosting applications for free on [shinyapps.io](https://shiny.posit.co/py/docs/deploy.html#deploy-to-shinyapps.io-cloud-hosting), [Hugging Face](https://shiny.posit.co/blog/posts/shiny-on-hugging-face/), or [Shinylive](https://shiny.posit.co/py/docs/shinylive.html). +- Hosting applications for free on [shinyapps.io](https://shiny.posit.co/py/docs/deploy.html#deploy-to-shinyapps.io-cloud-hosting), [Hugging Face](https://shiny.posit.co/blog/posts/shiny-on-hugging-face/), or [Shinylive](https://shiny.posit.co/py/docs/shinylive.html). ## Join the conversation @@ -26,24 +25,19 @@ If you have questions about Shiny for Python, or want to help us decide what to To get started with shiny follow the [installation instructions](https://shiny.posit.co/py/docs/install.html) or just install it from pip. -``` sh +```sh pip install shiny ``` To install the latest development version: -``` sh +```sh # First install htmltools, then shiny pip install https://github.com/posit-dev/py-htmltools/tarball/main pip install https://github.com/posit-dev/py-shiny/tarball/main ``` -You can create and run your first application with: - -``` -shiny create . -shiny run app.py --reload -``` +You can create and run your first application with `shiny create`, the CLI will ask you which template you would like to use. You can either run the app with the Shiny extension, or call `shiny run app.py --reload --launch-browser`. ## Development @@ -51,13 +45,13 @@ API documentation for the `main` branch of Shiny: https://posit-dev.github.io/py If you want to do development on Shiny for Python: -``` sh +```sh pip install -e ".[dev,test]" ``` Additionally, you can install pre-commit hooks which will automatically reformat and lint the code when you make a commit: -``` sh +```sh pre-commit install # To disable: From a12dea0784d57baf3929d1ac1f2cc8a54bbe2829 Mon Sep 17 00:00:00 2001 From: Gordon Shotwell Date: Wed, 3 Jan 2024 10:36:00 -0400 Subject: [PATCH 04/11] Error when template and github are both provided --- shiny/_main.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shiny/_main.py b/shiny/_main.py index 019a9ddb0..286151434 100644 --- a/shiny/_main.py +++ b/shiny/_main.py @@ -526,6 +526,9 @@ def create( ) -> None: from ._template_utils import template_query, use_git_template + if github is not None and template is not None: + raise click.UsageError("You cannot provide both --github and --template") + if isinstance(directory, str): directory = Path(directory) From 10b896b65386b1667412582f5b226fb4b83e76e1 Mon Sep 17 00:00:00 2001 From: Gordon Shotwell Date: Wed, 3 Jan 2024 11:49:47 -0400 Subject: [PATCH 05/11] Better file checking Closed #958 --- shiny/_template_utils.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/shiny/_template_utils.py b/shiny/_template_utils.py index 99dd78053..b49237f8d 100644 --- a/shiny/_template_utils.py +++ b/shiny/_template_utils.py @@ -271,9 +271,12 @@ def copy_template_files( express_available: bool, mode: Optional[str] = None, ): - duplicate_files = [ - file.name for file in template_dir.iterdir() if (app_dir / file.name).exists() - ] + files_to_check = [file.name for file in template_dir.iterdir()] + + files_to_check.remove("__pycache__") + files_to_check.append("app.py") + + duplicate_files = [file for file in files_to_check if (app_dir / file).exists()] if any(duplicate_files): err_files = ", ".join(['"' + file + '"' for file in duplicate_files]) @@ -289,7 +292,8 @@ def copy_template_files( if item.is_file(): shutil.copy(item, app_dir / item.name) else: - shutil.copytree(item, app_dir / item.name) + if item.name != "__pycache__": + shutil.copytree(item, app_dir / item.name) def rename_unlink(file_to_rename: str, file_to_delete: str, dir: Path = app_dir): (dir / file_to_rename).rename(dir / "app.py") From cdf204af208ab4f3c6507e577235f5c53f0447d0 Mon Sep 17 00:00:00 2001 From: Gordon Shotwell Date: Wed, 3 Jan 2024 13:42:31 -0400 Subject: [PATCH 06/11] Validate whether the module name is installed in the current environment Closes #959 --- shiny/_custom_component_template_questions.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/shiny/_custom_component_template_questions.py b/shiny/_custom_component_template_questions.py index 34ebcd3e2..00e64e4b0 100644 --- a/shiny/_custom_component_template_questions.py +++ b/shiny/_custom_component_template_questions.py @@ -1,10 +1,27 @@ import re +from importlib import util from pathlib import Path from prompt_toolkit.document import Document from questionary import ValidationError, Validator +def is_existing_module(name: str) -> bool: + """ + Check if a module name can be imported, which indicates that it is either + a standard module name, or the name of an installed module. + In either case the new module would probably cause a name conflict. + """ + try: + spec = util.find_spec(name) + if spec is not None: + return True + else: + return False + except ImportError: + return False + + def is_pep508_identifier(name: str): """ Checks if a package name is a PEP 508 identifier. @@ -65,6 +82,14 @@ def validate(self, document: Document): cursor_position=len(name), ) + # Using the name of an existing package causes an import error + + if is_existing_module(name): + raise ValidationError( + message="Package already installed in your current environment.", + cursor_position=len(name), + ) + def update_component_name_in_template(template_dir: Path, new_component_name: str): """ From db1a6707122c78770a7d48986ed0c90821db2ead Mon Sep 17 00:00:00 2001 From: Gordon Shotwell Date: Wed, 3 Jan 2024 14:50:50 -0400 Subject: [PATCH 07/11] Add flag to js-component template --- shiny/_main.py | 10 ++++++++- shiny/_template_utils.py | 36 ++++++++++++++++++------------- tests/pytest/test_shiny_create.py | 18 +++++++++++++--- 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/shiny/_main.py b/shiny/_main.py index 286151434..fa6060aca 100644 --- a/shiny/_main.py +++ b/shiny/_main.py @@ -518,11 +518,19 @@ def try_import_module(module: str) -> Optional[types.ModuleType]: "-d", help="The destination directory, you will be prompted if this is not provided.", ) +@click.option( + "--package-name", + help=""" + If you are using one of the JavaScript component templates, + you can use this flag to specify the name of the resulting package without being prompted. + """, +) def create( template: Optional[str] = None, mode: Optional[str] = None, github: Optional[str] = None, directory: Optional[str | Path] = None, + package_name: Optional[str] = None, ) -> None: from ._template_utils import template_query, use_git_template @@ -536,7 +544,7 @@ def create( use_git_template(github, mode, directory) return - template_query(template, mode, directory) + template_query(template, mode, directory, package_name) @main.command( diff --git a/shiny/_template_utils.py b/shiny/_template_utils.py index b49237f8d..d38d47cbe 100644 --- a/shiny/_template_utils.py +++ b/shiny/_template_utils.py @@ -43,7 +43,8 @@ def choice_from_dict(choice_dict: dict[str, str]) -> list[Choice]: def template_query( question_state: Optional[str] = None, mode: Optional[str] = None, - dest_dir: Optional[Path | None] = None, + dest_dir: Optional[Path] = None, + package_name: Optional[str] = None, ): """ This will initiate a CLI query which will ask the user which template they would like. @@ -73,10 +74,10 @@ def template_query( if template is None or template == "cancel": sys.exit(1) elif template == "js-component": - js_component_questions(dest_dir=dest_dir) + js_component_questions(dest_dir=dest_dir, package_name=package_name) return elif template in package_template_choices.values(): - js_component_questions(template, dest_dir=dest_dir) + js_component_questions(template, dest_dir=dest_dir, package_name=package_name) else: app_template_questions(template, mode, dest_dir=dest_dir) @@ -176,7 +177,9 @@ def app_template_questions( def js_component_questions( - component_type: Optional[str] = None, dest_dir: Optional[Path | None] = None + component_type: Optional[str] = None, + dest_dir: Optional[Path] = None, + package_name: Optional[str] = None, ): """ Hand question branch for the custom js templates. This should handle the entire rest @@ -202,15 +205,16 @@ def js_component_questions( if component_type is None or component_type == "cancel": sys.exit(1) - # As what the user wants the name of their component to be - component_name = questionary.text( - "What do you want to name your component?", - instruction="Name must be dash-delimited and all lowercase. E.g. 'my-component-name'", - validate=ComponentNameValidator, - ).ask() + # Ask what the user wants the name of their component to be + if package_name is None: + package_name = questionary.text( + "What do you want to name your component?", + instruction="Name must be dash-delimited and all lowercase. E.g. 'my-component-name'", + validate=ComponentNameValidator, + ).ask() - if component_name is None: - sys.exit(1) + if package_name is None: + sys.exit(1) template_dir = ( Path(__file__).parent / "templates/package-templates" / component_type @@ -226,8 +230,8 @@ def js_component_questions( ) # Print messsage saying we're building the component - print(f"Setting up {component_name} component package...") - update_component_name_in_template(app_dir, component_name) + print(f"Setting up {package_name} component package...") + update_component_name_in_template(app_dir, package_name) print("\nNext steps:") print(f"- Run `cd {app_dir}` to change into the new directory") @@ -273,7 +277,9 @@ def copy_template_files( ): files_to_check = [file.name for file in template_dir.iterdir()] - files_to_check.remove("__pycache__") + if "__pycache__" in files_to_check: + files_to_check.remove("__pycache__") + files_to_check.append("app.py") duplicate_files = [file for file in files_to_check if (app_dir / file).exists()] diff --git a/tests/pytest/test_shiny_create.py b/tests/pytest/test_shiny_create.py index bb45a8285..ef73964d4 100644 --- a/tests/pytest/test_shiny_create.py +++ b/tests/pytest/test_shiny_create.py @@ -6,7 +6,7 @@ import pytest -def subprocess_create(app_template: str, mode: str): +def subprocess_create(app_template: str, mode: str = "core", package_name: str = ""): dest_dir = tempfile.mkdtemp() cmd = [ "shiny", @@ -17,11 +17,18 @@ def subprocess_create(app_template: str, mode: str): mode, "--directory", dest_dir, + "--package-name", + package_name, ] subprocess.run(cmd) assert os.path.isdir(dest_dir) - assert os.path.isfile(f"{dest_dir}/app.py") + + # Package templates don't have a top-level app.py file + if package_name == "": + assert os.path.isfile(f"{dest_dir}/app.py") + else: + assert os.path.isfile(f"{dest_dir}/pyproject.toml") with pytest.raises(subprocess.CalledProcessError): subprocess.run(cmd, check=True) @@ -31,9 +38,14 @@ def subprocess_create(app_template: str, mode: str): @pytest.mark.parametrize("app_template", ["basic-app", "dashboard", "multi-page"]) def test_create_core(app_template: str): - subprocess_create(app_template, "core") + subprocess_create(app_template) @pytest.mark.parametrize("app_template", ["basic-app"]) def test_create_express(app_template: str): subprocess_create(app_template, "express") + + +@pytest.mark.parametrize("app_template", ["js-input", "js-output", "js-react"]) +def test_create_js(app_template: str): + subprocess_create("js-input", package_name="my_component") From 3c2233169fa299e64f454e2179f71de45cd5887b Mon Sep 17 00:00:00 2001 From: Gordon Shotwell Date: Thu, 4 Jan 2024 10:56:49 -0400 Subject: [PATCH 08/11] Update template to use new npm package --- .../templates/package-templates/js-react/srcts/index.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/shiny/templates/package-templates/js-react/srcts/index.tsx b/shiny/templates/package-templates/js-react/srcts/index.tsx index 4698b8219..1b35e7257 100644 --- a/shiny/templates/package-templates/js-react/srcts/index.tsx +++ b/shiny/templates/package-templates/js-react/srcts/index.tsx @@ -1,12 +1,15 @@ import { SketchPicker } from "react-color"; import React from "react"; -import { makeReactInput, makeReactOutput } from "@shiny-helpers/react"; +import { + makeReactInput, + makeReactOutput, +} from "@posit-dev/shiny-bindings-react"; // Generates a new input binding that renders the supplied react component // into the root of the webcomponent. makeReactInput({ - tagName: "custom-component-input", + name: "custom-component-input", initialValue: "#fff", renderComp: ({ initialValue, onNewValue }) => ( ({ - tagName: "custom-component-output", + name: "custom-component-output", renderComp: ({ value }) => (
Date: Tue, 9 Jan 2024 10:39:35 -0500 Subject: [PATCH 09/11] Add future testing comment --- tests/pytest/test_shiny_create.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/pytest/test_shiny_create.py b/tests/pytest/test_shiny_create.py index ef73964d4..1b5ccd8c3 100644 --- a/tests/pytest/test_shiny_create.py +++ b/tests/pytest/test_shiny_create.py @@ -36,6 +36,7 @@ def subprocess_create(app_template: str, mode: str = "core", package_name: str = shutil.rmtree(dest_dir) +# TODO-karan; Integrate all tests below with _examples_ testing and check for JS errors / output errors. @pytest.mark.parametrize("app_template", ["basic-app", "dashboard", "multi-page"]) def test_create_core(app_template: str): subprocess_create(app_template) From 237a5117be23cd138252d8f51713ba5f8075e32e Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Tue, 9 Jan 2024 13:48:38 -0500 Subject: [PATCH 10/11] Update CHANGELOG.md --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3fe12412..b7bc07bc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [UNRELEASED] +### Bug fixes + +* CLI command `shiny create`... (#965) + * has added a `-d`/`--dir` flag for saving to a specific output directory + * will raise an error if if will overwrite existing files + * prompt users to install `requirements.txt` +* Fixed `js-react` template build error. (#965) + ## [0.6.1.1] - 2023-12-22 From 37ac79d52e41380ff306921441dd657666fbd150 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Tue, 9 Jan 2024 13:49:54 -0500 Subject: [PATCH 11/11] Rename `--directory` to `--dir` --- shiny/_main.py | 12 ++++++------ tests/pytest/test_shiny_create.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/shiny/_main.py b/shiny/_main.py index fa6060aca..acdca39d7 100644 --- a/shiny/_main.py +++ b/shiny/_main.py @@ -514,7 +514,7 @@ def try_import_module(module: str) -> Optional[types.ModuleType]: help="The GitHub URL of the template sub-directory. For example https://github.com/posit-dev/py-shiny-templates/tree/main/dashboard", ) @click.option( - "--directory", + "--dir", "-d", help="The destination directory, you will be prompted if this is not provided.", ) @@ -529,7 +529,7 @@ def create( template: Optional[str] = None, mode: Optional[str] = None, github: Optional[str] = None, - directory: Optional[str | Path] = None, + dir: Optional[str | Path] = None, package_name: Optional[str] = None, ) -> None: from ._template_utils import template_query, use_git_template @@ -537,14 +537,14 @@ def create( if github is not None and template is not None: raise click.UsageError("You cannot provide both --github and --template") - if isinstance(directory, str): - directory = Path(directory) + if isinstance(dir, str): + dir = Path(dir) if github is not None: - use_git_template(github, mode, directory) + use_git_template(github, mode, dir) return - template_query(template, mode, directory, package_name) + template_query(template, mode, dir, package_name) @main.command( diff --git a/tests/pytest/test_shiny_create.py b/tests/pytest/test_shiny_create.py index 1b5ccd8c3..a777f5022 100644 --- a/tests/pytest/test_shiny_create.py +++ b/tests/pytest/test_shiny_create.py @@ -15,7 +15,7 @@ def subprocess_create(app_template: str, mode: str = "core", package_name: str = app_template, "--mode", mode, - "--directory", + "--dir", dest_dir, "--package-name", package_name, @@ -36,7 +36,7 @@ def subprocess_create(app_template: str, mode: str = "core", package_name: str = shutil.rmtree(dest_dir) -# TODO-karan; Integrate all tests below with _examples_ testing and check for JS errors / output errors. +# TODO-karan; Integrate all tests below with _examples_ testing and check for JS errors / output errors. @pytest.mark.parametrize("app_template", ["basic-app", "dashboard", "multi-page"]) def test_create_core(app_template: str): subprocess_create(app_template)