amsdal_cli 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- amsdal_cli/Third-Party Materials - AMSDAL Dependencies - License Notices.md +1099 -0
- amsdal_cli/__about__.py +4 -0
- amsdal_cli/__init__.py +0 -0
- amsdal_cli/app.py +8 -0
- amsdal_cli/commands/__init__.py +0 -0
- amsdal_cli/commands/build/__init__.py +0 -0
- amsdal_cli/commands/build/command.py +27 -0
- amsdal_cli/commands/build/constants.py +1 -0
- amsdal_cli/commands/build/utils/__init__.py +0 -0
- amsdal_cli/commands/build/utils/build_app.py +46 -0
- amsdal_cli/commands/build/utils/build_config_file.py +36 -0
- amsdal_cli/commands/callbacks.py +47 -0
- amsdal_cli/commands/generate/__init__.py +0 -0
- amsdal_cli/commands/generate/app.py +5 -0
- amsdal_cli/commands/generate/command.py +5 -0
- amsdal_cli/commands/generate/enums.py +52 -0
- amsdal_cli/commands/generate/sub_commands/__init__.py +13 -0
- amsdal_cli/commands/generate/sub_commands/generate_hook.py +35 -0
- amsdal_cli/commands/generate/sub_commands/generate_model.py +94 -0
- amsdal_cli/commands/generate/sub_commands/generate_modifier.py +32 -0
- amsdal_cli/commands/generate/sub_commands/generate_property.py +38 -0
- amsdal_cli/commands/generate/sub_commands/generate_transaction.py +38 -0
- amsdal_cli/commands/generate/templates/hook.pyt +3 -0
- amsdal_cli/commands/generate/templates/modifier/constructor.pyt +10 -0
- amsdal_cli/commands/generate/templates/modifier/display_name.pyt +4 -0
- amsdal_cli/commands/generate/templates/modifier/version_name.pyt +4 -0
- amsdal_cli/commands/generate/templates/property.pyt +4 -0
- amsdal_cli/commands/generate/templates/transaction.pyt +7 -0
- amsdal_cli/commands/generate/utils/__init__.py +0 -0
- amsdal_cli/commands/generate/utils/build_base_path.py +22 -0
- amsdal_cli/commands/generate/utils/cast_to_attribute_type.py +19 -0
- amsdal_cli/commands/generate/utils/model_attributes.py +131 -0
- amsdal_cli/commands/new/__init__.py +0 -0
- amsdal_cli/commands/new/command.py +54 -0
- amsdal_cli/commands/new/templates/.amsdal-cli +6 -0
- amsdal_cli/commands/new/templates/.gitignore +4 -0
- amsdal_cli/commands/new/templates/README.md +646 -0
- amsdal_cli/commands/new/templates/config.yml +19 -0
- amsdal_cli/commands/serve/__init__.py +0 -0
- amsdal_cli/commands/serve/command.py +38 -0
- amsdal_cli/commands/serve/filters/__init__.py +0 -0
- amsdal_cli/commands/serve/filters/models_watch_filter.py +6 -0
- amsdal_cli/commands/serve/filters/static_files_watch_filter.py +21 -0
- amsdal_cli/commands/serve/services/__init__.py +0 -0
- amsdal_cli/commands/serve/services/supervisor.py +373 -0
- amsdal_cli/commands/serve/utils.py +16 -0
- amsdal_cli/commands/verify/__init__.py +0 -0
- amsdal_cli/commands/verify/command.py +74 -0
- amsdal_cli/commands/verify/models.py +10 -0
- amsdal_cli/commands/verify/utils/__init__.py +0 -0
- amsdal_cli/commands/verify/utils/verify_json_model.py +31 -0
- amsdal_cli/commands/verify/utils/verify_python_file.py +21 -0
- amsdal_cli/config/__init__.py +0 -0
- amsdal_cli/config/main.py +38 -0
- amsdal_cli/main.py +7 -0
- amsdal_cli/py.typed +0 -0
- amsdal_cli/utils/__init__.py +0 -0
- amsdal_cli/utils/cli_config.py +27 -0
- amsdal_cli/utils/copier.py +103 -0
- amsdal_cli/utils/render_template.py +12 -0
- amsdal_cli-0.0.1.dist-info/METADATA +353 -0
- amsdal_cli-0.0.1.dist-info/RECORD +65 -0
- amsdal_cli-0.0.1.dist-info/WHEEL +4 -0
- amsdal_cli-0.0.1.dist-info/entry_points.txt +2 -0
- amsdal_cli-0.0.1.dist-info/licenses/LICENSE.txt +107 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
from rich import print
|
|
7
|
+
|
|
8
|
+
from amsdal_cli.commands.generate.enums import AttributeType
|
|
9
|
+
from amsdal_cli.commands.generate.enums import JsonType
|
|
10
|
+
from amsdal_cli.commands.generate.enums import OptionName
|
|
11
|
+
from amsdal_cli.commands.generate.utils.cast_to_attribute_type import cast_to_attribute_type
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Attribute(BaseModel):
|
|
15
|
+
class NotSet:
|
|
16
|
+
...
|
|
17
|
+
|
|
18
|
+
name: str
|
|
19
|
+
type: AttributeType # noqa: A003
|
|
20
|
+
reference: str | None = None
|
|
21
|
+
default: Any = NotSet
|
|
22
|
+
index: bool = False
|
|
23
|
+
required: bool = False
|
|
24
|
+
unique: bool = False
|
|
25
|
+
item_key_type: str | None = None
|
|
26
|
+
item_value_type: str | None = None
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def json_type(self) -> str | None:
|
|
30
|
+
return self.resolve_attribute_type_to_json(self.type, reference_type=self.reference)
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def has_items(self) -> bool:
|
|
34
|
+
return self.json_items is not None
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def json_items(self) -> dict[str, Any]: # type: ignore[return]
|
|
38
|
+
if self.reference and self.type == AttributeType.HAS_MANY:
|
|
39
|
+
return {'type': self.reference}
|
|
40
|
+
elif self.type == AttributeType.DICT and self.item_key_type and self.item_value_type:
|
|
41
|
+
return {
|
|
42
|
+
'key': {
|
|
43
|
+
'type': self.resolve_attribute_type_to_json(self.item_key_type, self.item_key_type),
|
|
44
|
+
},
|
|
45
|
+
'value': {
|
|
46
|
+
'type': self.resolve_attribute_type_to_json(self.item_value_type, self.item_value_type),
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def resolve_attribute_type_to_json(attribute_type: str | AttributeType, reference_type: str | None) -> str | None:
|
|
52
|
+
try:
|
|
53
|
+
match AttributeType(attribute_type):
|
|
54
|
+
case AttributeType.STRING:
|
|
55
|
+
return JsonType.STRING.value
|
|
56
|
+
case AttributeType.NUMBER:
|
|
57
|
+
return JsonType.NUMBER.value
|
|
58
|
+
case AttributeType.BOOLEAN:
|
|
59
|
+
return JsonType.BOOLEAN.value
|
|
60
|
+
case AttributeType.HAS_MANY:
|
|
61
|
+
return JsonType.ARRAY.value
|
|
62
|
+
case AttributeType.DICT:
|
|
63
|
+
return JsonType.DICT.value
|
|
64
|
+
case _:
|
|
65
|
+
return reference_type
|
|
66
|
+
except ValueError:
|
|
67
|
+
return reference_type
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def parse_attributes(attrs: list[str]) -> list[Attribute]:
|
|
71
|
+
attributes: dict[str, Attribute] = {}
|
|
72
|
+
|
|
73
|
+
for _attr_item in attrs:
|
|
74
|
+
if not _attr_item:
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
attr_item = re.sub(r'\s+', ' ', _attr_item)
|
|
78
|
+
|
|
79
|
+
for attr in attr_item.split(' '):
|
|
80
|
+
[attr_name, _attr_type, *attr_options] = attr.split(':')
|
|
81
|
+
attr_type = AttributeType(_attr_type)
|
|
82
|
+
params: dict[str, Any] = {}
|
|
83
|
+
|
|
84
|
+
if attr_name in attributes:
|
|
85
|
+
print(f'[red]The "{attr_name}" attribute is duplicated![/red]')
|
|
86
|
+
raise typer.Exit
|
|
87
|
+
|
|
88
|
+
if attr_type in (AttributeType.BELONGS_TO, AttributeType.HAS_MANY):
|
|
89
|
+
try:
|
|
90
|
+
params['reference'] = JsonType[AttributeType(attr_options[0].lower()).name].value
|
|
91
|
+
except ValueError:
|
|
92
|
+
params['reference'] = attr_options[0]
|
|
93
|
+
|
|
94
|
+
attr_options = attr_options[1:]
|
|
95
|
+
elif attr_type == AttributeType.DICT:
|
|
96
|
+
params['item_key_type'] = attr_options[0]
|
|
97
|
+
params['item_value_type'] = attr_options[1]
|
|
98
|
+
attr_options = attr_options[2:]
|
|
99
|
+
|
|
100
|
+
for attr_option in attr_options:
|
|
101
|
+
if attr_option.lower() == OptionName.INDEX.value:
|
|
102
|
+
params['index'] = True
|
|
103
|
+
continue
|
|
104
|
+
|
|
105
|
+
# property can be marked as indexed + required + unique
|
|
106
|
+
if attr_option.lower() == OptionName.REQUIRED.value:
|
|
107
|
+
params['required'] = True
|
|
108
|
+
continue
|
|
109
|
+
|
|
110
|
+
# property can be marked as indexed + required + unique
|
|
111
|
+
if attr_option.lower() == OptionName.UNIQUE.value:
|
|
112
|
+
params['unique'] = True
|
|
113
|
+
continue
|
|
114
|
+
|
|
115
|
+
if '=' in attr_option:
|
|
116
|
+
_option, value = attr_option.split('=')
|
|
117
|
+
option = OptionName(_option)
|
|
118
|
+
|
|
119
|
+
match option:
|
|
120
|
+
case OptionName.DEFAULT:
|
|
121
|
+
params['default'] = cast_to_attribute_type(attr_type, value)
|
|
122
|
+
case _:
|
|
123
|
+
print(f'[red]Unknown option "{option}"[/red]')
|
|
124
|
+
raise typer.Exit
|
|
125
|
+
|
|
126
|
+
attributes[attr_name] = Attribute(
|
|
127
|
+
name=attr_name,
|
|
128
|
+
type=attr_type,
|
|
129
|
+
**params,
|
|
130
|
+
)
|
|
131
|
+
return list(attributes.values())
|
|
File without changes
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from amsdal_utils.utils.text import slugify
|
|
5
|
+
from amsdal_utils.utils.text import to_snake_case
|
|
6
|
+
from rich import print
|
|
7
|
+
|
|
8
|
+
from amsdal_cli.app import app
|
|
9
|
+
from amsdal_cli.utils.copier import copy_blueprints_from_directory
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@app.command(name='new')
|
|
13
|
+
def new_command(
|
|
14
|
+
app_name: str = typer.Argument(
|
|
15
|
+
...,
|
|
16
|
+
help='The Application name. For example: MyApplication',
|
|
17
|
+
),
|
|
18
|
+
output_path: Path = typer.Argument( # noqa: B008
|
|
19
|
+
...,
|
|
20
|
+
help='Output path, where the app will be created.',
|
|
21
|
+
),
|
|
22
|
+
) -> None:
|
|
23
|
+
"""
|
|
24
|
+
Generates a new AMSDAL application.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
if not output_path.exists():
|
|
28
|
+
print(f'[red]The output path "{output_path.resolve()}" does not exist.[/red]')
|
|
29
|
+
raise typer.Exit
|
|
30
|
+
|
|
31
|
+
if output_path.is_file():
|
|
32
|
+
print(f'[red]The output path "{output_path.resolve()}" is not a directory.[/red]')
|
|
33
|
+
raise typer.Exit
|
|
34
|
+
|
|
35
|
+
output_path /= to_snake_case(app_name)
|
|
36
|
+
|
|
37
|
+
if output_path.exists():
|
|
38
|
+
if output_path.is_file():
|
|
39
|
+
print(f'[red]The path "{output_path.resolve()}" is not a directory.[/red]')
|
|
40
|
+
raise typer.Exit
|
|
41
|
+
|
|
42
|
+
if any(output_path.iterdir()):
|
|
43
|
+
print(f'[red]The directory "{output_path.resolve()}" is not empty.[/red]')
|
|
44
|
+
raise typer.Exit
|
|
45
|
+
|
|
46
|
+
copy_blueprints_from_directory(
|
|
47
|
+
source_path=Path(__file__).parent / 'templates',
|
|
48
|
+
destination_path=output_path,
|
|
49
|
+
context={
|
|
50
|
+
'application_name': app_name,
|
|
51
|
+
'application_name_slugify': slugify(app_name),
|
|
52
|
+
},
|
|
53
|
+
)
|
|
54
|
+
print(f'[green]The application is successfully created in {output_path.resolve()}[/green]')
|