python-package-folder 5.1.5__tar.gz → 5.2.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-5.1.5 → python_package_folder-5.2.0}/PKG-INFO +1 -1
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/pyproject.toml +1 -1
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/publisher.py +60 -14
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/version_calculator.py +97 -9
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/test_version_calculator.py +54 -2
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/.copier-answers.yml +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/.cursor/plans/optional_version_+_semantic-release_efed88a6.plan.md +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/.cursor/plans/replace_node.js_semantic-release_with_custom_python_implementation_64e05e1a.plan.md +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/.cursor/rules/general.mdc +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/.cursor/rules/python.mdc +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/.github/workflows/ci.yml +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/.github/workflows/publish.yml +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/.gitignore +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/.vscode/settings.json +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/LICENSE +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/MANIFEST.in +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/Makefile +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/README.md +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/coverage.svg +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/development.md +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/docs/DEVELOPMENT.md +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/docs/INSTALLATION.md +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/docs/PUBLISHING.md +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/docs/REFERENCE.md +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/docs/USAGE.md +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/docs/VERSION_RESOLUTION.md +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/installation.md +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/publishing.md +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/__init__.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/__main__.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/analyzer.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/finder.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/manager.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/py.typed +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/python_package_folder.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/subfolder_build.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/types.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/utils.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/version.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/conftest.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/folder_structure/some_globals.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/folder_structure/subfolder_to_build/README.md +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/folder_structure/subfolder_to_build/__init__.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/folder_structure/subfolder_to_build/some_function.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/folder_structure/subfolder_to_build/some_globals.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/folder_structure/utility_folder/_SS/some_superseded_file.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/folder_structure/utility_folder/some_utility.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/test_build_with_external_deps.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/test_exclude_patterns.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/test_linting.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/test_preserve_directory_structure.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/test_publisher.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/test_shared_subdirectory_imports.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/test_spreadsheet_creation_imports.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/test_subfolder_build.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/test_third_party_dependencies.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/test_utils.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/test_version_manager.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/tests.py +0 -0
- {python_package_folder-5.1.5 → python_package_folder-5.2.0}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-package-folder
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.2.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>
|
{python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/publisher.py
RENAMED
|
@@ -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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
126
|
-
|
|
138
|
+
is_non_interactive_env = _is_non_interactive()
|
|
139
|
+
|
|
140
|
+
# Get username
|
|
127
141
|
if not username:
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
|
134
|
-
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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"):
|
|
@@ -13,6 +13,7 @@ from __future__ import annotations
|
|
|
13
13
|
import logging
|
|
14
14
|
import re
|
|
15
15
|
import subprocess
|
|
16
|
+
from html.parser import HTMLParser
|
|
16
17
|
from pathlib import Path
|
|
17
18
|
|
|
18
19
|
import requests
|
|
@@ -110,6 +111,68 @@ def _query_pypi_version(package_name: str, registry: str) -> str | None:
|
|
|
110
111
|
return None
|
|
111
112
|
|
|
112
113
|
|
|
114
|
+
class SimpleIndexParser(HTMLParser):
|
|
115
|
+
"""Parser for PEP 503 simple index HTML to extract package versions."""
|
|
116
|
+
|
|
117
|
+
def __init__(self, package_name: str):
|
|
118
|
+
super().__init__()
|
|
119
|
+
self.package_name = package_name
|
|
120
|
+
self.versions: set[str] = set()
|
|
121
|
+
self.in_anchor = False
|
|
122
|
+
self.current_href = ""
|
|
123
|
+
|
|
124
|
+
def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None:
|
|
125
|
+
if tag == "a":
|
|
126
|
+
self.in_anchor = True
|
|
127
|
+
# Extract href attribute
|
|
128
|
+
for attr_name, attr_value in attrs:
|
|
129
|
+
if attr_name == "href" and attr_value:
|
|
130
|
+
self.current_href = attr_value
|
|
131
|
+
break
|
|
132
|
+
|
|
133
|
+
def handle_data(self, data: str) -> None:
|
|
134
|
+
if self.in_anchor:
|
|
135
|
+
# Extract version from link text or href
|
|
136
|
+
# Format: package-name-version-... or package-name-version.tar.gz
|
|
137
|
+
version = self._extract_version_from_filename(data.strip())
|
|
138
|
+
if version:
|
|
139
|
+
self.versions.add(version)
|
|
140
|
+
# Also check href if it contains version info
|
|
141
|
+
if self.current_href:
|
|
142
|
+
version = self._extract_version_from_filename(self.current_href)
|
|
143
|
+
if version:
|
|
144
|
+
self.versions.add(version)
|
|
145
|
+
|
|
146
|
+
def handle_endtag(self, tag: str) -> None:
|
|
147
|
+
if tag == "a":
|
|
148
|
+
self.in_anchor = False
|
|
149
|
+
self.current_href = ""
|
|
150
|
+
|
|
151
|
+
def _extract_version_from_filename(self, filename: str) -> str | None:
|
|
152
|
+
"""Extract version number from package filename."""
|
|
153
|
+
# Pattern: package-name-version-... or package-name-version.tar.gz
|
|
154
|
+
# Examples: data-0.1.0-py3-none-any.whl, data-0.1.0.tar.gz
|
|
155
|
+
# The version is between the package name and the next separator
|
|
156
|
+
|
|
157
|
+
# Normalize package name (replace - with _ for matching)
|
|
158
|
+
normalized_package = self.package_name.replace("-", "_").replace(".", "_")
|
|
159
|
+
|
|
160
|
+
# Try to match: package-name-version- or package-name-version.
|
|
161
|
+
# Version format: X.Y.Z (semantic versioning)
|
|
162
|
+
pattern = rf"{re.escape(self.package_name)}-(\d+\.\d+\.\d+(?:\.\d+)?(?:[a-zA-Z0-9]+)?)"
|
|
163
|
+
match = re.search(pattern, filename, re.IGNORECASE)
|
|
164
|
+
if match:
|
|
165
|
+
return match.group(1)
|
|
166
|
+
|
|
167
|
+
# Fallback: try with normalized package name
|
|
168
|
+
pattern = rf"{re.escape(normalized_package)}-(\d+\.\d+\.\d+(?:\.\d+)?(?:[a-zA-Z0-9]+)?)"
|
|
169
|
+
match = re.search(pattern, filename, re.IGNORECASE)
|
|
170
|
+
if match:
|
|
171
|
+
return match.group(1)
|
|
172
|
+
|
|
173
|
+
return None
|
|
174
|
+
|
|
175
|
+
|
|
113
176
|
def _query_azure_artifacts_version(
|
|
114
177
|
package_name: str,
|
|
115
178
|
repository_url: str,
|
|
@@ -117,8 +180,8 @@ def _query_azure_artifacts_version(
|
|
|
117
180
|
"""
|
|
118
181
|
Query Azure Artifacts for the latest version.
|
|
119
182
|
|
|
120
|
-
Azure Artifacts uses a simple index format (HTML)
|
|
121
|
-
|
|
183
|
+
Azure Artifacts uses a simple index format (HTML) following PEP 503.
|
|
184
|
+
Parses the HTML to extract version numbers from package filenames.
|
|
122
185
|
|
|
123
186
|
Args:
|
|
124
187
|
package_name: Package name to query
|
|
@@ -141,24 +204,49 @@ def _query_azure_artifacts_version(
|
|
|
141
204
|
return None
|
|
142
205
|
|
|
143
206
|
try:
|
|
144
|
-
response = requests.get(simple_index_url, timeout=
|
|
207
|
+
response = requests.get(simple_index_url, timeout=10)
|
|
145
208
|
logger.debug(f"Azure Artifacts response status: {response.status_code}")
|
|
146
209
|
|
|
147
210
|
if response.status_code == 401:
|
|
148
211
|
logger.warning(f"Authentication required for Azure Artifacts (401). Package '{package_name}' may require authentication to query.")
|
|
212
|
+
return None
|
|
149
213
|
elif response.status_code == 403:
|
|
150
214
|
logger.warning(f"Access forbidden for Azure Artifacts (403). Package '{package_name}' may not be accessible or requires different permissions.")
|
|
215
|
+
return None
|
|
151
216
|
elif response.status_code == 404:
|
|
152
217
|
logger.debug(f"Package '{package_name}' not found on Azure Artifacts (404) - first release")
|
|
218
|
+
return None
|
|
153
219
|
elif response.status_code != 200:
|
|
154
220
|
logger.warning(f"Unexpected status code {response.status_code} from Azure Artifacts for '{package_name}'")
|
|
221
|
+
return None
|
|
155
222
|
|
|
156
|
-
#
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
223
|
+
# Parse HTML to extract versions
|
|
224
|
+
parser = SimpleIndexParser(package_name)
|
|
225
|
+
try:
|
|
226
|
+
parser.feed(response.text)
|
|
227
|
+
except Exception as e:
|
|
228
|
+
logger.warning(f"Error parsing Azure Artifacts HTML for '{package_name}': {e}")
|
|
229
|
+
return None
|
|
230
|
+
|
|
231
|
+
if not parser.versions:
|
|
232
|
+
logger.debug(f"No versions found in Azure Artifacts HTML for '{package_name}'")
|
|
233
|
+
return None
|
|
234
|
+
|
|
235
|
+
# Find the latest version
|
|
236
|
+
versions = list(parser.versions)
|
|
237
|
+
logger.debug(f"Found {len(versions)} versions in Azure Artifacts: {versions}")
|
|
238
|
+
|
|
239
|
+
# Sort versions to find the latest
|
|
240
|
+
try:
|
|
241
|
+
sorted_versions = sorted(versions, key=_parse_version_for_sort, reverse=True)
|
|
242
|
+
latest_version = sorted_versions[0]
|
|
243
|
+
logger.info(f"Found latest version {latest_version} on Azure Artifacts for '{package_name}'")
|
|
244
|
+
return latest_version
|
|
245
|
+
except Exception as e:
|
|
246
|
+
logger.warning(f"Error sorting versions for '{package_name}': {e}")
|
|
247
|
+
# Fallback: return the first version found
|
|
248
|
+
return versions[0]
|
|
249
|
+
|
|
162
250
|
except requests.RequestException as e:
|
|
163
251
|
logger.warning(f"Network error querying Azure Artifacts for '{package_name}': {e}")
|
|
164
252
|
return None
|
{python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/test_version_calculator.py
RENAMED
|
@@ -86,9 +86,22 @@ class TestQueryRegistryVersion:
|
|
|
86
86
|
|
|
87
87
|
@patch("python_package_folder.version_calculator.requests.get")
|
|
88
88
|
def test_query_azure_artifacts_version(self, mock_get: MagicMock) -> None:
|
|
89
|
-
"""Test querying Azure Artifacts
|
|
89
|
+
"""Test querying Azure Artifacts with HTML parsing."""
|
|
90
90
|
mock_response = Mock()
|
|
91
91
|
mock_response.status_code = 200
|
|
92
|
+
# Simulate PEP 503 simple index HTML response
|
|
93
|
+
mock_response.text = """<!DOCTYPE html>
|
|
94
|
+
<html>
|
|
95
|
+
<head>
|
|
96
|
+
<title>Links for test-package</title>
|
|
97
|
+
</head>
|
|
98
|
+
<body>
|
|
99
|
+
<h1>Links for test-package</h1>
|
|
100
|
+
<a href="test-package-0.1.0-py3-none-any.whl">test-package-0.1.0-py3-none-any.whl</a>
|
|
101
|
+
<a href="test-package-0.2.0-py3-none-any.whl">test-package-0.2.0-py3-none-any.whl</a>
|
|
102
|
+
<a href="test-package-0.1.5.tar.gz">test-package-0.1.5.tar.gz</a>
|
|
103
|
+
</body>
|
|
104
|
+
</html>"""
|
|
92
105
|
mock_get.return_value = mock_response
|
|
93
106
|
|
|
94
107
|
version = query_registry_version(
|
|
@@ -96,7 +109,46 @@ class TestQueryRegistryVersion:
|
|
|
96
109
|
"azure",
|
|
97
110
|
repository_url="https://pkgs.dev.azure.com/ORG/PROJECT/_packaging/FEED/pypi/upload",
|
|
98
111
|
)
|
|
99
|
-
#
|
|
112
|
+
# Should parse HTML and return the latest version
|
|
113
|
+
assert version == "0.2.0"
|
|
114
|
+
|
|
115
|
+
@patch("python_package_folder.version_calculator.requests.get")
|
|
116
|
+
def test_query_azure_artifacts_version_not_found(self, mock_get: MagicMock) -> None:
|
|
117
|
+
"""Test querying Azure Artifacts when package doesn't exist (404)."""
|
|
118
|
+
mock_response = Mock()
|
|
119
|
+
mock_response.status_code = 404
|
|
120
|
+
mock_get.return_value = mock_response
|
|
121
|
+
|
|
122
|
+
version = query_registry_version(
|
|
123
|
+
"test-package",
|
|
124
|
+
"azure",
|
|
125
|
+
repository_url="https://pkgs.dev.azure.com/ORG/PROJECT/_packaging/FEED/pypi/upload",
|
|
126
|
+
)
|
|
127
|
+
# Should return None for 404 (first release)
|
|
128
|
+
assert version is None
|
|
129
|
+
|
|
130
|
+
@patch("python_package_folder.version_calculator.requests.get")
|
|
131
|
+
def test_query_azure_artifacts_version_empty_html(self, mock_get: MagicMock) -> None:
|
|
132
|
+
"""Test querying Azure Artifacts with empty HTML (no versions)."""
|
|
133
|
+
mock_response = Mock()
|
|
134
|
+
mock_response.status_code = 200
|
|
135
|
+
mock_response.text = """<!DOCTYPE html>
|
|
136
|
+
<html>
|
|
137
|
+
<head>
|
|
138
|
+
<title>Links for test-package</title>
|
|
139
|
+
</head>
|
|
140
|
+
<body>
|
|
141
|
+
<h1>Links for test-package</h1>
|
|
142
|
+
</body>
|
|
143
|
+
</html>"""
|
|
144
|
+
mock_get.return_value = mock_response
|
|
145
|
+
|
|
146
|
+
version = query_registry_version(
|
|
147
|
+
"test-package",
|
|
148
|
+
"azure",
|
|
149
|
+
repository_url="https://pkgs.dev.azure.com/ORG/PROJECT/_packaging/FEED/pypi/upload",
|
|
150
|
+
)
|
|
151
|
+
# Should return None when no versions found in HTML
|
|
100
152
|
assert version is None
|
|
101
153
|
|
|
102
154
|
@patch("python_package_folder.version_calculator.requests.get")
|
|
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
|
|
File without changes
|
{python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/__init__.py
RENAMED
|
File without changes
|
{python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/__main__.py
RENAMED
|
File without changes
|
{python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/analyzer.py
RENAMED
|
File without changes
|
{python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/finder.py
RENAMED
|
File without changes
|
{python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/manager.py
RENAMED
|
File without changes
|
{python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/types.py
RENAMED
|
File without changes
|
{python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/utils.py
RENAMED
|
File without changes
|
{python_package_folder-5.1.5 → python_package_folder-5.2.0}/src/python_package_folder/version.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_package_folder-5.1.5 → python_package_folder-5.2.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-5.1.5 → python_package_folder-5.2.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
|
|
File without changes
|
{python_package_folder-5.1.5 → python_package_folder-5.2.0}/tests/test_third_party_dependencies.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|