python-package-folder 5.3.0__tar.gz → 6.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/PKG-INFO +1 -1
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/coverage.svg +2 -2
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/pyproject.toml +1 -1
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/analyzer.py +22 -45
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/manager.py +58 -10
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/python_package_folder.py +83 -10
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/subfolder_build.py +111 -13
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/test_build_with_external_deps.py +14 -6
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/test_preserve_directory_structure.py +4 -2
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/test_spreadsheet_creation_imports.py +3 -1
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/test_subfolder_build.py +198 -11
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/.copier-answers.yml +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/.cursor/plans/optional_version_+_semantic-release_efed88a6.plan.md +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/.cursor/plans/replace_node.js_semantic-release_with_custom_python_implementation_64e05e1a.plan.md +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/.cursor/rules/general.mdc +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/.cursor/rules/python.mdc +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/.github/workflows/ci.yml +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/.github/workflows/publish.yml +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/.gitignore +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/.vscode/settings.json +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/LICENSE +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/MANIFEST.in +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/Makefile +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/README.md +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/development.md +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/docs/DEVELOPMENT.md +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/docs/INSTALLATION.md +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/docs/PUBLISHING.md +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/docs/REFERENCE.md +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/docs/USAGE.md +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/docs/VERSION_RESOLUTION.md +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/installation.md +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/publishing.md +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/__init__.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/__main__.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/finder.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/publisher.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/py.typed +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/types.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/utils.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/version.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/version_calculator.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/conftest.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/folder_structure/some_globals.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/folder_structure/subfolder_to_build/README.md +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/folder_structure/subfolder_to_build/__init__.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/folder_structure/subfolder_to_build/some_function.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/folder_structure/subfolder_to_build/some_globals.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/folder_structure/utility_folder/_SS/some_superseded_file.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/folder_structure/utility_folder/some_utility.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/test_exclude_patterns.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/test_linting.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/test_publisher.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/test_shared_subdirectory_imports.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/test_third_party_dependencies.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/test_utils.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/test_version_calculator.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/test_version_manager.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/tests.py +0 -0
- {python_package_folder-5.3.0 → python_package_folder-6.0.0}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-package-folder
|
|
3
|
-
Version:
|
|
3
|
+
Version: 6.0.0
|
|
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>
|
|
@@ -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">65%</text>
|
|
18
|
+
<text x="81" y="14">65%</text>
|
|
19
19
|
</g>
|
|
20
20
|
</svg>
|
{python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/analyzer.py
RENAMED
|
@@ -330,56 +330,33 @@ class ImportAnalyzer:
|
|
|
330
330
|
|
|
331
331
|
# Check all subdirectories in parent (not just common ones)
|
|
332
332
|
# This handles cases like src/data/spreadsheet_creation/spreadsheet_formatting_dataclasses.py
|
|
333
|
-
|
|
333
|
+
# Use recursive search to find modules in nested directories
|
|
334
|
+
if parent.is_dir() and parent.is_relative_to(self.project_root):
|
|
335
|
+
# Recursively search for the module file in subdirectories
|
|
336
|
+
# Limit search to project_root and its subdirectories to avoid searching too broadly
|
|
337
|
+
module_basename = module_name.split(".")[-1]
|
|
334
338
|
try:
|
|
335
|
-
for
|
|
336
|
-
|
|
339
|
+
# Search recursively for the module file
|
|
340
|
+
for potential_file in parent.rglob(f"{module_basename}.py"):
|
|
341
|
+
# Only search within project_root to avoid going too far
|
|
342
|
+
if not potential_file.is_relative_to(self.project_root):
|
|
337
343
|
continue
|
|
338
|
-
# Skip
|
|
339
|
-
if
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
# Check if module directory exists in subdirectory
|
|
346
|
-
potential_subdir_module = subdir / module_name.replace(".", "/")
|
|
347
|
-
if (
|
|
348
|
-
potential_subdir_module.is_dir()
|
|
349
|
-
and (potential_subdir_module / "__init__.py").exists()
|
|
344
|
+
# Skip excluded patterns
|
|
345
|
+
if any(
|
|
346
|
+
part.startswith("_SS")
|
|
347
|
+
or part.startswith("__SS")
|
|
348
|
+
or part.startswith("_sandbox")
|
|
349
|
+
or part.startswith("__sandbox")
|
|
350
|
+
for part in potential_file.parts
|
|
350
351
|
):
|
|
351
|
-
return potential_subdir_module / "__init__.py"
|
|
352
|
-
if potential_subdir_module.with_suffix(".py").is_file():
|
|
353
|
-
return potential_subdir_module.with_suffix(".py")
|
|
354
|
-
# Check nested subdirectories (e.g., data/spreadsheet_creation)
|
|
355
|
-
# Recursively check subdirectories up to 2 levels deep
|
|
356
|
-
try:
|
|
357
|
-
for nested_subdir in subdir.iterdir():
|
|
358
|
-
if not nested_subdir.is_dir():
|
|
359
|
-
continue
|
|
360
|
-
# Check if module file exists in nested subdirectory
|
|
361
|
-
potential_nested_file = (
|
|
362
|
-
nested_subdir / f"{module_name.split('.')[-1]}.py"
|
|
363
|
-
)
|
|
364
|
-
if potential_nested_file.exists():
|
|
365
|
-
return potential_nested_file
|
|
366
|
-
# Check if module directory exists in nested subdirectory
|
|
367
|
-
potential_nested_module = nested_subdir / module_name.replace(
|
|
368
|
-
".", "/"
|
|
369
|
-
)
|
|
370
|
-
if (
|
|
371
|
-
potential_nested_module.is_dir()
|
|
372
|
-
and (potential_nested_module / "__init__.py").exists()
|
|
373
|
-
):
|
|
374
|
-
return potential_nested_module / "__init__.py"
|
|
375
|
-
if potential_nested_module.with_suffix(".py").is_file():
|
|
376
|
-
return potential_nested_module.with_suffix(".py")
|
|
377
|
-
except (OSError, PermissionError):
|
|
378
|
-
# Skip nested directories we can't read
|
|
379
352
|
continue
|
|
353
|
+
# Skip if it's in the src_dir (we're looking for external dependencies)
|
|
354
|
+
if potential_file.is_relative_to(src_dir):
|
|
355
|
+
continue
|
|
356
|
+
return potential_file
|
|
380
357
|
except (OSError, PermissionError):
|
|
381
|
-
# Skip
|
|
382
|
-
|
|
358
|
+
# Skip if we can't read the directory
|
|
359
|
+
pass
|
|
383
360
|
|
|
384
361
|
# Check common subdirectories in parent (e.g., _shared, shared, common)
|
|
385
362
|
# This handles cases like src/_shared/better_enum.py
|
{python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/manager.py
RENAMED
|
@@ -239,10 +239,19 @@ class BuildManager:
|
|
|
239
239
|
)
|
|
240
240
|
|
|
241
241
|
if not package_name:
|
|
242
|
-
# Derive package name from subfolder
|
|
243
|
-
|
|
242
|
+
# Derive package name from subfolder: {root_project_name}-{subfolder_name}
|
|
243
|
+
root_project_name = self._get_project_name()
|
|
244
|
+
subfolder_name = (
|
|
244
245
|
self.src_dir.name.replace("_", "-").replace(" ", "-").lower().strip("-")
|
|
245
246
|
)
|
|
247
|
+
|
|
248
|
+
if root_project_name:
|
|
249
|
+
# Normalize root project name (replace underscores/hyphens consistently)
|
|
250
|
+
root_name_normalized = root_project_name.replace("_", "-").lower()
|
|
251
|
+
package_name = f"{root_name_normalized}-{subfolder_name}"
|
|
252
|
+
else:
|
|
253
|
+
# Fallback to just subfolder name if root project name not found
|
|
254
|
+
package_name = subfolder_name
|
|
246
255
|
|
|
247
256
|
print(
|
|
248
257
|
f"Detected subfolder build. Setting up package '{package_name}' version '{version}'..."
|
|
@@ -259,10 +268,30 @@ class BuildManager:
|
|
|
259
268
|
# This is acceptable for tests or dependency-only operations
|
|
260
269
|
if temp_pyproject is None:
|
|
261
270
|
self.subfolder_config = None
|
|
271
|
+
else:
|
|
272
|
+
# If temporary package directory was created, use it for all operations
|
|
273
|
+
# This ensures dependencies are copied to the correct location and
|
|
274
|
+
# imports are fixed in the files that will actually be packaged
|
|
275
|
+
if (
|
|
276
|
+
self.subfolder_config
|
|
277
|
+
and self.subfolder_config._temp_package_dir
|
|
278
|
+
and self.subfolder_config._temp_package_dir.exists()
|
|
279
|
+
):
|
|
280
|
+
# Update src_dir to point to temp package directory
|
|
281
|
+
self.src_dir = self.subfolder_config._temp_package_dir
|
|
282
|
+
# Recreate finder with updated src_dir so it calculates target paths correctly
|
|
283
|
+
self.finder = ExternalDependencyFinder(
|
|
284
|
+
self.project_root,
|
|
285
|
+
self.src_dir,
|
|
286
|
+
exclude_patterns=self.exclude_patterns,
|
|
287
|
+
)
|
|
288
|
+
print(
|
|
289
|
+
f"Using temporary package directory for build: {self.src_dir}"
|
|
290
|
+
)
|
|
262
291
|
|
|
263
292
|
analyzer = ImportAnalyzer(self.project_root)
|
|
264
293
|
|
|
265
|
-
# Find all Python files in src/
|
|
294
|
+
# Find all Python files in src/ (which may now be the temp package directory)
|
|
266
295
|
python_files = analyzer.find_all_python_files(self.src_dir)
|
|
267
296
|
|
|
268
297
|
# Find external dependencies using the configured finder
|
|
@@ -1191,13 +1220,23 @@ class BuildManager:
|
|
|
1191
1220
|
captured_package_name = None
|
|
1192
1221
|
if self._is_subfolder_build():
|
|
1193
1222
|
# We need to get the package name before run_build cleans up subfolder_config
|
|
1194
|
-
if
|
|
1195
|
-
#
|
|
1196
|
-
captured_package_name =
|
|
1223
|
+
if package_name:
|
|
1224
|
+
# Use provided package name (from --package-name arg)
|
|
1225
|
+
captured_package_name = package_name
|
|
1226
|
+
else:
|
|
1227
|
+
# Derive from root project name + src_dir name (same logic as in prepare_build)
|
|
1228
|
+
root_project_name = self._get_project_name()
|
|
1229
|
+
subfolder_name = (
|
|
1197
1230
|
self.src_dir.name.replace("_", "-").replace(" ", "-").lower().strip("-")
|
|
1198
1231
|
)
|
|
1199
|
-
|
|
1200
|
-
|
|
1232
|
+
|
|
1233
|
+
if root_project_name:
|
|
1234
|
+
# Normalize root project name (replace underscores/hyphens consistently)
|
|
1235
|
+
root_name_normalized = root_project_name.replace("_", "-").lower()
|
|
1236
|
+
captured_package_name = f"{root_name_normalized}-{subfolder_name}"
|
|
1237
|
+
else:
|
|
1238
|
+
# Fallback to just subfolder name if root project name not found
|
|
1239
|
+
captured_package_name = subfolder_name
|
|
1201
1240
|
|
|
1202
1241
|
self.run_build(
|
|
1203
1242
|
build_command,
|
|
@@ -1223,10 +1262,19 @@ class BuildManager:
|
|
|
1223
1262
|
elif package_name:
|
|
1224
1263
|
publish_package_name = package_name
|
|
1225
1264
|
else:
|
|
1226
|
-
# Last resort: derive from src_dir name
|
|
1227
|
-
|
|
1265
|
+
# Last resort: derive from root project name + src_dir name
|
|
1266
|
+
root_project_name = self._get_project_name()
|
|
1267
|
+
subfolder_name = (
|
|
1228
1268
|
self.src_dir.name.replace("_", "-").replace(" ", "-").lower().strip("-")
|
|
1229
1269
|
)
|
|
1270
|
+
|
|
1271
|
+
if root_project_name:
|
|
1272
|
+
# Normalize root project name (replace underscores/hyphens consistently)
|
|
1273
|
+
root_name_normalized = root_project_name.replace("_", "-").lower()
|
|
1274
|
+
publish_package_name = f"{root_name_normalized}-{subfolder_name}"
|
|
1275
|
+
else:
|
|
1276
|
+
# Fallback to just subfolder name if root project name not found
|
|
1277
|
+
publish_package_name = subfolder_name
|
|
1230
1278
|
|
|
1231
1279
|
# Log the package name being used for publishing
|
|
1232
1280
|
import logging
|
|
@@ -30,6 +30,45 @@ logging.basicConfig(
|
|
|
30
30
|
|
|
31
31
|
def is_github_actions() -> bool:
|
|
32
32
|
"""Check if running in GitHub Actions."""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _get_root_project_name(project_root: Path) -> str | None:
|
|
36
|
+
"""
|
|
37
|
+
Get the root project name from pyproject.toml.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
project_root: Root directory of the project
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Project name from pyproject.toml, or None if not found
|
|
44
|
+
"""
|
|
45
|
+
pyproject_path = project_root / "pyproject.toml"
|
|
46
|
+
if not pyproject_path.exists():
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
import tomllib
|
|
51
|
+
except ImportError:
|
|
52
|
+
try:
|
|
53
|
+
import tomli as tomllib
|
|
54
|
+
except ImportError:
|
|
55
|
+
tomllib = None
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
if tomllib:
|
|
59
|
+
with open(pyproject_path, "rb") as f:
|
|
60
|
+
data = tomllib.load(f)
|
|
61
|
+
return data.get("project", {}).get("name")
|
|
62
|
+
else:
|
|
63
|
+
# Fallback: simple string parsing
|
|
64
|
+
content = pyproject_path.read_text(encoding="utf-8")
|
|
65
|
+
for line in content.split("\n"):
|
|
66
|
+
if line.strip().startswith("name ="):
|
|
67
|
+
return line.split("=", 1)[1].strip().strip('"').strip("'")
|
|
68
|
+
except Exception:
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
return None
|
|
33
72
|
return os.getenv("GITHUB_ACTIONS") == "true"
|
|
34
73
|
|
|
35
74
|
|
|
@@ -177,6 +216,27 @@ def main() -> int:
|
|
|
177
216
|
|
|
178
217
|
# Resolve version via conventional commits if not provided and needed
|
|
179
218
|
resolved_version = args.version
|
|
219
|
+
|
|
220
|
+
# Derive package name for subfolder builds (used for both version resolution and publishing)
|
|
221
|
+
derived_package_name = None
|
|
222
|
+
if is_subfolder:
|
|
223
|
+
if args.package_name:
|
|
224
|
+
derived_package_name = args.package_name
|
|
225
|
+
else:
|
|
226
|
+
# Derive package name: {root_project_name}-{subfolder_name}
|
|
227
|
+
root_project_name = _get_root_project_name(project_root)
|
|
228
|
+
subfolder_name = src_dir.name.replace("_", "-").replace(
|
|
229
|
+
" ", "-"
|
|
230
|
+
).lower().strip("-")
|
|
231
|
+
|
|
232
|
+
if root_project_name:
|
|
233
|
+
# Normalize root project name (replace underscores/hyphens consistently)
|
|
234
|
+
root_name_normalized = root_project_name.replace("_", "-").lower()
|
|
235
|
+
derived_package_name = f"{root_name_normalized}-{subfolder_name}"
|
|
236
|
+
else:
|
|
237
|
+
# Fallback to just subfolder name if root project name not found
|
|
238
|
+
derived_package_name = subfolder_name
|
|
239
|
+
|
|
180
240
|
if not resolved_version and not args.analyze_only:
|
|
181
241
|
# Version is needed for subfolder builds or when publishing main package
|
|
182
242
|
if is_subfolder or args.publish:
|
|
@@ -204,21 +264,18 @@ def main() -> int:
|
|
|
204
264
|
if is_subfolder:
|
|
205
265
|
# Workflow 1: subfolder build
|
|
206
266
|
# src_dir is guaranteed to be relative to project_root due to is_subfolder check
|
|
207
|
-
package_name = args.package_name or src_dir.name.replace("_", "-").replace(
|
|
208
|
-
" ", "-"
|
|
209
|
-
).lower().strip("-")
|
|
210
267
|
subfolder_rel_path = src_dir.relative_to(project_root)
|
|
211
268
|
|
|
212
269
|
# Log the package name being used for version query
|
|
213
270
|
logger = logging.getLogger(__name__)
|
|
214
271
|
logger.info(
|
|
215
|
-
f"Querying registry for package name: '{
|
|
216
|
-
f"(derived from src_dir: '{src_dir.name}', args.package_name: {args.package_name})"
|
|
272
|
+
f"Querying registry for package name: '{derived_package_name}' "
|
|
273
|
+
f"(derived from src_dir: '{src_dir.name}', root_project: {_get_root_project_name(project_root)}, args.package_name: {args.package_name})"
|
|
217
274
|
)
|
|
218
275
|
|
|
219
276
|
resolved_version, error_details = resolve_version(
|
|
220
277
|
project_root,
|
|
221
|
-
package_name=
|
|
278
|
+
package_name=derived_package_name,
|
|
222
279
|
subfolder_path=subfolder_rel_path,
|
|
223
280
|
repository=repository,
|
|
224
281
|
repository_url=repository_url,
|
|
@@ -279,7 +336,7 @@ def main() -> int:
|
|
|
279
336
|
skip_existing=args.skip_existing,
|
|
280
337
|
version=args.version,
|
|
281
338
|
restore_versioning=not args.no_restore_versioning,
|
|
282
|
-
package_name=args.package_name,
|
|
339
|
+
package_name=derived_package_name if is_subfolder else args.package_name,
|
|
283
340
|
dependency_group=args.dependency_group,
|
|
284
341
|
)
|
|
285
342
|
else:
|
|
@@ -289,9 +346,25 @@ def main() -> int:
|
|
|
289
346
|
if is_subfolder:
|
|
290
347
|
from .subfolder_build import SubfolderBuildConfig
|
|
291
348
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
349
|
+
# Use derived_package_name if available, otherwise derive it again
|
|
350
|
+
if derived_package_name is not None:
|
|
351
|
+
package_name = derived_package_name
|
|
352
|
+
elif args.package_name:
|
|
353
|
+
package_name = args.package_name
|
|
354
|
+
else:
|
|
355
|
+
# Derive package name: {root_project_name}-{subfolder_name}
|
|
356
|
+
root_project_name = _get_root_project_name(project_root)
|
|
357
|
+
subfolder_name = src_dir.name.replace("_", "-").replace(
|
|
358
|
+
" ", "-"
|
|
359
|
+
).lower().strip("-")
|
|
360
|
+
|
|
361
|
+
if root_project_name:
|
|
362
|
+
# Normalize root project name (replace underscores/hyphens consistently)
|
|
363
|
+
root_name_normalized = root_project_name.replace("_", "-").lower()
|
|
364
|
+
package_name = f"{root_name_normalized}-{subfolder_name}"
|
|
365
|
+
else:
|
|
366
|
+
# Fallback to just subfolder name if root project name not found
|
|
367
|
+
package_name = subfolder_name
|
|
295
368
|
subfolder_config = SubfolderBuildConfig(
|
|
296
369
|
project_root=project_root,
|
|
297
370
|
src_dir=src_dir,
|
|
@@ -78,16 +78,91 @@ class SubfolderBuildConfig:
|
|
|
78
78
|
self._used_subfolder_pyproject = False
|
|
79
79
|
self._excluded_files: list[tuple[Path, Path]] = [] # List of (original_path, temp_path) tuples
|
|
80
80
|
self._exclude_temp_dir: Path | None = None
|
|
81
|
+
self._temp_package_dir: Path | None = None
|
|
81
82
|
|
|
82
83
|
def _derive_package_name(self) -> str:
|
|
83
|
-
"""
|
|
84
|
+
"""
|
|
85
|
+
Derive package name from root project name and source directory name.
|
|
86
|
+
|
|
87
|
+
Format: {root_project_name}-{subfolder_name}
|
|
88
|
+
Falls back to just subfolder_name if root project name not found.
|
|
89
|
+
"""
|
|
90
|
+
# Get root project name from pyproject.toml
|
|
91
|
+
root_project_name = None
|
|
92
|
+
pyproject_path = self.project_root / "pyproject.toml"
|
|
93
|
+
if pyproject_path.exists():
|
|
94
|
+
try:
|
|
95
|
+
if tomllib:
|
|
96
|
+
with open(pyproject_path, "rb") as f:
|
|
97
|
+
data = tomllib.load(f)
|
|
98
|
+
root_project_name = data.get("project", {}).get("name")
|
|
99
|
+
else:
|
|
100
|
+
# Fallback: simple string parsing
|
|
101
|
+
content = pyproject_path.read_text(encoding="utf-8")
|
|
102
|
+
for line in content.split("\n"):
|
|
103
|
+
if line.strip().startswith("name ="):
|
|
104
|
+
root_project_name = line.split("=", 1)[1].strip().strip('"').strip("'")
|
|
105
|
+
break
|
|
106
|
+
except Exception:
|
|
107
|
+
pass
|
|
108
|
+
|
|
84
109
|
# Use the directory name, replacing invalid characters
|
|
85
|
-
|
|
110
|
+
subfolder_name = self.src_dir.name
|
|
86
111
|
# Replace invalid characters with hyphens
|
|
87
|
-
|
|
112
|
+
subfolder_name = subfolder_name.replace("_", "-").replace(" ", "-").lower()
|
|
88
113
|
# Remove any leading/trailing hyphens
|
|
89
|
-
|
|
90
|
-
|
|
114
|
+
subfolder_name = subfolder_name.strip("-")
|
|
115
|
+
|
|
116
|
+
# Combine with root project name if available
|
|
117
|
+
if root_project_name:
|
|
118
|
+
# Normalize root project name (replace underscores/hyphens consistently)
|
|
119
|
+
root_name_normalized = root_project_name.replace("_", "-").lower()
|
|
120
|
+
return f"{root_name_normalized}-{subfolder_name}"
|
|
121
|
+
else:
|
|
122
|
+
# Fallback to just subfolder name
|
|
123
|
+
return subfolder_name
|
|
124
|
+
|
|
125
|
+
def _create_temp_package_directory(self) -> None:
|
|
126
|
+
"""
|
|
127
|
+
Create a temporary package directory with the correct import name.
|
|
128
|
+
|
|
129
|
+
This ensures the installed package has the correct directory structure.
|
|
130
|
+
The package name (with hyphens) is converted to the import name (with underscores).
|
|
131
|
+
For example: 'ml-drawing-assistant-data' -> 'ml_drawing_assistant_data'
|
|
132
|
+
|
|
133
|
+
The temporary directory is created in the project root and contains a copy
|
|
134
|
+
of the source directory contents.
|
|
135
|
+
"""
|
|
136
|
+
if not self.package_name:
|
|
137
|
+
return
|
|
138
|
+
|
|
139
|
+
# Convert package name (with hyphens) to import name (with underscores)
|
|
140
|
+
# PyPI package names use hyphens, but Python import names use underscores
|
|
141
|
+
import_name = self.package_name.replace("-", "_")
|
|
142
|
+
|
|
143
|
+
# Create temporary directory name
|
|
144
|
+
temp_dir_name = f".temp_package_{import_name}"
|
|
145
|
+
temp_package_dir = self.project_root / temp_dir_name
|
|
146
|
+
|
|
147
|
+
# Remove if it already exists (from a previous failed build)
|
|
148
|
+
if temp_package_dir.exists():
|
|
149
|
+
shutil.rmtree(temp_package_dir)
|
|
150
|
+
|
|
151
|
+
# Copy the entire source directory contents to the temporary directory
|
|
152
|
+
try:
|
|
153
|
+
shutil.copytree(self.src_dir, temp_package_dir)
|
|
154
|
+
self._temp_package_dir = temp_package_dir
|
|
155
|
+
print(
|
|
156
|
+
f"Created temporary package directory: {temp_package_dir} "
|
|
157
|
+
f"(import name: {import_name})"
|
|
158
|
+
)
|
|
159
|
+
except Exception as e:
|
|
160
|
+
print(
|
|
161
|
+
f"Warning: Could not create temporary package directory: {e}",
|
|
162
|
+
file=sys.stderr,
|
|
163
|
+
)
|
|
164
|
+
# Fall back to using src_dir directly
|
|
165
|
+
self._temp_package_dir = None
|
|
91
166
|
|
|
92
167
|
def _get_package_structure(self) -> tuple[str, list[str]]:
|
|
93
168
|
"""
|
|
@@ -98,21 +173,24 @@ class SubfolderBuildConfig:
|
|
|
98
173
|
- packages_path: The path to the directory containing packages
|
|
99
174
|
- package_dirs: List of package directories to include
|
|
100
175
|
"""
|
|
101
|
-
#
|
|
102
|
-
|
|
176
|
+
# Use temporary package directory if it exists, otherwise use src_dir
|
|
177
|
+
package_dir = self._temp_package_dir if self._temp_package_dir and self._temp_package_dir.exists() else self.src_dir
|
|
178
|
+
|
|
179
|
+
# Check if package_dir itself is a package (has __init__.py)
|
|
180
|
+
has_init = (package_dir / "__init__.py").exists()
|
|
103
181
|
|
|
104
|
-
# Check for Python files directly in
|
|
105
|
-
py_files = list(
|
|
182
|
+
# Check for Python files directly in package_dir
|
|
183
|
+
py_files = list(package_dir.glob("*.py"))
|
|
106
184
|
has_py_files = bool(py_files)
|
|
107
185
|
|
|
108
|
-
# Calculate relative path
|
|
186
|
+
# Calculate relative path from project root
|
|
109
187
|
try:
|
|
110
|
-
rel_path =
|
|
188
|
+
rel_path = package_dir.relative_to(self.project_root)
|
|
111
189
|
packages_path = str(rel_path).replace("\\", "/")
|
|
112
190
|
except ValueError:
|
|
113
191
|
packages_path = None
|
|
114
192
|
|
|
115
|
-
# If
|
|
193
|
+
# If package_dir has Python files but no __init__.py, we need to make it a package
|
|
116
194
|
# or include it as a module directory
|
|
117
195
|
if has_py_files and not has_init:
|
|
118
196
|
# For flat structures, we include the directory itself
|
|
@@ -266,7 +344,8 @@ class SubfolderBuildConfig:
|
|
|
266
344
|
if not self.version:
|
|
267
345
|
raise ValueError("Version is required for subfolder builds")
|
|
268
346
|
|
|
269
|
-
# Ensure src_dir is a package (has __init__.py)
|
|
347
|
+
# Ensure src_dir is a package (has __init__.py) before creating temp directory
|
|
348
|
+
# This way the __init__.py will be copied to the temp directory
|
|
270
349
|
init_file = self.src_dir / "__init__.py"
|
|
271
350
|
if not init_file.exists():
|
|
272
351
|
# Create a temporary __init__.py to make it a package
|
|
@@ -275,6 +354,13 @@ class SubfolderBuildConfig:
|
|
|
275
354
|
else:
|
|
276
355
|
self._temp_init_created = False
|
|
277
356
|
|
|
357
|
+
# Create temporary package directory with correct import name
|
|
358
|
+
# This will copy the __init__.py we just created (if any)
|
|
359
|
+
self._create_temp_package_directory()
|
|
360
|
+
|
|
361
|
+
# Determine which directory to use (temp package dir or src_dir)
|
|
362
|
+
package_dir = self._temp_package_dir if self._temp_package_dir and self._temp_package_dir.exists() else self.src_dir
|
|
363
|
+
|
|
278
364
|
# Check if pyproject.toml exists in subfolder
|
|
279
365
|
subfolder_pyproject = self.src_dir / "pyproject.toml"
|
|
280
366
|
if subfolder_pyproject.exists():
|
|
@@ -1174,6 +1260,18 @@ class SubfolderBuildConfig:
|
|
|
1174
1260
|
self.original_pyproject_path = None
|
|
1175
1261
|
self._used_subfolder_pyproject = False
|
|
1176
1262
|
|
|
1263
|
+
# Remove temporary package directory if it exists
|
|
1264
|
+
if self._temp_package_dir and self._temp_package_dir.exists():
|
|
1265
|
+
try:
|
|
1266
|
+
shutil.rmtree(self._temp_package_dir)
|
|
1267
|
+
print(f"Removed temporary package directory: {self._temp_package_dir}")
|
|
1268
|
+
except Exception as e:
|
|
1269
|
+
print(
|
|
1270
|
+
f"Warning: Could not remove temporary package directory {self._temp_package_dir}: {e}",
|
|
1271
|
+
file=sys.stderr,
|
|
1272
|
+
)
|
|
1273
|
+
self._temp_package_dir = None
|
|
1274
|
+
|
|
1177
1275
|
def __enter__(self) -> Self:
|
|
1178
1276
|
"""Context manager entry."""
|
|
1179
1277
|
return self
|
{python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/test_build_with_external_deps.py
RENAMED
|
@@ -440,11 +440,15 @@ def shared_function():
|
|
|
440
440
|
|
|
441
441
|
# Verify dependencies were copied
|
|
442
442
|
assert len(external_deps) >= 2
|
|
443
|
-
|
|
444
|
-
|
|
443
|
+
# Dependencies are copied to the temp package directory (if it exists) or original subfolder
|
|
444
|
+
package_dir = manager.src_dir # This will be temp package dir if it was created
|
|
445
|
+
assert (package_dir / "_shared").exists()
|
|
446
|
+
assert (package_dir / "_globals.py").exists()
|
|
445
447
|
|
|
446
448
|
# Verify imports were converted to relative
|
|
447
|
-
|
|
449
|
+
# Read from package_dir which may be temp package directory
|
|
450
|
+
test_file_in_package = package_dir / test_file.name
|
|
451
|
+
modified_content = test_file_in_package.read_text()
|
|
448
452
|
assert "from ._shared.image_utils import save_PIL_image" in modified_content
|
|
449
453
|
assert "from ._shared.file_utils import get_filepaths_config" in modified_content
|
|
450
454
|
assert "from ._globals import is_testing" in modified_content
|
|
@@ -455,12 +459,15 @@ def shared_function():
|
|
|
455
459
|
assert "from pathlib import Path" in modified_content
|
|
456
460
|
|
|
457
461
|
# Verify import statement conversion
|
|
458
|
-
|
|
462
|
+
test_file2_in_package = package_dir / test_file2.name
|
|
463
|
+
modified_content2 = test_file2_in_package.read_text()
|
|
459
464
|
assert "from . import _globals" in modified_content2
|
|
460
465
|
|
|
461
466
|
# Verify relative imports in copied files were fixed
|
|
462
|
-
|
|
463
|
-
|
|
467
|
+
# Check in the package directory (which may be temp package dir)
|
|
468
|
+
shared_utils_path = package_dir / "_shared" / "shared_utils.py"
|
|
469
|
+
if shared_utils_path.exists():
|
|
470
|
+
shared_utils_content = shared_utils_path.read_text()
|
|
464
471
|
# The relative import should be converted to absolute
|
|
465
472
|
assert (
|
|
466
473
|
"from .file_utils import" not in shared_utils_content
|
|
@@ -470,6 +477,7 @@ def shared_function():
|
|
|
470
477
|
# Cleanup should restore original imports
|
|
471
478
|
manager.cleanup()
|
|
472
479
|
|
|
480
|
+
# After cleanup, check original files (not temp package dir)
|
|
473
481
|
restored_content = test_file.read_text()
|
|
474
482
|
assert restored_content == original_content
|
|
475
483
|
|
|
@@ -161,14 +161,16 @@ packages = ["src/test_package"]
|
|
|
161
161
|
assert len(data_deps) > 0, "data dependencies should be found"
|
|
162
162
|
|
|
163
163
|
# Verify models structure was copied with full path
|
|
164
|
-
|
|
164
|
+
# Use manager.src_dir which may point to temp package directory
|
|
165
|
+
package_dir = manager.src_dir
|
|
166
|
+
models_path = package_dir / "models" / "Information_extraction" / "_shared_ie" / "ie_enums.py"
|
|
165
167
|
assert models_path.exists(), (
|
|
166
168
|
"models/Information_extraction/_shared_ie/ie_enums.py should be copied with full structure"
|
|
167
169
|
)
|
|
168
170
|
|
|
169
171
|
# Verify data structure was copied with full path
|
|
170
172
|
data_path = (
|
|
171
|
-
|
|
173
|
+
package_dir / "data" / "spreadsheet_creation" / "spreadsheet_formatting_dataclasses.py"
|
|
172
174
|
)
|
|
173
175
|
assert data_path.exists(), (
|
|
174
176
|
"data/spreadsheet_creation/spreadsheet_formatting_dataclasses.py should be copied with full structure"
|
|
@@ -139,7 +139,9 @@ packages = ["src/test_package"]
|
|
|
139
139
|
|
|
140
140
|
# Verify spreadsheet_creation directory was copied with full structure preserved
|
|
141
141
|
# Import is "data.spreadsheet_creation.spreadsheet_formatting_dataclasses", so structure should be preserved
|
|
142
|
-
|
|
142
|
+
# Use manager.src_dir which may point to temp package directory
|
|
143
|
+
package_dir = manager.src_dir
|
|
144
|
+
copied_dir = package_dir / "data" / "spreadsheet_creation"
|
|
143
145
|
assert copied_dir.exists(), (
|
|
144
146
|
f"spreadsheet_creation directory should be copied with structure at {copied_dir}"
|
|
145
147
|
)
|
|
@@ -63,7 +63,7 @@ class TestSubfolderBuildConfig:
|
|
|
63
63
|
version="1.0.0",
|
|
64
64
|
)
|
|
65
65
|
|
|
66
|
-
assert config.package_name == "subfolder"
|
|
66
|
+
assert config.package_name == "test-package-subfolder"
|
|
67
67
|
assert config.version == "1.0.0"
|
|
68
68
|
assert config.dependency_group is None
|
|
69
69
|
|
|
@@ -104,7 +104,7 @@ class TestSubfolderBuildConfig:
|
|
|
104
104
|
content = pyproject_path.read_text()
|
|
105
105
|
|
|
106
106
|
# Check package name and version are set
|
|
107
|
-
assert 'name = "subfolder"' in content
|
|
107
|
+
assert 'name = "test-package-subfolder"' in content
|
|
108
108
|
assert 'version = "2.0.0"' in content
|
|
109
109
|
|
|
110
110
|
# Check dynamic versioning is removed
|
|
@@ -226,7 +226,7 @@ class TestSubfolderBuildConfig:
|
|
|
226
226
|
) as config:
|
|
227
227
|
config.create_temp_pyproject()
|
|
228
228
|
content = (test_project_with_pyproject / "pyproject.toml").read_text()
|
|
229
|
-
assert 'name = "subfolder"' in content
|
|
229
|
+
assert 'name = "test-package-subfolder"' in content
|
|
230
230
|
|
|
231
231
|
# Check restore happened automatically
|
|
232
232
|
restored_content = (test_project_with_pyproject / "pyproject.toml").read_text()
|
|
@@ -262,7 +262,7 @@ class TestSubfolderBuildConfig:
|
|
|
262
262
|
config.create_temp_pyproject()
|
|
263
263
|
|
|
264
264
|
def test_package_name_derivation(self, test_project_with_pyproject: Path) -> None:
|
|
265
|
-
"""Test package name derivation from directory name."""
|
|
265
|
+
"""Test package name derivation from root project name and directory name."""
|
|
266
266
|
# Test with underscores
|
|
267
267
|
subfolder = test_project_with_pyproject / "subfolder_to_build"
|
|
268
268
|
subfolder.mkdir()
|
|
@@ -271,7 +271,7 @@ class TestSubfolderBuildConfig:
|
|
|
271
271
|
src_dir=subfolder,
|
|
272
272
|
version="1.0.0",
|
|
273
273
|
)
|
|
274
|
-
assert config.package_name == "subfolder-to-build"
|
|
274
|
+
assert config.package_name == "test-package-subfolder-to-build"
|
|
275
275
|
|
|
276
276
|
# Test with spaces
|
|
277
277
|
subfolder2 = test_project_with_pyproject / "subfolder with spaces"
|
|
@@ -281,7 +281,24 @@ class TestSubfolderBuildConfig:
|
|
|
281
281
|
src_dir=subfolder2,
|
|
282
282
|
version="1.0.0",
|
|
283
283
|
)
|
|
284
|
-
assert config2.package_name == "subfolder-with-spaces"
|
|
284
|
+
assert config2.package_name == "test-package-subfolder-with-spaces"
|
|
285
|
+
|
|
286
|
+
def test_package_name_derivation_no_root_project(self, tmp_path: Path) -> None:
|
|
287
|
+
"""Test package name derivation when root project name is not found (fallback)."""
|
|
288
|
+
# Create a project without pyproject.toml
|
|
289
|
+
project_root = tmp_path / "test_project_no_pyproject"
|
|
290
|
+
project_root.mkdir()
|
|
291
|
+
|
|
292
|
+
subfolder = project_root / "subfolder"
|
|
293
|
+
subfolder.mkdir()
|
|
294
|
+
|
|
295
|
+
config = SubfolderBuildConfig(
|
|
296
|
+
project_root=project_root,
|
|
297
|
+
src_dir=subfolder,
|
|
298
|
+
version="1.0.0",
|
|
299
|
+
)
|
|
300
|
+
# Should fallback to just subfolder name when root project name not found
|
|
301
|
+
assert config.package_name == "subfolder"
|
|
285
302
|
|
|
286
303
|
|
|
287
304
|
def test_readme_handling_with_existing_readme(test_project_with_pyproject: Path):
|
|
@@ -666,8 +683,8 @@ class TestSubfolderBuildTemporaryPyprojectCreation:
|
|
|
666
683
|
assert "[tool.hatch.version]" not in content
|
|
667
684
|
assert "[tool.uv-dynamic-versioning]" not in content
|
|
668
685
|
|
|
669
|
-
# Verify packages path is set correctly
|
|
670
|
-
assert '
|
|
686
|
+
# Verify packages path is set correctly (should use temp package directory)
|
|
687
|
+
assert '.temp_package_my_custom_package' in content
|
|
671
688
|
|
|
672
689
|
# Verify backup was created
|
|
673
690
|
assert (project_root / "pyproject.toml.original").exists()
|
|
@@ -717,8 +734,8 @@ class TestSubfolderBuildTemporaryPyprojectCreation:
|
|
|
717
734
|
# Verify only-include is present
|
|
718
735
|
assert "only-include = [" in content
|
|
719
736
|
|
|
720
|
-
# Verify the
|
|
721
|
-
assert '
|
|
737
|
+
# Verify the temp package directory is included (not the original subfolder)
|
|
738
|
+
assert '.temp_package_test_package' in content
|
|
722
739
|
|
|
723
740
|
# Verify necessary files are included
|
|
724
741
|
assert '"pyproject.toml"' in content
|
|
@@ -856,7 +873,7 @@ description = "Subfolder package"
|
|
|
856
873
|
# Verify it was modified
|
|
857
874
|
modified_content = (project_root / "pyproject.toml").read_text()
|
|
858
875
|
assert modified_content != original_content
|
|
859
|
-
assert 'name = "subfolder"' in modified_content
|
|
876
|
+
assert 'name = "test-package-subfolder"' in modified_content
|
|
860
877
|
|
|
861
878
|
# Restore
|
|
862
879
|
config.restore()
|
|
@@ -933,3 +950,173 @@ description = "Subfolder package"
|
|
|
933
950
|
assert 'build-backend = "hatchling.build"' in content
|
|
934
951
|
|
|
935
952
|
config.restore()
|
|
953
|
+
|
|
954
|
+
|
|
955
|
+
class TestTemporaryPackageDirectory:
|
|
956
|
+
"""Tests for temporary package directory creation and cleanup."""
|
|
957
|
+
|
|
958
|
+
def test_temp_package_directory_created_with_correct_name(
|
|
959
|
+
self, test_project_with_pyproject: Path
|
|
960
|
+
) -> None:
|
|
961
|
+
"""Test that temporary package directory is created with correct import name."""
|
|
962
|
+
project_root = test_project_with_pyproject
|
|
963
|
+
subfolder = project_root / "subfolder"
|
|
964
|
+
(subfolder / "module.py").write_text("def func(): pass")
|
|
965
|
+
|
|
966
|
+
config = SubfolderBuildConfig(
|
|
967
|
+
project_root=project_root,
|
|
968
|
+
src_dir=subfolder,
|
|
969
|
+
version="1.0.0",
|
|
970
|
+
)
|
|
971
|
+
|
|
972
|
+
# Package name should be "test-package-subfolder" (with hyphens)
|
|
973
|
+
assert config.package_name == "test-package-subfolder"
|
|
974
|
+
|
|
975
|
+
# Create temp pyproject (which creates temp package directory)
|
|
976
|
+
config.create_temp_pyproject()
|
|
977
|
+
|
|
978
|
+
# Temp package directory should exist with import name (underscores)
|
|
979
|
+
temp_package_dir = project_root / ".temp_package_test_package_subfolder"
|
|
980
|
+
assert temp_package_dir.exists()
|
|
981
|
+
assert config._temp_package_dir == temp_package_dir
|
|
982
|
+
|
|
983
|
+
# Temp package directory should contain the subfolder contents
|
|
984
|
+
assert (temp_package_dir / "module.py").exists()
|
|
985
|
+
|
|
986
|
+
# Cleanup
|
|
987
|
+
config.restore()
|
|
988
|
+
|
|
989
|
+
def test_temp_package_directory_uses_import_name(
|
|
990
|
+
self, test_project_with_pyproject: Path
|
|
991
|
+
) -> None:
|
|
992
|
+
"""Test that temp package directory name converts hyphens to underscores."""
|
|
993
|
+
project_root = test_project_with_pyproject
|
|
994
|
+
subfolder = project_root / "subfolder"
|
|
995
|
+
(subfolder / "module.py").write_text("def func(): pass")
|
|
996
|
+
|
|
997
|
+
config = SubfolderBuildConfig(
|
|
998
|
+
project_root=project_root,
|
|
999
|
+
src_dir=subfolder,
|
|
1000
|
+
version="1.0.0",
|
|
1001
|
+
package_name="my-custom-package", # Package name with hyphens
|
|
1002
|
+
)
|
|
1003
|
+
|
|
1004
|
+
config.create_temp_pyproject()
|
|
1005
|
+
|
|
1006
|
+
# Temp directory should use underscores (import name)
|
|
1007
|
+
temp_package_dir = project_root / ".temp_package_my_custom_package"
|
|
1008
|
+
assert temp_package_dir.exists()
|
|
1009
|
+
assert config._temp_package_dir == temp_package_dir
|
|
1010
|
+
|
|
1011
|
+
config.restore()
|
|
1012
|
+
|
|
1013
|
+
def test_temp_package_directory_cleaned_up(self, test_project_with_pyproject: Path) -> None:
|
|
1014
|
+
"""Test that temporary package directory is cleaned up on restore."""
|
|
1015
|
+
project_root = test_project_with_pyproject
|
|
1016
|
+
subfolder = project_root / "subfolder"
|
|
1017
|
+
(subfolder / "module.py").write_text("def func(): pass")
|
|
1018
|
+
|
|
1019
|
+
config = SubfolderBuildConfig(
|
|
1020
|
+
project_root=project_root,
|
|
1021
|
+
src_dir=subfolder,
|
|
1022
|
+
version="1.0.0",
|
|
1023
|
+
)
|
|
1024
|
+
|
|
1025
|
+
config.create_temp_pyproject()
|
|
1026
|
+
|
|
1027
|
+
# Verify temp directory exists
|
|
1028
|
+
temp_package_dir = config._temp_package_dir
|
|
1029
|
+
assert temp_package_dir is not None
|
|
1030
|
+
assert temp_package_dir.exists()
|
|
1031
|
+
|
|
1032
|
+
# Restore should clean it up
|
|
1033
|
+
config.restore()
|
|
1034
|
+
|
|
1035
|
+
# Temp directory should be removed
|
|
1036
|
+
assert not temp_package_dir.exists()
|
|
1037
|
+
assert config._temp_package_dir is None
|
|
1038
|
+
|
|
1039
|
+
def test_packages_configuration_uses_temp_directory(
|
|
1040
|
+
self, test_project_with_pyproject: Path
|
|
1041
|
+
) -> None:
|
|
1042
|
+
"""Test that packages configuration uses temp directory path."""
|
|
1043
|
+
project_root = test_project_with_pyproject
|
|
1044
|
+
subfolder = project_root / "subfolder"
|
|
1045
|
+
(subfolder / "module.py").write_text("def func(): pass")
|
|
1046
|
+
|
|
1047
|
+
config = SubfolderBuildConfig(
|
|
1048
|
+
project_root=project_root,
|
|
1049
|
+
src_dir=subfolder,
|
|
1050
|
+
version="1.0.0",
|
|
1051
|
+
)
|
|
1052
|
+
|
|
1053
|
+
pyproject_path = config.create_temp_pyproject()
|
|
1054
|
+
assert pyproject_path is not None
|
|
1055
|
+
|
|
1056
|
+
content = pyproject_path.read_text()
|
|
1057
|
+
|
|
1058
|
+
# Packages configuration should use temp directory path
|
|
1059
|
+
# Temp directory name is ".temp_package_test_package_subfolder"
|
|
1060
|
+
assert ".temp_package_test_package_subfolder" in content
|
|
1061
|
+
|
|
1062
|
+
config.restore()
|
|
1063
|
+
|
|
1064
|
+
def test_temp_package_directory_preserves_structure(
|
|
1065
|
+
self, test_project_with_pyproject: Path
|
|
1066
|
+
) -> None:
|
|
1067
|
+
"""Test that temp package directory preserves the original directory structure."""
|
|
1068
|
+
project_root = test_project_with_pyproject
|
|
1069
|
+
subfolder = project_root / "subfolder"
|
|
1070
|
+
(subfolder / "module.py").write_text("def func(): pass")
|
|
1071
|
+
(subfolder / "submodule").mkdir()
|
|
1072
|
+
(subfolder / "submodule" / "__init__.py").write_text("")
|
|
1073
|
+
(subfolder / "submodule" / "helper.py").write_text("def helper(): pass")
|
|
1074
|
+
|
|
1075
|
+
config = SubfolderBuildConfig(
|
|
1076
|
+
project_root=project_root,
|
|
1077
|
+
src_dir=subfolder,
|
|
1078
|
+
version="1.0.0",
|
|
1079
|
+
)
|
|
1080
|
+
|
|
1081
|
+
config.create_temp_pyproject()
|
|
1082
|
+
|
|
1083
|
+
temp_package_dir = config._temp_package_dir
|
|
1084
|
+
assert temp_package_dir is not None
|
|
1085
|
+
|
|
1086
|
+
# Verify structure is preserved
|
|
1087
|
+
assert (temp_package_dir / "module.py").exists()
|
|
1088
|
+
assert (temp_package_dir / "submodule" / "__init__.py").exists()
|
|
1089
|
+
assert (temp_package_dir / "submodule" / "helper.py").exists()
|
|
1090
|
+
|
|
1091
|
+
config.restore()
|
|
1092
|
+
|
|
1093
|
+
def test_temp_package_directory_handles_existing_directory(
|
|
1094
|
+
self, test_project_with_pyproject: Path
|
|
1095
|
+
) -> None:
|
|
1096
|
+
"""Test that temp package directory creation handles existing directory."""
|
|
1097
|
+
project_root = test_project_with_pyproject
|
|
1098
|
+
subfolder = project_root / "subfolder"
|
|
1099
|
+
(subfolder / "module.py").write_text("def func(): pass")
|
|
1100
|
+
|
|
1101
|
+
# Create a directory that would conflict
|
|
1102
|
+
existing_temp_dir = project_root / ".temp_package_test_package_subfolder"
|
|
1103
|
+
existing_temp_dir.mkdir()
|
|
1104
|
+
(existing_temp_dir / "old_file.py").write_text("# Old file")
|
|
1105
|
+
|
|
1106
|
+
config = SubfolderBuildConfig(
|
|
1107
|
+
project_root=project_root,
|
|
1108
|
+
src_dir=subfolder,
|
|
1109
|
+
version="1.0.0",
|
|
1110
|
+
)
|
|
1111
|
+
|
|
1112
|
+
# Should remove existing directory and create new one
|
|
1113
|
+
config.create_temp_pyproject()
|
|
1114
|
+
|
|
1115
|
+
temp_package_dir = config._temp_package_dir
|
|
1116
|
+
assert temp_package_dir is not None
|
|
1117
|
+
assert temp_package_dir.exists()
|
|
1118
|
+
# Should have new file, not old file
|
|
1119
|
+
assert (temp_package_dir / "module.py").exists()
|
|
1120
|
+
assert not (temp_package_dir / "old_file.py").exists()
|
|
1121
|
+
|
|
1122
|
+
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
|
|
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-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/__init__.py
RENAMED
|
File without changes
|
{python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/__main__.py
RENAMED
|
File without changes
|
{python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/finder.py
RENAMED
|
File without changes
|
{python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/publisher.py
RENAMED
|
File without changes
|
{python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/py.typed
RENAMED
|
File without changes
|
{python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/types.py
RENAMED
|
File without changes
|
{python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/utils.py
RENAMED
|
File without changes
|
{python_package_folder-5.3.0 → python_package_folder-6.0.0}/src/python_package_folder/version.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/folder_structure/some_globals.py
RENAMED
|
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-5.3.0 → python_package_folder-6.0.0}/tests/test_third_party_dependencies.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_package_folder-5.3.0 → python_package_folder-6.0.0}/tests/test_version_calculator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|