pulp-python 3.29.0__py3-none-any.whl → 3.30.1__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.
Files changed (40) hide show
  1. pulp_python/app/__init__.py +5 -3
  2. pulp_python/app/management/commands/repair-python-metadata.py +7 -3
  3. pulp_python/app/modelresource.py +1 -0
  4. pulp_python/app/models.py +16 -14
  5. pulp_python/app/pypi/serializers.py +7 -5
  6. pulp_python/app/pypi/views.py +40 -28
  7. pulp_python/app/replica.py +3 -2
  8. pulp_python/app/serializers.py +17 -16
  9. pulp_python/app/tasks/publish.py +2 -2
  10. pulp_python/app/tasks/repair.py +4 -2
  11. pulp_python/app/tasks/sync.py +13 -15
  12. pulp_python/app/tasks/upload.py +7 -6
  13. pulp_python/app/urls.py +2 -2
  14. pulp_python/app/utils.py +23 -9
  15. pulp_python/app/viewsets.py +3 -1
  16. pulp_python/pytest_plugin.py +8 -6
  17. pulp_python/tests/functional/api/test_attestations.py +2 -2
  18. pulp_python/tests/functional/api/test_blocklist.py +1 -0
  19. pulp_python/tests/functional/api/test_consume_content.py +0 -1
  20. pulp_python/tests/functional/api/test_crud_content_unit.py +5 -4
  21. pulp_python/tests/functional/api/test_crud_publications.py +6 -5
  22. pulp_python/tests/functional/api/test_crud_remotes.py +3 -2
  23. pulp_python/tests/functional/api/test_domains.py +6 -5
  24. pulp_python/tests/functional/api/test_download_content.py +2 -2
  25. pulp_python/tests/functional/api/test_export_import.py +5 -3
  26. pulp_python/tests/functional/api/test_full_mirror.py +9 -9
  27. pulp_python/tests/functional/api/test_pypi_apis.py +48 -5
  28. pulp_python/tests/functional/api/test_pypi_simple_api.py +5 -6
  29. pulp_python/tests/functional/api/test_rbac.py +5 -4
  30. pulp_python/tests/functional/api/test_repair.py +2 -1
  31. pulp_python/tests/functional/api/test_sync.py +11 -11
  32. pulp_python/tests/functional/api/test_upload.py +5 -3
  33. pulp_python/tests/functional/constants.py +4 -0
  34. pulp_python/tests/functional/utils.py +2 -2
  35. {pulp_python-3.29.0.dist-info → pulp_python-3.30.1.dist-info}/METADATA +1 -1
  36. {pulp_python-3.29.0.dist-info → pulp_python-3.30.1.dist-info}/RECORD +40 -40
  37. {pulp_python-3.29.0.dist-info → pulp_python-3.30.1.dist-info}/WHEEL +0 -0
  38. {pulp_python-3.29.0.dist-info → pulp_python-3.30.1.dist-info}/entry_points.txt +0 -0
  39. {pulp_python-3.29.0.dist-info → pulp_python-3.30.1.dist-info}/licenses/LICENSE +0 -0
  40. {pulp_python-3.29.0.dist-info → pulp_python-3.30.1.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,8 @@
1
+ from gettext import gettext as _
2
+
1
3
  from django.db.models.signals import post_migrate
4
+
2
5
  from pulpcore.plugin import PulpPluginAppConfig
3
- from gettext import gettext as _
4
6
 
5
7
 
6
8
  class PulpPythonPluginAppConfig(PulpPluginAppConfig):
@@ -10,7 +12,7 @@ class PulpPythonPluginAppConfig(PulpPluginAppConfig):
10
12
 
11
13
  name = "pulp_python.app"
12
14
  label = "python"
13
- version = "3.29.0"
15
+ version = "3.30.1"
14
16
  python_package_name = "pulp-python"
15
17
  domain_compatible = True
16
18
 
@@ -26,7 +28,7 @@ class PulpPythonPluginAppConfig(PulpPluginAppConfig):
26
28
 
27
29
  # TODO: Remove this when https://github.com/pulp/pulpcore/issues/5500 is resolved
28
30
  def _populate_pypi_access_policies(sender, apps, verbosity, **kwargs):
29
- from pulp_python.app.pypi.views import PyPIView, SimpleView, UploadView, MetadataView
31
+ from pulp_python.app.pypi.views import MetadataView, PyPIView, SimpleView, UploadView
30
32
 
31
33
  try:
32
34
  AccessPolicy = apps.get_model("core", "AccessPolicy")
@@ -1,11 +1,12 @@
1
- import re
2
1
  import os
3
- from django.core.management import BaseCommand, CommandError
2
+ import re
4
3
  from gettext import gettext as _
5
4
 
6
5
  from django.conf import settings
6
+ from django.core.management import BaseCommand, CommandError
7
7
 
8
8
  from pulpcore.plugin.util import extract_pk
9
+
9
10
  from pulp_python.app.models import PythonPackageContent, PythonRepository
10
11
  from pulp_python.app.utils import artifact_to_python_content_data
11
12
 
@@ -78,7 +79,10 @@ class Command(BaseCommand):
78
79
  Management command to repair metadata of PythonPackageContent.
79
80
  """
80
81
 
81
- help = _("Repair the metadata of PythonPackageContent stored in PythonRepositories")
82
+ help = _(
83
+ "[Deprecated] Use the repository `repair_metadata` task instead. "
84
+ "Repair the metadata of PythonPackageContent stored in PythonRepositories."
85
+ )
82
86
 
83
87
  def add_arguments(self, parser):
84
88
  """Set up arguments."""
@@ -1,6 +1,7 @@
1
1
  from pulpcore.plugin.importexport import BaseContentResource
2
2
  from pulpcore.plugin.modelresources import RepositoryResource
3
3
  from pulpcore.plugin.util import get_domain
4
+
4
5
  from pulp_python.app.models import (
5
6
  PythonPackageContent,
6
7
  PythonRepository,
pulp_python/app/models.py CHANGED
@@ -1,44 +1,45 @@
1
1
  import hashlib
2
2
  import json
3
3
  from logging import getLogger
4
+ from pathlib import PurePath
4
5
 
5
6
  from aiohttp.web import json_response
7
+ from django.conf import settings
6
8
  from django.contrib.postgres.fields import ArrayField
7
9
  from django.core.exceptions import ObjectDoesNotExist
8
10
  from django.db import models
9
- from django.conf import settings
10
11
  from django_lifecycle import (
11
12
  BEFORE_SAVE,
12
13
  hook,
13
14
  )
14
15
  from rest_framework.serializers import ValidationError
16
+
15
17
  from pulpcore.plugin.models import (
16
18
  AutoAddObjPermsMixin,
17
19
  BaseModel,
18
20
  Content,
19
- Publication,
20
21
  Distribution,
22
+ Publication,
21
23
  Remote,
22
24
  Repository,
23
25
  )
26
+ from pulpcore.plugin.repo_version_utils import (
27
+ collect_duplicates,
28
+ remove_duplicates,
29
+ validate_repo_version,
30
+ )
24
31
  from pulpcore.plugin.responses import ArtifactResponse
32
+ from pulpcore.plugin.util import get_domain, get_domain_pk
25
33
 
26
- from pathlib import PurePath
27
34
  from .provenance import Provenance
28
35
  from .utils import (
29
- artifact_to_python_content_data,
36
+ PYPI_LAST_SERIAL,
37
+ PYPI_SERIAL_CONSTANT,
30
38
  artifact_to_metadata_artifact,
39
+ artifact_to_python_content_data,
31
40
  canonicalize_name,
32
41
  python_content_to_json,
33
- PYPI_LAST_SERIAL,
34
- PYPI_SERIAL_CONSTANT,
35
- )
36
- from pulpcore.plugin.repo_version_utils import (
37
- collect_duplicates,
38
- remove_duplicates,
39
- validate_repo_version,
40
42
  )
41
- from pulpcore.plugin.util import get_domain_pk, get_domain
42
43
 
43
44
  log = getLogger(__name__)
44
45
 
@@ -453,8 +454,9 @@ class PythonRepository(Repository, AutoAddObjPermsMixin):
453
454
  break
454
455
  if blocked:
455
456
  raise ValidationError(
456
- "Blocklisted packages cannot be added to this repository: "
457
- "{}".format(", ".join(blocked))
457
+ "Blocklisted packages cannot be added to this repository: {}".format(
458
+ ", ".join(blocked)
459
+ )
458
460
  )
459
461
 
460
462
 
@@ -1,13 +1,15 @@
1
1
  import logging
2
2
  from gettext import gettext as _
3
3
 
4
- from rest_framework import serializers
4
+ from django.db.utils import IntegrityError
5
5
  from pydantic import TypeAdapter, ValidationError
6
- from pulp_python.app.provenance import Attestation
7
- from pulp_python.app.utils import DIST_EXTENSIONS, SUPPORTED_METADATA_VERSIONS
6
+ from rest_framework import serializers
7
+
8
8
  from pulpcore.plugin.models import Artifact
9
9
  from pulpcore.plugin.util import get_domain
10
- from django.db.utils import IntegrityError
10
+
11
+ from pulp_python.app.provenance import Attestation
12
+ from pulp_python.app.utils import DIST_EXTENSIONS, SUPPORTED_METADATA_VERSIONS
11
13
 
12
14
  log = logging.getLogger(__name__)
13
15
 
@@ -110,7 +112,7 @@ class PackageUploadSerializer(serializers.Serializer):
110
112
  attestations = TypeAdapter(list[Attestation]).validate_python(attestations)
111
113
  except ValidationError as e:
112
114
  raise serializers.ValidationError(
113
- {"attestations": _("The uploaded attestations are not valid: {}".format(e))}
115
+ {"attestations": _("The uploaded attestations are not valid: {}").format(e)}
114
116
  )
115
117
 
116
118
  sha256 = data.get("sha256_digest")
@@ -1,60 +1,61 @@
1
1
  import logging
2
-
3
- from rest_framework.viewsets import ViewSet
4
- from rest_framework.renderers import BrowsableAPIRenderer, JSONRenderer, TemplateHTMLRenderer
5
- from rest_framework.response import Response
6
- from rest_framework.exceptions import NotAcceptable
7
- from django.core.exceptions import ObjectDoesNotExist
8
- from django.shortcuts import redirect
9
- from datetime import datetime, timezone, timedelta
2
+ from datetime import datetime, timedelta, timezone
3
+ from itertools import chain
4
+ from pathlib import PurePath
5
+ from urllib.parse import urljoin, urlparse, urlunsplit
10
6
 
11
7
  from django.contrib.sessions.models import Session
8
+ from django.core.exceptions import ObjectDoesNotExist
12
9
  from django.db import transaction
10
+ from django.db.models import OuterRef, Subquery
13
11
  from django.db.utils import DatabaseError
14
12
  from django.http.response import (
15
13
  Http404,
16
- HttpResponseNotFound,
17
- HttpResponseForbidden,
14
+ HttpResponse,
18
15
  HttpResponseBadRequest,
16
+ HttpResponseForbidden,
17
+ HttpResponseNotFound,
19
18
  StreamingHttpResponse,
20
- HttpResponse,
21
19
  )
20
+ from django.shortcuts import redirect
22
21
  from drf_spectacular.utils import extend_schema
23
22
  from dynaconf import settings
24
- from itertools import chain
25
23
  from packaging.utils import canonicalize_name
26
- from urllib.parse import urljoin, urlparse, urlunsplit
27
- from pathlib import PurePath
24
+ from rest_framework.exceptions import NotAcceptable
25
+ from rest_framework.renderers import BrowsableAPIRenderer, JSONRenderer, TemplateHTMLRenderer
26
+ from rest_framework.response import Response
27
+ from rest_framework.viewsets import ViewSet
28
28
 
29
- from pulpcore.plugin.viewsets import OperationPostponedResponse
29
+ from pulpcore.plugin.models import RepositoryContent
30
30
  from pulpcore.plugin.tasking import dispatch
31
31
  from pulpcore.plugin.util import get_domain, get_url
32
+ from pulpcore.plugin.viewsets import OperationPostponedResponse
33
+
34
+ from pulp_python.app import tasks
32
35
  from pulp_python.app.models import (
36
+ PackageProvenance,
33
37
  PythonDistribution,
34
38
  PythonPackageContent,
35
39
  PythonPublication,
36
- PackageProvenance,
37
40
  )
38
41
  from pulp_python.app.pypi.serializers import (
39
- SummarySerializer,
40
42
  PackageMetadataSerializer,
41
43
  PackageUploadSerializer,
42
44
  PackageUploadTaskSerializer,
45
+ SummarySerializer,
43
46
  )
44
47
  from pulp_python.app.utils import (
45
- write_simple_index,
46
- write_simple_index_json,
47
- write_simple_detail,
48
- write_simple_detail_json,
49
- python_content_to_json,
50
48
  PYPI_LAST_SERIAL,
51
49
  PYPI_SERIAL_CONSTANT,
52
50
  get_remote_package_filter,
53
51
  get_remote_simple_page,
52
+ python_content_to_json,
53
+ write_simple_detail,
54
+ write_simple_detail_json,
55
+ write_simple_index,
56
+ write_simple_index_json,
54
57
  )
55
58
 
56
- from pulp_python.app import tasks
57
-
58
59
  log = logging.getLogger(__name__)
59
60
 
60
61
  ORIGIN_HOST = settings.CONTENT_ORIGIN if settings.CONTENT_ORIGIN else settings.PYPI_API_HOSTNAME
@@ -367,13 +368,20 @@ class SimpleView(PackageUploadMixin, ViewSet):
367
368
  return redirect(urljoin(self.base_content_url, f"{path}/simple/{normalized}/"))
368
369
  if content is not None:
369
370
  local_packages = content.filter(name_normalized=normalized)
370
- packages = local_packages.values(
371
+ repo_added_subquery = RepositoryContent.objects.filter(
372
+ content_id=OuterRef("pk"),
373
+ repository=repo_ver.repository,
374
+ version_removed=None,
375
+ ).values("pulp_created")[:1]
376
+ packages = local_packages.annotate(
377
+ repo_added_time=Subquery(repo_added_subquery)
378
+ ).values(
371
379
  "filename",
372
380
  "sha256",
373
381
  "metadata_sha256",
374
382
  "requires_python",
375
383
  "size",
376
- "pulp_created",
384
+ "repo_added_time",
377
385
  "version",
378
386
  )
379
387
  provenances = PackageProvenance.objects.filter(package__in=local_packages).values_list(
@@ -383,7 +391,7 @@ class SimpleView(PackageUploadMixin, ViewSet):
383
391
  p["filename"]: {
384
392
  **p,
385
393
  "url": urljoin(self.base_content_url, f"{path}/{p['filename']}"),
386
- "upload_time": p["pulp_created"],
394
+ "upload_time": p["repo_added_time"],
387
395
  "provenance": (
388
396
  self.get_provenance_url(normalized, p["version"], p["filename"])
389
397
  if p["filename"] in provenances
@@ -465,7 +473,11 @@ class MetadataView(PyPIMixin, ViewSet):
465
473
  if settings.DOMAIN_ENABLED:
466
474
  domain = get_domain()
467
475
  json_body = python_content_to_json(
468
- path, package_content, version=version, domain=domain
476
+ path,
477
+ package_content,
478
+ version=version,
479
+ domain=domain,
480
+ repository_version=repo_ver,
469
481
  )
470
482
  if json_body:
471
483
  return Response(data=json_body, headers=headers)
@@ -1,10 +1,11 @@
1
- from pulpcore.plugin.replica import Replicator
2
-
3
1
  from pulp_glue.python.context import (
4
2
  PulpPythonDistributionContext,
5
3
  PulpPythonPublicationContext,
6
4
  PulpPythonRepositoryContext,
7
5
  )
6
+
7
+ from pulpcore.plugin.replica import Replicator
8
+
8
9
  from pulp_python.app.models import PythonDistribution, PythonRemote, PythonRepository
9
10
  from pulp_python.app.tasks import sync as python_sync
10
11
 
@@ -2,33 +2,34 @@ import logging
2
2
  import os
3
3
  import tempfile
4
4
  from gettext import gettext as _
5
+ from urllib.parse import urljoin
6
+
5
7
  from django.conf import settings
6
8
  from django.db.utils import IntegrityError
7
9
  from drf_spectacular.utils import extend_schema_serializer
8
10
  from packaging.requirements import Requirement
9
- from packaging.version import Version, InvalidVersion
10
- from rest_framework import serializers
11
- from pypi_attestations import AttestationError
11
+ from packaging.version import InvalidVersion, Version
12
12
  from pydantic import TypeAdapter, ValidationError
13
- from urllib.parse import urljoin
13
+ from pypi_attestations import AttestationError
14
+ from rest_framework import serializers
14
15
 
15
16
  from pulpcore.plugin import models as core_models
16
17
  from pulpcore.plugin import serializers as core_serializers
17
- from pulpcore.plugin.util import get_domain, get_prn, get_current_authenticated_user, reverse
18
+ from pulpcore.plugin.util import get_current_authenticated_user, get_domain, get_prn, reverse
18
19
 
19
20
  from pulp_python.app import models as python_models
20
- from pulp_python.app.utils import canonicalize_name
21
21
  from pulp_python.app.provenance import (
22
+ AnyPublisher,
22
23
  Attestation,
24
+ AttestationBundle,
23
25
  Provenance,
24
26
  verify_provenance,
25
- AttestationBundle,
26
- AnyPublisher,
27
27
  )
28
28
  from pulp_python.app.utils import (
29
29
  DIST_EXTENSIONS,
30
30
  artifact_to_metadata_artifact,
31
31
  artifact_to_python_content_data,
32
+ canonicalize_name,
32
33
  get_project_metadata_from_file,
33
34
  parse_project_metadata,
34
35
  )
@@ -238,7 +239,7 @@ class PythonPackageContentSerializer(core_serializers.SingleArtifactContentUploa
238
239
  required=False,
239
240
  allow_blank=True,
240
241
  help_text=_(
241
- "The maintainer's name at a minimum; " "additional contact information may be provided."
242
+ "The maintainer's name at a minimum; additional contact information may be provided."
242
243
  ),
243
244
  )
244
245
  maintainer_email = serializers.CharField(
@@ -387,7 +388,7 @@ class PythonPackageContentSerializer(core_serializers.SingleArtifactContentUploa
387
388
  else:
388
389
  attestations = TypeAdapter(list[Attestation]).validate_python(value)
389
390
  except ValidationError as e:
390
- raise serializers.ValidationError(_("Invalid attestations: {}".format(e)))
391
+ raise serializers.ValidationError(_("Invalid attestations: {}").format(e))
391
392
  return attestations
392
393
 
393
394
  def handle_attestations(self, filename, sha256, attestations, offline=True):
@@ -400,7 +401,7 @@ class PythonPackageContentSerializer(core_serializers.SingleArtifactContentUploa
400
401
  verify_provenance(filename, sha256, provenance, offline=offline)
401
402
  except AttestationError as e:
402
403
  raise serializers.ValidationError(
403
- {"attestations": _("Attestations failed verification: {}".format(e))}
404
+ {"attestations": _("Attestations failed verification: {}").format(e)}
404
405
  )
405
406
  return provenance.model_dump(mode="json")
406
407
 
@@ -655,13 +656,13 @@ class PackageProvenanceSerializer(core_serializers.NoArtifactContentUploadSerial
655
656
  data["provenance"] = provenance.model_dump(mode="json")
656
657
  except ValidationError as e:
657
658
  raise serializers.ValidationError(
658
- _("The uploaded provenance is not valid: {}".format(e))
659
+ _("The uploaded provenance is not valid: {}").format(e)
659
660
  )
660
661
  if data.pop("verify"):
661
662
  try:
662
663
  verify_provenance(data["package"].filename, data["package"].sha256, provenance)
663
664
  except AttestationError as e:
664
- raise serializers.ValidationError(_("Provenance verification failed: {}".format(e)))
665
+ raise serializers.ValidationError(_("Provenance verification failed: {}").format(e))
665
666
  return data
666
667
 
667
668
  def retrieve(self, validated_data):
@@ -729,7 +730,7 @@ class PythonRemoteSerializer(core_serializers.RemoteSerializer):
729
730
  package_types = MultipleChoiceArrayField(
730
731
  required=False,
731
732
  help_text=_(
732
- "The package types to sync for Python content. Leave blank to get every" "package type."
733
+ "The package types to sync for Python content. Leave blank to get everypackage type."
733
734
  ),
734
735
  choices=python_models.PACKAGE_TYPES,
735
736
  default=list,
@@ -764,7 +765,7 @@ class PythonRemoteSerializer(core_serializers.RemoteSerializer):
764
765
  Requirement(pkg)
765
766
  except ValueError as ve:
766
767
  raise serializers.ValidationError(
767
- _("includes specifier {} is invalid. {}".format(pkg, ve))
768
+ _("includes specifier {} is invalid. {}").format(pkg, ve)
768
769
  )
769
770
  return value
770
771
 
@@ -775,7 +776,7 @@ class PythonRemoteSerializer(core_serializers.RemoteSerializer):
775
776
  Requirement(pkg)
776
777
  except ValueError as ve:
777
778
  raise serializers.ValidationError(
778
- _("excludes specifier {} is invalid. {}".format(pkg, ve))
779
+ _("excludes specifier {} is invalid. {}").format(pkg, ve)
779
780
  )
780
781
  return value
781
782
 
@@ -1,6 +1,6 @@
1
- from gettext import gettext as _
2
1
  import logging
3
2
  import os
3
+ from gettext import gettext as _
4
4
 
5
5
  from django.core.files import File
6
6
  from packaging.utils import canonicalize_name
@@ -10,7 +10,7 @@ from pulpcore.plugin.util import get_domain
10
10
 
11
11
  from pulp_python.app import models as python_models
12
12
  from pulp_python.app.serializers import PythonPublicationSerializer
13
- from pulp_python.app.utils import write_simple_index, write_simple_detail
13
+ from pulp_python.app.utils import write_simple_detail, write_simple_index
14
14
 
15
15
  log = logging.getLogger(__name__)
16
16
 
@@ -7,6 +7,10 @@ from uuid import UUID
7
7
 
8
8
  from django.db.models import Prefetch
9
9
  from django.db.models.query import QuerySet
10
+
11
+ from pulpcore.plugin.models import ContentArtifact, ProgressReport
12
+ from pulpcore.plugin.util import get_domain
13
+
10
14
  from pulp_python.app.models import PythonPackageContent, PythonRepository
11
15
  from pulp_python.app.utils import (
12
16
  artifact_to_python_content_data,
@@ -16,8 +20,6 @@ from pulp_python.app.utils import (
16
20
  metadata_content_to_artifact,
17
21
  parse_metadata,
18
22
  )
19
- from pulpcore.plugin.models import ContentArtifact, ProgressReport
20
- from pulpcore.plugin.util import get_domain
21
23
 
22
24
  log = logging.getLogger(__name__)
23
25
 
@@ -1,11 +1,17 @@
1
- import logging
2
1
  import asyncio
3
-
4
- from aiohttp import ClientResponseError, ClientError
5
- from lxml.etree import LxmlError
6
- from gettext import gettext as _
2
+ import logging
7
3
  from functools import partial
4
+ from gettext import gettext as _
5
+ from urllib.parse import urljoin
8
6
 
7
+ from aiohttp import ClientError, ClientResponseError
8
+ from bandersnatch.configuration import BandersnatchConfig
9
+ from bandersnatch.master import Master
10
+ from bandersnatch.mirror import Mirror
11
+ from lxml.etree import LxmlError
12
+ from packaging.requirements import Requirement
13
+ from pypi_attestations import Provenance
14
+ from pypi_simple import IndexPage
9
15
  from rest_framework import serializers
10
16
 
11
17
  from pulpcore.plugin.download import HttpDownloader
@@ -18,19 +24,11 @@ from pulpcore.plugin.stages import (
18
24
  )
19
25
 
20
26
  from pulp_python.app.models import (
27
+ PackageProvenance,
21
28
  PythonPackageContent,
22
29
  PythonRemote,
23
- PackageProvenance,
24
30
  )
25
- from pulp_python.app.utils import parse_metadata, PYPI_LAST_SERIAL, aget_remote_simple_page
26
- from pypi_simple import IndexPage
27
- from pypi_attestations import Provenance
28
-
29
- from bandersnatch.mirror import Mirror
30
- from bandersnatch.master import Master
31
- from bandersnatch.configuration import BandersnatchConfig
32
- from packaging.requirements import Requirement
33
- from urllib.parse import urljoin
31
+ from pulp_python.app.utils import PYPI_LAST_SERIAL, aget_remote_simple_page, parse_metadata
34
32
 
35
33
  logger = logging.getLogger(__name__)
36
34
 
@@ -1,17 +1,18 @@
1
1
  import time
2
-
3
2
  from datetime import datetime, timezone
4
- from django.db import transaction
3
+
5
4
  from django.contrib.sessions.models import Session
5
+ from django.db import transaction
6
6
  from pydantic import TypeAdapter
7
- from pulpcore.plugin.models import Artifact, CreatedResource, Content, ContentArtifact
8
- from pulpcore.plugin.util import get_domain, get_current_authenticated_user, get_prn
9
7
 
10
- from pulp_python.app.models import PythonPackageContent, PythonRepository, PackageProvenance
8
+ from pulpcore.plugin.models import Artifact, Content, ContentArtifact, CreatedResource
9
+ from pulpcore.plugin.util import get_current_authenticated_user, get_domain, get_prn
10
+
11
+ from pulp_python.app.models import PackageProvenance, PythonPackageContent, PythonRepository
11
12
  from pulp_python.app.provenance import (
13
+ AnyPublisher,
12
14
  Attestation,
13
15
  AttestationBundle,
14
- AnyPublisher,
15
16
  Provenance,
16
17
  verify_provenance,
17
18
  )
pulp_python/app/urls.py CHANGED
@@ -2,11 +2,11 @@ from django.conf import settings
2
2
  from django.urls import path
3
3
 
4
4
  from pulp_python.app.pypi.views import (
5
- SimpleView,
6
5
  MetadataView,
6
+ ProvenanceView,
7
7
  PyPIView,
8
+ SimpleView,
8
9
  UploadView,
9
- ProvenanceView,
10
10
  )
11
11
 
12
12
  if settings.DOMAIN_ENABLED:
pulp_python/app/utils.py CHANGED
@@ -1,23 +1,26 @@
1
1
  import hashlib
2
+ import json
2
3
  import logging
3
- import pkginfo
4
4
  import re
5
5
  import shutil
6
6
  import tempfile
7
7
  import zipfile
8
- import json
9
- from aiohttp.client_exceptions import ClientError
10
8
  from collections import defaultdict
11
9
  from datetime import timezone
10
+
11
+ import pkginfo
12
+ from aiohttp.client_exceptions import ClientError
12
13
  from django.conf import settings
14
+ from django.db.models import OuterRef, Subquery
13
15
  from django.db.utils import IntegrityError
14
16
  from jinja2 import Template
15
- from packaging.utils import canonicalize_name
16
17
  from packaging.requirements import Requirement
17
- from packaging.version import parse, InvalidVersion
18
+ from packaging.utils import canonicalize_name
19
+ from packaging.version import InvalidVersion, parse
18
20
  from pypi_simple import ACCEPT_JSON_PREFERRED, ProjectPage
19
- from pulpcore.plugin.models import Artifact, Remote
21
+
20
22
  from pulpcore.plugin.exceptions import TimeoutException
23
+ from pulpcore.plugin.models import Artifact, Remote, RepositoryContent
21
24
  from pulpcore.plugin.util import get_domain
22
25
 
23
26
  log = logging.getLogger(__name__)
@@ -357,7 +360,9 @@ def fetch_json_release_metadata(name: str, version: str, remotes: set[Remote]) -
357
360
  raise Exception(f"Failed to fetch {url} from any remote.")
358
361
 
359
362
 
360
- def python_content_to_json(base_path, content_query, version=None, domain=None):
363
+ def python_content_to_json(
364
+ base_path, content_query, version=None, domain=None, repository_version=None
365
+ ):
361
366
  """
362
367
  Converts a QuerySet of PythonPackageContent into the PyPi JSON format
363
368
  https://www.python.org/dev/peps/pep-0566/
@@ -369,6 +374,13 @@ def python_content_to_json(base_path, content_query, version=None, domain=None):
369
374
 
370
375
  Returns None if version is specified but not found within content_query
371
376
  """
377
+ if repository_version:
378
+ repo_added_subquery = RepositoryContent.objects.filter(
379
+ content_id=OuterRef("pk"),
380
+ repository=repository_version.repository,
381
+ version_removed=None,
382
+ ).values("pulp_created")[:1]
383
+ content_query = content_query.annotate(repo_added_time=Subquery(repo_added_subquery))
372
384
  full_metadata = {"last_serial": 0} # For now the serial field isn't supported by Pulp
373
385
  latest_content = latest_content_version(content_query, version)
374
386
  if not latest_content:
@@ -513,8 +525,10 @@ def python_content_to_download_info(content, base_path, domain=None):
513
525
  "python_version": content.python_version,
514
526
  "requires_python": content.requires_python or None,
515
527
  "size": content.size,
516
- "upload_time": str(content.pulp_created),
517
- "upload_time_iso_8601": str(content.pulp_created.isoformat()),
528
+ "upload_time": str(getattr(content, "repo_added_time", None) or content.pulp_created),
529
+ "upload_time_iso_8601": str(
530
+ (getattr(content, "repo_added_time", None) or content.pulp_created).isoformat()
531
+ ),
518
532
  "url": url,
519
533
  "yanked": False,
520
534
  "yanked_reason": None,
@@ -1,10 +1,11 @@
1
+ from pathlib import Path
2
+
1
3
  from bandersnatch.configuration import BandersnatchConfig
2
4
  from django.db import transaction
3
5
  from django_filters import CharFilter
4
6
  from django_filters.rest_framework import filters as drf_filters
5
7
  from drf_spectacular.utils import extend_schema, extend_schema_view
6
8
  from packaging.utils import canonicalize_name
7
- from pathlib import Path
8
9
  from rest_framework import status
9
10
  from rest_framework.decorators import action
10
11
  from rest_framework.mixins import (
@@ -259,6 +260,7 @@ class PythonBlocklistEntryViewSet(
259
260
  parent_lookup_kwargs = {"repository_pk": "repository__pk"}
260
261
  serializer_class = python_serializers.PythonBlocklistEntrySerializer
261
262
  queryset = python_models.PythonBlocklistEntry.objects.all()
263
+ filterset_fields = {"name": ["exact"], "version": ["exact"], "filename": ["exact"]}
262
264
  ordering = ("-pulp_created",)
263
265
 
264
266
  DEFAULT_ACCESS_POLICY = {
@@ -1,16 +1,18 @@
1
- import pytest
2
- import uuid
3
1
  import subprocess
2
+ import uuid
3
+
4
+ import pytest
4
5
 
5
6
  from pulpcore.tests.functional.utils import BindingsNamespace
7
+
6
8
  from pulp_python.tests.functional.constants import (
7
- PYTHON_FIXTURE_URL,
8
- PYTHON_XS_PROJECT_SPECIFIER,
9
9
  PYTHON_EGG_FILENAME,
10
- PYTHON_URL,
11
10
  PYTHON_EGG_URL,
12
- PYTHON_WHEEL_URL,
11
+ PYTHON_FIXTURE_URL,
12
+ PYTHON_URL,
13
13
  PYTHON_WHEEL_FILENAME,
14
+ PYTHON_WHEEL_URL,
15
+ PYTHON_XS_PROJECT_SPECIFIER,
14
16
  )
15
17
 
16
18
  # Bindings API Fixtures
@@ -1,11 +1,11 @@
1
- import pytest
2
1
  import json
3
- import requests
4
2
  import shutil
5
3
  import subprocess
6
4
  from pathlib import Path
7
5
  from urllib.parse import urljoin
8
6
 
7
+ import pytest
8
+ import requests
9
9
  from pypi_simple import PyPISimple
10
10
 
11
11
  from pulpcore.tests.functional.utils import PulpTaskError
@@ -1,6 +1,7 @@
1
1
  import pytest
2
2
 
3
3
  from pulpcore.tests.functional.utils import PulpTaskError
4
+
4
5
  from pulp_python.tests.functional.constants import PYTHON_EGG_FILENAME, PYTHON_EGG_URL
5
6
 
6
7
  CONTENT_BODY = {"relative_path": PYTHON_EGG_FILENAME, "file_url": PYTHON_EGG_URL}
@@ -1,5 +1,4 @@
1
1
  import subprocess
2
-
3
2
  from urllib.parse import urlsplit
4
3
 
5
4
 
@@ -1,14 +1,15 @@
1
- import pytest
2
-
3
1
  from urllib.parse import urljoin
2
+
3
+ import pytest
4
4
  from pypi_simple import PyPISimple
5
5
 
6
6
  from pulpcore.tests.functional.utils import PulpTaskError
7
+
7
8
  from pulp_python.tests.functional.constants import (
8
- PYTHON_FIXTURES_URL,
9
- PYTHON_PACKAGE_DATA,
10
9
  PYTHON_EGG_FILENAME,
11
10
  PYTHON_EGG_URL,
11
+ PYTHON_FIXTURES_URL,
12
+ PYTHON_PACKAGE_DATA,
12
13
  PYTHON_SM_FIXTURE_CHECKSUMS,
13
14
  PYTHON_WHEEL_FILENAME,
14
15
  PYTHON_WHEEL_URL,
@@ -1,13 +1,14 @@
1
- import pytest
2
1
  import random
3
- from pypi_simple import PyPISimple
4
2
  from urllib.parse import urljoin
5
3
 
4
+ import pytest
5
+ from pypi_simple import PyPISimple
6
+
6
7
  from pulp_python.tests.functional.constants import (
7
- PYTHON_SM_PROJECT_SPECIFIER,
8
- PYTHON_SM_FIXTURE_RELEASES,
9
- PYTHON_SM_FIXTURE_CHECKSUMS,
10
8
  PYTHON_EGG_FILENAME,
9
+ PYTHON_SM_FIXTURE_CHECKSUMS,
10
+ PYTHON_SM_FIXTURE_RELEASES,
11
+ PYTHON_SM_PROJECT_SPECIFIER,
11
12
  PYTHON_WHEEL_FILENAME,
12
13
  )
13
14
  from pulp_python.tests.functional.utils import ensure_simple
@@ -1,11 +1,12 @@
1
- import pytest
2
1
  import uuid
3
2
 
3
+ import pytest
4
+
4
5
  from pulp_python.tests.functional.constants import (
5
6
  BANDERSNATCH_CONF,
6
7
  DEFAULT_BANDER_REMOTE_BODY,
7
- PYTHON_INVALID_SPECIFIER_NO_NAME,
8
8
  PYTHON_INVALID_SPECIFIER_BAD_VERSION,
9
+ PYTHON_INVALID_SPECIFIER_NO_NAME,
9
10
  PYTHON_VALID_SPECIFIER_NO_VERSION,
10
11
  )
11
12
 
@@ -1,16 +1,17 @@
1
- import pytest
2
- import uuid
3
1
  import json
4
2
  import subprocess
3
+ import uuid
4
+ from urllib.parse import urlsplit
5
5
 
6
- from pulpcore.app import settings
6
+ import pytest
7
+
8
+ from pulpcore.app import settings # noqa: TID251
7
9
 
8
10
  from pulp_python.tests.functional.constants import (
9
11
  PYTHON_EGG_FILENAME,
10
- PYTHON_SM_PROJECT_SPECIFIER,
11
12
  PYTHON_SM_PACKAGE_COUNT,
13
+ PYTHON_SM_PROJECT_SPECIFIER,
12
14
  )
13
- from urllib.parse import urlsplit
14
15
 
15
16
  pytestmark = pytest.mark.skipif(not settings.DOMAIN_ENABLED, reason="Domain not enabled")
16
17
 
@@ -1,10 +1,10 @@
1
1
  import pytest
2
2
 
3
3
  from pulp_python.tests.functional.constants import (
4
- PYTHON_MD_PROJECT_SPECIFIER,
4
+ PYTHON_LG_PACKAGE_COUNT,
5
5
  PYTHON_LG_PROJECT_SPECIFIER,
6
6
  PYTHON_MD_PACKAGE_COUNT,
7
- PYTHON_LG_PACKAGE_COUNT,
7
+ PYTHON_MD_PROJECT_SPECIFIER,
8
8
  )
9
9
 
10
10
 
@@ -5,13 +5,15 @@ NOTE: assumes ALLOWED_EXPORT_PATHS setting contains "/tmp" - all tests will fail
5
5
  the case.
6
6
  """
7
7
 
8
- import pytest
9
8
  import uuid
10
9
 
11
- from pulpcore.app import settings
10
+ import pytest
11
+
12
+ from pulpcore.app import settings # noqa: TID251
13
+
12
14
  from pulp_python.tests.functional.constants import (
13
- PYTHON_XS_PROJECT_SPECIFIER,
14
15
  PYTHON_SM_PROJECT_SPECIFIER,
16
+ PYTHON_XS_PROJECT_SPECIFIER,
15
17
  )
16
18
 
17
19
  pytestmark = [
@@ -1,20 +1,20 @@
1
+ import subprocess
2
+ from hashlib import sha256
3
+ from random import sample
4
+ from urllib.parse import urljoin, urlsplit, urlunsplit
5
+
1
6
  import pytest
2
7
  import requests
3
- import subprocess
8
+ from packaging.version import parse
9
+ from pypi_simple import ProjectPage
4
10
 
5
11
  from pulp_python.tests.functional.constants import (
6
12
  PYPI_URL,
7
- PYTHON_XS_FIXTURE_CHECKSUMS,
8
- PYTHON_SM_PROJECT_SPECIFIER,
9
13
  PYTHON_SM_FIXTURE_RELEASES,
14
+ PYTHON_SM_PROJECT_SPECIFIER,
15
+ PYTHON_XS_FIXTURE_CHECKSUMS,
10
16
  )
11
17
 
12
- from pypi_simple import ProjectPage
13
- from packaging.version import parse
14
- from urllib.parse import urljoin, urlsplit, urlunsplit
15
- from random import sample
16
- from hashlib import sha256
17
-
18
18
 
19
19
  def test_pull_through_install(
20
20
  python_bindings, python_remote_factory, python_distribution_factory, delete_orphans_pre
@@ -1,18 +1,23 @@
1
- import pytest
2
- import requests
3
1
  import subprocess
4
-
2
+ import time
3
+ from datetime import datetime
5
4
  from urllib.parse import urljoin
6
5
 
6
+ import pytest
7
+ import requests
8
+
7
9
  from pulp_python.tests.functional.constants import (
8
10
  PYPI_SERIAL_CONSTANT,
9
- PYTHON_MD_PROJECT_SPECIFIER,
10
- PYTHON_MD_PYPI_SUMMARY,
11
+ PYPI_SIMPLE_V1_JSON,
11
12
  PYTHON_EGG_FILENAME,
12
13
  PYTHON_EGG_SHA256,
14
+ PYTHON_MD_PROJECT_SPECIFIER,
15
+ PYTHON_MD_PYPI_SUMMARY,
13
16
  PYTHON_WHEEL_FILENAME,
14
17
  PYTHON_WHEEL_SHA256,
15
18
  SHELF_PYTHON_JSON,
19
+ TWINE_WHEEL_FILENAME,
20
+ TWINE_WHEEL_URL,
16
21
  )
17
22
  from pulp_python.tests.functional.utils import ensure_metadata
18
23
 
@@ -328,3 +333,41 @@ def assert_download_info(expected, received, message="Failed to match"):
328
333
  matched = True
329
334
  break
330
335
  assert matched is True, message
336
+
337
+
338
+ @pytest.mark.parallel
339
+ def test_upload_time_reflects_repo_addition(
340
+ monitor_task,
341
+ python_bindings,
342
+ python_content_factory,
343
+ python_distribution_factory,
344
+ python_repo_factory,
345
+ ):
346
+ """
347
+ Test that upload_time reflects repository addition time instead of content creation time.
348
+ Checks both Simple and JSON APIs.
349
+ """
350
+ content = python_content_factory(TWINE_WHEEL_FILENAME, url=TWINE_WHEEL_URL)
351
+ content_created = datetime.fromisoformat(
352
+ str(python_bindings.ContentPackagesApi.read(content.pulp_href).pulp_created)
353
+ )
354
+ time.sleep(2)
355
+
356
+ repo = python_repo_factory()
357
+ body = {"add_content_units": [content.pulp_href]}
358
+ monitor_task(python_bindings.RepositoriesPythonApi.modify(repo.pulp_href, body).task)
359
+ distro = python_distribution_factory(repository=repo)
360
+
361
+ # Simple API
362
+ headers = {"Accept": PYPI_SIMPLE_V1_JSON}
363
+ resp = requests.get(f"{urljoin(distro.base_url, 'simple/')}twine", headers=headers)
364
+ assert resp.status_code == 200
365
+ simple_time = datetime.fromisoformat(resp.json()["files"][0]["upload-time"])
366
+ assert simple_time > content_created
367
+
368
+ # JSON API
369
+ json_resp = requests.get(urljoin(distro.base_url, "pypi/twine/json"))
370
+ assert json_resp.status_code == 200
371
+ json_time = datetime.fromisoformat(json_resp.json()["urls"][0]["upload_time"])
372
+ assert json_time > content_created
373
+ assert json_time == simple_time
@@ -5,6 +5,9 @@ import requests
5
5
 
6
6
  from pulp_python.tests.functional.constants import (
7
7
  PYPI_SERIAL_CONSTANT,
8
+ PYPI_SIMPLE_V1_HTML,
9
+ PYPI_SIMPLE_V1_JSON,
10
+ PYPI_TEXT_HTML,
8
11
  PYTHON_SM_FIXTURE_CHECKSUMS,
9
12
  PYTHON_SM_FIXTURE_RELEASES,
10
13
  PYTHON_SM_PROJECT_SPECIFIER,
@@ -27,10 +30,6 @@ from pulp_python.tests.functional.utils import ensure_simple
27
30
 
28
31
  API_VERSION = "1.1"
29
32
 
30
- PYPI_TEXT_HTML = "text/html"
31
- PYPI_SIMPLE_V1_HTML = "application/vnd.pypi.simple.v1+html"
32
- PYPI_SIMPLE_V1_JSON = "application/vnd.pypi.simple.v1+json"
33
-
34
33
 
35
34
  @pytest.mark.parallel
36
35
  def test_simple_html_index_api(
@@ -69,7 +68,7 @@ def test_simple_html_detail_api(
69
68
  monitor_task(python_bindings.RepositoriesPythonApi.modify(repo.pulp_href, body).task)
70
69
  distro = python_distribution_factory(repository=repo)
71
70
 
72
- url = f'{urljoin(distro.base_url, "simple/")}twine'
71
+ url = f"{urljoin(distro.base_url, 'simple/')}twine"
73
72
  headers = {"Accept": PYPI_SIMPLE_V1_HTML}
74
73
 
75
74
  response = requests.get(url, headers=headers)
@@ -125,7 +124,7 @@ def test_simple_json_detail_api(
125
124
  monitor_task(python_bindings.RepositoriesPythonApi.modify(repo.pulp_href, body).task)
126
125
  distro = python_distribution_factory(repository=repo)
127
126
 
128
- url = f'{urljoin(distro.base_url, "simple/")}twine'
127
+ url = f"{urljoin(distro.base_url, 'simple/')}twine"
129
128
  headers = {"Accept": PYPI_SIMPLE_V1_JSON}
130
129
 
131
130
  response = requests.get(url, headers=headers)
@@ -1,6 +1,7 @@
1
- import pytest
2
1
  import uuid
3
2
 
3
+ import pytest
4
+
4
5
  from pulp_python.tests.functional.constants import (
5
6
  PYTHON_EGG_FILENAME,
6
7
  PYTHON_EGG_SHA256,
@@ -44,9 +45,9 @@ def try_action(python_bindings, monitor_task):
44
45
  except python_bindings.module.ApiException as e:
45
46
  assert e.status == outcome, f"{e}"
46
47
  else:
47
- assert (
48
- status_code == outcome
49
- ), f"User performed {action} when they shouldn't been able to"
48
+ assert status_code == outcome, (
49
+ f"User performed {action} when they shouldn't been able to"
50
+ )
50
51
  return data
51
52
 
52
53
  return _try_action
@@ -1,7 +1,8 @@
1
- import pytest
2
1
  import subprocess
3
2
  from urllib.parse import urljoin
4
3
 
4
+ import pytest
5
+
5
6
  from pulp_python.tests.functional.constants import (
6
7
  PYTHON_EGG_FILENAME,
7
8
  PYTHON_FIXTURES_URL,
@@ -1,21 +1,21 @@
1
1
  import pytest
2
2
 
3
3
  from pulp_python.tests.functional.constants import (
4
- PYTHON_XS_PACKAGE_COUNT,
5
- PYTHON_PRERELEASE_TEST_SPECIFIER,
6
- PYTHON_WITH_PRERELEASE_COUNT,
7
- PYTHON_WITHOUT_PRERELEASE_COUNT,
8
- PYTHON_XS_PROJECT_SPECIFIER,
9
- PYTHON_MD_PROJECT_SPECIFIER,
4
+ DJANGO_LATEST_3,
5
+ PYTHON_LG_FIXTURE_COUNTS,
6
+ PYTHON_LG_PACKAGE_COUNT,
7
+ PYTHON_LG_PROJECT_SPECIFIER,
10
8
  PYTHON_MD_PACKAGE_COUNT,
11
- PYTHON_SM_PROJECT_SPECIFIER,
9
+ PYTHON_MD_PROJECT_SPECIFIER,
10
+ PYTHON_PRERELEASE_TEST_SPECIFIER,
12
11
  PYTHON_SM_PACKAGE_COUNT,
12
+ PYTHON_SM_PROJECT_SPECIFIER,
13
13
  PYTHON_UNAVAILABLE_PACKAGE_COUNT,
14
14
  PYTHON_UNAVAILABLE_PROJECT_SPECIFIER,
15
- PYTHON_LG_PROJECT_SPECIFIER,
16
- PYTHON_LG_PACKAGE_COUNT,
17
- PYTHON_LG_FIXTURE_COUNTS,
18
- DJANGO_LATEST_3,
15
+ PYTHON_WITH_PRERELEASE_COUNT,
16
+ PYTHON_WITHOUT_PRERELEASE_COUNT,
17
+ PYTHON_XS_PACKAGE_COUNT,
18
+ PYTHON_XS_PROJECT_SPECIFIER,
19
19
  SCIPY_COUNTS,
20
20
  )
21
21
  from pulp_python.tests.functional.utils import ensure_metadata
@@ -1,16 +1,18 @@
1
+ from urllib.parse import urljoin
2
+
1
3
  import pytest
2
4
  import requests
5
+
3
6
  from pulp_python.tests.functional.constants import (
4
7
  PYTHON_EGG_FILENAME,
8
+ PYTHON_EGG_SHA256,
5
9
  PYTHON_EGG_URL,
6
10
  PYTHON_FIXTURES_URL,
7
11
  PYTHON_WHEEL_FILENAME,
8
- PYTHON_WHEEL_URL,
9
- PYTHON_EGG_SHA256,
10
12
  PYTHON_WHEEL_SHA256,
13
+ PYTHON_WHEEL_URL,
11
14
  )
12
15
  from pulp_python.tests.functional.utils import ensure_metadata
13
- from urllib.parse import urljoin
14
16
 
15
17
 
16
18
  @pytest.mark.parametrize(
@@ -382,3 +382,7 @@ VULNERABILITY_REPORT_TEST_PACKAGES = [
382
382
  ]
383
383
 
384
384
  PYPI_SERIAL_CONSTANT = 1000000000
385
+
386
+ PYPI_TEXT_HTML = "text/html"
387
+ PYPI_SIMPLE_V1_HTML = "application/vnd.pypi.simple.v1+html"
388
+ PYPI_SIMPLE_V1_JSON = "application/vnd.pypi.simple.v1+json"
@@ -1,6 +1,6 @@
1
- import requests
2
-
3
1
  from urllib.parse import urljoin
2
+
3
+ import requests
4
4
  from lxml import html
5
5
 
6
6
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pulp-python
3
- Version: 3.29.0
3
+ Version: 3.30.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
@@ -1,19 +1,19 @@
1
1
  pulp_python/__init__.py,sha256=GIuTLoBTc-07dSLJUh8xrZPRz8x-jJ61pfR0J1IjnzI,65
2
- pulp_python/pytest_plugin.py,sha256=EBivPJa39ZE1QaDWea9candeeJL_W_cBk6Q7Onhw4bE,8604
3
- pulp_python/app/__init__.py,sha256=rWQatXxN5F1fdkajaunRkP5PUdVrWTH0qCZGU8jRHuw,2488
2
+ pulp_python/pytest_plugin.py,sha256=LNnLjOkeEu2X4gJi614bHVmbsHyEwooHYIeecr96Qy4,8606
3
+ pulp_python/app/__init__.py,sha256=kvIZAie_YepDZxtZCUo9YVSjAZXhIjWL7sq7aSI88L8,2490
4
4
  pulp_python/app/global_access_conditions.py,sha256=MZJtyoVsr-4hRaty6mKDqh3caOHd5UKJjEWLV2crOLs,1080
5
- pulp_python/app/modelresource.py,sha256=dogoBWibBmQyFpcV-Hp1lu7D2WwSECa5PEShWSIg7mg,1248
6
- pulp_python/app/models.py,sha256=1lyO4Po_vTS8prrtBL1Lo5qh12fUQpvX6H3x2kVOCrY,17685
5
+ pulp_python/app/modelresource.py,sha256=4SFAdqk6lozi_cZz4uqDIqhqPAZF-7l5jJwPn-xGZFs,1249
6
+ pulp_python/app/models.py,sha256=Y7MDTl2nKz1dz2S4KQIQQ4oWcYgBA4TyDVxJGBYPHY4,17705
7
7
  pulp_python/app/provenance.py,sha256=iyhkuNahHiTDK0Djrd4-PlgErA5SJVI0uQOIPj46tEI,2352
8
- pulp_python/app/replica.py,sha256=W60Kt9CwZSfztRi3-f82Rfp0F_zhzpOTiz35bvRFBBE,1881
9
- pulp_python/app/serializers.py,sha256=Pulopm6BFfDrH4sUmt2x1ZI7mLzHtrQrOp3K9ILrxlw,33853
8
+ pulp_python/app/replica.py,sha256=qiWRP7tM_v4yP_XLIQfumfGolru-Jt6ZA0KVb-9g2cA,1882
9
+ pulp_python/app/serializers.py,sha256=Wg83g7LE9Qkf1S7hkkvG2_EJUi7D12l8UyCA1wmwf-I,33819
10
10
  pulp_python/app/settings.py,sha256=Cyc_p6U0HQjKpyrRL6JFrK3R7RMQJ9MAgNMJCfzPEiA,255
11
- pulp_python/app/urls.py,sha256=3-UG9-bkPW_bs8362XBnxbpGqQetyuMOfPaayadMYFo,1387
12
- pulp_python/app/utils.py,sha256=2MEHK_fuLpZA9w4ohbhcs1D2ii478gwW_iAuSTsu-kw,26740
13
- pulp_python/app/viewsets.py,sha256=8-FPEgNGY_KEaoJbdE_N5hQg-KOe--OXvxQZ6p6wFhE,34120
11
+ pulp_python/app/urls.py,sha256=M2xjQ0j47BwQVpi75QCa5eUnQDcroKv3Cee7UrQ3QcA,1387
12
+ pulp_python/app/utils.py,sha256=f9sCzZ58Sf7EBNqzBG0NBGtWE6gE2eIcnoSTAhdVIIg,27303
13
+ pulp_python/app/viewsets.py,sha256=EyeuNNvklB74tSyL4MRfTnh4a5KVv2kUPgmeTUd6oSY,34209
14
14
  pulp_python/app/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  pulp_python/app/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- pulp_python/app/management/commands/repair-python-metadata.py,sha256=i-mC3UYxIiHJoknRV4xZZ7cQ44lyqWshpbaeYi7as8E,4457
16
+ pulp_python/app/management/commands/repair-python-metadata.py,sha256=knvTPcPwyfgCH0-KNNCK1Mj0mQKzXUdYEwo-v6F94XU,4548
17
17
  pulp_python/app/migrations/0001_initial.py,sha256=xbEeZoLAUhdVrySf22Uz-e9Jm32rbY_HjxuNcEar6EE,6843
18
18
  pulp_python/app/migrations/0001_squashed_0010_update_json_field.py,sha256=hFo1OD0JS_vn8bl49nF3Qz9QZBkVc5uDdNRnporvuyY,10455
19
19
  pulp_python/app/migrations/0002_pythonpackagecontent_python_version.py,sha256=2WMNRVfjbkVfI_cTu8VNQRlPXK4n-JuFRsBZFcm04AE,427
@@ -39,47 +39,47 @@ pulp_python/app/migrations/0021_pythonrepository_upload_duplicate_filenames.py,s
39
39
  pulp_python/app/migrations/0022_pythonblocklistentry.py,sha256=EbtjZuN65myTAHVWrJYbt4mWgWL7EElEYs1XulHB6Bo,1732
40
40
  pulp_python/app/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
41
  pulp_python/app/pypi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
- pulp_python/app/pypi/serializers.py,sha256=w6_doLpaO8Dnzur57MYrTIqEP4I3LI8biu9ipLC66fk,5028
43
- pulp_python/app/pypi/views.py,sha256=s53NgE_LiWKVJJdLMOwj8XG23vvKObmSI95cLklkXtw,21127
42
+ pulp_python/app/pypi/serializers.py,sha256=rE0Cci2IMg4NbNWlVdo-8zPaJCAUq2Re57q_T3jMt0Y,5030
43
+ pulp_python/app/pypi/views.py,sha256=D2lsHijKp3ZJemt-iwWxjJEin5rAkc0pZzi9kZyQgwk,21651
44
44
  pulp_python/app/tasks/__init__.py,sha256=lTFpVvpDKbqv9RC0b2RYU8Bo6svDjrA-djt16pADFr8,284
45
- pulp_python/app/tasks/publish.py,sha256=_1SymLwmJsZepBLdecb69ijnnTeqiH054I6n4HuSIVo,4334
46
- pulp_python/app/tasks/repair.py,sha256=KQzVhdtjcfFTCco9zk_iETfVETsUqQJSvMV4OBOd7es,12255
47
- pulp_python/app/tasks/sync.py,sha256=hBA4iyY9HFbLZMFWqVJ4W3Q3NAN122QVaOSEGSSnMtc,12868
48
- pulp_python/app/tasks/upload.py,sha256=12E9ihDqbe9Ihij9o6p_yuV6WF1Yyt6zPeOI2dzCEms,5697
45
+ pulp_python/app/tasks/publish.py,sha256=bjsJzqJbLu7TF5rLb-UsZMmlNnc_LKw-sdHX9Gcatbw,4334
46
+ pulp_python/app/tasks/repair.py,sha256=5InzdbjW8y3AC4Vj2PsNLm3wGGTr8D3LcfPw_WA2Fks,12257
47
+ pulp_python/app/tasks/sync.py,sha256=LqGQsiSbOQl05H9e7PC830aaLDuQXS1Ql1GiwfrO1Qc,12866
48
+ pulp_python/app/tasks/upload.py,sha256=Pclsh6co5hBO6wdxZbGKBUSBV643nd9c2RXQO2Nkdik,5698
49
49
  pulp_python/app/tasks/vulnerability_report.py,sha256=0cyxNb4048HFUdUlGBA6wYsg-hEMjSfE8mtw05Ct9BQ,1126
50
50
  pulp_python/app/webserver_snippets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
51
  pulp_python/app/webserver_snippets/apache.conf,sha256=3frHSl2YV_8pJPscaFxMVo7HmxGJdb8XVmfdLtCxzoA,97
52
52
  pulp_python/app/webserver_snippets/nginx.conf,sha256=gMqZGFefsTJVVx9YRxpHVS7NMEll9CzOseYdtLr3Avc,344
53
53
  pulp_python/tests/__init__.py,sha256=4Yz43a8s-KyhdHFb5eEhIIvH72807Y84uAHnG5bO5y0,31
54
54
  pulp_python/tests/functional/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
- pulp_python/tests/functional/constants.py,sha256=SvzlxGQz1I-p3JEBSqNz9qoAYfq5yhGsqtYoJpCOioU,13819
56
- pulp_python/tests/functional/utils.py,sha256=ZmOVSa94o0KvH7l42YwuUAcNJo8Eb733QBH2G6nGkeQ,5901
55
+ pulp_python/tests/functional/constants.py,sha256=4e_zssE9G1bSNNJxYo7VgwvojUL_NocG5mUH996KBJs,13969
56
+ pulp_python/tests/functional/utils.py,sha256=GWnXrsQGZd0Ngewa_9yce58Qc3z7FbrlRvqao_8ZML0,5901
57
57
  pulp_python/tests/functional/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
- pulp_python/tests/functional/api/test_attestations.py,sha256=_opUZT65c5H2j_8ous-nKGHmDOw8EMjxdooTIQhiXQ8,8640
58
+ pulp_python/tests/functional/api/test_attestations.py,sha256=cyZl4jCL-Q5Qu7XpxLc5_YmCzyc1Ctfl1IvSJ6YPQQU,8640
59
59
  pulp_python/tests/functional/api/test_auto_publish.py,sha256=uCIt4LsO61oMk3bDs3LMQDJI8zkKqvY0b1uX16bTxzM,1747
60
- pulp_python/tests/functional/api/test_blocklist.py,sha256=ichJo5UxDdWcR3pnuRouAsPLVBZ7Wcss7oB-AJEV-s8,5993
61
- pulp_python/tests/functional/api/test_consume_content.py,sha256=QUOZ_bQ_Ortzitc7sjlMEJzRhPm00wayxjZvEeK18jI,1000
62
- pulp_python/tests/functional/api/test_crud_content_unit.py,sha256=IjkyVC761ZTOhdM3ksT_5zvvWhMk326BSJlUyql0vFM,13793
63
- pulp_python/tests/functional/api/test_crud_publications.py,sha256=uoTGHbhKq_mYOYtNV8Tt9cyhzY0zsoG1DhYrfIdYcMc,5646
64
- pulp_python/tests/functional/api/test_crud_remotes.py,sha256=uRo51X3MDWIls4Fdxw5unvU47_JyyLEg2w41ByvDcmY,5811
65
- pulp_python/tests/functional/api/test_domains.py,sha256=owbvFxOKDuAVX2PUpsO0olAmQmIKFThBqnQtjfKbS8Y,10210
66
- pulp_python/tests/functional/api/test_download_content.py,sha256=msnsKpU6TGT8eNu6e0uFa4fte6hj85OTexwOHdf66-c,4950
67
- pulp_python/tests/functional/api/test_export_import.py,sha256=QciJ7Pdv6HSv3mKGqKSNW5g9M8e9tkWcapRQ1PUxabU,4512
68
- pulp_python/tests/functional/api/test_full_mirror.py,sha256=npBj0IR10JUmjZyBY99NAGc8t5Xjbzl-y__69X9Eh1E,12045
69
- pulp_python/tests/functional/api/test_pypi_apis.py,sha256=sdovsmCb88aDaEqTe_RKXiBJDaAx5BRRaT1oNPbIAfo,11691
70
- pulp_python/tests/functional/api/test_pypi_simple_api.py,sha256=UzO3K3GMqiDUsAMWlxy9xM3kYtnD6e2WYNtwlJWYm-U,7251
71
- pulp_python/tests/functional/api/test_rbac.py,sha256=cy1RQHvWKbE4f4aPu33ZdIUBiJBnW8aOXKlDHHcCuxo,10512
72
- pulp_python/tests/functional/api/test_repair.py,sha256=8tW4jgR4pAsAswsblZM2NKdGAKnh1zuH7572k2GO4ag,12908
73
- pulp_python/tests/functional/api/test_sync.py,sha256=a9bSHFesOnh0Pvc9KCNSUw0ghIlEWdIvXhVw7gSRG2Y,13801
74
- pulp_python/tests/functional/api/test_upload.py,sha256=zd-qRwjGDuEazLZeVgeZqLbz6Lhd8jdOyS1K5QB0PDE,5877
60
+ pulp_python/tests/functional/api/test_blocklist.py,sha256=IWzlazoQbrfyHNq9bNAa9FcbShWqzC2Zhq8qrN7HBwg,5994
61
+ pulp_python/tests/functional/api/test_consume_content.py,sha256=-7b6KOrIT3NLSUafeu1tzXEXRPddDbS5VeMHxMIy2n8,999
62
+ pulp_python/tests/functional/api/test_crud_content_unit.py,sha256=R5Gvl4ZjW1eQHmrbqsR0zfzKANBxEKwlr_lugHir7Kk,13794
63
+ pulp_python/tests/functional/api/test_crud_publications.py,sha256=3cuSDC9C9M1opt0lh5ObGj8t7gq5jUW-RWj6MrA4Teo,5647
64
+ pulp_python/tests/functional/api/test_crud_remotes.py,sha256=clFFhgG5udyKzWOLwxpmwjhiVz8r5JEPAQHkztcAf9w,5812
65
+ pulp_python/tests/functional/api/test_domains.py,sha256=BnWBwid_RA0xenBBHwvkT5_23RPe19DjQCICdMWad3w,10227
66
+ pulp_python/tests/functional/api/test_download_content.py,sha256=5IuaHXyLakPkjm5sLTxtTl7Dq0yl7N36HpObnIa0Sks,4950
67
+ pulp_python/tests/functional/api/test_export_import.py,sha256=rHns9wdaeP-vtfW_qoGHU9EVuJ4YuWE0-rjl_8otAgU,4530
68
+ pulp_python/tests/functional/api/test_full_mirror.py,sha256=eU5HzgBBFOnX1q4m8ELx-t-I3U4TWXL-LNrlc2BcWVc,12045
69
+ pulp_python/tests/functional/api/test_pypi_apis.py,sha256=mhST0GV-uDrVPsBWYRGaJx1pp9htzbYiUGuIGOI0s_s,13218
70
+ pulp_python/tests/functional/api/test_pypi_simple_api.py,sha256=tOUl8WXgJkMoxGyLbA-WorCxIRKfGWM-27_dK_Jc0Q4,7171
71
+ pulp_python/tests/functional/api/test_rbac.py,sha256=-xNWqvKKU-v1uC6tCRGBK0aWaff25K9C-AfzQkdHhhI,10513
72
+ pulp_python/tests/functional/api/test_repair.py,sha256=4FR7jx_LA2K-pnRJXKkhq-1uUoWXST1leZ9XdyhGM2U,12909
73
+ pulp_python/tests/functional/api/test_sync.py,sha256=TTHR1CpZeRoD97RKxj2pZPsP0OS9ibYKGPOh1WfKISg,13801
74
+ pulp_python/tests/functional/api/test_upload.py,sha256=PZ0HK7UU9gvxNaRlB_EAY1-pcghDtx22DMGk5C1oM2I,5879
75
75
  pulp_python/tests/functional/api/test_vulnerability_report.py,sha256=Rv492Wrvu1FY7O_moo9DTB6OkI-OZURj_fuTKbENLh8,1730
76
76
  pulp_python/tests/functional/assets/shelf-reader-0.1.tar.gz.publish.attestation,sha256=_Ygrz7523z55s4uPmQWYxF29jr0NqJxVm_d-Z8KvrZ0,10363
77
77
  pulp_python/tests/functional/assets/shelf_reader-0.1-py2-none-any.whl.publish.attestation,sha256=muTQ8dqYSSdx76DlaPjB1REcNIS-aak-Na0TkASxu8M,10426
78
78
  pulp_python/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
79
  pulp_python/tests/unit/test_models.py,sha256=TBI0yKsrdbnJSPeBFfxSqhXK7zaNvR6qg5JehGH3Pds,229
80
- pulp_python-3.29.0.dist-info/licenses/LICENSE,sha256=2ylvL381vKOhdO-w6zkrOxe9lLNBhRQpo9_0EbHC_HM,18046
81
- pulp_python-3.29.0.dist-info/METADATA,sha256=alLnLZtMqhz4pl-EyaETY-NOOrRG7ziRJEQFO4bcfms,1744
82
- pulp_python-3.29.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
83
- pulp_python-3.29.0.dist-info/entry_points.txt,sha256=HvqLEXjw_dS5jqAwnE5JiRZFE6f-y5SRtitKLPml2To,115
84
- pulp_python-3.29.0.dist-info/top_level.txt,sha256=X0hXgXc_bpbiKqVrkt8jD5_QEiQviKbHDwveQcOcJjo,12
85
- pulp_python-3.29.0.dist-info/RECORD,,
80
+ pulp_python-3.30.1.dist-info/licenses/LICENSE,sha256=2ylvL381vKOhdO-w6zkrOxe9lLNBhRQpo9_0EbHC_HM,18046
81
+ pulp_python-3.30.1.dist-info/METADATA,sha256=BcaJBgi3HQekc7OK4Ub3IBxMf5q42FQJDfnfRvQbevY,1744
82
+ pulp_python-3.30.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
83
+ pulp_python-3.30.1.dist-info/entry_points.txt,sha256=HvqLEXjw_dS5jqAwnE5JiRZFE6f-y5SRtitKLPml2To,115
84
+ pulp_python-3.30.1.dist-info/top_level.txt,sha256=X0hXgXc_bpbiKqVrkt8jD5_QEiQviKbHDwveQcOcJjo,12
85
+ pulp_python-3.30.1.dist-info/RECORD,,