common-python-tasks 0.0.1__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Joseph Asbury
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,295 @@
1
+ Metadata-Version: 2.4
2
+ Name: common-python-tasks
3
+ Version: 0.0.1
4
+ Summary: Opinionated Poe the Poet tasks for Python package development.
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Author: Joseph Asbury
8
+ Author-email: ci_sourcerer@yahoo.com
9
+ Requires-Python: >=3.10,<4.0
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Topic :: Software Development :: Build Tools
19
+ Requires-Dist: autoflake (>=2.3.1,<3.0.0)
20
+ Requires-Dist: black (>=25.11.0,<26.0.0)
21
+ Requires-Dist: dunamai (>=1.25.0,<2.0.0)
22
+ Requires-Dist: flake8 (>=7.3.0,<8.0.0)
23
+ Requires-Dist: isort (>=7.0.0,<8.0.0)
24
+ Requires-Dist: poethepoet-tasks (>=0.3.0,<0.4.0)
25
+ Requires-Dist: pytest (>=9.0.1,<10.0.0)
26
+ Requires-Dist: pytest-cov (>=7.0.0,<8.0.0)
27
+ Requires-Dist: tomlkit (>=0.13.3,<0.14.0)
28
+ Project-URL: Homepage, http://github.com/ci-sourcerer/common-python-tasks
29
+ Project-URL: issues, http://github.com/ci-sourcerer/common-python-tasks/issues
30
+ Project-URL: source, http://github.com/ci-sourcerer/common-python-tasks
31
+ Description-Content-Type: text/markdown
32
+
33
+ # Common Python tasks
34
+
35
+ This package is a collection of (very) opinionated [Poe the Poet Python tasks](https://poethepoet.natn.io/guides/packaged_tasks.html) for common Python development workflows.
36
+
37
+ ## Quick start
38
+
39
+ ### Automated setup
40
+
41
+ You can add `common-python-tasks` to a new project by using the handy automated installation script.
42
+
43
+ ```shell
44
+ curl -sSL https://api.github.com/repos/ci-sourcerer/common-python-tasks/contents/scripts/add-common-python-tasks.sh | TAGS_TO_INCLUDE="format lint test" sh
45
+ ```
46
+
47
+ This will complete the following steps.
48
+
49
+ 1. Add the latest version of `common-python-tasks` to your `pyproject.toml` dependencies
50
+ 2. Configure Poe the Poet to include only the tasks with the specified tags
51
+ 3. Install the package using Poetry
52
+
53
+ **Always review scripts before running them!** Even though I believe I write good software, it's best practice to verify any script you download from the Internet.
54
+
55
+ ### Manual setup
56
+
57
+ 1. Add `common-python-tasks` to your `pyproject.toml` and configure Poe the Poet to include the desired tasks
58
+
59
+ ```toml
60
+ [project]
61
+ name = "my-awesome-project"
62
+ version = "0.0.1"
63
+ dependencies = [
64
+ "common-python-tasks==0.0.1", # Always pin to a specific version
65
+ ]
66
+
67
+ [tool.poe]
68
+ include_script = "common_python_tasks:tasks(include_tags=['format', 'lint', 'test'])" # Include or exclude tasks by tags
69
+ ```
70
+
71
+ 2. Install the package
72
+
73
+ ```shell
74
+ poetry install
75
+ ```
76
+
77
+ 3. Run tasks
78
+
79
+ ```shell
80
+ poe format # Format your code
81
+ poe lint # Check code quality
82
+ poe test # Run tests with coverage
83
+ ```
84
+
85
+ ## Available tasks
86
+
87
+ Internal tasks are used by other tasks and are not meant to be run directly.
88
+
89
+ | Task | Description | Tags |
90
+ | - | - | - |
91
+ | `build` | Build the project; also builds container images when the `containers` tag is included | packaging, containers |
92
+ | `build-image` | Build a container image using the bundled Containerfile template | containers, build |
93
+ | `build-package` | Build the package (wheel and sdist) | packaging, build |
94
+ | `bump-version` | Bump project version and create a git tag | packaging |
95
+ | `clean` | Remove build, cache, and coverage artifacts | clean |
96
+ | `format` | Format code with autoflake, black, and isort | format |
97
+ | `lint` | Run autoflake, black, isort checks, and flake8 linting | lint |
98
+ | `publish-package` | Publish the package to PyPI via Poetry | packaging |
99
+ | `push-image` | Push container images to the configured registry | containers, packaging, release |
100
+ | `run-container` | Run the built container image with the selected tag | containers |
101
+ | `test` | Run tests with pytest and generate coverage reports | test |
102
+
103
+ ## How it works
104
+
105
+ ### Prerequisites
106
+
107
+ Your project must meet the following requirements.
108
+
109
+ - Use Poetry for dependency management
110
+ - Have a `pyproject.toml` file at the root
111
+ - Have a package name (automatically inferred from `project.name` in `pyproject.toml`, or set via `PACKAGE_NAME` environment variable)
112
+
113
+ ### Configuration precedence
114
+
115
+ Tasks that need configuration files (`pytest`, `coverage`, `flake8`, `isort`) follow this order of precedence.
116
+
117
+ 1. **`pyproject.toml` sections** - `[tool.pytest]`, `[tool.coverage]`, `[tool.isort]` take priority
118
+ 2. **Environment variables** - Override config paths (see [Environment Variables](#environment-variables))
119
+ 3. **Local config files** - `pytest.ini`, `.coveragerc`, `.flake8`, `.isort.cfg` in project root
120
+ 4. **Bundled defaults** - Sensible defaults included with this package, found in the [`src/common_python_tasks/data`](src/common_python_tasks/data) directory
121
+
122
+ You can start with zero configuration and customize as needed.
123
+
124
+ ### Environment variables
125
+
126
+ #### Configuration files
127
+
128
+ The following environment variables configure the paths to configuration files.
129
+
130
+ - `PYTEST_CONFIG` specifies the path to the pytest configuration file
131
+ - `COVERAGE_RCFILE` specifies the path to the coverage configuration file
132
+ - `FLAKE8_CONFIG` specifies the path to the flake8 configuration file
133
+ - `ISORT_CONFIG` specifies the path to the isort configuration file
134
+
135
+ #### Package/Container settings
136
+
137
+ The following environment variables configure package and container behavior.
138
+
139
+ - `PACKAGE_NAME` overrides the package name (default is from `pyproject.toml`)
140
+ - `POETRY_VERSION` overrides the Poetry version for container builds
141
+ - `DOCKERHUB_USERNAME` specifies the Docker Hub username for image tagging (default is current local user)
142
+ - `CONTAINER_REGISTRY_URL` specifies the registry URL (default is `docker.io/{username}`)
143
+ - `CUSTOM_IMAGE_ENTRYPOINT` specifies a custom entrypoint script name for containers
144
+
145
+ #### Debugging
146
+
147
+ The following environment variable enables debugging output.
148
+
149
+ - `COMMON_PYTHON_TASKS_LOG_LEVEL` should be set to `DEBUG` to see detailed configuration resolution
150
+
151
+ ### Usage examples
152
+
153
+ You can include or exclude tasks by tags in your `pyproject.toml`
154
+
155
+ #### Minimal setup
156
+
157
+ ```toml
158
+ [project]
159
+ name = "simple-cli-tool"
160
+ version = "0.0.1"
161
+ dependencies = ["common-python-tasks==0.0.1"]
162
+
163
+ [tool.poe]
164
+ include_script = "common_python_tasks:tasks(include_tags=['format', 'lint'])"
165
+ ```
166
+
167
+ Available tasks: `format`, `lint`.
168
+
169
+ #### Container-based project
170
+
171
+ ```toml
172
+ [project]
173
+ name = "containerized-app"
174
+ version = "0.0.1"
175
+ dependencies = ["common-python-tasks==0.0.1"]
176
+
177
+ [tool.poe]
178
+ include_script = "common_python_tasks:tasks(include_tags=['format', 'lint', 'test', 'containers'])"
179
+
180
+ [tool.poe.env]
181
+ DOCKERHUB_USERNAME = "myusername"
182
+ PACKAGE_NAME = "containerized-app"
183
+ ```
184
+
185
+ Available tasks: All tasks including `build-image` and `push-image`.
186
+
187
+ #### Custom pytest configuration
188
+
189
+ ```toml
190
+ [project]
191
+ name = "custom-test-setup"
192
+ dependencies = ["common-python-tasks==0.0.1"]
193
+ dynamic = ["version"]
194
+
195
+ [tool.poe]
196
+ include_script = "common_python_tasks:tasks(include_tags=['test'])"
197
+
198
+ [tool.pytest.ini_options]
199
+ testpaths = ["tests", "integration"]
200
+ addopts = "-ra"
201
+ ```
202
+
203
+ The `test` task will automatically use your `[tool.pytest.ini_options]` configuration.
204
+
205
+ ## Release workflow
206
+
207
+ The `release` tag is used to identify tasks that are part of the release process. To perform a complete release, follow these steps.
208
+
209
+ ```shell
210
+ # 1. Ensure all changes are committed
211
+ git add .
212
+ git commit -m "Prepare for release" # You probably want a better commit message than this
213
+
214
+ # 2. Bump the version (creates a git tag)
215
+ poe bump-version patch # or 'minor', 'major'; for pre-releases: poe bump-version patch --stage alpha
216
+
217
+ # 3. Build the package
218
+ poetry build
219
+
220
+ # 4. Publish to PyPI
221
+ poe publish-package
222
+
223
+ # 5. (Optional) If using containers
224
+ poe build-image
225
+ poe push-image
226
+
227
+ # 6. Push tags to remote
228
+ git push --tags
229
+ ```
230
+
231
+ ## Troubleshooting
232
+
233
+ ### "No tests were collected"
234
+
235
+ The `test` task exits with code 5 if no tests are found. You can address this in one of the following ways.
236
+
237
+ - Add tests to your `tests/` directory
238
+ - Exclude the `test` tag and simply do not run `poe test` with this configuration `include_script = "common_python_tasks:tasks(exclude_tags=['test', 'internal'])"`
239
+
240
+ ### Tasks not showing up with `poe --help`
241
+
242
+ Check your `[tool.poe]` configuration in `pyproject.toml`. Make sure you're using `include_script`, not `includes`.
243
+
244
+ ```toml
245
+ # Correct
246
+ [tool.poe]
247
+ include_script = "common_python_tasks:tasks(exclude_tags=['internal'])"
248
+
249
+ # Incorrect
250
+ [tool.poe]
251
+ includes = "common_python_tasks:tasks"
252
+ ```
253
+
254
+ ### Version bump fails with "no changes since last tag"
255
+
256
+ This is expected behavior. The `bump-version` task requires commits between the last tag and HEAD. You can resolve this in one of the following ways.
257
+
258
+ - Make changes and commit them first
259
+ - If you need to re-tag the same commit, delete the old tag (for example, `git tag -d v0.0.1`). This is not recommended. Versions should be immutable, and if you need to fix something, you should create a new patch version instead
260
+
261
+ ### Config files not being used
262
+
263
+ Check the configuration precedence (see [How it works](#how-it-works)). Use debug logging to see which config is selected.
264
+
265
+ ```shell
266
+ COMMON_PYTHON_TASKS_LOG_LEVEL=DEBUG poe test
267
+ ```
268
+
269
+ ### Container build fails with "unable to find package"
270
+
271
+ Make sure your `pyproject.toml` contains the following.
272
+
273
+ - A correct package name in `[project]`
274
+ - A package location defined with this configuration `[tool.poetry] packages = [{ include = "your_package", from = "src" }]`
275
+
276
+ ## Design choices
277
+
278
+ ### Containerfile (see [src/common_python_tasks/data/Containerfile](src/common_python_tasks/data/Containerfile))
279
+
280
+ The standard Python Containerfile incorporates several intentional design choices.
281
+
282
+ - Multi-stage build: the build stage installs Poetry and builds a wheel while the runtime stage installs only the wheel to keep the final image slim and reproducible
283
+ - Cache-aware installs mean pip and Poetry cache mounts speed up iterative builds without bloating the final image
284
+ - Explicit inputs through build args (`PYTHON_VERSION`, `POETRY_VERSION`, `PACKAGE_NAME`, `AUTHORS`, `GIT_COMMIT`, `CUSTOM_ENTRYPOINT`) make image metadata and behavior predictable and auditable
285
+ - Optional debug stage exports and installs the `debug` dependency group only when present without failing otherwise and is not part of the default final image
286
+ - Stable package path creates symlinks to the installed package so entrypoints and consumers have a consistent `/pkg` and `/_$PACKAGE_NAME` path regardless of wheel layout, which ensures that the package can be reliably imported and executed from a known location, and allows for the less common use case of reading files directly from the package path
287
+ - Safe entrypoint selection means the default entrypoint resolves the console script matching the package name while `CUSTOM_ENTRYPOINT` allows overriding at build time while keeping runtime behavior predictable
288
+ - Minimal final image uses the slim Python base, cleans wheel artifacts and caches, and sets `runtime` as the explicit final target so the debug stage is opt-in
289
+
290
+ ## Notes
291
+
292
+ - This project dogfoods itself - it uses `common-python-tasks` for its own development
293
+ - Contributions welcome! Open an issue/discussion to discuss changes before submitting a PR. I do not claim to have all the answers, and you can help determine the future of low-code solutions for Python. I am very interested in your feedback as I don't want to work in a vacuum
294
+ - Alpha status: expect breaking changes between minor versions until 1.0.0
295
+
@@ -0,0 +1,262 @@
1
+ # Common Python tasks
2
+
3
+ This package is a collection of (very) opinionated [Poe the Poet Python tasks](https://poethepoet.natn.io/guides/packaged_tasks.html) for common Python development workflows.
4
+
5
+ ## Quick start
6
+
7
+ ### Automated setup
8
+
9
+ You can add `common-python-tasks` to a new project by using the handy automated installation script.
10
+
11
+ ```shell
12
+ curl -sSL https://api.github.com/repos/ci-sourcerer/common-python-tasks/contents/scripts/add-common-python-tasks.sh | TAGS_TO_INCLUDE="format lint test" sh
13
+ ```
14
+
15
+ This will complete the following steps.
16
+
17
+ 1. Add the latest version of `common-python-tasks` to your `pyproject.toml` dependencies
18
+ 2. Configure Poe the Poet to include only the tasks with the specified tags
19
+ 3. Install the package using Poetry
20
+
21
+ **Always review scripts before running them!** Even though I believe I write good software, it's best practice to verify any script you download from the Internet.
22
+
23
+ ### Manual setup
24
+
25
+ 1. Add `common-python-tasks` to your `pyproject.toml` and configure Poe the Poet to include the desired tasks
26
+
27
+ ```toml
28
+ [project]
29
+ name = "my-awesome-project"
30
+ version = "0.0.1"
31
+ dependencies = [
32
+ "common-python-tasks==0.0.1", # Always pin to a specific version
33
+ ]
34
+
35
+ [tool.poe]
36
+ include_script = "common_python_tasks:tasks(include_tags=['format', 'lint', 'test'])" # Include or exclude tasks by tags
37
+ ```
38
+
39
+ 2. Install the package
40
+
41
+ ```shell
42
+ poetry install
43
+ ```
44
+
45
+ 3. Run tasks
46
+
47
+ ```shell
48
+ poe format # Format your code
49
+ poe lint # Check code quality
50
+ poe test # Run tests with coverage
51
+ ```
52
+
53
+ ## Available tasks
54
+
55
+ Internal tasks are used by other tasks and are not meant to be run directly.
56
+
57
+ | Task | Description | Tags |
58
+ | - | - | - |
59
+ | `build` | Build the project; also builds container images when the `containers` tag is included | packaging, containers |
60
+ | `build-image` | Build a container image using the bundled Containerfile template | containers, build |
61
+ | `build-package` | Build the package (wheel and sdist) | packaging, build |
62
+ | `bump-version` | Bump project version and create a git tag | packaging |
63
+ | `clean` | Remove build, cache, and coverage artifacts | clean |
64
+ | `format` | Format code with autoflake, black, and isort | format |
65
+ | `lint` | Run autoflake, black, isort checks, and flake8 linting | lint |
66
+ | `publish-package` | Publish the package to PyPI via Poetry | packaging |
67
+ | `push-image` | Push container images to the configured registry | containers, packaging, release |
68
+ | `run-container` | Run the built container image with the selected tag | containers |
69
+ | `test` | Run tests with pytest and generate coverage reports | test |
70
+
71
+ ## How it works
72
+
73
+ ### Prerequisites
74
+
75
+ Your project must meet the following requirements.
76
+
77
+ - Use Poetry for dependency management
78
+ - Have a `pyproject.toml` file at the root
79
+ - Have a package name (automatically inferred from `project.name` in `pyproject.toml`, or set via `PACKAGE_NAME` environment variable)
80
+
81
+ ### Configuration precedence
82
+
83
+ Tasks that need configuration files (`pytest`, `coverage`, `flake8`, `isort`) follow this order of precedence.
84
+
85
+ 1. **`pyproject.toml` sections** - `[tool.pytest]`, `[tool.coverage]`, `[tool.isort]` take priority
86
+ 2. **Environment variables** - Override config paths (see [Environment Variables](#environment-variables))
87
+ 3. **Local config files** - `pytest.ini`, `.coveragerc`, `.flake8`, `.isort.cfg` in project root
88
+ 4. **Bundled defaults** - Sensible defaults included with this package, found in the [`src/common_python_tasks/data`](src/common_python_tasks/data) directory
89
+
90
+ You can start with zero configuration and customize as needed.
91
+
92
+ ### Environment variables
93
+
94
+ #### Configuration files
95
+
96
+ The following environment variables configure the paths to configuration files.
97
+
98
+ - `PYTEST_CONFIG` specifies the path to the pytest configuration file
99
+ - `COVERAGE_RCFILE` specifies the path to the coverage configuration file
100
+ - `FLAKE8_CONFIG` specifies the path to the flake8 configuration file
101
+ - `ISORT_CONFIG` specifies the path to the isort configuration file
102
+
103
+ #### Package/Container settings
104
+
105
+ The following environment variables configure package and container behavior.
106
+
107
+ - `PACKAGE_NAME` overrides the package name (default is from `pyproject.toml`)
108
+ - `POETRY_VERSION` overrides the Poetry version for container builds
109
+ - `DOCKERHUB_USERNAME` specifies the Docker Hub username for image tagging (default is current local user)
110
+ - `CONTAINER_REGISTRY_URL` specifies the registry URL (default is `docker.io/{username}`)
111
+ - `CUSTOM_IMAGE_ENTRYPOINT` specifies a custom entrypoint script name for containers
112
+
113
+ #### Debugging
114
+
115
+ The following environment variable enables debugging output.
116
+
117
+ - `COMMON_PYTHON_TASKS_LOG_LEVEL` should be set to `DEBUG` to see detailed configuration resolution
118
+
119
+ ### Usage examples
120
+
121
+ You can include or exclude tasks by tags in your `pyproject.toml`
122
+
123
+ #### Minimal setup
124
+
125
+ ```toml
126
+ [project]
127
+ name = "simple-cli-tool"
128
+ version = "0.0.1"
129
+ dependencies = ["common-python-tasks==0.0.1"]
130
+
131
+ [tool.poe]
132
+ include_script = "common_python_tasks:tasks(include_tags=['format', 'lint'])"
133
+ ```
134
+
135
+ Available tasks: `format`, `lint`.
136
+
137
+ #### Container-based project
138
+
139
+ ```toml
140
+ [project]
141
+ name = "containerized-app"
142
+ version = "0.0.1"
143
+ dependencies = ["common-python-tasks==0.0.1"]
144
+
145
+ [tool.poe]
146
+ include_script = "common_python_tasks:tasks(include_tags=['format', 'lint', 'test', 'containers'])"
147
+
148
+ [tool.poe.env]
149
+ DOCKERHUB_USERNAME = "myusername"
150
+ PACKAGE_NAME = "containerized-app"
151
+ ```
152
+
153
+ Available tasks: All tasks including `build-image` and `push-image`.
154
+
155
+ #### Custom pytest configuration
156
+
157
+ ```toml
158
+ [project]
159
+ name = "custom-test-setup"
160
+ dependencies = ["common-python-tasks==0.0.1"]
161
+ dynamic = ["version"]
162
+
163
+ [tool.poe]
164
+ include_script = "common_python_tasks:tasks(include_tags=['test'])"
165
+
166
+ [tool.pytest.ini_options]
167
+ testpaths = ["tests", "integration"]
168
+ addopts = "-ra"
169
+ ```
170
+
171
+ The `test` task will automatically use your `[tool.pytest.ini_options]` configuration.
172
+
173
+ ## Release workflow
174
+
175
+ The `release` tag is used to identify tasks that are part of the release process. To perform a complete release, follow these steps.
176
+
177
+ ```shell
178
+ # 1. Ensure all changes are committed
179
+ git add .
180
+ git commit -m "Prepare for release" # You probably want a better commit message than this
181
+
182
+ # 2. Bump the version (creates a git tag)
183
+ poe bump-version patch # or 'minor', 'major'; for pre-releases: poe bump-version patch --stage alpha
184
+
185
+ # 3. Build the package
186
+ poetry build
187
+
188
+ # 4. Publish to PyPI
189
+ poe publish-package
190
+
191
+ # 5. (Optional) If using containers
192
+ poe build-image
193
+ poe push-image
194
+
195
+ # 6. Push tags to remote
196
+ git push --tags
197
+ ```
198
+
199
+ ## Troubleshooting
200
+
201
+ ### "No tests were collected"
202
+
203
+ The `test` task exits with code 5 if no tests are found. You can address this in one of the following ways.
204
+
205
+ - Add tests to your `tests/` directory
206
+ - Exclude the `test` tag and simply do not run `poe test` with this configuration `include_script = "common_python_tasks:tasks(exclude_tags=['test', 'internal'])"`
207
+
208
+ ### Tasks not showing up with `poe --help`
209
+
210
+ Check your `[tool.poe]` configuration in `pyproject.toml`. Make sure you're using `include_script`, not `includes`.
211
+
212
+ ```toml
213
+ # Correct
214
+ [tool.poe]
215
+ include_script = "common_python_tasks:tasks(exclude_tags=['internal'])"
216
+
217
+ # Incorrect
218
+ [tool.poe]
219
+ includes = "common_python_tasks:tasks"
220
+ ```
221
+
222
+ ### Version bump fails with "no changes since last tag"
223
+
224
+ This is expected behavior. The `bump-version` task requires commits between the last tag and HEAD. You can resolve this in one of the following ways.
225
+
226
+ - Make changes and commit them first
227
+ - If you need to re-tag the same commit, delete the old tag (for example, `git tag -d v0.0.1`). This is not recommended. Versions should be immutable, and if you need to fix something, you should create a new patch version instead
228
+
229
+ ### Config files not being used
230
+
231
+ Check the configuration precedence (see [How it works](#how-it-works)). Use debug logging to see which config is selected.
232
+
233
+ ```shell
234
+ COMMON_PYTHON_TASKS_LOG_LEVEL=DEBUG poe test
235
+ ```
236
+
237
+ ### Container build fails with "unable to find package"
238
+
239
+ Make sure your `pyproject.toml` contains the following.
240
+
241
+ - A correct package name in `[project]`
242
+ - A package location defined with this configuration `[tool.poetry] packages = [{ include = "your_package", from = "src" }]`
243
+
244
+ ## Design choices
245
+
246
+ ### Containerfile (see [src/common_python_tasks/data/Containerfile](src/common_python_tasks/data/Containerfile))
247
+
248
+ The standard Python Containerfile incorporates several intentional design choices.
249
+
250
+ - Multi-stage build: the build stage installs Poetry and builds a wheel while the runtime stage installs only the wheel to keep the final image slim and reproducible
251
+ - Cache-aware installs mean pip and Poetry cache mounts speed up iterative builds without bloating the final image
252
+ - Explicit inputs through build args (`PYTHON_VERSION`, `POETRY_VERSION`, `PACKAGE_NAME`, `AUTHORS`, `GIT_COMMIT`, `CUSTOM_ENTRYPOINT`) make image metadata and behavior predictable and auditable
253
+ - Optional debug stage exports and installs the `debug` dependency group only when present without failing otherwise and is not part of the default final image
254
+ - Stable package path creates symlinks to the installed package so entrypoints and consumers have a consistent `/pkg` and `/_$PACKAGE_NAME` path regardless of wheel layout, which ensures that the package can be reliably imported and executed from a known location, and allows for the less common use case of reading files directly from the package path
255
+ - Safe entrypoint selection means the default entrypoint resolves the console script matching the package name while `CUSTOM_ENTRYPOINT` allows overriding at build time while keeping runtime behavior predictable
256
+ - Minimal final image uses the slim Python base, cleans wheel artifacts and caches, and sets `runtime` as the explicit final target so the debug stage is opt-in
257
+
258
+ ## Notes
259
+
260
+ - This project dogfoods itself - it uses `common-python-tasks` for its own development
261
+ - Contributions welcome! Open an issue/discussion to discuss changes before submitting a PR. I do not claim to have all the answers, and you can help determine the future of low-code solutions for Python. I am very interested in your feedback as I don't want to work in a vacuum
262
+ - Alpha status: expect breaking changes between minor versions until 1.0.0
@@ -0,0 +1,61 @@
1
+ [project]
2
+ name = "common-python-tasks"
3
+ description = "Opinionated Poe the Poet tasks for Python package development."
4
+ readme = "README.md"
5
+ requires-python = ">=3.10,<4.0"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [{ name = "Joseph Asbury", email = "ci_sourcerer@yahoo.com" }]
9
+ classifiers = [
10
+ "Development Status :: 3 - Alpha",
11
+ "Intended Audience :: Developers",
12
+ "Programming Language :: Python :: 3",
13
+ "Programming Language :: Python :: 3.10",
14
+ "Programming Language :: Python :: 3.11",
15
+ "Programming Language :: Python :: 3.12",
16
+ "Programming Language :: Python :: 3.13",
17
+ "Programming Language :: Python :: 3.14",
18
+ "Topic :: Software Development :: Build Tools",
19
+ ]
20
+ dependencies = [
21
+ "autoflake (>=2.3.1,<3.0.0)",
22
+ "black (>=25.11.0,<26.0.0)",
23
+ "dunamai (>=1.25.0,<2.0.0)",
24
+ "flake8 (>=7.3.0,<8.0.0)",
25
+ "isort (>=7.0.0,<8.0.0)",
26
+ "poethepoet-tasks (>=0.3.0,<0.4.0)",
27
+ "pytest-cov (>=7.0.0,<8.0.0)",
28
+ "pytest (>=9.0.1,<10.0.0)",
29
+ "tomlkit (>=0.13.3,<0.14.0)",
30
+ ]
31
+ dynamic = []
32
+ version = "0.0.1"
33
+
34
+ [project.urls]
35
+ homepage = "http://github.com/ci-sourcerer/common-python-tasks"
36
+ issues = "http://github.com/ci-sourcerer/common-python-tasks/issues"
37
+ source = "http://github.com/ci-sourcerer/common-python-tasks"
38
+
39
+ [tool.poe]
40
+ include_script = "common_python_tasks:tasks(exclude_tags=['containers'])"
41
+
42
+ [tool.poetry.requires-plugins]
43
+ poetry-dynamic-versioning = { version = ">=1.0.0,<2.0.0", extras = ["plugin"] }
44
+ poetry-plugin-export = { version = ">=1.9.0,<2.0.0" }
45
+
46
+ [tool.poetry]
47
+ packages = [{ include = "common_python_tasks", from = "src" }]
48
+ include = ["src/common_python_tasks/data/*"]
49
+ # This is set by poetry-dynamic-versioning
50
+
51
+ [dependency-groups]
52
+ debug = ["debugpy (>=1.8.16,<2.0.0)"]
53
+
54
+ [build-system]
55
+ requires = ["poetry-core>=2.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"]
56
+ build-backend = "poetry.core.masonry.api"
57
+
58
+ [tool.poetry-dynamic-versioning]
59
+ enable = false
60
+ style = "pep440"
61
+ dirty = true
@@ -0,0 +1,16 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ if TYPE_CHECKING:
4
+ from collections.abc import Sequence
5
+
6
+ from poethepoet_tasks import TaskCollection
7
+
8
+ __version__ = "0.0.0"
9
+
10
+ __all__ = ["TaskCollection"]
11
+
12
+
13
+ def tasks(include_tags: Sequence[str] = tuple(), exclude_tags: Sequence[str] = tuple()):
14
+ from .tasks import tasks
15
+
16
+ return tasks(include_tags=include_tags, exclude_tags=exclude_tags)
@@ -0,0 +1,8 @@
1
+ [run]
2
+ omit =
3
+ tests/*
4
+ */vendor/*
5
+ */__main__.py
6
+ [paths]
7
+ source =
8
+ src/*
@@ -0,0 +1,10 @@
1
+ *
2
+ !dist/*.whl
3
+ !pyproject.toml
4
+ !poetry.lock
5
+ !README.md
6
+ !LICENSE
7
+
8
+ !src
9
+
10
+ !.git
@@ -0,0 +1,9 @@
1
+ [flake8]
2
+ extend-ignore = E501,E203,W503
3
+ max-line-length = 88
4
+ select = B,C,E,F,W,T4,B9
5
+ exclude =
6
+ .poetry
7
+ .venv
8
+ .dist
9
+ build