python-package-folder 5.1.6__py3-none-any.whl → 5.2.0__py3-none-any.whl

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.
@@ -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) which is more complex to parse.
121
- For now, we'll attempt to query but fall back gracefully if it fails.
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=5)
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
- # Azure Artifacts simple index returns HTML, not JSON
157
- # Parsing HTML is complex and may require authentication
158
- # For now, we'll return None to fall back to git tags
159
- # This can be enhanced later with proper HTML parsing or API endpoint discovery
160
- logger.info(f"Azure Artifacts version query not fully implemented (HTML parsing required). Falling back to git tags.")
161
- return None
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-package-folder
3
- Version: 5.1.6
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>
@@ -10,9 +10,9 @@ python_package_folder/subfolder_build.py,sha256=8uoaWAHMVL4rvnWzm3ChWIO-aGxhn5cQ
10
10
  python_package_folder/types.py,sha256=3yeSRR5p_3PDKEAaehW_RJ7NwJHexOIeA08bGaT1iSY,2368
11
11
  python_package_folder/utils.py,sha256=b6Ukcc0fctXdxS5zhGLS86kqn0vz1yOEK7XjCY9fjfY,5621
12
12
  python_package_folder/version.py,sha256=kIDP6S9trEfs9gj7lBYGxrWm4RPssRla24UtlO9Jkh4,9111
13
- python_package_folder/version_calculator.py,sha256=KD1tRrdGtDwAwdqbBBdKAskVEDdwFOEDcucHzj0ksWQ,21818
14
- python_package_folder-5.1.6.dist-info/METADATA,sha256=xHP_EQ8dTYs5o2XIxW0CmJCj7OyNZKEn6RZGDN0m0ek,7838
15
- python_package_folder-5.1.6.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
16
- python_package_folder-5.1.6.dist-info/entry_points.txt,sha256=ttu4wAhoYSHGhWQNercLz9IVTTpXxhVlRA9vSTvaLe0,91
17
- python_package_folder-5.1.6.dist-info/licenses/LICENSE,sha256=vNgRJh8YiecqZoZld7TtwPI5I72HIymKD9g32fiJjCE,1073
18
- python_package_folder-5.1.6.dist-info/RECORD,,
13
+ python_package_folder/version_calculator.py,sha256=cmHmMfIGYted5bV2yFvCGHmK-WaEbYOcooF2i7Xx44g,25273
14
+ python_package_folder-5.2.0.dist-info/METADATA,sha256=JIjT4dqCeJwDJz-g8Xd_FrUad-X5CesaE1YYxHvqRCs,7838
15
+ python_package_folder-5.2.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
16
+ python_package_folder-5.2.0.dist-info/entry_points.txt,sha256=ttu4wAhoYSHGhWQNercLz9IVTTpXxhVlRA9vSTvaLe0,91
17
+ python_package_folder-5.2.0.dist-info/licenses/LICENSE,sha256=vNgRJh8YiecqZoZld7TtwPI5I72HIymKD9g32fiJjCE,1073
18
+ python_package_folder-5.2.0.dist-info/RECORD,,