pulp-python 3.13.5__py3-none-any.whl → 3.13.7__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.
- pulp_python/__init__.py +1 -1
- pulp_python/app/__init__.py +5 -3
- pulp_python/app/global_access_conditions.py +0 -1
- pulp_python/app/management/commands/repair-python-metadata.py +5 -4
- pulp_python/app/modelresource.py +1 -0
- pulp_python/app/models.py +8 -7
- pulp_python/app/pypi/serializers.py +11 -9
- pulp_python/app/pypi/views.py +69 -54
- pulp_python/app/replica.py +5 -3
- pulp_python/app/serializers.py +187 -110
- pulp_python/app/settings.py +1 -1
- pulp_python/app/tasks/publish.py +24 -25
- pulp_python/app/tasks/sync.py +15 -29
- pulp_python/app/tasks/upload.py +7 -8
- pulp_python/app/urls.py +5 -5
- pulp_python/app/utils.py +52 -45
- pulp_python/app/viewsets.py +43 -46
- pulp_python/pytest_plugin.py +14 -5
- pulp_python/tests/functional/api/test_consume_content.py +1 -1
- pulp_python/tests/functional/api/test_crud_content_unit.py +8 -5
- pulp_python/tests/functional/api/test_crud_publications.py +9 -6
- pulp_python/tests/functional/api/test_crud_remotes.py +3 -2
- pulp_python/tests/functional/api/test_domains.py +10 -7
- pulp_python/tests/functional/api/test_download_content.py +2 -2
- pulp_python/tests/functional/api/test_export_import.py +7 -4
- pulp_python/tests/functional/api/test_full_mirror.py +4 -4
- pulp_python/tests/functional/api/test_pypi_apis.py +13 -38
- pulp_python/tests/functional/api/test_rbac.py +6 -5
- pulp_python/tests/functional/api/test_repair.py +3 -2
- pulp_python/tests/functional/api/test_sync.py +28 -19
- pulp_python/tests/functional/constants.py +24 -38
- pulp_python/tests/functional/utils.py +15 -6
- {pulp_python-3.13.5.dist-info → pulp_python-3.13.7.dist-info}/METADATA +1 -1
- {pulp_python-3.13.5.dist-info → pulp_python-3.13.7.dist-info}/RECORD +38 -38
- {pulp_python-3.13.5.dist-info → pulp_python-3.13.7.dist-info}/WHEEL +1 -1
- {pulp_python-3.13.5.dist-info → pulp_python-3.13.7.dist-info}/entry_points.txt +0 -0
- {pulp_python-3.13.5.dist-info → pulp_python-3.13.7.dist-info}/licenses/LICENSE +0 -0
- {pulp_python-3.13.5.dist-info → pulp_python-3.13.7.dist-info}/top_level.txt +0 -0
pulp_python/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
default_app_config =
|
|
1
|
+
default_app_config = "pulp_python.app.PulpPythonPluginAppConfig"
|
pulp_python/app/__init__.py
CHANGED
|
@@ -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.13.
|
|
15
|
+
version = "3.13.7"
|
|
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
|
|
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
|
-
|
|
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
|
|
|
@@ -23,7 +24,7 @@ def repair_metadata(content):
|
|
|
23
24
|
batch = []
|
|
24
25
|
set_of_update_fields = set()
|
|
25
26
|
total_repaired = 0
|
|
26
|
-
for package in immediate_content.prefetch_related(
|
|
27
|
+
for package in immediate_content.prefetch_related("_artifacts").iterator(chunk_size=1000):
|
|
27
28
|
new_data = artifact_to_python_content_data(
|
|
28
29
|
package.filename, package._artifacts.get(), package.pulp_domain
|
|
29
30
|
)
|
|
@@ -55,7 +56,7 @@ def href_prn_list_handler(value):
|
|
|
55
56
|
(?:{settings.API_ROOT}(?:[-_a-zA-Z0-9]+/)?api/v3/repositories/python/python/[-a-f0-9]+/)
|
|
56
57
|
|(?:prn:python\.pythonrepository:[-a-f0-9]+)
|
|
57
58
|
""",
|
|
58
|
-
re.VERBOSE
|
|
59
|
+
re.VERBOSE,
|
|
59
60
|
)
|
|
60
61
|
values = []
|
|
61
62
|
for v in value.split(","):
|
pulp_python/app/modelresource.py
CHANGED
pulp_python/app/models.py
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
from logging import getLogger
|
|
2
|
+
from pathlib import PurePath
|
|
2
3
|
|
|
3
4
|
from aiohttp.web import json_response
|
|
5
|
+
from django.conf import settings
|
|
4
6
|
from django.contrib.postgres.fields import ArrayField
|
|
5
7
|
from django.core.exceptions import ObjectDoesNotExist
|
|
6
8
|
from django.db import models
|
|
7
|
-
|
|
9
|
+
|
|
8
10
|
from pulpcore.plugin.models import (
|
|
9
11
|
AutoAddObjPermsMixin,
|
|
10
12
|
Content,
|
|
11
|
-
Publication,
|
|
12
13
|
Distribution,
|
|
14
|
+
Publication,
|
|
13
15
|
Remote,
|
|
14
16
|
Repository,
|
|
15
17
|
)
|
|
18
|
+
from pulpcore.plugin.repo_version_utils import remove_duplicates, validate_repo_version
|
|
16
19
|
from pulpcore.plugin.responses import ArtifactResponse
|
|
20
|
+
from pulpcore.plugin.util import get_domain, get_domain_pk
|
|
17
21
|
|
|
18
|
-
from pathlib import PurePath
|
|
19
22
|
from .utils import (
|
|
23
|
+
PYPI_LAST_SERIAL,
|
|
24
|
+
PYPI_SERIAL_CONSTANT,
|
|
20
25
|
artifact_to_python_content_data,
|
|
21
26
|
canonicalize_name,
|
|
22
27
|
python_content_to_json,
|
|
23
|
-
PYPI_LAST_SERIAL,
|
|
24
|
-
PYPI_SERIAL_CONSTANT,
|
|
25
28
|
)
|
|
26
|
-
from pulpcore.plugin.repo_version_utils import remove_duplicates, validate_repo_version
|
|
27
|
-
from pulpcore.plugin.util import get_domain_pk, get_domain
|
|
28
29
|
|
|
29
30
|
log = getLogger(__name__)
|
|
30
31
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from gettext import gettext as _
|
|
3
3
|
|
|
4
|
+
from django.db.utils import IntegrityError
|
|
4
5
|
from rest_framework import serializers
|
|
5
|
-
|
|
6
|
+
|
|
6
7
|
from pulpcore.plugin.models import Artifact
|
|
7
8
|
from pulpcore.plugin.util import get_domain
|
|
8
|
-
|
|
9
|
+
|
|
10
|
+
from pulp_python.app.utils import DIST_EXTENSIONS
|
|
9
11
|
|
|
10
12
|
log = logging.getLogger(__name__)
|
|
11
13
|
|
|
@@ -46,7 +48,7 @@ class PackageUploadSerializer(serializers.Serializer):
|
|
|
46
48
|
action = serializers.CharField(
|
|
47
49
|
help_text=_("Defaults to `file_upload`, don't change it or request will fail!"),
|
|
48
50
|
default="file_upload",
|
|
49
|
-
source=":action"
|
|
51
|
+
source=":action",
|
|
50
52
|
)
|
|
51
53
|
sha256_digest = serializers.CharField(
|
|
52
54
|
help_text=_("SHA256 of package to validate upload integrity."),
|
|
@@ -59,17 +61,17 @@ class PackageUploadSerializer(serializers.Serializer):
|
|
|
59
61
|
"""Validates the request."""
|
|
60
62
|
action = data.get(":action")
|
|
61
63
|
if action != "file_upload":
|
|
62
|
-
raise serializers.ValidationError(
|
|
63
|
-
_("We do not support the :action {}").format(action)
|
|
64
|
-
)
|
|
64
|
+
raise serializers.ValidationError(_("We do not support the :action {}").format(action))
|
|
65
65
|
file = data.get("content")
|
|
66
66
|
for ext, packagetype in DIST_EXTENSIONS.items():
|
|
67
67
|
if file.name.endswith(ext):
|
|
68
68
|
break
|
|
69
69
|
else:
|
|
70
|
-
raise serializers.ValidationError(
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
raise serializers.ValidationError(
|
|
71
|
+
_(
|
|
72
|
+
"Extension on {} is not a valid python extension "
|
|
73
|
+
"(.whl, .exe, .egg, .tar.gz, .tar.bz2, .zip)"
|
|
74
|
+
).format(file.name)
|
|
73
75
|
)
|
|
74
76
|
sha256 = data.get("sha256_digest")
|
|
75
77
|
digests = {"sha256": sha256} if sha256 else None
|
pulp_python/app/pypi/views.py
CHANGED
|
@@ -1,54 +1,53 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from django.core.exceptions import ObjectDoesNotExist
|
|
7
|
-
from django.shortcuts import redirect
|
|
8
|
-
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
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
import requests
|
|
11
8
|
from django.contrib.sessions.models import Session
|
|
9
|
+
from django.core.exceptions import ObjectDoesNotExist
|
|
12
10
|
from django.db import transaction
|
|
13
11
|
from django.db.utils import DatabaseError
|
|
14
12
|
from django.http.response import (
|
|
15
13
|
Http404,
|
|
16
|
-
HttpResponseForbidden,
|
|
17
14
|
HttpResponseBadRequest,
|
|
18
|
-
|
|
15
|
+
HttpResponseForbidden,
|
|
16
|
+
StreamingHttpResponse,
|
|
19
17
|
)
|
|
18
|
+
from django.shortcuts import redirect
|
|
20
19
|
from drf_spectacular.utils import extend_schema
|
|
21
20
|
from dynaconf import settings
|
|
22
|
-
from itertools import chain
|
|
23
21
|
from packaging.utils import canonicalize_name
|
|
24
|
-
from urllib.parse import urljoin, urlparse, urlunsplit
|
|
25
|
-
from pathlib import PurePath
|
|
26
22
|
from pypi_simple import parse_links_stream_response
|
|
23
|
+
from rest_framework.response import Response
|
|
24
|
+
from rest_framework.reverse import reverse
|
|
25
|
+
from rest_framework.viewsets import ViewSet
|
|
27
26
|
|
|
28
|
-
from pulpcore.plugin.viewsets import OperationPostponedResponse
|
|
29
27
|
from pulpcore.plugin.tasking import dispatch
|
|
30
28
|
from pulpcore.plugin.util import get_domain
|
|
29
|
+
from pulpcore.plugin.viewsets import OperationPostponedResponse
|
|
30
|
+
|
|
31
|
+
from pulp_python.app import tasks
|
|
31
32
|
from pulp_python.app.models import (
|
|
32
33
|
PythonDistribution,
|
|
33
34
|
PythonPackageContent,
|
|
34
35
|
PythonPublication,
|
|
35
36
|
)
|
|
36
37
|
from pulp_python.app.pypi.serializers import (
|
|
37
|
-
SummarySerializer,
|
|
38
38
|
PackageMetadataSerializer,
|
|
39
39
|
PackageUploadSerializer,
|
|
40
|
-
PackageUploadTaskSerializer
|
|
40
|
+
PackageUploadTaskSerializer,
|
|
41
|
+
SummarySerializer,
|
|
41
42
|
)
|
|
42
43
|
from pulp_python.app.utils import (
|
|
43
|
-
write_simple_index,
|
|
44
|
-
write_simple_detail,
|
|
45
|
-
python_content_to_json,
|
|
46
44
|
PYPI_LAST_SERIAL,
|
|
47
45
|
PYPI_SERIAL_CONSTANT,
|
|
46
|
+
python_content_to_json,
|
|
47
|
+
write_simple_detail,
|
|
48
|
+
write_simple_index,
|
|
48
49
|
)
|
|
49
50
|
|
|
50
|
-
from pulp_python.app import tasks
|
|
51
|
-
|
|
52
51
|
log = logging.getLogger(__name__)
|
|
53
52
|
|
|
54
53
|
ORIGIN_HOST = settings.CONTENT_ORIGIN if settings.CONTENT_ORIGIN else settings.PYPI_API_HOSTNAME
|
|
@@ -159,10 +158,15 @@ class PackageUploadMixin(PyPIMixin):
|
|
|
159
158
|
if settings.PYTHON_GROUP_UPLOADS:
|
|
160
159
|
return self.upload_package_group(repo, artifact, filename, request.session)
|
|
161
160
|
|
|
162
|
-
result = dispatch(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
161
|
+
result = dispatch(
|
|
162
|
+
tasks.upload,
|
|
163
|
+
exclusive_resources=[artifact, repo],
|
|
164
|
+
kwargs={
|
|
165
|
+
"artifact_sha256": artifact.sha256,
|
|
166
|
+
"filename": filename,
|
|
167
|
+
"repository_pk": str(repo.pk),
|
|
168
|
+
},
|
|
169
|
+
)
|
|
166
170
|
return OperationPostponedResponse(result, request)
|
|
167
171
|
|
|
168
172
|
def upload_package_group(self, repo, artifact, filename, session):
|
|
@@ -176,10 +180,10 @@ class PackageUploadMixin(PyPIMixin):
|
|
|
176
180
|
try:
|
|
177
181
|
with transaction.atomic():
|
|
178
182
|
sq.first()
|
|
179
|
-
current_start = datetime.fromisoformat(session[
|
|
183
|
+
current_start = datetime.fromisoformat(session["start"])
|
|
180
184
|
if current_start >= datetime.now(tz=timezone.utc):
|
|
181
|
-
session[
|
|
182
|
-
session[
|
|
185
|
+
session["artifacts"].append((str(artifact.sha256), filename))
|
|
186
|
+
session["start"] = str(start_time)
|
|
183
187
|
session.modified = False
|
|
184
188
|
session.save()
|
|
185
189
|
else:
|
|
@@ -192,14 +196,19 @@ class PackageUploadMixin(PyPIMixin):
|
|
|
192
196
|
|
|
193
197
|
def create_group_upload_task(self, cur_session, repository, artifact, filename, start_time):
|
|
194
198
|
"""Creates the actual task that adds the packages to the index."""
|
|
195
|
-
cur_session[
|
|
196
|
-
cur_session[
|
|
199
|
+
cur_session["start"] = str(start_time)
|
|
200
|
+
cur_session["artifacts"] = [(str(artifact.sha256), filename)]
|
|
197
201
|
cur_session.modified = False
|
|
198
202
|
cur_session.save()
|
|
199
|
-
result = dispatch(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
+
result = dispatch(
|
|
204
|
+
tasks.upload_group,
|
|
205
|
+
exclusive_resources=[artifact, repository],
|
|
206
|
+
kwargs={
|
|
207
|
+
"session_pk": str(cur_session.session_key),
|
|
208
|
+
"repository_pk": str(repository.pk),
|
|
209
|
+
},
|
|
210
|
+
)
|
|
211
|
+
return reverse("tasks-detail", args=[result.pk], request=None)
|
|
203
212
|
|
|
204
213
|
|
|
205
214
|
class SimpleView(PackageUploadMixin, ViewSet):
|
|
@@ -227,21 +236,22 @@ class SimpleView(PackageUploadMixin, ViewSet):
|
|
|
227
236
|
"""Gets the simple api html page for the index."""
|
|
228
237
|
repo_version, content = self.get_rvc()
|
|
229
238
|
if self.should_redirect(repo_version=repo_version):
|
|
230
|
-
return redirect(urljoin(self.base_content_url, f
|
|
231
|
-
names = content.order_by(
|
|
239
|
+
return redirect(urljoin(self.base_content_url, f"{path}/simple/"))
|
|
240
|
+
names = content.order_by("name").values_list("name", flat=True).distinct().iterator()
|
|
232
241
|
return StreamingHttpResponse(write_simple_index(names, streamed=True))
|
|
233
242
|
|
|
234
243
|
def pull_through_package_simple(self, package, path, remote):
|
|
235
244
|
"""Gets the package's simple page from remote."""
|
|
245
|
+
|
|
236
246
|
def parse_url(link):
|
|
237
247
|
parsed = urlparse(link.url)
|
|
238
|
-
digest, _, value = parsed.fragment.partition(
|
|
248
|
+
digest, _, value = parsed.fragment.partition("=")
|
|
239
249
|
stripped_url = urlunsplit(chain(parsed[:3], ("", "")))
|
|
240
|
-
redirect = f
|
|
250
|
+
redirect = f"{path}/{link.text}?redirect={stripped_url}"
|
|
241
251
|
d_url = urljoin(self.base_content_url, redirect)
|
|
242
|
-
return link.text, d_url, value if digest ==
|
|
252
|
+
return link.text, d_url, value if digest == "sha256" else ""
|
|
243
253
|
|
|
244
|
-
url = remote.get_remote_artifact_url(f
|
|
254
|
+
url = remote.get_remote_artifact_url(f"simple/{package}/")
|
|
245
255
|
kwargs = {}
|
|
246
256
|
if proxy_url := remote.proxy_url:
|
|
247
257
|
if remote.proxy_username or remote.proxy_password:
|
|
@@ -265,10 +275,10 @@ class SimpleView(PackageUploadMixin, ViewSet):
|
|
|
265
275
|
if not repo_ver or not content.filter(name__normalize=normalized).exists():
|
|
266
276
|
return self.pull_through_package_simple(normalized, path, self.distribution.remote)
|
|
267
277
|
if self.should_redirect(repo_version=repo_ver):
|
|
268
|
-
return redirect(urljoin(self.base_content_url, f
|
|
278
|
+
return redirect(urljoin(self.base_content_url, f"{path}/simple/{normalized}/"))
|
|
269
279
|
packages = (
|
|
270
280
|
content.filter(name__normalize=normalized)
|
|
271
|
-
.values_list(
|
|
281
|
+
.values_list("filename", "sha256", "name")
|
|
272
282
|
.iterator()
|
|
273
283
|
)
|
|
274
284
|
try:
|
|
@@ -278,12 +288,14 @@ class SimpleView(PackageUploadMixin, ViewSet):
|
|
|
278
288
|
else:
|
|
279
289
|
packages = chain([present], packages)
|
|
280
290
|
name = present[2]
|
|
281
|
-
releases = ((f, urljoin(self.base_content_url, f
|
|
291
|
+
releases = ((f, urljoin(self.base_content_url, f"{path}/{f}"), d) for f, d, _ in packages)
|
|
282
292
|
return StreamingHttpResponse(write_simple_detail(name, releases, streamed=True))
|
|
283
293
|
|
|
284
|
-
@extend_schema(
|
|
285
|
-
|
|
286
|
-
|
|
294
|
+
@extend_schema(
|
|
295
|
+
request=PackageUploadSerializer,
|
|
296
|
+
responses={200: PackageUploadTaskSerializer},
|
|
297
|
+
summary="Upload a package",
|
|
298
|
+
)
|
|
287
299
|
def create(self, request, path):
|
|
288
300
|
"""
|
|
289
301
|
Upload package to the index.
|
|
@@ -308,9 +320,11 @@ class MetadataView(PyPIMixin, ViewSet):
|
|
|
308
320
|
],
|
|
309
321
|
}
|
|
310
322
|
|
|
311
|
-
@extend_schema(
|
|
312
|
-
|
|
313
|
-
|
|
323
|
+
@extend_schema(
|
|
324
|
+
tags=["Pypi: Metadata"],
|
|
325
|
+
responses={200: PackageMetadataSerializer},
|
|
326
|
+
summary="Get package metadata",
|
|
327
|
+
)
|
|
314
328
|
def retrieve(self, request, path, meta):
|
|
315
329
|
"""
|
|
316
330
|
Retrieves the package's core-metadata specified by
|
|
@@ -356,8 +370,7 @@ class PyPIView(PyPIMixin, ViewSet):
|
|
|
356
370
|
],
|
|
357
371
|
}
|
|
358
372
|
|
|
359
|
-
@extend_schema(responses={200: SummarySerializer},
|
|
360
|
-
summary="Get index summary")
|
|
373
|
+
@extend_schema(responses={200: SummarySerializer}, summary="Get index summary")
|
|
361
374
|
def retrieve(self, request, path):
|
|
362
375
|
"""Gets package summary stats of index."""
|
|
363
376
|
repo_ver, content = self.get_rvc()
|
|
@@ -383,9 +396,11 @@ class UploadView(PackageUploadMixin, ViewSet):
|
|
|
383
396
|
],
|
|
384
397
|
}
|
|
385
398
|
|
|
386
|
-
@extend_schema(
|
|
387
|
-
|
|
388
|
-
|
|
399
|
+
@extend_schema(
|
|
400
|
+
request=PackageUploadSerializer,
|
|
401
|
+
responses={200: PackageUploadTaskSerializer},
|
|
402
|
+
summary="Upload a package",
|
|
403
|
+
)
|
|
389
404
|
def create(self, request, path):
|
|
390
405
|
"""
|
|
391
406
|
Upload package to the index.
|
pulp_python/app/replica.py
CHANGED
|
@@ -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
|
|
|
@@ -31,7 +32,8 @@ class PythonReplicator(Replicator):
|
|
|
31
32
|
def url(self, upstream_distribution):
|
|
32
33
|
# Ignore distributions that are only pull-through
|
|
33
34
|
repo, pub = upstream_distribution["repository"], upstream_distribution["publication"]
|
|
34
|
-
|
|
35
|
+
repo_ver = upstream_distribution.get("repository_version")
|
|
36
|
+
if repo or pub or repo_ver:
|
|
35
37
|
return super().url(upstream_distribution)
|
|
36
38
|
|
|
37
39
|
return None
|