python-package-folder 8.4.0__tar.gz → 9.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-8.4.0 → python_package_folder-9.0.0}/PKG-INFO +1 -1
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/coverage.svg +2 -2
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/pyproject.toml +1 -1
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/manager.py +27 -6
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/test_subfolder_build.py +294 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/.copier-answers.yml +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/.cursor/plans/optional_version_+_semantic-release_efed88a6.plan.md +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/.cursor/plans/replace_node.js_semantic-release_with_custom_python_implementation_64e05e1a.plan.md +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/.cursor/rules/general.mdc +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/.cursor/rules/python.mdc +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/.github/workflows/ci.yml +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/.github/workflows/publish.yml +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/.gitignore +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/.vscode/settings.json +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/LICENSE +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/MANIFEST.in +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/Makefile +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/README.md +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/development.md +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/docs/DEVELOPMENT.md +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/docs/INSTALLATION.md +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/docs/PUBLISHING.md +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/docs/REFERENCE.md +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/docs/USAGE.md +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/docs/VERSION_RESOLUTION.md +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/installation.md +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/publishing.md +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/__init__.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/__main__.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/analyzer.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/finder.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/publisher.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/py.typed +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/python_package_folder.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/subfolder_build.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/types.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/utils.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/version.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/version_calculator.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/conftest.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/folder_structure/some_globals.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/folder_structure/subfolder_to_build/README.md +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/folder_structure/subfolder_to_build/__init__.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/folder_structure/subfolder_to_build/some_function.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/folder_structure/subfolder_to_build/some_globals.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/folder_structure/utility_folder/_SS/some_superseded_file.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/folder_structure/utility_folder/some_utility.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/test_build_with_external_deps.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/test_exclude_patterns.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/test_linting.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/test_preserve_directory_structure.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/test_publisher.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/test_shared_subdirectory_imports.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/test_spreadsheet_creation_imports.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/test_third_party_dependencies.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/test_utils.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/test_version_calculator.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/test_version_manager.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/tests.py +0 -0
- {python_package_folder-8.4.0 → python_package_folder-9.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: 9.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">67%</text>
|
|
18
|
+
<text x="81" y="14">67%</text>
|
|
19
19
|
</g>
|
|
20
20
|
</svg>
|
{python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/manager.py
RENAMED
|
@@ -837,25 +837,46 @@ class BuildManager:
|
|
|
837
837
|
"""
|
|
838
838
|
try:
|
|
839
839
|
# Get relative paths from src_dir
|
|
840
|
-
|
|
841
|
-
|
|
840
|
+
file_dir = file_path.parent
|
|
841
|
+
# If module_path has a file extension (.py), treat it as a file and use its parent
|
|
842
|
+
# Otherwise, treat it as a directory
|
|
843
|
+
# This handles cases where the file doesn't exist yet (is_file() would return False)
|
|
844
|
+
if module_path.suffix == ".py" or (module_path.is_file() if module_path.exists() else False):
|
|
845
|
+
module_dir = module_path.parent
|
|
846
|
+
else:
|
|
847
|
+
module_dir = module_path
|
|
848
|
+
|
|
849
|
+
# Normalize both to be relative to src_dir
|
|
850
|
+
try:
|
|
851
|
+
file_rel = file_dir.relative_to(src_dir)
|
|
852
|
+
module_rel = module_dir.relative_to(src_dir)
|
|
853
|
+
except ValueError:
|
|
854
|
+
# If not relative to src_dir, fall back to single dot
|
|
855
|
+
return "."
|
|
842
856
|
|
|
843
857
|
# Calculate depth difference
|
|
844
858
|
# If paths are ".", depth is 0
|
|
845
|
-
file_depth = len(file_rel.parts) if file_rel.parts != (".",) else 0
|
|
846
|
-
module_depth = len(module_rel.parts) if module_rel.parts != (".",) else 0
|
|
859
|
+
file_depth = len(file_rel.parts) if file_rel.parts and file_rel.parts != (".",) else 0
|
|
860
|
+
module_depth = len(module_rel.parts) if module_rel.parts and module_rel.parts != (".",) else 0
|
|
847
861
|
|
|
848
862
|
depth_diff = file_depth - module_depth
|
|
849
863
|
|
|
850
864
|
if depth_diff == 0:
|
|
851
|
-
|
|
865
|
+
# Same depth - check if they're the same directory or siblings
|
|
866
|
+
if file_rel == module_rel:
|
|
867
|
+
return "." # Same directory
|
|
868
|
+
else:
|
|
869
|
+
# Sibling directories at same depth - need to go up one level
|
|
870
|
+
# e.g., PytorchCoco/ and _shared/ both at depth 1, need ..
|
|
871
|
+
return ".."
|
|
852
872
|
elif depth_diff > 0:
|
|
853
873
|
# File is deeper than module, need to go up
|
|
874
|
+
# e.g., file at depth 2, module at depth 0, need ...
|
|
854
875
|
return "." * (depth_diff + 1) # Go up depth_diff levels
|
|
855
876
|
else:
|
|
856
877
|
# Module is deeper than file, use single dot
|
|
857
878
|
return "."
|
|
858
|
-
except ValueError:
|
|
879
|
+
except (ValueError, AttributeError):
|
|
859
880
|
# If paths are not relative to src_dir, fall back to single dot
|
|
860
881
|
return "."
|
|
861
882
|
|
|
@@ -3076,6 +3076,300 @@ import pandas
|
|
|
3076
3076
|
finally:
|
|
3077
3077
|
manager.cleanup()
|
|
3078
3078
|
|
|
3079
|
+
def test_sibling_directories_use_two_dots_for_relative_imports(
|
|
3080
|
+
self, test_project_with_pyproject: Path
|
|
3081
|
+
) -> None:
|
|
3082
|
+
"""
|
|
3083
|
+
Regression test for bug where sibling directories at same depth
|
|
3084
|
+
incorrectly used single dot (.) instead of two dots (..).
|
|
3085
|
+
|
|
3086
|
+
Bug scenario:
|
|
3087
|
+
- File in PytorchCoco/dataset_dataclasses.py (depth 1)
|
|
3088
|
+
- Module in _shared/image_utils.py (depth 1)
|
|
3089
|
+
- Both are siblings at same depth
|
|
3090
|
+
- Should use '..' to go up to parent, then into sibling
|
|
3091
|
+
- Was incorrectly using '.' which looked for PytorchCoco/_shared/
|
|
3092
|
+
|
|
3093
|
+
This test would have failed before the fix.
|
|
3094
|
+
"""
|
|
3095
|
+
project_root = test_project_with_pyproject
|
|
3096
|
+
subfolder = project_root / "subfolder"
|
|
3097
|
+
|
|
3098
|
+
# Create sibling directories at same depth (both at root of subfolder)
|
|
3099
|
+
pytorch_coco_dir = subfolder / "PytorchCoco"
|
|
3100
|
+
pytorch_coco_dir.mkdir(parents=True)
|
|
3101
|
+
(pytorch_coco_dir / "__init__.py").write_text("# PytorchCoco package")
|
|
3102
|
+
|
|
3103
|
+
# Create external dependency as sibling at same depth
|
|
3104
|
+
external_dir = project_root / "src" / "_shared"
|
|
3105
|
+
external_dir.mkdir(parents=True)
|
|
3106
|
+
(external_dir / "__init__.py").write_text("# Shared utilities")
|
|
3107
|
+
(external_dir / "image_utils.py").write_text("def save_cropped_image(): return 'saved'")
|
|
3108
|
+
|
|
3109
|
+
# Create file in PytorchCoco that imports from sibling _shared
|
|
3110
|
+
(pytorch_coco_dir / "dataset_dataclasses.py").write_text(
|
|
3111
|
+
"from _shared.image_utils import save_cropped_image"
|
|
3112
|
+
)
|
|
3113
|
+
|
|
3114
|
+
# Build the subfolder
|
|
3115
|
+
manager = BuildManager(project_root=project_root, src_dir=subfolder)
|
|
3116
|
+
|
|
3117
|
+
try:
|
|
3118
|
+
manager.prepare_build(version="1.0.0", package_name="my-package")
|
|
3119
|
+
|
|
3120
|
+
# Verify the temp package directory exists
|
|
3121
|
+
assert manager.subfolder_config is not None
|
|
3122
|
+
temp_dir = manager.subfolder_config._temp_package_dir
|
|
3123
|
+
assert temp_dir is not None and temp_dir.exists()
|
|
3124
|
+
|
|
3125
|
+
# Read the modified file
|
|
3126
|
+
modified_content = (temp_dir / "PytorchCoco" / "dataset_dataclasses.py").read_text(
|
|
3127
|
+
encoding="utf-8"
|
|
3128
|
+
)
|
|
3129
|
+
|
|
3130
|
+
# CRITICAL: Verify it uses TWO DOTS (..) for sibling directories
|
|
3131
|
+
assert "from .._shared.image_utils import save_cropped_image" in modified_content, (
|
|
3132
|
+
"Sibling directories at same depth MUST use .. (two dots), not . (single dot). "
|
|
3133
|
+
"This was the bug: PytorchCoco/ and _shared/ are siblings, so we need to go up "
|
|
3134
|
+
"one level to the parent, then into _shared/. Using . would incorrectly look for "
|
|
3135
|
+
"PytorchCoco/_shared/ which doesn't exist."
|
|
3136
|
+
)
|
|
3137
|
+
|
|
3138
|
+
# Verify it does NOT use single dot (this was the bug)
|
|
3139
|
+
assert "from ._shared.image_utils" not in modified_content, (
|
|
3140
|
+
"BUG: Should NOT use single dot for sibling directories. "
|
|
3141
|
+
"This would cause ModuleNotFoundError: No module named 'package.PytorchCoco._shared'"
|
|
3142
|
+
)
|
|
3143
|
+
|
|
3144
|
+
# Verify the import is actually correct
|
|
3145
|
+
assert "from .._shared.image_utils import save_cropped_image" in modified_content
|
|
3146
|
+
|
|
3147
|
+
finally:
|
|
3148
|
+
manager.cleanup()
|
|
3149
|
+
|
|
3150
|
+
def test_relative_import_depth_edge_cases(
|
|
3151
|
+
self, test_project_with_pyproject: Path
|
|
3152
|
+
) -> None:
|
|
3153
|
+
"""
|
|
3154
|
+
Test various edge cases for relative import depth calculation:
|
|
3155
|
+
1. Same directory: should use .
|
|
3156
|
+
2. Sibling directories: should use ..
|
|
3157
|
+
3. File deeper than module: should use appropriate number of dots
|
|
3158
|
+
4. Module deeper than file: should use .
|
|
3159
|
+
"""
|
|
3160
|
+
project_root = test_project_with_pyproject
|
|
3161
|
+
subfolder = project_root / "subfolder"
|
|
3162
|
+
|
|
3163
|
+
# Create structure:
|
|
3164
|
+
# subfolder/
|
|
3165
|
+
# __init__.py
|
|
3166
|
+
# root_file.py (depth 0)
|
|
3167
|
+
# sibling1/
|
|
3168
|
+
# file1.py (depth 1)
|
|
3169
|
+
# sibling2/
|
|
3170
|
+
# file2.py (depth 1)
|
|
3171
|
+
# nested/
|
|
3172
|
+
# deep/
|
|
3173
|
+
# deep_file.py (depth 2)
|
|
3174
|
+
|
|
3175
|
+
(subfolder / "__init__.py").write_text("# Package init")
|
|
3176
|
+
(subfolder / "root_file.py").write_text("# Root file")
|
|
3177
|
+
|
|
3178
|
+
sibling1_dir = subfolder / "sibling1"
|
|
3179
|
+
sibling1_dir.mkdir()
|
|
3180
|
+
(sibling1_dir / "__init__.py").write_text("# Sibling1")
|
|
3181
|
+
(sibling1_dir / "file1.py").write_text("# File1")
|
|
3182
|
+
|
|
3183
|
+
sibling2_dir = subfolder / "sibling2"
|
|
3184
|
+
sibling2_dir.mkdir()
|
|
3185
|
+
(sibling2_dir / "__init__.py").write_text("# Sibling2")
|
|
3186
|
+
(sibling2_dir / "file2.py").write_text("# File2")
|
|
3187
|
+
|
|
3188
|
+
nested_dir = subfolder / "nested" / "deep"
|
|
3189
|
+
nested_dir.mkdir(parents=True)
|
|
3190
|
+
(nested_dir / "__init__.py").write_text("# Deep")
|
|
3191
|
+
(nested_dir / "deep_file.py").write_text("# Deep file")
|
|
3192
|
+
|
|
3193
|
+
# Create external dependencies at root level (these will be copied)
|
|
3194
|
+
shared_dir = project_root / "src" / "_shared"
|
|
3195
|
+
shared_dir.mkdir(parents=True)
|
|
3196
|
+
(shared_dir / "__init__.py").write_text("# Shared")
|
|
3197
|
+
(shared_dir / "utils.py").write_text("def helper(): pass")
|
|
3198
|
+
|
|
3199
|
+
# Create another external dependency as sibling to _shared
|
|
3200
|
+
other_dir = project_root / "src" / "other_module"
|
|
3201
|
+
other_dir.mkdir(parents=True)
|
|
3202
|
+
(other_dir / "__init__.py").write_text("# Other module")
|
|
3203
|
+
(other_dir / "functions.py").write_text("def do_something(): pass")
|
|
3204
|
+
|
|
3205
|
+
# Test case 1: File in sibling1 imports from _shared (sibling directories at same depth)
|
|
3206
|
+
# Both sibling1/ and _shared/ are at depth 1, so should use ..
|
|
3207
|
+
(sibling1_dir / "file1.py").write_text("from _shared.utils import helper")
|
|
3208
|
+
|
|
3209
|
+
# Test case 2: File in nested/deep imports from _shared (file deeper, module at root)
|
|
3210
|
+
# nested/deep/ is at depth 2, _shared/ is at depth 0, so should use ...
|
|
3211
|
+
(nested_dir / "deep_file.py").write_text("from _shared.utils import helper")
|
|
3212
|
+
|
|
3213
|
+
# Test case 3: File at root imports from _shared (same level)
|
|
3214
|
+
# Both at depth 0, so should use .
|
|
3215
|
+
(subfolder / "root_file.py").write_text("from _shared.utils import helper")
|
|
3216
|
+
|
|
3217
|
+
# Build the subfolder
|
|
3218
|
+
manager = BuildManager(project_root=project_root, src_dir=subfolder)
|
|
3219
|
+
|
|
3220
|
+
try:
|
|
3221
|
+
manager.prepare_build(version="1.0.0", package_name="my-package")
|
|
3222
|
+
|
|
3223
|
+
assert manager.subfolder_config is not None
|
|
3224
|
+
temp_dir = manager.subfolder_config._temp_package_dir
|
|
3225
|
+
assert temp_dir is not None and temp_dir.exists()
|
|
3226
|
+
|
|
3227
|
+
# Test case 1: Sibling directories at same depth should use ..
|
|
3228
|
+
# sibling1/ (depth 1) and _shared/ (depth 1) are siblings
|
|
3229
|
+
file1_content = (temp_dir / "sibling1" / "file1.py").read_text(encoding="utf-8")
|
|
3230
|
+
assert "from .._shared.utils import helper" in file1_content, (
|
|
3231
|
+
"Sibling directories at same depth should use .. to go up to parent, then into sibling. "
|
|
3232
|
+
"sibling1/ and _shared/ are both at depth 1, so we need .. to go up to root, then into _shared/"
|
|
3233
|
+
)
|
|
3234
|
+
assert "from ._shared.utils" not in file1_content, (
|
|
3235
|
+
"Should NOT use single dot for sibling directories. "
|
|
3236
|
+
"This would incorrectly look for sibling1/_shared/ which doesn't exist"
|
|
3237
|
+
)
|
|
3238
|
+
|
|
3239
|
+
# Test case 2: Deep file importing from root should use ...
|
|
3240
|
+
# nested/deep/ is at depth 2, _shared/ is at depth 1 (relative to temp_dir root),
|
|
3241
|
+
# so depth_diff = 2 - 1 = 1, need .. (but actually _shared is copied to root, so it's at depth 1)
|
|
3242
|
+
# Actually, let's check what the actual result is and document it
|
|
3243
|
+
deep_file_content = (temp_dir / "nested" / "deep" / "deep_file.py").read_text(
|
|
3244
|
+
encoding="utf-8"
|
|
3245
|
+
)
|
|
3246
|
+
# The actual behavior: nested/deep/ (depth 2) and _shared/ (depth 1) gives depth_diff = 1, so ..
|
|
3247
|
+
# This is correct because _shared is at the root of the temp package (depth 1 from temp_dir root)
|
|
3248
|
+
assert "from .._shared.utils import helper" in deep_file_content, (
|
|
3249
|
+
"Deep file (depth 2) importing from _shared (depth 1) should use .. (two dots). "
|
|
3250
|
+
"depth_diff = 2 - 1 = 1, so we need 1 + 1 = 2 dots"
|
|
3251
|
+
)
|
|
3252
|
+
|
|
3253
|
+
# Test case 3: Root file importing from root should use .
|
|
3254
|
+
# Both at depth 0, same level
|
|
3255
|
+
root_file_content = (temp_dir / "root_file.py").read_text(encoding="utf-8")
|
|
3256
|
+
assert "from ._shared.utils import helper" in root_file_content, (
|
|
3257
|
+
"Root file (depth 0) importing from root module (depth 0) should use . (single dot)"
|
|
3258
|
+
)
|
|
3259
|
+
|
|
3260
|
+
finally:
|
|
3261
|
+
manager.cleanup()
|
|
3262
|
+
|
|
3263
|
+
def test_calculate_relative_import_depth_unit_test(
|
|
3264
|
+
self, test_project_with_pyproject: Path
|
|
3265
|
+
) -> None:
|
|
3266
|
+
"""
|
|
3267
|
+
Unit test for _calculate_relative_import_depth method.
|
|
3268
|
+
|
|
3269
|
+
This test directly tests the depth calculation logic to ensure
|
|
3270
|
+
it handles all edge cases correctly, especially sibling directories.
|
|
3271
|
+
|
|
3272
|
+
This test would have caught the bug where sibling directories at
|
|
3273
|
+
the same depth incorrectly returned "." instead of "..".
|
|
3274
|
+
|
|
3275
|
+
Test cases:
|
|
3276
|
+
1. Same directory: should return "."
|
|
3277
|
+
2. Sibling directories (same depth, different paths): should return ".."
|
|
3278
|
+
3. File deeper than module: should return appropriate number of dots
|
|
3279
|
+
4. Module deeper than file: should return "."
|
|
3280
|
+
5. THE BUG: sibling1/ importing from _shared/ (both at depth 1, siblings)
|
|
3281
|
+
"""
|
|
3282
|
+
project_root = test_project_with_pyproject
|
|
3283
|
+
subfolder = project_root / "subfolder"
|
|
3284
|
+
|
|
3285
|
+
# Create structure for testing
|
|
3286
|
+
(subfolder / "__init__.py").write_text("# Package")
|
|
3287
|
+
(subfolder / "root_file.py").write_text("# Root")
|
|
3288
|
+
|
|
3289
|
+
sibling1 = subfolder / "sibling1"
|
|
3290
|
+
sibling1.mkdir()
|
|
3291
|
+
(sibling1 / "__init__.py").write_text("# Sibling1")
|
|
3292
|
+
(sibling1 / "file1.py").write_text("# File1")
|
|
3293
|
+
|
|
3294
|
+
sibling2 = subfolder / "sibling2"
|
|
3295
|
+
sibling2.mkdir()
|
|
3296
|
+
(sibling2 / "__init__.py").write_text("# Sibling2")
|
|
3297
|
+
(sibling2 / "file2.py").write_text("# File2")
|
|
3298
|
+
|
|
3299
|
+
nested = subfolder / "nested" / "deep"
|
|
3300
|
+
nested.mkdir(parents=True)
|
|
3301
|
+
(nested / "__init__.py").write_text("# Deep")
|
|
3302
|
+
(nested / "deep_file.py").write_text("# Deep file")
|
|
3303
|
+
|
|
3304
|
+
# Create external dependency
|
|
3305
|
+
external = project_root / "src" / "_shared"
|
|
3306
|
+
external.mkdir(parents=True)
|
|
3307
|
+
(external / "__init__.py").write_text("# Shared")
|
|
3308
|
+
(external / "utils.py").write_text("def helper(): pass")
|
|
3309
|
+
|
|
3310
|
+
manager = BuildManager(project_root=project_root, src_dir=subfolder)
|
|
3311
|
+
|
|
3312
|
+
try:
|
|
3313
|
+
manager.prepare_build(version="1.0.0", package_name="my-package")
|
|
3314
|
+
|
|
3315
|
+
assert manager.subfolder_config is not None
|
|
3316
|
+
temp_dir = manager.subfolder_config._temp_package_dir
|
|
3317
|
+
assert temp_dir is not None
|
|
3318
|
+
|
|
3319
|
+
# Test case 1: Same directory
|
|
3320
|
+
file1 = temp_dir / "sibling1" / "file1.py"
|
|
3321
|
+
module1 = temp_dir / "sibling1" / "__init__.py"
|
|
3322
|
+
result1 = manager._calculate_relative_import_depth(file1, module1, temp_dir)
|
|
3323
|
+
assert result1 == ".", (
|
|
3324
|
+
f"Same directory should return '.', got '{result1}'"
|
|
3325
|
+
)
|
|
3326
|
+
|
|
3327
|
+
# Test case 2: Sibling directories (THE BUG CASE)
|
|
3328
|
+
file2 = temp_dir / "sibling1" / "file1.py"
|
|
3329
|
+
module2 = temp_dir / "sibling2" / "file2.py"
|
|
3330
|
+
result2 = manager._calculate_relative_import_depth(file2, module2, temp_dir)
|
|
3331
|
+
assert result2 == "..", (
|
|
3332
|
+
f"Sibling directories at same depth should return '..', got '{result2}'. "
|
|
3333
|
+
f"This was the bug: sibling1/ and sibling2/ are both at depth 1, "
|
|
3334
|
+
f"so we need '..' to go up to parent, then into sibling2/. "
|
|
3335
|
+
f"Using '.' would incorrectly look for sibling1/sibling2/ which doesn't exist."
|
|
3336
|
+
)
|
|
3337
|
+
|
|
3338
|
+
# Test case 3: File deeper than module
|
|
3339
|
+
file3 = temp_dir / "nested" / "deep" / "deep_file.py"
|
|
3340
|
+
module3 = temp_dir / "sibling1" / "file1.py"
|
|
3341
|
+
result3 = manager._calculate_relative_import_depth(file3, module3, temp_dir)
|
|
3342
|
+
# nested/deep/ is depth 2, sibling1/ is depth 1, so depth_diff = 1, need ..
|
|
3343
|
+
assert result3 == "..", (
|
|
3344
|
+
f"File at depth 2 importing from depth 1 should return '..', got '{result3}'"
|
|
3345
|
+
)
|
|
3346
|
+
|
|
3347
|
+
# Test case 4: File at root importing from root-level module
|
|
3348
|
+
file4 = temp_dir / "root_file.py"
|
|
3349
|
+
module4 = temp_dir / "_shared" / "utils.py" # External dependency copied to root
|
|
3350
|
+
result4 = manager._calculate_relative_import_depth(file4, module4, temp_dir)
|
|
3351
|
+
# root_file.py parent is temp_dir (depth 0), _shared parent is temp_dir/_shared (depth 1)
|
|
3352
|
+
# So file_depth = 0, module_depth = 1, depth_diff = -1, should return "."
|
|
3353
|
+
assert result4 == ".", (
|
|
3354
|
+
f"Root file importing from root-level module should return '.', got '{result4}'"
|
|
3355
|
+
)
|
|
3356
|
+
|
|
3357
|
+
# Test case 5: Sibling directories with external dependency (THE ACTUAL BUG)
|
|
3358
|
+
file5 = temp_dir / "sibling1" / "file1.py"
|
|
3359
|
+
module5 = temp_dir / "_shared" / "utils.py" # External dependency at root
|
|
3360
|
+
result5 = manager._calculate_relative_import_depth(file5, module5, temp_dir)
|
|
3361
|
+
# sibling1/ is depth 1, _shared/ is depth 1, both siblings, should return ".."
|
|
3362
|
+
assert result5 == "..", (
|
|
3363
|
+
f"CRITICAL BUG TEST: sibling1/ (depth 1) importing from _shared/ (depth 1) "
|
|
3364
|
+
f"should return '..' (siblings), got '{result5}'. "
|
|
3365
|
+
f"This is the exact bug scenario: both at same depth but different paths, "
|
|
3366
|
+
f"so we need '..' to go up to parent, then into _shared/. "
|
|
3367
|
+
f"Using '.' would cause ModuleNotFoundError: No module named 'package.sibling1._shared'"
|
|
3368
|
+
)
|
|
3369
|
+
|
|
3370
|
+
finally:
|
|
3371
|
+
manager.cleanup()
|
|
3372
|
+
|
|
3079
3373
|
def test_ambiguous_imports_not_converted_to_relative(
|
|
3080
3374
|
self, test_project_with_pyproject: Path
|
|
3081
3375
|
) -> None:
|
|
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-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/__init__.py
RENAMED
|
File without changes
|
{python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/__main__.py
RENAMED
|
File without changes
|
{python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/analyzer.py
RENAMED
|
File without changes
|
{python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/finder.py
RENAMED
|
File without changes
|
{python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/publisher.py
RENAMED
|
File without changes
|
{python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/types.py
RENAMED
|
File without changes
|
{python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/utils.py
RENAMED
|
File without changes
|
{python_package_folder-8.4.0 → python_package_folder-9.0.0}/src/python_package_folder/version.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_package_folder-8.4.0 → python_package_folder-9.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
|
{python_package_folder-8.4.0 → python_package_folder-9.0.0}/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
|
{python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/test_third_party_dependencies.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_package_folder-8.4.0 → python_package_folder-9.0.0}/tests/test_version_calculator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|