Skip to content

Commit

Permalink
Declare compatibility with pulpcore 3.70
Browse files Browse the repository at this point in the history
  • Loading branch information
gerrod3 committed Feb 5, 2025
1 parent 86f5710 commit c1a84bb
Show file tree
Hide file tree
Showing 12 changed files with 66 additions and 73 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ minio_access_key: "'$MINIO_ACCESS_KEY'"\
minio_secret_key: "'$MINIO_SECRET_KEY'"\
pulp_scenario_settings: {"domain_enabled": true}\
pulp_scenario_env: {}\
test_storages_compat_layer: false\
test_storages_compat_layer: true\
' vars/main.yaml
export PULP_API_ROOT="/rerouted/djnd/"
fi
Expand Down
1 change: 1 addition & 0 deletions CHANGES/+pulpcore-3.70.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added pulpcore 3.70 compatibility
12 changes: 0 additions & 12 deletions pulp_python/app/fields.py

This file was deleted.

7 changes: 3 additions & 4 deletions pulp_python/app/pypi/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

from rest_framework import serializers
from pulp_python.app.utils import DIST_EXTENSIONS
from pulp_python.app import fields
from pulpcore.plugin.models import Artifact
from pulpcore.plugin.util import get_domain
from django.db.utils import IntegrityError
Expand All @@ -29,9 +28,9 @@ class PackageMetadataSerializer(serializers.Serializer):
"""

last_serial = serializers.IntegerField(help_text=_("Cache value from last PyPI sync"))
info = fields.JSONObjectField(help_text=_("Core metadata of the package"))
releases = fields.JSONObjectField(help_text=_("List of all the releases of the package"))
urls = fields.JSONObjectField()
info = serializers.JSONField(help_text=_("Core metadata of the package"))
releases = serializers.JSONField(help_text=_("List of all the releases of the package"))
urls = serializers.JSONField()


class PackageUploadSerializer(serializers.Serializer):
Expand Down
13 changes: 6 additions & 7 deletions pulp_python/app/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from pulpcore.plugin.util import get_domain

from pulp_python.app import models as python_models
from pulp_python.app import fields
from pulp_python.app.utils import artifact_to_python_content_data


Expand Down Expand Up @@ -158,7 +157,7 @@ class PythonPackageContentSerializer(core_serializers.SingleArtifactContentUploa
required=False, allow_blank=True,
help_text=_('A browsable URL for the project and a label for it, separated by a comma.')
)
project_urls = fields.JSONObjectField(
project_urls = serializers.JSONField(
required=False, default=dict,
help_text=_('A dictionary of labels and URLs for the project.')
)
Expand All @@ -171,28 +170,28 @@ class PythonPackageContentSerializer(core_serializers.SingleArtifactContentUploa
required=False, allow_blank=True,
help_text=_('Field to specify the OS and CPU for which the binary package was compiled. ')
)
requires_dist = fields.JSONObjectField(
requires_dist = serializers.JSONField(
required=False, default=list,
help_text=_('A JSON list containing names of some other distutils project '
'required by this distribution.')
)
provides_dist = fields.JSONObjectField(
provides_dist = serializers.JSONField(
required=False, default=list,
help_text=_('A JSON list containing names of a Distutils project which is contained'
' within this distribution.')
)
obsoletes_dist = fields.JSONObjectField(
obsoletes_dist = serializers.JSONField(
required=False, default=list,
help_text=_('A JSON list containing names of a distutils project\'s distribution which '
'this distribution renders obsolete, meaning that the two projects should not '
'be installed at the same time.')
)
requires_external = fields.JSONObjectField(
requires_external = serializers.JSONField(
required=False, default=list,
help_text=_('A JSON list containing some dependency in the system that the distribution '
'is to be used.')
)
classifiers = fields.JSONObjectField(
classifiers = serializers.JSONField(
required=False, default=list,
help_text=_('A JSON list containing classification values for a Python package.')
)
Expand Down
2 changes: 1 addition & 1 deletion pulp_python/pytest_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def _download_python_file(relative_path, url):
file_path = tmp_path / relative_path
with open(file_path, mode="wb") as f:
f.write(http_get(url))
return file_path
return str(file_path)

yield _download_python_file

Expand Down
30 changes: 15 additions & 15 deletions pulp_python/tests/functional/api/test_crud_content_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,23 @@ def test_content_crud(
content_body = {"relative_path": PYTHON_EGG_FILENAME, "artifact": artifact.pulp_href}
response = python_bindings.ContentPackagesApi.create(**content_body)
task = monitor_task(response.task)
content = python_bindings.ContentPackagesApi.read(task.created_resources[0]).to_dict()
content = python_bindings.ContentPackagesApi.read(task.created_resources[0])
for k, v in PYTHON_PACKAGE_DATA.items():
assert content[k] == v
assert getattr(content, k) == v

# Test read
result = python_bindings.ContentPackagesApi.list(filename=content["filename"])
result = python_bindings.ContentPackagesApi.list(filename=content.filename)
assert result.count == 1
assert result.results[0].to_dict() == content
assert result.results[0] == content

# Test partial update
with pytest.raises(AttributeError) as e:
python_bindings.ContentPackagesApi.partial_update(content["pulp_href"], {"filename": "te"})
python_bindings.ContentPackagesApi.partial_update(content.pulp_href, {"filename": "te"})
assert "object has no attribute 'partial_update'" in e.value.args[0]

# Test delete
with pytest.raises(AttributeError) as e:
python_bindings.ContentPackagesApi.delete(content["pulp_href"])
python_bindings.ContentPackagesApi.delete(content.pulp_href)
assert "object has no attribute 'delete'" in e.value.args[0]

monitor_task(pulpcore_bindings.OrphansCleanupApi.cleanup({"orphan_protection_time": 0}).task)
Expand All @@ -51,9 +51,9 @@ def test_content_crud(
content_body = {"relative_path": PYTHON_EGG_FILENAME, "file": python_file}
response = python_bindings.ContentPackagesApi.create(**content_body)
task = monitor_task(response.task)
content = python_bindings.ContentPackagesApi.read(task.created_resources[0]).to_dict()
content = python_bindings.ContentPackagesApi.read(task.created_resources[0])
for k, v in PYTHON_PACKAGE_DATA.items():
assert content[k] == v
assert getattr(content, k) == v

monitor_task(pulpcore_bindings.OrphansCleanupApi.cleanup({"orphan_protection_time": 0}).task)

Expand All @@ -65,36 +65,36 @@ def test_content_crud(
content_search = python_bindings.ContentPackagesApi.list(
repository_version_added=task.created_resources[0]
)
content = python_bindings.ContentPackagesApi.read(content_search.results[0].pulp_href).to_dict()
content = python_bindings.ContentPackagesApi.read(content_search.results[0].pulp_href)
for k, v in PYTHON_PACKAGE_DATA.items():
assert content[k] == v
assert getattr(content, k) == v

# Test duplicate upload
content_body = {"relative_path": PYTHON_EGG_FILENAME, "file": python_file}
response = python_bindings.ContentPackagesApi.create(**content_body)
task = monitor_task(response.task)
assert task.created_resources[0] == content["pulp_href"]
assert task.created_resources[0] == content.pulp_href

# Test upload same filename w/ different artifact
second_python_url = urljoin(urljoin(PYTHON_FIXTURES_URL, "packages/"), "aiohttp-3.3.0.tar.gz")
second_python_file = download_python_file("aiohttp-3.3.0.tar.gz", second_python_url)
content_body = {"relative_path": PYTHON_EGG_FILENAME, "file": second_python_file}
response = python_bindings.ContentPackagesApi.create(**content_body)
task = monitor_task(response.task)
content2 = python_bindings.ContentPackagesApi.read(task.created_resources[0]).to_dict()
assert content2["pulp_href"] != content["pulp_href"]
content2 = python_bindings.ContentPackagesApi.read(task.created_resources[0])
assert content2.pulp_href != content.pulp_href

# Test upload same filename w/ different artifacts in same repo
# repo already has EGG_FILENAME w/ EGG_ARTIFACT, not upload EGG_FILENAME w/ AIO_ARTIFACT
# and see that repo will only have the second content unit inside after upload
response = python_bindings.ContentPackagesApi.create(repository=repo.pulp_href, **content_body)
task = monitor_task(response.task)
assert len(task.created_resources) == 2
assert content2["pulp_href"] in task.created_resources
assert content2.pulp_href in task.created_resources
repo_ver2 = task.created_resources[0]
content_list = python_bindings.ContentPackagesApi.list(repository_version=repo_ver2)
assert content_list.count == 1
assert content_list.results[0].pulp_href == content2["pulp_href"]
assert content_list.results[0].pulp_href == content2.pulp_href

# Test upload w/ mismatched sha256
# If we don't perform orphan cleanup here, the upload will fail with a different error :hmm:
Expand Down
35 changes: 21 additions & 14 deletions pulp_python/tests/functional/api/test_crud_remotes.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@
@pytest.mark.parametrize("kwargs", [{}, {"policy": "on_demand"}])
def test_remote_from_bandersnatch_config(kwargs, python_bindings, add_to_cleanup, tmp_path):
"""Verify whether it's possible to create a remote from a Bandersnatch config."""
filename = tmp_path / "bandersnatch.conf"
filename = str(tmp_path / "bandersnatch.conf")
with open(filename, mode="wb") as config:
config.write(BANDERSNATCH_CONF)
config.flush()
name = str(uuid.uuid4())
remote = python_bindings.RemotesPythonApi.from_bandersnatch(filename, name, **kwargs).to_dict()
add_to_cleanup(python_bindings.RemotesPythonApi, remote["pulp_href"])
remote = python_bindings.RemotesPythonApi.from_bandersnatch(filename, name, **kwargs)
add_to_cleanup(python_bindings.RemotesPythonApi, remote.pulp_href)
expected = _gen_expected_remote_body(name, **kwargs)
for key, val in expected.items():
assert remote[key] == val
assert getattr(remote, key) == val


@pytest.mark.parallel
Expand All @@ -40,16 +40,18 @@ def test_remote_default_policy(python_bindings, gen_object_with_cleanup, monitor


@pytest.mark.parallel
def test_remote_invalid_project_specifier(python_bindings):
def test_remote_invalid_project_specifier(python_bindings, has_pulp_plugin):
"""Test that creating a remote with an invalid project specifier fails."""
# Test an include specifier without a "name" field.
body = {
"name": str(uuid.uuid4()),
"url": "https://test",
"includes": PYTHON_INVALID_SPECIFIER_NO_NAME,
}
with pytest.raises(python_bindings.ApiException):
python_bindings.RemotesPythonApi.create(body)
# Pydantic addition to bindings in 3.70 prevent this test from working
if has_pulp_plugin("core", max="3.70"):
with pytest.raises(python_bindings.ApiException):
python_bindings.RemotesPythonApi.create(body)

# Test an include specifier with an invalid "version_specifier" field value.
body["includes"] = PYTHON_INVALID_SPECIFIER_BAD_VERSION
Expand All @@ -59,8 +61,9 @@ def test_remote_invalid_project_specifier(python_bindings):
# Test an exclude specifier without a "name" field.
body.pop("includes")
body["excludes"] = PYTHON_INVALID_SPECIFIER_NO_NAME
with pytest.raises(python_bindings.ApiException):
python_bindings.RemotesPythonApi.create(body)
if has_pulp_plugin("core", max="3.70"):
with pytest.raises(python_bindings.ApiException):
python_bindings.RemotesPythonApi.create(body)

# Test an exclude specifier with an invalid "version_specifier" field value.
body["excludes"] = PYTHON_INVALID_SPECIFIER_BAD_VERSION
Expand Down Expand Up @@ -95,14 +98,17 @@ def test_remote_version_specifier(python_bindings, add_to_cleanup):


@pytest.mark.parallel
def test_remote_update_invalid_project_specifier(python_bindings, python_remote_factory):
def test_remote_update_invalid_project_specifier(
python_bindings, python_remote_factory, has_pulp_plugin
):
"""Test that updating a remote with an invalid project specifier fails non-destructively."""
remote = python_remote_factory()

# Test an include specifier without a "name" field.
body = {"includes": PYTHON_INVALID_SPECIFIER_NO_NAME}
with pytest.raises(python_bindings.ApiException):
python_bindings.RemotesPythonApi.partial_update(remote.pulp_href, body)
if has_pulp_plugin("core", max="3.70"):
with pytest.raises(python_bindings.ApiException):
python_bindings.RemotesPythonApi.partial_update(remote.pulp_href, body)

# Test an include specifier with an invalid "version_specifier" field value.
body = {"includes": PYTHON_INVALID_SPECIFIER_BAD_VERSION}
Expand All @@ -111,8 +117,9 @@ def test_remote_update_invalid_project_specifier(python_bindings, python_remote_

# Test an exclude specifier without a "name" field.
body = {"excludes": PYTHON_INVALID_SPECIFIER_NO_NAME}
with pytest.raises(python_bindings.ApiException):
python_bindings.RemotesPythonApi.partial_update(remote.pulp_href, body)
if has_pulp_plugin("core", max="3.70"):
with pytest.raises(python_bindings.ApiException):
python_bindings.RemotesPythonApi.partial_update(remote.pulp_href, body)

# Test an exclude specifier with an invalid "version_specifier" field value.
body = {"excludes": PYTHON_INVALID_SPECIFIER_BAD_VERSION}
Expand Down
9 changes: 0 additions & 9 deletions pulp_python/tests/functional/api/test_domains.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from pulpcore.app import settings

from pulp_python.tests.functional.constants import (
PYTHON_URL,
PYTHON_EGG_FILENAME,
PYTHON_SM_PROJECT_SPECIFIER,
PYTHON_SM_PACKAGE_COUNT,
Expand Down Expand Up @@ -82,14 +81,6 @@ def test_domain_object_creation(
}


@pytest.fixture
def python_file(tmp_path, http_get):
filename = tmp_path / PYTHON_EGG_FILENAME
with open(filename, mode="wb") as f:
f.write(http_get(PYTHON_URL))
yield filename


@pytest.mark.parallel
def test_domain_content_upload(
domain_factory,
Expand Down
24 changes: 16 additions & 8 deletions pulp_python/tests/functional/api/test_rbac.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import pytest
import uuid

from pulpcore.client.pulp_python import ApiException, AsyncOperationResponse
from pulp_python.tests.functional.constants import (
PYTHON_EGG_FILENAME,
PYTHON_EGG_SHA256,
Expand All @@ -27,19 +26,28 @@ def _gen_users(role_names=list()):


@pytest.fixture
def try_action(monitor_task):
def try_action(python_bindings, monitor_task):
def _try_action(user, client, action, outcome, *args, **kwargs):
action_api = getattr(client, f"{action}_with_http_info")
try:
with user:
response, status, _ = action_api(*args, **kwargs, _return_http_data_only=False)
if isinstance(response, AsyncOperationResponse):
response = monitor_task(response.task)
except ApiException as e:
response = action_api(*args, **kwargs)
if isinstance(response, tuple):
# old bindings
data, status_code, _ = response
else:
# new bindings
data = response.data
status_code = response.status_code
if isinstance(data, python_bindings.module.AsyncOperationResponse):
data = monitor_task(data.task)
except python_bindings.module.ApiException as e:
assert e.status == outcome, f"{e}"
else:
assert status == outcome, f"User performed {action} when they shouldn't been able to"
return response
assert (
status_code == outcome
), f"User performed {action} when they shouldn't been able to"
return data

return _try_action

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ classifiers=[
]
requires-python = ">=3.9"
dependencies = [
"pulpcore>=3.49.0,<3.70",
"pulpcore>=3.49.0,<3.85",
"pkginfo>=1.10.0,<1.12.0", # Twine has <1.11 in their requirements
"bandersnatch>=6.3,<7.0", # Anything >6.3 requires Python 3.10+
"pypi-simple>=1.5.0,<2.0",
Expand Down
2 changes: 1 addition & 1 deletion template_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,6 @@ test_lowerbounds: true
test_performance: false
test_reroute: true
test_s3: true
test_storages_compat_layer: false
test_storages_compat_layer: true
use_issue_template: true

0 comments on commit c1a84bb

Please sign in to comment.