makeapp 2.2.0__tar.gz → 2.4.0__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 (103) hide show
  1. {makeapp-2.2.0 → makeapp-2.4.0}/.gitignore +1 -0
  2. makeapp-2.4.0/PKG-INFO +85 -0
  3. makeapp-2.4.0/README.md +68 -0
  4. makeapp-2.4.0/src/makeapp/__init__.py +3 -0
  5. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/__default__/.github/workflows/python-package.yml +0 -2
  6. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/__default__/.gitignore +2 -1
  7. makeapp-2.4.0/src/makeapp/app_templates/__default__/INSTALL.md +35 -0
  8. makeapp-2.4.0/src/makeapp/app_templates/__default__/README.md +33 -0
  9. makeapp-2.4.0/src/makeapp/app_templates/__default__/docs/index.md +21 -0
  10. makeapp-2.4.0/src/makeapp/app_templates/__default__/docs/quickstart.md +21 -0
  11. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/__default__/pyproject.toml +4 -0
  12. makeapp-2.4.0/src/makeapp/app_templates/__default__/tests/test_basic.py +11 -0
  13. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/makeappconf.py +10 -12
  14. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/appmaker.py +35 -10
  15. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/apptemplate.py +5 -5
  16. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/apptools.py +84 -61
  17. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/cli.py +11 -3
  18. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/helpers/dist.py +6 -6
  19. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/helpers/files.py +1 -1
  20. makeapp-2.4.0/src/makeapp/helpers/tests.py +177 -0
  21. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/helpers/vcs.py +45 -27
  22. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/utils.py +59 -28
  23. makeapp-2.2.0/PKG-INFO +0 -136
  24. makeapp-2.2.0/README.md +0 -119
  25. makeapp-2.2.0/src/makeapp/__init__.py +0 -3
  26. makeapp-2.2.0/src/makeapp/app_templates/__default__/INSTALL.md +0 -24
  27. makeapp-2.2.0/src/makeapp/app_templates/__default__/README.md +0 -22
  28. makeapp-2.2.0/src/makeapp/app_templates/__default__/docs/index.md +0 -37
  29. makeapp-2.2.0/src/makeapp/app_templates/__default__/docs/quickstart.md +0 -3
  30. makeapp-2.2.0/src/makeapp/app_templates/__default__/tests/test_basic.py +0 -11
  31. makeapp-2.2.0/src/makeapp/helpers/tests.py +0 -123
  32. {makeapp-2.2.0 → makeapp-2.4.0}/LICENSE +0 -0
  33. {makeapp-2.2.0 → makeapp-2.4.0}/pyproject.toml +0 -0
  34. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/__default__/AUTHORS.md +0 -0
  35. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/__default__/CHANGELOG.md +0 -0
  36. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/__default__/CONTRIBUTING.md +0 -0
  37. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/__default__/mkdocs.yml +0 -0
  38. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/__default__/ruff.toml +0 -0
  39. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/__default__/src/__package_name__/__init__.py +0 -0
  40. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/__default__/tests/__init__.py +0 -0
  41. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/click/makeappconf.py +0 -0
  42. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/click/pyproject.toml +0 -0
  43. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/click/src/__package_name__/cli.py +0 -0
  44. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/console/pyproject.toml +0 -0
  45. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/console/src/__package_name__/cli.py +0 -0
  46. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/.github/workflows/python-package.yml +0 -0
  47. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/makeappconf.py +0 -0
  48. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/pyproject.toml +0 -0
  49. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/src/__package_name__/__init__.py +0 -0
  50. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/src/__package_name__/admin.py +0 -0
  51. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/src/__package_name__/apps.py +0 -0
  52. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/src/__package_name__/locale/empty +0 -0
  53. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/src/__package_name__/management/__init__.py +0 -0
  54. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/src/__package_name__/management/commands/__init__.py +0 -0
  55. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/src/__package_name__/models.py +0 -0
  56. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/src/__package_name__/templates/empty +0 -0
  57. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/src/__package_name__/templatetags/empty +0 -0
  58. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/src/__package_name__/tests/__init__.py +0 -0
  59. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/src/__package_name__/tests/conftest.py +0 -0
  60. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/src/__package_name__/tests/test_basic.py +0 -0
  61. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/django/src/__package_name__/views.py +0 -0
  62. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/pytestplugin/pyproject.toml +0 -0
  63. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/pytestplugin/src/__package_name__/entry.py +0 -0
  64. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/pytestplugin/tests/test_basic.py +0 -0
  65. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/.gitignore +0 -0
  66. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/conf/__package_name__-certbot-hook.sh +0 -0
  67. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/conf/__package_name__.service +0 -0
  68. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/conf/env_production.py +0 -0
  69. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/pyproject.toml +0 -0
  70. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/requirements.txt +0 -0
  71. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/src/__package_name__/core/uwsgiinit.py +0 -0
  72. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/src/__package_name__/settings/__init__.py +0 -0
  73. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/src/__package_name__/settings/auto.py +0 -0
  74. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/src/__package_name__/settings/base.py +0 -0
  75. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/src/__package_name__/settings/env_development.py +0 -0
  76. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/src/__package_name__/settings/env_testing.py +0 -0
  77. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/src/__package_name__/settings/sub_paths.py +0 -0
  78. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/src/__package_name__/uwsgicfg.py +0 -0
  79. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/state/certbot/empty +0 -0
  80. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/state/dumps/empty +0 -0
  81. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/state/media/empty +0 -0
  82. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/state/spool/empty +0 -0
  83. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/state/static/empty +0 -0
  84. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/tests/conftest.py +0 -0
  85. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/tests/requirements.txt +0 -0
  86. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/tests/test_module.py +0 -0
  87. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/app_templates/webscaff/wscaff.yml +0 -0
  88. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/appconfig.py +0 -0
  89. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/exceptions.py +0 -0
  90. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/helpers/__init__.py +0 -0
  91. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/helpers/venvs.py +0 -0
  92. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/license_templates/apache2 +0 -0
  93. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/license_templates/apache2_src +0 -0
  94. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/license_templates/bsd2cl +0 -0
  95. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/license_templates/bsd3cl +0 -0
  96. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/license_templates/gpl2 +0 -0
  97. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/license_templates/gpl2_src +0 -0
  98. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/license_templates/gpl3 +0 -0
  99. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/license_templates/gpl3_src +0 -0
  100. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/license_templates/mit +0 -0
  101. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/license_templates/no +0 -0
  102. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/license_templates/no_src +0 -0
  103. {makeapp-2.2.0 → makeapp-2.4.0}/src/makeapp/rendering.py +0 -0
@@ -10,4 +10,5 @@ __pycache__
10
10
  .mypy_cache
11
11
  .ruff_cache
12
12
  .pytest_cache
13
+ .ma-*
13
14
  .env
makeapp-2.4.0/PKG-INFO ADDED
@@ -0,0 +1,85 @@
1
+ Metadata-Version: 2.5
2
+ Name: makeapp
3
+ Version: 2.4.0
4
+ Summary: Simplifies routine Python application development processes.
5
+ Project-URL: Homepage, https://github.com/idlesign/makeapp
6
+ Project-URL: Documentation, https://makeapp.readthedocs.io/
7
+ Author-email: Igor Starikov <idlesign@yandex.ru>
8
+ License-Expression: BSD-3-Clause
9
+ License-File: LICENSE
10
+ Keywords: development,scaffolding
11
+ Requires-Python: >=3.11
12
+ Requires-Dist: click
13
+ Requires-Dist: jinja2~=3.1
14
+ Requires-Dist: pyyaml
15
+ Requires-Dist: requests
16
+ Description-Content-Type: text/markdown
17
+
18
+ # makeapp
19
+
20
+ [![PyPI - Version](https://img.shields.io/pypi/v/makeapp)](https://pypi.org/project/makeapp/)
21
+ [![License](https://img.shields.io/pypi/l/makeapp)](https://pypi.org/project/makeapp/)
22
+ [![Coverage](https://img.shields.io/coverallsCoverage/github/idlesign/makeapp)](https://coveralls.io/github/idlesign/makeapp)
23
+ [![Docs](https://img.shields.io/readthedocs/makeapp)](https://makeapp.readthedocs.io/)
24
+
25
+ `makeapp` scaffolds Python projects and provides one CLI for their common development tasks. It can create a project
26
+ from composable templates, initialize Git and a virtual environment, run a GitHub Actions test matrix locally, maintain
27
+ a changelog, and publish releases.
28
+
29
+ ## Install
30
+
31
+ Python 3.11 or newer and [uv](https://docs.astral.sh/uv/getting-started/installation/) are required.
32
+
33
+ ```bash
34
+ uv tool install makeapp
35
+ ```
36
+
37
+ Both `makeapp` and its short alias `ma` invoke the same command.
38
+
39
+ ## Quick start
40
+
41
+ ```bash
42
+ ma new shiny_app ./shiny-app --description "My app" --author "I am" --no-prompt
43
+ cd shiny-app
44
+ ma tests
45
+ ```
46
+
47
+ The default scaffold contains a `src`-layout package, tests, project metadata, a changelog, and MkDocs documentation.
48
+ The non-interactive command also initializes Git and runs `uv sync` to create `.venv`.
49
+
50
+ Bundled templates can extend the default scaffold:
51
+
52
+ - `console` for an `argparse` command-line application;
53
+ - `click` for a Click command-line application;
54
+ - `django` for a reusable Django application;
55
+ - `pytestplugin` for a pytest plugin;
56
+ - `webscaff` for a Linux-hosted Django/Webscaff project.
57
+
58
+ For example:
59
+
60
+ ```bash
61
+ ma new shiny_cli ./shiny-cli -t click --no-prompt
62
+ ```
63
+
64
+ ## Project workflow
65
+
66
+ ```bash
67
+ ma up # Synchronize the development environment.
68
+ ma style # Run Ruff checks and apply safe fixes.
69
+ ma tests # Run the configured test matrix.
70
+ ma docs --build # Build documentation without starting a server.
71
+ ma change "+ Add a feature" # Update the changelog and commit modified files.
72
+ ma release # Prepare a release and optionally publish it.
73
+ ```
74
+
75
+ Review changes before running `ma change`: it stages and commits modified tracked files together with the changelog.
76
+
77
+ ## Documentation
78
+
79
+ The full user and extension documentation is available at <https://makeapp.readthedocs.io/>.
80
+
81
+ - [Quickstart](https://makeapp.readthedocs.io/en/latest/quickstart/)
82
+ - [CLI reference](https://makeapp.readthedocs.io/en/latest/cli_reference/)
83
+ - [Template authoring](https://makeapp.readthedocs.io/en/latest/template_authoring/)
84
+ - [Publishing](https://makeapp.readthedocs.io/en/latest/publishing/)
85
+ Issues and feature requests are welcome in the [GitHub issue tracker](https://github.com/idlesign/makeapp/issues).
@@ -0,0 +1,68 @@
1
+ # makeapp
2
+
3
+ [![PyPI - Version](https://img.shields.io/pypi/v/makeapp)](https://pypi.org/project/makeapp/)
4
+ [![License](https://img.shields.io/pypi/l/makeapp)](https://pypi.org/project/makeapp/)
5
+ [![Coverage](https://img.shields.io/coverallsCoverage/github/idlesign/makeapp)](https://coveralls.io/github/idlesign/makeapp)
6
+ [![Docs](https://img.shields.io/readthedocs/makeapp)](https://makeapp.readthedocs.io/)
7
+
8
+ `makeapp` scaffolds Python projects and provides one CLI for their common development tasks. It can create a project
9
+ from composable templates, initialize Git and a virtual environment, run a GitHub Actions test matrix locally, maintain
10
+ a changelog, and publish releases.
11
+
12
+ ## Install
13
+
14
+ Python 3.11 or newer and [uv](https://docs.astral.sh/uv/getting-started/installation/) are required.
15
+
16
+ ```bash
17
+ uv tool install makeapp
18
+ ```
19
+
20
+ Both `makeapp` and its short alias `ma` invoke the same command.
21
+
22
+ ## Quick start
23
+
24
+ ```bash
25
+ ma new shiny_app ./shiny-app --description "My app" --author "I am" --no-prompt
26
+ cd shiny-app
27
+ ma tests
28
+ ```
29
+
30
+ The default scaffold contains a `src`-layout package, tests, project metadata, a changelog, and MkDocs documentation.
31
+ The non-interactive command also initializes Git and runs `uv sync` to create `.venv`.
32
+
33
+ Bundled templates can extend the default scaffold:
34
+
35
+ - `console` for an `argparse` command-line application;
36
+ - `click` for a Click command-line application;
37
+ - `django` for a reusable Django application;
38
+ - `pytestplugin` for a pytest plugin;
39
+ - `webscaff` for a Linux-hosted Django/Webscaff project.
40
+
41
+ For example:
42
+
43
+ ```bash
44
+ ma new shiny_cli ./shiny-cli -t click --no-prompt
45
+ ```
46
+
47
+ ## Project workflow
48
+
49
+ ```bash
50
+ ma up # Synchronize the development environment.
51
+ ma style # Run Ruff checks and apply safe fixes.
52
+ ma tests # Run the configured test matrix.
53
+ ma docs --build # Build documentation without starting a server.
54
+ ma change "+ Add a feature" # Update the changelog and commit modified files.
55
+ ma release # Prepare a release and optionally publish it.
56
+ ```
57
+
58
+ Review changes before running `ma change`: it stages and commits modified tracked files together with the changelog.
59
+
60
+ ## Documentation
61
+
62
+ The full user and extension documentation is available at <https://makeapp.readthedocs.io/>.
63
+
64
+ - [Quickstart](https://makeapp.readthedocs.io/en/latest/quickstart/)
65
+ - [CLI reference](https://makeapp.readthedocs.io/en/latest/cli_reference/)
66
+ - [Template authoring](https://makeapp.readthedocs.io/en/latest/template_authoring/)
67
+ - [Publishing](https://makeapp.readthedocs.io/en/latest/publishing/)
68
+ Issues and feature requests are welcome in the [GitHub issue tracker](https://github.com/idlesign/makeapp/issues).
@@ -0,0 +1,3 @@
1
+
2
+ VERSION = '2.4.0'
3
+ """Application version number tuple."""
@@ -2,9 +2,7 @@ name: Python package
2
2
 
3
3
  on:
4
4
  push:
5
- branches: [ master ]
6
5
  pull_request:
7
- branches: [ master ]
8
6
 
9
7
  jobs:
10
8
  build:
@@ -11,5 +11,6 @@ __pycache__
11
11
  .mypy_cache
12
12
  .ruff_cache
13
13
  .pytest_cache
14
+ .ma-*
14
15
  .env
15
- {% endblock %}
16
+ {% endblock %}
@@ -0,0 +1,35 @@
1
+ # Installing {{ app_name }}
2
+
3
+ Python {{ python_version }} or newer and [uv](https://docs.astral.sh/uv/) are required.
4
+
5
+ ## From PyPI
6
+
7
+ Add the package to a project:
8
+
9
+ ```bash
10
+ uv add {{ app_name }}
11
+ ```
12
+
13
+ If the package exposes a command-line application, install it as an isolated tool:
14
+
15
+ ```bash
16
+ uv tool install {{ app_name }}
17
+ ```
18
+
19
+ Upgrade the tool with:
20
+
21
+ ```bash
22
+ uv tool upgrade {{ app_name }}
23
+ ```
24
+
25
+ ## From source
26
+
27
+ Clone the repository and synchronize its development environment:
28
+
29
+ ```bash
30
+ git clone https://example.com/owner/repository.git {{ app_name }}
31
+ cd {{ app_name }}
32
+ uv sync
33
+ ```
34
+
35
+ Replace the example repository URL with the source repository. Run commands in the project environment with `uv run`.
@@ -0,0 +1,33 @@
1
+ # {{ app_name }}
2
+
3
+ [![PyPI - Version](https://img.shields.io/pypi/v/{{ app_name }})](https://pypi.org/project/{{ app_name }}/)
4
+ [![License](https://img.shields.io/pypi/l/{{ app_name }})](https://pypi.org/project/{{ app_name }}/)
5
+ [![Docs](https://img.shields.io/readthedocs/{{ app_name }})](https://{{ app_name }}.readthedocs.io/)
6
+ {% block badges %}
7
+ {% endblock %}
8
+
9
+ *{{ description }}*
10
+
11
+ Project homepage: <{{ url }}>
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ uv add {{ app_name }}
17
+ ```
18
+
19
+ See [INSTALL.md](INSTALL.md) for installation from source and tool installation.
20
+
21
+ ## Development
22
+
23
+ ```bash
24
+ uv sync
25
+ uv run pytest
26
+ uv run mkdocs build --strict
27
+ ```
28
+
29
+ Project documentation is available at <https://{{ app_name }}.readthedocs.io/>.
30
+
31
+ ## Contributing
32
+
33
+ See [CONTRIBUTING.md](CONTRIBUTING.md) before submitting an issue or pull request.
@@ -0,0 +1,21 @@
1
+ # {{ app_name }}
2
+
3
+ *{{ description }}*
4
+
5
+ ## Requirements
6
+
7
+ - Python {{ python_version }} or newer
8
+ - [uv](https://docs.astral.sh/uv/)
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ uv add {{ app_name }}
14
+ ```
15
+
16
+ Continue with the [quickstart](quickstart.md) to verify the installation and run the project checks.
17
+
18
+ ## Project links
19
+
20
+ - [Source and issue tracker]({{ url }})
21
+ - [PyPI](https://pypi.org/project/{{ app_name }}/)
@@ -0,0 +1,21 @@
1
+ # Quickstart
2
+
3
+ Install {{ app_name }} in an existing uv project:
4
+
5
+ ```bash
6
+ uv add {{ app_name }}
7
+ ```
8
+
9
+ To work on the source checkout, synchronize dependencies and run the checks:
10
+
11
+ ```bash
12
+ uv sync
13
+ uv run pytest
14
+ uv run mkdocs build --strict
15
+ ```
16
+
17
+ Start the local documentation server with:
18
+
19
+ ```bash
20
+ uv run mkdocs serve
21
+ ```
@@ -40,11 +40,15 @@ Homepage = "{{ url }}"
40
40
 
41
41
  [dependency-groups]
42
42
  dev = [
43
+ {include-group = "docs"},
43
44
  {include-group = "linters"},
44
45
  {include-group = "tests"},
45
46
  {% block deps_dev %}
46
47
  {% endblock %}
47
48
  ]
49
+ docs = [
50
+ "mkdocs-material",
51
+ ]
48
52
  linters = [
49
53
  {% block deps_linters %}
50
54
  {% endblock %}
@@ -0,0 +1,11 @@
1
+ import pytest
2
+
3
+
4
+ class TestApp:
5
+
6
+ def test_method(self):
7
+
8
+ assert 1 == 1
9
+
10
+ with pytest.raises(ValueError, match='Tested!'):
11
+ raise ValueError('Tested!')
@@ -10,8 +10,6 @@ join = os.path.join # Short alias
10
10
 
11
11
  class WebscaffConfig(Config):
12
12
 
13
- parent_template = ['pytest']
14
-
15
13
  domain = ConfigSetting(title='Domain Name', default='')
16
14
  email = ConfigSetting(title='Admin E-mail')
17
15
  host = ConfigSetting(title='Remote Host IP')
@@ -51,21 +49,21 @@ class WebscaffConfig(Config):
51
49
 
52
50
  # Install into venv the package itself not to conflict
53
51
  # with Django's `startproject` command.
54
- run_command('. venv/bin/activate && pip install -e .')
52
+ run_command(['venv/bin/pip', 'install', '-e', '.'])
55
53
 
56
54
  # Initialize local sqlite DB.
57
- run_command(f'venv/bin/{package_name} makemigrations')
58
- run_command(f'venv/bin/{package_name} migrate')
55
+ run_command([f'venv/bin/{package_name}', 'makemigrations'])
56
+ run_command([f'venv/bin/{package_name}', 'migrate'])
59
57
 
60
58
  def prepare_venv(self):
61
59
  self.logger.info('Bootstrapping virtual environment for project ...')
62
60
 
63
- run_command('python3 -m venv venv/')
61
+ run_command(['python3', '-m', 'venv', 'venv/'])
64
62
 
65
- cmd_install = '. venv/bin/activate && pip install -r '
63
+ cmd_install = ['venv/bin/pip', 'install', '-r']
66
64
 
67
- run_command(cmd_install + 'requirements.txt')
68
- run_command(cmd_install + 'tests/requirements.txt')
65
+ run_command([*cmd_install, 'requirements.txt'])
66
+ run_command([*cmd_install, 'tests/requirements.txt'])
69
67
 
70
68
  def prepare_django_settings_base(self, dir_tmp):
71
69
 
@@ -107,10 +105,10 @@ class WebscaffConfig(Config):
107
105
  dir_package = self.dir_package_root
108
106
  package_name = self.package_name
109
107
 
110
- command_django_admin = './venv/bin/django-admin'
108
+ command_django_admin = 'venv/bin/django-admin'
111
109
 
112
110
  with temp_dir() as dir_tmp:
113
- run_command(f'{command_django_admin} startproject {package_name} {dir_tmp}')
111
+ run_command([command_django_admin, 'startproject', package_name, dir_tmp])
114
112
 
115
113
  # We'd replace settings module paths.
116
114
  replace = partial(
@@ -131,7 +129,7 @@ class WebscaffConfig(Config):
131
129
 
132
130
  # Create basic app.
133
131
  dir_app = join(dir_package, 'core')
134
- run_command(f'{command_django_admin} startapp core {dir_app}')
132
+ run_command([command_django_admin, 'startapp', 'core', dir_app])
135
133
  replace_infile(
136
134
  join(dir_app, 'apps.py'),
137
135
  {
@@ -1,3 +1,4 @@
1
+ import keyword
1
2
  import logging
2
3
  import os
3
4
  import re
@@ -13,7 +14,7 @@ from .exceptions import AppMakerException
13
14
  from .helpers.vcs import VcsHelper
14
15
  from .helpers.venvs import VenvHelper
15
16
  from .rendering import Renderer
16
- from .utils import PYTHON_VERSION, configure_logging, get_user_dir, read_ini
17
+ from .utils import PYTHON_MIN_VERSION, configure_logging, get_user_dir, read_ini
17
18
 
18
19
  RE_UNKNOWN_MARKER = re.compile(r'{{ [^}]+ }}')
19
20
  BASE_PATH = os.path.dirname(__file__)
@@ -68,7 +69,7 @@ class AppMaker:
68
69
  'license_ident': LICENSES[default_license][1],
69
70
  'vcs': default_vcs,
70
71
  'vcs_remote': None,
71
- 'python_version': '.'.join(map(str, PYTHON_VERSION[:2])),
72
+ 'python_version': '.'.join(map(str, PYTHON_MIN_VERSION)),
72
73
  }
73
74
 
74
75
  app_template_default: AppTemplate = None
@@ -113,7 +114,7 @@ class AppMaker:
113
114
 
114
115
  # Support for user-supplied template directories.
115
116
  for template in templates_to_use or []:
116
- if '/' in template:
117
+ if os.sep in template:
117
118
  parent = str(Path(template).parent)
118
119
  if parent not in search_paths:
119
120
  search_paths.append(parent)
@@ -225,13 +226,24 @@ class AppMaker:
225
226
  name_available = True
226
227
 
227
228
  for label, url in sites_registry.items():
228
- response = requests.get(url)
229
+ try:
230
+ response = requests.get(url, timeout=5)
231
+ except requests.RequestException as e:
232
+ raise AppMakerException(
233
+ f'Unable to check application name at {label}: {e}.'
234
+ ) from e
229
235
 
230
236
  if response.status_code == 200:
231
237
  self.logger.warning(f'Application name seems to be in use: {label} - {url}')
232
238
  name_available = False
233
239
  break
234
240
 
241
+ if response.status_code != 404:
242
+ raise AppMakerException(
243
+ f'Unable to check application name at {label}: '
244
+ f'HTTP {response.status_code}.'
245
+ )
246
+
235
247
  if name_available:
236
248
  self.logger.info(
237
249
  f"Application name `{self.settings['app_name']}` seems "
@@ -302,6 +314,7 @@ class AppMaker:
302
314
  :param remote_push: Whether to push to remote.
303
315
 
304
316
  """
317
+ dest = os.path.abspath(dest)
305
318
  self.logger.info(f'Application target path: {dest}')
306
319
 
307
320
  # Make remote available for hooks.
@@ -329,8 +342,18 @@ class AppMaker:
329
342
  self._hook_run('rollout_pre')
330
343
 
331
344
  files = self._get_template_files()
345
+ dest_path = Path(dest).resolve()
332
346
  for target, template_file in files.items():
333
- target = os.path.join(dest, target)
347
+ target_path = (dest_path / target).resolve()
348
+
349
+ try:
350
+ target_path.relative_to(dest_path)
351
+ except ValueError as e:
352
+ raise AppMakerException(
353
+ f'Template target path escapes destination: {target}.'
354
+ ) from e
355
+
356
+ target = f'{target_path}'
334
357
 
335
358
  if not os.path.exists(target) or overwrite:
336
359
 
@@ -377,11 +400,7 @@ class AppMaker:
377
400
 
378
401
  """
379
402
  with open(path, 'w') as f:
380
-
381
- f.write(contents)
382
-
383
- if contents.endswith('\n'):
384
- f.write('\n')
403
+ f.write(contents.rstrip('\n') + '\n')
385
404
 
386
405
  def _copy_file(self, src: TemplateFile, dest: str, prepend_data: str = None):
387
406
  """Copies a file from `src` to `dest` replacing settings markers
@@ -579,6 +598,12 @@ class AppMaker:
579
598
  for name, val in settings_base.items():
580
599
  settings_base[name] = self._replace_settings_markers(val, settings=settings_base)
581
600
 
601
+ package_name = settings_base['package_name']
602
+ if not package_name or not package_name.isidentifier() or keyword.iskeyword(package_name):
603
+ raise AppMakerException(
604
+ f'Invalid Python package name: `{package_name}`.'
605
+ )
606
+
582
607
  self._validate_setting('license', list(self.LICENSES), settings_base)
583
608
 
584
609
  license = self.LICENSES[settings_base['license']]
@@ -120,12 +120,12 @@ class AppTemplate:
120
120
 
121
121
  full_path = os.path.join(path, fname)
122
122
 
123
- rel_path = full_path.replace(templates_path, '').lstrip('/')
123
+ rel_path = os.path.relpath(full_path, templates_path)
124
124
 
125
125
  template_file = TemplateFile(
126
126
  template=self,
127
127
  path_full=full_path,
128
- path_rel=rel_path,
128
+ path_rel=rel_path.replace(os.sep, '/'),
129
129
  )
130
130
 
131
131
  rel_path = rel_path.replace(maker.package_dir_marker, maker.settings['package_name'])
@@ -174,9 +174,9 @@ class AppTemplate:
174
174
 
175
175
  """
176
176
  for supposed_path in search_paths:
177
- if '/' in supposed_path and os.path.exists(supposed_path):
177
+ if os.sep in supposed_path and os.path.exists(supposed_path):
178
178
  path = str(os.path.abspath(supposed_path))
179
- return path.split('/')[-1], path
179
+ return path.split(os.sep)[-1], path
180
180
 
181
181
  raise AppMakerException(
182
182
  f"Unable to find application template {name_or_path}. "
@@ -221,7 +221,7 @@ class TemplateFile:
221
221
 
222
222
  if os.path.exists(path_full):
223
223
  # Check parent file exists in template.
224
- paths.append(os.path.join(parent.name, path_rel))
224
+ paths.append(f'{parent.name}/{path_rel}')
225
225
 
226
226
  if parent.is_default:
227
227
  break