arize-phoenix 2.11.1__py3-none-any.whl → 3.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of arize-phoenix might be problematic. Click here for more details.

phoenix/trace/otel.py CHANGED
@@ -19,6 +19,7 @@ from typing import (
19
19
  cast,
20
20
  )
21
21
 
22
+ import numpy as np
22
23
  import opentelemetry.proto.trace.v1.trace_pb2 as otlp
23
24
  from opentelemetry.proto.common.v1.common_pb2 import AnyValue, ArrayValue, KeyValue
24
25
  from opentelemetry.util.types import Attributes, AttributeValue
@@ -320,7 +321,11 @@ def encode(span: Span) -> otlp.Span:
320
321
  attributes[key] = json.dumps(value)
321
322
  else:
322
323
  attributes.update(_flatten_mapping(value, key))
323
- elif not isinstance(value, str) and isinstance(value, Sequence) and _has_mapping(value):
324
+ elif (
325
+ not isinstance(value, str)
326
+ and (isinstance(value, Sequence) or isinstance(value, np.ndarray))
327
+ and _has_mapping(value)
328
+ ):
324
329
  attributes.pop(key, None)
325
330
  attributes.update(_flatten_sequence(value, key))
326
331
 
@@ -413,6 +418,8 @@ def _encode_attributes(attributes: Attributes) -> Iterator[KeyValue]:
413
418
  if not attributes:
414
419
  return
415
420
  for key, value in attributes.items():
421
+ if isinstance(value, np.ndarray):
422
+ value = value.tolist()
416
423
  yield KeyValue(key=key, value=_encode_value(value))
417
424
 
418
425
 
phoenix/trace/tracer.py CHANGED
@@ -1,122 +1,99 @@
1
+ """
2
+ This module is defunct and will be removed in the future. It's currently
3
+ maintaining a dummy class to avoid breaking any import code.
4
+ """
1
5
  import logging
2
- from datetime import datetime
3
- from threading import RLock
4
- from typing import Any, Callable, Iterator, List, Optional, Protocol
5
- from uuid import uuid4
6
-
7
- from .schemas import (
8
- Span,
9
- SpanAttributes,
10
- SpanContext,
11
- SpanConversationAttributes,
12
- SpanEvent,
13
- SpanID,
14
- SpanKind,
15
- SpanStatusCode,
16
- TraceID,
17
- )
6
+ import sys
7
+ from typing import Any, Iterator, Protocol
8
+
9
+ from phoenix.trace.exporter import HttpExporter
18
10
 
19
11
  logger = logging.getLogger(__name__)
20
- logger.addHandler(logging.NullHandler())
21
12
 
22
13
 
23
14
  class SpanExporter(Protocol):
24
- def export(self, span: Span) -> None:
15
+ def export(self, _: Any) -> None:
25
16
  ...
26
17
 
27
18
 
19
+ _DEFUNCT_MSG = (
20
+ "`phoenix.trace.tracer.Tracer` is defunct in the current version of Phoenix, "
21
+ "and will be removed in the future. For a migration guide, see "
22
+ "https://github.com/Arize-ai/phoenix/blob/main/MIGRATION.md"
23
+ )
24
+
25
+ _USE_ENV_MSG = """
26
+ Setting the Phoenix endpoint via HttpExporter() is no longer supported.
27
+ Please use environment variables instead:
28
+ - os.environ["PHOENIX_HOST"] = "127.0.0.1"
29
+ - os.environ["PHOENIX_PORT"] = "54321"
30
+ - os.environ["PHOENIX_COLLECTOR_ENDPOINT"] = "http://127.0.0.1:54321
31
+ For a migration guide, see https://github.com/Arize-ai/phoenix/blob/main/MIGRATION.md
32
+ """
33
+
34
+ _ON_APPEND_DEPRECATION_MSG = (
35
+ "OpenInference has been updated for full OpenTelemetry compliance. The ability to set "
36
+ "`on_append` callbacks are removed. For a migration guide, see "
37
+ "https://github.com/Arize-ai/phoenix/blob/main/MIGRATION.md"
38
+ )
39
+
40
+
41
+ def _show_deprecation_warnings(obj: object, *args: Any, **kwargs: Any) -> None:
42
+ if args or kwargs:
43
+ logger.warning(
44
+ f"{obj.__class__.__name__}() no longer takes any arguments. "
45
+ "The arguments provided has been ignored. For a migration guide, "
46
+ "see https://github.com/Arize-ai/phoenix/blob/main/MIGRATION.md"
47
+ )
48
+ if any(callable(arg) for arg in args) or "callback" in kwargs:
49
+ logger.warning(
50
+ "The `callback` argument is defunct and no longer has any effect. "
51
+ "If you need access to spans for processing, some options include "
52
+ "exporting spans from Phoenix or adding a SpanProcessor to the "
53
+ "OpenTelemetry TracerProvider. For a migration guide, "
54
+ "see https://github.com/Arize-ai/phoenix/blob/main/MIGRATION.md"
55
+ )
56
+ if any(isinstance(arg, HttpExporter) for arg in args):
57
+ logger.warning(_USE_ENV_MSG)
58
+
59
+
28
60
  class Tracer:
29
- """
30
- Tracer creates spans containing more information about what is happening for
31
- a given operation, such as a request in a service.
32
-
33
- OpenTelemetry Inspiration:
34
- https://opentelemetry.io/docs/concepts/signals/traces/#tracer
35
- """
36
-
37
- span_buffer: List[Span]
38
- on_append: Optional[Callable[[List[Span]], None]]
39
-
40
- def __init__(
41
- self,
42
- exporter: Optional[SpanExporter] = None,
43
- on_append: Optional[Callable[[List[Span]], None]] = None,
44
- *args: Any,
45
- **kwargs: Any,
46
- ):
47
- """
48
- Create a new Tracer. A Tracer's main purpose is to create spans.
49
- Serialization should be handled by a separate component.
50
-
51
- Args:
52
- on_append:
53
- A callback function that will be called when a span is
54
- created and appended to the buffer. This is useful for
55
- serializing data to a file or sending it to a remote server.
56
- """
57
- self.span_buffer = []
58
- self.on_append = on_append
59
- self._exporter: Optional[SpanExporter] = exporter
60
- self._lock = RLock()
61
- super().__init__(*args, **kwargs)
62
-
63
- def create_span(
64
- self,
65
- name: str,
66
- span_kind: SpanKind,
67
- start_time: datetime,
68
- end_time: Optional[datetime] = None,
69
- status_code: SpanStatusCode = SpanStatusCode.UNSET,
70
- status_message: Optional[str] = "",
71
- parent_id: Optional[SpanID] = None,
72
- trace_id: Optional[TraceID] = None,
73
- attributes: Optional[SpanAttributes] = None,
74
- events: Optional[List[SpanEvent]] = None,
75
- conversation: Optional[SpanConversationAttributes] = None,
76
- span_id: Optional[SpanID] = None,
77
- ) -> Span:
78
- """
79
- create_span creates a new span with the given name and options.
80
- """
81
- # If no trace_id is provided, generate a new one
82
- if trace_id is None:
83
- trace_id = TraceID(uuid4())
84
-
85
- # If no attributes are provided, create an empty dict
86
- if attributes is None:
87
- attributes = {}
88
-
89
- # If no events are provided, create an empty list
90
- if events is None:
91
- events = []
92
-
93
- span = Span(
94
- name=name,
95
- context=SpanContext(trace_id=trace_id, span_id=span_id or SpanID(uuid4())),
96
- span_kind=span_kind,
97
- parent_id=parent_id,
98
- start_time=start_time,
99
- end_time=end_time,
100
- status_code=status_code,
101
- status_message=status_message if status_message is not None else "",
102
- attributes=attributes,
103
- events=events,
104
- conversation=conversation,
61
+ _exporter: Any
62
+
63
+ def __init__(self, exporter: Any = None, on_append: Any = None) -> None:
64
+ logger.warning(_DEFUNCT_MSG)
65
+ if exporter is not None:
66
+ logger.warning(_USE_ENV_MSG)
67
+ if on_append is not None:
68
+ logger.warning(_ON_APPEND_DEPRECATION_MSG)
69
+
70
+ def create_span(self, *_: Any, **__: Any) -> Any:
71
+ logger.warning(_DEFUNCT_MSG)
72
+
73
+ def get_spans(self) -> Iterator[Any]:
74
+ logger.warning(_DEFUNCT_MSG)
75
+ logger.warning(
76
+ ".get_spans() is a defunct method that does nothing. "
77
+ "It will be removed in the future. For a migration guide, "
78
+ "see https://github.com/Arize-ai/phoenix/blob/main/MIGRATION.md"
105
79
  )
80
+ return iter(())
81
+
106
82
 
107
- if self._exporter:
108
- self._exporter.export(span)
83
+ class _DefunctModule:
84
+ __all__ = ("Tracer", "SpanExporter")
109
85
 
110
- with self._lock:
111
- self.span_buffer.append(span)
86
+ def __getattr__(self, name: str) -> Any:
87
+ if name == "Tracer":
88
+ logger.warning(_DEFUNCT_MSG)
89
+ return Tracer
90
+ if name == "SpanExporter":
91
+ logger.warning("`SpanExporter` is defunct and will be removed in the future.")
92
+ return SpanExporter
93
+ if name == "_show_deprecation_warnings":
94
+ return _show_deprecation_warnings
95
+ raise AttributeError(f"module {__name__} has no attribute {name}")
112
96
 
113
- if self.on_append is not None:
114
- self.on_append(self.span_buffer)
115
- return span
116
97
 
117
- def get_spans(self) -> Iterator[Span]:
118
- """
119
- Returns the spans stored in the tracer. This is useful if you are running
120
- in a notebook environment and you want to inspect the spans.
121
- """
122
- yield from self.span_buffer
98
+ # See e.g. https://stackoverflow.com/a/7668273
99
+ sys.modules[__name__] = _DefunctModule() # type: ignore
phoenix/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2.11.1"
1
+ __version__ = "3.0.1"
@@ -1,92 +0,0 @@
1
- from datetime import datetime, timezone
2
- from typing import TYPE_CHECKING, Generator, List
3
-
4
- from llama_index.callbacks.schema import TIMESTAMP_FORMAT
5
- from llama_index.response.schema import StreamingResponse
6
-
7
- from phoenix.trace.schemas import SpanID, SpanKind, SpanStatusCode
8
- from phoenix.trace.semantic_conventions import OUTPUT_VALUE
9
- from phoenix.trace.tracer import Tracer
10
-
11
- if TYPE_CHECKING:
12
- from phoenix.trace.llama_index.callback import CBEventData
13
-
14
- _LOCAL_TZINFO = datetime.now().astimezone().tzinfo
15
-
16
-
17
- class TokenGenInstrumentor:
18
- def __init__(
19
- self, stream: Generator[str, None, None], tracer: Tracer, event_data: "CBEventData"
20
- ):
21
- self._stream = stream
22
- self._token_stream: List[str] = []
23
- self._finished = False
24
- self._tracer = tracer
25
- self._event_data = event_data
26
-
27
- def __iter__(self) -> "TokenGenInstrumentor":
28
- return self
29
-
30
- def __next__(self) -> str:
31
- if self._finished:
32
- raise StopIteration
33
-
34
- try:
35
- value = next(self._stream)
36
- self._token_stream.append(value)
37
- return value
38
- except StopIteration:
39
- self._finished = True
40
- self._handle_end_of_stream()
41
- raise
42
-
43
- def _handle_end_of_stream(self) -> None:
44
- # Handle the end-of-stream logic here
45
- parent_id = self._event_data.parent_id
46
- output = "".join(self._token_stream)
47
- start_event = self._event_data.start_event
48
- if start_event:
49
- start_time = _timestamp_to_tz_aware_datetime(start_event.time)
50
- else:
51
- start_time = datetime.now(timezone.utc)
52
- attributes = self._event_data.attributes
53
- attributes.update({OUTPUT_VALUE: output})
54
- self._tracer.create_span(
55
- name=self._event_data.name if self._event_data.name else "",
56
- span_kind=SpanKind.LLM,
57
- trace_id=self._event_data.trace_id,
58
- start_time=start_time,
59
- end_time=datetime.now(timezone.utc),
60
- status_code=SpanStatusCode.OK,
61
- status_message="",
62
- parent_id=SpanID(parent_id) if parent_id else None,
63
- attributes=self._event_data.attributes,
64
- events=[],
65
- conversation=None,
66
- span_id=SpanID(self._event_data.span_id),
67
- )
68
-
69
-
70
- def instrument_streaming_response(
71
- response: StreamingResponse,
72
- tracer: Tracer,
73
- event_data: "CBEventData",
74
- ) -> StreamingResponse:
75
- if response.response_gen is not None:
76
- response.response_gen = TokenGenInstrumentor(response.response_gen, tracer, event_data) # type: ignore
77
- return response
78
-
79
-
80
- def _timestamp_to_tz_aware_datetime(timestamp: str) -> datetime:
81
- """Converts a timestamp string to a timezone-aware datetime."""
82
- return _tz_naive_to_tz_aware_datetime(_timestamp_to_tz_naive_datetime(timestamp))
83
-
84
-
85
- def _timestamp_to_tz_naive_datetime(timestamp: str) -> datetime:
86
- """Converts a timestamp string to a timezone-naive datetime."""
87
- return datetime.strptime(timestamp, TIMESTAMP_FORMAT)
88
-
89
-
90
- def _tz_naive_to_tz_aware_datetime(timestamp: datetime) -> datetime:
91
- """Converts a timezone-naive datetime to a timezone-aware datetime."""
92
- return timestamp.replace(tzinfo=_LOCAL_TZINFO)