python-package-folder 3.1.1__tar.gz → 3.1.3__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-3.1.1 → python_package_folder-3.1.3}/PKG-INFO +1 -1
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/coverage.svg +2 -2
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/manager.py +274 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/test_build_with_external_deps.py +118 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/.copier-answers.yml +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/.cursor/rules/general.mdc +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/.cursor/rules/python.mdc +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/.github/workflows/ci.yml +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/.github/workflows/publish.yml +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/.gitignore +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/.vscode/settings.json +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/LICENSE +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/Makefile +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/README.md +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/development.md +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/installation.md +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/publishing.md +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/pyproject.toml +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/__init__.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/__main__.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/analyzer.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/finder.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/publisher.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/py.typed +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/python_package_folder.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/subfolder_build.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/types.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/utils.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/version.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/conftest.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/folder_structure/some_globals.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/folder_structure/subfolder_to_build/README.md +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/folder_structure/subfolder_to_build/__init__.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/folder_structure/subfolder_to_build/some_function.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/folder_structure/subfolder_to_build/some_globals.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/folder_structure/utility_folder/_SS/some_superseded_file.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/folder_structure/utility_folder/some_utility.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/test_linting.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/test_preserve_directory_structure.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/test_publisher.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/test_shared_subdirectory_imports.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/test_spreadsheet_creation_imports.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/test_subfolder_build.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/test_third_party_dependencies.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/test_utils.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/test_version_manager.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/tests.py +0 -0
- {python_package_folder-3.1.1 → python_package_folder-3.1.3}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-package-folder
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.3
|
|
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">69%</text>
|
|
18
|
+
<text x="81" y="14">69%</text>
|
|
19
19
|
</g>
|
|
20
20
|
</svg>
|
{python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/manager.py
RENAMED
|
@@ -88,6 +88,8 @@ class BuildManager:
|
|
|
88
88
|
self.subfolder_config: SubfolderBuildConfig | None = None
|
|
89
89
|
# Cache for package name lookups (expensive operation)
|
|
90
90
|
self._packages_distributions_cache: dict[str, list[str]] | None = None
|
|
91
|
+
# Track files with modified imports and their original content
|
|
92
|
+
self._modified_import_files: dict[Path, str] = {}
|
|
91
93
|
|
|
92
94
|
# Check if it's a valid Python package directory
|
|
93
95
|
if not any(self.src_dir.glob("*.py")) and not (self.src_dir / "__init__.py").exists():
|
|
@@ -270,6 +272,13 @@ class BuildManager:
|
|
|
270
272
|
for dep in external_deps:
|
|
271
273
|
self._copy_dependency(dep)
|
|
272
274
|
|
|
275
|
+
# For subfolder builds, fix imports
|
|
276
|
+
if self._is_subfolder_build() and external_deps:
|
|
277
|
+
# Fix relative imports in copied dependency files (convert to absolute)
|
|
278
|
+
self._fix_relative_imports_in_copied_files(external_deps)
|
|
279
|
+
# Convert absolute imports of copied dependencies and local files to relative imports
|
|
280
|
+
self._convert_imports_to_relative(python_files, external_deps)
|
|
281
|
+
|
|
273
282
|
# For subfolder builds, extract third-party dependencies and add to pyproject.toml
|
|
274
283
|
if self._is_subfolder_build() and self.subfolder_config:
|
|
275
284
|
# Re-analyze all Python files (including copied dependencies) to find third-party imports
|
|
@@ -629,6 +638,258 @@ class BuildManager:
|
|
|
629
638
|
|
|
630
639
|
return sorted(list(third_party_packages))
|
|
631
640
|
|
|
641
|
+
def _fix_relative_imports_in_copied_files(
|
|
642
|
+
self, external_deps: list[ExternalDependency]
|
|
643
|
+
) -> None:
|
|
644
|
+
"""
|
|
645
|
+
Fix relative imports in copied dependency files.
|
|
646
|
+
|
|
647
|
+
When files are copied into the subfolder, their relative imports (like
|
|
648
|
+
`from ._shared.shared_dataclasses import ...`) break because the file
|
|
649
|
+
structure has changed. Convert these to absolute imports based on the
|
|
650
|
+
target location.
|
|
651
|
+
|
|
652
|
+
Args:
|
|
653
|
+
external_deps: List of external dependencies that were copied
|
|
654
|
+
"""
|
|
655
|
+
import ast
|
|
656
|
+
import re
|
|
657
|
+
|
|
658
|
+
# Find all Python files in copied dependencies
|
|
659
|
+
copied_files: list[Path] = []
|
|
660
|
+
for dep in external_deps:
|
|
661
|
+
if dep.target_path.is_file() and dep.target_path.suffix == ".py":
|
|
662
|
+
copied_files.append(dep.target_path)
|
|
663
|
+
elif dep.target_path.is_dir():
|
|
664
|
+
copied_files.extend(dep.target_path.rglob("*.py"))
|
|
665
|
+
|
|
666
|
+
for file_path in copied_files:
|
|
667
|
+
try:
|
|
668
|
+
content = file_path.read_text(encoding="utf-8")
|
|
669
|
+
original_content = content
|
|
670
|
+
lines = content.split("\n")
|
|
671
|
+
modified = False
|
|
672
|
+
|
|
673
|
+
try:
|
|
674
|
+
tree = ast.parse(content, filename=str(file_path))
|
|
675
|
+
except SyntaxError:
|
|
676
|
+
continue
|
|
677
|
+
|
|
678
|
+
lines_to_modify: dict[int, str] = {}
|
|
679
|
+
|
|
680
|
+
for node in ast.walk(tree):
|
|
681
|
+
if isinstance(node, ast.ImportFrom):
|
|
682
|
+
if node.module is None:
|
|
683
|
+
continue
|
|
684
|
+
|
|
685
|
+
# Check if this is a relative import (level > 0)
|
|
686
|
+
if node.level == 0:
|
|
687
|
+
continue
|
|
688
|
+
|
|
689
|
+
line_num = node.lineno - 1
|
|
690
|
+
if line_num < 0 or line_num >= len(lines):
|
|
691
|
+
continue
|
|
692
|
+
|
|
693
|
+
original_line = lines[line_num]
|
|
694
|
+
|
|
695
|
+
# Convert relative import to absolute based on target location
|
|
696
|
+
# When a file is copied to the package root, relative imports need to be absolute
|
|
697
|
+
# For example: from ._shared.shared_dataclasses -> from _shared.shared_dataclasses
|
|
698
|
+
if node.module:
|
|
699
|
+
# Remove the leading dots and convert to absolute
|
|
700
|
+
# If it was `from ._shared.shared_dataclasses`, it becomes `from _shared.shared_dataclasses`
|
|
701
|
+
absolute_module = node.module
|
|
702
|
+
new_line = re.sub(
|
|
703
|
+
rf"^(\s*)from\s+\.+{re.escape(node.module)}\s+import",
|
|
704
|
+
rf"\1from {absolute_module} import",
|
|
705
|
+
original_line,
|
|
706
|
+
)
|
|
707
|
+
else:
|
|
708
|
+
# from . import X -> from . import X (keep as relative, but at package root level)
|
|
709
|
+
# Actually, if we're at package root, this should work as-is
|
|
710
|
+
# But if the file was in a subdirectory, we need to adjust
|
|
711
|
+
# For now, keep it as relative import
|
|
712
|
+
continue
|
|
713
|
+
|
|
714
|
+
if new_line != original_line:
|
|
715
|
+
lines_to_modify[line_num] = new_line
|
|
716
|
+
modified = True
|
|
717
|
+
|
|
718
|
+
if modified:
|
|
719
|
+
for line_num, new_line in lines_to_modify.items():
|
|
720
|
+
lines[line_num] = new_line
|
|
721
|
+
|
|
722
|
+
new_content = "\n".join(lines)
|
|
723
|
+
if file_path not in self._modified_import_files:
|
|
724
|
+
self._modified_import_files[file_path] = original_content
|
|
725
|
+
|
|
726
|
+
file_path.write_text(new_content, encoding="utf-8")
|
|
727
|
+
print(f"Fixed relative imports in copied file: {file_path}")
|
|
728
|
+
|
|
729
|
+
except Exception as e:
|
|
730
|
+
print(
|
|
731
|
+
f"Warning: Could not fix imports in copied file {file_path}: {e}",
|
|
732
|
+
file=sys.stderr,
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
def _convert_imports_to_relative(
|
|
736
|
+
self, python_files: list[Path], external_deps: list[ExternalDependency]
|
|
737
|
+
) -> None:
|
|
738
|
+
"""
|
|
739
|
+
Convert absolute imports to relative imports for subfolder builds.
|
|
740
|
+
|
|
741
|
+
For subfolder builds, when external dependencies are copied into the subfolder,
|
|
742
|
+
imports need to be converted from absolute to relative so they work correctly
|
|
743
|
+
when the package is installed. This includes:
|
|
744
|
+
1. Imports of copied dependencies (e.g., `from _shared.image_utils` -> `from ._shared.image_utils`)
|
|
745
|
+
2. Imports of local files within the subfolder (e.g., `from detect_empty_drawings_utils` -> `from .detect_empty_drawings_utils`)
|
|
746
|
+
|
|
747
|
+
Args:
|
|
748
|
+
python_files: List of Python files in the source directory
|
|
749
|
+
external_deps: List of external dependencies that were copied
|
|
750
|
+
"""
|
|
751
|
+
import ast
|
|
752
|
+
import re
|
|
753
|
+
|
|
754
|
+
# Build a set of import names that were copied
|
|
755
|
+
copied_import_names: set[str] = set()
|
|
756
|
+
for dep in external_deps:
|
|
757
|
+
root_module = dep.import_name.split(".")[0]
|
|
758
|
+
copied_import_names.add(root_module)
|
|
759
|
+
copied_import_names.add(dep.import_name)
|
|
760
|
+
|
|
761
|
+
# Build a set of local file names in the subfolder (excluding copied dependencies)
|
|
762
|
+
local_file_names: set[str] = set()
|
|
763
|
+
for file_path in python_files:
|
|
764
|
+
# Skip files that are part of copied dependencies
|
|
765
|
+
is_copied_file = any(file_path.is_relative_to(dep.target_path) for dep in external_deps)
|
|
766
|
+
if is_copied_file:
|
|
767
|
+
continue
|
|
768
|
+
if not file_path.is_relative_to(self.src_dir):
|
|
769
|
+
continue
|
|
770
|
+
# Get the module name (filename without .py extension)
|
|
771
|
+
if file_path.suffix == ".py":
|
|
772
|
+
module_name = file_path.stem
|
|
773
|
+
if module_name != "__init__":
|
|
774
|
+
local_file_names.add(module_name)
|
|
775
|
+
|
|
776
|
+
# Only modify files that are in the original subfolder (not the copied dependencies)
|
|
777
|
+
for file_path in python_files:
|
|
778
|
+
# Skip files that are part of copied dependencies
|
|
779
|
+
is_copied_file = any(file_path.is_relative_to(dep.target_path) for dep in external_deps)
|
|
780
|
+
if is_copied_file:
|
|
781
|
+
continue
|
|
782
|
+
|
|
783
|
+
# Skip if file is not in src_dir (shouldn't happen, but safety check)
|
|
784
|
+
if not file_path.is_relative_to(self.src_dir):
|
|
785
|
+
continue
|
|
786
|
+
|
|
787
|
+
try:
|
|
788
|
+
content = file_path.read_text(encoding="utf-8")
|
|
789
|
+
original_content = content
|
|
790
|
+
lines = content.split("\n")
|
|
791
|
+
modified = False
|
|
792
|
+
|
|
793
|
+
# Parse the file with AST to find imports accurately
|
|
794
|
+
try:
|
|
795
|
+
tree = ast.parse(content, filename=str(file_path))
|
|
796
|
+
except SyntaxError:
|
|
797
|
+
# Skip files with syntax errors
|
|
798
|
+
continue
|
|
799
|
+
|
|
800
|
+
# Track which lines need to be modified
|
|
801
|
+
lines_to_modify: dict[int, str] = {}
|
|
802
|
+
|
|
803
|
+
for node in ast.walk(tree):
|
|
804
|
+
if isinstance(node, ast.ImportFrom):
|
|
805
|
+
if node.module is None:
|
|
806
|
+
continue
|
|
807
|
+
|
|
808
|
+
# Check if this import matches a copied dependency or a local file
|
|
809
|
+
root_module = node.module.split(".")[0]
|
|
810
|
+
is_copied_dependency = (
|
|
811
|
+
root_module in copied_import_names or node.module in copied_import_names
|
|
812
|
+
)
|
|
813
|
+
is_local_file = root_module in local_file_names
|
|
814
|
+
|
|
815
|
+
if not is_copied_dependency and not is_local_file:
|
|
816
|
+
continue
|
|
817
|
+
|
|
818
|
+
# Get the line content
|
|
819
|
+
line_num = node.lineno - 1 # Convert to 0-based index
|
|
820
|
+
if line_num < 0 or line_num >= len(lines):
|
|
821
|
+
continue
|
|
822
|
+
|
|
823
|
+
original_line = lines[line_num]
|
|
824
|
+
|
|
825
|
+
# Skip if already a relative import
|
|
826
|
+
if original_line.strip().startswith("from ."):
|
|
827
|
+
continue
|
|
828
|
+
|
|
829
|
+
# Convert absolute import to relative import
|
|
830
|
+
# from _shared.image_utils import ... -> from ._shared.image_utils import ...
|
|
831
|
+
new_line = re.sub(
|
|
832
|
+
rf"^(\s*)from\s+{re.escape(node.module)}\s+import",
|
|
833
|
+
rf"\1from .{node.module} import",
|
|
834
|
+
original_line,
|
|
835
|
+
)
|
|
836
|
+
|
|
837
|
+
if new_line != original_line:
|
|
838
|
+
lines_to_modify[line_num] = new_line
|
|
839
|
+
modified = True
|
|
840
|
+
|
|
841
|
+
elif isinstance(node, ast.Import):
|
|
842
|
+
# Handle "import X" statements
|
|
843
|
+
for alias in node.names:
|
|
844
|
+
root_module = alias.name.split(".")[0]
|
|
845
|
+
is_copied_dependency = root_module in copied_import_names
|
|
846
|
+
is_local_file = root_module in local_file_names
|
|
847
|
+
|
|
848
|
+
if not is_copied_dependency and not is_local_file:
|
|
849
|
+
continue
|
|
850
|
+
|
|
851
|
+
line_num = node.lineno - 1
|
|
852
|
+
if line_num < 0 or line_num >= len(lines):
|
|
853
|
+
continue
|
|
854
|
+
|
|
855
|
+
original_line = lines[line_num]
|
|
856
|
+
|
|
857
|
+
# Skip if already a relative import
|
|
858
|
+
if original_line.strip().startswith("import ."):
|
|
859
|
+
continue
|
|
860
|
+
|
|
861
|
+
# Convert "import _shared" to "from . import _shared"
|
|
862
|
+
# This is more complex, so we'll use a regex replacement
|
|
863
|
+
new_line = re.sub(
|
|
864
|
+
rf"^(\s*)import\s+{re.escape(alias.name)}\b",
|
|
865
|
+
rf"\1from . import {alias.name}",
|
|
866
|
+
original_line,
|
|
867
|
+
)
|
|
868
|
+
|
|
869
|
+
if new_line != original_line:
|
|
870
|
+
lines_to_modify[line_num] = new_line
|
|
871
|
+
modified = True
|
|
872
|
+
|
|
873
|
+
# Apply modifications
|
|
874
|
+
if modified:
|
|
875
|
+
for line_num, new_line in lines_to_modify.items():
|
|
876
|
+
lines[line_num] = new_line
|
|
877
|
+
|
|
878
|
+
new_content = "\n".join(lines)
|
|
879
|
+
# Store original content for restoration
|
|
880
|
+
if file_path not in self._modified_import_files:
|
|
881
|
+
self._modified_import_files[file_path] = original_content
|
|
882
|
+
|
|
883
|
+
# Write modified content
|
|
884
|
+
file_path.write_text(new_content, encoding="utf-8")
|
|
885
|
+
print(f"Converted imports to relative in: {file_path}")
|
|
886
|
+
|
|
887
|
+
except Exception as e:
|
|
888
|
+
print(
|
|
889
|
+
f"Warning: Could not modify imports in {file_path}: {e}",
|
|
890
|
+
file=sys.stderr,
|
|
891
|
+
)
|
|
892
|
+
|
|
632
893
|
def _report_ambiguous_imports(self, python_files: list[Path]) -> None:
|
|
633
894
|
"""
|
|
634
895
|
Report any ambiguous imports that couldn't be resolved.
|
|
@@ -708,6 +969,19 @@ class BuildManager:
|
|
|
708
969
|
self.copied_files.clear()
|
|
709
970
|
self.copied_dirs.clear()
|
|
710
971
|
|
|
972
|
+
# Restore files with modified imports
|
|
973
|
+
for file_path, original_content in self._modified_import_files.items():
|
|
974
|
+
if file_path.exists():
|
|
975
|
+
try:
|
|
976
|
+
file_path.write_text(original_content, encoding="utf-8")
|
|
977
|
+
print(f"Restored original imports in: {file_path}")
|
|
978
|
+
except Exception as e:
|
|
979
|
+
print(
|
|
980
|
+
f"Warning: Could not restore imports in {file_path}: {e}",
|
|
981
|
+
file=sys.stderr,
|
|
982
|
+
)
|
|
983
|
+
self._modified_import_files.clear()
|
|
984
|
+
|
|
711
985
|
# Remove all .egg-info directories in src_dir and project_root
|
|
712
986
|
self._cleanup_egg_info_dirs()
|
|
713
987
|
|
{python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/test_build_with_external_deps.py
RENAMED
|
@@ -363,6 +363,124 @@ class TestBuildManager:
|
|
|
363
363
|
assert len(manager.copied_files) == 0
|
|
364
364
|
assert len(manager.copied_dirs) == 0
|
|
365
365
|
|
|
366
|
+
def test_convert_copied_dependency_imports_to_relative(self, tmp_path: Path) -> None:
|
|
367
|
+
"""Test that absolute imports of copied dependencies are converted to relative imports for subfolder builds."""
|
|
368
|
+
project_root = tmp_path / "test_project"
|
|
369
|
+
project_root.mkdir()
|
|
370
|
+
|
|
371
|
+
# Create pyproject.toml
|
|
372
|
+
(project_root / "pyproject.toml").write_text(
|
|
373
|
+
"""[project]
|
|
374
|
+
name = "test-package"
|
|
375
|
+
version = "0.1.0"
|
|
376
|
+
"""
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
# Create external dependency _shared
|
|
380
|
+
shared_dir = project_root / "_shared"
|
|
381
|
+
shared_dir.mkdir()
|
|
382
|
+
(shared_dir / "__init__.py").write_text("")
|
|
383
|
+
(shared_dir / "image_utils.py").write_text("def save_PIL_image(): pass")
|
|
384
|
+
(shared_dir / "file_utils.py").write_text("def get_filepaths_config(): pass")
|
|
385
|
+
|
|
386
|
+
# Create external dependency _globals
|
|
387
|
+
(project_root / "_globals.py").write_text("is_testing = False")
|
|
388
|
+
|
|
389
|
+
# Create subfolder to build
|
|
390
|
+
subfolder = project_root / "src" / "integration" / "empty_drawing_detection"
|
|
391
|
+
subfolder.mkdir(parents=True)
|
|
392
|
+
(subfolder / "__init__.py").write_text("")
|
|
393
|
+
|
|
394
|
+
# Create a local file that will be imported
|
|
395
|
+
local_file = subfolder / "local_utils.py"
|
|
396
|
+
local_file.write_text("def local_function(): return 42")
|
|
397
|
+
|
|
398
|
+
# Create a file in subfolder that imports copied dependencies with absolute imports
|
|
399
|
+
test_file = subfolder / "detect_empty_drawings.py"
|
|
400
|
+
original_content = """from pathlib import Path
|
|
401
|
+
from _shared.image_utils import save_PIL_image
|
|
402
|
+
from _shared.file_utils import get_filepaths_config
|
|
403
|
+
from _globals import is_testing
|
|
404
|
+
from local_utils import local_function
|
|
405
|
+
from config import get_config
|
|
406
|
+
|
|
407
|
+
def analyze_folder():
|
|
408
|
+
save_PIL_image()
|
|
409
|
+
get_filepaths_config()
|
|
410
|
+
return is_testing
|
|
411
|
+
"""
|
|
412
|
+
test_file.write_text(original_content)
|
|
413
|
+
|
|
414
|
+
# Create another file with different import style
|
|
415
|
+
test_file2 = subfolder / "config.py"
|
|
416
|
+
original_content2 = """import _globals
|
|
417
|
+
|
|
418
|
+
def get_config():
|
|
419
|
+
return _globals.is_testing
|
|
420
|
+
"""
|
|
421
|
+
test_file2.write_text(original_content2)
|
|
422
|
+
|
|
423
|
+
# Create a copied dependency file with relative imports (simulating detect_empty_drawings_utils.py)
|
|
424
|
+
# This will be created when _shared is copied
|
|
425
|
+
# First, let's create a file in _shared that will be copied
|
|
426
|
+
shared_utils = shared_dir / "shared_utils.py"
|
|
427
|
+
shared_utils.write_text(
|
|
428
|
+
"""from .file_utils import get_filepaths_config
|
|
429
|
+
|
|
430
|
+
def shared_function():
|
|
431
|
+
return get_filepaths_config()
|
|
432
|
+
"""
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
manager = BuildManager(project_root, subfolder)
|
|
436
|
+
|
|
437
|
+
try:
|
|
438
|
+
# Prepare build - this should copy dependencies and convert imports
|
|
439
|
+
external_deps = manager.prepare_build(version="1.0.0", package_name="test-package")
|
|
440
|
+
|
|
441
|
+
# Verify dependencies were copied
|
|
442
|
+
assert len(external_deps) >= 2
|
|
443
|
+
assert (subfolder / "_shared").exists()
|
|
444
|
+
assert (subfolder / "_globals.py").exists()
|
|
445
|
+
|
|
446
|
+
# Verify imports were converted to relative
|
|
447
|
+
modified_content = test_file.read_text()
|
|
448
|
+
assert "from ._shared.image_utils import save_PIL_image" in modified_content
|
|
449
|
+
assert "from ._shared.file_utils import get_filepaths_config" in modified_content
|
|
450
|
+
assert "from ._globals import is_testing" in modified_content
|
|
451
|
+
# Verify local file imports were converted to relative
|
|
452
|
+
assert "from .local_utils import local_function" in modified_content
|
|
453
|
+
assert "from .config import get_config" in modified_content
|
|
454
|
+
# Verify stdlib import was not changed
|
|
455
|
+
assert "from pathlib import Path" in modified_content
|
|
456
|
+
|
|
457
|
+
# Verify import statement conversion
|
|
458
|
+
modified_content2 = test_file2.read_text()
|
|
459
|
+
assert "from . import _globals" in modified_content2
|
|
460
|
+
|
|
461
|
+
# Verify relative imports in copied files were fixed
|
|
462
|
+
if (subfolder / "_shared" / "shared_utils.py").exists():
|
|
463
|
+
shared_utils_content = (subfolder / "_shared" / "shared_utils.py").read_text()
|
|
464
|
+
# The relative import should be converted to absolute
|
|
465
|
+
assert (
|
|
466
|
+
"from .file_utils import" not in shared_utils_content
|
|
467
|
+
or "from file_utils import" in shared_utils_content
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
# Cleanup should restore original imports
|
|
471
|
+
manager.cleanup()
|
|
472
|
+
|
|
473
|
+
restored_content = test_file.read_text()
|
|
474
|
+
assert restored_content == original_content
|
|
475
|
+
|
|
476
|
+
restored_content2 = test_file2.read_text()
|
|
477
|
+
assert restored_content2 == original_content2
|
|
478
|
+
|
|
479
|
+
finally:
|
|
480
|
+
# Ensure cleanup even if test fails
|
|
481
|
+
if manager._modified_import_files:
|
|
482
|
+
manager.cleanup()
|
|
483
|
+
|
|
366
484
|
|
|
367
485
|
class TestRealFolderStructure:
|
|
368
486
|
"""Tests using the real folder_structure from tests directory."""
|
|
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-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/__init__.py
RENAMED
|
File without changes
|
{python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/__main__.py
RENAMED
|
File without changes
|
{python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/analyzer.py
RENAMED
|
File without changes
|
{python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/finder.py
RENAMED
|
File without changes
|
{python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/publisher.py
RENAMED
|
File without changes
|
{python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/types.py
RENAMED
|
File without changes
|
{python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/utils.py
RENAMED
|
File without changes
|
{python_package_folder-3.1.1 → python_package_folder-3.1.3}/src/python_package_folder/version.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_package_folder-3.1.1 → python_package_folder-3.1.3}/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
|
|
File without changes
|
|
File without changes
|
{python_package_folder-3.1.1 → python_package_folder-3.1.3}/tests/test_third_party_dependencies.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|