Repository: pulp/pulpcore

Issue:
[noissue]: Update opentelemetry-exporter-otlp-proto-http requirement from <=1.24.0,>=1.24.0 to >=1.24.0,<=1.25.0
Updates the requirements on [opentelemetry-exporter-otlp-proto-http](https://github.com/open-telemetry/opentelemetry-python) to permit the latest version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/open-telemetry/opentelemetry-python/blob/main/CHANGELOG.md">opentelemetry-exporter-otlp-proto-http's changelog</a>.</em></p>
<blockquote>
<h2>Version 1.25.0/0.46b0 (2024-05-30)</h2>
<ul>
<li>Fix class BoundedAttributes to have RLock rather than Lock
(<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/pull/3859">#3859</a>)</li>
<li>Remove thread lock by loading RuntimeContext explicitly.
(<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/pull/3763">#3763</a>)</li>
<li>Update proto version to v1.2.0
(<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/pull/3844">#3844</a>)</li>
<li>Add to_json method to ExponentialHistogram
(<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/pull/3780">#3780</a>)</li>
<li>Bump mypy to 1.9.0
(<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/pull/3795">#3795</a>)</li>
<li>Fix exponential histograms
(<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/pull/3798">#3798</a>)</li>
<li>Fix otlp exporter to export log_record.observed_timestamp
(<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/pull/3785">#3785</a>)</li>
<li>Add capture the fully qualified type name for raised exceptions in spans
(<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/pull/3837">#3837</a>)</li>
<li>Prometheus exporter sort label keys to prevent duplicate metrics when user input changes order
(<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/pull/3698">#3698</a>)</li>
<li>Update semantic conventions to version 1.25.0.
Refactor semantic-convention structure:
<ul>
<li><code>SpanAttributes</code>, <code>ResourceAttributes</code>, and <code>MetricInstruments</code> are deprecated.</li>
<li>Attribute and metric definitions are now grouped by the namespace.</li>
<li>Stable attributes and metrics are moved to <code>opentelemetry.semconv.attributes</code>
and <code>opentelemetry.semconv.metrics</code> modules.</li>
<li>Stable and experimental attributes and metrics are defined under
<code>opentelemetry.semconv._incubating</code> import path.
(<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/pull/3586">#3586</a>)</li>
</ul>
</li>
<li>Rename test objects to avoid pytest warnings
(<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/issues/3823">#3823</a> (<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/pull/3823">open-telemetry/opentelemetry-python#3823</a>))</li>
<li>Add span flags to OTLP spans and links
(<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/pull/3881">#3881</a>)</li>
<li>Record links with invalid SpanContext if either attributes or TraceState are not empty
(<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/pull/3917/">#3917</a>)</li>
<li>Add OpenTelemetry trove classifiers to PyPI packages
(<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/issues/3913">#3913</a> (<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/pull/3913">open-telemetry/opentelemetry-python#3913</a>))</li>
<li>Fix prometheus metric name and unit conversion
(<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/pull/3924">#3924</a>)
<ul>
<li>this is a breaking change to prometheus metric names so they comply with the
<a href="https://github.com/open-telemetry/opentelemetry-specification/blob/v1.33.0/specification/compatibility/prometheus_and_openmetrics.md#otlp-metric-points-to-prometheus">specification</a>.</li>
<li>you can temporarily opt-out of the unit normalization by setting the environment variable
<code>OTEL_PYTHON_EXPERIMENTAL_DISABLE_PROMETHEUS_UNIT_NORMALIZATION=true</code></li>
<li>common unit abbreviations are converted to Prometheus conventions (<code>s</code> -&gt; <code>seconds</code>),
following the <a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/c0b51136575aa7ba89326d18edb4549e7e1bbdb9/pkg/translator/prometheus/normalize_name.go#L108">collector's implementation</a></li>
<li>repeated <code>_</code> are replaced with a single <code>_</code></li>
<li>unit annotations (enclosed in curly braces like <code>{requests}</code>) are stripped away</li>
<li>units with slash are converted e.g. <code>m/s</code> -&gt; <code>meters_per_second</code>.</li>
<li>The exporter's API is not changed</li>
</ul>
</li>
<li>Add parameters for Distros and configurators to configure autoinstrumentation in addition to existing environment variables.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/open-telemetry/opentelemetry-python/commit/257e6fe3345d42203109128a6ccc9afbb4b777bc"><code>257e6fe</code></a> [release/v1.25.x-0.46bx] Prepare release 1.25.0/0.46b0 (<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/issues/3942">#3942</a>)</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-python/commit/d73593d1137a3854ceff3d7c94180d2bdb8b097f"><code>d73593d</code></a> Fix prometheus metric name and unit conversion (<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/issues/3924">#3924</a>)</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-python/commit/832e85946a2a4ffcc566646b6fa0e830b9b04a66"><code>832e859</code></a> Add OpenTelemetry trove classifiers to PyPI packages (<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/issues/3913">#3913</a>)</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-python/commit/dbf69435269896a344074e7563ede71e5697ff0c"><code>dbf6943</code></a> Fixup pylint broad exceptions warnings (<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/issues/3923">#3923</a>)</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-python/commit/a156bf161d4de96766cac09a5ef4fcddbf367604"><code>a156bf1</code></a> Do not install unnecessary packages (<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/issues/3896">#3896</a>)</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-python/commit/6e84b1f50979c77896c687a40a65f0e79f20a4b2"><code>6e84b1f</code></a> exporter: add is_remote_parent span flags to OTLP exported spans and links (#...</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-python/commit/fbbf5b565032e2d9826dd8e631733c0cd255513f"><code>fbbf5b5</code></a> Revert modifications to Apache license (<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/issues/3870">#3870</a>)</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-python/commit/afc3acef6d32b26511f1ad7080493225015afaac"><code>afc3ace</code></a> Bump black to 24.3.0 (<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/issues/3871">#3871</a>)</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-python/commit/b51a6f8e62a10a4f22455f55e439fe5c5fcac44d"><code>b51a6f8</code></a> Sort by label keys before generating labels key and value lists (<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/issues/3698">#3698</a>)</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-python/commit/9398f26ecad09e02ad044859334cd4c75299c3cd"><code>9398f26</code></a> Use a single install command for lint (<a href="https://redirect.github.com/open-telemetry/opentelemetry-python/issues/3848">#3848</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/open-telemetry/opentelemetry-python/compare/v1.24.0...v1.25.0">compare view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Discussion:

Resolving patch:
diff --git a/pulpcore/app/serializers/content.py b/pulpcore/app/serializers/content.py
--- a/pulpcore/app/serializers/content.py
+++ b/pulpcore/app/serializers/content.py
@@ -27,16 +27,27 @@ class Meta:
 
 
 class SingleArtifactContentSerializer(BaseContentSerializer):
-    _artifact = fields.SingleContentArtifactField(
+    artifact = fields.SingleContentArtifactField(
         help_text=_("Artifact file representing the physical content"),
     )
 
-    _relative_path = serializers.CharField(
+    relative_path = serializers.CharField(
         help_text=_("Path where the artifact is located relative to distributions base_path"),
         validators=[fields.relative_path_validator],
         write_only=True,
     )
 
+    def __init__(self, *args, **kwargs):
+        """
+        Initializer for SingleArtifactContentSerializer
+        """
+        super().__init__(*args, **kwargs)
+
+        # If the content model has its own database field 'relative_path',
+        # we should not mark the field write_only
+        if hasattr(self.Meta.model, 'relative_path'):
+            self.fields["relative_path"].write_only = False
+
     @transaction.atomic
     def create(self, validated_data):
         """
@@ -45,8 +56,11 @@ def create(self, validated_data):
         Args:
             validated_data (dict): Data to save to the database
         """
-        artifact = validated_data.pop('_artifact')
-        relative_path = validated_data.pop('_relative_path')
+        artifact = validated_data.pop('artifact')
+        if self.fields["relative_path"].write_only:
+            relative_path = validated_data.pop('relative_path')
+        else:
+            relative_path = validated_data.get('relative_path')
         content = self.Meta.model.objects.create(**validated_data)
         models.ContentArtifact.objects.create(
             artifact=artifact,
@@ -57,11 +71,11 @@ def create(self, validated_data):
 
     class Meta:
         model = models.Content
-        fields = BaseContentSerializer.Meta.fields + ('_artifact', '_relative_path')
+        fields = BaseContentSerializer.Meta.fields + ('artifact', 'relative_path')
 
 
 class MultipleArtifactContentSerializer(BaseContentSerializer):
-    _artifacts = fields.ContentArtifactsField(
+    artifacts = fields.ContentArtifactsField(
         help_text=_("A dict mapping relative paths inside the Content to the corresponding"
                     "Artifact URLs. E.g.: {'relative/path': "
                     "'/artifacts/1/'"),
@@ -75,9 +89,9 @@ def create(self, validated_data):
         Args:
             validated_data (dict): Data to save to the database
         """
-        _artifacts = validated_data.pop('_artifacts')
+        artifacts = validated_data.pop('artifacts')
         content = self.Meta.model.objects.create(**validated_data)
-        for relative_path, artifact in _artifacts.items():
+        for relative_path, artifact in artifacts.items():
             models.ContentArtifact.objects.create(
                 artifact=artifact,
                 content=content,
@@ -87,7 +101,7 @@ def create(self, validated_data):
 
     class Meta:
         model = models.Content
-        fields = BaseContentSerializer.Meta.fields + ('_artifacts',)
+        fields = BaseContentSerializer.Meta.fields + ('artifacts',)
 
 
 class ContentChecksumSerializer(serializers.Serializer):
diff --git a/pulpcore/app/serializers/fields.py b/pulpcore/app/serializers/fields.py
--- a/pulpcore/app/serializers/fields.py
+++ b/pulpcore/app/serializers/fields.py
@@ -123,7 +123,7 @@ def run_validation(self, data):
         """
         ret = {}
         if data is empty:
-            raise serializers.ValidationError(_('_artifacts field must be specified.'))
+            raise serializers.ValidationError(_('artifacts field must be specified.'))
         for relative_path, url in data.items():
             relative_path_validator(relative_path)
             artifactfield = RelatedField(view_name='artifacts-detail',


Test patch:
diff --git a/.travis/test_bindings.rb b/.travis/test_bindings.rb
--- a/.travis/test_bindings.rb
+++ b/.travis/test_bindings.rb
@@ -125,7 +125,7 @@ def upload_file_in_chunks(file_path)
 artifact = @artifacts_api.create({file: File.new(file_path)})
 
 # Create a FileContent from the artifact
-file_data = PulpFileClient::FileContent.new({relative_path: 'foo.tar.gz', _artifact: artifact._href})
+file_data = PulpFileClient::FileContent.new({relative_path: 'foo.tar.gz', artifact: artifact._href})
 filecontent = @filecontent_api.create(file_data)
 
 # Add the new FileContent to a repository version
diff --git a/pulpcore/tests/functional/api/using_plugin/test_orphans.py b/pulpcore/tests/functional/api/using_plugin/test_orphans.py
--- a/pulpcore/tests/functional/api/using_plugin/test_orphans.py
+++ b/pulpcore/tests/functional/api/using_plugin/test_orphans.py
@@ -80,7 +80,7 @@ def test_clean_orphan_content_unit(self):
         )
 
         # Verify that the artifact is present on disk.
-        artifact_path = os.path.join(MEDIA_PATH, self.api_client.get(content['_artifact'])['file'])
+        artifact_path = os.path.join(MEDIA_PATH, self.api_client.get(content['artifact'])['file'])
         cmd = ('ls', artifact_path)
         self.cli_client.run(cmd, sudo=True)
 
diff --git a/pulpcore/tests/functional/api/using_plugin/test_repo_versions.py b/pulpcore/tests/functional/api/using_plugin/test_repo_versions.py
--- a/pulpcore/tests/functional/api/using_plugin/test_repo_versions.py
+++ b/pulpcore/tests/functional/api/using_plugin/test_repo_versions.py
@@ -330,7 +330,7 @@ def test_delete_first_version(self):
             get_content(self.repo, self.repo_version_hrefs[0])
         for repo_version_href in self.repo_version_hrefs[1:]:
             artifact_paths = get_artifact_paths(self.repo, repo_version_href)
-            self.assertIn(self.content[0]['_artifact'], artifact_paths)
+            self.assertIn(self.content[0]['artifact'], artifact_paths)
 
     def test_delete_last_version(self):
         """Delete the last repository version.
@@ -352,8 +352,8 @@ def test_delete_last_version(self):
         self.repo = self.client.get(self.repo['_href'])
         artifact_paths = get_artifact_paths(self.repo)
 
-        self.assertNotIn(self.content[-2]['_artifact'], artifact_paths)
-        self.assertIn(self.content[-1]['_artifact'], artifact_paths)
+        self.assertNotIn(self.content[-2]['artifact'], artifact_paths)
+        self.assertIn(self.content[-1]['artifact'], artifact_paths)
 
     def test_delete_middle_version(self):
         """Delete a middle version."""
@@ -365,7 +365,7 @@ def test_delete_middle_version(self):
 
         for repo_version_href in self.repo_version_hrefs[index + 1:]:
             artifact_paths = get_artifact_paths(self.repo, repo_version_href)
-            self.assertIn(self.content[index]['_artifact'], artifact_paths)
+            self.assertIn(self.content[index]['artifact'], artifact_paths)
 
     def test_delete_publication(self):
         """Delete a publication.