|
10 | 10 |
|
11 | 11 | from haystack import AsyncPipeline, Pipeline, component |
12 | 12 | from haystack.core.serialization import generate_qualified_class_name |
13 | | -from haystack.telemetry._telemetry import pipeline_running |
| 13 | +from haystack.telemetry._telemetry import pipeline_running, tutorial_running |
14 | 14 | from haystack.utils.auth import Secret, TokenSecret |
15 | 15 |
|
16 | 16 |
|
@@ -114,3 +114,27 @@ def run(self): |
114 | 114 | with caplog.at_level(logging.DEBUG): |
115 | 115 | pipeline_running(pipe) |
116 | 116 | assert "TypeError: Telemetry data for component my_component must be a dictionary" in caplog.text |
| 117 | + |
| 118 | + |
| 119 | +def test_send_telemetry_preserves_function_metadata(): |
| 120 | + """ |
| 121 | + Regression test for https://github.com/deepset-ai/haystack/issues/11568. |
| 122 | +
|
| 123 | + The ``send_telemetry`` decorator must use ``functools.wraps`` so that decorated functions such as |
| 124 | + ``pipeline_running`` and ``tutorial_running`` keep their own metadata (``__name__``, ``__doc__`` and |
| 125 | + ``__annotations__``) instead of exposing the ``send_telemetry_wrapper`` wrapper's. |
| 126 | + """ |
| 127 | + # ``__name__`` comes from the wrapped function, not the wrapper. |
| 128 | + assert pipeline_running.__name__ == "pipeline_running" |
| 129 | + assert tutorial_running.__name__ == "tutorial_running" |
| 130 | + |
| 131 | + # ``__doc__`` is preserved. |
| 132 | + assert pipeline_running.__doc__ is not None |
| 133 | + assert "Collects telemetry data for a pipeline run" in pipeline_running.__doc__ |
| 134 | + |
| 135 | + # ``__annotations__`` are preserved, e.g. the wrapped functions' parameters. |
| 136 | + assert "pipeline" in pipeline_running.__annotations__ |
| 137 | + assert "tutorial_id" in tutorial_running.__annotations__ |
| 138 | + |
| 139 | + # ``functools.wraps`` also exposes the undecorated function through ``__wrapped__``. |
| 140 | + assert pipeline_running.__wrapped__.__name__ == "pipeline_running" |
0 commit comments