python-package-folder 5.1.5__tar.gz → 5.1.6__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.5 → python_package_folder-5.1.6}/PKG-INFO +1 -1
  2. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/pyproject.toml +1 -1
  3. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/src/python_package_folder/publisher.py +60 -14
  4. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/.copier-answers.yml +0 -0
  5. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/.cursor/plans/optional_version_+_semantic-release_efed88a6.plan.md +0 -0
  6. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/.cursor/plans/replace_node.js_semantic-release_with_custom_python_implementation_64e05e1a.plan.md +0 -0
  7. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/.cursor/rules/general.mdc +0 -0
  8. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/.cursor/rules/python.mdc +0 -0
  9. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/.github/workflows/ci.yml +0 -0
  10. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/.github/workflows/publish.yml +0 -0
  11. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/.gitignore +0 -0
  12. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/.vscode/settings.json +0 -0
  13. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/LICENSE +0 -0
  14. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/MANIFEST.in +0 -0
  15. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/Makefile +0 -0
  16. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/README.md +0 -0
  17. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/coverage.svg +0 -0
  18. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/development.md +0 -0
  19. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/docs/DEVELOPMENT.md +0 -0
  20. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/docs/INSTALLATION.md +0 -0
  21. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/docs/PUBLISHING.md +0 -0
  22. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/docs/REFERENCE.md +0 -0
  23. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/docs/USAGE.md +0 -0
  24. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/docs/VERSION_RESOLUTION.md +0 -0
  25. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/installation.md +0 -0
  26. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/publishing.md +0 -0
  27. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/src/python_package_folder/__init__.py +0 -0
  28. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/src/python_package_folder/__main__.py +0 -0
  29. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/src/python_package_folder/analyzer.py +0 -0
  30. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/src/python_package_folder/finder.py +0 -0
  31. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/src/python_package_folder/manager.py +0 -0
  32. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/src/python_package_folder/py.typed +0 -0
  33. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/src/python_package_folder/python_package_folder.py +0 -0
  34. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/src/python_package_folder/subfolder_build.py +0 -0
  35. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/src/python_package_folder/types.py +0 -0
  36. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/src/python_package_folder/utils.py +0 -0
  37. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/src/python_package_folder/version.py +0 -0
  38. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/src/python_package_folder/version_calculator.py +0 -0
  39. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/conftest.py +0 -0
  40. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/folder_structure/some_globals.py +0 -0
  41. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/folder_structure/subfolder_to_build/README.md +0 -0
  42. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/folder_structure/subfolder_to_build/__init__.py +0 -0
  43. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/folder_structure/subfolder_to_build/some_function.py +0 -0
  44. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/folder_structure/subfolder_to_build/some_globals.py +0 -0
  45. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/folder_structure/utility_folder/_SS/some_superseded_file.py +0 -0
  46. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/folder_structure/utility_folder/some_utility.py +0 -0
  47. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/test_build_with_external_deps.py +0 -0
  48. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/test_exclude_patterns.py +0 -0
  49. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/test_linting.py +0 -0
  50. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/test_preserve_directory_structure.py +0 -0
  51. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/test_publisher.py +0 -0
  52. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/test_shared_subdirectory_imports.py +0 -0
  53. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/test_spreadsheet_creation_imports.py +0 -0
  54. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/test_subfolder_build.py +0 -0
  55. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/test_third_party_dependencies.py +0 -0
  56. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/test_utils.py +0 -0
  57. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/test_version_calculator.py +0 -0
  58. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/test_version_manager.py +0 -0
  59. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/tests/tests.py +0 -0
  60. {python_package_folder-5.1.5 → python_package_folder-5.1.6}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-package-folder
3
- Version: 5.1.5
3
+ Version: 5.1.6
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>
@@ -43,7 +43,7 @@ dependencies = [
43
43
 
44
44
  # ---- Dev dependencies ----
45
45
 
46
- version = "5.1.5"
46
+ version = "5.1.6"
47
47
  [dependency-groups]
48
48
  dev = [
49
49
  "pytest>=8.3.5",
@@ -8,6 +8,7 @@ repositories including PyPI, PyPI Test, and Azure Artifacts.
8
8
  from __future__ import annotations
9
9
 
10
10
  import getpass
11
+ import os
11
12
  import subprocess
12
13
  import sys
13
14
  from enum import Enum
@@ -19,6 +20,18 @@ except ImportError:
19
20
  keyring = None
20
21
 
21
22
 
23
+ def _is_non_interactive() -> bool:
24
+ """Check if running in a non-interactive environment (CI/CD)."""
25
+ # Check for common CI environment variables
26
+ ci_vars = ["GITHUB_ACTIONS", "CI", "CONTINUOUS_INTEGRATION", "TF_BUILD"]
27
+ if any(os.getenv(var) for var in ci_vars):
28
+ return True
29
+ # Check if stdin is not a TTY (non-interactive)
30
+ if not sys.stdin.isatty():
31
+ return True
32
+ return False
33
+
34
+
22
35
  class Repository(Enum):
23
36
  """
24
37
  Supported package repositories.
@@ -112,9 +125,9 @@ class Publisher:
112
125
  """
113
126
  Get credentials for publishing.
114
127
 
115
- Always prompts for username and password/token if not already provided.
116
- Does not use keyring to store/retrieve credentials - credentials must be
117
- provided via command-line arguments or will be prompted each time.
128
+ Prompts for username and password/token if not already provided.
129
+ In non-interactive environments (CI/CD), checks environment variables
130
+ or raises an error if credentials are missing.
118
131
 
119
132
  Returns:
120
133
  Tuple of (username, password/token)
@@ -122,21 +135,54 @@ class Publisher:
122
135
  username = self.username
123
136
  password = self.password
124
137
 
125
- # Always prompt if not provided via command-line arguments
126
- # We don't use keyring to avoid storing credentials
138
+ is_non_interactive_env = _is_non_interactive()
139
+
140
+ # Get username
127
141
  if not username:
128
- username = input(f"Enter username for {self.repository.value}: ").strip()
129
- if not username:
130
- raise ValueError("Username is required")
142
+ if is_non_interactive_env:
143
+ # Check environment variables
144
+ username = os.getenv("TWINE_USERNAME") or os.getenv("PYPI_USERNAME")
145
+ if not username:
146
+ raise ValueError(
147
+ f"Username is required for publishing to {self.repository.value} in CI/CD. "
148
+ "Please provide --username argument or set TWINE_USERNAME/PYPI_USERNAME environment variable."
149
+ )
150
+ else:
151
+ username = input(f"Enter username for {self.repository.value}: ").strip()
152
+ if not username:
153
+ raise ValueError("Username is required")
131
154
 
155
+ # Get password
132
156
  if not password:
133
- if self.repository == Repository.AZURE:
134
- prompt = f"Enter Azure Artifacts token for {username}: "
157
+ if is_non_interactive_env:
158
+ # Check environment variables (common names used by twine and CI/CD)
159
+ password = (
160
+ os.getenv("TWINE_PASSWORD")
161
+ or os.getenv("PYPI_PASSWORD")
162
+ or os.getenv("AZURE_ARTIFACTS_TOKEN") # For Azure
163
+ )
164
+ if not password:
165
+ raise ValueError(
166
+ f"Password/token is required for publishing to {self.repository.value} in CI/CD. "
167
+ "Please provide --password argument or set one of: "
168
+ "TWINE_PASSWORD, PYPI_PASSWORD, or AZURE_ARTIFACTS_TOKEN environment variable."
169
+ )
135
170
  else:
136
- prompt = f"Enter PyPI token for {username} (or __token__ for API token): "
137
- password = getpass.getpass(prompt)
138
- if not password:
139
- raise ValueError("Password/token is required")
171
+ if self.repository == Repository.AZURE:
172
+ prompt = f"Enter Azure Artifacts token for {username}: "
173
+ else:
174
+ prompt = f"Enter PyPI token for {username} (or __token__ for API token): "
175
+ try:
176
+ password = getpass.getpass(prompt)
177
+ except (EOFError, OSError):
178
+ # Handle non-interactive environments gracefully
179
+ raise ValueError(
180
+ f"Password/token is required for publishing to {self.repository.value}. "
181
+ "Cannot prompt for password in non-interactive environment. "
182
+ "Please provide --password argument or set TWINE_PASSWORD/PYPI_PASSWORD environment variable."
183
+ )
184
+ if not password:
185
+ raise ValueError("Password/token is required")
140
186
 
141
187
  # Auto-detect if password is an API token and adjust username
142
188
  if password.startswith("pypi-") or password.startswith("pypi_Ag"):