Skip to content

Commit f158c9c

Browse files
authored
Basic cli (#5)
* basic create and serve project cli * tweak cli
1 parent 8f6f1ee commit f158c9c

File tree

3 files changed

+73
-7
lines changed

3 files changed

+73
-7
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "FireFrame"
7-
version = "0.0.0-alpha.9"
7+
version = "0.0.0-alpha.10"
88
authors = [
99
{ name="Zachary Spar", email="[email protected]" },
1010
]

src/fireframe/cli/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
from .project import project_cli
44

5-
cli = click.CommandCollection(sources=[project_cli])
5+
cli = project_cli()

src/fireframe/cli/project.py

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ def project_cli(ctx):
1212

1313
@project_cli.command()
1414
@click.argument("name", required=True, type=str)
15-
@click.option("--path", "-p", type=click.Path())
15+
@click.option("--path", "-p", type=click.Path(), help="The path to create the project in.")
1616
@click.pass_context
1717
def create(ctx, name: str, path):
18+
"""
19+
Create a new FireFrame project scaffold.
20+
"""
1821
click.echo(f"Creating new project {name}...")
1922
# create a new subdirectory to path if given,
2023
# otherwise create a new subdirectory to current working directory
@@ -25,10 +28,73 @@ def create(ctx, name: str, path):
2528
elif not os.path.exists(name):
2629
os.makedirs(os.path.join(os.getcwd(), name))
2730

31+
# NOTE: We should probably use proper templates for these files
32+
# create a file called main.py in the new project directory
33+
with open(os.path.join(os.getcwd(), name, "main.py"), "w") as f:
34+
f.write(f"# Path: {name}/main.py\n\n")
35+
f.write(f"from fireframe.core.api import FireFrameAPI\n")
36+
f.write(f"from fireframe.core.viewsets import crud_viewset\n\n")
37+
f.write(f"from serializers import Example{name.capitalize()}Serializer\n")
38+
f.write(f"from views import Example{name.capitalize()}ListAPIView\n\n")
39+
f.write(f'app = FireFrameAPI(name="{name}", version="0.0.0")\n\n')
40+
f.write(f"# TODO: Add your routes here\n")
41+
f.write(f"app.include_router(crud_viewset(Example{name.capitalize()}Serializer))\n")
42+
f.write(f"app.include_router(Example{name.capitalize()}ListAPIView())\n")
43+
44+
# create a file called models.py in the new project directory
45+
with open(os.path.join(os.getcwd(), name, "models.py"), "w") as f:
46+
f.write(f"# Path: {name}/models.py\n\n")
47+
f.write(f"from fireframe.core.models import Model\n\n")
48+
f.write(f"class Example{name.capitalize()}Model(Model):\n")
49+
f.write(f" example: str\n\n")
50+
f.write(f"# TODO: Add more models here\n")
51+
52+
# create a file called serializers.py in the new project directory
53+
with open(os.path.join(os.getcwd(), name, "serializers.py"), "w") as f:
54+
f.write(f"# Path: {name}/serializers.py\n\n")
55+
f.write("from fireframe.core.serializers import ModelSerializer\n\n")
56+
f.write(f"from models import Example{name.capitalize()}Model\n\n")
57+
f.write(f"class Example{name.capitalize()}Serializer(ModelSerializer):\n")
58+
f.write(f" class Meta:\n")
59+
f.write(f" model = Example{name.capitalize()}Model\n")
60+
f.write(f' fields = ["example"]\n\n')
61+
f.write(f"# TODO: Add more serializers here\n")
62+
63+
# create a file called views.py in the new project directory
64+
with open(os.path.join(os.getcwd(), name, "views.py"), "w") as f:
65+
f.write(f"# Path: {name}/views.py\n\n")
66+
f.write("from fireframe.core.views import BaseListAPIView\n\n")
67+
f.write(f"from serializers import Example{name.capitalize()}Serializer\n\n")
68+
f.write(f"class Example{name.capitalize()}ListAPIView(BaseListAPIView):\n")
69+
f.write(f" serializer_class = Example{name.capitalize()}Serializer\n\n")
70+
f.write(f"# TODO: Add more views here\n")
71+
2872

2973
@project_cli.command()
30-
@click.argument("name", required=True, type=str)
74+
@click.option(
75+
"--entrypoint", "-e", type=str, default="main:app", help="The entrypoint of the project as specified by uvicorn."
76+
)
77+
@click.option("--port", "-p", type=int, default=8000, help="The port to run the project on.")
3178
@click.pass_context
32-
def startapp(ctx, name: str):
33-
click.echo(f"Starting new app {name}...")
34-
raise NotImplementedError("Implement project startapp.")
79+
def serve(ctx, entrypoint: str, port: int):
80+
"""
81+
Run the FireFrame project.
82+
"""
83+
click.echo(f"Running FireFrame project on port {port} ...")
84+
# check if uvicorn is installed via pip
85+
try:
86+
import uvicorn
87+
except ImportError:
88+
click.echo("Uvicorn is not installed. Installing it via pip.")
89+
os.system("pip install uvicorn")
90+
91+
# check if the project has a main.py file
92+
if not os.path.exists(os.path.join(os.getcwd(), f"{entrypoint.split(':')[0]}.py")):
93+
click.echo("No main.py file found. Please run this command from the root directory of your project.")
94+
click.echo(
95+
"If you have renamed your main.py file, please specify the new entrypoint with the --entrypoint flag."
96+
)
97+
return
98+
99+
# run the project with uvicorn in background
100+
os.system(f"uvicorn {entrypoint} --reload --port {port} --host '0.0.0.0'")

0 commit comments

Comments
 (0)