python-package-folder 1.2.0__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.2.0 → python_package_folder-1.2.1}/PKG-INFO +6 -4
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/README.md +5 -3
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/coverage.svg +2 -2
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/analyzer.py +43 -1
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/python_package_folder.py +2 -1
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/subfolder_build.py +124 -6
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/utils.py +7 -5
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/tests/test_subfolder_build.py +73 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/.copier-answers.yml +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/.cursor/rules/general.mdc +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/.cursor/rules/python.mdc +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/.github/workflows/ci.yml +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/.github/workflows/publish.yml +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/.gitignore +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/.vscode/settings.json +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/LICENSE +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/Makefile +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/development.md +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/installation.md +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/publishing.md +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/pyproject.toml +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/__init__.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/__main__.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/finder.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/manager.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/publisher.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/py.typed +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/types.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/version.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/tests/folder_structure/some_globals.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/tests/folder_structure/subfolder_to_build/README.md +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/tests/folder_structure/subfolder_to_build/some_function.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/tests/folder_structure/utility_folder/_SS/some_superseded_file.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/tests/folder_structure/utility_folder/some_utility.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/tests/test_build_with_external_deps.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/tests/test_linting.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/tests/test_publisher.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/tests/test_utils.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/tests/test_version_manager.py +0 -0
- {python_package_folder-1.2.0 → python_package_folder-1.2.1}/tests/tests.py +0 -0
- {python_package_folder-1.2.0 → 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.2.
|
|
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>
|
|
@@ -247,6 +247,7 @@ python-package-folder --project-root /path/to/project --src-dir /path/to/src --b
|
|
|
247
247
|
- If found, copies the subfolder README to project root (backing up the original parent README)
|
|
248
248
|
- If not found, creates a minimal README with just the folder name
|
|
249
249
|
5. **Configuration Creation**: Creates temporary `pyproject.toml` with:
|
|
250
|
+
- `[build-system]` section using hatchling (replaces any existing build-system configuration)
|
|
250
251
|
- Subfolder-specific package name (derived or custom)
|
|
251
252
|
- Specified version
|
|
252
253
|
- Correct package path for hatchling
|
|
@@ -278,8 +279,9 @@ The tool automatically:
|
|
|
278
279
|
- Uses the current directory as the source directory if it contains Python files
|
|
279
280
|
- Falls back to `project_root/src` if the current directory isn't suitable
|
|
280
281
|
- **For subfolder builds**: Handles `pyproject.toml` configuration:
|
|
281
|
-
- **If `pyproject.toml` exists in subfolder**: Uses that file (copies it to project root temporarily)
|
|
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)
|
|
282
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)
|
|
283
285
|
- Package name derived from the subfolder name (e.g., `empty_drawing_detection` → `empty-drawing-detection`)
|
|
284
286
|
- Version from `--version` argument (defaults to `0.0.0` with a warning if not provided)
|
|
285
287
|
- Proper package path configuration for hatchling
|
|
@@ -811,11 +813,11 @@ config.restore()
|
|
|
811
813
|
```
|
|
812
814
|
|
|
813
815
|
**Methods:**
|
|
814
|
-
- `create_temp_pyproject() -> Path`: Use subfolder's `pyproject.toml` if it exists, otherwise create temporary `pyproject.toml` with subfolder-specific configuration
|
|
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
|
|
815
817
|
- `restore() -> None`: Restore original `pyproject.toml` and clean up temporary files
|
|
816
818
|
|
|
817
819
|
**Note**: This class automatically:
|
|
818
|
-
- **pyproject.toml handling**: If a `pyproject.toml` exists in the subfolder, it will be used (copied to project root temporarily). Otherwise, creates a temporary one from the parent configuration.
|
|
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.
|
|
819
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.
|
|
820
822
|
- **Package initialization**: Creates `__init__.py` files if needed to make subfolders valid Python packages.
|
|
821
823
|
|
|
@@ -227,6 +227,7 @@ python-package-folder --project-root /path/to/project --src-dir /path/to/src --b
|
|
|
227
227
|
- If found, copies the subfolder README to project root (backing up the original parent README)
|
|
228
228
|
- If not found, creates a minimal README with just the folder name
|
|
229
229
|
5. **Configuration Creation**: Creates temporary `pyproject.toml` with:
|
|
230
|
+
- `[build-system]` section using hatchling (replaces any existing build-system configuration)
|
|
230
231
|
- Subfolder-specific package name (derived or custom)
|
|
231
232
|
- Specified version
|
|
232
233
|
- Correct package path for hatchling
|
|
@@ -258,8 +259,9 @@ The tool automatically:
|
|
|
258
259
|
- Uses the current directory as the source directory if it contains Python files
|
|
259
260
|
- Falls back to `project_root/src` if the current directory isn't suitable
|
|
260
261
|
- **For subfolder builds**: Handles `pyproject.toml` configuration:
|
|
261
|
-
- **If `pyproject.toml` exists in subfolder**: Uses that file (copies it to project root temporarily)
|
|
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)
|
|
262
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)
|
|
263
265
|
- Package name derived from the subfolder name (e.g., `empty_drawing_detection` → `empty-drawing-detection`)
|
|
264
266
|
- Version from `--version` argument (defaults to `0.0.0` with a warning if not provided)
|
|
265
267
|
- Proper package path configuration for hatchling
|
|
@@ -791,11 +793,11 @@ config.restore()
|
|
|
791
793
|
```
|
|
792
794
|
|
|
793
795
|
**Methods:**
|
|
794
|
-
- `create_temp_pyproject() -> Path`: Use subfolder's `pyproject.toml` if it exists, otherwise create temporary `pyproject.toml` with subfolder-specific configuration
|
|
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
|
|
795
797
|
- `restore() -> None`: Restore original `pyproject.toml` and clean up temporary files
|
|
796
798
|
|
|
797
799
|
**Note**: This class automatically:
|
|
798
|
-
- **pyproject.toml handling**: If a `pyproject.toml` exists in the subfolder, it will be used (copied to project root temporarily). Otherwise, creates a temporary one from the parent configuration.
|
|
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.
|
|
799
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.
|
|
800
802
|
- **Package initialization**: Creates `__init__.py` files if needed to make subfolders valid Python packages.
|
|
801
803
|
|
|
@@ -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.2.0 → 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
|
"""
|
|
@@ -122,7 +122,8 @@ def main() -> int:
|
|
|
122
122
|
src_dir = Path(args.src_dir).resolve()
|
|
123
123
|
else:
|
|
124
124
|
# Auto-detect: use current directory if it has Python files, otherwise use project_root/src
|
|
125
|
-
|
|
125
|
+
current_dir = Path.cwd()
|
|
126
|
+
src_dir = find_source_directory(project_root, current_dir=current_dir)
|
|
126
127
|
if src_dir:
|
|
127
128
|
print(f"Auto-detected source directory: {src_dir}")
|
|
128
129
|
else:
|
|
@@ -30,8 +30,11 @@ class SubfolderBuildConfig:
|
|
|
30
30
|
Manages temporary build configuration for subfolder builds.
|
|
31
31
|
|
|
32
32
|
When building a subfolder as a separate package, this class:
|
|
33
|
-
- Uses the subfolder's pyproject.toml if it exists
|
|
33
|
+
- Uses the subfolder's pyproject.toml if it exists (adjusts package paths and ensures
|
|
34
|
+
[build-system] uses hatchling)
|
|
34
35
|
- Otherwise creates a temporary pyproject.toml with the appropriate package name and version
|
|
36
|
+
- Always ensures [build-system] section uses hatchling (replaces any existing build-system
|
|
37
|
+
configuration from parent or subfolder)
|
|
35
38
|
- Handles README files similarly (uses subfolder README if present)
|
|
36
39
|
"""
|
|
37
40
|
|
|
@@ -111,13 +114,96 @@ class SubfolderBuildConfig:
|
|
|
111
114
|
# If it's a package or has subpackages, return the path
|
|
112
115
|
return packages_path, [packages_path] if packages_path else []
|
|
113
116
|
|
|
117
|
+
def _adjust_subfolder_pyproject_packages_path(self, content: str) -> str:
|
|
118
|
+
"""
|
|
119
|
+
Adjust packages path in subfolder pyproject.toml to be relative to project root.
|
|
120
|
+
|
|
121
|
+
When a subfolder's pyproject.toml is copied to project root, the packages path
|
|
122
|
+
needs to be adjusted to point to the subfolder relative to the project root.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
content: Content of the subfolder's pyproject.toml
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
Adjusted content with correct packages path
|
|
129
|
+
"""
|
|
130
|
+
# Get the correct packages path relative to project root
|
|
131
|
+
_, package_dirs = self._get_package_structure()
|
|
132
|
+
if not package_dirs:
|
|
133
|
+
# No adjustment needed if we can't determine the path
|
|
134
|
+
return content
|
|
135
|
+
|
|
136
|
+
correct_packages_path = package_dirs[0]
|
|
137
|
+
lines = content.split("\n")
|
|
138
|
+
result = []
|
|
139
|
+
in_hatch_build = False
|
|
140
|
+
packages_set = False
|
|
141
|
+
|
|
142
|
+
for line in lines:
|
|
143
|
+
# Detect hatch build section
|
|
144
|
+
if line.strip().startswith("[tool.hatch.build.targets.wheel]"):
|
|
145
|
+
in_hatch_build = True
|
|
146
|
+
result.append(line)
|
|
147
|
+
continue
|
|
148
|
+
elif line.strip().startswith("[") and in_hatch_build:
|
|
149
|
+
# End of hatch build section, add packages if not set
|
|
150
|
+
if not packages_set and correct_packages_path:
|
|
151
|
+
packages_str = f'"{correct_packages_path}"'
|
|
152
|
+
result.append(f"packages = [{packages_str}]")
|
|
153
|
+
in_hatch_build = False
|
|
154
|
+
result.append(line)
|
|
155
|
+
elif in_hatch_build:
|
|
156
|
+
# Modify packages path if found
|
|
157
|
+
if re.match(r"^\s*packages\s*=", line):
|
|
158
|
+
packages_str = f'"{correct_packages_path}"'
|
|
159
|
+
result.append(f"packages = [{packages_str}]")
|
|
160
|
+
packages_set = True
|
|
161
|
+
continue
|
|
162
|
+
# Keep other lines in hatch build section
|
|
163
|
+
result.append(line)
|
|
164
|
+
else:
|
|
165
|
+
result.append(line)
|
|
166
|
+
|
|
167
|
+
# Add packages if we're still in hatch build section and haven't set it
|
|
168
|
+
if in_hatch_build and not packages_set and correct_packages_path:
|
|
169
|
+
packages_str = f'"{correct_packages_path}"'
|
|
170
|
+
result.append(f"packages = [{packages_str}]")
|
|
171
|
+
|
|
172
|
+
# Ensure build-system section exists (required for hatchling)
|
|
173
|
+
# Check if build-system section exists in the result
|
|
174
|
+
has_build_system = any(line.strip().startswith("[build-system]") for line in result)
|
|
175
|
+
if not has_build_system:
|
|
176
|
+
# Insert build-system at the very beginning of the file
|
|
177
|
+
build_system_lines = [
|
|
178
|
+
"[build-system]",
|
|
179
|
+
'requires = ["hatchling"]',
|
|
180
|
+
'build-backend = "hatchling.build"',
|
|
181
|
+
"",
|
|
182
|
+
]
|
|
183
|
+
result = build_system_lines + result
|
|
184
|
+
|
|
185
|
+
# Ensure hatch build section exists if packages path is needed
|
|
186
|
+
if not packages_set and correct_packages_path:
|
|
187
|
+
# Check if we need to add the section
|
|
188
|
+
if "[tool.hatch.build.targets.wheel]" not in content:
|
|
189
|
+
result.append("")
|
|
190
|
+
result.append("[tool.hatch.build.targets.wheel]")
|
|
191
|
+
packages_str = f'"{correct_packages_path}"'
|
|
192
|
+
result.append(f"packages = [{packages_str}]")
|
|
193
|
+
|
|
194
|
+
return "\n".join(result)
|
|
195
|
+
|
|
114
196
|
def create_temp_pyproject(self) -> Path | None:
|
|
115
197
|
"""
|
|
116
198
|
Create a temporary pyproject.toml for the subfolder build.
|
|
117
199
|
|
|
118
|
-
If a pyproject.toml exists in the subfolder, it will be used
|
|
119
|
-
|
|
120
|
-
|
|
200
|
+
If a pyproject.toml exists in the subfolder, it will be used (copied to project root
|
|
201
|
+
with adjusted package paths and ensuring [build-system] uses hatchling). Otherwise,
|
|
202
|
+
creates a pyproject.toml in the project root based on the parent pyproject.toml with
|
|
203
|
+
the appropriate package name and version.
|
|
204
|
+
|
|
205
|
+
The [build-system] section is always set to use hatchling, even if the parent or
|
|
206
|
+
subfolder pyproject.toml uses a different build backend (e.g., setuptools).
|
|
121
207
|
|
|
122
208
|
Returns:
|
|
123
209
|
Path to the pyproject.toml file (either from subfolder or created temporary),
|
|
@@ -149,8 +235,13 @@ class SubfolderBuildConfig:
|
|
|
149
235
|
shutil.copy2(original_pyproject, backup_path)
|
|
150
236
|
self.original_pyproject_backup = backup_path
|
|
151
237
|
|
|
152
|
-
#
|
|
153
|
-
|
|
238
|
+
# Read and adjust the subfolder pyproject.toml
|
|
239
|
+
subfolder_content = subfolder_pyproject.read_text(encoding="utf-8")
|
|
240
|
+
# Adjust packages path to be relative to project root
|
|
241
|
+
adjusted_content = self._adjust_subfolder_pyproject_packages_path(subfolder_content)
|
|
242
|
+
|
|
243
|
+
# Write adjusted content to project root
|
|
244
|
+
original_pyproject.write_text(adjusted_content, encoding="utf-8")
|
|
154
245
|
self.temp_pyproject = original_pyproject
|
|
155
246
|
|
|
156
247
|
# Handle README file
|
|
@@ -259,6 +350,7 @@ class SubfolderBuildConfig:
|
|
|
259
350
|
skip_uv_dynamic = False
|
|
260
351
|
in_hatch_build = False
|
|
261
352
|
packages_set = False
|
|
353
|
+
build_system_set = False
|
|
262
354
|
|
|
263
355
|
# Get package structure
|
|
264
356
|
packages_path, package_dirs = self._get_package_structure()
|
|
@@ -266,6 +358,19 @@ class SubfolderBuildConfig:
|
|
|
266
358
|
package_dirs = []
|
|
267
359
|
|
|
268
360
|
for _i, line in enumerate(lines):
|
|
361
|
+
# Skip build-system section - we'll add our own for subfolder builds
|
|
362
|
+
if line.strip().startswith("[build-system]"):
|
|
363
|
+
build_system_set = True
|
|
364
|
+
continue # Skip the [build-system] line
|
|
365
|
+
elif build_system_set and line.strip().startswith("["):
|
|
366
|
+
# End of build-system section
|
|
367
|
+
build_system_set = False
|
|
368
|
+
result.append(line)
|
|
369
|
+
continue
|
|
370
|
+
elif build_system_set:
|
|
371
|
+
# Skip build-system content - we'll add our own
|
|
372
|
+
continue
|
|
373
|
+
|
|
269
374
|
# Skip hatch versioning and uv-dynamic-versioning sections
|
|
270
375
|
if line.strip().startswith("[tool.hatch.version]"):
|
|
271
376
|
skip_hatch_version = True
|
|
@@ -361,6 +466,19 @@ class SubfolderBuildConfig:
|
|
|
361
466
|
packages_str = ", ".join(f'"{p}"' for p in package_dirs)
|
|
362
467
|
result.append(f"packages = [{packages_str}]")
|
|
363
468
|
|
|
469
|
+
# Ensure build-system section exists (required for hatchling)
|
|
470
|
+
# Check if build-system section exists in the result
|
|
471
|
+
has_build_system = any(line.strip().startswith("[build-system]") for line in result)
|
|
472
|
+
if not has_build_system:
|
|
473
|
+
# Insert build-system at the very beginning of the file
|
|
474
|
+
build_system_lines = [
|
|
475
|
+
"[build-system]",
|
|
476
|
+
'requires = ["hatchling"]',
|
|
477
|
+
'build-backend = "hatchling.build"',
|
|
478
|
+
"",
|
|
479
|
+
]
|
|
480
|
+
result = build_system_lines + result
|
|
481
|
+
|
|
364
482
|
# Ensure packages is always set for subfolder builds
|
|
365
483
|
if not packages_set and package_dirs:
|
|
366
484
|
# Add the section if it doesn't exist
|
{python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/utils.py
RENAMED
|
@@ -63,7 +63,8 @@ def find_source_directory(project_root: Path, current_dir: Path | None = None) -
|
|
|
63
63
|
project_root = project_root.resolve()
|
|
64
64
|
|
|
65
65
|
# Check if current directory is a subdirectory with Python files
|
|
66
|
-
if
|
|
66
|
+
# Prioritize current directory if it's within the project and has Python files
|
|
67
|
+
if current_dir.is_relative_to(project_root) and current_dir != project_root:
|
|
67
68
|
python_files = list(current_dir.glob("*.py"))
|
|
68
69
|
if python_files:
|
|
69
70
|
# Current directory has Python files, use it as source
|
|
@@ -74,10 +75,11 @@ def find_source_directory(project_root: Path, current_dir: Path | None = None) -
|
|
|
74
75
|
if src_dir.exists() and src_dir.is_dir():
|
|
75
76
|
return src_dir
|
|
76
77
|
|
|
77
|
-
#
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
# Only check project_root if current_dir is the project_root
|
|
79
|
+
if current_dir == project_root:
|
|
80
|
+
python_files = list(project_root.glob("*.py"))
|
|
81
|
+
if python_files:
|
|
82
|
+
return project_root
|
|
81
83
|
|
|
82
84
|
return None
|
|
83
85
|
|
|
@@ -584,6 +584,11 @@ class TestSubfolderBuildTemporaryPyprojectCreation:
|
|
|
584
584
|
|
|
585
585
|
# Verify dynamic versioning is removed
|
|
586
586
|
assert 'dynamic = ["version"]' not in content
|
|
587
|
+
|
|
588
|
+
# Verify build-system section is added (required for hatchling)
|
|
589
|
+
assert "[build-system]" in content
|
|
590
|
+
assert 'requires = ["hatchling"]' in content
|
|
591
|
+
assert 'build-backend = "hatchling.build"' in content
|
|
587
592
|
assert "[tool.hatch.version]" not in content
|
|
588
593
|
assert "[tool.uv-dynamic-versioning]" not in content
|
|
589
594
|
|
|
@@ -648,3 +653,71 @@ class TestSubfolderBuildTemporaryPyprojectCreation:
|
|
|
648
653
|
restored_content = (project_root / "pyproject.toml").read_text()
|
|
649
654
|
assert restored_content == original_content
|
|
650
655
|
assert 'name = "test-package"' in restored_content
|
|
656
|
+
|
|
657
|
+
def test_build_system_section_replaces_setuptools(
|
|
658
|
+
self, test_project_with_pyproject: Path
|
|
659
|
+
) -> None:
|
|
660
|
+
"""Test that build-system section replaces existing setuptools configuration."""
|
|
661
|
+
project_root = test_project_with_pyproject
|
|
662
|
+
subfolder = project_root / "subfolder"
|
|
663
|
+
|
|
664
|
+
# Modify parent pyproject.toml to have setuptools build-system
|
|
665
|
+
pyproject_path = project_root / "pyproject.toml"
|
|
666
|
+
original_content = pyproject_path.read_text()
|
|
667
|
+
modified_content = (
|
|
668
|
+
original_content
|
|
669
|
+
+ '\n[build-system]\nrequires = ["setuptools"]\nbuild-backend = "setuptools.build_meta"\n'
|
|
670
|
+
)
|
|
671
|
+
pyproject_path.write_text(modified_content)
|
|
672
|
+
|
|
673
|
+
try:
|
|
674
|
+
config = SubfolderBuildConfig(
|
|
675
|
+
project_root=project_root,
|
|
676
|
+
src_dir=subfolder,
|
|
677
|
+
version="1.0.0",
|
|
678
|
+
)
|
|
679
|
+
|
|
680
|
+
pyproject_path = config.create_temp_pyproject()
|
|
681
|
+
content = pyproject_path.read_text()
|
|
682
|
+
|
|
683
|
+
# Verify build-system section uses hatchling, not setuptools
|
|
684
|
+
assert "[build-system]" in content
|
|
685
|
+
assert 'requires = ["hatchling"]' in content
|
|
686
|
+
assert 'build-backend = "hatchling.build"' in content
|
|
687
|
+
assert "setuptools" not in content or 'build-backend = "setuptools' not in content
|
|
688
|
+
|
|
689
|
+
config.restore()
|
|
690
|
+
finally:
|
|
691
|
+
# Restore original content
|
|
692
|
+
pyproject_path.write_text(original_content)
|
|
693
|
+
|
|
694
|
+
def test_build_system_section_with_subfolder_pyproject(
|
|
695
|
+
self, test_project_with_pyproject: Path
|
|
696
|
+
) -> None:
|
|
697
|
+
"""Test that build-system section is added when using subfolder's pyproject.toml."""
|
|
698
|
+
project_root = test_project_with_pyproject
|
|
699
|
+
subfolder = project_root / "subfolder"
|
|
700
|
+
|
|
701
|
+
# Create pyproject.toml in subfolder without build-system
|
|
702
|
+
subfolder_pyproject_content = """[project]
|
|
703
|
+
name = "subfolder-package"
|
|
704
|
+
version = "3.0.0"
|
|
705
|
+
description = "Subfolder package"
|
|
706
|
+
"""
|
|
707
|
+
(subfolder / "pyproject.toml").write_text(subfolder_pyproject_content)
|
|
708
|
+
|
|
709
|
+
config = SubfolderBuildConfig(
|
|
710
|
+
project_root=project_root,
|
|
711
|
+
src_dir=subfolder,
|
|
712
|
+
version="1.0.0",
|
|
713
|
+
)
|
|
714
|
+
|
|
715
|
+
pyproject_path = config.create_temp_pyproject()
|
|
716
|
+
content = pyproject_path.read_text()
|
|
717
|
+
|
|
718
|
+
# Verify build-system section is added
|
|
719
|
+
assert "[build-system]" in content
|
|
720
|
+
assert 'requires = ["hatchling"]' in content
|
|
721
|
+
assert 'build-backend = "hatchling.build"' in content
|
|
722
|
+
|
|
723
|
+
config.restore()
|
|
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
|
|
File without changes
|
|
File without changes
|
{python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/__init__.py
RENAMED
|
File without changes
|
{python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/__main__.py
RENAMED
|
File without changes
|
{python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/finder.py
RENAMED
|
File without changes
|
{python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/manager.py
RENAMED
|
File without changes
|
{python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/publisher.py
RENAMED
|
File without changes
|
{python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/py.typed
RENAMED
|
File without changes
|
{python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/types.py
RENAMED
|
File without changes
|
{python_package_folder-1.2.0 → python_package_folder-1.2.1}/src/python_package_folder/version.py
RENAMED
|
File without changes
|
{python_package_folder-1.2.0 → python_package_folder-1.2.1}/tests/folder_structure/some_globals.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_package_folder-1.2.0 → python_package_folder-1.2.1}/tests/test_build_with_external_deps.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|