Skip to content

Commit c673813

Browse files
authored
Improve create command (#137)
* Allow description, name and email to be empty * Add test * Bump pre-commit versions * Copy from pyscript config * Run pre-commit and update tests * trigger pre-commit * Prompt users for an app name instead of blowing up * Allow to pass .py files at the same level as the call * Actually wrap the file automatically if using single .py file
1 parent edb062c commit c673813

File tree

4 files changed

+79
-10
lines changed

4 files changed

+79
-10
lines changed

src/pyscript/_generator.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,12 @@ def create_project(
100100
assert app_or_file_name is not None
101101
app_name = app_or_file_name.removesuffix(".py")
102102
else:
103-
assert app_or_file_name is not None
104-
app_name = app_or_file_name
103+
if app_or_file_name and app_or_file_name.endswith(".py"):
104+
app_name = app_or_file_name.removesuffix(".py")
105+
else:
106+
# At this point we should always have a name, but typing
107+
# was complaining so let's add a default
108+
app_name = app_or_file_name or "my-pyscript-app"
105109

106110
context = {
107111
"name": app_name,
@@ -111,6 +115,7 @@ def create_project(
111115
"author_email": author_email,
112116
"version": f"{date_stamp.year}.{'{:02d}'.format(date_stamp.month)}.1",
113117
}
118+
114119
app_dir = Path(".") / app_name
115120
app_dir.mkdir()
116121
manifest_file = app_dir / config["project_config_filename"]
@@ -128,9 +133,12 @@ def create_project(
128133
python_filepath = app_dir / "main.py"
129134

130135
if not wrap:
131-
# Save the new python file
132-
with python_filepath.open("w", encoding="utf-8") as fp:
133-
fp.write(TEMPLATE_PYTHON_CODE)
136+
if app_or_file_name and app_or_file_name.endswith(".py"):
137+
python_filepath.write_bytes(Path(app_or_file_name).read_bytes())
138+
else:
139+
# Save the new python file
140+
with python_filepath.open("w", encoding="utf-8") as fp:
141+
fp.write(TEMPLATE_PYTHON_CODE)
134142
else:
135143
if command:
136144
with python_filepath.open("w", encoding="utf-8") as fp:

src/pyscript/plugins/create.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,7 @@ def create(
4949
a python file instead.
5050
"""
5151
if not app_or_file_name and not command:
52-
raise cli.Abort(
53-
"Must provide either an input '.py' file or a command with the '-c' option."
54-
)
52+
app_or_file_name = typer.prompt("App name", default="my-pyscript-app")
5553

5654
if app_or_file_name and command:
5755
raise cli.Abort("Cannot provide both an input '.py' file and '-c' option.")

tests/conftest.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@
88
@pytest.fixture
99
def auto_enter(monkeypatch):
1010
"""
11-
Monkey patch 'typer.confirm' to always hit <Enter>".
11+
Monkey patch 'typer.prompt' to always hit <Enter>".
1212
"""
1313

1414
def user_hit_enter(*args, **kwargs):
15-
return ""
15+
# This makes sure that if there is a default value on a prompt
16+
# we will return it, otherwise we will return an empty string
17+
# which isn't the same as hitting enter!
18+
default_value = kwargs.get("default", "")
19+
return default_value
1620

1721
monkeypatch.setattr("typer.prompt", user_hit_enter)
1822

tests/test_cli.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,65 @@ def test_create_command(
7272
assert 'author_email = ""' in config_text
7373

7474

75+
def test_create_command_no_app_name(
76+
invoke_cli: CLIInvoker, tmp_path: Path, app_details_args: list[str], auto_enter
77+
) -> None:
78+
result = invoke_cli("create")
79+
assert result.exit_code == 0
80+
81+
expected_path = tmp_path / "my-pyscript-app"
82+
assert expected_path.exists()
83+
84+
expected_main_py_path = expected_path / "main.py"
85+
assert expected_main_py_path.exists()
86+
87+
expected_config_path = expected_path / config["project_config_filename"]
88+
assert expected_config_path.exists()
89+
with expected_config_path.open() as fp:
90+
config_text = fp.read()
91+
92+
assert 'name = "my-pyscript-app' in config_text
93+
# Assert that description, author name and email are empty
94+
assert 'description = ""' in config_text
95+
assert 'author_name = ""' in config_text
96+
assert 'author_email = ""' in config_text
97+
98+
99+
def test_create_command_with_single_py_file(
100+
invoke_cli: CLIInvoker, tmp_path: Path, app_details_args: list[str], auto_enter
101+
):
102+
"""
103+
Test that when create is called with a single python file as input,
104+
the project is created correctly
105+
"""
106+
input_file = tmp_path / "hello.py"
107+
with input_file.open("w") as fp:
108+
fp.write('print("Yo!")')
109+
110+
result = invoke_cli("create", "hello.py", *app_details_args)
111+
assert result.exit_code == 0
112+
113+
expected_path = tmp_path / "hello"
114+
assert expected_path.exists()
115+
116+
expected_main_py_path = expected_path / "main.py"
117+
assert expected_main_py_path.exists()
118+
with expected_main_py_path.open() as fp:
119+
py_text = fp.read()
120+
121+
assert 'print("Yo!")' in py_text
122+
123+
expected_config_path = expected_path / config["project_config_filename"]
124+
assert expected_config_path.exists()
125+
with expected_config_path.open() as fp:
126+
config_text = fp.read()
127+
128+
assert 'name = "hello' in config_text
129+
# Assert that description, author name and email are empty
130+
assert 'description = "tester-app"' in config_text
131+
assert 'author_name = "tester"' in config_text
132+
133+
75134
@pytest.mark.parametrize("flag", ["-c", "--command"])
76135
def test_wrap_command(
77136
invoke_cli: CLIInvoker, tmp_path: Path, flag: str, app_details_args: list[str]

0 commit comments

Comments
 (0)