Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update pkginfo library to support newer python packages #683

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES/689.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support Python package metadata version 2.3
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.10 on 2024-07-08 00:47

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('python', '0013_add_rbac_permissions'),
]

operations = [
migrations.AddField(
model_name='pythonpackagecontent',
name='dynamic',
field=models.JSONField(null=True),
),
migrations.AddField(
model_name='pythonpackagecontent',
name='provides_extra',
field=models.JSONField(null=True),
),
]
8 changes: 8 additions & 0 deletions pulp_python/app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ class PythonPackageContent(Content):

PROTECTED_FROM_RECLAIM = False

# TODO: it appears we've set the default (usually empty-string) for each of these fields
# manually in the migrations rather than setting them declaratively. That's not ideal.
# At some point we should add proper default values and probably make some fields nullable.

TYPE = "python"
repo_key_fields = ("filename",)
# Required metadata
Expand Down Expand Up @@ -177,7 +181,11 @@ class PythonPackageContent(Content):
requires_external = models.JSONField(default=list)
classifiers = models.JSONField(default=list)
project_urls = models.JSONField(default=dict)
# Metadata 2.1
description_content_type = models.TextField()
provides_extra = models.JSONField(default=list, null=True)
# Metadata 2.2
dynamic = models.JSONField(default=list, null=True)
# Pulp Domains
_pulp_domain = models.ForeignKey("core.Domain", default=get_domain_pk, on_delete=models.PROTECT)

Expand Down
31 changes: 22 additions & 9 deletions pulp_python/app/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,6 @@ class PythonPackageContentSerializer(core_serializers.SingleArtifactContentUploa
required=False, allow_blank=True,
help_text=_('A longer description of the package that can run to several paragraphs.')
)
description_content_type = serializers.CharField(
required=False, allow_blank=True,
help_text=_('A string stating the markup syntax (if any) used in the distribution’s'
' description, so that tools can intelligently render the description.')
)
keywords = serializers.CharField(
required=False, allow_blank=True,
help_text=_('Additional keywords to be used to assist searching for the '
Expand Down Expand Up @@ -195,6 +190,23 @@ class PythonPackageContentSerializer(core_serializers.SingleArtifactContentUploa
required=False, default=list,
help_text=_('A JSON list containing classification values for a Python package.')
)
# Metadata 2.1
description_content_type = serializers.CharField(
required=False, allow_blank=True,
help_text=_('A string stating the markup syntax (if any) used in the distribution’s'
' description, so that tools can intelligently render the description.')
)
provides_extra = serializers.JSONField(
required=False, default=list,
help_text=_('A JSON list containing names of optional features provided by the package.')
)
# Metadata 2.2
dynamic = serializers.JSONField(
required=False, default=list,
help_text=_('A JSON list containing names of other core metadata fields which are '
'permitted to vary between sdist and bdist packages. Fields NOT marked '
'dynamic MUST be the same between bdist and sdist.')
)

def deferred_validate(self, data):
"""
Expand Down Expand Up @@ -251,10 +263,11 @@ def retrieve(self, validated_data):
class Meta:
fields = core_serializers.SingleArtifactContentUploadSerializer.Meta.fields + (
'filename', 'packagetype', 'name', 'version', 'sha256', 'metadata_version', 'summary',
'description', 'description_content_type', 'keywords', 'home_page', 'download_url',
'author', 'author_email', 'maintainer', 'maintainer_email', 'license',
'requires_python', 'project_url', 'project_urls', 'platform', 'supported_platform',
'requires_dist', 'provides_dist', 'obsoletes_dist', 'requires_external', 'classifiers'
'description', 'keywords', 'home_page', 'download_url', 'author', 'author_email',
'maintainer', 'maintainer_email', 'license', 'requires_python', 'project_url',
'project_urls', 'platform', 'supported_platform', 'requires_dist', 'provides_dist',
'obsoletes_dist', 'requires_external', 'classifiers', 'description_content_type',
'provides_extra', 'dynamic',
)
model = python_models.PythonPackageContent

Expand Down
7 changes: 5 additions & 2 deletions pulp_python/app/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,9 @@ def parse_project_metadata(project):
package['obsoletes_dist'] = json.dumps(project.get('obsoletes_dist', []))
package['requires_external'] = json.dumps(project.get('requires_external', []))
package['classifiers'] = json.dumps(project.get('classifiers', []))
package['project_urls'] = json.dumps(project.get('project_urls', {}))
package['description_content_type'] = project.get('description_content_type') or ""
package['provides_extra'] = project.get('provides_extra', None)
package['dynamic'] = project.get('dynamic', None)

return package

Expand Down Expand Up @@ -219,7 +220,6 @@ def python_content_to_info(content):
"summary": content.summary or "",
"keywords": content.keywords or "",
"description": content.description or "",
"description_content_type": content.description_content_type or "",
"bugtrack_url": None, # These two are basically never used
"docs_url": None,
"downloads": {"last_day": -1, "last_month": -1, "last_week": -1},
Expand All @@ -240,6 +240,9 @@ def python_content_to_info(content):
"classifiers": json_to_dict(content.classifiers) or None,
"yanked": False, # These are no longer used on PyPI, but are still present
"yanked_reason": None,
"description_content_type": content.description_content_type or "",
"provides_extra": content.provides_extra,
"dynamic": content.dynamic,
}


Expand Down
Loading