Skip to content

Commit 081f5fb

Browse files
committed
Call startapp management command if the app doesn't already exist.
1 parent bc55d77 commit 081f5fb

File tree

2 files changed

+133
-54
lines changed

2 files changed

+133
-54
lines changed

django_unicorn/management/commands/startunicorn.py

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
import webbrowser
33
from pathlib import Path
44

5+
from django.apps import apps
56
from django.conf import settings
7+
from django.core.management import call_command
68
from django.core.management.base import BaseCommand, CommandError
7-
from django.apps import apps
89

910
from django_unicorn.components.unicorn_view import (
1011
convert_to_pascal_case,
@@ -25,6 +26,14 @@ class {pascal_case_component_name}View(UnicornView):
2526
"""
2627

2728

29+
def get_app_path(app_name: str) -> Path:
30+
"""
31+
Gets the directory path for an installed application.
32+
"""
33+
34+
return Path(apps.get_app_config(app_name).path)
35+
36+
2837
class Command(BaseCommand):
2938
help = "Creates a new component for `django-unicorn`"
3039

@@ -55,18 +64,31 @@ def handle(self, *args, **options):
5564
raise CommandError("At least one component name is required.")
5665

5766
app_name = options["app_name"]
67+
is_new_app = False
68+
5869
try:
59-
app_directory = Path(apps.get_app_config(app_name).path)
70+
app_directory = get_app_path(app_name)
6071
except LookupError:
61-
# this app does not exist yet
62-
raise CommandError(
63-
f"An app named '{app_name}' does not exist yet. "
64-
"You have to create it first."
72+
should_create_app = input(
73+
f"\n'{app_name}' cannot be found. Should it be created automatically with `startapp {app_name}`? [y/N] "
6574
)
6675

76+
if should_create_app.strip().lower() in ("y", "yes"):
77+
call_command(
78+
"startapp", app_name, verbosity=0,
79+
)
80+
app_directory = base_path / app_name
81+
82+
is_new_app = True
83+
else:
84+
raise CommandError(
85+
f"An app named '{app_name}' does not exist yet. You might need to create it first."
86+
)
87+
6788
is_first_component = False
6889

69-
(app_directory / "__init__.py").touch(exist_ok=True)
90+
if not app_directory.exists():
91+
app_directory.mkdir()
7092

7193
# Create component
7294
component_base_path = app_directory / "components"
@@ -75,7 +97,7 @@ def handle(self, *args, **options):
7597
component_base_path.mkdir()
7698

7799
self.stdout.write(
78-
self.style.SUCCESS(f"Created your first component in {app_name}! ✨\n")
100+
self.style.SUCCESS(f"Created your first component in '{app_name}'! ✨\n")
79101
)
80102

81103
is_first_component = True
@@ -165,3 +187,10 @@ def handle(self, *args, **options):
165187
"That's a bummer, but I understand. I hope you will star it for me later!"
166188
)
167189
)
190+
191+
if is_new_app:
192+
self.stdout.write(
193+
self.style.WARNING(
194+
f'\nMake sure to add `"{app_name}",` to your INSTALLED_APPS list in your settings file if necessary.'
195+
)
196+
)

tests/management/commands/startunicorn/test_handle.py

Lines changed: 96 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import io
22
import os
3+
import uuid
34

45
from django.core.management.base import CommandError
56

@@ -23,16 +24,24 @@ def test_handle_no_args(settings):
2324
def test_handle_new_app(settings, tmp_path, monkeypatch, capsys):
2425
settings.BASE_DIR = tmp_path
2526

26-
# Reply "y" then "n"
27+
# Reply "y" to create new app then "n" to star the repo
2728
monkeypatch.setattr("sys.stdin", io.StringIO("y\nn\n"))
2829

29-
app_name = "test123"
30-
component_names = ["hello-world"]
30+
# Prevent the `startapp` command from actually creating a new app
31+
monkeypatch.setattr(
32+
"django_unicorn.management.commands.startunicorn.call_command",
33+
lambda *args, **kwargs: None,
34+
)
35+
36+
app_name = f"test-{uuid.uuid4()}".replace("-", "_")
37+
component_names = [
38+
"hello-world",
39+
]
3140
Command().handle(app_name=app_name, component_names=component_names)
3241

33-
assert (tmp_path / f"{app_name}/components/__init__.py").exists()
34-
assert (tmp_path / f"{app_name}/components/hello_world.py").exists()
35-
assert (tmp_path / f"{app_name}/templates/unicorn/hello-world.html").exists()
42+
assert (tmp_path / app_name / "components/__init__.py").exists()
43+
assert (tmp_path / app_name / "components/hello_world.py").exists()
44+
assert (tmp_path / app_name / "templates/unicorn/hello-world.html").exists()
3645

3746
captured = capsys.readouterr()
3847
assert "Starring the GitHub repo " in captured.out
@@ -41,19 +50,24 @@ def test_handle_new_app(settings, tmp_path, monkeypatch, capsys):
4150

4251
def test_handle_existing_app(settings, tmp_path, monkeypatch, capsys):
4352
settings.BASE_DIR = tmp_path
53+
app_name = f"test-{uuid.uuid4()}".replace("-", "_")
4454

45-
app_name = "test123"
46-
(tmp_path / app_name).mkdir()
55+
monkeypatch.setattr(
56+
"django_unicorn.management.commands.startunicorn.get_app_path",
57+
lambda a: tmp_path / app_name,
58+
)
4759

48-
# Reply "y" then "n"
49-
monkeypatch.setattr("sys.stdin", io.StringIO("y\nn\n"))
60+
# Reply "n" to starring question
61+
monkeypatch.setattr("sys.stdin", io.StringIO("n\n"))
5062

51-
component_names = ["hello-world"]
63+
component_names = [
64+
"hello-world",
65+
]
5266
Command().handle(app_name=app_name, component_names=component_names)
5367

54-
assert (tmp_path / f"{app_name}/components/__init__.py").exists()
55-
assert (tmp_path / f"{app_name}/components/hello_world.py").exists()
56-
assert (tmp_path / f"{app_name}/templates/unicorn/hello-world.html").exists()
68+
assert (tmp_path / app_name / "components/__init__.py").exists()
69+
assert (tmp_path / app_name / "components/hello_world.py").exists()
70+
assert (tmp_path / app_name / "templates/unicorn/hello-world.html").exists()
5771

5872
captured = capsys.readouterr()
5973
assert "Starring the GitHub repo " in captured.out
@@ -63,20 +77,24 @@ def test_handle_existing_app(settings, tmp_path, monkeypatch, capsys):
6377

6478
def test_handle_existing_component(settings, tmp_path, monkeypatch, capsys):
6579
settings.BASE_DIR = tmp_path
80+
app_name = f"test-{uuid.uuid4()}".replace("-", "_")
81+
82+
monkeypatch.setattr(
83+
"django_unicorn.management.commands.startunicorn.get_app_path",
84+
lambda a: tmp_path / app_name,
85+
)
6686

67-
app_name = "test123"
6887
(tmp_path / app_name).mkdir()
6988
(tmp_path / app_name / "components").mkdir()
7089

71-
# Reply "y"
72-
monkeypatch.setattr("sys.stdin", io.StringIO("y\n"))
73-
74-
component_names = ["hello-world"]
90+
component_names = [
91+
"hello-world",
92+
]
7593
Command().handle(app_name=app_name, component_names=component_names)
7694

77-
assert (tmp_path / f"{app_name}/components/__init__.py").exists()
78-
assert (tmp_path / f"{app_name}/components/hello_world.py").exists()
79-
assert (tmp_path / f"{app_name}/templates/unicorn/hello-world.html").exists()
95+
assert (tmp_path / app_name / "components/__init__.py").exists()
96+
assert (tmp_path / app_name / "components/hello_world.py").exists()
97+
assert (tmp_path / app_name / "templates/unicorn/hello-world.html").exists()
8098

8199
captured = capsys.readouterr()
82100
assert "Starring the GitHub repo " not in captured.out
@@ -85,21 +103,25 @@ def test_handle_existing_component(settings, tmp_path, monkeypatch, capsys):
85103

86104
def test_handle_existing_templates(settings, tmp_path, monkeypatch, capsys):
87105
settings.BASE_DIR = tmp_path
106+
app_name = f"test-{uuid.uuid4()}".replace("-", "_")
107+
108+
monkeypatch.setattr(
109+
"django_unicorn.management.commands.startunicorn.get_app_path",
110+
lambda a: tmp_path / app_name,
111+
)
88112

89-
app_name = "test123"
90113
(tmp_path / app_name).mkdir()
91114
(tmp_path / app_name / "components").mkdir()
92115
(tmp_path / app_name / "templates").mkdir()
93116

94-
# Reply "y"
95-
monkeypatch.setattr("sys.stdin", io.StringIO("y\n"))
96-
97-
component_names = ["hello-world"]
117+
component_names = [
118+
"hello-world",
119+
]
98120
Command().handle(app_name=app_name, component_names=component_names)
99121

100-
assert (tmp_path / f"{app_name}/components/__init__.py").exists()
101-
assert (tmp_path / f"{app_name}/components/hello_world.py").exists()
102-
assert (tmp_path / f"{app_name}/templates/unicorn/hello-world.html").exists()
122+
assert (tmp_path / app_name / "components/__init__.py").exists()
123+
assert (tmp_path / app_name / "components/hello_world.py").exists()
124+
assert (tmp_path / app_name / "templates/unicorn/hello-world.html").exists()
103125

104126
captured = capsys.readouterr()
105127
assert "Starring the GitHub repo " not in captured.out
@@ -108,17 +130,21 @@ def test_handle_existing_templates(settings, tmp_path, monkeypatch, capsys):
108130

109131
def test_handle_existing_unicorn_templates(settings, tmp_path, monkeypatch, capsys):
110132
settings.BASE_DIR = tmp_path
133+
app_name = f"test-{uuid.uuid4()}".replace("-", "_")
134+
135+
monkeypatch.setattr(
136+
"django_unicorn.management.commands.startunicorn.get_app_path",
137+
lambda a: tmp_path / app_name,
138+
)
111139

112-
app_name = "test123"
113140
(tmp_path / app_name).mkdir()
114141
(tmp_path / app_name / "components").mkdir()
115142
(tmp_path / app_name / "templates").mkdir()
116-
(tmp_path / app_name / "templates" / "unicorn").mkdir()
117-
118-
# Reply "y"
119-
monkeypatch.setattr("sys.stdin", io.StringIO("y\n"))
143+
(tmp_path / app_name / "templates/unicorn").mkdir()
120144

121-
component_names = ["hello-world"]
145+
component_names = [
146+
"hello-world",
147+
]
122148
Command().handle(app_name=app_name, component_names=component_names)
123149

124150
assert (tmp_path / f"{app_name}/components/__init__.py").exists()
@@ -130,33 +156,49 @@ def test_handle_existing_unicorn_templates(settings, tmp_path, monkeypatch, caps
130156
assert "Make sure to add " not in captured.out
131157

132158

133-
def test_handle_reply_no(settings, tmp_path, monkeypatch, capsys):
159+
def test_handle_reply_n(settings, tmp_path, monkeypatch, capsys):
134160
settings.BASE_DIR = tmp_path
135161

136162
# Reply "n"
137163
monkeypatch.setattr("sys.stdin", io.StringIO("n\n"))
138164

139-
app_name = "test123"
140-
component_names = ["hello-world"]
141-
Command().handle(app_name=app_name, component_names=component_names)
165+
app_name = f"test-{uuid.uuid4()}".replace("-", "_")
166+
component_names = [
167+
"hello-world",
168+
]
169+
170+
with pytest.raises(CommandError):
171+
Command().handle(app_name=app_name, component_names=component_names)
142172

143173
assert not (tmp_path / f"{app_name}/components/__init__.py").exists()
144174
assert not (tmp_path / f"{app_name}/components/hello_world.py").exists()
145175
assert not (tmp_path / f"{app_name}/templates/unicorn/hello-world.html").exists()
146176

147177
captured = capsys.readouterr()
178+
assert "cannot be found." in captured.out
148179
assert "Make sure to add " not in captured.out
149180

181+
182+
def test_handle_reply_no(settings, tmp_path, monkeypatch, capsys):
183+
settings.BASE_DIR = tmp_path
184+
150185
# Reply "no"
151186
monkeypatch.setattr("sys.stdin", io.StringIO("no\n"))
152187

153-
Command().handle(app_name=app_name, component_names=component_names)
188+
app_name = f"test-{uuid.uuid4()}".replace("-", "_")
189+
component_names = [
190+
"hello-world",
191+
]
192+
193+
with pytest.raises(CommandError):
194+
Command().handle(app_name=app_name, component_names=component_names)
154195

155196
assert not (tmp_path / f"{app_name}/components/__init__.py").exists()
156197
assert not (tmp_path / f"{app_name}/components/hello_world.py").exists()
157198
assert not (tmp_path / f"{app_name}/templates/unicorn/hello-world.html").exists()
158199

159200
captured = capsys.readouterr()
201+
assert "cannot be found." in captured.out
160202
assert "Make sure to add " not in captured.out
161203

162204

@@ -172,14 +214,22 @@ def webbrowser_open(url, **kwargs):
172214

173215
monkeypatch.setattr("webbrowser.open", webbrowser_open)
174216

175-
app_name = "test123"
176-
component_names = ["hello-world"]
217+
# Prevent the `startapp` command from actually creating a new app
218+
monkeypatch.setattr(
219+
"django_unicorn.management.commands.startunicorn.call_command",
220+
lambda *args, **kwargs: None,
221+
)
222+
223+
app_name = f"test-{uuid.uuid4()}".replace("-", "_")
224+
component_names = [
225+
"hello-world",
226+
]
177227

178228
Command().handle(app_name=app_name, component_names=component_names)
179229

180-
assert (tmp_path / f"{app_name}/components/__init__.py").exists()
181-
assert (tmp_path / f"{app_name}/components/hello_world.py").exists()
182-
assert (tmp_path / f"{app_name}/templates/unicorn/hello-world.html").exists()
230+
assert (tmp_path / app_name / "components/__init__.py").exists()
231+
assert (tmp_path / app_name / "components/hello_world.py").exists()
232+
assert (tmp_path / app_name / "templates/unicorn/hello-world.html").exists()
183233

184234
captured = capsys.readouterr()
185235
assert "Starring the GitHub repo " in captured.out

0 commit comments

Comments
 (0)