|
7 | 7 | import json |
8 | 8 | from collections import defaultdict |
9 | 9 | from django.conf import settings |
| 10 | +from django.utils import timezone |
10 | 11 | from jinja2 import Template |
11 | 12 | from packaging.utils import canonicalize_name |
12 | 13 | from packaging.requirements import Requirement |
|
18 | 19 | """TODO This serial constant is temporary until Python repositories implements serials""" |
19 | 20 | PYPI_SERIAL_CONSTANT = 1000000000 |
20 | 21 |
|
21 | | -SIMPLE_API_VERSION = "1.0" |
| 22 | +SIMPLE_API_VERSION = "1.1" |
22 | 23 |
|
23 | 24 | simple_index_template = """<!DOCTYPE html> |
24 | 25 | <html> |
@@ -161,6 +162,7 @@ def parse_metadata(project, version, distribution): |
161 | 162 | package["sha256"] = distribution.get("digests", {}).get("sha256") or "" |
162 | 163 | package["python_version"] = distribution.get("python_version") or "" |
163 | 164 | package["requires_python"] = distribution.get("requires_python") or "" |
| 165 | + package["size"] = distribution.get("size") or 0 |
164 | 166 |
|
165 | 167 | return package |
166 | 168 |
|
@@ -223,6 +225,7 @@ def artifact_to_python_content_data(filename, artifact, domain=None): |
223 | 225 | metadata = get_project_metadata_from_file(temp_file.name) |
224 | 226 | data = parse_project_metadata(vars(metadata)) |
225 | 227 | data["sha256"] = artifact.sha256 |
| 228 | + data["size"] = artifact.size |
226 | 229 | data["filename"] = filename |
227 | 230 | data["pulp_domain"] = domain or artifact.pulp_domain |
228 | 231 | data["_pulp_domain"] = data["pulp_domain"] |
@@ -403,7 +406,7 @@ def find_artifact(): |
403 | 406 | components.insert(2, domain.name) |
404 | 407 | url = "/".join(components) |
405 | 408 | md5 = artifact.md5 if artifact and artifact.md5 else "" |
406 | | - size = artifact.size if artifact and artifact.size else 0 |
| 409 | + size = content.size or 0 |
407 | 410 | return { |
408 | 411 | "comment_text": "", |
409 | 412 | "digests": {"md5": md5, "sha256": content.sha256}, |
@@ -471,20 +474,32 @@ def write_simple_detail_json(project_name, project_packages): |
471 | 474 | {"sha256": package["metadata_sha256"]} if package["metadata_sha256"] else False |
472 | 475 | ), |
473 | 476 | # yanked and yanked_reason are not implemented because they are mutable |
| 477 | + # (v1.1, PEP 700) |
| 478 | + "size": package["size"], |
| 479 | + "upload-time": format_upload_time(package["upload_time"]), |
474 | 480 | # TODO in the future: |
475 | | - # size, upload-time (v1.1, PEP 700) |
476 | 481 | # core-metadata (PEP 7.14) |
477 | 482 | # provenance (v1.3, PEP 740) |
478 | 483 | } |
479 | 484 | for package in project_packages |
480 | 485 | ], |
| 486 | + # (v1.1, PEP 700) |
| 487 | + "versions": set(package["version"] for package in project_packages), |
481 | 488 | # TODO in the future: |
482 | | - # versions (v1.1, PEP 700) |
483 | 489 | # alternate-locations (v1.2, PEP 708) |
484 | 490 | # project-status (v1.4, PEP 792 - pypi and docs differ) |
485 | 491 | } |
486 | 492 |
|
487 | 493 |
|
| 494 | +def format_upload_time(upload_time): |
| 495 | + """Formats the upload time to be in Zulu time. UTC with Z suffix""" |
| 496 | + if upload_time: |
| 497 | + if upload_time.tzinfo: |
| 498 | + dt = upload_time.astimezone(timezone.utc) |
| 499 | + return dt.isoformat().replace("+00:00", "Z") |
| 500 | + return None |
| 501 | + |
| 502 | + |
488 | 503 | class PackageIncludeFilter: |
489 | 504 | """A special class to help filter Package's based on a remote's include/exclude""" |
490 | 505 |
|
|
0 commit comments