djangx 0.1.0.dev2__tar.gz → 0.1.0.dev3__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-0.1.0.dev3/PKG-INFO +26 -0
- djangx-0.1.0.dev3/README.md +1 -0
- djangx-0.1.0.dev3/pyproject.toml +92 -0
- djangx-0.1.0.dev3/pyproject.toml.orig +79 -0
- djangx-0.1.0.dev3/src/djangx/__init__.py +9 -0
- djangx-0.1.0.dev3/src/djangx/core/__init__.py +27 -0
- djangx-0.1.0.dev3/src/djangx/core/apps.py +7 -0
- djangx-0.1.0.dev3/src/djangx/core/asgi.py +22 -0
- djangx-0.1.0.dev3/src/djangx/core/management/__init__.py +81 -0
- djangx-0.1.0.dev3/src/djangx/core/management/commands/__init__.py +9 -0
- djangx-0.1.0.dev3/src/djangx/core/utils/__init__.py +4 -0
- djangx-0.1.0.dev3/src/djangx/core/utils/enum.py +16 -0
- djangx-0.1.0.dev3/src/djangx/core/utils/platform.py +79 -0
- djangx-0.1.0.dev3/src/djangx/core/utils/pyproject.py +80 -0
- djangx-0.1.0.dev3/src/djangx/core/utils/version.py +87 -0
- djangx-0.1.0.dev3/src/djangx/core/wsgi.py +22 -0
- djangx-0.1.0.dev2/PKG-INFO +0 -12
- djangx-0.1.0.dev2/pyproject.toml +0 -48
- djangx-0.1.0.dev2/pyproject.toml.orig +0 -40
- djangx-0.1.0.dev2/src/djangx/conf/urls.py +0 -0
- djangx-0.1.0.dev2/src/djangx/entrypoints/__init__.py +0 -0
- djangx-0.1.0.dev2/src/djangx/entrypoints/asgi.py +0 -0
- djangx-0.1.0.dev2/src/djangx/entrypoints/cli.py +0 -6
- djangx-0.1.0.dev2/src/djangx/entrypoints/wsgi.py +0 -0
- {djangx-0.1.0.dev2 → djangx-0.1.0.dev3}/LICENSE +0 -0
- {djangx-0.1.0.dev2/src/djangx → djangx-0.1.0.dev3/src/djangx/components}/__init__.py +0 -0
- /djangx-0.1.0.dev2/README.md → /djangx-0.1.0.dev3/src/djangx/core/management/commands/cp.py +0 -0
- /djangx-0.1.0.dev2/src/djangx/components/__init__.py → /djangx-0.1.0.dev3/src/djangx/core/management/commands/platform.py +0 -0
- /djangx-0.1.0.dev2/src/djangx/conf/__init__.py → /djangx-0.1.0.dev3/src/djangx/core/management/commands/random.py +0 -0
- /djangx-0.1.0.dev2/src/djangx/conf/settings.py → /djangx-0.1.0.dev3/src/djangx/core/management/commands/rm.py +0 -0
- {djangx-0.1.0.dev2 → djangx-0.1.0.dev3}/src/djangx/py.typed +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: djangX
|
|
3
|
+
Version: 0.1.0.dev3
|
|
4
|
+
Summary:
|
|
5
|
+
Author: Kevin Wakhisi
|
|
6
|
+
Author-email: Kevin Wakhisi <kevin@treeolive.tech>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Requires-Dist: django>=6.1.2
|
|
15
|
+
Requires-Dist: pillow>=13.0.0
|
|
16
|
+
Requires-Dist: python-dotenv>=1.2.4
|
|
17
|
+
Requires-Dist: psycopg[binary,pool]>=3.3.6 ; extra == 'postgres'
|
|
18
|
+
Requires-Dist: psycopg[binary,pool]>=3.3.6 ; extra == 'vercel'
|
|
19
|
+
Requires-Dist: vercel>=0.12.0 ; extra == 'vercel'
|
|
20
|
+
Requires-Python: >=3.14
|
|
21
|
+
Project-URL: repository, https://github.com/treeolive-tech/djangX.git
|
|
22
|
+
Provides-Extra: postgres
|
|
23
|
+
Provides-Extra: vercel
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# djangX
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# djangX
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "djangX"
|
|
3
|
+
version = "0.1.0.dev3"
|
|
4
|
+
description = ""
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
requires-python = ">=3.14"
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Development Status :: 4 - Beta",
|
|
11
|
+
"Intended Audience :: Developers",
|
|
12
|
+
"Programming Language :: Python :: 3.14",
|
|
13
|
+
"Operating System :: OS Independent",
|
|
14
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
15
|
+
]
|
|
16
|
+
dependencies = [
|
|
17
|
+
"django>=6.1.2",
|
|
18
|
+
"pillow>=13.0.0",
|
|
19
|
+
"python-dotenv>=1.2.4",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
repository = "https://github.com/treeolive-tech/djangX.git"
|
|
24
|
+
|
|
25
|
+
[[project.authors]]
|
|
26
|
+
name = "Kevin Wakhisi"
|
|
27
|
+
email = "kevin@treeolive.tech"
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
postgres = ["psycopg[binary,pool]>=3.3.6"]
|
|
31
|
+
vercel = [
|
|
32
|
+
"psycopg[binary,pool]>=3.3.6",
|
|
33
|
+
"vercel>=0.12.0",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
djangx = "djangx.core.management:main"
|
|
38
|
+
djx = "djangx.core.management:main"
|
|
39
|
+
|
|
40
|
+
[dependency-groups]
|
|
41
|
+
dev = [
|
|
42
|
+
"django-browser-reload>=1.21.0",
|
|
43
|
+
"django-http-compression[brotli]>=1.4.0",
|
|
44
|
+
"django-minify-html>=1.14.0",
|
|
45
|
+
"django-stubs>=6.1.2",
|
|
46
|
+
"djlint>=1.47.0",
|
|
47
|
+
"poethepoet>=0.49.0",
|
|
48
|
+
"psycopg[binary,pool]>=3.3.6",
|
|
49
|
+
"vercel>=0.12.0",
|
|
50
|
+
"djangorestframework>=3.18.3",
|
|
51
|
+
"django-filter>=26.2",
|
|
52
|
+
"markdown>=3.11.2",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
[build-system]
|
|
56
|
+
requires = ["uv_build>=0.13.4,<0.14.0"]
|
|
57
|
+
build-backend = "uv_build"
|
|
58
|
+
|
|
59
|
+
[tool.uv]
|
|
60
|
+
preview-features = [
|
|
61
|
+
"format-command",
|
|
62
|
+
"check-command",
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
[[tool.uv.index]]
|
|
66
|
+
name = "testpypi"
|
|
67
|
+
url = "https://test.pypi.org/simple/"
|
|
68
|
+
publish-url = "https://test.pypi.org/legacy/"
|
|
69
|
+
explicit = true
|
|
70
|
+
|
|
71
|
+
[[tool.poe.tasks.format.sequence]]
|
|
72
|
+
cmd = "uv format"
|
|
73
|
+
|
|
74
|
+
[[tool.poe.tasks.lint.sequence]]
|
|
75
|
+
cmd = "uv format --check"
|
|
76
|
+
|
|
77
|
+
[[tool.poe.tasks.lint.sequence]]
|
|
78
|
+
cmd = "uv lock --check"
|
|
79
|
+
|
|
80
|
+
[[tool.poe.tasks.lint.sequence]]
|
|
81
|
+
cmd = "uv check"
|
|
82
|
+
|
|
83
|
+
[tool.djlint]
|
|
84
|
+
format_css = true
|
|
85
|
+
format_js = true
|
|
86
|
+
custom_blocks = "body,aside,header,footer,main,section,list"
|
|
87
|
+
blank_line_before_tag = "block,list"
|
|
88
|
+
blank_line_after_tag = "endblock,endlist"
|
|
89
|
+
ignore = "H016,H030,H031"
|
|
90
|
+
|
|
91
|
+
[tool.ruff]
|
|
92
|
+
exclude = ["*/migrations/*"]
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
[project.urls]
|
|
2
|
+
repository = "https://github.com/treeolive-tech/djangX.git"
|
|
3
|
+
|
|
4
|
+
[project]
|
|
5
|
+
name = "djangX"
|
|
6
|
+
version = "0.1.0.dev3"
|
|
7
|
+
description = ""
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
license = "MIT"
|
|
10
|
+
license-files = ["LICENSE"]
|
|
11
|
+
authors = [{ name = "Kevin Wakhisi", email = "kevin@treeolive.tech" }]
|
|
12
|
+
requires-python = ">=3.14"
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"Programming Language :: Python :: 3.14",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
19
|
+
]
|
|
20
|
+
dependencies = ["django>=6.1.2", "pillow>=13.0.0", "python-dotenv>=1.2.4"]
|
|
21
|
+
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
postgres = ["psycopg[binary,pool]>=3.3.6"]
|
|
24
|
+
vercel = ["psycopg[binary,pool]>=3.3.6", "vercel>=0.12.0"]
|
|
25
|
+
|
|
26
|
+
[dependency-groups]
|
|
27
|
+
dev = [
|
|
28
|
+
"django-browser-reload>=1.21.0",
|
|
29
|
+
"django-http-compression[brotli]>=1.4.0",
|
|
30
|
+
"django-minify-html>=1.14.0",
|
|
31
|
+
"django-stubs>=6.1.2",
|
|
32
|
+
"djlint>=1.47.0",
|
|
33
|
+
"poethepoet>=0.49.0",
|
|
34
|
+
"psycopg[binary,pool]>=3.3.6",
|
|
35
|
+
"vercel>=0.12.0",
|
|
36
|
+
|
|
37
|
+
# rest framework
|
|
38
|
+
"djangorestframework>=3.18.3",
|
|
39
|
+
"django-filter>=26.2",
|
|
40
|
+
"markdown>=3.11.2",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[project.scripts]
|
|
44
|
+
djangx = "djangx.core.management:main"
|
|
45
|
+
djx = "djangx.core.management:main"
|
|
46
|
+
|
|
47
|
+
[build-system]
|
|
48
|
+
requires = ["uv_build>=0.13.4,<0.14.0"]
|
|
49
|
+
build-backend = "uv_build"
|
|
50
|
+
|
|
51
|
+
[tool.uv]
|
|
52
|
+
preview-features = ["format-command", "check-command"]
|
|
53
|
+
|
|
54
|
+
[tool.poe.tasks.format]
|
|
55
|
+
sequence = [{ cmd = "uv format" }]
|
|
56
|
+
|
|
57
|
+
[tool.poe.tasks.lint]
|
|
58
|
+
sequence = [
|
|
59
|
+
{ cmd = "uv format --check" },
|
|
60
|
+
{ cmd = "uv lock --check" },
|
|
61
|
+
{ cmd = "uv check" },
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[tool.djlint]
|
|
65
|
+
format_css = true
|
|
66
|
+
format_js = true
|
|
67
|
+
custom_blocks = "body,aside,header,footer,main,section,list"
|
|
68
|
+
blank_line_before_tag = "block,list"
|
|
69
|
+
blank_line_after_tag = "endblock,endlist"
|
|
70
|
+
ignore = "H016,H030,H031"
|
|
71
|
+
|
|
72
|
+
[tool.ruff]
|
|
73
|
+
exclude = ["*/migrations/*"]
|
|
74
|
+
|
|
75
|
+
[[tool.uv.index]]
|
|
76
|
+
name = "testpypi"
|
|
77
|
+
url = "https://test.pypi.org/simple/"
|
|
78
|
+
publish-url = "https://test.pypi.org/legacy/"
|
|
79
|
+
explicit = true
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Final
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Package:
|
|
6
|
+
name: Final[str] = Path(__file__).resolve().parent.name # djangx
|
|
7
|
+
verbose_name: Final[str] = name[:-1] + name[-1].upper() # djangX
|
|
8
|
+
core: Final[str] = f"{name}.core"
|
|
9
|
+
components: Final[str] = f"{name}.components"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from sys import argv
|
|
3
|
+
|
|
4
|
+
from .. import Package
|
|
5
|
+
from .utils import ExitCode, PyProject
|
|
6
|
+
|
|
7
|
+
DJANGO_SETTINGS_MODULE: str | None = PyProject(Path.cwd() / "pyproject.toml").settings
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def print_help_message() -> None:
|
|
11
|
+
"""Print built-in help, or an error and exit if the command is unknown."""
|
|
12
|
+
from .management.commands import HELP_COMMANDS
|
|
13
|
+
|
|
14
|
+
match argv[1]:
|
|
15
|
+
case cmd if cmd in HELP_COMMANDS:
|
|
16
|
+
print(
|
|
17
|
+
f"No pyproject.toml found (or it's missing [tool.{Package.name}] `settings` key), "
|
|
18
|
+
"so only built-in commands are shown below.\n\n"
|
|
19
|
+
"To see project-specific commands, run this from the root of a "
|
|
20
|
+
f"{Package.verbose_name} project, or add to your pyproject.toml:\n\n"
|
|
21
|
+
f" [tool.{Package.name}]\n"
|
|
22
|
+
' settings = "app.settings"'
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
case _:
|
|
26
|
+
print(f"Unknown command: '{cmd}'\nType '{Package.name} help' for usage.")
|
|
27
|
+
raise SystemExit(ExitCode.ERROR)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ASGI config.
|
|
3
|
+
|
|
4
|
+
It exposes the ASGI callable as a module-level variable named ``app``.
|
|
5
|
+
|
|
6
|
+
For more information on this file, see
|
|
7
|
+
https://docs.djangoproject.com/en/6.0/howto/deployment/asgi/
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from . import DJANGO_SETTINGS_MODULE
|
|
11
|
+
|
|
12
|
+
if DJANGO_SETTINGS_MODULE is None:
|
|
13
|
+
from . import print_help_message
|
|
14
|
+
|
|
15
|
+
print_help_message()
|
|
16
|
+
else:
|
|
17
|
+
from os import environ
|
|
18
|
+
|
|
19
|
+
from django.core.asgi import get_asgi_application
|
|
20
|
+
|
|
21
|
+
environ.setdefault("DJANGO_SETTINGS_MODULE", DJANGO_SETTINGS_MODULE)
|
|
22
|
+
application = get_asgi_application()
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Command-line entry point."""
|
|
2
|
+
|
|
3
|
+
from sys import argv
|
|
4
|
+
|
|
5
|
+
from .commands import BUILTIN_COMMANDS, HELP_COMMANDS
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _run_builtin() -> None:
|
|
9
|
+
"""Run a built-in command with a minimal Django setup and no Django core commands."""
|
|
10
|
+
from django import setup
|
|
11
|
+
from django.conf import settings
|
|
12
|
+
from django.core.management import execute_from_command_line, get_commands
|
|
13
|
+
|
|
14
|
+
from ..apps import CoreConfig
|
|
15
|
+
|
|
16
|
+
if not settings.configured:
|
|
17
|
+
settings.configure(INSTALLED_APPS=[CoreConfig.name])
|
|
18
|
+
setup()
|
|
19
|
+
|
|
20
|
+
commands = get_commands()
|
|
21
|
+
for name, app in list(commands.items()):
|
|
22
|
+
if app == "django.core":
|
|
23
|
+
del commands[name]
|
|
24
|
+
|
|
25
|
+
execute_from_command_line(argv)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _run_project_or_help(command: str) -> None:
|
|
29
|
+
"""Run a command against the project's settings, or show help if none is found."""
|
|
30
|
+
|
|
31
|
+
from .. import DJANGO_SETTINGS_MODULE, print_help_message
|
|
32
|
+
|
|
33
|
+
if DJANGO_SETTINGS_MODULE:
|
|
34
|
+
from os import environ
|
|
35
|
+
from pathlib import Path
|
|
36
|
+
from sys import path
|
|
37
|
+
|
|
38
|
+
from django.core.management import execute_from_command_line
|
|
39
|
+
from dotenv import load_dotenv
|
|
40
|
+
|
|
41
|
+
base_dir = Path.cwd()
|
|
42
|
+
path.insert(0, str(base_dir))
|
|
43
|
+
environ.setdefault("DJANGO_SETTINGS_MODULE", DJANGO_SETTINGS_MODULE)
|
|
44
|
+
dotenv = base_dir / ".env.local"
|
|
45
|
+
|
|
46
|
+
if dotenv.is_file():
|
|
47
|
+
load_dotenv(dotenv)
|
|
48
|
+
|
|
49
|
+
execute_from_command_line(argv)
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
print_help_message()
|
|
53
|
+
if command in HELP_COMMANDS:
|
|
54
|
+
_run_builtin()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def main() -> None:
|
|
58
|
+
"""Dispatch the CLI command."""
|
|
59
|
+
command: str | None = argv[1] if len(argv) > 1 else None
|
|
60
|
+
|
|
61
|
+
match command:
|
|
62
|
+
case None:
|
|
63
|
+
print(
|
|
64
|
+
"...but the people who know their God shall be strong and do exploits. — Daniel 11:32"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
case "-v" | "--version" | "version":
|
|
68
|
+
from ... import Package
|
|
69
|
+
from ..utils import print_version
|
|
70
|
+
|
|
71
|
+
raise SystemExit(print_version(Package.name))
|
|
72
|
+
|
|
73
|
+
case _ if command in BUILTIN_COMMANDS:
|
|
74
|
+
_run_builtin()
|
|
75
|
+
|
|
76
|
+
case _:
|
|
77
|
+
_run_project_or_help(command)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__":
|
|
81
|
+
main()
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from enum import IntEnum
|
|
2
|
+
|
|
3
|
+
__all__: list[str] = ["ExitCode"]
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ExitCode(IntEnum):
|
|
7
|
+
"""Standard process exit codes following Unix conventions.
|
|
8
|
+
|
|
9
|
+
Examples::
|
|
10
|
+
|
|
11
|
+
raise SystemExit(ExitCode.ERROR) # exits with code 1
|
|
12
|
+
raise SystemExit(ExitCode.SUCCESS) # exits with code 0
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
SUCCESS = 0 # Command completed without errors.
|
|
16
|
+
ERROR = 1 # Command encountered an error.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Platform and architecture detection utilities."""
|
|
2
|
+
|
|
3
|
+
from platform import machine, system
|
|
4
|
+
from typing import Final
|
|
5
|
+
|
|
6
|
+
__all__: list[str] = ["Platform"]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Platform:
|
|
10
|
+
"""Detect the current OS and CPU architecture as normalised codes.
|
|
11
|
+
|
|
12
|
+
Raises:
|
|
13
|
+
OSError: If the OS is unsupported.
|
|
14
|
+
ValueError: If the CPU architecture is unsupported.
|
|
15
|
+
|
|
16
|
+
Examples::
|
|
17
|
+
|
|
18
|
+
p = Platform()
|
|
19
|
+
str(p) # "macos-arm64"
|
|
20
|
+
p.os_name # "macos"
|
|
21
|
+
p.architecture # "arm64"
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
_PLATFORM_MAP: Final[dict[str, str]] = {
|
|
25
|
+
"darwin": "macos",
|
|
26
|
+
"linux": "linux",
|
|
27
|
+
"windows": "windows",
|
|
28
|
+
"android": "android",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
_ARCH_MAP: Final[dict[str, str]] = {
|
|
32
|
+
"x86_64": "x64",
|
|
33
|
+
"amd64": "x64",
|
|
34
|
+
"x64": "x64",
|
|
35
|
+
"arm64": "arm64",
|
|
36
|
+
"aarch64": "arm64",
|
|
37
|
+
"armv8": "arm64",
|
|
38
|
+
"armv7l": "arm",
|
|
39
|
+
"armv7": "arm",
|
|
40
|
+
"armv6l": "arm",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
def __init__(self) -> None:
|
|
44
|
+
"""Detect the current OS and architecture and store them on the instance."""
|
|
45
|
+
self.os_name: str = self._detect_os()
|
|
46
|
+
self.architecture: str = self._detect_architecture()
|
|
47
|
+
|
|
48
|
+
def _detect_os(self) -> str:
|
|
49
|
+
"""Normalise :func:`platform.system`, e.g. ``"Darwin"`` -> ``"macos"``."""
|
|
50
|
+
system_platform: str = system().lower()
|
|
51
|
+
platform_name: str | None = self._PLATFORM_MAP.get(system_platform)
|
|
52
|
+
if not platform_name:
|
|
53
|
+
supported: str = ", ".join(dict.fromkeys(self._PLATFORM_MAP.values()))
|
|
54
|
+
raise OSError(
|
|
55
|
+
f"Unsupported operating system: {system_platform}. Supported: {supported}"
|
|
56
|
+
)
|
|
57
|
+
return platform_name
|
|
58
|
+
|
|
59
|
+
def _detect_architecture(self) -> str:
|
|
60
|
+
"""Normalise :func:`platform.machine`, e.g. ``"aarch64"`` -> ``"arm64"``."""
|
|
61
|
+
machine_platform: str = machine().lower()
|
|
62
|
+
architecture: str | None = self._ARCH_MAP.get(machine_platform)
|
|
63
|
+
if not architecture:
|
|
64
|
+
supported: str = ", ".join(dict.fromkeys(self._ARCH_MAP.values()))
|
|
65
|
+
raise ValueError(
|
|
66
|
+
f"Unsupported architecture: {machine_platform}. Supported: {supported}"
|
|
67
|
+
)
|
|
68
|
+
return architecture
|
|
69
|
+
|
|
70
|
+
def __str__(self) -> str:
|
|
71
|
+
"""Return ``"<os_name>-<architecture>"``.
|
|
72
|
+
|
|
73
|
+
Examples::
|
|
74
|
+
|
|
75
|
+
str(Platform()) # "linux-x64"
|
|
76
|
+
f"{Platform()}" # "macos-arm64"
|
|
77
|
+
print(Platform()) # windows-x64
|
|
78
|
+
"""
|
|
79
|
+
return f"{self.os_name}-{self.architecture}"
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Read ``pyproject.toml`` data and the project's settings module."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from ... import Package
|
|
7
|
+
|
|
8
|
+
__all__: list[str] = ["PyProject"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PyProject:
|
|
12
|
+
"""Read-only view of a parsed ``pyproject.toml`` file.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
toml_path: Path to the ``pyproject.toml`` file.
|
|
16
|
+
|
|
17
|
+
Raises:
|
|
18
|
+
FileNotFoundError: If *toml_path* does not exist.
|
|
19
|
+
tomllib.TOMLDecodeError: If the file contains invalid TOML.
|
|
20
|
+
|
|
21
|
+
Examples::
|
|
22
|
+
|
|
23
|
+
p = PyProject(Path("pyproject.toml"))
|
|
24
|
+
p.name # "my-project"
|
|
25
|
+
p.version # "0.1.0"
|
|
26
|
+
p.data # the full parsed dict
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, toml_path: Path) -> None:
|
|
30
|
+
"""Parse *toml_path* and store the result."""
|
|
31
|
+
from tomllib import load
|
|
32
|
+
|
|
33
|
+
self.path: Path = toml_path
|
|
34
|
+
|
|
35
|
+
with open(file=self.path, mode="rb") as f:
|
|
36
|
+
self._data: dict[str, Any] = load(f)
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def name(self) -> str:
|
|
40
|
+
"""The ``[project] name`` value.
|
|
41
|
+
|
|
42
|
+
Raises:
|
|
43
|
+
KeyError: If ``[project]`` or ``name`` is missing.
|
|
44
|
+
"""
|
|
45
|
+
return self._data["project"]["name"]
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def version(self) -> str:
|
|
49
|
+
"""The ``[project] version`` value.
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
KeyError: If ``[project]`` or ``version`` is missing.
|
|
53
|
+
"""
|
|
54
|
+
return self._data["project"]["version"]
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def description(self) -> str | None:
|
|
58
|
+
"""The ``[project] description`` value, or ``None`` if not set."""
|
|
59
|
+
return self._data["project"].get("description")
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def settings(self) -> str | None:
|
|
63
|
+
"""The ``[tool.<package>] settings`` value, or ``None`` if missing or blank.
|
|
64
|
+
|
|
65
|
+
Examples::
|
|
66
|
+
|
|
67
|
+
# [tool.djangx]
|
|
68
|
+
# settings = "app.settings"
|
|
69
|
+
p.settings # "app.settings"
|
|
70
|
+
"""
|
|
71
|
+
try:
|
|
72
|
+
value: Any = self._data["tool"][Package.name]["settings"]
|
|
73
|
+
return value if isinstance(value, str) and value.strip() else None
|
|
74
|
+
except KeyError:
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def data(self) -> dict[str, Any]:
|
|
79
|
+
"""The full parsed TOML as a dict."""
|
|
80
|
+
return self._data
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""Version lookup utilities."""
|
|
2
|
+
|
|
3
|
+
from typing import Literal, NamedTuple, final
|
|
4
|
+
|
|
5
|
+
from .enum import ExitCode
|
|
6
|
+
|
|
7
|
+
__all__: list[str] = ["Version", "VersionResult", "print_version"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class VersionResult(NamedTuple):
|
|
11
|
+
"""A version string paired with an error message (empty on success).
|
|
12
|
+
|
|
13
|
+
Examples::
|
|
14
|
+
|
|
15
|
+
output, error = Version.get("django")
|
|
16
|
+
Version.get("django").output
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
output: str
|
|
20
|
+
error: str
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@final
|
|
24
|
+
class Version:
|
|
25
|
+
"""Namespace for looking up installed package versions.
|
|
26
|
+
|
|
27
|
+
Examples::
|
|
28
|
+
|
|
29
|
+
Version.get("django").output # "5.1.0"
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
__slots__ = ()
|
|
33
|
+
|
|
34
|
+
def __new__(cls):
|
|
35
|
+
raise TypeError(f"{cls.__name__} cannot be instantiated.")
|
|
36
|
+
|
|
37
|
+
@staticmethod
|
|
38
|
+
def placeholder() -> Literal["X.Y.Z"]:
|
|
39
|
+
"""Return the placeholder used when a version cannot be found.
|
|
40
|
+
|
|
41
|
+
Examples::
|
|
42
|
+
|
|
43
|
+
Version.placeholder() # "X.Y.Z"
|
|
44
|
+
"""
|
|
45
|
+
return "X.Y.Z"
|
|
46
|
+
|
|
47
|
+
@staticmethod
|
|
48
|
+
def get(package: str) -> VersionResult:
|
|
49
|
+
"""Return the installed version of *package*, or a placeholder on failure.
|
|
50
|
+
|
|
51
|
+
Examples::
|
|
52
|
+
|
|
53
|
+
Version.get("django") # VersionResult("5.1.0", "")
|
|
54
|
+
Version.get("not-installed-pkg") # VersionResult("X.Y.Z", "Package ... not installed ...")
|
|
55
|
+
"""
|
|
56
|
+
try:
|
|
57
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
58
|
+
|
|
59
|
+
return VersionResult(version(distribution_name=package), error="")
|
|
60
|
+
except PackageNotFoundError:
|
|
61
|
+
return VersionResult(
|
|
62
|
+
output=Version.placeholder(),
|
|
63
|
+
error=f"Package '{package}' is not installed or could not be found.",
|
|
64
|
+
)
|
|
65
|
+
except Exception as e: # noqa: BLE001 - must always return a VersionResult
|
|
66
|
+
return VersionResult(
|
|
67
|
+
output=Version.placeholder(),
|
|
68
|
+
error=f"Could not determine version for '{package}': {type(e).__name__}: {e}",
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def print_version(package: str) -> ExitCode:
|
|
73
|
+
"""Print the installed version of *package* and return an exit code.
|
|
74
|
+
|
|
75
|
+
Examples::
|
|
76
|
+
|
|
77
|
+
print_version("django") # prints "5.1.0", returns ExitCode.SUCCESS
|
|
78
|
+
print_version("nope") # prints an error, returns ExitCode.ERROR
|
|
79
|
+
"""
|
|
80
|
+
result: VersionResult = Version.get(package)
|
|
81
|
+
|
|
82
|
+
if result.error:
|
|
83
|
+
print(f"Could not determine version for package '{package}'.\n{result.error}")
|
|
84
|
+
return ExitCode.ERROR
|
|
85
|
+
else:
|
|
86
|
+
print(result.output)
|
|
87
|
+
return ExitCode.SUCCESS
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
WSGI config.
|
|
3
|
+
|
|
4
|
+
It exposes the WSGI callable as a module-level variable named ``app``.
|
|
5
|
+
|
|
6
|
+
For more information on this file, see
|
|
7
|
+
https://docs.djangoproject.com/en/6.0/howto/deployment/wsgi/
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from . import DJANGO_SETTINGS_MODULE
|
|
11
|
+
|
|
12
|
+
if DJANGO_SETTINGS_MODULE is None:
|
|
13
|
+
from . import print_help_message
|
|
14
|
+
|
|
15
|
+
print_help_message()
|
|
16
|
+
else:
|
|
17
|
+
from os import environ
|
|
18
|
+
|
|
19
|
+
from django.core.wsgi import get_wsgi_application
|
|
20
|
+
|
|
21
|
+
environ.setdefault("DJANGO_SETTINGS_MODULE", DJANGO_SETTINGS_MODULE)
|
|
22
|
+
application = get_wsgi_application()
|
djangx-0.1.0.dev2/PKG-INFO
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: djangX
|
|
3
|
-
Version: 0.1.0.dev2
|
|
4
|
-
Summary: Add your description here
|
|
5
|
-
Author: Kevin Wakhisi
|
|
6
|
-
Author-email: Kevin Wakhisi <kevin@treeolive.tech>
|
|
7
|
-
License-Expression: MIT
|
|
8
|
-
License-File: LICENSE
|
|
9
|
-
Requires-Dist: django>=6.1.2
|
|
10
|
-
Requires-Python: >=3.14
|
|
11
|
-
Description-Content-Type: text/markdown
|
|
12
|
-
|
djangx-0.1.0.dev2/pyproject.toml
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
[project]
|
|
2
|
-
name = "djangX"
|
|
3
|
-
version = "0.1.0.dev2"
|
|
4
|
-
description = "Add your description here"
|
|
5
|
-
readme = "README.md"
|
|
6
|
-
license = "MIT"
|
|
7
|
-
license-files = ["LICENSE"]
|
|
8
|
-
requires-python = ">=3.14"
|
|
9
|
-
dependencies = ["django>=6.1.2"]
|
|
10
|
-
|
|
11
|
-
[[project.authors]]
|
|
12
|
-
name = "Kevin Wakhisi"
|
|
13
|
-
email = "kevin@treeolive.tech"
|
|
14
|
-
|
|
15
|
-
[project.scripts]
|
|
16
|
-
djangx = "djangx.entrypoints.cli:main"
|
|
17
|
-
djx = "djangx.entrypoints.cli:main"
|
|
18
|
-
|
|
19
|
-
[build-system]
|
|
20
|
-
requires = ["uv_build>=0.13.4,<0.14.0"]
|
|
21
|
-
build-backend = "uv_build"
|
|
22
|
-
|
|
23
|
-
[dependency-groups]
|
|
24
|
-
dev = ["poethepoet>=0.49.0"]
|
|
25
|
-
|
|
26
|
-
[tool.uv]
|
|
27
|
-
preview-features = [
|
|
28
|
-
"format-command",
|
|
29
|
-
"check-command",
|
|
30
|
-
]
|
|
31
|
-
|
|
32
|
-
[[tool.uv.index]]
|
|
33
|
-
name = "testpypi"
|
|
34
|
-
url = "https://test.pypi.org/simple/"
|
|
35
|
-
publish-url = "https://test.pypi.org/legacy/"
|
|
36
|
-
explicit = true
|
|
37
|
-
|
|
38
|
-
[[tool.poe.tasks.format.sequence]]
|
|
39
|
-
cmd = "uv format"
|
|
40
|
-
|
|
41
|
-
[[tool.poe.tasks.lint.sequence]]
|
|
42
|
-
cmd = "uv format --check"
|
|
43
|
-
|
|
44
|
-
[[tool.poe.tasks.lint.sequence]]
|
|
45
|
-
cmd = "uv lock --check"
|
|
46
|
-
|
|
47
|
-
[[tool.poe.tasks.lint.sequence]]
|
|
48
|
-
cmd = "uv check"
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
[project]
|
|
2
|
-
name = "djangX"
|
|
3
|
-
version = "0.1.0.dev2"
|
|
4
|
-
description = "Add your description here"
|
|
5
|
-
readme = "README.md"
|
|
6
|
-
license = "MIT"
|
|
7
|
-
license-files = ["LICENSE"]
|
|
8
|
-
authors = [{ name = "Kevin Wakhisi", email = "kevin@treeolive.tech" }]
|
|
9
|
-
requires-python = ">=3.14"
|
|
10
|
-
dependencies = ["django>=6.1.2"]
|
|
11
|
-
|
|
12
|
-
[project.scripts]
|
|
13
|
-
djangx = "djangx.entrypoints.cli:main"
|
|
14
|
-
djx = "djangx.entrypoints.cli:main"
|
|
15
|
-
|
|
16
|
-
[build-system]
|
|
17
|
-
requires = ["uv_build>=0.13.4,<0.14.0"]
|
|
18
|
-
build-backend = "uv_build"
|
|
19
|
-
|
|
20
|
-
[dependency-groups]
|
|
21
|
-
dev = ["poethepoet>=0.49.0"]
|
|
22
|
-
|
|
23
|
-
[tool.uv]
|
|
24
|
-
preview-features = ["format-command", "check-command"]
|
|
25
|
-
|
|
26
|
-
[tool.poe.tasks.format]
|
|
27
|
-
sequence = [{ cmd = "uv format" }]
|
|
28
|
-
|
|
29
|
-
[tool.poe.tasks.lint]
|
|
30
|
-
sequence = [
|
|
31
|
-
{ cmd = "uv format --check" },
|
|
32
|
-
{ cmd = "uv lock --check" },
|
|
33
|
-
{ cmd = "uv check" },
|
|
34
|
-
]
|
|
35
|
-
|
|
36
|
-
[[tool.uv.index]]
|
|
37
|
-
name = "testpypi"
|
|
38
|
-
url = "https://test.pypi.org/simple/"
|
|
39
|
-
publish-url = "https://test.pypi.org/legacy/"
|
|
40
|
-
explicit = true
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|