|
1 |
| -from collections.abc import Generator |
2 | 1 | import sentry_sdk
|
3 | 2 | from sentry_sdk.consts import OP, SPANDATA
|
4 | 3 | from sentry_sdk.integrations import _check_minimum_version, Integration, DidNotEnable
|
|
12 | 11 | # without introducing a hard dependency on `typing_extensions`
|
13 | 12 | # from: https://stackoverflow.com/a/71944042/300572
|
14 | 13 | if TYPE_CHECKING:
|
15 |
| - from typing import ParamSpec, Callable |
| 14 | + from collections.abc import Iterator |
| 15 | + from typing import Any, ParamSpec, Callable |
16 | 16 | else:
|
17 | 17 | # Fake ParamSpec
|
18 | 18 | class ParamSpec:
|
@@ -127,26 +127,37 @@ def _inner_end(*args: P.args, **kwargs: P.kwargs) -> T:
|
127 | 127 | return _inner_end
|
128 | 128 |
|
129 | 129 |
|
130 |
| -def _wrap_send_data(): |
| 130 | +def _wrap_send_data() -> None: |
131 | 131 | original_send_data = clickhouse_driver.client.Client.send_data
|
132 | 132 |
|
133 |
| - def _inner_send_data( |
134 |
| - self: clickhouse_driver.client.Client, |
135 |
| - sample_block: object, |
136 |
| - data: list | tuple | Generator, |
137 |
| - types_check: bool = False, |
138 |
| - columnar: bool = False, |
139 |
| - *args, |
140 |
| - **kwargs, |
141 |
| - ) -> int: |
| 133 | + def _inner_send_data( # type: ignore[no-untyped-def] # clickhouse-driver does not type send_data |
| 134 | + self, sample_block, data, types_check=False, columnar=False, *args, **kwargs |
| 135 | + ): |
142 | 136 | span = getattr(self.connection, "_sentry_span", None)
|
143 | 137 |
|
144 | 138 | if span is not None:
|
145 | 139 | _set_db_data(span, self.connection)
|
146 | 140 |
|
147 | 141 | if should_send_default_pii():
|
148 | 142 | db_params = span._data.get("db.params", [])
|
149 |
| - db_params.extend(data) |
| 143 | + |
| 144 | + if isinstance(data, (list, tuple)): |
| 145 | + db_params.extend(data) |
| 146 | + |
| 147 | + else: # data is a generic iterator |
| 148 | + orig_data = data |
| 149 | + |
| 150 | + # Wrap the generator to add items to db.params as they are yielded. |
| 151 | + # This allows us to send the params to Sentry without needing to allocate |
| 152 | + # memory for the entire generator at once. |
| 153 | + def wrapped_generator() -> "Iterator[Any]": |
| 154 | + for item in orig_data: |
| 155 | + db_params.append(item) |
| 156 | + yield item |
| 157 | + |
| 158 | + # Replace the original iterator with the wrapped one. |
| 159 | + data = wrapped_generator() |
| 160 | + |
150 | 161 | span.set_data("db.params", db_params)
|
151 | 162 |
|
152 | 163 | return original_send_data(
|
|
0 commit comments