python-package-folder 1.1.3__tar.gz → 1.2.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.
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/PKG-INFO +97 -22
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/README.md +96 -21
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/coverage.svg +2 -2
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/src/python_package_folder/analyzer.py +43 -1
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/src/python_package_folder/manager.py +175 -57
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/src/python_package_folder/python_package_folder.py +2 -1
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/src/python_package_folder/subfolder_build.py +187 -13
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/src/python_package_folder/utils.py +7 -5
- python_package_folder-1.2.1/tests/test_subfolder_build.py +723 -0
- python_package_folder-1.1.3/tests/test_subfolder_build.py +0 -362
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/.copier-answers.yml +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/.cursor/rules/general.mdc +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/.cursor/rules/python.mdc +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/.github/workflows/ci.yml +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/.github/workflows/publish.yml +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/.gitignore +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/.vscode/settings.json +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/LICENSE +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/Makefile +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/development.md +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/installation.md +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/publishing.md +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/pyproject.toml +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/src/python_package_folder/__init__.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/src/python_package_folder/__main__.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/src/python_package_folder/finder.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/src/python_package_folder/publisher.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/src/python_package_folder/py.typed +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/src/python_package_folder/types.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/src/python_package_folder/version.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/tests/folder_structure/some_globals.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/tests/folder_structure/subfolder_to_build/README.md +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/tests/folder_structure/subfolder_to_build/some_function.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/tests/folder_structure/utility_folder/_SS/some_superseded_file.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/tests/folder_structure/utility_folder/some_utility.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/tests/test_build_with_external_deps.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/tests/test_linting.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/tests/test_publisher.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/tests/test_utils.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/tests/test_version_manager.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/tests/tests.py +0 -0
- {python_package_folder-1.1.3 → python_package_folder-1.2.1}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-package-folder
|
|
3
|
-
Version: 1.1
|
|
3
|
+
Version: 1.2.1
|
|
4
4
|
Summary: Python package to automatically package and build a folder, fetching all relevant dependencies.
|
|
5
5
|
Project-URL: Repository, https://github.com/alelom/python-package-folder
|
|
6
6
|
Author-email: Alessio Lombardi <work@alelom.com>
|
|
@@ -125,9 +125,11 @@ This package will automatically:
|
|
|
125
125
|
|
|
126
126
|
## Features
|
|
127
127
|
|
|
128
|
-
- **Subfolder Build Support**: Build subfolders as separate packages with automatic
|
|
128
|
+
- **Subfolder Build Support**: Build subfolders as separate packages with automatic detection and configuration
|
|
129
|
+
- **Automatic subfolder detection**: Detects when building a subfolder (not the main `src/` directory)
|
|
129
130
|
- Creates any needed file for publishing automatically, cleaning up if not originally in the subfolder after the build/publish process. E.g. copies external dependencies into the source directory before build and cleans them up afterward; temporary `__init__.py` creation for non-package subfolders; uses subfolder README if present, otherwise creates minimal README
|
|
130
131
|
- Automatic package name derivation from subfolder name
|
|
132
|
+
- Automatic temporary `pyproject.toml` creation with correct package structure
|
|
131
133
|
- Dependency group selection: specify which dependency group from parent `pyproject.toml` to include.
|
|
132
134
|
|
|
133
135
|
- **Smart Import Classification and analysis**:
|
|
@@ -245,6 +247,7 @@ python-package-folder --project-root /path/to/project --src-dir /path/to/src --b
|
|
|
245
247
|
- If found, copies the subfolder README to project root (backing up the original parent README)
|
|
246
248
|
- If not found, creates a minimal README with just the folder name
|
|
247
249
|
5. **Configuration Creation**: Creates temporary `pyproject.toml` with:
|
|
250
|
+
- `[build-system]` section using hatchling (replaces any existing build-system configuration)
|
|
248
251
|
- Subfolder-specific package name (derived or custom)
|
|
249
252
|
- Specified version
|
|
250
253
|
- Correct package path for hatchling
|
|
@@ -268,16 +271,21 @@ cd my_project/subfolder_to_build
|
|
|
268
271
|
python-package-folder --version "1.0.0" --publish pypi
|
|
269
272
|
```
|
|
270
273
|
|
|
271
|
-
|
|
274
|
+
The tool **automatically detects** when you're building a subfolder (any directory that's not the main `src/` directory) and sets up the appropriate build configuration.
|
|
272
275
|
|
|
273
276
|
The tool automatically:
|
|
277
|
+
- **Detects subfolder builds**: Automatically identifies when building from a subdirectory
|
|
274
278
|
- Finds the project root by looking for `pyproject.toml` in parent directories
|
|
275
279
|
- Uses the current directory as the source directory if it contains Python files
|
|
276
280
|
- Falls back to `project_root/src` if the current directory isn't suitable
|
|
277
|
-
- For subfolder builds
|
|
278
|
-
-
|
|
279
|
-
-
|
|
280
|
-
|
|
281
|
+
- **For subfolder builds**: Handles `pyproject.toml` configuration:
|
|
282
|
+
- **If `pyproject.toml` exists in subfolder**: Uses that file (copies it to project root temporarily, adjusting package paths and ensuring `[build-system]` uses hatchling)
|
|
283
|
+
- **If no `pyproject.toml` in subfolder**: Creates a temporary `pyproject.toml` with:
|
|
284
|
+
- `[build-system]` section using hatchling (always uses hatchling, even if parent uses setuptools)
|
|
285
|
+
- Package name derived from the subfolder name (e.g., `empty_drawing_detection` → `empty-drawing-detection`)
|
|
286
|
+
- Version from `--version` argument (defaults to `0.0.0` with a warning if not provided)
|
|
287
|
+
- Proper package path configuration for hatchling
|
|
288
|
+
- Dependency groups from parent `pyproject.toml` if specified
|
|
281
289
|
- Creates temporary `__init__.py` files if needed to make subfolders valid Python packages
|
|
282
290
|
- **README handling for subfolder builds**:
|
|
283
291
|
- If a README file (README.md, README.rst, README.txt, or README) exists in the subfolder, it will be used instead of the parent README
|
|
@@ -285,6 +293,8 @@ The tool automatically:
|
|
|
285
293
|
- Restores the original `pyproject.toml` after build (unless `--no-restore-versioning` is used)
|
|
286
294
|
- Cleans up temporary `__init__.py` files after build
|
|
287
295
|
|
|
296
|
+
**Note**: While version is not strictly required (defaults to `0.0.0`), it's recommended to specify `--version` for subfolder builds to ensure proper versioning.
|
|
297
|
+
|
|
288
298
|
**Subfolder Build Example:**
|
|
289
299
|
```bash
|
|
290
300
|
# Build a subfolder as a separate package
|
|
@@ -293,6 +303,11 @@ python-package-folder --version "0.1.0" --package-name "my-subfolder-package" --
|
|
|
293
303
|
|
|
294
304
|
# Build with a specific dependency group from parent pyproject.toml
|
|
295
305
|
python-package-folder --version "0.1.0" --dependency-group "dev" --publish pypi
|
|
306
|
+
|
|
307
|
+
# If subfolder has its own pyproject.toml, it will be used automatically
|
|
308
|
+
# (package-name and version arguments are ignored in this case)
|
|
309
|
+
cd src/integration/my_package # assuming my_package/pyproject.toml exists
|
|
310
|
+
python-package-folder --publish pypi
|
|
296
311
|
```
|
|
297
312
|
|
|
298
313
|
**Dependency Groups**: When building a subfolder, you can specify a dependency group from the parent `pyproject.toml` to include in the subfolder's build configuration. This allows subfolders to inherit specific dependencies from the parent project:
|
|
@@ -308,6 +323,8 @@ The specified dependency group will be copied from the parent `pyproject.toml`'s
|
|
|
308
323
|
|
|
309
324
|
You can also use the package programmatically:
|
|
310
325
|
|
|
326
|
+
### Basic Usage
|
|
327
|
+
|
|
311
328
|
```python
|
|
312
329
|
from pathlib import Path
|
|
313
330
|
from python_package_folder import BuildManager
|
|
@@ -328,11 +345,11 @@ for dep in external_deps:
|
|
|
328
345
|
# Run your build process here
|
|
329
346
|
# ...
|
|
330
347
|
|
|
331
|
-
# Cleanup copied files
|
|
348
|
+
# Cleanup copied files (also restores pyproject.toml if subfolder build)
|
|
332
349
|
manager.cleanup()
|
|
333
350
|
```
|
|
334
351
|
|
|
335
|
-
|
|
352
|
+
### Using the Convenience Method
|
|
336
353
|
|
|
337
354
|
```python
|
|
338
355
|
from pathlib import Path
|
|
@@ -348,6 +365,55 @@ def build_command():
|
|
|
348
365
|
manager.run_build(build_command)
|
|
349
366
|
```
|
|
350
367
|
|
|
368
|
+
### Subfolder Builds (Automatic Detection)
|
|
369
|
+
|
|
370
|
+
The tool automatically detects when you're building a subfolder and sets up the appropriate configuration:
|
|
371
|
+
|
|
372
|
+
```python
|
|
373
|
+
from pathlib import Path
|
|
374
|
+
from python_package_folder import BuildManager
|
|
375
|
+
import subprocess
|
|
376
|
+
|
|
377
|
+
# Building a subfolder - automatic detection!
|
|
378
|
+
manager = BuildManager(
|
|
379
|
+
project_root=Path("."),
|
|
380
|
+
src_dir=Path("src/integration/empty_drawing_detection")
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
def build_command():
|
|
384
|
+
subprocess.run(["uv", "build"], check=True)
|
|
385
|
+
|
|
386
|
+
# prepare_build() automatically:
|
|
387
|
+
# - Detects this is a subfolder build
|
|
388
|
+
# - If pyproject.toml exists in subfolder: uses that file
|
|
389
|
+
# - If no pyproject.toml in subfolder: creates temporary one with package name "empty-drawing-detection"
|
|
390
|
+
# - Uses version "0.0.0" (or pass version="1.0.0" to override) if creating temporary pyproject.toml
|
|
391
|
+
external_deps = manager.prepare_build(version="1.0.0")
|
|
392
|
+
|
|
393
|
+
# Run build - uses the pyproject.toml (either from subfolder or temporary)
|
|
394
|
+
build_command()
|
|
395
|
+
|
|
396
|
+
# Cleanup restores original pyproject.toml and removes copied files
|
|
397
|
+
manager.cleanup()
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Note**: If the subfolder has its own `pyproject.toml`, it will be used automatically. The `version` and `package_name` parameters are only used when creating a temporary `pyproject.toml` from the parent configuration.
|
|
401
|
+
|
|
402
|
+
Or use the convenience method:
|
|
403
|
+
|
|
404
|
+
```python
|
|
405
|
+
manager = BuildManager(
|
|
406
|
+
project_root=Path("."),
|
|
407
|
+
src_dir=Path("src/integration/empty_drawing_detection")
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
def build_command():
|
|
411
|
+
subprocess.run(["uv", "build"], check=True)
|
|
412
|
+
|
|
413
|
+
# All handled automatically: subfolder detection, pyproject.toml setup, build, cleanup
|
|
414
|
+
manager.run_build(build_command, version="1.0.0", package_name="my-custom-name")
|
|
415
|
+
```
|
|
416
|
+
|
|
351
417
|
## Working with sysappend
|
|
352
418
|
|
|
353
419
|
This package works well with projects using [sysappend](https://pypi.org/project/sysappend/) for flexible import management. When you have imports like:
|
|
@@ -393,20 +459,28 @@ The `--version` option:
|
|
|
393
459
|
|
|
394
460
|
### Subfolder Versioning
|
|
395
461
|
|
|
396
|
-
When building from a subdirectory (not the main `src/` directory),
|
|
462
|
+
When building from a subdirectory (not the main `src/` directory), the tool automatically detects the subfolder and sets up the build configuration:
|
|
397
463
|
|
|
398
464
|
```bash
|
|
399
|
-
# Build a subfolder as a separate package
|
|
465
|
+
# Build a subfolder as a separate package (version recommended but not required)
|
|
400
466
|
cd my_project/subfolder_to_build
|
|
401
467
|
python-package-folder --version "1.0.0" --publish pypi
|
|
402
468
|
|
|
403
469
|
# With custom package name
|
|
404
470
|
python-package-folder --version "1.0.0" --package-name "my-custom-name" --publish pypi
|
|
471
|
+
|
|
472
|
+
# Version defaults to "0.0.0" if not specified (with a warning)
|
|
473
|
+
python-package-folder --publish pypi
|
|
405
474
|
```
|
|
406
475
|
|
|
407
476
|
For subfolder builds:
|
|
408
|
-
- **
|
|
409
|
-
- **
|
|
477
|
+
- **Automatic detection**: The tool automatically detects subfolder builds
|
|
478
|
+
- **pyproject.toml handling**:
|
|
479
|
+
- If `pyproject.toml` exists in subfolder: Uses that file (copied to project root temporarily)
|
|
480
|
+
- If no `pyproject.toml` in subfolder: Creates temporary one with correct package structure
|
|
481
|
+
- **Version**: Recommended but not required when creating temporary pyproject.toml. If not provided, defaults to `0.0.0` with a warning. Ignored if subfolder has its own `pyproject.toml`.
|
|
482
|
+
- **Package name**: Automatically derived from the subfolder name (e.g., `subfolder_to_build` → `subfolder-to-build`). Only used when creating temporary pyproject.toml.
|
|
483
|
+
- **Restoration**: Original `pyproject.toml` is restored after build
|
|
410
484
|
- **Temporary configuration**: Creates a temporary `pyproject.toml` with:
|
|
411
485
|
- Custom package name (from `--package-name` or derived)
|
|
412
486
|
- Specified version
|
|
@@ -715,7 +789,8 @@ version_manager.restore_dynamic_versioning()
|
|
|
715
789
|
|
|
716
790
|
### SubfolderBuildConfig
|
|
717
791
|
|
|
718
|
-
Manages temporary build configuration for subfolder builds.
|
|
792
|
+
Manages temporary build configuration for subfolder builds. If a `pyproject.toml` exists
|
|
793
|
+
in the subfolder, it will be used instead of creating a new one.
|
|
719
794
|
|
|
720
795
|
```python
|
|
721
796
|
from python_package_folder import SubfolderBuildConfig
|
|
@@ -724,11 +799,11 @@ from pathlib import Path
|
|
|
724
799
|
config = SubfolderBuildConfig(
|
|
725
800
|
project_root=Path("."),
|
|
726
801
|
src_dir=Path("subfolder"),
|
|
727
|
-
package_name="my-subfolder",
|
|
728
|
-
version="1.0.0"
|
|
802
|
+
package_name="my-subfolder", # Only used if subfolder has no pyproject.toml
|
|
803
|
+
version="1.0.0" # Only used if subfolder has no pyproject.toml
|
|
729
804
|
)
|
|
730
805
|
|
|
731
|
-
# Create temporary pyproject.toml
|
|
806
|
+
# Create temporary pyproject.toml (or use subfolder's if it exists)
|
|
732
807
|
config.create_temp_pyproject()
|
|
733
808
|
|
|
734
809
|
# ... build process ...
|
|
@@ -738,13 +813,13 @@ config.restore()
|
|
|
738
813
|
```
|
|
739
814
|
|
|
740
815
|
**Methods:**
|
|
741
|
-
- `create_temp_pyproject() -> Path`:
|
|
816
|
+
- `create_temp_pyproject() -> Path`: Use subfolder's `pyproject.toml` if it exists (adjusting package paths and ensuring `[build-system]` uses hatchling), otherwise create temporary `pyproject.toml` with subfolder-specific configuration including `[build-system]` section using hatchling
|
|
742
817
|
- `restore() -> None`: Restore original `pyproject.toml` and clean up temporary files
|
|
743
818
|
|
|
744
|
-
**Note**: This class automatically
|
|
745
|
-
- If a
|
|
746
|
-
- If no README exists in the subfolder, a minimal README with just the folder name will be created
|
|
747
|
-
-
|
|
819
|
+
**Note**: This class automatically:
|
|
820
|
+
- **pyproject.toml handling**: If a `pyproject.toml` exists in the subfolder, it will be used (copied to project root temporarily with adjusted package paths). Otherwise, creates a temporary one from the parent configuration. In both cases, the `[build-system]` section is always set to use hatchling, replacing any existing build-system configuration.
|
|
821
|
+
- **README handling**: If a README exists in the subfolder, it will be used instead of the parent README. If no README exists in the subfolder, a minimal README with just the folder name will be created. The original parent README is backed up and restored after the build completes.
|
|
822
|
+
- **Package initialization**: Creates `__init__.py` files if needed to make subfolders valid Python packages.
|
|
748
823
|
|
|
749
824
|
|
|
750
825
|
## Development
|
|
@@ -105,9 +105,11 @@ This package will automatically:
|
|
|
105
105
|
|
|
106
106
|
## Features
|
|
107
107
|
|
|
108
|
-
- **Subfolder Build Support**: Build subfolders as separate packages with automatic
|
|
108
|
+
- **Subfolder Build Support**: Build subfolders as separate packages with automatic detection and configuration
|
|
109
|
+
- **Automatic subfolder detection**: Detects when building a subfolder (not the main `src/` directory)
|
|
109
110
|
- Creates any needed file for publishing automatically, cleaning up if not originally in the subfolder after the build/publish process. E.g. copies external dependencies into the source directory before build and cleans them up afterward; temporary `__init__.py` creation for non-package subfolders; uses subfolder README if present, otherwise creates minimal README
|
|
110
111
|
- Automatic package name derivation from subfolder name
|
|
112
|
+
- Automatic temporary `pyproject.toml` creation with correct package structure
|
|
111
113
|
- Dependency group selection: specify which dependency group from parent `pyproject.toml` to include.
|
|
112
114
|
|
|
113
115
|
- **Smart Import Classification and analysis**:
|
|
@@ -225,6 +227,7 @@ python-package-folder --project-root /path/to/project --src-dir /path/to/src --b
|
|
|
225
227
|
- If found, copies the subfolder README to project root (backing up the original parent README)
|
|
226
228
|
- If not found, creates a minimal README with just the folder name
|
|
227
229
|
5. **Configuration Creation**: Creates temporary `pyproject.toml` with:
|
|
230
|
+
- `[build-system]` section using hatchling (replaces any existing build-system configuration)
|
|
228
231
|
- Subfolder-specific package name (derived or custom)
|
|
229
232
|
- Specified version
|
|
230
233
|
- Correct package path for hatchling
|
|
@@ -248,16 +251,21 @@ cd my_project/subfolder_to_build
|
|
|
248
251
|
python-package-folder --version "1.0.0" --publish pypi
|
|
249
252
|
```
|
|
250
253
|
|
|
251
|
-
|
|
254
|
+
The tool **automatically detects** when you're building a subfolder (any directory that's not the main `src/` directory) and sets up the appropriate build configuration.
|
|
252
255
|
|
|
253
256
|
The tool automatically:
|
|
257
|
+
- **Detects subfolder builds**: Automatically identifies when building from a subdirectory
|
|
254
258
|
- Finds the project root by looking for `pyproject.toml` in parent directories
|
|
255
259
|
- Uses the current directory as the source directory if it contains Python files
|
|
256
260
|
- Falls back to `project_root/src` if the current directory isn't suitable
|
|
257
|
-
- For subfolder builds
|
|
258
|
-
-
|
|
259
|
-
-
|
|
260
|
-
|
|
261
|
+
- **For subfolder builds**: Handles `pyproject.toml` configuration:
|
|
262
|
+
- **If `pyproject.toml` exists in subfolder**: Uses that file (copies it to project root temporarily, adjusting package paths and ensuring `[build-system]` uses hatchling)
|
|
263
|
+
- **If no `pyproject.toml` in subfolder**: Creates a temporary `pyproject.toml` with:
|
|
264
|
+
- `[build-system]` section using hatchling (always uses hatchling, even if parent uses setuptools)
|
|
265
|
+
- Package name derived from the subfolder name (e.g., `empty_drawing_detection` → `empty-drawing-detection`)
|
|
266
|
+
- Version from `--version` argument (defaults to `0.0.0` with a warning if not provided)
|
|
267
|
+
- Proper package path configuration for hatchling
|
|
268
|
+
- Dependency groups from parent `pyproject.toml` if specified
|
|
261
269
|
- Creates temporary `__init__.py` files if needed to make subfolders valid Python packages
|
|
262
270
|
- **README handling for subfolder builds**:
|
|
263
271
|
- If a README file (README.md, README.rst, README.txt, or README) exists in the subfolder, it will be used instead of the parent README
|
|
@@ -265,6 +273,8 @@ The tool automatically:
|
|
|
265
273
|
- Restores the original `pyproject.toml` after build (unless `--no-restore-versioning` is used)
|
|
266
274
|
- Cleans up temporary `__init__.py` files after build
|
|
267
275
|
|
|
276
|
+
**Note**: While version is not strictly required (defaults to `0.0.0`), it's recommended to specify `--version` for subfolder builds to ensure proper versioning.
|
|
277
|
+
|
|
268
278
|
**Subfolder Build Example:**
|
|
269
279
|
```bash
|
|
270
280
|
# Build a subfolder as a separate package
|
|
@@ -273,6 +283,11 @@ python-package-folder --version "0.1.0" --package-name "my-subfolder-package" --
|
|
|
273
283
|
|
|
274
284
|
# Build with a specific dependency group from parent pyproject.toml
|
|
275
285
|
python-package-folder --version "0.1.0" --dependency-group "dev" --publish pypi
|
|
286
|
+
|
|
287
|
+
# If subfolder has its own pyproject.toml, it will be used automatically
|
|
288
|
+
# (package-name and version arguments are ignored in this case)
|
|
289
|
+
cd src/integration/my_package # assuming my_package/pyproject.toml exists
|
|
290
|
+
python-package-folder --publish pypi
|
|
276
291
|
```
|
|
277
292
|
|
|
278
293
|
**Dependency Groups**: When building a subfolder, you can specify a dependency group from the parent `pyproject.toml` to include in the subfolder's build configuration. This allows subfolders to inherit specific dependencies from the parent project:
|
|
@@ -288,6 +303,8 @@ The specified dependency group will be copied from the parent `pyproject.toml`'s
|
|
|
288
303
|
|
|
289
304
|
You can also use the package programmatically:
|
|
290
305
|
|
|
306
|
+
### Basic Usage
|
|
307
|
+
|
|
291
308
|
```python
|
|
292
309
|
from pathlib import Path
|
|
293
310
|
from python_package_folder import BuildManager
|
|
@@ -308,11 +325,11 @@ for dep in external_deps:
|
|
|
308
325
|
# Run your build process here
|
|
309
326
|
# ...
|
|
310
327
|
|
|
311
|
-
# Cleanup copied files
|
|
328
|
+
# Cleanup copied files (also restores pyproject.toml if subfolder build)
|
|
312
329
|
manager.cleanup()
|
|
313
330
|
```
|
|
314
331
|
|
|
315
|
-
|
|
332
|
+
### Using the Convenience Method
|
|
316
333
|
|
|
317
334
|
```python
|
|
318
335
|
from pathlib import Path
|
|
@@ -328,6 +345,55 @@ def build_command():
|
|
|
328
345
|
manager.run_build(build_command)
|
|
329
346
|
```
|
|
330
347
|
|
|
348
|
+
### Subfolder Builds (Automatic Detection)
|
|
349
|
+
|
|
350
|
+
The tool automatically detects when you're building a subfolder and sets up the appropriate configuration:
|
|
351
|
+
|
|
352
|
+
```python
|
|
353
|
+
from pathlib import Path
|
|
354
|
+
from python_package_folder import BuildManager
|
|
355
|
+
import subprocess
|
|
356
|
+
|
|
357
|
+
# Building a subfolder - automatic detection!
|
|
358
|
+
manager = BuildManager(
|
|
359
|
+
project_root=Path("."),
|
|
360
|
+
src_dir=Path("src/integration/empty_drawing_detection")
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
def build_command():
|
|
364
|
+
subprocess.run(["uv", "build"], check=True)
|
|
365
|
+
|
|
366
|
+
# prepare_build() automatically:
|
|
367
|
+
# - Detects this is a subfolder build
|
|
368
|
+
# - If pyproject.toml exists in subfolder: uses that file
|
|
369
|
+
# - If no pyproject.toml in subfolder: creates temporary one with package name "empty-drawing-detection"
|
|
370
|
+
# - Uses version "0.0.0" (or pass version="1.0.0" to override) if creating temporary pyproject.toml
|
|
371
|
+
external_deps = manager.prepare_build(version="1.0.0")
|
|
372
|
+
|
|
373
|
+
# Run build - uses the pyproject.toml (either from subfolder or temporary)
|
|
374
|
+
build_command()
|
|
375
|
+
|
|
376
|
+
# Cleanup restores original pyproject.toml and removes copied files
|
|
377
|
+
manager.cleanup()
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
**Note**: If the subfolder has its own `pyproject.toml`, it will be used automatically. The `version` and `package_name` parameters are only used when creating a temporary `pyproject.toml` from the parent configuration.
|
|
381
|
+
|
|
382
|
+
Or use the convenience method:
|
|
383
|
+
|
|
384
|
+
```python
|
|
385
|
+
manager = BuildManager(
|
|
386
|
+
project_root=Path("."),
|
|
387
|
+
src_dir=Path("src/integration/empty_drawing_detection")
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
def build_command():
|
|
391
|
+
subprocess.run(["uv", "build"], check=True)
|
|
392
|
+
|
|
393
|
+
# All handled automatically: subfolder detection, pyproject.toml setup, build, cleanup
|
|
394
|
+
manager.run_build(build_command, version="1.0.0", package_name="my-custom-name")
|
|
395
|
+
```
|
|
396
|
+
|
|
331
397
|
## Working with sysappend
|
|
332
398
|
|
|
333
399
|
This package works well with projects using [sysappend](https://pypi.org/project/sysappend/) for flexible import management. When you have imports like:
|
|
@@ -373,20 +439,28 @@ The `--version` option:
|
|
|
373
439
|
|
|
374
440
|
### Subfolder Versioning
|
|
375
441
|
|
|
376
|
-
When building from a subdirectory (not the main `src/` directory),
|
|
442
|
+
When building from a subdirectory (not the main `src/` directory), the tool automatically detects the subfolder and sets up the build configuration:
|
|
377
443
|
|
|
378
444
|
```bash
|
|
379
|
-
# Build a subfolder as a separate package
|
|
445
|
+
# Build a subfolder as a separate package (version recommended but not required)
|
|
380
446
|
cd my_project/subfolder_to_build
|
|
381
447
|
python-package-folder --version "1.0.0" --publish pypi
|
|
382
448
|
|
|
383
449
|
# With custom package name
|
|
384
450
|
python-package-folder --version "1.0.0" --package-name "my-custom-name" --publish pypi
|
|
451
|
+
|
|
452
|
+
# Version defaults to "0.0.0" if not specified (with a warning)
|
|
453
|
+
python-package-folder --publish pypi
|
|
385
454
|
```
|
|
386
455
|
|
|
387
456
|
For subfolder builds:
|
|
388
|
-
- **
|
|
389
|
-
- **
|
|
457
|
+
- **Automatic detection**: The tool automatically detects subfolder builds
|
|
458
|
+
- **pyproject.toml handling**:
|
|
459
|
+
- If `pyproject.toml` exists in subfolder: Uses that file (copied to project root temporarily)
|
|
460
|
+
- If no `pyproject.toml` in subfolder: Creates temporary one with correct package structure
|
|
461
|
+
- **Version**: Recommended but not required when creating temporary pyproject.toml. If not provided, defaults to `0.0.0` with a warning. Ignored if subfolder has its own `pyproject.toml`.
|
|
462
|
+
- **Package name**: Automatically derived from the subfolder name (e.g., `subfolder_to_build` → `subfolder-to-build`). Only used when creating temporary pyproject.toml.
|
|
463
|
+
- **Restoration**: Original `pyproject.toml` is restored after build
|
|
390
464
|
- **Temporary configuration**: Creates a temporary `pyproject.toml` with:
|
|
391
465
|
- Custom package name (from `--package-name` or derived)
|
|
392
466
|
- Specified version
|
|
@@ -695,7 +769,8 @@ version_manager.restore_dynamic_versioning()
|
|
|
695
769
|
|
|
696
770
|
### SubfolderBuildConfig
|
|
697
771
|
|
|
698
|
-
Manages temporary build configuration for subfolder builds.
|
|
772
|
+
Manages temporary build configuration for subfolder builds. If a `pyproject.toml` exists
|
|
773
|
+
in the subfolder, it will be used instead of creating a new one.
|
|
699
774
|
|
|
700
775
|
```python
|
|
701
776
|
from python_package_folder import SubfolderBuildConfig
|
|
@@ -704,11 +779,11 @@ from pathlib import Path
|
|
|
704
779
|
config = SubfolderBuildConfig(
|
|
705
780
|
project_root=Path("."),
|
|
706
781
|
src_dir=Path("subfolder"),
|
|
707
|
-
package_name="my-subfolder",
|
|
708
|
-
version="1.0.0"
|
|
782
|
+
package_name="my-subfolder", # Only used if subfolder has no pyproject.toml
|
|
783
|
+
version="1.0.0" # Only used if subfolder has no pyproject.toml
|
|
709
784
|
)
|
|
710
785
|
|
|
711
|
-
# Create temporary pyproject.toml
|
|
786
|
+
# Create temporary pyproject.toml (or use subfolder's if it exists)
|
|
712
787
|
config.create_temp_pyproject()
|
|
713
788
|
|
|
714
789
|
# ... build process ...
|
|
@@ -718,13 +793,13 @@ config.restore()
|
|
|
718
793
|
```
|
|
719
794
|
|
|
720
795
|
**Methods:**
|
|
721
|
-
- `create_temp_pyproject() -> Path`:
|
|
796
|
+
- `create_temp_pyproject() -> Path`: Use subfolder's `pyproject.toml` if it exists (adjusting package paths and ensuring `[build-system]` uses hatchling), otherwise create temporary `pyproject.toml` with subfolder-specific configuration including `[build-system]` section using hatchling
|
|
722
797
|
- `restore() -> None`: Restore original `pyproject.toml` and clean up temporary files
|
|
723
798
|
|
|
724
|
-
**Note**: This class automatically
|
|
725
|
-
- If a
|
|
726
|
-
- If no README exists in the subfolder, a minimal README with just the folder name will be created
|
|
727
|
-
-
|
|
799
|
+
**Note**: This class automatically:
|
|
800
|
+
- **pyproject.toml handling**: If a `pyproject.toml` exists in the subfolder, it will be used (copied to project root temporarily with adjusted package paths). Otherwise, creates a temporary one from the parent configuration. In both cases, the `[build-system]` section is always set to use hatchling, replacing any existing build-system configuration.
|
|
801
|
+
- **README handling**: If a README exists in the subfolder, it will be used instead of the parent README. If no README exists in the subfolder, a minimal README with just the folder name will be created. The original parent README is backed up and restored after the build completes.
|
|
802
|
+
- **Package initialization**: Creates `__init__.py` files if needed to make subfolders valid Python packages.
|
|
728
803
|
|
|
729
804
|
|
|
730
805
|
## Development
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
|
|
15
15
|
<text x="31.5" y="15" fill="#010101" fill-opacity=".3">coverage</text>
|
|
16
16
|
<text x="31.5" y="14">coverage</text>
|
|
17
|
-
<text x="81" y="15" fill="#010101" fill-opacity=".3">
|
|
18
|
-
<text x="81" y="14">
|
|
17
|
+
<text x="81" y="15" fill="#010101" fill-opacity=".3">68%</text>
|
|
18
|
+
<text x="81" y="14">68%</text>
|
|
19
19
|
</g>
|
|
20
20
|
</svg>
|
{python_package_folder-1.1.3 → python_package_folder-1.2.1}/src/python_package_folder/analyzer.py
RENAMED
|
@@ -45,13 +45,55 @@ class ImportAnalyzer:
|
|
|
45
45
|
"""
|
|
46
46
|
Recursively find all Python files in a directory.
|
|
47
47
|
|
|
48
|
+
Excludes common directories like .venv, venv, __pycache__, etc.
|
|
49
|
+
|
|
48
50
|
Args:
|
|
49
51
|
directory: Directory to search for Python files
|
|
50
52
|
|
|
51
53
|
Returns:
|
|
52
54
|
List of paths to all .py files found in the directory tree
|
|
53
55
|
"""
|
|
54
|
-
|
|
56
|
+
exclude_patterns = {
|
|
57
|
+
".venv",
|
|
58
|
+
"venv",
|
|
59
|
+
"__pycache__",
|
|
60
|
+
".git",
|
|
61
|
+
".pytest_cache",
|
|
62
|
+
".mypy_cache",
|
|
63
|
+
"node_modules",
|
|
64
|
+
".tox",
|
|
65
|
+
"dist",
|
|
66
|
+
"build",
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
python_files = []
|
|
70
|
+
for path in directory.rglob("*.py"):
|
|
71
|
+
if not path.is_file():
|
|
72
|
+
continue
|
|
73
|
+
|
|
74
|
+
# Check if any part of the path matches exclusion patterns
|
|
75
|
+
should_exclude = False
|
|
76
|
+
for part in path.parts:
|
|
77
|
+
# Check exact matches
|
|
78
|
+
if part in exclude_patterns:
|
|
79
|
+
should_exclude = True
|
|
80
|
+
break
|
|
81
|
+
# Check if part starts with excluded pattern or contains .egg-info
|
|
82
|
+
for pattern in exclude_patterns:
|
|
83
|
+
if part.startswith(pattern):
|
|
84
|
+
should_exclude = True
|
|
85
|
+
break
|
|
86
|
+
# Also exclude .egg-info directories
|
|
87
|
+
if ".egg-info" in part:
|
|
88
|
+
should_exclude = True
|
|
89
|
+
break
|
|
90
|
+
if should_exclude:
|
|
91
|
+
break
|
|
92
|
+
|
|
93
|
+
if not should_exclude:
|
|
94
|
+
python_files.append(path)
|
|
95
|
+
|
|
96
|
+
return python_files
|
|
55
97
|
|
|
56
98
|
def extract_imports(self, file_path: Path) -> list[ImportInfo]:
|
|
57
99
|
"""
|