Skip to content

Commit 47c106e

Browse files
authored
Merge branch 'master' into dependabot/pip/mypy-1.4.1
2 parents c80634a + 74307a3 commit 47c106e

File tree

25 files changed

+328
-228
lines changed

25 files changed

+328
-228
lines changed

.github/workflows/test_full.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
runs-on: ubuntu-latest
1111
strategy:
1212
matrix:
13-
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
13+
python-version: ['3.8', '3.9', '3.10', '3.11']
1414

1515
steps:
1616
- uses: actions/checkout@v3
@@ -39,9 +39,7 @@ jobs:
3939
run: flit install --symlink
4040
- name: Black
4141
run: black --check ellar_cli tests
42-
- name: isort
43-
run: isort --check ellar_cli tests
44-
- name: Flake8
45-
run: flake8 ellar_cli tests
42+
- name: Ruff linting check
43+
run: ruff check ellar_cli tests
4644
- name: mypy
4745
run: mypy ellar_cli

Makefile

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,12 @@ install-full: ## Install dependencies
1919

2020
lint: ## Run code linters
2121
black --check ellar_cli tests
22-
isort --check ellar_cli tests
23-
autoflake --remove-unused-variables --remove-unused-variables -r ellar_cli tests
24-
flake8 ellar_cli tests
22+
ruff check ellar_cli tests
2523
mypy ellar_cli
2624

2725
fmt format: ## Run code formatters
2826
black ellar_cli tests
29-
isort ellar_cli tests
27+
ruff check --fix ellar_cli tests
3028

3129
test: ## Run tests
3230
pytest tests

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<p align="center">
2-
<a href="#" target="blank"><img src="docs/img/EllarLogoIconOnly.png" width="200" alt="Ellar Logo" /></a>
2+
<a href="#" target="blank"><img src="https://eadwincode.github.io/ellar/img/EllarLogoB.png" width="200" alt="Ellar Logo" /></a>
33
</p>
44

55
<p align="center"> Ellar CLI Tool for Scaffolding Ellar Projects and Modules and also running Ellar Commands</p>

ellar_cli/file_scaffolding.py

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import os
22
import typing as t
33
from abc import abstractmethod
4+
from pathlib import Path
45

56
from jinja2 import Environment
67

78
from ellar_cli.schema import EllarScaffoldList, EllarScaffoldSchema
89

9-
from .service import EllarCLIService
10-
1110
__all__ = ["FileTemplateScaffold"]
1211

1312

@@ -26,17 +25,20 @@ def __init__(
2625
working_project_name: str,
2726
working_directory: str,
2827
scaffold_ellar_template_root_path: str,
29-
ellar_cli_service: t.Optional[EllarCLIService] = None,
28+
specified_directory: t.Optional[str] = None,
3029
) -> None:
30+
self._specified_directory = specified_directory
3131
self._schema = schema
32-
self._working_project_name = working_project_name
33-
self._ctx = ProjectScaffoldContext(
34-
Environment(), **self.get_scaffolding_context(working_project_name)
35-
)
36-
self._working_directory = working_directory
32+
self._ctx = ProjectScaffoldContext(Environment())
3733
self._scaffold_ellar_template_root_path = scaffold_ellar_template_root_path
38-
self.ellar_cli_service = ellar_cli_service
39-
self.validate_project_name()
34+
35+
if self._specified_directory:
36+
_cwd_path = Path(self._get_working_cwd(working_directory))
37+
self._working_project_name = _cwd_path.name
38+
self._working_directory = str(_cwd_path.parent)
39+
else:
40+
self._working_directory = working_directory
41+
self._working_project_name = working_project_name
4042

4143
def get_scaffolding_context(self, working_project_name: str) -> t.Dict:
4244
return {}
@@ -61,6 +63,8 @@ def create_file(self, base_path: str, file_name: str, content: t.Any) -> None:
6163
fw.writelines(refined_content)
6264

6365
def scaffold(self) -> None:
66+
self.validate_project_name()
67+
self._ctx = self.get_templating_context()
6468
self.on_scaffold_started()
6569
for file in self._schema.files:
6670
self.create_directory(
@@ -92,9 +96,9 @@ def create_directory(
9296
if file.is_directory:
9397
new_scaffold_dir = os.path.join(working_directory, name)
9498
os.makedirs(new_scaffold_dir, exist_ok=True)
95-
for file in file.files or []:
99+
for _file in file.files:
96100
self.create_directory(
97-
file=file,
101+
file=_file,
98102
working_directory=new_scaffold_dir,
99103
scaffold_ellar_template_path=scaffold_template_path,
100104
)
@@ -108,3 +112,22 @@ def create_directory(
108112
def validate_project_name(self) -> None:
109113
# Check it's a valid directory name.
110114
pass
115+
116+
def _get_working_cwd(self, working_directory: str) -> str:
117+
if self._specified_directory:
118+
return self._handle_directory_change(working_directory)
119+
return working_directory
120+
121+
def _handle_directory_change(self, working_directory: str) -> str:
122+
if self._specified_directory == ".":
123+
return working_directory
124+
125+
_specified_directory = (
126+
self._specified_directory.lower() # type:ignore[union-attr]
127+
)
128+
return os.path.join(working_directory, _specified_directory)
129+
130+
def get_templating_context(self) -> ProjectScaffoldContext:
131+
return ProjectScaffoldContext(
132+
Environment(), **self.get_scaffolding_context(self._working_project_name)
133+
)

ellar_cli/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def build_typers() -> t.Any:
6161

6262
if meta_ and meta_.has_meta:
6363
module_configs = AppFactory.get_all_modules(
64-
ModuleSetup(meta_.import_root_module()) # type:ignore
64+
ModuleSetup(meta_.import_root_module())
6565
)
6666
reflector = Reflector()
6767

ellar_cli/manage_commands/create_module.py

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@
22
import sys
33
import typing as t
44
from importlib import import_module
5+
from pathlib import Path
56

67
import typer
78
from ellar.common.helper.module_loading import module_dir
89

910
from ellar_cli import scaffolding
10-
from ellar_cli.constants import ELLAR_META
1111
from ellar_cli.schema import EllarScaffoldSchema
1212

1313
from ..file_scaffolding import FileTemplateScaffold
14-
from ..service import EllarCLIException, EllarCLIService
14+
from ..service import EllarCLIException
1515

1616
__all__ = ["create_module"]
1717

@@ -21,6 +21,19 @@
2121

2222

2323
class ModuleTemplateScaffold(FileTemplateScaffold):
24+
def __init__(
25+
self, working_project_name: str, working_directory: str, **kwargs: t.Any
26+
) -> None:
27+
super().__init__(
28+
working_project_name=working_project_name,
29+
working_directory=working_directory,
30+
**kwargs,
31+
)
32+
if self._specified_directory:
33+
_cwd_path = Path(self._get_working_cwd(working_directory))
34+
self._working_project_name = working_project_name
35+
self._working_directory = str(_cwd_path)
36+
2437
def on_scaffold_completed(self) -> None:
2538
print(f"{self._working_project_name} module completely scaffolded")
2639

@@ -55,28 +68,26 @@ def validate_project_name(self) -> None:
5568
sys.path.remove(self._working_directory)
5669

5770
def get_scaffolding_context(self, working_project_name: str) -> t.Dict:
58-
template_context = dict(module_name=working_project_name)
71+
template_context = {"module_name": working_project_name}
5972
return template_context
6073

6174

62-
def create_module(ctx: typer.Context, module_name: str):
75+
def create_module(
76+
module_name: str,
77+
directory: t.Optional[str] = typer.Argument(
78+
None,
79+
help="The name of a new directory to scaffold the module into.",
80+
show_default=False,
81+
),
82+
):
6383
"""- Scaffolds Ellar Application Module -"""
6484

65-
ellar_project_meta = t.cast(t.Optional[EllarCLIService], ctx.meta.get(ELLAR_META))
66-
if not ellar_project_meta:
67-
raise EllarCLIException("No pyproject.toml file found.")
68-
69-
if not ellar_project_meta.has_meta:
70-
raise EllarCLIException(
71-
"No available project found. please create ellar project with `ellar create-project 'project-name'`"
72-
)
73-
7485
schema = EllarScaffoldSchema.parse_file(module_template_json)
7586
project_template_scaffold = ModuleTemplateScaffold(
7687
schema=schema,
77-
working_directory=ellar_project_meta.get_apps_module_path(),
88+
working_directory=os.getcwd(),
7889
scaffold_ellar_template_root_path=root_scaffold_template_path,
79-
ellar_cli_service=ellar_project_meta,
90+
specified_directory=directory,
8091
working_project_name=module_name.lower(),
8192
)
8293
project_template_scaffold.scaffold()

ellar_cli/manage_commands/create_project.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,15 @@
2222

2323

2424
class ProjectTemplateScaffold(FileTemplateScaffold):
25+
def __init__(self, ellar_cli_service: EllarCLIService, **kwargs: t.Any) -> None:
26+
super().__init__(**kwargs)
27+
self.ellar_cli_service = ellar_cli_service
28+
2529
def get_scaffolding_context(self, working_project_name: str) -> t.Dict:
26-
template_context = dict(
27-
project_name=working_project_name, secret_key=f"ellar_{uuid.uuid4()}"
28-
)
30+
template_context = {
31+
"project_name": working_project_name,
32+
"secret_key": f"ellar_{uuid.uuid4()}",
33+
}
2934
return template_context
3035

3136
def validate_project_name(self) -> None:

ellar_cli/manage_commands/new.py

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,21 @@ class NewTemplateScaffold(FileTemplateScaffold):
2424
unwanted_chars = "".join(["-", ";", "!", "*", ":", " "])
2525

2626
def __init__(self, project_name: str = None, **kwargs: t.Any) -> None:
27+
super(NewTemplateScaffold, self).__init__(
28+
working_project_name=project_name, **kwargs
29+
)
2730
self._project_name = project_name
28-
super(NewTemplateScaffold, self).__init__(**kwargs)
31+
32+
def create_file(self, base_path: str, file_name: str, content: t.Any) -> None:
33+
_path = os.path.join(base_path, file_name.replace(".ellar", ".py"))
34+
if os.path.exists(_path):
35+
content = self.read_file_content(path=_path)
36+
37+
with open(
38+
os.path.join(base_path, file_name.replace(".ellar", ".py")), mode="w"
39+
) as fw:
40+
refined_content = self._ctx.environment.from_string(content).render()
41+
fw.writelines(refined_content)
2942

3043
def on_scaffold_completed(self) -> None:
3144
popen_res = subprocess.run(
@@ -36,9 +49,18 @@ def on_scaffold_completed(self) -> None:
3649
)
3750
if popen_res.returncode == 0:
3851
project_working_project_name = self.get_project_name()
52+
53+
log_1 = f"- cd {self._working_project_name}"
54+
if self._specified_directory:
55+
log_1 = (
56+
f"- cd {self._specified_directory.lower()}"
57+
if self._specified_directory != "."
58+
else ""
59+
)
60+
3961
print(
40-
f"`{self._working_project_name}` project created successfully.\n"
41-
f"- cd {self._working_project_name}"
62+
f"`{project_working_project_name}` project created successfully.\n"
63+
f"{log_1}"
4264
)
4365
print("To start your server, run the command below")
4466
print(
@@ -47,13 +69,37 @@ def on_scaffold_completed(self) -> None:
4769
else:
4870
print(popen_res.stderr.decode("utf8"))
4971

72+
def is_directory_empty(self) -> bool:
73+
"""
74+
Check if the given directory is empty.
75+
"""
76+
# Get the list of files and directories in the directory
77+
working_project_dir = os.path.join(
78+
self._working_directory, self._working_project_name
79+
)
80+
if os.path.isdir(working_project_dir):
81+
items = os.listdir(working_project_dir)
82+
exclude = ["poetry.lock", "pyproject.toml"]
83+
items = [item for item in items if item not in exclude]
84+
return len(items) == 0
85+
return True
86+
5087
def validate_project_name(self) -> None:
5188
if os.path.exists(self._working_project_name):
5289
message = "A folder with same name exist '{name}' ".format(
5390
name=self._working_project_name
5491
)
5592
raise EllarCLIException(message)
5693

94+
if not self.is_directory_empty():
95+
working_project_dir = os.path.join(
96+
self._working_directory, self._working_project_name
97+
)
98+
message = (
99+
f"Scaffolding Project Directory is not empty. - {working_project_dir}"
100+
)
101+
raise EllarCLIException(message)
102+
57103
project_working_project_name = self.get_project_name()
58104
if not project_working_project_name.isidentifier():
59105
message = (
@@ -64,9 +110,10 @@ def validate_project_name(self) -> None:
64110
raise EllarCLIException(message)
65111

66112
def get_scaffolding_context(self, working_project_name: str) -> t.Dict:
67-
template_context = dict(
68-
folder_name=working_project_name, project_name=self.get_project_name()
69-
)
113+
template_context = {
114+
"folder_name": working_project_name,
115+
"project_name": self.get_project_name(),
116+
}
70117
return template_context
71118

72119
def get_project_name(self) -> str:
@@ -78,10 +125,14 @@ def get_project_cwd(self) -> str:
78125

79126

80127
def new_command(
81-
folder_name: str,
82-
project_name: t.Optional[str] = typer.Option(
128+
project_name: str = typer.Argument(
129+
None,
130+
help="Project Module Name. Defaults to `project-name` if not set",
131+
show_default=False,
132+
),
133+
directory: t.Optional[str] = typer.Argument(
83134
None,
84-
help="Project Module Name. Defaults to `folder-name` if not set",
135+
help="The name of a new directory to scaffold the project into. Scaffolding into an existing directory is only allowed if the directory is empty",
85136
show_default=False,
86137
),
87138
):
@@ -91,7 +142,7 @@ def new_command(
91142
schema=schema,
92143
working_directory=os.getcwd(),
93144
scaffold_ellar_template_root_path=root_scaffold_template_path,
94-
working_project_name=folder_name.lower(),
95145
project_name=project_name,
146+
specified_directory=directory,
96147
)
97148
init_template_scaffold.scaffold()

0 commit comments

Comments
 (0)