We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add min/max fields to Histogram in otlp metrics exporter
From proto https://github.com/open-telemetry/opentelemetry-proto/pull/279

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py`
Content:
```
1 # Copyright The OpenTelemetry Authors
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13 
14 from logging import getLogger
15 from os import environ
16 from typing import Optional, Sequence
17 from grpc import ChannelCredentials, Compression
18 from opentelemetry.exporter.otlp.proto.grpc.exporter import (
19     OTLPExporterMixin,
20     get_resource_data,
21 )
22 from opentelemetry.proto.collector.metrics.v1.metrics_service_pb2 import (
23     ExportMetricsServiceRequest,
24 )
25 from opentelemetry.proto.collector.metrics.v1.metrics_service_pb2_grpc import (
26     MetricsServiceStub,
27 )
28 from opentelemetry.proto.common.v1.common_pb2 import InstrumentationScope
29 from opentelemetry.proto.metrics.v1 import metrics_pb2 as pb2
30 from opentelemetry.sdk.environment_variables import (
31     OTEL_EXPORTER_OTLP_METRICS_INSECURE,
32 )
33 from opentelemetry.sdk.metrics.export import (
34     Gauge,
35     Histogram,
36     Metric,
37     Sum,
38 )
39 
40 from opentelemetry.sdk.metrics.export import (
41     MetricExporter,
42     MetricExportResult,
43     MetricsData,
44 )
45 
46 _logger = getLogger(__name__)
47 
48 
49 class OTLPMetricExporter(
50     MetricExporter,
51     OTLPExporterMixin[Metric, ExportMetricsServiceRequest, MetricExportResult],
52 ):
53     _result = MetricExportResult
54     _stub = MetricsServiceStub
55 
56     def __init__(
57         self,
58         endpoint: Optional[str] = None,
59         insecure: Optional[bool] = None,
60         credentials: Optional[ChannelCredentials] = None,
61         headers: Optional[Sequence] = None,
62         timeout: Optional[int] = None,
63         compression: Optional[Compression] = None,
64     ):
65 
66         if insecure is None:
67             insecure = environ.get(OTEL_EXPORTER_OTLP_METRICS_INSECURE)
68             if insecure is not None:
69                 insecure = insecure.lower() == "true"
70 
71         super().__init__(
72             **{
73                 "endpoint": endpoint,
74                 "insecure": insecure,
75                 "credentials": credentials,
76                 "headers": headers,
77                 "timeout": timeout,
78                 "compression": compression,
79             }
80         )
81 
82     def _translate_data(
83         self, data: MetricsData
84     ) -> ExportMetricsServiceRequest:
85 
86         resource_metrics_dict = {}
87 
88         for resource_metrics in data.resource_metrics:
89 
90             resource = resource_metrics.resource
91 
92             # It is safe to assume that each entry in data.resource_metrics is
93             # associated with an unique resource.
94             scope_metrics_dict = {}
95 
96             resource_metrics_dict[resource] = scope_metrics_dict
97 
98             for scope_metrics in resource_metrics.scope_metrics:
99 
100                 instrumentation_scope = scope_metrics.scope
101 
102                 # The SDK groups metrics in instrumentation scopes already so
103                 # there is no need to check for existing instrumentation scopes
104                 # here.
105                 pb2_scope_metrics = pb2.ScopeMetrics(
106                     scope=InstrumentationScope(
107                         name=instrumentation_scope.name,
108                         version=instrumentation_scope.version,
109                     )
110                 )
111 
112                 scope_metrics_dict[instrumentation_scope] = pb2_scope_metrics
113 
114                 for metric in scope_metrics.metrics:
115                     pb2_metric = pb2.Metric(
116                         name=metric.name,
117                         description=metric.description,
118                         unit=metric.unit,
119                     )
120 
121                     if isinstance(metric.data, Gauge):
122                         for data_point in metric.data.data_points:
123                             pt = pb2.NumberDataPoint(
124                                 attributes=self._translate_attributes(
125                                     data_point.attributes
126                                 ),
127                                 time_unix_nano=data_point.time_unix_nano,
128                             )
129                             if isinstance(data_point.value, int):
130                                 pt.as_int = data_point.value
131                             else:
132                                 pt.as_double = data_point.value
133                             pb2_metric.gauge.data_points.append(pt)
134 
135                     elif isinstance(metric.data, Histogram):
136                         for data_point in metric.data.data_points:
137                             pt = pb2.HistogramDataPoint(
138                                 attributes=self._translate_attributes(
139                                     data_point.attributes
140                                 ),
141                                 time_unix_nano=data_point.time_unix_nano,
142                                 start_time_unix_nano=(
143                                     data_point.start_time_unix_nano
144                                 ),
145                                 count=data_point.count,
146                                 sum=data_point.sum,
147                                 bucket_counts=data_point.bucket_counts,
148                                 explicit_bounds=data_point.explicit_bounds,
149                             )
150                             pb2_metric.histogram.aggregation_temporality = (
151                                 metric.data.aggregation_temporality
152                             )
153                             pb2_metric.histogram.data_points.append(pt)
154 
155                     elif isinstance(metric.data, Sum):
156                         for data_point in metric.data.data_points:
157                             pt = pb2.NumberDataPoint(
158                                 attributes=self._translate_attributes(
159                                     data_point.attributes
160                                 ),
161                                 start_time_unix_nano=(
162                                     data_point.start_time_unix_nano
163                                 ),
164                                 time_unix_nano=data_point.time_unix_nano,
165                             )
166                             if isinstance(data_point.value, int):
167                                 pt.as_int = data_point.value
168                             else:
169                                 pt.as_double = data_point.value
170                             # note that because sum is a message type, the
171                             # fields must be set individually rather than
172                             # instantiating a pb2.Sum and setting it once
173                             pb2_metric.sum.aggregation_temporality = (
174                                 metric.data.aggregation_temporality
175                             )
176                             pb2_metric.sum.is_monotonic = (
177                                 metric.data.is_monotonic
178                             )
179                             pb2_metric.sum.data_points.append(pt)
180                     else:
181                         _logger.warn(
182                             "unsupported datapoint type %s", metric.point
183                         )
184                         continue
185 
186                     pb2_scope_metrics.metrics.append(pb2_metric)
187 
188         return ExportMetricsServiceRequest(
189             resource_metrics=get_resource_data(
190                 resource_metrics_dict,
191                 pb2.ResourceMetrics,
192                 "metrics",
193             )
194         )
195 
196     def export(
197         self,
198         metrics_data: MetricsData,
199         timeout_millis: float = 10_000,
200         **kwargs,
201     ) -> MetricExportResult:
202         # TODO(#2663): OTLPExporterMixin should pass timeout to gRPC
203         return self._export(metrics_data)
204 
205     def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None:
206         pass
207
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py
--- a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py
+++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py
@@ -146,6 +146,8 @@
                                 sum=data_point.sum,
                                 bucket_counts=data_point.bucket_counts,
                                 explicit_bounds=data_point.explicit_bounds,
+                                max=data_point.max,
+                                min=data_point.min,
                             )
                             pb2_metric.histogram.aggregation_temporality = (
                                 metric.data.aggregation_temporality

{"golden_diff": "diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py\n--- a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py\n+++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py\n@@ -146,6 +146,8 @@\n                                 sum=data_point.sum,\n                                 bucket_counts=data_point.bucket_counts,\n                                 explicit_bounds=data_point.explicit_bounds,\n+                                max=data_point.max,\n+                                min=data_point.min,\n                             )\n                             pb2_metric.histogram.aggregation_temporality = (\n                                 metric.data.aggregation_temporality\n", "issue": "Add min/max fields to Histogram in otlp metrics exporter\nFrom proto https://github.com/open-telemetry/opentelemetry-proto/pull/279\n", "before_files": [{"content": "# Copyright The OpenTelemetry Authors\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom logging import getLogger\nfrom os import environ\nfrom typing import Optional, Sequence\nfrom grpc import ChannelCredentials, Compression\nfrom opentelemetry.exporter.otlp.proto.grpc.exporter import (\n    OTLPExporterMixin,\n    get_resource_data,\n)\nfrom opentelemetry.proto.collector.metrics.v1.metrics_service_pb2 import (\n    ExportMetricsServiceRequest,\n)\nfrom opentelemetry.proto.collector.metrics.v1.metrics_service_pb2_grpc import (\n    MetricsServiceStub,\n)\nfrom opentelemetry.proto.common.v1.common_pb2 import InstrumentationScope\nfrom opentelemetry.proto.metrics.v1 import metrics_pb2 as pb2\nfrom opentelemetry.sdk.environment_variables import (\n    OTEL_EXPORTER_OTLP_METRICS_INSECURE,\n)\nfrom opentelemetry.sdk.metrics.export import (\n    Gauge,\n    Histogram,\n    Metric,\n    Sum,\n)\n\nfrom opentelemetry.sdk.metrics.export import (\n    MetricExporter,\n    MetricExportResult,\n    MetricsData,\n)\n\n_logger = getLogger(__name__)\n\n\nclass OTLPMetricExporter(\n    MetricExporter,\n    OTLPExporterMixin[Metric, ExportMetricsServiceRequest, MetricExportResult],\n):\n    _result = MetricExportResult\n    _stub = MetricsServiceStub\n\n    def __init__(\n        self,\n        endpoint: Optional[str] = None,\n        insecure: Optional[bool] = None,\n        credentials: Optional[ChannelCredentials] = None,\n        headers: Optional[Sequence] = None,\n        timeout: Optional[int] = None,\n        compression: Optional[Compression] = None,\n    ):\n\n        if insecure is None:\n            insecure = environ.get(OTEL_EXPORTER_OTLP_METRICS_INSECURE)\n            if insecure is not None:\n                insecure = insecure.lower() == \"true\"\n\n        super().__init__(\n            **{\n                \"endpoint\": endpoint,\n                \"insecure\": insecure,\n                \"credentials\": credentials,\n                \"headers\": headers,\n                \"timeout\": timeout,\n                \"compression\": compression,\n            }\n        )\n\n    def _translate_data(\n        self, data: MetricsData\n    ) -> ExportMetricsServiceRequest:\n\n        resource_metrics_dict = {}\n\n        for resource_metrics in data.resource_metrics:\n\n            resource = resource_metrics.resource\n\n            # It is safe to assume that each entry in data.resource_metrics is\n            # associated with an unique resource.\n            scope_metrics_dict = {}\n\n            resource_metrics_dict[resource] = scope_metrics_dict\n\n            for scope_metrics in resource_metrics.scope_metrics:\n\n                instrumentation_scope = scope_metrics.scope\n\n                # The SDK groups metrics in instrumentation scopes already so\n                # there is no need to check for existing instrumentation scopes\n                # here.\n                pb2_scope_metrics = pb2.ScopeMetrics(\n                    scope=InstrumentationScope(\n                        name=instrumentation_scope.name,\n                        version=instrumentation_scope.version,\n                    )\n                )\n\n                scope_metrics_dict[instrumentation_scope] = pb2_scope_metrics\n\n                for metric in scope_metrics.metrics:\n                    pb2_metric = pb2.Metric(\n                        name=metric.name,\n                        description=metric.description,\n                        unit=metric.unit,\n                    )\n\n                    if isinstance(metric.data, Gauge):\n                        for data_point in metric.data.data_points:\n                            pt = pb2.NumberDataPoint(\n                                attributes=self._translate_attributes(\n                                    data_point.attributes\n                                ),\n                                time_unix_nano=data_point.time_unix_nano,\n                            )\n                            if isinstance(data_point.value, int):\n                                pt.as_int = data_point.value\n                            else:\n                                pt.as_double = data_point.value\n                            pb2_metric.gauge.data_points.append(pt)\n\n                    elif isinstance(metric.data, Histogram):\n                        for data_point in metric.data.data_points:\n                            pt = pb2.HistogramDataPoint(\n                                attributes=self._translate_attributes(\n                                    data_point.attributes\n                                ),\n                                time_unix_nano=data_point.time_unix_nano,\n                                start_time_unix_nano=(\n                                    data_point.start_time_unix_nano\n                                ),\n                                count=data_point.count,\n                                sum=data_point.sum,\n                                bucket_counts=data_point.bucket_counts,\n                                explicit_bounds=data_point.explicit_bounds,\n                            )\n                            pb2_metric.histogram.aggregation_temporality = (\n                                metric.data.aggregation_temporality\n                            )\n                            pb2_metric.histogram.data_points.append(pt)\n\n                    elif isinstance(metric.data, Sum):\n                        for data_point in metric.data.data_points:\n                            pt = pb2.NumberDataPoint(\n                                attributes=self._translate_attributes(\n                                    data_point.attributes\n                                ),\n                                start_time_unix_nano=(\n                                    data_point.start_time_unix_nano\n                                ),\n                                time_unix_nano=data_point.time_unix_nano,\n                            )\n                            if isinstance(data_point.value, int):\n                                pt.as_int = data_point.value\n                            else:\n                                pt.as_double = data_point.value\n                            # note that because sum is a message type, the\n                            # fields must be set individually rather than\n                            # instantiating a pb2.Sum and setting it once\n                            pb2_metric.sum.aggregation_temporality = (\n                                metric.data.aggregation_temporality\n                            )\n                            pb2_metric.sum.is_monotonic = (\n                                metric.data.is_monotonic\n                            )\n                            pb2_metric.sum.data_points.append(pt)\n                    else:\n                        _logger.warn(\n                            \"unsupported datapoint type %s\", metric.point\n                        )\n                        continue\n\n                    pb2_scope_metrics.metrics.append(pb2_metric)\n\n        return ExportMetricsServiceRequest(\n            resource_metrics=get_resource_data(\n                resource_metrics_dict,\n                pb2.ResourceMetrics,\n                \"metrics\",\n            )\n        )\n\n    def export(\n        self,\n        metrics_data: MetricsData,\n        timeout_millis: float = 10_000,\n        **kwargs,\n    ) -> MetricExportResult:\n        # TODO(#2663): OTLPExporterMixin should pass timeout to gRPC\n        return self._export(metrics_data)\n\n    def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None:\n        pass\n", "path": "exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py"}], "after_files": [{"content": "# Copyright The OpenTelemetry Authors\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom logging import getLogger\nfrom os import environ\nfrom typing import Optional, Sequence\nfrom grpc import ChannelCredentials, Compression\nfrom opentelemetry.exporter.otlp.proto.grpc.exporter import (\n    OTLPExporterMixin,\n    get_resource_data,\n)\nfrom opentelemetry.proto.collector.metrics.v1.metrics_service_pb2 import (\n    ExportMetricsServiceRequest,\n)\nfrom opentelemetry.proto.collector.metrics.v1.metrics_service_pb2_grpc import (\n    MetricsServiceStub,\n)\nfrom opentelemetry.proto.common.v1.common_pb2 import InstrumentationScope\nfrom opentelemetry.proto.metrics.v1 import metrics_pb2 as pb2\nfrom opentelemetry.sdk.environment_variables import (\n    OTEL_EXPORTER_OTLP_METRICS_INSECURE,\n)\nfrom opentelemetry.sdk.metrics.export import (\n    Gauge,\n    Histogram,\n    Metric,\n    Sum,\n)\n\nfrom opentelemetry.sdk.metrics.export import (\n    MetricExporter,\n    MetricExportResult,\n    MetricsData,\n)\n\n_logger = getLogger(__name__)\n\n\nclass OTLPMetricExporter(\n    MetricExporter,\n    OTLPExporterMixin[Metric, ExportMetricsServiceRequest, MetricExportResult],\n):\n    _result = MetricExportResult\n    _stub = MetricsServiceStub\n\n    def __init__(\n        self,\n        endpoint: Optional[str] = None,\n        insecure: Optional[bool] = None,\n        credentials: Optional[ChannelCredentials] = None,\n        headers: Optional[Sequence] = None,\n        timeout: Optional[int] = None,\n        compression: Optional[Compression] = None,\n    ):\n\n        if insecure is None:\n            insecure = environ.get(OTEL_EXPORTER_OTLP_METRICS_INSECURE)\n            if insecure is not None:\n                insecure = insecure.lower() == \"true\"\n\n        super().__init__(\n            **{\n                \"endpoint\": endpoint,\n                \"insecure\": insecure,\n                \"credentials\": credentials,\n                \"headers\": headers,\n                \"timeout\": timeout,\n                \"compression\": compression,\n            }\n        )\n\n    def _translate_data(\n        self, data: MetricsData\n    ) -> ExportMetricsServiceRequest:\n\n        resource_metrics_dict = {}\n\n        for resource_metrics in data.resource_metrics:\n\n            resource = resource_metrics.resource\n\n            # It is safe to assume that each entry in data.resource_metrics is\n            # associated with an unique resource.\n            scope_metrics_dict = {}\n\n            resource_metrics_dict[resource] = scope_metrics_dict\n\n            for scope_metrics in resource_metrics.scope_metrics:\n\n                instrumentation_scope = scope_metrics.scope\n\n                # The SDK groups metrics in instrumentation scopes already so\n                # there is no need to check for existing instrumentation scopes\n                # here.\n                pb2_scope_metrics = pb2.ScopeMetrics(\n                    scope=InstrumentationScope(\n                        name=instrumentation_scope.name,\n                        version=instrumentation_scope.version,\n                    )\n                )\n\n                scope_metrics_dict[instrumentation_scope] = pb2_scope_metrics\n\n                for metric in scope_metrics.metrics:\n                    pb2_metric = pb2.Metric(\n                        name=metric.name,\n                        description=metric.description,\n                        unit=metric.unit,\n                    )\n\n                    if isinstance(metric.data, Gauge):\n                        for data_point in metric.data.data_points:\n                            pt = pb2.NumberDataPoint(\n                                attributes=self._translate_attributes(\n                                    data_point.attributes\n                                ),\n                                time_unix_nano=data_point.time_unix_nano,\n                            )\n                            if isinstance(data_point.value, int):\n                                pt.as_int = data_point.value\n                            else:\n                                pt.as_double = data_point.value\n                            pb2_metric.gauge.data_points.append(pt)\n\n                    elif isinstance(metric.data, Histogram):\n                        for data_point in metric.data.data_points:\n                            pt = pb2.HistogramDataPoint(\n                                attributes=self._translate_attributes(\n                                    data_point.attributes\n                                ),\n                                time_unix_nano=data_point.time_unix_nano,\n                                start_time_unix_nano=(\n                                    data_point.start_time_unix_nano\n                                ),\n                                count=data_point.count,\n                                sum=data_point.sum,\n                                bucket_counts=data_point.bucket_counts,\n                                explicit_bounds=data_point.explicit_bounds,\n                                max=data_point.max,\n                                min=data_point.min,\n                            )\n                            pb2_metric.histogram.aggregation_temporality = (\n                                metric.data.aggregation_temporality\n                            )\n                            pb2_metric.histogram.data_points.append(pt)\n\n                    elif isinstance(metric.data, Sum):\n                        for data_point in metric.data.data_points:\n                            pt = pb2.NumberDataPoint(\n                                attributes=self._translate_attributes(\n                                    data_point.attributes\n                                ),\n                                start_time_unix_nano=(\n                                    data_point.start_time_unix_nano\n                                ),\n                                time_unix_nano=data_point.time_unix_nano,\n                            )\n                            if isinstance(data_point.value, int):\n                                pt.as_int = data_point.value\n                            else:\n                                pt.as_double = data_point.value\n                            # note that because sum is a message type, the\n                            # fields must be set individually rather than\n                            # instantiating a pb2.Sum and setting it once\n                            pb2_metric.sum.aggregation_temporality = (\n                                metric.data.aggregation_temporality\n                            )\n                            pb2_metric.sum.is_monotonic = (\n                                metric.data.is_monotonic\n                            )\n                            pb2_metric.sum.data_points.append(pt)\n                    else:\n                        _logger.warn(\n                            \"unsupported datapoint type %s\", metric.point\n                        )\n                        continue\n\n                    pb2_scope_metrics.metrics.append(pb2_metric)\n\n        return ExportMetricsServiceRequest(\n            resource_metrics=get_resource_data(\n                resource_metrics_dict,\n                pb2.ResourceMetrics,\n                \"metrics\",\n            )\n        )\n\n    def export(\n        self,\n        metrics_data: MetricsData,\n        timeout_millis: float = 10_000,\n        **kwargs,\n    ) -> MetricExportResult:\n        # TODO(#2663): OTLPExporterMixin should pass timeout to gRPC\n        return self._export(metrics_data)\n\n    def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None:\n        pass\n", "path": "exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py"}]}