djangx 1.5.5__tar.gz → 1.5.7__tar.gz
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.
- {djangx-1.5.5 → djangx-1.5.7}/PKG-INFO +2 -1
- {djangx-1.5.5 → djangx-1.5.7}/pyproject.toml +2 -1
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/__init__.py +14 -6
- djangx-1.5.7/src/djangx/api/enums.py +8 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/settings/databases.py +9 -8
- djangx-1.5.7/src/djangx/enums.py +2 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/cli.py +14 -1
- djangx-1.5.5/src/djangx/management/commands/generators/file.py → djangx-1.5.7/src/djangx/management/commands/generate.py +49 -6
- djangx-1.5.7/src/djangx/management/commands/startproject.py +1020 -0
- djangx-1.5.7/src/djangx/management/enums.py +63 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/settings/apps.py +41 -83
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/urls.py +5 -1
- djangx-1.5.5/src/djangx/management/commands/generate.py +0 -61
- djangx-1.5.5/src/djangx/management/commands/generators/__init__.py +0 -1
- djangx-1.5.5/src/djangx/management/commands/startproject.py +0 -573
- {djangx-1.5.5 → djangx-1.5.7}/LICENSE +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/README.md +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/__init__.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/backends/__init__.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/backends/auth.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/backends/server/__init__.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/backends/server/asgi.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/backends/server/wsgi.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/backends/storages.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/settings/__init__.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/settings/auth.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/settings/server.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/settings/storages.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/types/__init__.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/types/auth.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/types/databases.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/types/storages.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/urls.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/__init__.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/__init__.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/collectstatic.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/helpers/__init__.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/helpers/art.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/helpers/run.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/runbuild.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/runinstall.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/runserver.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/tailwind.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/settings/__init__.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/settings/runcommands.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/settings/security.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/settings/tailwind.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/types/__init__.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/types/apps.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/py.typed +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/settings.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/types.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/__init__.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/admin.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/settings/__init__.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/settings/contactinfo.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/settings/org.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/settings/social.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/css/.gitignore +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/css/aos.css +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/css/bootstrap-icons.min.css +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/css/fonts/bootstrap-icons.woff +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/css/fonts/bootstrap-icons.woff2 +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/img/apple-touch-icon.png +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/img/favicon.ico +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/img/logo.png +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/js/aos-init.js +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/js/aos.js +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/js/preloader.js +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/js/scroll-top.js +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templates/ui/footer.html +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templates/ui/header.html +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templates/ui/hero.html +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templates/ui/index.html +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templates/ui/preloader.html +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templates/ui/scroll-top.html +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templatetags/__init__.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templatetags/contactinfo.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templatetags/org.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templatetags/social.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templatetags/tailwind_css.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/types/__init__.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/types/contactinfo.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/types/org.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/types/social.py +0 -0
- {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/urls.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: djangx
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.7
|
|
4
4
|
Summary: Build and deploy Django apps with confidence.
|
|
5
5
|
Author: Kevin Wasike Wakhisi
|
|
6
6
|
Author-email: Kevin Wasike Wakhisi <kevin@christianwhocodes.space>
|
|
@@ -34,6 +34,7 @@ Requires-Dist: django-phonenumber-field[phonenumberslite]>=8.4.0
|
|
|
34
34
|
Requires-Dist: django-watchfiles>=1.4.0
|
|
35
35
|
Requires-Dist: pyperclip>=1.11.0
|
|
36
36
|
Requires-Dist: python-dotenv>=1.2.1
|
|
37
|
+
Requires-Dist: rich>=14.3.2
|
|
37
38
|
Requires-Python: >=3.12
|
|
38
39
|
Project-URL: homepage, https://github.com/christianwhocodes/djangx#readme
|
|
39
40
|
Project-URL: repository, https://github.com/christianwhocodes/djangx
|
|
@@ -13,7 +13,7 @@ djx = "djangx.management.cli:main"
|
|
|
13
13
|
|
|
14
14
|
[project]
|
|
15
15
|
name = "djangx"
|
|
16
|
-
version = "1.5.
|
|
16
|
+
version = "1.5.7"
|
|
17
17
|
description = "Build and deploy Django apps with confidence."
|
|
18
18
|
readme = "README.md"
|
|
19
19
|
license = { file = "LICENSE" }
|
|
@@ -31,6 +31,7 @@ dependencies = [
|
|
|
31
31
|
"django-watchfiles>=1.4.0",
|
|
32
32
|
"pyperclip>=1.11.0",
|
|
33
33
|
"python-dotenv>=1.2.1",
|
|
34
|
+
"rich>=14.3.2",
|
|
34
35
|
]
|
|
35
36
|
|
|
36
37
|
[dependency-groups]
|
|
@@ -43,6 +43,10 @@ PROJECT_INIT_NAME: str = PROJECT_DIR.name
|
|
|
43
43
|
|
|
44
44
|
PROJECT_MAIN_APP_NAME: str = "home"
|
|
45
45
|
|
|
46
|
+
# bools
|
|
47
|
+
|
|
48
|
+
INCLUDE_PROJECT_MAIN_APP: bool = PROJECT_MAIN_APP_DIR.exists() and PROJECT_MAIN_APP_DIR.is_dir()
|
|
49
|
+
|
|
46
50
|
# Settings configuration classes
|
|
47
51
|
|
|
48
52
|
_ValueType: TypeAlias = Optional[str | bool | list[str] | pathlib.Path | int]
|
|
@@ -206,14 +210,18 @@ class Conf:
|
|
|
206
210
|
|
|
207
211
|
except (FileNotFoundError, KeyError, ValueError) as e:
|
|
208
212
|
cls._validated = False
|
|
213
|
+
print(f"Not in a valid {PKG_DISPLAY_NAME} project directory.", Text.ERROR)
|
|
209
214
|
print(
|
|
210
|
-
f"
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
215
|
+
f"A valid project requires: pyproject.toml with a 'tool.{PKG_NAME}' section (even if empty)",
|
|
216
|
+
Text.INFO,
|
|
217
|
+
)
|
|
218
|
+
print(
|
|
219
|
+
[
|
|
220
|
+
("Create a new project: ", None),
|
|
221
|
+
(f"uvx {PKG_NAME} startproject (if uv is installed.)", Text.HIGHLIGHT),
|
|
222
|
+
]
|
|
216
223
|
)
|
|
224
|
+
print(f"Validation error: {e}")
|
|
217
225
|
|
|
218
226
|
except Exception as e:
|
|
219
227
|
cls._validated = False
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
# https://www.postgresql.org/docs/current/libpq-pgpass.html
|
|
6
6
|
# ==============================================================================
|
|
7
7
|
from ... import PROJECT_DIR, Conf, ConfField
|
|
8
|
+
from ..enums import DatabaseBackend
|
|
8
9
|
from ..types import DatabaseDict, DatabaseOptionsDict, DatabasesDict
|
|
9
10
|
|
|
10
11
|
|
|
@@ -13,10 +14,10 @@ class DatabaseConf(Conf):
|
|
|
13
14
|
|
|
14
15
|
backend = ConfField(
|
|
15
16
|
type=str,
|
|
16
|
-
choices=[
|
|
17
|
+
choices=[DatabaseBackend.SQLITE3, DatabaseBackend.POSTGRESQL],
|
|
17
18
|
env="DB_BACKEND",
|
|
18
19
|
toml="db.backend",
|
|
19
|
-
default=
|
|
20
|
+
default=DatabaseBackend.SQLITE3,
|
|
20
21
|
)
|
|
21
22
|
# postgresql specific
|
|
22
23
|
use_vars = ConfField(
|
|
@@ -79,14 +80,14 @@ def _get_databases_config() -> DatabasesDict:
|
|
|
79
80
|
backend: str = _DATABASE.backend.lower()
|
|
80
81
|
|
|
81
82
|
match backend:
|
|
82
|
-
case
|
|
83
|
+
case DatabaseBackend.SQLITE3:
|
|
83
84
|
return {
|
|
84
85
|
"default": {
|
|
85
|
-
"ENGINE": "django.db.backends.
|
|
86
|
-
"NAME": PROJECT_DIR / "db.
|
|
86
|
+
"ENGINE": f"django.db.backends.{DatabaseBackend.SQLITE3.value}",
|
|
87
|
+
"NAME": PROJECT_DIR / f"db.{DatabaseBackend.SQLITE3.value}",
|
|
87
88
|
}
|
|
88
89
|
}
|
|
89
|
-
case
|
|
90
|
+
case DatabaseBackend.POSTGRESQL:
|
|
90
91
|
options: DatabaseOptionsDict = {
|
|
91
92
|
"pool": _DATABASE.pool,
|
|
92
93
|
"sslmode": _DATABASE.ssl_mode,
|
|
@@ -95,7 +96,7 @@ def _get_databases_config() -> DatabasesDict:
|
|
|
95
96
|
# Add service or connection vars
|
|
96
97
|
if _DATABASE.use_vars:
|
|
97
98
|
config: DatabaseDict = {
|
|
98
|
-
"ENGINE": "django.db.backends.
|
|
99
|
+
"ENGINE": f"django.db.backends.{DatabaseBackend.POSTGRESQL.value}",
|
|
99
100
|
"NAME": _DATABASE.name,
|
|
100
101
|
"USER": _DATABASE.user,
|
|
101
102
|
"PASSWORD": _DATABASE.password,
|
|
@@ -106,7 +107,7 @@ def _get_databases_config() -> DatabasesDict:
|
|
|
106
107
|
else:
|
|
107
108
|
options["service"] = _DATABASE.service
|
|
108
109
|
config: DatabaseDict = {
|
|
109
|
-
"ENGINE": "django.db.backends.
|
|
110
|
+
"ENGINE": f"django.db.backends.{DatabaseBackend.POSTGRESQL.value}",
|
|
110
111
|
"NAME": _DATABASE.name,
|
|
111
112
|
"OPTIONS": options,
|
|
112
113
|
}
|
|
@@ -17,6 +17,7 @@ def main() -> Optional[NoReturn]:
|
|
|
17
17
|
case "startproject" | "init" | "new":
|
|
18
18
|
from argparse import ArgumentParser, Namespace
|
|
19
19
|
|
|
20
|
+
from ..enums import DatabaseBackend
|
|
20
21
|
from .commands.startproject import initialize
|
|
21
22
|
|
|
22
23
|
parser = ArgumentParser(description=f"Initialize a new {PKG_DISPLAY_NAME} project")
|
|
@@ -25,9 +26,21 @@ def main() -> Optional[NoReturn]:
|
|
|
25
26
|
choices=["default", "vercel"],
|
|
26
27
|
help="Project preset to use (skips interactive prompt)",
|
|
27
28
|
)
|
|
29
|
+
parser.add_argument(
|
|
30
|
+
"--database",
|
|
31
|
+
"--db",
|
|
32
|
+
choices=[DatabaseBackend.SQLITE3, DatabaseBackend.POSTGRESQL],
|
|
33
|
+
help=f"Database backend to use (skips interactive prompt). Note: Vercel preset requires {DatabaseBackend.POSTGRESQL.value}.",
|
|
34
|
+
)
|
|
35
|
+
parser.add_argument(
|
|
36
|
+
"--force",
|
|
37
|
+
"-f",
|
|
38
|
+
action="store_true",
|
|
39
|
+
help="Skip directory validation and initialize even if directory is not empty",
|
|
40
|
+
)
|
|
28
41
|
args: Namespace = parser.parse_args(sys.argv[2:])
|
|
29
42
|
|
|
30
|
-
sys.exit(initialize(preset=args.preset))
|
|
43
|
+
sys.exit(initialize(preset=args.preset, database=args.database, force=args.force))
|
|
31
44
|
|
|
32
45
|
case _:
|
|
33
46
|
from os import environ
|
|
@@ -2,12 +2,19 @@ import builtins
|
|
|
2
2
|
import pathlib
|
|
3
3
|
from typing import Any, Optional, cast
|
|
4
4
|
|
|
5
|
-
from christianwhocodes.generators import
|
|
5
|
+
from christianwhocodes.generators import (
|
|
6
|
+
FileGenerator,
|
|
7
|
+
PgPassFileGenerator,
|
|
8
|
+
PgServiceFileGenerator,
|
|
9
|
+
SSHConfigFileGenerator,
|
|
10
|
+
)
|
|
11
|
+
from django.core.management.base import BaseCommand, CommandParser
|
|
6
12
|
|
|
7
|
-
from
|
|
13
|
+
from ... import PKG_DISPLAY_NAME, PKG_NAME, PROJECT_API_DIR, PROJECT_DIR, Conf
|
|
14
|
+
from ..enums import FileOption
|
|
8
15
|
|
|
9
16
|
|
|
10
|
-
class
|
|
17
|
+
class _ServerFileGenerator(FileGenerator):
|
|
11
18
|
f"""
|
|
12
19
|
Generator for ASGI / WSGI configuration in api/server.py file.
|
|
13
20
|
|
|
@@ -27,7 +34,7 @@ class ServerFileGenerator(FileGenerator):
|
|
|
27
34
|
return f"from {PKG_NAME}.api.backends.server import application\n\napp = application\n"
|
|
28
35
|
|
|
29
36
|
|
|
30
|
-
class
|
|
37
|
+
class _VercelFileGenerator(FileGenerator):
|
|
31
38
|
"""
|
|
32
39
|
Generator for Vercel configuration file (vercel.json).
|
|
33
40
|
|
|
@@ -59,7 +66,7 @@ class VercelFileGenerator(FileGenerator):
|
|
|
59
66
|
return "\n".join(lines) + "\n"
|
|
60
67
|
|
|
61
68
|
|
|
62
|
-
class
|
|
69
|
+
class _EnvFileGenerator(FileGenerator):
|
|
63
70
|
"""
|
|
64
71
|
Generator for environment configuration file (.env.example).
|
|
65
72
|
|
|
@@ -214,4 +221,40 @@ class EnvFileGenerator(FileGenerator):
|
|
|
214
221
|
return str(value)
|
|
215
222
|
|
|
216
223
|
|
|
217
|
-
|
|
224
|
+
class Command(BaseCommand):
|
|
225
|
+
help: str = "Generate configuration files (e.g., .env.example, vercel.json, asgi.py, wsgi.py, .pg_service.conf, pgpass.conf / .pgpass, ssh config)."
|
|
226
|
+
|
|
227
|
+
def add_arguments(self, parser: CommandParser) -> None:
|
|
228
|
+
parser.add_argument(
|
|
229
|
+
"-f",
|
|
230
|
+
"--file",
|
|
231
|
+
dest="file",
|
|
232
|
+
choices=[opt.value for opt in FileOption],
|
|
233
|
+
type=FileOption,
|
|
234
|
+
required=True,
|
|
235
|
+
help=f"Specify which file to generate (options: {', '.join(o.value for o in FileOption)}).",
|
|
236
|
+
)
|
|
237
|
+
parser.add_argument(
|
|
238
|
+
"-y",
|
|
239
|
+
"--force",
|
|
240
|
+
dest="force",
|
|
241
|
+
action="store_true",
|
|
242
|
+
help="Force overwrite without confirmation.",
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
def handle(self, *args: Any, **options: Any) -> None:
|
|
246
|
+
file_option: FileOption = FileOption(options["file"])
|
|
247
|
+
force: bool = options["force"]
|
|
248
|
+
|
|
249
|
+
generators: dict[FileOption, type[FileGenerator]] = {
|
|
250
|
+
FileOption.VERCEL: _VercelFileGenerator,
|
|
251
|
+
FileOption.SERVER: _ServerFileGenerator,
|
|
252
|
+
FileOption.PG_SERVICE: PgServiceFileGenerator,
|
|
253
|
+
FileOption.PGPASS: PgPassFileGenerator,
|
|
254
|
+
FileOption.SSH_CONFIG: SSHConfigFileGenerator,
|
|
255
|
+
FileOption.ENV: _EnvFileGenerator,
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
generator_class: type[FileGenerator] = generators[file_option]
|
|
259
|
+
generator = generator_class()
|
|
260
|
+
generator.create(force=force)
|