pulp-python 3.30.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.
- pulp_python/app/__init__.py +1 -1
- pulp_python/app/pypi/views.py +17 -4
- pulp_python/app/utils.py +16 -4
- pulp_python/tests/functional/api/test_pypi_apis.py +43 -0
- pulp_python/tests/functional/api/test_pypi_simple_api.py +3 -4
- pulp_python/tests/functional/constants.py +4 -0
- {pulp_python-3.30.0.dist-info → pulp_python-3.30.1.dist-info}/METADATA +1 -1
- {pulp_python-3.30.0.dist-info → pulp_python-3.30.1.dist-info}/RECORD +12 -12
- {pulp_python-3.30.0.dist-info → pulp_python-3.30.1.dist-info}/WHEEL +0 -0
- {pulp_python-3.30.0.dist-info → pulp_python-3.30.1.dist-info}/entry_points.txt +0 -0
- {pulp_python-3.30.0.dist-info → pulp_python-3.30.1.dist-info}/licenses/LICENSE +0 -0
- {pulp_python-3.30.0.dist-info → pulp_python-3.30.1.dist-info}/top_level.txt +0 -0
pulp_python/app/__init__.py
CHANGED
pulp_python/app/pypi/views.py
CHANGED
|
@@ -7,6 +7,7 @@ from urllib.parse import urljoin, urlparse, urlunsplit
|
|
|
7
7
|
from django.contrib.sessions.models import Session
|
|
8
8
|
from django.core.exceptions import ObjectDoesNotExist
|
|
9
9
|
from django.db import transaction
|
|
10
|
+
from django.db.models import OuterRef, Subquery
|
|
10
11
|
from django.db.utils import DatabaseError
|
|
11
12
|
from django.http.response import (
|
|
12
13
|
Http404,
|
|
@@ -25,6 +26,7 @@ from rest_framework.renderers import BrowsableAPIRenderer, JSONRenderer, Templat
|
|
|
25
26
|
from rest_framework.response import Response
|
|
26
27
|
from rest_framework.viewsets import ViewSet
|
|
27
28
|
|
|
29
|
+
from pulpcore.plugin.models import RepositoryContent
|
|
28
30
|
from pulpcore.plugin.tasking import dispatch
|
|
29
31
|
from pulpcore.plugin.util import get_domain, get_url
|
|
30
32
|
from pulpcore.plugin.viewsets import OperationPostponedResponse
|
|
@@ -366,13 +368,20 @@ class SimpleView(PackageUploadMixin, ViewSet):
|
|
|
366
368
|
return redirect(urljoin(self.base_content_url, f"{path}/simple/{normalized}/"))
|
|
367
369
|
if content is not None:
|
|
368
370
|
local_packages = content.filter(name_normalized=normalized)
|
|
369
|
-
|
|
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(
|
|
370
379
|
"filename",
|
|
371
380
|
"sha256",
|
|
372
381
|
"metadata_sha256",
|
|
373
382
|
"requires_python",
|
|
374
383
|
"size",
|
|
375
|
-
"
|
|
384
|
+
"repo_added_time",
|
|
376
385
|
"version",
|
|
377
386
|
)
|
|
378
387
|
provenances = PackageProvenance.objects.filter(package__in=local_packages).values_list(
|
|
@@ -382,7 +391,7 @@ class SimpleView(PackageUploadMixin, ViewSet):
|
|
|
382
391
|
p["filename"]: {
|
|
383
392
|
**p,
|
|
384
393
|
"url": urljoin(self.base_content_url, f"{path}/{p['filename']}"),
|
|
385
|
-
"upload_time": p["
|
|
394
|
+
"upload_time": p["repo_added_time"],
|
|
386
395
|
"provenance": (
|
|
387
396
|
self.get_provenance_url(normalized, p["version"], p["filename"])
|
|
388
397
|
if p["filename"] in provenances
|
|
@@ -464,7 +473,11 @@ class MetadataView(PyPIMixin, ViewSet):
|
|
|
464
473
|
if settings.DOMAIN_ENABLED:
|
|
465
474
|
domain = get_domain()
|
|
466
475
|
json_body = python_content_to_json(
|
|
467
|
-
path,
|
|
476
|
+
path,
|
|
477
|
+
package_content,
|
|
478
|
+
version=version,
|
|
479
|
+
domain=domain,
|
|
480
|
+
repository_version=repo_ver,
|
|
468
481
|
)
|
|
469
482
|
if json_body:
|
|
470
483
|
return Response(data=json_body, headers=headers)
|
pulp_python/app/utils.py
CHANGED
|
@@ -11,6 +11,7 @@ from datetime import timezone
|
|
|
11
11
|
import pkginfo
|
|
12
12
|
from aiohttp.client_exceptions import ClientError
|
|
13
13
|
from django.conf import settings
|
|
14
|
+
from django.db.models import OuterRef, Subquery
|
|
14
15
|
from django.db.utils import IntegrityError
|
|
15
16
|
from jinja2 import Template
|
|
16
17
|
from packaging.requirements import Requirement
|
|
@@ -19,7 +20,7 @@ from packaging.version import InvalidVersion, parse
|
|
|
19
20
|
from pypi_simple import ACCEPT_JSON_PREFERRED, ProjectPage
|
|
20
21
|
|
|
21
22
|
from pulpcore.plugin.exceptions import TimeoutException
|
|
22
|
-
from pulpcore.plugin.models import Artifact, Remote
|
|
23
|
+
from pulpcore.plugin.models import Artifact, Remote, RepositoryContent
|
|
23
24
|
from pulpcore.plugin.util import get_domain
|
|
24
25
|
|
|
25
26
|
log = logging.getLogger(__name__)
|
|
@@ -359,7 +360,9 @@ def fetch_json_release_metadata(name: str, version: str, remotes: set[Remote]) -
|
|
|
359
360
|
raise Exception(f"Failed to fetch {url} from any remote.")
|
|
360
361
|
|
|
361
362
|
|
|
362
|
-
def python_content_to_json(
|
|
363
|
+
def python_content_to_json(
|
|
364
|
+
base_path, content_query, version=None, domain=None, repository_version=None
|
|
365
|
+
):
|
|
363
366
|
"""
|
|
364
367
|
Converts a QuerySet of PythonPackageContent into the PyPi JSON format
|
|
365
368
|
https://www.python.org/dev/peps/pep-0566/
|
|
@@ -371,6 +374,13 @@ def python_content_to_json(base_path, content_query, version=None, domain=None):
|
|
|
371
374
|
|
|
372
375
|
Returns None if version is specified but not found within content_query
|
|
373
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))
|
|
374
384
|
full_metadata = {"last_serial": 0} # For now the serial field isn't supported by Pulp
|
|
375
385
|
latest_content = latest_content_version(content_query, version)
|
|
376
386
|
if not latest_content:
|
|
@@ -515,8 +525,10 @@ def python_content_to_download_info(content, base_path, domain=None):
|
|
|
515
525
|
"python_version": content.python_version,
|
|
516
526
|
"requires_python": content.requires_python or None,
|
|
517
527
|
"size": content.size,
|
|
518
|
-
"upload_time": str(content.pulp_created),
|
|
519
|
-
"upload_time_iso_8601": str(
|
|
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
|
+
),
|
|
520
532
|
"url": url,
|
|
521
533
|
"yanked": False,
|
|
522
534
|
"yanked_reason": None,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import subprocess
|
|
2
|
+
import time
|
|
3
|
+
from datetime import datetime
|
|
2
4
|
from urllib.parse import urljoin
|
|
3
5
|
|
|
4
6
|
import pytest
|
|
@@ -6,6 +8,7 @@ import requests
|
|
|
6
8
|
|
|
7
9
|
from pulp_python.tests.functional.constants import (
|
|
8
10
|
PYPI_SERIAL_CONSTANT,
|
|
11
|
+
PYPI_SIMPLE_V1_JSON,
|
|
9
12
|
PYTHON_EGG_FILENAME,
|
|
10
13
|
PYTHON_EGG_SHA256,
|
|
11
14
|
PYTHON_MD_PROJECT_SPECIFIER,
|
|
@@ -13,6 +16,8 @@ from pulp_python.tests.functional.constants import (
|
|
|
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(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
pulp_python/__init__.py,sha256=GIuTLoBTc-07dSLJUh8xrZPRz8x-jJ61pfR0J1IjnzI,65
|
|
2
2
|
pulp_python/pytest_plugin.py,sha256=LNnLjOkeEu2X4gJi614bHVmbsHyEwooHYIeecr96Qy4,8606
|
|
3
|
-
pulp_python/app/__init__.py,sha256=
|
|
3
|
+
pulp_python/app/__init__.py,sha256=kvIZAie_YepDZxtZCUo9YVSjAZXhIjWL7sq7aSI88L8,2490
|
|
4
4
|
pulp_python/app/global_access_conditions.py,sha256=MZJtyoVsr-4hRaty6mKDqh3caOHd5UKJjEWLV2crOLs,1080
|
|
5
5
|
pulp_python/app/modelresource.py,sha256=4SFAdqk6lozi_cZz4uqDIqhqPAZF-7l5jJwPn-xGZFs,1249
|
|
6
6
|
pulp_python/app/models.py,sha256=Y7MDTl2nKz1dz2S4KQIQQ4oWcYgBA4TyDVxJGBYPHY4,17705
|
|
@@ -9,7 +9,7 @@ pulp_python/app/replica.py,sha256=qiWRP7tM_v4yP_XLIQfumfGolru-Jt6ZA0KVb-9g2cA,18
|
|
|
9
9
|
pulp_python/app/serializers.py,sha256=Wg83g7LE9Qkf1S7hkkvG2_EJUi7D12l8UyCA1wmwf-I,33819
|
|
10
10
|
pulp_python/app/settings.py,sha256=Cyc_p6U0HQjKpyrRL6JFrK3R7RMQJ9MAgNMJCfzPEiA,255
|
|
11
11
|
pulp_python/app/urls.py,sha256=M2xjQ0j47BwQVpi75QCa5eUnQDcroKv3Cee7UrQ3QcA,1387
|
|
12
|
-
pulp_python/app/utils.py,sha256=
|
|
12
|
+
pulp_python/app/utils.py,sha256=f9sCzZ58Sf7EBNqzBG0NBGtWE6gE2eIcnoSTAhdVIIg,27303
|
|
13
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
|
|
@@ -40,7 +40,7 @@ pulp_python/app/migrations/0022_pythonblocklistentry.py,sha256=EbtjZuN65myTAHVWr
|
|
|
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
42
|
pulp_python/app/pypi/serializers.py,sha256=rE0Cci2IMg4NbNWlVdo-8zPaJCAUq2Re57q_T3jMt0Y,5030
|
|
43
|
-
pulp_python/app/pypi/views.py,sha256=
|
|
43
|
+
pulp_python/app/pypi/views.py,sha256=D2lsHijKp3ZJemt-iwWxjJEin5rAkc0pZzi9kZyQgwk,21651
|
|
44
44
|
pulp_python/app/tasks/__init__.py,sha256=lTFpVvpDKbqv9RC0b2RYU8Bo6svDjrA-djt16pADFr8,284
|
|
45
45
|
pulp_python/app/tasks/publish.py,sha256=bjsJzqJbLu7TF5rLb-UsZMmlNnc_LKw-sdHX9Gcatbw,4334
|
|
46
46
|
pulp_python/app/tasks/repair.py,sha256=5InzdbjW8y3AC4Vj2PsNLm3wGGTr8D3LcfPw_WA2Fks,12257
|
|
@@ -52,7 +52,7 @@ pulp_python/app/webserver_snippets/apache.conf,sha256=3frHSl2YV_8pJPscaFxMVo7Hmx
|
|
|
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=
|
|
55
|
+
pulp_python/tests/functional/constants.py,sha256=4e_zssE9G1bSNNJxYo7VgwvojUL_NocG5mUH996KBJs,13969
|
|
56
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
58
|
pulp_python/tests/functional/api/test_attestations.py,sha256=cyZl4jCL-Q5Qu7XpxLc5_YmCzyc1Ctfl1IvSJ6YPQQU,8640
|
|
@@ -66,8 +66,8 @@ pulp_python/tests/functional/api/test_domains.py,sha256=BnWBwid_RA0xenBBHwvkT5_2
|
|
|
66
66
|
pulp_python/tests/functional/api/test_download_content.py,sha256=5IuaHXyLakPkjm5sLTxtTl7Dq0yl7N36HpObnIa0Sks,4950
|
|
67
67
|
pulp_python/tests/functional/api/test_export_import.py,sha256=rHns9wdaeP-vtfW_qoGHU9EVuJ4YuWE0-rjl_8otAgU,4530
|
|
68
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=
|
|
70
|
-
pulp_python/tests/functional/api/test_pypi_simple_api.py,sha256=
|
|
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
71
|
pulp_python/tests/functional/api/test_rbac.py,sha256=-xNWqvKKU-v1uC6tCRGBK0aWaff25K9C-AfzQkdHhhI,10513
|
|
72
72
|
pulp_python/tests/functional/api/test_repair.py,sha256=4FR7jx_LA2K-pnRJXKkhq-1uUoWXST1leZ9XdyhGM2U,12909
|
|
73
73
|
pulp_python/tests/functional/api/test_sync.py,sha256=TTHR1CpZeRoD97RKxj2pZPsP0OS9ibYKGPOh1WfKISg,13801
|
|
@@ -77,9 +77,9 @@ pulp_python/tests/functional/assets/shelf-reader-0.1.tar.gz.publish.attestation,
|
|
|
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.30.
|
|
81
|
-
pulp_python-3.30.
|
|
82
|
-
pulp_python-3.30.
|
|
83
|
-
pulp_python-3.30.
|
|
84
|
-
pulp_python-3.30.
|
|
85
|
-
pulp_python-3.30.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|