We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Do not count invalid attributes for dropped
https://github.com/open-telemetry/opentelemetry-python/blob/653207dd2181db1a766a4a703dcda78fd7703bb2/opentelemetry-api/src/opentelemetry/attributes/__init__.py#L175-L183

Existing attribute is deleted and new attribute is counted for dropped.  This should be fixed. Also we can use `.popitem()` which is optimised for deleting item on ends when we need to drop an attribute.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `opentelemetry-api/src/opentelemetry/attributes/__init__.py`
Content:
```
1 # Copyright The OpenTelemetry Authors
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 # type: ignore
15 
16 import logging
17 import threading
18 from collections import OrderedDict
19 from collections.abc import MutableMapping
20 from typing import Optional, Sequence, Union
21 
22 from opentelemetry.util import types
23 
24 # bytes are accepted as a user supplied value for attributes but
25 # decoded to strings internally.
26 _VALID_ATTR_VALUE_TYPES = (bool, str, bytes, int, float)
27 
28 
29 _logger = logging.getLogger(__name__)
30 
31 
32 def _clean_attribute(
33     key: str, value: types.AttributeValue, max_len: Optional[int]
34 ) -> Optional[types.AttributeValue]:
35     """Checks if attribute value is valid and cleans it if required.
36 
37     The function returns the cleaned value or None if the value is not valid.
38 
39     An attribute value is valid if it is either:
40         - A primitive type: string, boolean, double precision floating
41             point (IEEE 754-1985) or integer.
42         - An array of primitive type values. The array MUST be homogeneous,
43             i.e. it MUST NOT contain values of different types.
44 
45     An attribute needs cleansing if:
46         - Its length is greater than the maximum allowed length.
47         - It needs to be encoded/decoded e.g, bytes to strings.
48     """
49 
50     if not (key and isinstance(key, str)):
51         _logger.warning("invalid key `%s`. must be non-empty string.", key)
52         return None
53 
54     if isinstance(value, _VALID_ATTR_VALUE_TYPES):
55         return _clean_attribute_value(value, max_len)
56 
57     if isinstance(value, Sequence):
58         sequence_first_valid_type = None
59         cleaned_seq = []
60 
61         for element in value:
62             # None is considered valid in any sequence
63             if element is None:
64                 cleaned_seq.append(element)
65 
66             element = _clean_attribute_value(element, max_len)
67             # reject invalid elements
68             if element is None:
69                 continue
70 
71             element_type = type(element)
72             # Reject attribute value if sequence contains a value with an incompatible type.
73             if element_type not in _VALID_ATTR_VALUE_TYPES:
74                 _logger.warning(
75                     "Invalid type %s in attribute value sequence. Expected one of "
76                     "%s or None",
77                     element_type.__name__,
78                     [
79                         valid_type.__name__
80                         for valid_type in _VALID_ATTR_VALUE_TYPES
81                     ],
82                 )
83                 return None
84 
85             # The type of the sequence must be homogeneous. The first non-None
86             # element determines the type of the sequence
87             if sequence_first_valid_type is None:
88                 sequence_first_valid_type = element_type
89             # use equality instead of isinstance as isinstance(True, int) evaluates to True
90             elif element_type != sequence_first_valid_type:
91                 _logger.warning(
92                     "Mixed types %s and %s in attribute value sequence",
93                     sequence_first_valid_type.__name__,
94                     type(element).__name__,
95                 )
96                 return None
97 
98             cleaned_seq.append(element)
99 
100         # Freeze mutable sequences defensively
101         return tuple(cleaned_seq)
102 
103     _logger.warning(
104         "Invalid type %s for attribute value. Expected one of %s or a "
105         "sequence of those types",
106         type(value).__name__,
107         [valid_type.__name__ for valid_type in _VALID_ATTR_VALUE_TYPES],
108     )
109     return None
110 
111 
112 def _clean_attribute_value(
113     value: types.AttributeValue, limit: Optional[int]
114 ) -> Union[types.AttributeValue, None]:
115     if value is None:
116         return None
117 
118     if isinstance(value, bytes):
119         try:
120             value = value.decode()
121         except UnicodeDecodeError:
122             _logger.warning("Byte attribute could not be decoded.")
123             return None
124 
125     if limit is not None and isinstance(value, str):
126         value = value[:limit]
127     return value
128 
129 
130 class BoundedAttributes(MutableMapping):
131     """An ordered dict with a fixed max capacity.
132 
133     Oldest elements are dropped when the dict is full and a new element is
134     added.
135     """
136 
137     def __init__(
138         self,
139         maxlen: Optional[int] = None,
140         attributes: types.Attributes = None,
141         immutable: bool = True,
142         max_value_len: Optional[int] = None,
143     ):
144         if maxlen is not None:
145             if not isinstance(maxlen, int) or maxlen < 0:
146                 raise ValueError(
147                     "maxlen must be valid int greater or equal to 0"
148                 )
149         self.maxlen = maxlen
150         self.dropped = 0
151         self.max_value_len = max_value_len
152         self._dict = OrderedDict()  # type: OrderedDict
153         self._lock = threading.Lock()  # type: threading.Lock
154         if attributes:
155             for key, value in attributes.items():
156                 self[key] = value
157         self._immutable = immutable
158 
159     def __repr__(self):
160         return "{}({}, maxlen={})".format(
161             type(self).__name__, dict(self._dict), self.maxlen
162         )
163 
164     def __getitem__(self, key):
165         return self._dict[key]
166 
167     def __setitem__(self, key, value):
168         if getattr(self, "_immutable", False):
169             raise TypeError
170         with self._lock:
171             if self.maxlen is not None and self.maxlen == 0:
172                 self.dropped += 1
173                 return
174 
175             if key in self._dict:
176                 del self._dict[key]
177             elif self.maxlen is not None and len(self._dict) == self.maxlen:
178                 del self._dict[next(iter(self._dict.keys()))]
179                 self.dropped += 1
180 
181             value = _clean_attribute(key, value, self.max_value_len)
182             if value is not None:
183                 self._dict[key] = value
184 
185     def __delitem__(self, key):
186         if getattr(self, "_immutable", False):
187             raise TypeError
188         with self._lock:
189             del self._dict[key]
190 
191     def __iter__(self):
192         with self._lock:
193             return iter(self._dict.copy())
194 
195     def __len__(self):
196         return len(self._dict)
197 
198     def copy(self):
199         return self._dict.copy()
200
```
--- 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/opentelemetry-api/src/opentelemetry/attributes/__init__.py b/opentelemetry-api/src/opentelemetry/attributes/__init__.py
--- a/opentelemetry-api/src/opentelemetry/attributes/__init__.py
+++ b/opentelemetry-api/src/opentelemetry/attributes/__init__.py
@@ -172,14 +172,16 @@
                 self.dropped += 1
                 return
 
-            if key in self._dict:
-                del self._dict[key]
-            elif self.maxlen is not None and len(self._dict) == self.maxlen:
-                del self._dict[next(iter(self._dict.keys()))]
-                self.dropped += 1
-
             value = _clean_attribute(key, value, self.max_value_len)
             if value is not None:
+                if key in self._dict:
+                    del self._dict[key]
+                elif (
+                    self.maxlen is not None and len(self._dict) == self.maxlen
+                ):
+                    self._dict.popitem(last=False)
+                    self.dropped += 1
+
                 self._dict[key] = value
 
     def __delitem__(self, key):

{"golden_diff": "diff --git a/opentelemetry-api/src/opentelemetry/attributes/__init__.py b/opentelemetry-api/src/opentelemetry/attributes/__init__.py\n--- a/opentelemetry-api/src/opentelemetry/attributes/__init__.py\n+++ b/opentelemetry-api/src/opentelemetry/attributes/__init__.py\n@@ -172,14 +172,16 @@\n                 self.dropped += 1\n                 return\n \n-            if key in self._dict:\n-                del self._dict[key]\n-            elif self.maxlen is not None and len(self._dict) == self.maxlen:\n-                del self._dict[next(iter(self._dict.keys()))]\n-                self.dropped += 1\n-\n             value = _clean_attribute(key, value, self.max_value_len)\n             if value is not None:\n+                if key in self._dict:\n+                    del self._dict[key]\n+                elif (\n+                    self.maxlen is not None and len(self._dict) == self.maxlen\n+                ):\n+                    self._dict.popitem(last=False)\n+                    self.dropped += 1\n+\n                 self._dict[key] = value\n \n     def __delitem__(self, key):\n", "issue": "Do not count invalid attributes for dropped\nhttps://github.com/open-telemetry/opentelemetry-python/blob/653207dd2181db1a766a4a703dcda78fd7703bb2/opentelemetry-api/src/opentelemetry/attributes/__init__.py#L175-L183\r\n\r\nExisting attribute is deleted and new attribute is counted for dropped.  This should be fixed. Also we can use `.popitem()` which is optimised for deleting item on ends when we need to drop an attribute.\n", "before_files": [{"content": "# Copyright The OpenTelemetry Authors\n#\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# type: ignore\n\nimport logging\nimport threading\nfrom collections import OrderedDict\nfrom collections.abc import MutableMapping\nfrom typing import Optional, Sequence, Union\n\nfrom opentelemetry.util import types\n\n# bytes are accepted as a user supplied value for attributes but\n# decoded to strings internally.\n_VALID_ATTR_VALUE_TYPES = (bool, str, bytes, int, float)\n\n\n_logger = logging.getLogger(__name__)\n\n\ndef _clean_attribute(\n    key: str, value: types.AttributeValue, max_len: Optional[int]\n) -> Optional[types.AttributeValue]:\n    \"\"\"Checks if attribute value is valid and cleans it if required.\n\n    The function returns the cleaned value or None if the value is not valid.\n\n    An attribute value is valid if it is either:\n        - A primitive type: string, boolean, double precision floating\n            point (IEEE 754-1985) or integer.\n        - An array of primitive type values. The array MUST be homogeneous,\n            i.e. it MUST NOT contain values of different types.\n\n    An attribute needs cleansing if:\n        - Its length is greater than the maximum allowed length.\n        - It needs to be encoded/decoded e.g, bytes to strings.\n    \"\"\"\n\n    if not (key and isinstance(key, str)):\n        _logger.warning(\"invalid key `%s`. must be non-empty string.\", key)\n        return None\n\n    if isinstance(value, _VALID_ATTR_VALUE_TYPES):\n        return _clean_attribute_value(value, max_len)\n\n    if isinstance(value, Sequence):\n        sequence_first_valid_type = None\n        cleaned_seq = []\n\n        for element in value:\n            # None is considered valid in any sequence\n            if element is None:\n                cleaned_seq.append(element)\n\n            element = _clean_attribute_value(element, max_len)\n            # reject invalid elements\n            if element is None:\n                continue\n\n            element_type = type(element)\n            # Reject attribute value if sequence contains a value with an incompatible type.\n            if element_type not in _VALID_ATTR_VALUE_TYPES:\n                _logger.warning(\n                    \"Invalid type %s in attribute value sequence. Expected one of \"\n                    \"%s or None\",\n                    element_type.__name__,\n                    [\n                        valid_type.__name__\n                        for valid_type in _VALID_ATTR_VALUE_TYPES\n                    ],\n                )\n                return None\n\n            # The type of the sequence must be homogeneous. The first non-None\n            # element determines the type of the sequence\n            if sequence_first_valid_type is None:\n                sequence_first_valid_type = element_type\n            # use equality instead of isinstance as isinstance(True, int) evaluates to True\n            elif element_type != sequence_first_valid_type:\n                _logger.warning(\n                    \"Mixed types %s and %s in attribute value sequence\",\n                    sequence_first_valid_type.__name__,\n                    type(element).__name__,\n                )\n                return None\n\n            cleaned_seq.append(element)\n\n        # Freeze mutable sequences defensively\n        return tuple(cleaned_seq)\n\n    _logger.warning(\n        \"Invalid type %s for attribute value. Expected one of %s or a \"\n        \"sequence of those types\",\n        type(value).__name__,\n        [valid_type.__name__ for valid_type in _VALID_ATTR_VALUE_TYPES],\n    )\n    return None\n\n\ndef _clean_attribute_value(\n    value: types.AttributeValue, limit: Optional[int]\n) -> Union[types.AttributeValue, None]:\n    if value is None:\n        return None\n\n    if isinstance(value, bytes):\n        try:\n            value = value.decode()\n        except UnicodeDecodeError:\n            _logger.warning(\"Byte attribute could not be decoded.\")\n            return None\n\n    if limit is not None and isinstance(value, str):\n        value = value[:limit]\n    return value\n\n\nclass BoundedAttributes(MutableMapping):\n    \"\"\"An ordered dict with a fixed max capacity.\n\n    Oldest elements are dropped when the dict is full and a new element is\n    added.\n    \"\"\"\n\n    def __init__(\n        self,\n        maxlen: Optional[int] = None,\n        attributes: types.Attributes = None,\n        immutable: bool = True,\n        max_value_len: Optional[int] = None,\n    ):\n        if maxlen is not None:\n            if not isinstance(maxlen, int) or maxlen < 0:\n                raise ValueError(\n                    \"maxlen must be valid int greater or equal to 0\"\n                )\n        self.maxlen = maxlen\n        self.dropped = 0\n        self.max_value_len = max_value_len\n        self._dict = OrderedDict()  # type: OrderedDict\n        self._lock = threading.Lock()  # type: threading.Lock\n        if attributes:\n            for key, value in attributes.items():\n                self[key] = value\n        self._immutable = immutable\n\n    def __repr__(self):\n        return \"{}({}, maxlen={})\".format(\n            type(self).__name__, dict(self._dict), self.maxlen\n        )\n\n    def __getitem__(self, key):\n        return self._dict[key]\n\n    def __setitem__(self, key, value):\n        if getattr(self, \"_immutable\", False):\n            raise TypeError\n        with self._lock:\n            if self.maxlen is not None and self.maxlen == 0:\n                self.dropped += 1\n                return\n\n            if key in self._dict:\n                del self._dict[key]\n            elif self.maxlen is not None and len(self._dict) == self.maxlen:\n                del self._dict[next(iter(self._dict.keys()))]\n                self.dropped += 1\n\n            value = _clean_attribute(key, value, self.max_value_len)\n            if value is not None:\n                self._dict[key] = value\n\n    def __delitem__(self, key):\n        if getattr(self, \"_immutable\", False):\n            raise TypeError\n        with self._lock:\n            del self._dict[key]\n\n    def __iter__(self):\n        with self._lock:\n            return iter(self._dict.copy())\n\n    def __len__(self):\n        return len(self._dict)\n\n    def copy(self):\n        return self._dict.copy()\n", "path": "opentelemetry-api/src/opentelemetry/attributes/__init__.py"}], "after_files": [{"content": "# Copyright The OpenTelemetry Authors\n#\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# type: ignore\n\nimport logging\nimport threading\nfrom collections import OrderedDict\nfrom collections.abc import MutableMapping\nfrom typing import Optional, Sequence, Union\n\nfrom opentelemetry.util import types\n\n# bytes are accepted as a user supplied value for attributes but\n# decoded to strings internally.\n_VALID_ATTR_VALUE_TYPES = (bool, str, bytes, int, float)\n\n\n_logger = logging.getLogger(__name__)\n\n\ndef _clean_attribute(\n    key: str, value: types.AttributeValue, max_len: Optional[int]\n) -> Optional[types.AttributeValue]:\n    \"\"\"Checks if attribute value is valid and cleans it if required.\n\n    The function returns the cleaned value or None if the value is not valid.\n\n    An attribute value is valid if it is either:\n        - A primitive type: string, boolean, double precision floating\n            point (IEEE 754-1985) or integer.\n        - An array of primitive type values. The array MUST be homogeneous,\n            i.e. it MUST NOT contain values of different types.\n\n    An attribute needs cleansing if:\n        - Its length is greater than the maximum allowed length.\n        - It needs to be encoded/decoded e.g, bytes to strings.\n    \"\"\"\n\n    if not (key and isinstance(key, str)):\n        _logger.warning(\"invalid key `%s`. must be non-empty string.\", key)\n        return None\n\n    if isinstance(value, _VALID_ATTR_VALUE_TYPES):\n        return _clean_attribute_value(value, max_len)\n\n    if isinstance(value, Sequence):\n        sequence_first_valid_type = None\n        cleaned_seq = []\n\n        for element in value:\n            # None is considered valid in any sequence\n            if element is None:\n                cleaned_seq.append(element)\n\n            element = _clean_attribute_value(element, max_len)\n            # reject invalid elements\n            if element is None:\n                continue\n\n            element_type = type(element)\n            # Reject attribute value if sequence contains a value with an incompatible type.\n            if element_type not in _VALID_ATTR_VALUE_TYPES:\n                _logger.warning(\n                    \"Invalid type %s in attribute value sequence. Expected one of \"\n                    \"%s or None\",\n                    element_type.__name__,\n                    [\n                        valid_type.__name__\n                        for valid_type in _VALID_ATTR_VALUE_TYPES\n                    ],\n                )\n                return None\n\n            # The type of the sequence must be homogeneous. The first non-None\n            # element determines the type of the sequence\n            if sequence_first_valid_type is None:\n                sequence_first_valid_type = element_type\n            # use equality instead of isinstance as isinstance(True, int) evaluates to True\n            elif element_type != sequence_first_valid_type:\n                _logger.warning(\n                    \"Mixed types %s and %s in attribute value sequence\",\n                    sequence_first_valid_type.__name__,\n                    type(element).__name__,\n                )\n                return None\n\n            cleaned_seq.append(element)\n\n        # Freeze mutable sequences defensively\n        return tuple(cleaned_seq)\n\n    _logger.warning(\n        \"Invalid type %s for attribute value. Expected one of %s or a \"\n        \"sequence of those types\",\n        type(value).__name__,\n        [valid_type.__name__ for valid_type in _VALID_ATTR_VALUE_TYPES],\n    )\n    return None\n\n\ndef _clean_attribute_value(\n    value: types.AttributeValue, limit: Optional[int]\n) -> Union[types.AttributeValue, None]:\n    if value is None:\n        return None\n\n    if isinstance(value, bytes):\n        try:\n            value = value.decode()\n        except UnicodeDecodeError:\n            _logger.warning(\"Byte attribute could not be decoded.\")\n            return None\n\n    if limit is not None and isinstance(value, str):\n        value = value[:limit]\n    return value\n\n\nclass BoundedAttributes(MutableMapping):\n    \"\"\"An ordered dict with a fixed max capacity.\n\n    Oldest elements are dropped when the dict is full and a new element is\n    added.\n    \"\"\"\n\n    def __init__(\n        self,\n        maxlen: Optional[int] = None,\n        attributes: types.Attributes = None,\n        immutable: bool = True,\n        max_value_len: Optional[int] = None,\n    ):\n        if maxlen is not None:\n            if not isinstance(maxlen, int) or maxlen < 0:\n                raise ValueError(\n                    \"maxlen must be valid int greater or equal to 0\"\n                )\n        self.maxlen = maxlen\n        self.dropped = 0\n        self.max_value_len = max_value_len\n        self._dict = OrderedDict()  # type: OrderedDict\n        self._lock = threading.Lock()  # type: threading.Lock\n        if attributes:\n            for key, value in attributes.items():\n                self[key] = value\n        self._immutable = immutable\n\n    def __repr__(self):\n        return \"{}({}, maxlen={})\".format(\n            type(self).__name__, dict(self._dict), self.maxlen\n        )\n\n    def __getitem__(self, key):\n        return self._dict[key]\n\n    def __setitem__(self, key, value):\n        if getattr(self, \"_immutable\", False):\n            raise TypeError\n        with self._lock:\n            if self.maxlen is not None and self.maxlen == 0:\n                self.dropped += 1\n                return\n\n            value = _clean_attribute(key, value, self.max_value_len)\n            if value is not None:\n                if key in self._dict:\n                    del self._dict[key]\n                elif (\n                    self.maxlen is not None and len(self._dict) == self.maxlen\n                ):\n                    self._dict.popitem(last=False)\n                    self.dropped += 1\n\n                self._dict[key] = value\n\n    def __delitem__(self, key):\n        if getattr(self, \"_immutable\", False):\n            raise TypeError\n        with self._lock:\n            del self._dict[key]\n\n    def __iter__(self):\n        with self._lock:\n            return iter(self._dict.copy())\n\n    def __len__(self):\n        return len(self._dict)\n\n    def copy(self):\n        return self._dict.copy()\n", "path": "opentelemetry-api/src/opentelemetry/attributes/__init__.py"}]}