pulpcore 3.86.0__py3-none-any.whl → 3.87.0__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.

Potentially problematic release.


This version of pulpcore might be problematic. Click here for more details.

@@ -6,6 +6,6 @@ class PulpCertGuardPluginAppConfig(PulpPluginAppConfig):
6
6
 
7
7
  name = "pulp_certguard.app"
8
8
  label = "certguard"
9
- version = "3.86.0"
9
+ version = "3.87.0"
10
10
  python_package_name = "pulpcore"
11
11
  domain_compatible = True
pulp_file/app/__init__.py CHANGED
@@ -8,6 +8,6 @@ class PulpFilePluginAppConfig(PulpPluginAppConfig):
8
8
 
9
9
  name = "pulp_file.app"
10
10
  label = "file"
11
- version = "3.86.0"
11
+ version = "3.87.0"
12
12
  python_package_name = "pulpcore"
13
13
  domain_compatible = True
pulpcore/app/apps.py CHANGED
@@ -239,7 +239,7 @@ class PulpAppConfig(PulpPluginAppConfig):
239
239
  label = "core"
240
240
 
241
241
  # The version of this app
242
- version = "3.86.0"
242
+ version = "3.87.0"
243
243
 
244
244
  # The python package name providing this app
245
245
  python_package_name = "pulpcore"
@@ -11,7 +11,7 @@ from django.contrib.contenttypes.models import ContentType
11
11
  from django.core.management import BaseCommand, call_command, CommandError
12
12
 
13
13
  from pulpcore.app.apps import pulp_plugin_configs
14
- from pulpcore.app.models import AccessPolicy, ContentAppStatus, Worker
14
+ from pulpcore.app.models import AccessPolicy, AppStatus
15
15
  from pulpcore.app.models.role import Role
16
16
  from pulpcore.app.util import get_view_urlpattern
17
17
 
@@ -53,10 +53,7 @@ class Command(BaseCommand):
53
53
  "Checking if Pulp services are running, it can take up to {}s...".format(waiting_time)
54
54
  )
55
55
  while is_pulp_running and (time.time() - check_started) < waiting_time:
56
- is_pulp_running = (
57
- ContentAppStatus.objects.online().exists()
58
- or Worker.objects.online_workers().exists()
59
- )
56
+ is_pulp_running = AppStatus.objects.online().exists()
60
57
  time.sleep(2)
61
58
 
62
59
  if is_pulp_running:
@@ -0,0 +1,15 @@
1
+ # Generated by Django 4.2.23 on 2025-08-12 15:20
2
+
3
+ from django.db import migrations
4
+ from pulpcore.migrations import RequireVersion
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('core', '0139_task_app_lock'),
11
+ ]
12
+
13
+ operations = [
14
+ RequireVersion("core", "3.85"),
15
+ ]
@@ -0,0 +1,18 @@
1
+ # Generated by Django 4.2.23 on 2025-08-27 10:56
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('core', '0140_require_appstatus_zdu'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name='appstatus',
15
+ name='name',
16
+ field=models.TextField(),
17
+ ),
18
+ ]
@@ -61,16 +61,7 @@ class _AppStatusManager(AppStatusManager):
61
61
  if self._current_app_status is not None:
62
62
  raise RuntimeError("There is already an app status in this process.")
63
63
 
64
- if app_type == "api":
65
- old_obj = ApiAppStatus.objects.create(**kwargs)
66
- elif app_type == "worker":
67
- from pulpcore.app.models import Worker
68
-
69
- old_obj = Worker.objects.create(**kwargs)
70
- else:
71
- raise NotImplementedError(f"Invalid app_type: {app_type}")
72
64
  obj = super().create(app_type=app_type, **kwargs)
73
- obj._old_status = old_obj
74
65
  self._current_app_status = obj
75
66
  return obj
76
67
 
@@ -78,12 +69,7 @@ class _AppStatusManager(AppStatusManager):
78
69
  if self._current_app_status is not None:
79
70
  raise RuntimeError("There is already an app status in this process.")
80
71
 
81
- if app_type == "content":
82
- old_obj = await ContentAppStatus.objects.acreate(**kwargs)
83
- else:
84
- raise NotImplementedError(f"Invalid app_type: {app_type}")
85
72
  obj = await super().acreate(app_type=app_type, **kwargs)
86
- obj._old_status = old_obj
87
73
  self._current_app_status = obj
88
74
  return obj
89
75
 
@@ -125,7 +111,7 @@ class AppStatus(BaseModel):
125
111
  objects = _AppStatusManager()
126
112
 
127
113
  app_type = models.CharField(max_length=10, choices=APP_TYPES)
128
- name = models.TextField(db_index=True, unique=True)
114
+ name = models.TextField()
129
115
  versions = HStoreField(default=dict)
130
116
  ttl = models.DurationField(null=False)
131
117
  last_heartbeat = models.DateTimeField(auto_now=True)
@@ -133,13 +119,6 @@ class AppStatus(BaseModel):
133
119
  def __init__(self, *args, **kwargs):
134
120
  super().__init__(*args, **kwargs)
135
121
  self.ttl = timedelta(seconds=self._APP_TTL[self.app_type])
136
- self._old_status = None
137
-
138
- def delete(self, *args, **kwargs):
139
- # adelete will call into this, so we should not replicate that one here.
140
- if self._old_status is not None:
141
- self._old_status.delete(*args, **kwargs)
142
- super().delete(*args, **kwargs)
143
122
 
144
123
  @property
145
124
  def online(self) -> bool:
@@ -171,7 +150,6 @@ class AppStatus(BaseModel):
171
150
  ValueError: When the model instance has never been saved before. This method can
172
151
  only update an existing database record.
173
152
  """
174
- self._old_status.save_heartbeat()
175
153
  self.save(update_fields=["last_heartbeat"])
176
154
 
177
155
  async def asave_heartbeat(self):
@@ -184,7 +162,6 @@ class AppStatus(BaseModel):
184
162
  ValueError: When the model instance has never been saved before. This method can
185
163
  only update an existing database record.
186
164
  """
187
- await self._old_status.asave_heartbeat()
188
165
  await self.asave(update_fields=["last_heartbeat"])
189
166
 
190
167
  @property
@@ -2,11 +2,21 @@ from gettext import gettext as _
2
2
 
3
3
  from rest_framework import serializers
4
4
 
5
- from pulpcore.app.serializers.task import (
6
- ApiAppStatusSerializer,
7
- ContentAppStatusSerializer,
8
- WorkerSerializer,
9
- )
5
+ from pulpcore.app.models import AppStatus
6
+
7
+
8
+ class AppStatusSerializer(serializers.ModelSerializer):
9
+ name = serializers.CharField(help_text=_("The name of the worker."), read_only=True)
10
+ last_heartbeat = serializers.DateTimeField(
11
+ help_text=_("Timestamp of the last time the worker talked to the service."), read_only=True
12
+ )
13
+ versions = serializers.HStoreField(
14
+ help_text=_("Versions of the components installed."), read_only=True
15
+ )
16
+
17
+ class Meta:
18
+ model = AppStatus
19
+ fields = ("name", "last_heartbeat", "versions")
10
20
 
11
21
 
12
22
  class VersionSerializer(serializers.Serializer):
@@ -88,7 +98,7 @@ class StatusSerializer(serializers.Serializer):
88
98
 
89
99
  versions = VersionSerializer(help_text=_("Version information of Pulp components"), many=True)
90
100
 
91
- online_workers = WorkerSerializer(
101
+ online_workers = AppStatusSerializer(
92
102
  help_text=_(
93
103
  "List of online workers known to the application. An online worker is actively "
94
104
  "heartbeating and can respond to new work."
@@ -96,7 +106,7 @@ class StatusSerializer(serializers.Serializer):
96
106
  many=True,
97
107
  )
98
108
 
99
- online_api_apps = ApiAppStatusSerializer(
109
+ online_api_apps = AppStatusSerializer(
100
110
  help_text=_(
101
111
  "List of online api apps known to the application. An online api app "
102
112
  "is actively heartbeating and can serve the rest api to clients."
@@ -104,7 +114,7 @@ class StatusSerializer(serializers.Serializer):
104
114
  many=True,
105
115
  )
106
116
 
107
- online_content_apps = ContentAppStatusSerializer(
117
+ online_content_apps = AppStatusSerializer(
108
118
  help_text=_(
109
119
  "List of online content apps known to the application. An online content app "
110
120
  "is actively heartbeating and can serve data to clients."
@@ -198,34 +198,6 @@ class TaskCancelSerializer(serializers.Serializer):
198
198
  fields = ("state",)
199
199
 
200
200
 
201
- class ApiAppStatusSerializer(ModelSerializer):
202
- name = serializers.CharField(help_text=_("The name of the worker."), read_only=True)
203
- last_heartbeat = serializers.DateTimeField(
204
- help_text=_("Timestamp of the last time the worker talked to the service."), read_only=True
205
- )
206
- versions = serializers.HStoreField(
207
- help_text=_("Versions of the components installed."), read_only=True
208
- )
209
-
210
- class Meta:
211
- model = models.ApiAppStatus
212
- fields = ("name", "last_heartbeat", "versions")
213
-
214
-
215
- class ContentAppStatusSerializer(ModelSerializer):
216
- name = serializers.CharField(help_text=_("The name of the worker."), read_only=True)
217
- last_heartbeat = serializers.DateTimeField(
218
- help_text=_("Timestamp of the last time the worker talked to the service."), read_only=True
219
- )
220
- versions = serializers.HStoreField(
221
- help_text=_("Versions of the components installed."), read_only=True
222
- )
223
-
224
- class Meta:
225
- model = models.ContentAppStatus
226
- fields = ("name", "last_heartbeat", "versions")
227
-
228
-
229
201
  class WorkerSerializer(ModelSerializer):
230
202
  pulp_href = IdentityField(view_name="workers-detail")
231
203
 
@@ -246,7 +218,7 @@ class WorkerSerializer(ModelSerializer):
246
218
  )
247
219
 
248
220
  class Meta:
249
- model = models.Worker
221
+ model = models.AppStatus
250
222
  fields = ModelSerializer.Meta.fields + (
251
223
  "name",
252
224
  "last_heartbeat",
@@ -19,8 +19,7 @@ from google.protobuf.json_format import MessageToJson
19
19
  from pulpcore.app.apps import pulp_plugin_configs
20
20
  from pulpcore.app.models import SystemID, Group, Domain, AccessPolicy
21
21
  from pulpcore.app.models.role import Role
22
- from pulpcore.app.models.status import ContentAppStatus
23
- from pulpcore.app.models.task import Worker
22
+ from pulpcore.app.models.status import AppStatus
24
23
  from pulpcore.app.protobuf.analytics_pb2 import Analytics
25
24
 
26
25
 
@@ -79,13 +78,13 @@ async def _versions_data(analytics):
79
78
 
80
79
 
81
80
  async def _online_content_apps_data(analytics):
82
- online_content_apps_qs = ContentAppStatus.objects.online()
81
+ online_content_apps_qs = AppStatus.objects.online().filter(app_type="content")
83
82
  analytics.online_content_apps.processes = await online_content_apps_qs.acount()
84
83
  analytics.online_content_apps.hosts = await _num_hosts(online_content_apps_qs)
85
84
 
86
85
 
87
86
  async def _online_workers_data(analytics):
88
- online_workers_qs = Worker.objects.online()
87
+ online_workers_qs = AppStatus.objects.online().filter(app_type="worker")
89
88
  analytics.online_workers.processes = await online_workers_qs.acount()
90
89
  analytics.online_workers.hosts = await _num_hosts(online_workers_qs)
91
90
 
@@ -18,6 +18,7 @@ from tablib import Dataset
18
18
  from pulpcore.exceptions.plugin import MissingPlugin
19
19
  from pulpcore.app.apps import get_plugin_config
20
20
  from pulpcore.app.models import (
21
+ AppStatus,
21
22
  Artifact,
22
23
  Content,
23
24
  CreatedResource,
@@ -28,7 +29,6 @@ from pulpcore.app.models import (
28
29
  Repository,
29
30
  Task,
30
31
  TaskGroup,
31
- Worker,
32
32
  )
33
33
  from pulpcore.app.modelresource import (
34
34
  ArtifactResource,
@@ -508,7 +508,7 @@ def pulp_import(importer_pk, path, toc, create_repositories):
508
508
  # By default (setting is not-set), import will continue to use 100% of the available
509
509
  # workers.
510
510
  import_workers_percent = int(settings.get("IMPORT_WORKERS_PERCENT", 100))
511
- total_workers = Worker.objects.online().count()
511
+ total_workers = AppStatus.objects.online().filter(app_type="worker").count()
512
512
  import_workers = max(1, int(total_workers * (import_workers_percent / 100.0)))
513
513
 
514
514
  with open(os.path.join(temp_dir, REPO_FILE), "r") as repo_data_file:
@@ -11,8 +11,7 @@ from collections import namedtuple
11
11
 
12
12
  from pulpcore.app.apps import pulp_plugin_configs
13
13
  from pulpcore.app.models.content import Artifact
14
- from pulpcore.app.models.status import ApiAppStatus, ContentAppStatus
15
- from pulpcore.app.models.task import Worker
14
+ from pulpcore.app.models.status import AppStatus
16
15
  from pulpcore.app.serializers.status import StatusSerializer
17
16
  from pulpcore.app.redis_connection import get_redis_connection
18
17
  from pulpcore.app.util import get_domain
@@ -79,9 +78,9 @@ class StatusView(APIView):
79
78
 
80
79
  db_status = {"connected": self._get_db_conn_status()}
81
80
 
82
- online_workers = Worker.objects.online()
83
- online_api_apps = ApiAppStatus.objects.online()
84
- online_content_apps = ContentAppStatus.objects.online()
81
+ online_workers = AppStatus.objects.online().filter(app_type="worker")
82
+ online_api_apps = AppStatus.objects.online().filter(app_type="api")
83
+ online_content_apps = AppStatus.objects.online().filter(app_type="content")
85
84
 
86
85
  content_settings = {
87
86
  "content_origin": settings.CONTENT_ORIGIN,
@@ -113,7 +112,7 @@ class StatusView(APIView):
113
112
  bool: True if there's a db connection. False otherwise.
114
113
  """
115
114
  try:
116
- Worker.objects.count()
115
+ AppStatus.objects.count()
117
116
  except Exception:
118
117
  _logger.exception(_("Cannot connect to database during status check."))
119
118
  return False
@@ -12,11 +12,11 @@ from rest_framework.serializers import DictField, URLField, ValidationError
12
12
 
13
13
  from pulpcore.filters import BaseFilterSet
14
14
  from pulpcore.app.models import (
15
+ AppStatus,
15
16
  ProfileArtifact,
16
17
  Task,
17
18
  TaskGroup,
18
19
  TaskSchedule,
19
- Worker,
20
20
  CreatedResource,
21
21
  RepositoryVersion,
22
22
  )
@@ -48,6 +48,7 @@ from pulpcore.app.role_util import get_objects_for_user
48
48
 
49
49
  class TaskFilter(BaseFilterSet):
50
50
  created_resources = CreatedResourcesFilter()
51
+ worker = filters.CharFilter(method="worker_filter")
51
52
  # Non model field filters
52
53
  reserved_resources = ReservedResourcesFilter(exclusive=True, shared=True)
53
54
  reserved_resources__in = ReservedResourcesInFilter(exclusive=True, shared=True)
@@ -56,6 +57,13 @@ class TaskFilter(BaseFilterSet):
56
57
  shared_resources = ReservedResourcesFilter(exclusive=False, shared=True)
57
58
  shared_resources__in = ReservedResourcesInFilter(exclusive=False, shared=True)
58
59
 
60
+ def worker_filter(self, queryset, name, value):
61
+ # The worker field on tasks is no longer used.
62
+ if value is None:
63
+ return queryset
64
+ else:
65
+ return queryset.none()
66
+
59
67
  class Meta:
60
68
  model = Task
61
69
  fields = {
@@ -354,14 +362,14 @@ class WorkerFilter(BaseFilterSet):
354
362
  missing = filters.BooleanFilter(method="filter_missing")
355
363
 
356
364
  class Meta:
357
- model = Worker
365
+ model = AppStatus
358
366
  fields = {
359
367
  "name": NAME_FILTER_OPTIONS,
360
368
  "last_heartbeat": DATETIME_FILTER_OPTIONS,
361
369
  }
362
370
 
363
371
  def filter_online(self, queryset, name, value):
364
- online_workers = Worker.objects.online()
372
+ online_workers = AppStatus.objects.online()
365
373
 
366
374
  if value:
367
375
  return queryset.filter(pk__in=online_workers)
@@ -369,7 +377,7 @@ class WorkerFilter(BaseFilterSet):
369
377
  return queryset.exclude(pk__in=online_workers)
370
378
 
371
379
  def filter_missing(self, queryset, name, value):
372
- missing_workers = Worker.objects.missing()
380
+ missing_workers = AppStatus.objects.missing()
373
381
 
374
382
  if value:
375
383
  return queryset.filter(pk__in=missing_workers)
@@ -378,7 +386,8 @@ class WorkerFilter(BaseFilterSet):
378
386
 
379
387
 
380
388
  class WorkerViewSet(NamedModelViewSet, mixins.RetrieveModelMixin, mixins.ListModelMixin):
381
- queryset = Worker.objects.all()
389
+ queryset = AppStatus.objects.filter(app_type="worker")
390
+ pulp_model_alias = "Worker"
382
391
  serializer_class = WorkerSerializer
383
392
  endpoint_name = "workers"
384
393
  http_method_names = ["get", "options"]
@@ -260,7 +260,7 @@ class PulpSchemaGenerator(SchemaGenerator):
260
260
  prefix (str): Optional prefix to add to the slug
261
261
  pulp_model_alias (str): Optional model name to use instead of model.__name__
262
262
  Returns:
263
- str: *pulp_href where * is the model name in all lower case letters
263
+ str: '{model_name_snake_case}_href'
264
264
  """
265
265
  app_label = model._meta.app_label
266
266
  model_name = pulp_model_alias or model.__name__
@@ -77,7 +77,6 @@ class PulpcoreWorker:
77
77
  self.app_status = AppStatus.objects.create(
78
78
  name=self.name, app_type="worker", versions=self.versions
79
79
  )
80
- self.worker = self.app_status._old_status
81
80
  except IntegrityError:
82
81
  _logger.error(f"A worker with name {self.name} already exists in the database.")
83
82
  exit(1)
@@ -184,15 +183,17 @@ class PulpcoreWorker:
184
183
  for app_worker in qs:
185
184
  _logger.info(_("Clean missing %s worker %s."), app_worker.app_type, app_worker.name)
186
185
  qs.delete()
187
- for cls, cls_name in (
188
- (Worker, "pulp"),
189
- (ApiAppStatus, "api"),
190
- (ContentAppStatus, "content"),
191
- ):
192
- qs = cls.objects.missing(age=timedelta(days=7))
193
- for app_worker in qs:
194
- _logger.info(_("Clean missing %s worker %s."), cls_name, app_worker.name)
195
- qs.delete()
186
+ with contextlib.suppress(DatabaseError):
187
+ # By now a migration on a newer release may have deleted these tables already.
188
+ for cls, cls_name in (
189
+ (Worker, "pulp"),
190
+ (ApiAppStatus, "api"),
191
+ (ContentAppStatus, "content"),
192
+ ):
193
+ qs = cls.objects.missing(age=timedelta(days=7))
194
+ for app_worker in qs:
195
+ _logger.info(_("Clean missing %s worker %s."), cls_name, app_worker.name)
196
+ qs.delete()
196
197
 
197
198
  def beat(self):
198
199
  if self.app_status.last_heartbeat < timezone.now() - self.heartbeat_period:
@@ -385,13 +386,13 @@ class PulpcoreWorker:
385
386
  # Check if someone else changed the task before we got the lock.
386
387
  task.refresh_from_db()
387
388
 
388
- if task.state == TASK_STATES.CANCELING and task.worker is None:
389
+ if task.state == TASK_STATES.CANCELING:
389
390
  # No worker picked this task up before being canceled.
390
391
  if self.cancel_abandoned_task(task, TASK_STATES.CANCELED):
391
392
  # Continue looking for the next task without considering this
392
393
  # tasks resources, as we just released them.
393
394
  continue
394
- if task.state in [TASK_STATES.RUNNING, TASK_STATES.CANCELING]:
395
+ if task.state == TASK_STATES.RUNNING:
395
396
  # A running task without a lock must be abandoned.
396
397
  if self.cancel_abandoned_task(
397
398
  task, TASK_STATES.FAILED, "Worker has gone missing."
@@ -445,8 +446,6 @@ class PulpcoreWorker:
445
446
 
446
447
  self.cancel_task = False
447
448
  self.task = task
448
- task.worker = self.worker
449
- task.save(update_fields=["worker"])
450
449
  cancel_state = None
451
450
  cancel_reason = None
452
451
  domain = task.pulp_domain
@@ -230,25 +230,6 @@ def test_retrieve_task_with_minimal_fields(task, bindings_cfg):
230
230
  assert unexpected_fields.isdisjoint(returned_fields)
231
231
 
232
232
 
233
- @pytest.mark.parallel
234
- def test_retrieve_task_using_invalid_worker(pulpcore_bindings):
235
- """Expects to raise an exception when using invalid worker value as filter."""
236
-
237
- with pytest.raises(ApiException) as ctx:
238
- pulpcore_bindings.TasksApi.list(worker=str(uuid4()))
239
-
240
- assert ctx.value.status == 400
241
-
242
-
243
- @pytest.mark.parallel
244
- def test_retrieve_task_using_valid_worker(task, pulpcore_bindings):
245
- """Expects to retrieve a task using a valid worker URI as filter."""
246
-
247
- response = pulpcore_bindings.TasksApi.list(worker=task.worker)
248
-
249
- assert response.results and response.count
250
-
251
-
252
233
  @pytest.mark.parallel
253
234
  def test_retrieve_task_using_valid_date(task, pulpcore_bindings):
254
235
  """Expects to retrieve a task using a valid date."""
@@ -278,22 +259,6 @@ def test_search_task_using_an_invalid_name(pulpcore_bindings):
278
259
  assert not search_results.results and not search_results.count
279
260
 
280
261
 
281
- @pytest.mark.parallel
282
- def test_filter_tasks_using_worker__in_filter(pulpcore_bindings, dispatch_task, monitor_task):
283
- task1_href = dispatch_task("pulpcore.app.tasks.test.sleep", args=(0,))
284
- task2_href = dispatch_task("pulpcore.app.tasks.test.sleep", args=(0,))
285
-
286
- task1 = monitor_task(task1_href)
287
- task2 = monitor_task(task2_href)
288
-
289
- search_results = pulpcore_bindings.TasksApi.list(worker__in=(task1.worker, task2.worker))
290
-
291
- tasks_hrefs = [task.pulp_href for task in search_results.results]
292
-
293
- assert task1_href in tasks_hrefs
294
- assert task2_href in tasks_hrefs
295
-
296
-
297
262
  @pytest.mark.parallel
298
263
  def test_filter_tasks_using_pulp_created_filter(pulpcore_bindings, dispatch_task):
299
264
 
@@ -487,7 +452,6 @@ class TestImmediateTaskWithNoResource:
487
452
  )
488
453
  task = pulpcore_bindings.TasksApi.read(task_href)
489
454
  assert task.state == "completed"
490
- assert task.worker is None
491
455
 
492
456
  @pytest.mark.parallel
493
457
  def test_executes_on_api_worker_when_no_async(
@@ -519,7 +483,7 @@ class TestImmediateTaskWithNoResource:
519
483
  "pulpcore.app.tasks.test.asleep", args=(GT_TIMEOUT,), immediate=True
520
484
  )
521
485
  task = pulpcore_bindings.TasksApi.read(task_href)
522
- assert task.worker is None
486
+ assert task.state == "failed"
523
487
  assert "task timed out after" in task.error["description"]
524
488
 
525
489
 
@@ -555,7 +519,7 @@ class TestImmediateTaskWithBlockedResource:
555
519
  """
556
520
  GIVEN an async task requiring busy resources
557
521
  WHEN dispatching a task as immediate
558
- THEN the task completes with a worker
522
+ THEN the task returns as waiting first
559
523
  """
560
524
  COMMON_RESOURCE = str(uuid4())
561
525
  with resource_blocker(exclusive_resources=[COMMON_RESOURCE]):
@@ -565,9 +529,10 @@ class TestImmediateTaskWithBlockedResource:
565
529
  immediate=True,
566
530
  exclusive_resources=[COMMON_RESOURCE],
567
531
  )
532
+ task = pulpcore_bindings.TasksApi.read(task_href)
533
+ assert task.state == "waiting"
568
534
  task = monitor_task(task_href)
569
535
  assert task.state == "completed"
570
- assert task.worker is not None
571
536
 
572
537
  @pytest.mark.parallel
573
538
  def test_throws_when_non_deferrable(
@@ -589,7 +554,6 @@ class TestImmediateTaskWithBlockedResource:
589
554
  )
590
555
  task = pulpcore_bindings.TasksApi.read(task_href)
591
556
  assert task.state == "canceled"
592
- assert task.worker is None
593
557
  assert "Resources temporarily unavailable." in task.error["reason"]
594
558
 
595
559
  @pytest.mark.parallel
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pulpcore
3
- Version: 3.86.0
3
+ Version: 3.87.0
4
4
  Summary: Pulp Django Application and Related Modules
5
5
  Author-email: Pulp Team <pulp-list@redhat.com>
6
6
  Project-URL: Homepage, https://pulpproject.org
@@ -50,7 +50,7 @@ Requires-Dist: pulp-glue<0.36,>=0.28.0
50
50
  Requires-Dist: pygtrie<=2.5.0,>=2.5
51
51
  Requires-Dist: psycopg[binary]<3.3,>=3.1.8
52
52
  Requires-Dist: pyparsing<3.3,>=3.1.0
53
- Requires-Dist: python-gnupg<=0.5.4,>=0.5
53
+ Requires-Dist: python-gnupg<0.6,>=0.5.0
54
54
  Requires-Dist: PyYAML<6.1,>=5.1.1
55
55
  Requires-Dist: redis<6.5,>=4.3.0
56
56
  Requires-Dist: tablib<3.6,>=3.5.0
@@ -1,6 +1,6 @@
1
1
  pulp_certguard/__init__.py,sha256=llnEd00PrsAretsgAOHiNKFbmvIdXe3iDVPmSaKz7gU,71
2
2
  pulp_certguard/pytest_plugin.py,sha256=qhRbChzqN2PROtD-65KuoTfKr5k9T3GPsz9daFgpqpM,852
3
- pulp_certguard/app/__init__.py,sha256=uZZw9MWtJ_10aWLtmfluDTNp95Ys1lJil_PXTdA1_W4,297
3
+ pulp_certguard/app/__init__.py,sha256=xReedwLBMMCFC_Aey1FCvF7NPq1jAFxO9kqD1sPLHaI,297
4
4
  pulp_certguard/app/models.py,sha256=YLEhBtZM4hetekVZ_GTnbLlWD6CkIQw2B3ILwXRcq-s,7483
5
5
  pulp_certguard/app/serializers.py,sha256=9IxlQiy783RdKF9oI1mrYS4haG5Boy2DOjfP_eJtMLY,1726
6
6
  pulp_certguard/app/viewsets.py,sha256=1_gNmsWyOT8kcOiGVkn4-wrtAjZO4wC8q0-aoEsCpjI,697
@@ -51,7 +51,7 @@ pulp_certguard/tests/unit/test_rhsm_check_path.py,sha256=Q1CsXnUgD7ELvtolPeumyNr
51
51
  pulp_file/__init__.py,sha256=0vOCXofR6Eyxkg4y66esnOGPeESCe23C1cNBHj56w44,61
52
52
  pulp_file/manifest.py,sha256=1WwIOJrPSkFcmkRm7CkWifVOCoZvo_nnANgce6uuG7U,3796
53
53
  pulp_file/pytest_plugin.py,sha256=l1PvTxUi5D3uJy4SnHWNhr-otWEYNcm-kc5nSqVJg0Y,10646
54
- pulp_file/app/__init__.py,sha256=jD3E48tyhIAmkz0RW7ThsAoxuXVR5KpUsS68u6x5W4E,292
54
+ pulp_file/app/__init__.py,sha256=dibg5uhEg3n9ndMpkjTtaKs3Z3PzNWshY9pHL_noEgU,292
55
55
  pulp_file/app/modelresource.py,sha256=v-m-_bBEsfr8wG0TI5ffx1TuKUy2-PsirhuQz4XXF-0,1063
56
56
  pulp_file/app/models.py,sha256=QsrVg_2uKqnR89sLN2Y7Zy260_nLIcUfa94uZowlmFw,4571
57
57
  pulp_file/app/replica.py,sha256=OtNWVmdFUgNTYhPttftVNQnSrnvx2_hnrJgtW_G0Vrg,1894
@@ -96,7 +96,7 @@ pulpcore/pytest_plugin.py,sha256=fy9vz5-bw30T7f4jxDtNIgF7L_0MJ_q7KIAzpvizvnY,382
96
96
  pulpcore/responses.py,sha256=mIGKmdCfTSoZxbFu4yIH1xbdLx1u5gqt3D99LTamcJg,6125
97
97
  pulpcore/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
98
  pulpcore/app/access_policy.py,sha256=5vCKy6WoHtIt1_-eS5vMaZ7CmR4G-CIpsrB8yT-d88Q,6079
99
- pulpcore/app/apps.py,sha256=1X52djxH5kP1k2Tktti7NJttzmNqI2rSKuJ_JKti7Zg,17412
99
+ pulpcore/app/apps.py,sha256=0Gsmsyt1r937-0pABimY5Tlj8a2LRkGqFX1bdzfza0M,17412
100
100
  pulpcore/app/authentication.py,sha256=1LIJW6HIQQlZrliHy__jdzkDEh6Oj7xKgd0V-vRcDus,2855
101
101
  pulpcore/app/checks.py,sha256=jbfTF7nmftBbky4AQXHigpyCaGydKasvRUXsd72JZVg,1946
102
102
  pulpcore/app/entrypoint.py,sha256=GYEq4GjglQZhFlU3865AT_H0nPypDKJAsf8qdyR4tPY,4985
@@ -132,7 +132,7 @@ pulpcore/app/management/commands/migrationstat.py,sha256=Gy19UMSyUeXYT13ERQ-P1Pd
132
132
  pulpcore/app/management/commands/openapi.py,sha256=p-aPuVfbnFQYIU7BMnipxe9nId-f2agNiviSIy43y9Q,3634
133
133
  pulpcore/app/management/commands/optimizemigration.py,sha256=jt_V2PxvA7TSLz730hm6Yq8QwlcRIE5cllmve9KJo9M,3155
134
134
  pulpcore/app/management/commands/rebasemigrations.py,sha256=xpn8Gg-L3SfBGG0dD782sBmhLMgVHrveBg7xrGII3f8,3356
135
- pulpcore/app/management/commands/remove-plugin.py,sha256=bgcCm4y_Cl-C_8DL8wqTveOV4Jvw3cMwashauOhDD2E,7949
135
+ pulpcore/app/management/commands/remove-plugin.py,sha256=yOca4FtXtYdU_llhagZzlPS-TKuwXiqnUEszw2LQj5Y,7835
136
136
  pulpcore/app/management/commands/remove-signing-service.py,sha256=OF0IeGoldEhFAK3QvDaxMpsmoCu-q6Kcs8SbZJutLgU,2199
137
137
  pulpcore/app/management/commands/repository-size.py,sha256=jSbYUIvLY-lxsNtzcN9TE_ZGvha4mzewu3cPdFkrMbM,4999
138
138
  pulpcore/app/management/commands/reset-admin-password.py,sha256=vCELRG9KiiDzsmqNUfOpbI-Ii98MOpQkZJWNPe4mdSw,2255
@@ -188,6 +188,8 @@ pulpcore/app/migrations/0136_delete_basedistribution.py,sha256=4oKidAU27jLLWRkbo
188
188
  pulpcore/app/migrations/0137_appstatus.py,sha256=WMjQ8Tb-jsaCtyYBVZAmFemGyIzNDABVPfTKsEYvxjI,1332
189
189
  pulpcore/app/migrations/0138_vulnerabilityreport.py,sha256=rYmdIXfTCSZeH5sHLCCFMc2wrKhSuVE334A4kmFkJ6w,1372
190
190
  pulpcore/app/migrations/0139_task_app_lock.py,sha256=Dtu_om_zFplrPr8DageoiXOWUiOS5aHgOy99S0bMXH0,502
191
+ pulpcore/app/migrations/0140_require_appstatus_zdu.py,sha256=KrSyuQDg6Wd_M4RetDfGS9FDSMkHJxjh6BijR3Hro78,305
192
+ pulpcore/app/migrations/0141_alter_appstatus_name.py,sha256=bkNO_1RrCFn5VQWTNRpz5LhZyWXluLdVekPfDGEHFB8,375
191
193
  pulpcore/app/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
192
194
  pulpcore/app/models/__init__.py,sha256=P_2UnLmtQYbASWrm8elO2Zm_od-LXVqQKnjCwYFlZW0,3552
193
195
  pulpcore/app/models/access_policy.py,sha256=o4L41RGoZ5UMmh5UeeenmadD5MJgShguphgd4eAVxQA,6071
@@ -206,7 +208,7 @@ pulpcore/app/models/publication.py,sha256=75uUnm_sU5V_QraD6kPvEXVKxYyA1ikIsoFD51
206
208
  pulpcore/app/models/replica.py,sha256=i_wPxyPaVWpEVTJNVjJsBarxFauqeagtuwLadsmVz-g,2067
207
209
  pulpcore/app/models/repository.py,sha256=SIc21Gex6okxI7OCfHEGIpXpGlypG3z9IgMt5-mkNy0,58056
208
210
  pulpcore/app/models/role.py,sha256=dZklNd2VeAw4cT6dyJ7SyTBt9sZvdqakY86wXGAY3vU,3287
209
- pulpcore/app/models/status.py,sha256=2Fac5z8quv0cG-8CTxIzdT_uzPea6c0i5sEaHp4V82A,9268
211
+ pulpcore/app/models/status.py,sha256=WniovQQFdlR0TN-XWd_0FnBRiwzKxDyODyD-5VUgXjo,8290
210
212
  pulpcore/app/models/storage.py,sha256=2b-DQWaO31NqjV6FiISALegND-sQZAU7BVAsduUvm3o,6780
211
213
  pulpcore/app/models/task.py,sha256=fHubp1YO6CjSxfXVtgdZsQyn7NJ7apBHKz6-YEqnuDM,15653
212
214
  pulpcore/app/models/upload.py,sha256=3njXT2rrVJwBjEDegvqcLD9_7cPnnl974lhbAhikEp8,3004
@@ -231,16 +233,16 @@ pulpcore/app/serializers/reclaim.py,sha256=-ewdNqu-Ck1B_IUWJHG0pvN5zCMMEK9RiWI45
231
233
  pulpcore/app/serializers/repair.py,sha256=uKrxTnhoarxyyGCixPRn9pmG19gRRVUTM7nPwCVp6_8,554
232
234
  pulpcore/app/serializers/replica.py,sha256=E3jwn1vfBqT4Y4s9pWsTrUEJKPO9pO0q2ZmwcpIDVh4,4044
233
235
  pulpcore/app/serializers/repository.py,sha256=BNv0yX1JJs57VcMdzjU5rthRMcm1KB93Seqp6jve2i8,20468
234
- pulpcore/app/serializers/status.py,sha256=nIrQl-MlOzUIvV2DrkgC19gqGmRVNKvWVN4pIBELgcQ,3815
235
- pulpcore/app/serializers/task.py,sha256=IGJGoSEC_wKS8t77JGnZWRqK-Mk5-4rXSj8j0Ha6nRA,10026
236
+ pulpcore/app/serializers/status.py,sha256=RRlymRv_CrfCog3xIZUY86L03MHButvsJu8xmzdoreY,4245
237
+ pulpcore/app/serializers/task.py,sha256=m4BpydbxkC7isumXsYnfW07h6ApQn0VPdS7oXERGgTk,8973
236
238
  pulpcore/app/serializers/upload.py,sha256=4r6iBegbYHmgFYjBYPcqB8J7eSxXgY4ukayMxJZNh_M,2402
237
239
  pulpcore/app/serializers/user.py,sha256=QBEnUCfq2my3Lq_pohj7hphDE8wqU6g6fnYuEXl8VtI,18413
238
240
  pulpcore/app/serializers/vulnerability_report.py,sha256=N7geQkTDZ7_SCipo6Q4LGBInwuGy8-tGIpwGIPWimm4,787
239
241
  pulpcore/app/tasks/__init__.py,sha256=J8S3QDCIc8ONYPLVmp7tSLEfQZbHjouvpYBhZHYYV0o,625
240
- pulpcore/app/tasks/analytics.py,sha256=eB3p-sdocH5yyNoe0OG5rUzwiVOfayOfHNzkohAfx-U,4722
242
+ pulpcore/app/tasks/analytics.py,sha256=taQqEJ9RROIp77uSHA9S32MNlpxkI8admexMcGnHj3I,4720
241
243
  pulpcore/app/tasks/base.py,sha256=4I88Bn5SttqEvvVlNJmIwkPv2IWe7OhpM-kbQiQ9T_U,5929
242
244
  pulpcore/app/tasks/export.py,sha256=dRg-KcnM7HumXUx8mjgJ-EVMcz2RbzSOPmMkzVtJEnI,19320
243
- pulpcore/app/tasks/importer.py,sha256=5T14JynWJjBijAE-d_YstTRYOtY0WTHMqkF7GFJaj5o,23222
245
+ pulpcore/app/tasks/importer.py,sha256=KW5THJhcAYlUveL8lV-2GOUyN7RCWluHLWSiMJYpH0Q,23254
244
246
  pulpcore/app/tasks/migrate.py,sha256=wCjGskoF-XWzbINEyC_crgcigFZlC8EHqZTbjkLQykg,2452
245
247
  pulpcore/app/tasks/orphan.py,sha256=4rTZLZ549niJ7mGMh_7suy-czIcj06oCTxPYnsPN8mU,4685
246
248
  pulpcore/app/tasks/purge.py,sha256=IpdKTj9AvlNNuMNbkxa63xuaf3eK6dUvHZeMMWr_MjQ,7532
@@ -258,7 +260,7 @@ pulpcore/app/views/__init__.py,sha256=JgPFwb8s-mOQv8wYBv575X0ukZn8ZIhCQ494BirYGt
258
260
  pulpcore/app/views/importer.py,sha256=Ws_XFEqXe3b77IDfUz9UROBoOGBco2ffGzq5An7VOaY,4776
259
261
  pulpcore/app/views/orphans.py,sha256=e32kDdfn13fK94eNRvdKSAGQ09tyC-VLwGvszfaDOLU,1008
260
262
  pulpcore/app/views/repair.py,sha256=DTEd9FlEzpBjjuXLb42LbqJPA5EUN2FrFDFcJnkYxxo,1228
261
- pulpcore/app/views/status.py,sha256=snoAyU7KCfaxe04Tc9UF9Go8A8-zCxpKoZ6nxFfmaVU,4890
263
+ pulpcore/app/views/status.py,sha256=JRjQ9f9yTMcOOcExp1iLO0PUL7mdnLSBdTMUcCUa5K8,4897
262
264
  pulpcore/app/viewsets/__init__.py,sha256=Dh0vT4xnPPnxxES6V6uUB-dXJ_Z99s57p0lb8i9K8ts,2286
263
265
  pulpcore/app/viewsets/access_policy.py,sha256=Tjo443gpPfR9gRAgfQfTuV15eMWylZa7lPLucTAIKhQ,2447
264
266
  pulpcore/app/viewsets/acs.py,sha256=JabJntgGAMELbarKlTXDWrgMSYdMPgv6evJxoRdj66Y,2078
@@ -274,7 +276,7 @@ pulpcore/app/viewsets/publication.py,sha256=5os3PVMs0Z7oRJX5HkQ7U8JojLengq7rYCUd
274
276
  pulpcore/app/viewsets/reclaim.py,sha256=s8eURE5LItYBwo8c3aBou5SgclnXfDm0-KOW2seIzHQ,1757
275
277
  pulpcore/app/viewsets/replica.py,sha256=SOzcl30r-X5I5Ia_IZlb3BBGC31UqnMSf8uipgPC2sg,4981
276
278
  pulpcore/app/viewsets/repository.py,sha256=kRk1Ww61bvTiKVTz_o9Gr4sSJcM2s5CXvcYCF8A_Br4,12975
277
- pulpcore/app/viewsets/task.py,sha256=pMoOQnhjA91dUgNNAnL3OaCHcVOrQcB-CD3D5Px96YE,16753
279
+ pulpcore/app/viewsets/task.py,sha256=ACgPcynSTqs9g-rvI6HEXCRvoN2oOzTAT-Y2bUJ67I4,17087
278
280
  pulpcore/app/viewsets/upload.py,sha256=Mfy9Vcm5KcqARooH4iExzoXVkL6boDddEqAnGWDWzFg,5452
279
281
  pulpcore/app/viewsets/user.py,sha256=86eMawpaVrvp6ilQmb1C4j7SKpesPB5HgMovYL9rY3Q,13813
280
282
  pulpcore/app/viewsets/vulnerability_report.py,sha256=XCvhbkzxC6qJ5JvTrHbRwuS_R3y5T1lSASf0HGg6p3A,689
@@ -294,7 +296,7 @@ pulpcore/exceptions/__init__.py,sha256=ZgqOLvuNEAEPkC8lUVEJIFyUJZJOy94whdzXYoMP2
294
296
  pulpcore/exceptions/base.py,sha256=3iNTD8BsAfe7vpUaOzXl2f_WJPd4wfqEuf2GkFheBhs,2863
295
297
  pulpcore/exceptions/plugin.py,sha256=CrfzjCP1YZk_W6p1yRFrUfqTv0Iptzu2aBxzlebXeLU,613
296
298
  pulpcore/exceptions/validation.py,sha256=4iyDMxKzejHIzEuebDRXkvA_GNCdaommW9Ycsaa1v3Y,2481
297
- pulpcore/openapi/__init__.py,sha256=o32R5pngZvHZWi0lByGOafz7-7xC1zmz66qiR5Yx6i8,18748
299
+ pulpcore/openapi/__init__.py,sha256=x8gaXesSwM9S8aecqAtJWdeZ3e-tPFpatPzm_0s1YzY,18716
298
300
  pulpcore/openapi/hooks.py,sha256=uRFFW6khHNrntK6R99SUEDfP4LzmYJfsX7i8XGO4iaI,1426
299
301
  pulpcore/plugin/__init__.py,sha256=q0qu_15BTEY_EqPB9DSDk8rdnZMvld3cZsFXEnOVjuo,131
300
302
  pulpcore/plugin/access_policy.py,sha256=KHbWBXEOP59V8J_R52Pw2Q_Amodg-1bJYh6tyt5vDgk,4968
@@ -337,7 +339,7 @@ pulpcore/tasking/entrypoint.py,sha256=eAypZD4ORoNOrmBeMdbwO9p6GSQ59bMvZ3TrbnE0cz
337
339
  pulpcore/tasking/kafka.py,sha256=76z4DzeXM1WL5uu1HlKnduWeLO3-b-czvGBXdWR6054,3845
338
340
  pulpcore/tasking/storage.py,sha256=zQkwlpC_FDQtmZGZ8vKwHqxvD6CLO_gAS4Q7wijZE-k,3106
339
341
  pulpcore/tasking/tasks.py,sha256=CTlWLCmxP5-HZjo5_KLYIJQu-VKJnzQ5cyL7IFNRMWw,12944
340
- pulpcore/tasking/worker.py,sha256=pp_9e8fTUgmghiUZI6NDQlVVxv8hpNes4SnFnqVvawQ,27195
342
+ pulpcore/tasking/worker.py,sha256=n62lnZK2UFQrbLxxv1gUdkya0Z6L9uYW8RQ2HHE1QHM,27190
341
343
  pulpcore/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
342
344
  pulpcore/tests/functional/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
343
345
  pulpcore/tests/functional/content_with_coverage.py,sha256=gQK8himy32s9O9vpXdgoM6-_z2KySaXm5rTga9z0jGI,260
@@ -363,7 +365,7 @@ pulpcore/tests/functional/api/test_scoping.py,sha256=uiLOsx5_7puRMcvrpPKEYQziqlu
363
365
  pulpcore/tests/functional/api/test_signing_service.py,sha256=yr1HXBrNoliBHJNAGAN4PAN0eBKPIvAQP-uMoMSrO_I,222
364
366
  pulpcore/tests/functional/api/test_status.py,sha256=Vmmj-ueGxJw1JFSQtr5feTM8vjgyyROvxsRm-OgzLUQ,5370
365
367
  pulpcore/tests/functional/api/test_task_purge.py,sha256=Av4DrUdCqf-JegfoP1pkY4B-teoUzYd1LBZKAhDa-08,7273
366
- pulpcore/tests/functional/api/test_tasking.py,sha256=UELvclncYdiqRBEC_oZZ_HoNLV4SW9isMaPQHjxw2Q4,22388
368
+ pulpcore/tests/functional/api/test_tasking.py,sha256=4QPkdPVt1L01GzXyCWDmKwQbCPATSj-UznjDUFt609U,21204
367
369
  pulpcore/tests/functional/api/test_upload.py,sha256=oLP1ZmQgPzgK5jAQwGeXS8uLFHgAzVeLW0GfANMWexI,6794
368
370
  pulpcore/tests/functional/api/test_users_groups.py,sha256=YFG0xtyJuIRraczR7ERl_UNS7dlJfKd2eUmXgD1lLBU,2926
369
371
  pulpcore/tests/functional/api/test_workers.py,sha256=XJrQdxt0BpMeMVOdTyzcTEMk5bB8XC4rA8U580HnzBc,4691
@@ -438,9 +440,9 @@ pulpcore/tests/unit/stages/test_artifactdownloader.py,sha256=qB1ANdFmNtUnljg8fCd
438
440
  pulpcore/tests/unit/stages/test_stages.py,sha256=H1a2BQLjdZlZvcb_qULp62huZ1xy6ItTcthktVyGU0w,4735
439
441
  pulpcore/tests/unit/viewsets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
440
442
  pulpcore/tests/unit/viewsets/test_viewset_base.py,sha256=W9o3V6758bZctR6krMPPQytb0xJuF-jb4uBWTNDoD_U,4837
441
- pulpcore-3.86.0.dist-info/licenses/LICENSE,sha256=dhnHU8rJXUdAIgIjveSKAyYG_KzN5eVG-bxETIGrNW0,17988
442
- pulpcore-3.86.0.dist-info/METADATA,sha256=1JVEkZojL684SzjlPGm99WNzSTnuSeXODPsyYJg9UY0,4105
443
- pulpcore-3.86.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
444
- pulpcore-3.86.0.dist-info/entry_points.txt,sha256=OZven4wzXzQA5b5q9MpP4HUpIPPQCSvIOvkKtNInrK0,452
445
- pulpcore-3.86.0.dist-info/top_level.txt,sha256=6h-Lm3FKQSaT_nL1KSxu_hBnzKE15bcvf_BoU-ea4CI,34
446
- pulpcore-3.86.0.dist-info/RECORD,,
443
+ pulpcore-3.87.0.dist-info/licenses/LICENSE,sha256=dhnHU8rJXUdAIgIjveSKAyYG_KzN5eVG-bxETIGrNW0,17988
444
+ pulpcore-3.87.0.dist-info/METADATA,sha256=b93_7typl8xUkhSFLpatjHa_A375x9frLjecSz83IGE,4104
445
+ pulpcore-3.87.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
446
+ pulpcore-3.87.0.dist-info/entry_points.txt,sha256=OZven4wzXzQA5b5q9MpP4HUpIPPQCSvIOvkKtNInrK0,452
447
+ pulpcore-3.87.0.dist-info/top_level.txt,sha256=6h-Lm3FKQSaT_nL1KSxu_hBnzKE15bcvf_BoU-ea4CI,34
448
+ pulpcore-3.87.0.dist-info/RECORD,,