python-package-folder 5.1.3__tar.gz → 5.1.5__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.
Files changed (60) hide show
  1. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/PKG-INFO +1 -1
  2. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/coverage.svg +2 -2
  3. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/pyproject.toml +1 -1
  4. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/src/python_package_folder/subfolder_build.py +45 -34
  5. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/test_exclude_patterns.py +84 -0
  6. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/.copier-answers.yml +0 -0
  7. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/.cursor/plans/optional_version_+_semantic-release_efed88a6.plan.md +0 -0
  8. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/.cursor/plans/replace_node.js_semantic-release_with_custom_python_implementation_64e05e1a.plan.md +0 -0
  9. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/.cursor/rules/general.mdc +0 -0
  10. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/.cursor/rules/python.mdc +0 -0
  11. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/.github/workflows/ci.yml +0 -0
  12. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/.github/workflows/publish.yml +0 -0
  13. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/.gitignore +0 -0
  14. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/.vscode/settings.json +0 -0
  15. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/LICENSE +0 -0
  16. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/MANIFEST.in +0 -0
  17. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/Makefile +0 -0
  18. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/README.md +0 -0
  19. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/development.md +0 -0
  20. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/docs/DEVELOPMENT.md +0 -0
  21. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/docs/INSTALLATION.md +0 -0
  22. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/docs/PUBLISHING.md +0 -0
  23. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/docs/REFERENCE.md +0 -0
  24. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/docs/USAGE.md +0 -0
  25. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/docs/VERSION_RESOLUTION.md +0 -0
  26. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/installation.md +0 -0
  27. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/publishing.md +0 -0
  28. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/src/python_package_folder/__init__.py +0 -0
  29. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/src/python_package_folder/__main__.py +0 -0
  30. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/src/python_package_folder/analyzer.py +0 -0
  31. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/src/python_package_folder/finder.py +0 -0
  32. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/src/python_package_folder/manager.py +0 -0
  33. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/src/python_package_folder/publisher.py +0 -0
  34. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/src/python_package_folder/py.typed +0 -0
  35. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/src/python_package_folder/python_package_folder.py +0 -0
  36. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/src/python_package_folder/types.py +0 -0
  37. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/src/python_package_folder/utils.py +0 -0
  38. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/src/python_package_folder/version.py +0 -0
  39. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/src/python_package_folder/version_calculator.py +0 -0
  40. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/conftest.py +0 -0
  41. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/folder_structure/some_globals.py +0 -0
  42. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/folder_structure/subfolder_to_build/README.md +0 -0
  43. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/folder_structure/subfolder_to_build/__init__.py +0 -0
  44. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/folder_structure/subfolder_to_build/some_function.py +0 -0
  45. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/folder_structure/subfolder_to_build/some_globals.py +0 -0
  46. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/folder_structure/utility_folder/_SS/some_superseded_file.py +0 -0
  47. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/folder_structure/utility_folder/some_utility.py +0 -0
  48. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/test_build_with_external_deps.py +0 -0
  49. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/test_linting.py +0 -0
  50. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/test_preserve_directory_structure.py +0 -0
  51. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/test_publisher.py +0 -0
  52. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/test_shared_subdirectory_imports.py +0 -0
  53. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/test_spreadsheet_creation_imports.py +0 -0
  54. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/test_subfolder_build.py +0 -0
  55. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/test_third_party_dependencies.py +0 -0
  56. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/test_utils.py +0 -0
  57. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/test_version_calculator.py +0 -0
  58. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/test_version_manager.py +0 -0
  59. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/tests/tests.py +0 -0
  60. {python_package_folder-5.1.3 → python_package_folder-5.1.5}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-package-folder
3
- Version: 5.1.3
3
+ Version: 5.1.5
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">66%</text>
18
- <text x="81" y="14">66%</text>
17
+ <text x="81" y="15" fill="#010101" fill-opacity=".3">68%</text>
18
+ <text x="81" y="14">68%</text>
19
19
  </g>
20
20
  </svg>
@@ -43,7 +43,7 @@ dependencies = [
43
43
 
44
44
  # ---- Dev dependencies ----
45
45
 
46
- version = "5.1.3"
46
+ version = "5.1.5"
47
47
  [dependency-groups]
48
48
  dev = [
49
49
  "pytest>=8.3.5",
@@ -357,6 +357,13 @@ class SubfolderBuildConfig:
357
357
 
358
358
  original_content = original_pyproject.read_text(encoding="utf-8")
359
359
 
360
+ # Read exclude patterns from root pyproject.toml BEFORE moving the file
361
+ exclude_patterns = read_exclude_patterns(original_pyproject)
362
+ print(
363
+ f"INFO: Read exclude patterns from {original_pyproject}: {exclude_patterns}",
364
+ file=sys.stderr,
365
+ )
366
+
360
367
  # Store reference to original
361
368
  self.original_pyproject_path = original_pyproject
362
369
 
@@ -391,13 +398,6 @@ class SubfolderBuildConfig:
391
398
  file=sys.stderr,
392
399
  )
393
400
 
394
- # Read exclude patterns from root pyproject.toml
395
- exclude_patterns = read_exclude_patterns(original_pyproject)
396
- print(
397
- f"INFO: Read exclude patterns from {original_pyproject}: {exclude_patterns}",
398
- file=sys.stderr,
399
- )
400
-
401
401
  if data:
402
402
  # Modify using parsed data
403
403
  if "project" in data:
@@ -694,44 +694,55 @@ class SubfolderBuildConfig:
694
694
  # Usually after [dependency-groups] or at the end
695
695
  insert_index = len(result)
696
696
  tool_section_exists = False
697
+ tool_section_start = -1
698
+ tool_section_end = -1
699
+
700
+ # First, search specifically for [tool.python-package-folder]
697
701
  for i, line in enumerate(result):
698
702
  if line.strip() == "[tool.python-package-folder]":
699
703
  tool_section_exists = True
700
- insert_index = i
701
- break
702
- elif line.strip().startswith("[tool.") and i > 0:
703
- # Insert before other tool sections
704
- insert_index = i
704
+ tool_section_start = i
705
+ # Find end of section (next [section] or end of file)
706
+ for j in range(i + 1, len(result)):
707
+ if result[j].strip().startswith("["):
708
+ tool_section_end = j
709
+ break
710
+ if tool_section_end == -1:
711
+ tool_section_end = len(result)
705
712
  break
713
+
714
+ # If not found, find a good insertion point before other [tool.*] sections
715
+ if not tool_section_exists:
716
+ for i, line in enumerate(result):
717
+ if line.strip().startswith("[tool.") and i > 0:
718
+ # Insert before other tool sections
719
+ insert_index = i
720
+ break
706
721
 
707
722
  # Format exclude patterns
708
723
  patterns_str = ", ".join(f'"{p}"' for p in exclude_patterns)
709
- exclude_lines = [
710
- "",
711
- "[tool.python-package-folder]",
712
- f'exclude-patterns = [{patterns_str}]',
713
- ]
714
724
 
715
725
  if tool_section_exists:
716
- # Replace or update existing section
717
- end_index = insert_index + 1
718
- while end_index < len(result) and not result[end_index].strip().startswith("["):
719
- end_index += 1
720
- # Check if exclude-patterns already exists
721
- has_exclude_patterns = any(
722
- "exclude-patterns" in result[i] for i in range(insert_index, end_index)
723
- )
724
- if has_exclude_patterns:
725
- # Update existing exclude-patterns line
726
- for i in range(insert_index, end_index):
727
- if "exclude-patterns" in result[i]:
728
- result[i] = f'exclude-patterns = [{patterns_str}]'
729
- break
730
- else:
731
- # Add exclude-patterns to existing section
732
- result.insert(end_index - 1, f'exclude-patterns = [{patterns_str}]')
726
+ # Update existing section
727
+ # Check if exclude-patterns already exists in the section
728
+ has_exclude_patterns = False
729
+ for i in range(tool_section_start + 1, tool_section_end):
730
+ if "exclude-patterns" in result[i]:
731
+ has_exclude_patterns = True
732
+ # Update the existing line
733
+ result[i] = f'exclude-patterns = [{patterns_str}]'
734
+ break
735
+
736
+ if not has_exclude_patterns:
737
+ # Add exclude-patterns to existing section (before the next section)
738
+ result.insert(tool_section_end, f'exclude-patterns = [{patterns_str}]')
733
739
  else:
734
740
  # Insert new section
741
+ exclude_lines = [
742
+ "",
743
+ "[tool.python-package-folder]",
744
+ f'exclude-patterns = [{patterns_str}]',
745
+ ]
735
746
  result[insert_index:insert_index] = exclude_lines
736
747
 
737
748
  return "\n".join(result)
@@ -184,3 +184,87 @@ class TestExcludePatternsInBuild:
184
184
  assert ".*_test.*" in content
185
185
 
186
186
  config.restore()
187
+
188
+ def test_exclude_patterns_no_subfolder_toml(self, test_project_with_exclude_patterns: Path) -> None:
189
+ """Test that exclude patterns are read correctly when there's no subfolder pyproject.toml."""
190
+ project_root = test_project_with_exclude_patterns
191
+ src_dir = project_root / "src" / "test_package"
192
+
193
+ # This simulates the scenario where there's no subfolder pyproject.toml
194
+ # and we need to read exclude patterns from the root before it's moved
195
+ config = SubfolderBuildConfig(
196
+ project_root=project_root,
197
+ src_dir=src_dir,
198
+ package_name="test-package",
199
+ version="1.0.0",
200
+ )
201
+
202
+ # Create temporary pyproject.toml (this will read exclude patterns before moving root toml)
203
+ temp_pyproject = config.create_temp_pyproject()
204
+ assert temp_pyproject is not None
205
+
206
+ # Check that exclude patterns are in the temporary pyproject.toml
207
+ content = temp_pyproject.read_text()
208
+ assert "[tool.python-package-folder]" in content
209
+ assert "exclude-patterns" in content
210
+ assert "_SS" in content
211
+ assert ".*_test.*" in content
212
+ assert "sandbox" in content
213
+
214
+ # Verify there's only ONE [tool.python-package-folder] section (no duplicates)
215
+ sections = [line for line in content.split("\n") if line.strip() == "[tool.python-package-folder]"]
216
+ assert len(sections) == 1, f"Found {len(sections)} duplicate [tool.python-package-folder] sections"
217
+
218
+ config.restore()
219
+
220
+ def test_exclude_patterns_no_duplicate_section(self, tmp_path: Path) -> None:
221
+ """Test that exclude patterns don't create duplicate sections when original already has it."""
222
+ project_root = tmp_path / "test_project"
223
+ project_root.mkdir()
224
+
225
+ # Create pyproject.toml with existing [tool.python-package-folder] section
226
+ pyproject_content = """[project]
227
+ name = "test-package"
228
+ version = "0.1.0"
229
+
230
+ [build-system]
231
+ requires = ["hatchling"]
232
+ build-backend = "hatchling.build"
233
+
234
+ [tool.hatch.build.targets.wheel]
235
+ packages = ["src/test_package"]
236
+
237
+ [tool.python-package-folder]
238
+ exclude-patterns = ["_SS", ".*_test.*"]
239
+
240
+ [tool.pylint.'TYPECHECK']
241
+ generated-members = ["networkx.*"]
242
+ """
243
+ (project_root / "pyproject.toml").write_text(pyproject_content)
244
+
245
+ # Create source directory
246
+ src_dir = project_root / "src" / "test_package"
247
+ src_dir.mkdir(parents=True)
248
+ (src_dir / "__init__.py").write_text("")
249
+
250
+ config = SubfolderBuildConfig(
251
+ project_root=project_root,
252
+ src_dir=src_dir,
253
+ package_name="test-package",
254
+ version="1.0.0",
255
+ )
256
+
257
+ # Create temporary pyproject.toml
258
+ temp_pyproject = config.create_temp_pyproject()
259
+ assert temp_pyproject is not None
260
+
261
+ # Check that there's only ONE [tool.python-package-folder] section
262
+ content = temp_pyproject.read_text()
263
+ sections = [line for line in content.split("\n") if line.strip() == "[tool.python-package-folder]"]
264
+ assert len(sections) == 1, f"Found {len(sections)} duplicate [tool.python-package-folder] sections: {sections}"
265
+
266
+ # Verify exclude-patterns is present
267
+ assert "exclude-patterns" in content
268
+ assert "_SS" in content
269
+
270
+ config.restore()