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.
Files changed (86) hide show
  1. {djangx-1.5.5 → djangx-1.5.7}/PKG-INFO +2 -1
  2. {djangx-1.5.5 → djangx-1.5.7}/pyproject.toml +2 -1
  3. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/__init__.py +14 -6
  4. djangx-1.5.7/src/djangx/api/enums.py +8 -0
  5. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/settings/databases.py +9 -8
  6. djangx-1.5.7/src/djangx/enums.py +2 -0
  7. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/cli.py +14 -1
  8. djangx-1.5.5/src/djangx/management/commands/generators/file.py → djangx-1.5.7/src/djangx/management/commands/generate.py +49 -6
  9. djangx-1.5.7/src/djangx/management/commands/startproject.py +1020 -0
  10. djangx-1.5.7/src/djangx/management/enums.py +63 -0
  11. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/settings/apps.py +41 -83
  12. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/urls.py +5 -1
  13. djangx-1.5.5/src/djangx/management/commands/generate.py +0 -61
  14. djangx-1.5.5/src/djangx/management/commands/generators/__init__.py +0 -1
  15. djangx-1.5.5/src/djangx/management/commands/startproject.py +0 -573
  16. {djangx-1.5.5 → djangx-1.5.7}/LICENSE +0 -0
  17. {djangx-1.5.5 → djangx-1.5.7}/README.md +0 -0
  18. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/__init__.py +0 -0
  19. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/backends/__init__.py +0 -0
  20. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/backends/auth.py +0 -0
  21. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/backends/server/__init__.py +0 -0
  22. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/backends/server/asgi.py +0 -0
  23. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/backends/server/wsgi.py +0 -0
  24. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/backends/storages.py +0 -0
  25. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/settings/__init__.py +0 -0
  26. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/settings/auth.py +0 -0
  27. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/settings/server.py +0 -0
  28. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/settings/storages.py +0 -0
  29. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/types/__init__.py +0 -0
  30. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/types/auth.py +0 -0
  31. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/types/databases.py +0 -0
  32. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/types/storages.py +0 -0
  33. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/api/urls.py +0 -0
  34. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/__init__.py +0 -0
  35. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/__init__.py +0 -0
  36. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/collectstatic.py +0 -0
  37. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/helpers/__init__.py +0 -0
  38. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/helpers/art.py +0 -0
  39. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/helpers/run.py +0 -0
  40. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/runbuild.py +0 -0
  41. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/runinstall.py +0 -0
  42. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/runserver.py +0 -0
  43. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/commands/tailwind.py +0 -0
  44. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/settings/__init__.py +0 -0
  45. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/settings/runcommands.py +0 -0
  46. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/settings/security.py +0 -0
  47. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/settings/tailwind.py +0 -0
  48. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/types/__init__.py +0 -0
  49. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/management/types/apps.py +0 -0
  50. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/py.typed +0 -0
  51. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/settings.py +0 -0
  52. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/types.py +0 -0
  53. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/__init__.py +0 -0
  54. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/admin.py +0 -0
  55. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/settings/__init__.py +0 -0
  56. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/settings/contactinfo.py +0 -0
  57. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/settings/org.py +0 -0
  58. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/settings/social.py +0 -0
  59. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/css/.gitignore +0 -0
  60. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/css/aos.css +0 -0
  61. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/css/bootstrap-icons.min.css +0 -0
  62. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/css/fonts/bootstrap-icons.woff +0 -0
  63. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/css/fonts/bootstrap-icons.woff2 +0 -0
  64. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/img/apple-touch-icon.png +0 -0
  65. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/img/favicon.ico +0 -0
  66. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/img/logo.png +0 -0
  67. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/js/aos-init.js +0 -0
  68. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/js/aos.js +0 -0
  69. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/js/preloader.js +0 -0
  70. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/static/ui/js/scroll-top.js +0 -0
  71. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templates/ui/footer.html +0 -0
  72. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templates/ui/header.html +0 -0
  73. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templates/ui/hero.html +0 -0
  74. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templates/ui/index.html +0 -0
  75. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templates/ui/preloader.html +0 -0
  76. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templates/ui/scroll-top.html +0 -0
  77. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templatetags/__init__.py +0 -0
  78. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templatetags/contactinfo.py +0 -0
  79. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templatetags/org.py +0 -0
  80. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templatetags/social.py +0 -0
  81. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/templatetags/tailwind_css.py +0 -0
  82. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/types/__init__.py +0 -0
  83. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/types/contactinfo.py +0 -0
  84. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/types/org.py +0 -0
  85. {djangx-1.5.5 → djangx-1.5.7}/src/djangx/ui/types/social.py +0 -0
  86. {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.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.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"Are you currently executing in a {PKG_DISPLAY_NAME} project base directory?\n"
211
- f"If not, navigate to your project's root or create a new {PKG_DISPLAY_NAME} project to run the command.\n\n"
212
- "A valid project requires:\n"
213
- f" - `pyproject.toml` file with a 'tool.{PKG_NAME}' section (even if empty)\n"
214
- f"Validation failed: {e}",
215
- Text.WARNING,
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
@@ -0,0 +1,8 @@
1
+ from enum import StrEnum
2
+
3
+
4
+ class DatabaseBackend(StrEnum):
5
+ """Available database backends."""
6
+
7
+ SQLITE3 = "sqlite3"
8
+ POSTGRESQL = "postgresql"
@@ -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=["sqlite3", "postgresql"],
17
+ choices=[DatabaseBackend.SQLITE3, DatabaseBackend.POSTGRESQL],
17
18
  env="DB_BACKEND",
18
19
  toml="db.backend",
19
- default="sqlite3",
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 "sqlite" | "sqlite3":
83
+ case DatabaseBackend.SQLITE3:
83
84
  return {
84
85
  "default": {
85
- "ENGINE": "django.db.backends.sqlite3",
86
- "NAME": PROJECT_DIR / "db.sqlite3",
86
+ "ENGINE": f"django.db.backends.{DatabaseBackend.SQLITE3.value}",
87
+ "NAME": PROJECT_DIR / f"db.{DatabaseBackend.SQLITE3.value}",
87
88
  }
88
89
  }
89
- case "postgresql" | "postgres" | "psql" | "pgsql" | "pg" | "psycopg":
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.postgresql",
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.postgresql",
110
+ "ENGINE": f"django.db.backends.{DatabaseBackend.POSTGRESQL.value}",
110
111
  "NAME": _DATABASE.name,
111
112
  "OPTIONS": options,
112
113
  }
@@ -0,0 +1,2 @@
1
+ from .api.enums import * # noqa: F403
2
+ from .management.enums import * # noqa: F403
@@ -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 FileGenerator
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 .... import PKG_DISPLAY_NAME, PKG_NAME, PROJECT_API_DIR, PROJECT_DIR, Conf
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 ServerFileGenerator(FileGenerator):
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 VercelFileGenerator(FileGenerator):
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 EnvFileGenerator(FileGenerator):
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
- __all__: list[str] = ["EnvFileGenerator", "ServerFileGenerator", "VercelFileGenerator"]
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)