python-package-folder 4.2.0__tar.gz → 4.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. python_package_folder-4.3.1/MANIFEST.in +2 -0
  2. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/PKG-INFO +1 -1
  3. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/pyproject.toml +2 -1
  4. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/python_package_folder/scripts/get-next-version.cjs +85 -30
  5. python_package_folder-4.3.1/src/python_package_folder/_hatch_build.py +84 -0
  6. python_package_folder-4.2.0/src/python_package_folder/_hatch_build.py +0 -54
  7. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/.copier-answers.yml +0 -0
  8. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/.cursor/plans/optional_version_+_semantic-release_efed88a6.plan.md +0 -0
  9. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/.cursor/rules/general.mdc +0 -0
  10. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/.cursor/rules/python.mdc +0 -0
  11. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/.github/workflows/ci.yml +0 -0
  12. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/.github/workflows/publish.yml +0 -0
  13. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/.gitignore +0 -0
  14. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/.vscode/settings.json +0 -0
  15. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/LICENSE +0 -0
  16. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/Makefile +0 -0
  17. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/README.md +0 -0
  18. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/coverage.svg +0 -0
  19. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/development.md +0 -0
  20. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/installation.md +0 -0
  21. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/publishing.md +0 -0
  22. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/scripts/get-next-version.cjs +0 -0
  23. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/src/python_package_folder/__init__.py +0 -0
  24. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/src/python_package_folder/__main__.py +0 -0
  25. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/src/python_package_folder/analyzer.py +0 -0
  26. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/src/python_package_folder/finder.py +0 -0
  27. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/src/python_package_folder/manager.py +0 -0
  28. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/src/python_package_folder/publisher.py +0 -0
  29. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/src/python_package_folder/py.typed +0 -0
  30. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/src/python_package_folder/python_package_folder.py +0 -0
  31. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/src/python_package_folder/subfolder_build.py +0 -0
  32. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/src/python_package_folder/types.py +0 -0
  33. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/src/python_package_folder/utils.py +0 -0
  34. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/src/python_package_folder/version.py +0 -0
  35. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/conftest.py +0 -0
  36. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/folder_structure/some_globals.py +0 -0
  37. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/folder_structure/subfolder_to_build/README.md +0 -0
  38. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/folder_structure/subfolder_to_build/__init__.py +0 -0
  39. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/folder_structure/subfolder_to_build/some_function.py +0 -0
  40. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/folder_structure/subfolder_to_build/some_globals.py +0 -0
  41. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/folder_structure/utility_folder/_SS/some_superseded_file.py +0 -0
  42. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/folder_structure/utility_folder/some_utility.py +0 -0
  43. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/test_build_with_external_deps.py +0 -0
  44. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/test_linting.py +0 -0
  45. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/test_preserve_directory_structure.py +0 -0
  46. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/test_publisher.py +0 -0
  47. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/test_shared_subdirectory_imports.py +0 -0
  48. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/test_spreadsheet_creation_imports.py +0 -0
  49. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/test_subfolder_build.py +0 -0
  50. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/test_third_party_dependencies.py +0 -0
  51. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/test_utils.py +0 -0
  52. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/test_version_manager.py +0 -0
  53. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/tests/tests.py +0 -0
  54. {python_package_folder-4.2.0 → python_package_folder-4.3.1}/uv.lock +0 -0
@@ -0,0 +1,2 @@
1
+ include src/python_package_folder/scripts/get-next-version.cjs
2
+ recursive-include src/python_package_folder/scripts *.cjs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-package-folder
3
- Version: 4.2.0
3
+ Version: 4.3.1
4
4
  Summary: Python package to automatically package and build a folder, fetching all relevant dependencies.
5
5
  Project-URL: Repository, https://github.com/alelom/python-package-folder
6
6
  Author-email: Alessio Lombardi <work@alelom.com>
@@ -42,7 +42,7 @@ dependencies = [
42
42
 
43
43
  # ---- Dev dependencies ----
44
44
 
45
- version = "4.2.0"
45
+ version = "4.3.1"
46
46
  [dependency-groups]
47
47
  dev = [
48
48
  "pytest>=8.3.5",
@@ -75,6 +75,7 @@ build-backend = "hatchling.build"
75
75
  path = "src/python_package_folder/_hatch_build.py"
76
76
 
77
77
 
78
+
78
79
  # ---- Settings ----
79
80
 
80
81
  [tool.ruff]
@@ -26,6 +26,7 @@ const path = require('path');
26
26
  const fs = require('fs');
27
27
  const https = require('https');
28
28
  const http = require('http');
29
+ const { execSync } = require('child_process');
29
30
 
30
31
  // Parse command line arguments
31
32
  const args = process.argv.slice(2);
@@ -310,48 +311,102 @@ async function queryRegistryVersion(packageName, repository, repositoryUrl) {
310
311
  return null;
311
312
  }
312
313
 
314
+ /**
315
+ * Get global npm prefix for module resolution.
316
+ * This helps find globally installed npm packages.
317
+ * @returns {string|null} Path to global node_modules or null if not found
318
+ */
319
+ function getGlobalNpmPrefix() {
320
+ try {
321
+ // Get npm's global prefix (where global packages are installed)
322
+ const prefix = execSync('npm config get prefix', { encoding: 'utf8' }).trim();
323
+ // Global node_modules is typically at <prefix>/lib/node_modules
324
+ const globalNodeModules = path.join(prefix, 'lib', 'node_modules');
325
+ if (fs.existsSync(globalNodeModules)) {
326
+ return globalNodeModules;
327
+ }
328
+ // Alternative location on some systems
329
+ const altGlobalNodeModules = path.join(prefix, 'node_modules');
330
+ if (fs.existsSync(altGlobalNodeModules)) {
331
+ return altGlobalNodeModules;
332
+ }
333
+ return null;
334
+ } catch (e) {
335
+ // If npm config fails, try to find it via NODE_PATH or common locations
336
+ return null;
337
+ }
338
+ }
339
+
313
340
  // Main execution
314
341
  (async () => {
315
342
  try {
343
+ // Get global npm path for module resolution
344
+ const globalNpmPath = getGlobalNpmPrefix();
345
+ const resolvePaths = [projectRoot];
346
+ if (globalNpmPath) {
347
+ resolvePaths.push(globalNpmPath);
348
+ }
349
+
316
350
  // Try to require semantic-release
317
- // First try resolving from project root (for devDependencies), then fall back to global
351
+ // First try resolving from project root (for devDependencies), then try global, then fall back to default
318
352
  let semanticRelease;
319
- try {
320
- const semanticReleasePath = require.resolve('semantic-release', { paths: [projectRoot] });
321
- semanticRelease = require(semanticReleasePath);
322
- } catch (resolveError) {
323
353
  try {
324
- semanticRelease = require('semantic-release');
325
- } catch (e) {
326
- console.error('Error: semantic-release is not installed.');
327
- console.error('Please install it with: npm install -g semantic-release');
328
- console.error('Or install it as a devDependency: npm install --save-dev semantic-release');
329
- if (isSubfolderBuild) {
330
- console.error('For subfolder builds, also install: npm install -g semantic-release-commit-filter');
331
- console.error('Or as devDependency: npm install --save-dev semantic-release-commit-filter');
354
+ const semanticReleasePath = require.resolve('semantic-release', { paths: resolvePaths });
355
+ semanticRelease = require(semanticReleasePath);
356
+ } catch (resolveError) {
357
+ try {
358
+ // Try with just global path
359
+ if (globalNpmPath) {
360
+ const semanticReleasePath = require.resolve('semantic-release', { paths: [globalNpmPath] });
361
+ semanticRelease = require(semanticReleasePath);
362
+ } else {
363
+ throw resolveError;
364
+ }
365
+ } catch (globalError) {
366
+ try {
367
+ // Final fallback: default require (should work if in NODE_PATH or default locations)
368
+ semanticRelease = require('semantic-release');
369
+ } catch (e) {
370
+ console.error('Error: semantic-release is not installed.');
371
+ console.error('Please install it with: npm install -g semantic-release');
372
+ console.error('Or install it as a devDependency: npm install --save-dev semantic-release');
373
+ if (isSubfolderBuild) {
374
+ console.error('For subfolder builds, also install: npm install -g semantic-release-commit-filter');
375
+ console.error('Or as devDependency: npm install --save-dev semantic-release-commit-filter');
376
+ }
377
+ process.exit(1);
378
+ }
332
379
  }
333
- process.exit(1);
334
380
  }
335
- }
336
381
 
337
- // For subfolder builds, require semantic-release-commit-filter
338
- // (required only to verify it's installed; the plugin is used via options.plugins)
339
- // First try resolving from project root (for devDependencies), then fall back to global
340
- if (isSubfolderBuild) {
341
- try {
342
- const commitFilterPath = require.resolve('semantic-release-commit-filter', { paths: [projectRoot] });
343
- require(commitFilterPath);
344
- } catch (resolveError) {
382
+ // For subfolder builds, require semantic-release-commit-filter
383
+ // (required only to verify it's installed; the plugin is used via options.plugins)
384
+ if (isSubfolderBuild) {
345
385
  try {
346
- require('semantic-release-commit-filter');
347
- } catch (e) {
348
- console.error('Error: semantic-release-commit-filter is not installed.');
349
- console.error('Please install it with: npm install -g semantic-release-commit-filter');
350
- console.error('Or install it as a devDependency: npm install --save-dev semantic-release-commit-filter');
351
- process.exit(1);
386
+ const commitFilterPath = require.resolve('semantic-release-commit-filter', { paths: resolvePaths });
387
+ require(commitFilterPath);
388
+ } catch (resolveError) {
389
+ try {
390
+ // Try with just global path
391
+ if (globalNpmPath) {
392
+ const commitFilterPath = require.resolve('semantic-release-commit-filter', { paths: [globalNpmPath] });
393
+ require(commitFilterPath);
394
+ } else {
395
+ throw resolveError;
396
+ }
397
+ } catch (globalError) {
398
+ try {
399
+ // Final fallback: default require
400
+ require('semantic-release-commit-filter');
401
+ } catch (e) {
402
+ console.error('Error: semantic-release-commit-filter is not installed.');
403
+ console.error('Please install it with: npm install -g semantic-release-commit-filter');
404
+ console.error('Or install it as a devDependency: npm install --save-dev semantic-release-commit-filter');
405
+ process.exit(1);
406
+ }
407
+ }
352
408
  }
353
409
  }
354
- }
355
410
 
356
411
  // Query registry for latest version if repository info is provided
357
412
  let registryVersion = null;
@@ -0,0 +1,84 @@
1
+ """
2
+ Hatch build hook to automatically include all files from the scripts directory.
3
+
4
+ This hook ensures all non-Python files in the scripts directory are included
5
+ in the wheel without creating duplicates, and automatically includes any new
6
+ files added to the directory without requiring manual configuration updates.
7
+ """
8
+
9
+ import sys
10
+ from pathlib import Path
11
+ from typing import Any
12
+
13
+ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
14
+
15
+
16
+ class CustomBuildHook(BuildHookInterface):
17
+ """Build hook to include all files from the scripts directory."""
18
+
19
+ def initialize(self, version: str, build_data: dict[str, Any]) -> None:
20
+ """Initialize the build hook and add scripts directory files."""
21
+ # Debug: Print to stderr so it shows in build output
22
+ print(f"[DEBUG] Build hook called. Root: {self.root}", file=sys.stderr)
23
+
24
+ # Try multiple possible locations for the scripts directory
25
+ # 1. Source layout: src/python_package_folder/scripts
26
+ # 2. Sdist layout: python_package_folder/scripts (after extraction)
27
+ # 3. Alternative sdist layout: scripts/ (if extracted differently)
28
+ possible_scripts_dirs = [
29
+ Path(self.root) / "src" / "python_package_folder" / "scripts",
30
+ Path(self.root) / "python_package_folder" / "scripts",
31
+ Path(self.root) / "scripts",
32
+ ]
33
+
34
+ scripts_dir = None
35
+ for possible_dir in possible_scripts_dirs:
36
+ if possible_dir.exists() and possible_dir.is_dir():
37
+ scripts_dir = possible_dir
38
+ print(f"[DEBUG] Found scripts dir at: {scripts_dir}", file=sys.stderr)
39
+ break
40
+
41
+ if scripts_dir is None:
42
+ print(f"[DEBUG] Scripts directory not found. Tried: {[str(d) for d in possible_scripts_dirs]}", file=sys.stderr)
43
+ return
44
+
45
+ # If scripts directory exists, include all files from it
46
+ if scripts_dir.exists() and scripts_dir.is_dir():
47
+ # Add all files from scripts directory to force-include
48
+ # This ensures they're included in the wheel at the correct location
49
+ for script_file in scripts_dir.iterdir():
50
+ if script_file.is_file():
51
+ # Calculate relative paths from project root
52
+ try:
53
+ source_path = script_file.relative_to(self.root)
54
+ except ValueError:
55
+ # If relative_to fails, try to construct path manually
56
+ # This can happen with sdist layouts
57
+ if "python_package_folder" in str(script_file):
58
+ # Extract the part after python_package_folder
59
+ parts = script_file.parts
60
+ try:
61
+ idx = parts.index("python_package_folder")
62
+ source_path = Path(*parts[idx:])
63
+ except (ValueError, IndexError):
64
+ # Fallback: use the filename
65
+ source_path = Path("python_package_folder") / "scripts" / script_file.name
66
+ else:
67
+ source_path = Path("python_package_folder") / "scripts" / script_file.name
68
+
69
+ # Target path inside the wheel package (always the same)
70
+ target_path = f"python_package_folder/scripts/{script_file.name}"
71
+
72
+ print(f"[DEBUG] Adding {source_path} -> {target_path}", file=sys.stderr)
73
+
74
+ # Add to force-include (hatchling will handle this)
75
+ # We need to add it to build_data['force_include']
76
+ if "force_include" not in build_data:
77
+ build_data["force_include"] = {}
78
+ build_data["force_include"][str(source_path)] = target_path
79
+
80
+ print(f"[DEBUG] force_include now has {len(build_data.get('force_include', {}))} entries", file=sys.stderr)
81
+
82
+
83
+ # Export the hook class (hatchling might need this)
84
+ __all__ = ["CustomBuildHook"]
@@ -1,54 +0,0 @@
1
- """
2
- Hatch build hook to automatically include all files from the scripts directory.
3
-
4
- This hook ensures all non-Python files in the scripts directory are included
5
- in the wheel without creating duplicates, and automatically includes any new
6
- files added to the directory without requiring manual configuration updates.
7
- """
8
-
9
- import sys
10
- from pathlib import Path
11
- from typing import Any
12
-
13
- from hatchling.builders.hooks.plugin.interface import BuildHookInterface
14
-
15
-
16
- class CustomBuildHook(BuildHookInterface):
17
- """Build hook to include all files from the scripts directory."""
18
-
19
- def initialize(self, version: str, build_data: dict[str, Any]) -> None:
20
- """Initialize the build hook and add scripts directory files."""
21
- # Get the source directory for the package
22
- source_dir = Path(self.root) / "src" / "python_package_folder"
23
- scripts_dir = source_dir / "scripts"
24
-
25
- # Debug: Print to stderr so it shows in build output
26
- print(f"[DEBUG] Build hook called. Root: {self.root}", file=sys.stderr)
27
- print(f"[DEBUG] Scripts dir exists: {scripts_dir.exists()}", file=sys.stderr)
28
-
29
- # If scripts directory exists, include all files from it
30
- if scripts_dir.exists() and scripts_dir.is_dir():
31
- # Add all files from scripts directory to force-include
32
- # This ensures they're included in the wheel at the correct location
33
- for script_file in scripts_dir.iterdir():
34
- if script_file.is_file():
35
- # Calculate relative paths
36
- source_path = script_file.relative_to(self.root)
37
- # Target path inside the wheel package
38
- target_path = f"python_package_folder/scripts/{script_file.name}"
39
-
40
- print(f"[DEBUG] Adding {source_path} -> {target_path}", file=sys.stderr)
41
-
42
- # Add to force-include (hatchling will handle this)
43
- # We need to add it to build_data['force_include']
44
- if "force_include" not in build_data:
45
- build_data["force_include"] = {}
46
- build_data["force_include"][str(source_path)] = target_path
47
-
48
- print(f"[DEBUG] force_include now has {len(build_data.get('force_include', {}))} entries", file=sys.stderr)
49
- else:
50
- print(f"[DEBUG] Scripts directory not found at {scripts_dir}", file=sys.stderr)
51
-
52
-
53
- # Export the hook class (hatchling might need this)
54
- __all__ = ["CustomBuildHook"]