pulp-python 3.20.0__tar.gz → 3.20.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 (84) hide show
  1. {pulp_python-3.20.0 → pulp_python-3.20.1}/CHANGES.md +9 -0
  2. {pulp_python-3.20.0 → pulp_python-3.20.1}/PKG-INFO +2 -2
  3. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/__init__.py +1 -1
  4. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/pypi/views.py +31 -46
  5. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/test_full_mirror.py +30 -4
  6. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python.egg-info/PKG-INFO +2 -2
  7. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python.egg-info/requires.txt +1 -1
  8. {pulp_python-3.20.0 → pulp_python-3.20.1}/pyproject.toml +3 -3
  9. {pulp_python-3.20.0 → pulp_python-3.20.1}/COMMITMENT +0 -0
  10. {pulp_python-3.20.0 → pulp_python-3.20.1}/COPYRIGHT +0 -0
  11. {pulp_python-3.20.0 → pulp_python-3.20.1}/LICENSE +0 -0
  12. {pulp_python-3.20.0 → pulp_python-3.20.1}/MANIFEST.in +0 -0
  13. {pulp_python-3.20.0 → pulp_python-3.20.1}/README.md +0 -0
  14. {pulp_python-3.20.0 → pulp_python-3.20.1}/functest_requirements.txt +0 -0
  15. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/__init__.py +0 -0
  16. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/global_access_conditions.py +0 -0
  17. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/management/__init__.py +0 -0
  18. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/management/commands/__init__.py +0 -0
  19. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/management/commands/repair-python-metadata.py +0 -0
  20. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0001_initial.py +0 -0
  21. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0001_squashed_0010_update_json_field.py +0 -0
  22. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0002_pythonpackagecontent_python_version.py +0 -0
  23. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0003_new_sync_filters.py +0 -0
  24. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0004_DATA_swap_distribution_model.py +0 -0
  25. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0005_pythonpackagecontent_sha256.py +0 -0
  26. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0006_pythonrepository_autopublish.py +0 -0
  27. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0007_pythonpackagecontent_mv-2-1.py +0 -0
  28. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0008_pythonpackagecontent_unique_sha256.py +0 -0
  29. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0009_pythondistribution_allow_uploads.py +0 -0
  30. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0010_update_json_field.py +0 -0
  31. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0011_alter_pythondistribution_distribution_ptr_and_more.py +0 -0
  32. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0012_add_domain.py +0 -0
  33. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0013_add_rbac_permissions.py +0 -0
  34. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0014_pythonpackagecontent_dynamic_and_more.py +0 -0
  35. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0015_alter_pythonpackagecontent_options.py +0 -0
  36. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/0016_pythonpackagecontent_metadata_sha256.py +0 -0
  37. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/migrations/__init__.py +0 -0
  38. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/modelresource.py +0 -0
  39. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/models.py +0 -0
  40. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/pypi/__init__.py +0 -0
  41. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/pypi/serializers.py +0 -0
  42. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/replica.py +0 -0
  43. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/serializers.py +0 -0
  44. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/settings.py +0 -0
  45. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/tasks/__init__.py +0 -0
  46. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/tasks/publish.py +0 -0
  47. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/tasks/repair.py +0 -0
  48. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/tasks/sync.py +0 -0
  49. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/tasks/upload.py +0 -0
  50. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/urls.py +0 -0
  51. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/utils.py +0 -0
  52. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/viewsets.py +0 -0
  53. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/webserver_snippets/__init__.py +0 -0
  54. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/webserver_snippets/apache.conf +0 -0
  55. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/app/webserver_snippets/nginx.conf +0 -0
  56. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/pytest_plugin.py +0 -0
  57. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/__init__.py +0 -0
  58. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/__init__.py +0 -0
  59. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/__init__.py +0 -0
  60. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/test_auto_publish.py +0 -0
  61. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/test_consume_content.py +0 -0
  62. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/test_crud_content_unit.py +0 -0
  63. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/test_crud_publications.py +0 -0
  64. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/test_crud_remotes.py +0 -0
  65. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/test_domains.py +0 -0
  66. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/test_download_content.py +0 -0
  67. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/test_export_import.py +0 -0
  68. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/test_pypi_apis.py +0 -0
  69. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/test_pypi_simple_json_api.py +0 -0
  70. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/test_rbac.py +0 -0
  71. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/test_repair.py +0 -0
  72. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/test_sync.py +0 -0
  73. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/api/test_upload.py +0 -0
  74. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/constants.py +0 -0
  75. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/functional/utils.py +0 -0
  76. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/unit/__init__.py +0 -0
  77. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python/tests/unit/test_models.py +0 -0
  78. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python.egg-info/SOURCES.txt +0 -0
  79. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python.egg-info/dependency_links.txt +0 -0
  80. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python.egg-info/entry_points.txt +0 -0
  81. {pulp_python-3.20.0 → pulp_python-3.20.1}/pulp_python.egg-info/top_level.txt +0 -0
  82. {pulp_python-3.20.0 → pulp_python-3.20.1}/setup.cfg +0 -0
  83. {pulp_python-3.20.0 → pulp_python-3.20.1}/test_requirements.txt +0 -0
  84. {pulp_python-3.20.0 → pulp_python-3.20.1}/unittest_requirements.txt +0 -0
@@ -8,6 +8,15 @@
8
8
 
9
9
  [//]: # (towncrier release notes start)
10
10
 
11
+ ## 3.20.1 (2025-11-18) {: #3.20.1 }
12
+
13
+ #### Bugfixes {: #3.20.1-bugfix }
14
+
15
+ - Fixed pull-through caching not checking the repository if package was not present on remote.
16
+ [#1004](https://github.com/pulp/pulp_python/issues/1004)
17
+
18
+ ---
19
+
11
20
  ## 3.20.0 (2025-11-07) {: #3.20.0 }
12
21
 
13
22
  #### Features {: #3.20.0-feature }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pulp-python
3
- Version: 3.20.0
3
+ Version: 3.20.1
4
4
  Summary: pulp-python plugin for the Pulp Project
5
5
  Author-email: Pulp Team <pulp-list@redhat.com>
6
6
  Project-URL: Homepage, https://pulpproject.org
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: 3.13
20
20
  Requires-Python: >=3.11
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
- Requires-Dist: pulpcore<3.100,>=3.81.0
23
+ Requires-Dist: pulpcore<3.100,>=3.85.0
24
24
  Requires-Dist: pkginfo<1.13.0,>=1.12.0
25
25
  Requires-Dist: bandersnatch<6.6,>=6.3.0
26
26
  Requires-Dist: pypi-simple<2.0,>=1.5.0
@@ -10,7 +10,7 @@ class PulpPythonPluginAppConfig(PulpPluginAppConfig):
10
10
 
11
11
  name = "pulp_python.app"
12
12
  label = "python"
13
- version = "3.20.0"
13
+ version = "3.20.1"
14
14
  python_package_name = "pulp-python"
15
15
  domain_compatible = True
16
16
 
@@ -15,6 +15,7 @@ from django.db import transaction
15
15
  from django.db.utils import DatabaseError
16
16
  from django.http.response import (
17
17
  Http404,
18
+ HttpResponseNotFound,
18
19
  HttpResponseForbidden,
19
20
  HttpResponseBadRequest,
20
21
  StreamingHttpResponse,
@@ -287,7 +288,7 @@ class SimpleView(PackageUploadMixin, ViewSet):
287
288
  kwargs = {"content_type": media_type, "headers": headers}
288
289
  return StreamingHttpResponse(index_data, **kwargs)
289
290
 
290
- def pull_through_package_simple(self, package, path, remote, media_type):
291
+ def pull_through_package_simple(self, package, path, remote):
291
292
  """Gets the package's simple page from remote."""
292
293
 
293
294
  def parse_package(release_package):
@@ -305,7 +306,7 @@ class SimpleView(PackageUploadMixin, ViewSet):
305
306
 
306
307
  rfilter = get_remote_package_filter(remote)
307
308
  if not rfilter.filter_project(package):
308
- raise Http404(f"{package} does not exist.")
309
+ return {}
309
310
 
310
311
  url = remote.get_remote_artifact_url(f"simple/{package}/")
311
312
  remote.headers = remote.headers or []
@@ -313,27 +314,19 @@ class SimpleView(PackageUploadMixin, ViewSet):
313
314
  downloader = remote.get_downloader(url=url, max_retries=1)
314
315
  try:
315
316
  d = downloader.fetch()
316
- except ClientError:
317
- return HttpResponse(f"Failed to fetch {package} from {remote.url}.", status=502)
318
- except TimeoutException:
319
- return HttpResponse(f"{remote.url} timed out while fetching {package}.", status=504)
317
+ except (ClientError, TimeoutException):
318
+ log.info(f"Failed to fetch {package} simple page from {remote.url}")
319
+ return {}
320
320
 
321
321
  if d.headers["content-type"] == PYPI_SIMPLE_V1_JSON:
322
322
  page = ProjectPage.from_json_data(json.load(open(d.path, "rb")), base_url=url)
323
323
  else:
324
324
  page = ProjectPage.from_html(package, open(d.path, "rb").read(), base_url=url)
325
- packages = [
326
- parse_package(p) for p in page.packages if rfilter.filter_release(package, p.version)
327
- ]
328
- headers = {"X-PyPI-Last-Serial": str(PYPI_SERIAL_CONSTANT)}
329
-
330
- if media_type == PYPI_SIMPLE_V1_JSON:
331
- detail_data = write_simple_detail_json(package, packages)
332
- return Response(detail_data, headers=headers)
333
- else:
334
- detail_data = write_simple_detail(package, packages)
335
- kwargs = {"content_type": media_type, "headers": headers}
336
- return HttpResponse(detail_data, **kwargs)
325
+ return {
326
+ p.filename: parse_package(p)
327
+ for p in page.packages
328
+ if rfilter.filter_release(package, p.version)
329
+ }
337
330
 
338
331
  @extend_schema(operation_id="pypi_simple_package_read", summary="Get package simple page")
339
332
  def retrieve(self, request, path, package):
@@ -343,44 +336,36 @@ class SimpleView(PackageUploadMixin, ViewSet):
343
336
  repo_ver, content = self.get_rvc()
344
337
  # Should I redirect if the normalized name is different?
345
338
  normalized = canonicalize_name(package)
339
+ releases = {}
346
340
  if self.distribution.remote:
347
- return self.pull_through_package_simple(
348
- normalized, path, self.distribution.remote, media_type
349
- )
350
- if self.should_redirect(repo_version=repo_ver):
341
+ releases = self.pull_through_package_simple(normalized, path, self.distribution.remote)
342
+ elif self.should_redirect(repo_version=repo_ver):
351
343
  return redirect(urljoin(self.base_content_url, f"{path}/simple/{normalized}/"))
352
- packages = (
353
- content.filter(name__normalize=normalized)
354
- .values_list("filename", "sha256", "name", "metadata_sha256", "requires_python")
355
- .iterator()
356
- )
357
- try:
358
- present = next(packages)
359
- except StopIteration:
360
- raise Http404(f"{normalized} does not exist.")
361
- else:
362
- packages = chain([present], packages)
363
- name = present[2]
364
- releases = (
365
- {
366
- "filename": filename,
367
- "url": urljoin(self.base_content_url, f"{path}/{filename}"),
368
- "sha256": sha256,
369
- "metadata_sha256": metadata_sha256,
370
- "requires_python": requires_python,
344
+ if content:
345
+ packages = content.filter(name__normalize=normalized).values(
346
+ "filename", "sha256", "metadata_sha256", "requires_python"
347
+ )
348
+ local_releases = {
349
+ p["filename"]: {
350
+ **p,
351
+ "url": urljoin(self.base_content_url, f"{path}/{p['filename']}"),
352
+ }
353
+ for p in packages
371
354
  }
372
- for filename, sha256, _, metadata_sha256, requires_python in packages
373
- )
355
+ releases.update(local_releases)
356
+ if not releases:
357
+ return HttpResponseNotFound(f"{normalized} does not exist.")
358
+
374
359
  media_type = request.accepted_renderer.media_type
375
360
  headers = {"X-PyPI-Last-Serial": str(PYPI_SERIAL_CONSTANT)}
376
361
 
377
362
  if media_type == PYPI_SIMPLE_V1_JSON:
378
- detail_data = write_simple_detail_json(name, releases)
363
+ detail_data = write_simple_detail_json(normalized, releases.values())
379
364
  return Response(detail_data, headers=headers)
380
365
  else:
381
- detail_data = write_simple_detail(name, releases, streamed=True)
366
+ detail_data = write_simple_detail(normalized, releases.values())
382
367
  kwargs = {"content_type": media_type, "headers": headers}
383
- return StreamingHttpResponse(detail_data, **kwargs)
368
+ return HttpResponse(detail_data, **kwargs)
384
369
 
385
370
  @extend_schema(
386
371
  request=PackageUploadSerializer,
@@ -84,7 +84,7 @@ def test_pull_through_filter(python_remote_factory, python_distribution_factory)
84
84
 
85
85
  r = requests.get(f"{distro.base_url}simple/pulpcore/")
86
86
  assert r.status_code == 404
87
- assert r.text == "404 Not Found"
87
+ assert r.text == "pulpcore does not exist."
88
88
 
89
89
  r = requests.get(f"{distro.base_url}simple/shelf-reader/")
90
90
  assert r.status_code == 200
@@ -104,11 +104,11 @@ def test_pull_through_filter(python_remote_factory, python_distribution_factory)
104
104
 
105
105
  r = requests.get(f"{distro.base_url}simple/django/")
106
106
  assert r.status_code == 404
107
- assert r.text == "404 Not Found"
107
+ assert r.text == "django does not exist."
108
108
 
109
109
  r = requests.get(f"{distro.base_url}simple/pulpcore/")
110
- assert r.status_code == 502
111
- assert r.text == f"Failed to fetch pulpcore from {remote.url}."
110
+ assert r.status_code == 404
111
+ assert r.text == "pulpcore does not exist."
112
112
 
113
113
  r = requests.get(f"{distro.base_url}simple/shelf-reader/")
114
114
  assert r.status_code == 200
@@ -156,3 +156,29 @@ def test_pull_through_with_repo(
156
156
  assert r.status_code == 200
157
157
  tasks = pulpcore_bindings.TasksApi.list(reserved_resources=repo.prn)
158
158
  assert tasks.count == 3
159
+
160
+
161
+ @pytest.mark.parallel
162
+ def test_pull_through_local_only(
163
+ python_remote_factory, python_distribution_factory, python_repo_with_sync
164
+ ):
165
+ """Tests that pull-through checks the repository if the package is not present on the remote."""
166
+ remote = python_remote_factory(url=PYPI_URL, includes=["pulpcore"])
167
+ repo = python_repo_with_sync(remote=remote)
168
+ remote2 = python_remote_factory(includes=[]) # Fixtures does not have pulpcore
169
+ distro = python_distribution_factory(repository=repo.pulp_href, remote=remote2.pulp_href)
170
+
171
+ url = f"{distro.base_url}simple/pulpcore/"
172
+ r = requests.get(url)
173
+ assert r.status_code == 200
174
+ assert "?redirect=" not in r.text
175
+
176
+ url = f"{distro.base_url}simple/shelf-reader/"
177
+ r = requests.get(url)
178
+ assert r.status_code == 200
179
+ assert "?redirect=" in r.text
180
+
181
+ url = f"{distro.base_url}simple/pulp_python/"
182
+ r = requests.get(url)
183
+ assert r.status_code == 404
184
+ assert r.text == "pulp-python does not exist."
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pulp-python
3
- Version: 3.20.0
3
+ Version: 3.20.1
4
4
  Summary: pulp-python plugin for the Pulp Project
5
5
  Author-email: Pulp Team <pulp-list@redhat.com>
6
6
  Project-URL: Homepage, https://pulpproject.org
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: 3.13
20
20
  Requires-Python: >=3.11
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
- Requires-Dist: pulpcore<3.100,>=3.81.0
23
+ Requires-Dist: pulpcore<3.100,>=3.85.0
24
24
  Requires-Dist: pkginfo<1.13.0,>=1.12.0
25
25
  Requires-Dist: bandersnatch<6.6,>=6.3.0
26
26
  Requires-Dist: pypi-simple<2.0,>=1.5.0
@@ -1,4 +1,4 @@
1
- pulpcore<3.100,>=3.81.0
1
+ pulpcore<3.100,>=3.85.0
2
2
  pkginfo<1.13.0,>=1.12.0
3
3
  bandersnatch<6.6,>=6.3.0
4
4
  pypi-simple<2.0,>=1.5.0
@@ -7,7 +7,7 @@ build-backend = 'setuptools.build_meta'
7
7
 
8
8
  [project]
9
9
  name = "pulp-python"
10
- version = "3.20.0"
10
+ version = "3.20.1"
11
11
  description = "pulp-python plugin for the Pulp Project"
12
12
  readme = "README.md"
13
13
  authors = [
@@ -26,7 +26,7 @@ classifiers=[
26
26
  ]
27
27
  requires-python = ">=3.11"
28
28
  dependencies = [
29
- "pulpcore>=3.81.0,<3.100",
29
+ "pulpcore>=3.85.0,<3.100",
30
30
  "pkginfo>=1.12.0,<1.13.0",
31
31
  "bandersnatch>=6.3.0,<6.6", # 6.6 has breaking changes
32
32
  "pypi-simple>=1.5.0,<2.0",
@@ -76,7 +76,7 @@ ignore = [
76
76
  [tool.bumpversion]
77
77
  # This section is managed by the plugin template. Do not edit manually.
78
78
 
79
- current_version = "3.20.0"
79
+ current_version = "3.20.1"
80
80
  commit = false
81
81
  tag = false
82
82
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<alpha>0a)?(?P<patch>\\d+)(\\.(?P<release>[a-z]+))?"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes