pulp-python 3.28.0__tar.gz → 3.28.2__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 (95) hide show
  1. {pulp_python-3.28.0 → pulp_python-3.28.2}/CHANGES.md +17 -0
  2. {pulp_python-3.28.0 → pulp_python-3.28.2}/MANIFEST.in +2 -0
  3. {pulp_python-3.28.0 → pulp_python-3.28.2}/PKG-INFO +1 -1
  4. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/__init__.py +1 -1
  5. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/replica.py +2 -1
  6. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/tasks/repair.py +25 -12
  7. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/utils.py +35 -6
  8. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python.egg-info/PKG-INFO +1 -1
  9. {pulp_python-3.28.0 → pulp_python-3.28.2}/pyproject.toml +2 -2
  10. {pulp_python-3.28.0 → pulp_python-3.28.2}/COMMITMENT +0 -0
  11. {pulp_python-3.28.0 → pulp_python-3.28.2}/COPYRIGHT +0 -0
  12. {pulp_python-3.28.0 → pulp_python-3.28.2}/LICENSE +0 -0
  13. {pulp_python-3.28.0 → pulp_python-3.28.2}/README.md +0 -0
  14. {pulp_python-3.28.0 → pulp_python-3.28.2}/functest_requirements.txt +0 -0
  15. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/__init__.py +0 -0
  16. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/global_access_conditions.py +0 -0
  17. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/management/__init__.py +0 -0
  18. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/management/commands/__init__.py +0 -0
  19. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/management/commands/repair-python-metadata.py +0 -0
  20. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0001_initial.py +0 -0
  21. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0001_squashed_0010_update_json_field.py +0 -0
  22. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0002_pythonpackagecontent_python_version.py +0 -0
  23. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0003_new_sync_filters.py +0 -0
  24. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0004_DATA_swap_distribution_model.py +0 -0
  25. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0005_pythonpackagecontent_sha256.py +0 -0
  26. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0006_pythonrepository_autopublish.py +0 -0
  27. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0007_pythonpackagecontent_mv-2-1.py +0 -0
  28. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0008_pythonpackagecontent_unique_sha256.py +0 -0
  29. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0009_pythondistribution_allow_uploads.py +0 -0
  30. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0010_update_json_field.py +0 -0
  31. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0011_alter_pythondistribution_distribution_ptr_and_more.py +0 -0
  32. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0012_add_domain.py +0 -0
  33. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0013_add_rbac_permissions.py +0 -0
  34. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0014_pythonpackagecontent_dynamic_and_more.py +0 -0
  35. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0015_alter_pythonpackagecontent_options.py +0 -0
  36. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0016_pythonpackagecontent_metadata_sha256.py +0 -0
  37. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0017_pythonpackagecontent_size.py +0 -0
  38. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0018_packageprovenance.py +0 -0
  39. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0019_create_missing_metadata_artifacts.py +0 -0
  40. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0020_pythonpackagecontent_name_normalized.py +0 -0
  41. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/0021_pythonrepository_upload_duplicate_filenames.py +0 -0
  42. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/migrations/__init__.py +0 -0
  43. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/modelresource.py +0 -0
  44. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/models.py +0 -0
  45. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/provenance.py +0 -0
  46. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/pypi/__init__.py +0 -0
  47. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/pypi/serializers.py +0 -0
  48. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/pypi/views.py +0 -0
  49. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/serializers.py +0 -0
  50. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/settings.py +0 -0
  51. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/tasks/__init__.py +0 -0
  52. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/tasks/publish.py +0 -0
  53. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/tasks/sync.py +0 -0
  54. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/tasks/upload.py +0 -0
  55. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/tasks/vulnerability_report.py +0 -0
  56. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/urls.py +0 -0
  57. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/viewsets.py +0 -0
  58. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/webserver_snippets/__init__.py +0 -0
  59. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/webserver_snippets/apache.conf +0 -0
  60. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/app/webserver_snippets/nginx.conf +0 -0
  61. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/pytest_plugin.py +0 -0
  62. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/__init__.py +0 -0
  63. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/__init__.py +0 -0
  64. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/__init__.py +0 -0
  65. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_attestations.py +0 -0
  66. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_auto_publish.py +0 -0
  67. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_consume_content.py +0 -0
  68. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_crud_content_unit.py +0 -0
  69. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_crud_publications.py +0 -0
  70. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_crud_remotes.py +0 -0
  71. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_domains.py +0 -0
  72. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_download_content.py +0 -0
  73. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_export_import.py +0 -0
  74. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_full_mirror.py +0 -0
  75. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_pypi_apis.py +0 -0
  76. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_pypi_simple_api.py +0 -0
  77. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_rbac.py +0 -0
  78. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_repair.py +0 -0
  79. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_sync.py +0 -0
  80. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_upload.py +0 -0
  81. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/api/test_vulnerability_report.py +0 -0
  82. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/assets/shelf-reader-0.1.tar.gz.publish.attestation +0 -0
  83. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/assets/shelf_reader-0.1-py2-none-any.whl.publish.attestation +0 -0
  84. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/constants.py +0 -0
  85. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/functional/utils.py +0 -0
  86. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/unit/__init__.py +0 -0
  87. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python/tests/unit/test_models.py +0 -0
  88. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python.egg-info/SOURCES.txt +0 -0
  89. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python.egg-info/dependency_links.txt +0 -0
  90. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python.egg-info/entry_points.txt +0 -0
  91. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python.egg-info/requires.txt +0 -0
  92. {pulp_python-3.28.0 → pulp_python-3.28.2}/pulp_python.egg-info/top_level.txt +0 -0
  93. {pulp_python-3.28.0 → pulp_python-3.28.2}/setup.cfg +0 -0
  94. {pulp_python-3.28.0 → pulp_python-3.28.2}/test_requirements.txt +0 -0
  95. {pulp_python-3.28.0 → pulp_python-3.28.2}/unittest_requirements.txt +0 -0
@@ -8,6 +8,23 @@
8
8
 
9
9
  [//]: # (towncrier release notes start)
10
10
 
11
+ ## 3.28.2 (2026-04-14) {: #3.28.2 }
12
+
13
+ #### Bugfixes {: #3.28.2-bugfix }
14
+
15
+ - Fixed "Worker has gone missing" errors during repair_metadata on large repositories (1000+ packages) by reducing peak memory consumption.
16
+ [#1188](https://github.com/pulp/pulp_python/issues/1188)
17
+
18
+ ---
19
+
20
+ ## 3.28.1 (2026-04-01) {: #3.28.1 }
21
+
22
+ #### Bugfixes {: #3.28.1-bugfix }
23
+
24
+ - Support "atomic" replications in pulpcore 3.107
25
+
26
+ ---
27
+
11
28
  ## 3.28.0 (2026-03-27) {: #3.28.0 }
12
29
 
13
30
  #### Features {: #3.28.0-feature }
@@ -11,3 +11,5 @@ include unittest_requirements.txt
11
11
  include pulp_python/app/webserver_snippets/*
12
12
  include pulp_python/tests/functional/assets/*
13
13
  exclude releasing.md
14
+
15
+ exclude .gitleaks.toml
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pulp-python
3
- Version: 3.28.0
3
+ Version: 3.28.2
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
@@ -10,7 +10,7 @@ class PulpPythonPluginAppConfig(PulpPluginAppConfig):
10
10
 
11
11
  name = "pulp_python.app"
12
12
  label = "python"
13
- version = "3.28.0"
13
+ version = "3.28.2"
14
14
  python_package_name = "pulp-python"
15
15
  domain_compatible = True
16
16
 
@@ -31,7 +31,8 @@ class PythonReplicator(Replicator):
31
31
  def url(self, upstream_distribution):
32
32
  # Ignore distributions that are only pull-through
33
33
  repo, pub = upstream_distribution["repository"], upstream_distribution["publication"]
34
- if repo or pub:
34
+ repo_ver = upstream_distribution.get("repository_version")
35
+ if repo or pub or repo_ver:
35
36
  return super().url(upstream_distribution)
36
37
 
37
38
  return None
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ import os
2
3
  from collections import defaultdict
3
4
  from gettext import gettext as _
4
5
  from itertools import groupby
@@ -8,18 +9,20 @@ from django.db.models import Prefetch
8
9
  from django.db.models.query import QuerySet
9
10
  from pulp_python.app.models import PythonPackageContent, PythonRepository
10
11
  from pulp_python.app.utils import (
11
- artifact_to_metadata_artifact,
12
12
  artifact_to_python_content_data,
13
+ copy_artifact_to_temp_file,
14
+ extract_wheel_metadata,
13
15
  fetch_json_release_metadata,
16
+ metadata_content_to_artifact,
14
17
  parse_metadata,
15
18
  )
16
- from pulpcore.plugin.models import Artifact, ContentArtifact, ProgressReport
19
+ from pulpcore.plugin.models import ContentArtifact, ProgressReport
17
20
  from pulpcore.plugin.util import get_domain
18
21
 
19
22
  log = logging.getLogger(__name__)
20
23
 
21
24
 
22
- BULK_SIZE = 1000
25
+ BULK_SIZE = 250
23
26
 
24
27
 
25
28
  def repair(repository_pk: UUID) -> None:
@@ -118,11 +121,21 @@ def repair_metadata(content: QuerySet[PythonPackageContent]) -> tuple[int, set[s
118
121
  .first()
119
122
  .artifact
120
123
  )
121
- new_data = artifact_to_python_content_data(package.filename, main_artifact, domain)
124
+ # Copy artifact to temp file once, extract both content data and metadata
125
+ temp_path = copy_artifact_to_temp_file(main_artifact, package.filename)
126
+ try:
127
+ new_data = artifact_to_python_content_data(
128
+ package.filename, main_artifact, domain, temp_path=temp_path
129
+ )
130
+ metadata_content = (
131
+ extract_wheel_metadata(temp_path) if package.filename.endswith(".whl") else None
132
+ )
133
+ finally:
134
+ os.unlink(temp_path)
122
135
  total_metadata_repaired += update_metadata_artifact_if_needed(
123
136
  package,
124
137
  new_data.get("metadata_sha256"),
125
- main_artifact,
138
+ metadata_content,
126
139
  metadata_batch,
127
140
  pkgs_metadata_not_repaired,
128
141
  )
@@ -236,7 +249,7 @@ def update_package_if_needed(
236
249
  def update_metadata_artifact_if_needed(
237
250
  package: PythonPackageContent,
238
251
  new_metadata_sha256: str | None,
239
- main_artifact: Artifact,
252
+ metadata_content: bytes | None,
240
253
  metadata_batch: list[tuple],
241
254
  pkgs_metadata_not_repaired: set[str],
242
255
  ) -> int:
@@ -248,7 +261,7 @@ def update_metadata_artifact_if_needed(
248
261
  Args:
249
262
  package: Package to check for metadata changes.
250
263
  new_metadata_sha256: The correct metadata_sha256 extracted from the main artifact, or None.
251
- main_artifact: The main package artifact used to generate metadata.
264
+ metadata_content: Raw metadata bytes extracted from the wheel, or None.
252
265
  metadata_batch: List of tuples for batch processing (updated in-place).
253
266
  pkgs_metadata_not_repaired: Set of package PKs that failed repair (updated in-place).
254
267
 
@@ -265,13 +278,13 @@ def update_metadata_artifact_if_needed(
265
278
 
266
279
  # Create missing
267
280
  if not cas:
268
- metadata_batch.append((package, main_artifact))
281
+ metadata_batch.append((package, metadata_content))
269
282
  # Fix existing
270
283
  elif new_metadata_sha256 != original_metadata_sha256:
271
284
  ca = cas.first()
272
285
  metadata_artifact = ca.artifact
273
286
  if metadata_artifact is None or (metadata_artifact.sha256 != new_metadata_sha256):
274
- metadata_batch.append((package, main_artifact))
287
+ metadata_batch.append((package, metadata_content))
275
288
 
276
289
  if len(metadata_batch) == BULK_SIZE:
277
290
  not_repaired = _process_metadata_batch(metadata_batch)
@@ -288,7 +301,7 @@ def _process_metadata_batch(metadata_batch: list[tuple]) -> set[str]:
288
301
  and their corresponding ContentArtifacts.
289
302
 
290
303
  Args:
291
- metadata_batch: List of (package, main_artifact) tuples.
304
+ metadata_batch: List of (package, metadata_content) tuples.
292
305
 
293
306
  Returns:
294
307
  Set of package PKs for which metadata artifacts could not be created.
@@ -296,8 +309,8 @@ def _process_metadata_batch(metadata_batch: list[tuple]) -> set[str]:
296
309
  not_repaired = set()
297
310
  content_artifacts = []
298
311
 
299
- for package, main_artifact in metadata_batch:
300
- metadata_artifact = artifact_to_metadata_artifact(package.filename, main_artifact)
312
+ for package, metadata_content in metadata_batch:
313
+ metadata_artifact = metadata_content_to_artifact(metadata_content)
301
314
  if metadata_artifact:
302
315
  ca = ContentArtifact(
303
316
  artifact=metadata_artifact,
@@ -240,18 +240,37 @@ def compute_metadata_sha256(filename: str) -> str | None:
240
240
  return hashlib.sha256(metadata_content).hexdigest() if metadata_content else None
241
241
 
242
242
 
243
- def artifact_to_python_content_data(filename, artifact, domain=None):
243
+ def copy_artifact_to_temp_file(artifact, filename, tmp_dir="."):
244
+ """
245
+ Copy an artifact's file to a temporary file on disk.
246
+
247
+ Returns the path to the temp file. The caller is responsible for cleanup.
248
+ """
249
+ temp_file = tempfile.NamedTemporaryFile("wb", dir=tmp_dir, suffix=filename, delete=False)
250
+ artifact.file.seek(0)
251
+ shutil.copyfileobj(artifact.file, temp_file)
252
+ temp_file.flush()
253
+ temp_file.close()
254
+ return temp_file.name
255
+
256
+
257
+ def artifact_to_python_content_data(filename, artifact, domain=None, temp_path=None):
244
258
  """
245
259
  Takes the artifact/filename and returns the metadata needed to create a PythonPackageContent.
260
+
261
+ If temp_path is provided, uses it instead of copying the artifact to a new temp file.
246
262
  """
247
263
  # Copy file to a temp directory under the user provided filename, we do this
248
264
  # because pkginfo validates that the filename has a valid extension before
249
265
  # reading it
250
- with tempfile.NamedTemporaryFile("wb", dir=".", suffix=filename) as temp_file:
251
- artifact.file.seek(0)
252
- shutil.copyfileobj(artifact.file, temp_file)
253
- temp_file.flush()
254
- metadata = get_project_metadata_from_file(temp_file.name)
266
+ if temp_path:
267
+ metadata = get_project_metadata_from_file(temp_path)
268
+ else:
269
+ with tempfile.NamedTemporaryFile("wb", dir=".", suffix=filename) as temp_file:
270
+ artifact.file.seek(0)
271
+ shutil.copyfileobj(artifact.file, temp_file)
272
+ temp_file.flush()
273
+ metadata = get_project_metadata_from_file(temp_file.name)
255
274
  data = parse_project_metadata(vars(metadata))
256
275
  data["sha256"] = artifact.sha256
257
276
  data["size"] = artifact.size
@@ -280,6 +299,16 @@ def artifact_to_metadata_artifact(
280
299
  if not metadata_content:
281
300
  return None
282
301
 
302
+ return metadata_content_to_artifact(metadata_content, tmp_dir)
303
+
304
+
305
+ def metadata_content_to_artifact(metadata_content: bytes, tmp_dir: str = ".") -> Artifact | None:
306
+ """
307
+ Creates an Artifact from raw metadata content bytes.
308
+ """
309
+ if not metadata_content:
310
+ return None
311
+
283
312
  with tempfile.NamedTemporaryFile(
284
313
  "wb", dir=tmp_dir, suffix=".metadata", delete=False
285
314
  ) as temp_md:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pulp-python
3
- Version: 3.28.0
3
+ Version: 3.28.2
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
@@ -7,7 +7,7 @@ build-backend = 'setuptools.build_meta'
7
7
 
8
8
  [project]
9
9
  name = "pulp-python"
10
- version = "3.28.0"
10
+ version = "3.28.2"
11
11
  description = "pulp-python plugin for the Pulp Project"
12
12
  readme = "README.md"
13
13
  authors = [
@@ -79,7 +79,7 @@ ignore = [
79
79
  [tool.bumpversion]
80
80
  # This section is managed by the plugin template. Do not edit manually.
81
81
 
82
- current_version = "3.28.0"
82
+ current_version = "3.28.2"
83
83
  commit = false
84
84
  tag = false
85
85
  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