mirror of
https://github.com/ycd/manage-fastapi.git
synced 2021-11-08 01:34:39 +03:00
Support Windows and MacOS (#36)
* Support Windows and MacOS * Add questionary dependency * Remove the tests * Remove print
This commit is contained in:
committed by
GitHub
parent
ff798ab052
commit
41648fb46e
3
.github/workflows/test.yml
vendored
3
.github/workflows/test.yml
vendored
@@ -8,9 +8,10 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: "${{ matrix.os }}"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
python-version: [3.6, 3.7, 3.8, 3.9]
|
python-version: [3.6, 3.7, 3.8, 3.9]
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +1,19 @@
|
|||||||
import re
|
import re
|
||||||
from typing import Tuple, TypeVar
|
from typing import TypeVar
|
||||||
|
|
||||||
from bullet import Bullet, SlidePrompt, colors
|
import questionary
|
||||||
from bullet.client import YesNo
|
|
||||||
|
|
||||||
EnumType = TypeVar("EnumType")
|
EnumType = TypeVar("EnumType")
|
||||||
|
|
||||||
WHITE_FOREGROUND = colors.foreground["white"]
|
|
||||||
|
|
||||||
|
|
||||||
def camel_to_snake(text: str) -> str:
|
def camel_to_snake(text: str) -> str:
|
||||||
return re.sub(r"(?<!^)(?=[A-Z])", "_", text).lower()
|
return re.sub(r"(?<!^)(?=[A-Z])", "_", text).lower()
|
||||||
|
|
||||||
|
|
||||||
def bullet(choices: EnumType) -> Bullet:
|
def question(choices: EnumType) -> questionary.Question:
|
||||||
prompt = camel_to_snake(choices.__name__).replace("_", " ") # type: ignore
|
prompt = camel_to_snake(choices.__name__).replace("_", " ") # type: ignore
|
||||||
return Bullet(
|
return questionary.select(f"Select the {prompt}: ", choices=list(choices))
|
||||||
prompt=f"Select the {prompt}: ",
|
|
||||||
choices=list(choices), # type: ignore
|
|
||||||
bullet=" >",
|
|
||||||
margin=2,
|
|
||||||
word_color=WHITE_FOREGROUND,
|
|
||||||
word_on_switch=WHITE_FOREGROUND,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def yes_no(option: str) -> YesNo:
|
def binary_question(option: str) -> questionary.Question:
|
||||||
return YesNo(
|
return questionary.confirm(f"Do you want {option}?", default=False)
|
||||||
prompt=f"Do you want {option}?", default="n", word_color=WHITE_FOREGROUND
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def launch_cli(*prompt_objs: Tuple[str, Bullet]):
|
|
||||||
names, objs = zip(*prompt_objs)
|
|
||||||
results = SlidePrompt(objs).launch()
|
|
||||||
return {name: result[1] for name, result in zip(names, results)}
|
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ from typing import Optional
|
|||||||
|
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
import typer
|
import typer
|
||||||
|
from questionary.form import form
|
||||||
|
|
||||||
from manage_fastapi.constants import Database, License, PackageManager, PythonVersion
|
from manage_fastapi.constants import Database, License, PackageManager, PythonVersion
|
||||||
from manage_fastapi.context import AppContext, ProjectContext
|
from manage_fastapi.context import AppContext, ProjectContext
|
||||||
from manage_fastapi.generator import generate_app, generate_project
|
from manage_fastapi.generator import generate_app, generate_project
|
||||||
from manage_fastapi.helpers import bullet, launch_cli, yes_no
|
from manage_fastapi.helpers import binary_question, question
|
||||||
|
|
||||||
app = typer.Typer(
|
app = typer.Typer(
|
||||||
add_completion=False,
|
add_completion=False,
|
||||||
@@ -29,13 +30,13 @@ def startproject(
|
|||||||
python: PythonVersion = typer.Option(PythonVersion.THREE_DOT_EIG),
|
python: PythonVersion = typer.Option(PythonVersion.THREE_DOT_EIG),
|
||||||
):
|
):
|
||||||
if interactive:
|
if interactive:
|
||||||
result = launch_cli(
|
result = form(
|
||||||
("packaging", bullet(PackageManager)),
|
packaging=question(PackageManager),
|
||||||
("python", bullet(PythonVersion)),
|
python=question(PythonVersion),
|
||||||
("license", bullet(License)),
|
license=question(License),
|
||||||
("pre_commit", yes_no("pre commit")),
|
pre_commit=binary_question("pre commit"),
|
||||||
("docker", yes_no("docker")),
|
docker=binary_question("docker"),
|
||||||
("database", bullet(Database)),
|
database=question(Database),
|
||||||
)
|
)
|
||||||
context = ProjectContext(name=name, **result)
|
context = ProjectContext(name=name, **result)
|
||||||
else:
|
else:
|
||||||
|
|||||||
781
poetry.lock
generated
781
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -27,11 +27,11 @@ classifiers = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
bullet = "^2.2.0"
|
|
||||||
cookiecutter = "^1.7.2"
|
cookiecutter = "^1.7.2"
|
||||||
pydantic = { extras = ["email"], version = "^1.7.2" }
|
pydantic = { extras = ["email"], version = "^1.7.2" }
|
||||||
python = "^3.6.1"
|
python = "^3.6.1"
|
||||||
typer = "^0.3.2"
|
typer = "^0.4.0"
|
||||||
|
questionary = "^1.10.0"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
autoflake = "^1.4"
|
autoflake = "^1.4"
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import shutil
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def project_name():
|
|
||||||
name = "potato"
|
|
||||||
yield name
|
|
||||||
try:
|
|
||||||
shutil.rmtree(name)
|
|
||||||
except FileNotFoundError:
|
|
||||||
...
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typer.testing import CliRunner
|
from typer.testing import CliRunner
|
||||||
|
|
||||||
from manage_fastapi.main import app
|
from manage_fastapi.main import app
|
||||||
@@ -8,7 +10,8 @@ CREATED_SUCCESSFULLY = "FastAPI app created successfully! 🎉\n"
|
|||||||
ALREADY_EXISTS = "Folder 'potato' already exists. 😞\n"
|
ALREADY_EXISTS = "Folder 'potato' already exists. 😞\n"
|
||||||
|
|
||||||
|
|
||||||
def test_startproject_default(project_name: str):
|
def test_startproject_default(tmp_path: Path):
|
||||||
result = runner.invoke(app, ["startapp", project_name])
|
with runner.isolated_filesystem(temp_dir=tmp_path):
|
||||||
assert result.output == CREATED_SUCCESSFULLY
|
result = runner.invoke(app, ["startapp", "potato"])
|
||||||
assert result.exit_code == 0
|
assert result.output == CREATED_SUCCESSFULLY
|
||||||
|
assert result.exit_code == 0
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
from unittest.mock import patch
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
|
||||||
from typer.testing import CliRunner
|
from typer.testing import CliRunner
|
||||||
|
|
||||||
from manage_fastapi.main import app
|
from manage_fastapi.main import app
|
||||||
@@ -11,52 +10,19 @@ CREATED_SUCCESSFULLY = "FastAPI project created successfully! 🎉\n"
|
|||||||
ALREADY_EXISTS = "Folder 'potato' already exists. 😞\n"
|
ALREADY_EXISTS = "Folder 'potato' already exists. 😞\n"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("packaging", ["pip", "poetry"])
|
def test_startproject_default(tmp_path: Path):
|
||||||
@pytest.mark.parametrize("python", ["3.6", "3.7", "3.8"])
|
with runner.isolated_filesystem(temp_dir=tmp_path):
|
||||||
@pytest.mark.parametrize("license_", ["MIT", "BSD", "GNU", "Apache"])
|
result = runner.invoke(app, ["startproject", "potato"])
|
||||||
@pytest.mark.parametrize("pre_commit", [True, False])
|
|
||||||
@pytest.mark.parametrize("docker", [True, False])
|
|
||||||
@pytest.mark.parametrize("database", ["Postgres", "MySQL"])
|
|
||||||
def test_startproject(
|
|
||||||
project_name: str,
|
|
||||||
packaging: str,
|
|
||||||
python: str,
|
|
||||||
license_: str,
|
|
||||||
pre_commit: bool,
|
|
||||||
docker: bool,
|
|
||||||
database: str,
|
|
||||||
):
|
|
||||||
package = "manage_fastapi.main.launch_cli"
|
|
||||||
with patch(package) as mock_obj:
|
|
||||||
|
|
||||||
def side_effect(*args):
|
|
||||||
return {
|
|
||||||
"packaging": packaging,
|
|
||||||
"python": python,
|
|
||||||
"license": license_,
|
|
||||||
"pre_commit": pre_commit,
|
|
||||||
"docker": docker,
|
|
||||||
"database": database,
|
|
||||||
}
|
|
||||||
|
|
||||||
mock_obj.side_effect = side_effect
|
|
||||||
result = runner.invoke(app, ["startproject", project_name, "--interactive"])
|
|
||||||
assert mock_obj.assert_called_once
|
|
||||||
assert result.output == CREATED_SUCCESSFULLY
|
assert result.output == CREATED_SUCCESSFULLY
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
|
|
||||||
|
|
||||||
def test_startproject_default(project_name: str):
|
def test_startproject_already_exists(tmp_path: Path):
|
||||||
result = runner.invoke(app, ["startproject", project_name])
|
with runner.isolated_filesystem(temp_dir=tmp_path):
|
||||||
assert result.output == CREATED_SUCCESSFULLY
|
result = runner.invoke(app, ["startproject", "potato"])
|
||||||
assert result.exit_code == 0
|
assert result.output == CREATED_SUCCESSFULLY
|
||||||
|
assert result.exit_code == 0
|
||||||
|
|
||||||
|
result = runner.invoke(app, ["startproject", "potato"])
|
||||||
def test_startproject_already_exists(project_name: str):
|
assert result.output == ALREADY_EXISTS
|
||||||
result = runner.invoke(app, ["startproject", project_name])
|
assert result.exit_code == 0
|
||||||
assert result.output == CREATED_SUCCESSFULLY
|
|
||||||
assert result.exit_code == 0
|
|
||||||
|
|
||||||
result = runner.invoke(app, ["startproject", project_name])
|
|
||||||
assert result.output == ALREADY_EXISTS
|
|
||||||
assert result.exit_code == 0
|
|
||||||
|
|||||||
Reference in New Issue
Block a user