scale-gp-beta 0.1.0a21__py3-none-any.whl → 0.1.0a23__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.
scale_gp_beta/_version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
3
  __title__ = "scale_gp_beta"
4
- __version__ = "0.1.0-alpha.21" # x-release-please-version
4
+ __version__ = "0.1.0-alpha.23" # x-release-please-version
@@ -59,18 +59,18 @@ class BaseSpan:
59
59
  metadata: Optional[SpanMetadataParam] = None,
60
60
  span_type: SpanTypeLiterals = "STANDALONE"
61
61
  ):
62
- self.name = name
63
- self.trace_id = trace_id or "no_trace_id"
64
- self.group_id = group_id
65
- self.span_id: str = span_id or generate_span_id()
66
- self.parent_span_id = parent_span_id
62
+ self._name = name
63
+ self._trace_id: str = trace_id or "no_trace_id"
64
+ self._group_id = group_id
65
+ self._span_id: str = span_id or generate_span_id()
66
+ self._parent_span_id = parent_span_id
67
67
  self.start_time: Optional[str] = None
68
68
  self.end_time: Optional[str] = None
69
- self.input: SpanInputParam = input or {}
70
- self.output: SpanOutputParam = output or {}
71
- self.metadata: SpanMetadataParam = metadata or {}
72
- self.span_type: SpanTypeLiterals = span_type
73
- self.status: SpanStatusLiterals = "SUCCESS"
69
+ self._input: SpanInputParam = input or {}
70
+ self._output: SpanOutputParam = output or {}
71
+ self._metadata: SpanMetadataParam = metadata or {}
72
+ self._span_type: SpanTypeLiterals = span_type
73
+ self._status: SpanStatusLiterals = "SUCCESS"
74
74
  self._queue_manager = queue_manager
75
75
 
76
76
  self._contextvar_token: Optional[contextvars.Token[Optional[BaseSpan]]] = None
@@ -84,6 +84,73 @@ class BaseSpan:
84
84
  def flush(self, blocking: bool = True) -> None:
85
85
  pass
86
86
 
87
+ @property
88
+ def name(self) -> str:
89
+ return self._name
90
+
91
+ @property
92
+ def trace_id(self) -> str:
93
+ return self._trace_id
94
+
95
+ @property
96
+ def group_id(self) -> Optional[str]:
97
+ return self._group_id
98
+
99
+ @property
100
+ def span_id(self) -> str:
101
+ return self._span_id
102
+
103
+ @property
104
+ def parent_span_id(self) -> Optional[str]:
105
+ return self._parent_span_id
106
+
107
+ @property
108
+ def status(self) -> SpanStatusLiterals:
109
+ return self._status
110
+
111
+ @property
112
+ def span_type(self) -> SpanTypeLiterals:
113
+ return self._span_type
114
+
115
+ # with setters
116
+ @property
117
+ def metadata(self) -> SpanMetadataParam:
118
+ return self._metadata
119
+
120
+ @metadata.setter
121
+ def metadata(self, value: SpanMetadataParam) -> None:
122
+ self._metadata = value
123
+
124
+ @property
125
+ def input(self) -> SpanInputParam:
126
+ return self._input
127
+
128
+ @input.setter
129
+ def input(self, value: SpanInputParam) -> None:
130
+ self._input = value
131
+
132
+ @property
133
+ def output(self) -> SpanOutputParam:
134
+ return self._output
135
+
136
+ @output.setter
137
+ def output(self, value: SpanOutputParam) -> None:
138
+ self._output = value
139
+
140
+ def set_error(
141
+ self,
142
+ error_type: Optional[str] = None,
143
+ error_message: Optional[str] = None,
144
+ exception: Optional[BaseException] = None,
145
+ ) -> None:
146
+ # Naively record details in metadata for now, note that error capture only supported in context manager
147
+ exception_type = type(exception).__name__ if exception else None
148
+ exception_message = str(exception) if exception else None
149
+ self._status = "ERROR"
150
+ self.metadata["error"] = True
151
+ self.metadata["error_type"] = error_type or exception_type
152
+ self.metadata["error_message"] = error_message or exception_message
153
+
87
154
  def __enter__(self) -> BaseSpan:
88
155
  self.start()
89
156
  return self
@@ -94,13 +161,9 @@ class BaseSpan:
94
161
  exc_val: Optional[BaseException],
95
162
  exc_tb: Optional[TracebackType]
96
163
  ) -> None:
97
- # Naively record details in metadata for now, note that error capture only supported in context manager
98
164
  # TODO: support error observations when using direct span.start() and span.end()
99
165
  if exc_type is not None:
100
- self.metadata["error"] = True
101
- self.metadata["error.type"] = exc_type.__name__
102
- self.metadata["error.message"] = str(exc_val)
103
- self.status = "ERROR"
166
+ self.set_error(exception=exc_val)
104
167
  self.end()
105
168
 
106
169
  def to_request_params(self) -> SpanCreateRequest:
@@ -203,7 +266,7 @@ class Span(BaseSpan):
203
266
  ):
204
267
  super().__init__(name, trace_id, queue_manager, span_id, parent_span_id, group_id, input, output, metadata, span_type)
205
268
  self._queue_manager: TraceQueueManager = queue_manager
206
- self.trace_id: str = trace_id
269
+ self._trace_id: str = trace_id
207
270
 
208
271
  @override
209
272
  def flush(self, blocking: bool = True) -> None:
@@ -4,23 +4,30 @@ from types import TracebackType
4
4
  from typing import Type, Optional
5
5
  from typing_extensions import override
6
6
 
7
- from .span import Span, NoOpSpan
7
+ from .span import Span, BaseSpan, NoOpSpan
8
8
  from .util import generate_trace_id
9
9
  from .scope import Scope
10
- from .types import SpanInputParam, SpanOutputParam, SpanTypeLiterals, SpanMetadataParam
10
+ from .types import SpanInputParam, SpanOutputParam, SpanTypeLiterals, SpanMetadataParam, SpanStatusLiterals
11
11
  from .trace_queue_manager import TraceQueueManager
12
12
 
13
13
  log: logging.Logger = logging.getLogger(__name__)
14
14
 
15
15
 
16
16
  class BaseTrace:
17
- def __init__(self, queue_manager: Optional[TraceQueueManager], trace_id: Optional[str] = None):
18
- self.trace_id = trace_id or generate_trace_id()
17
+ def __init__(
18
+ self,
19
+ queue_manager: Optional[TraceQueueManager],
20
+ root_span: BaseSpan,
21
+ trace_id: str
22
+ ) -> None:
23
+ self._trace_id = trace_id
19
24
  self.queue_manager = queue_manager
20
25
 
21
26
  self._in_progress = False
22
27
  self._contextvar_token: Optional[contextvars.Token[Optional[BaseTrace]]] = None
23
28
 
29
+ self.root_span = root_span
30
+
24
31
  def start(self) -> None:
25
32
  pass
26
33
 
@@ -30,8 +37,62 @@ class BaseTrace:
30
37
  def flush(self, blocking: bool = True) -> None:
31
38
  pass
32
39
 
40
+ @property
41
+ def metadata(self) -> SpanMetadataParam:
42
+ return self.root_span.metadata
43
+
44
+ @metadata.setter
45
+ def metadata(self, value: SpanMetadataParam) -> None:
46
+ self.root_span.metadata = value
47
+
48
+ @property
49
+ def input(self) -> SpanInputParam:
50
+ return self.root_span.input
51
+
52
+ @input.setter
53
+ def input(self, value: SpanInputParam) -> None:
54
+ self.root_span.input = value
55
+
56
+ @property
57
+ def output(self) -> SpanOutputParam:
58
+ return self.root_span.output
59
+
60
+ @output.setter
61
+ def output(self, value: SpanOutputParam) -> None:
62
+ self.root_span.output = value
63
+
64
+ # no setters
65
+ @property
66
+ def name(self) -> Optional[str]:
67
+ return self.root_span.name
68
+
69
+ @property
70
+ def span_id(self) -> Optional[str]:
71
+ return self.root_span.span_id
72
+
73
+ @property
74
+ def trace_id(self) -> Optional[str]:
75
+ return self._trace_id
76
+
77
+ @property
33
78
  def group_id(self) -> Optional[str]:
34
- return None
79
+ return self.root_span.group_id
80
+
81
+ @property
82
+ def span_type(self) -> SpanTypeLiterals:
83
+ return self.root_span.span_type
84
+
85
+ @property
86
+ def status(self) -> SpanStatusLiterals:
87
+ return self.root_span.status
88
+
89
+ def set_error(
90
+ self,
91
+ error_type: Optional[str] = None,
92
+ error_message: Optional[str] = None,
93
+ exception: Optional[BaseException] = None,
94
+ ) -> None:
95
+ self.root_span.set_error(error_type=error_type, error_message=error_message, exception=exception)
35
96
 
36
97
  def __enter__(self) -> "BaseTrace":
37
98
  self.start()
@@ -47,7 +108,12 @@ class BaseTrace:
47
108
 
48
109
  @override
49
110
  def __repr__(self) -> str:
50
- return f"{self.__class__.__name__}(trace_id='{self.trace_id})"
111
+ return (
112
+ f"{self.__class__.__name__}("
113
+ f"trace_id='{self.trace_id}', "
114
+ f"root_span='{repr(self.root_span)}', "
115
+ ")"
116
+ )
51
117
 
52
118
  @override
53
119
  def __str__(self) -> str:
@@ -67,12 +133,11 @@ class NoOpTrace(BaseTrace):
67
133
  output: Optional[SpanOutputParam] = None,
68
134
  metadata: Optional[SpanMetadataParam] = None,
69
135
  ):
70
- super().__init__(queue_manager, trace_id)
71
-
72
- self.root_span = NoOpSpan(
136
+ trace_id = trace_id or generate_trace_id()
137
+ root_span = NoOpSpan(
73
138
  name=name,
74
139
  span_id=span_id,
75
- trace_id=self.trace_id,
140
+ trace_id=trace_id,
76
141
  group_id=group_id,
77
142
  queue_manager=queue_manager,
78
143
  metadata=metadata,
@@ -80,15 +145,7 @@ class NoOpTrace(BaseTrace):
80
145
  input=input,
81
146
  output=output,
82
147
  )
83
-
84
- @override
85
- def __repr__(self) -> str:
86
- return (
87
- f"{self.__class__.__name__}("
88
- f"trace_id='{self.trace_id}', "
89
- f"root_span='{repr(self.root_span)}', "
90
- ")"
91
- )
148
+ super().__init__(queue_manager, root_span, trace_id)
92
149
 
93
150
  @override
94
151
  def start(self) -> None:
@@ -98,10 +155,6 @@ class NoOpTrace(BaseTrace):
98
155
  def end(self) -> None:
99
156
  self.root_span.end()
100
157
 
101
- @override
102
- def group_id(self) -> Optional[str]:
103
- return self.root_span.group_id
104
-
105
158
 
106
159
  class Trace(BaseTrace):
107
160
  def __init__(
@@ -116,13 +169,11 @@ class Trace(BaseTrace):
116
169
  output: Optional[SpanOutputParam] = None,
117
170
  metadata: Optional[SpanMetadataParam] = None,
118
171
  ):
119
- super().__init__(queue_manager, trace_id)
120
- self.queue_manager: TraceQueueManager = queue_manager
121
-
122
- self.root_span = Span(
172
+ trace_id = trace_id or generate_trace_id()
173
+ root_span = Span(
123
174
  name=name,
124
175
  span_id=span_id,
125
- trace_id=self.trace_id,
176
+ trace_id=trace_id,
126
177
  group_id=group_id,
127
178
  queue_manager=queue_manager,
128
179
  metadata=metadata,
@@ -130,6 +181,8 @@ class Trace(BaseTrace):
130
181
  input=input,
131
182
  output=output,
132
183
  )
184
+ super().__init__(queue_manager, root_span, trace_id)
185
+ self.queue_manager: TraceQueueManager = queue_manager
133
186
 
134
187
  @override
135
188
  def start(self) -> None:
@@ -162,16 +215,3 @@ class Trace(BaseTrace):
162
215
  @override
163
216
  def flush(self, blocking: bool = True) -> None:
164
217
  self.root_span.flush(blocking=blocking)
165
-
166
- @override
167
- def group_id(self) -> Optional[str]:
168
- return self.root_span.group_id
169
-
170
- @override
171
- def __repr__(self) -> str:
172
- return (
173
- f"{self.__class__.__name__}("
174
- f"trace_id='{self.trace_id}', "
175
- f"root_span='{repr(self.root_span)}', "
176
- ")"
177
- )
@@ -182,7 +182,7 @@ def create_span(
182
182
 
183
183
  scoped_trace = current_trace()
184
184
  scoped_trace_id = scoped_trace.trace_id if scoped_trace else None
185
- scoped_group_id = scoped_trace.group_id() if scoped_trace else None
185
+ scoped_group_id = scoped_trace.group_id if scoped_trace else None
186
186
  scoped_span = current_span()
187
187
  scoped_span_id = scoped_span.span_id if scoped_span else None
188
188
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: scale-gp-beta
3
- Version: 0.1.0a21
3
+ Version: 0.1.0a23
4
4
  Summary: The official Python library for the Scale GP API
5
5
  Project-URL: Homepage, https://github.com/scaleapi/sgp-python-beta
6
6
  Project-URL: Repository, https://github.com/scaleapi/sgp-python-beta
@@ -31,7 +31,7 @@ Description-Content-Type: text/markdown
31
31
 
32
32
  # Scale GP Python API library
33
33
 
34
- [![PyPI version](https://img.shields.io/pypi/v/scale-gp-beta.svg)](https://pypi.org/project/scale-gp-beta/)
34
+ [![PyPI version](https://github.com/scaleapi/sgp-python-beta/tree/main/<https://img.shields.io/pypi/v/scale-gp-beta.svg?label=pypi%20(stable)>)](https://pypi.org/project/scale-gp-beta/)
35
35
 
36
36
  The Scale GP Python library provides convenient access to the Scale GP REST API from any Python 3.8+
37
37
  application. The library includes type definitions for all request params and response fields,
@@ -77,6 +77,244 @@ we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)
77
77
  to add `SGP_API_KEY="My API Key"` to your `.env` file
78
78
  so that your API Key is not stored in source control.
79
79
 
80
+ ---
81
+
82
+ ## Tracing & Spans
83
+
84
+ The SGP Tracing library provides a convenient way to instrument your Python applications with tracing capabilities, allowing you to generate, manage, and send spans to the Scale GP platform. This enables detailed monitoring and debugging of your workflows.
85
+
86
+ ### Quick Start Examples
87
+
88
+ For runnable examples, see the [examples/tracing](https://github.com/scaleapi/sgp-python-beta/tree/main/examples/tracing) directory in the repository.
89
+
90
+ ### Using the SDK
91
+
92
+ #### Initialization
93
+
94
+ Before you can create any traces or spans, you should initialize the tracing SDK with your `SGPClient`. It's best practice to do this once at your application's entry point. You can omit this step if you have set the `SGP_API_KEY` and `SGP_ACCOUNT_ID` environment variables, as the SDK will attempt to create a default client.
95
+
96
+ ```python
97
+ import scale_gp_beta.lib.tracing as tracing
98
+ from scale_gp_beta import SGPClient
99
+
100
+ client = SGPClient(api_key="YOUR_API_KEY", account_id="YOUR_ACCOUNT_ID")
101
+ tracing.init(client=client)
102
+ ```
103
+
104
+ Tracing uses the `SGPClient` for all requests. You can edit the `base_url` or any other parameters via the client you pass to `init()`.
105
+
106
+ #### Disabling Tracing
107
+
108
+ You can disable tracing by setting the environment variable `DISABLE_SCALE_TRACING` or programmatically via the `disabled` parameter in `init()`.
109
+
110
+ #### Core Concepts
111
+
112
+ The SDK revolves around two primary concepts: **Traces** and **Spans**.
113
+
114
+ * **Trace:** A trace represents a complete workflow or transaction, such as a web request or an AI agent's operation. It's a collection of related spans. Every trace has a single **root span**.
115
+ * **Span:** A span represents a single unit of work within a trace, like a function call, a database query, or an external API request. Spans can be nested to show hierarchical relationships.
116
+
117
+ When starting a trace, we will also create a root span. Server-side, we do not record the trace resource, only spans, but rely on the root span for trace data.
118
+
119
+ #### Creating Traces and Spans
120
+
121
+ The SDK offers flexible ways to create traces and spans: using **context managers** for automatic start/end handling, or **explicit control** for manual lifecycle management.
122
+
123
+ ##### 1\. Using Context Managers (Recommended)
124
+
125
+ The most straightforward way to create traces and spans is by using them as context managers (`with` statements). This ensures that spans are automatically started and ended, and errors are captured.
126
+
127
+ **Creating a Trace with a Root Span:**
128
+
129
+ Use `tracing.create_trace()` as a context manager to define a new trace. This automatically creates a root span for your trace.
130
+
131
+ ```python
132
+ import scale_gp_beta.lib.tracing as tracing
133
+
134
+ def my_workflow():
135
+ with tracing.create_trace(name="my_application_workflow", metadata={"env": "production"}):
136
+ # All spans created within this block will belong to "my_application_workflow" trace
137
+ print("Starting my application workflow...")
138
+ # ... your workflow logic
139
+ print("Application workflow completed.")
140
+ ```
141
+
142
+ **Creating Spans within a Trace:**
143
+
144
+ Inside a `create_trace` block, use `tracing.create_span()` as a context manager. These spans will automatically be associated with the current trace and parent span (if one exists).
145
+
146
+ ```python
147
+ import time
148
+ import scale_gp_beta.lib.tracing as tracing
149
+
150
+ def fibonacci(curr: int) -> int:
151
+ with tracing.create_span("fibonacci_calculation", input={"curr": curr}) as span:
152
+ time.sleep(0.1) # Simulate some work
153
+ if curr < 2:
154
+ span.output = {"res": curr}
155
+ return curr
156
+ res = fibonacci(curr - 1) + fibonacci(curr - 2)
157
+ span.output = {"res": res}
158
+ return res
159
+
160
+ def main_traced_example():
161
+ with tracing.create_trace("my_fibonacci_trace"): # Creates a root span
162
+ # This span will be a child of the "my_fibonacci_trace" root span
163
+ with tracing.create_span("main_execution", metadata={"version": "1.0"}) as main_span:
164
+ fib_result = fibonacci(5)
165
+ main_span.output = {"final_fib_result": fib_result}
166
+ print(f"Fibonacci(5) = {fib_result}")
167
+ ```
168
+
169
+ ##### 2\. Explicit Control
170
+
171
+ For scenarios where context managers aren't suitable, you can manually start and end spans. This approach requires more diligence to ensure all spans are properly ended and maintaining consistency.
172
+
173
+ **Manually Managing Spans (without an explicit Trace context):**
174
+
175
+ You can create spans and explicitly provide their `trace_id` and `parent_id` for fine-grained control. This is useful when integrating with existing systems that manage trace IDs.
176
+
177
+ ```python
178
+ import uuid
179
+ import time
180
+ import random
181
+ from typing import Any, Dict
182
+ import scale_gp_beta.lib.tracing as tracing
183
+
184
+ class MockDatabase:
185
+ def __init__(self) -> None:
186
+ self._data = {
187
+ "SELECT * FROM users WHERE id = 1;": {"id": 1, "name": "Alice"},
188
+ "SELECT * FROM users WHERE id = 2;": {"id": 2, "name": "Bob"},
189
+ }
190
+ def execute_query(self, query: str, trace_id: str) -> Dict[str, Any]:
191
+ db_span = tracing.create_span("db_query", input={"query": query}, trace_id=trace_id)
192
+ db_span.start()
193
+ try:
194
+ time.sleep(random.uniform(0.1, 0.3)) # Simulate delay
195
+ result = self._data.get(query, {})
196
+ db_span.output = {"result": result}
197
+ return result
198
+ finally:
199
+ db_span.end()
200
+
201
+ def get_user_from_db_explicit(db: MockDatabase, user_id: int, trace_id: str) -> Dict[str, Any]:
202
+ with tracing.create_span("get_user_from_db", input={"user_id": user_id}, trace_id=trace_id):
203
+ query = f"SELECT * FROM users WHERE id = {user_id};"
204
+ return db.execute_query(query, trace_id)
205
+
206
+ def main_explicit_control_example():
207
+ db = MockDatabase()
208
+ my_trace_id = str(uuid.uuid4())
209
+ # Manually create a root span
210
+ main_span = tracing.create_span("main_explicit_call", metadata={"env": "local"}, trace_id=my_trace_id)
211
+ main_span.start()
212
+ try:
213
+ user = get_user_from_db_explicit(db, 1, my_trace_id)
214
+ print(f"Retrieved user: {user.get('name')}")
215
+ finally:
216
+ main_span.end()
217
+ ```
218
+
219
+ **Exporting Existing Tracing Data (Manual Timestamps)**
220
+
221
+ You can even pre-define `start_time`, `end_time`, `span_id`, `parent_id`, and `trace_id` if you need to report historical data or reconstruct traces.
222
+
223
+ ```python
224
+ import uuid
225
+ from datetime import datetime, timezone, timedelta
226
+ import scale_gp_beta.lib.tracing as tracing
227
+
228
+ parent_span_id = str(uuid.uuid4())
229
+ trace_id = str(uuid.uuid4())
230
+ child_span_id = str(uuid.uuid4())
231
+
232
+ now = datetime.now(timezone.utc)
233
+
234
+ # Parent Span
235
+ parent_span = tracing.create_span(
236
+ "my_parent_span_name",
237
+ input={"test": "input"},
238
+ output={"test": "output"},
239
+ metadata={"test": "metadata"},
240
+ span_id=parent_span_id,
241
+ trace_id=trace_id,
242
+ )
243
+ parent_span.start_time = (now - timedelta(minutes=10)).isoformat()
244
+ parent_span.end_time = now.isoformat()
245
+ parent_span.flush(blocking=True)
246
+
247
+ # Child Span
248
+ child_span = tracing.create_span(
249
+ "my_child_span_name",
250
+ input={"test": "another input"},
251
+ output={"test": "another output"},
252
+ metadata={"test": "another metadata"},
253
+ span_id=child_span_id,
254
+ trace_id=trace_id,
255
+ parent_id=parent_span_id,
256
+ )
257
+ child_span.start_time = (now - timedelta(minutes=6)).isoformat()
258
+ child_span.end_time = (now - timedelta(minutes=2)).isoformat()
259
+ child_span.flush()
260
+ ```
261
+
262
+ Note that `span.flush()` will by default block the main thread until the request has finished. Use `blocking=False` to enqueue the request which will be picked up by the background worker.
263
+
264
+ #### Helper Methods
265
+
266
+ You can retrieve the currently active span or trace in the execution context using `current_span()` and `current_trace()`:
267
+
268
+ ```python
269
+ import scale_gp_beta.lib.tracing as tracing
270
+
271
+ def nested_function():
272
+ with tracing.create_span("nested_operation"):
273
+ current = tracing.current_span()
274
+ if current:
275
+ print(f"Currently active span: {current.name} (ID: {current.span_id})")
276
+ current_t = tracing.current_trace()
277
+ if current_t:
278
+ print(f"Currently active trace: (ID: {current_t.trace_id})")
279
+ ```
280
+
281
+ #### Flushing Tracing Data
282
+
283
+ Spans are generally batched and sent asynchronously by a background worker for efficiency. However, you might need to ensure all buffered spans are sent before an application exits or at critical points in your workflow (e.g., in a distributed worker setting).
284
+
285
+ You can force a synchronous flush of all queued spans using `flush_queue()` or on individual spans and traces (via their root span) with `span.flush()` & `trace.root_span.flush()`.
286
+
287
+ ```python
288
+ import scale_gp_beta.lib.tracing as tracing
289
+
290
+ # ... (create some spans) ...
291
+
292
+ # Ensure all spans are sent before continuing
293
+ tracing.flush_queue()
294
+ print("All pending spans have been flushed.")
295
+ ```
296
+
297
+ You do not need to manually flush all spans on program exit; when shutting down the background worker, we will attempt to flush all tracing data before exiting.
298
+
299
+ #### Configuration Options
300
+
301
+ | ENV Variable | Description |
302
+ |:------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------|
303
+ | `DISABLE_SCALE_TRACING` | If set, no tracing data will be exported. You can still observe tracing data programmatically via the No-Op variant of Trace and Span objects. |
304
+ | `SGP_API_KEY` | SGP API Key. Used by `SGPClient`. |
305
+ | `SGP_ACCOUNT_ID` | SGP Account ID. Used by `SGPClient`. |
306
+
307
+ #### Multi-Process / Multi-Worker Tracing
308
+
309
+ > **_WARNING:_** Developers should be careful when attempting tracing over multiple workers / Python processes. The SGP backend will expect well-formed trace data, and there is a strong chance of race conditions if a child span is reported before a parent span.
310
+
311
+ The easiest approach to working over multiple workers and Python processes is to only create one trace per worker. You can group traces with a `group_id`.
312
+
313
+ If you want to track an entire workflow over multiple workers, ensure you call `tracing.flush_queue()` before you enqueue a job which creates child spans of the current trace.
314
+
315
+ You will need to use the explicit controls to forward trace and parent span IDs to your workers. The automatic context detection works within the context of the original Python process only.
316
+
317
+
80
318
  ## Async usage
81
319
 
82
320
  Simply import `AsyncSGPClient` instead of `SGPClient` and use `await` with each API call:
@@ -340,7 +578,7 @@ client.with_options(max_retries=5).chat.completions.create(
340
578
  ### Timeouts
341
579
 
342
580
  By default requests time out after 1 minute. You can configure this with a `timeout` option,
343
- which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object:
581
+ which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
344
582
 
345
583
  ```python
346
584
  from scale_gp_beta import SGPClient
@@ -11,7 +11,7 @@ scale_gp_beta/_resource.py,sha256=siZly_U6D0AOVLAzaOsqUdEFFzVMbWRj-ml30nvRp7E,11
11
11
  scale_gp_beta/_response.py,sha256=GemuybPk0uemovTlGHyHkj-ScYTTDJA0jqH5FQqIPwQ,28852
12
12
  scale_gp_beta/_streaming.py,sha256=fcCSGXslmi2SmmkM05g2SACXHk2Mj7k1X5uMBu6U5s8,10112
13
13
  scale_gp_beta/_types.py,sha256=0wSs40TefKMPBj2wQKenEeZ0lzedoHClNJeqrpAgkII,6204
14
- scale_gp_beta/_version.py,sha256=eAvv8VO77KuKq0s3gmUyyDz59GNsypYW7UrSDWHIN9s,174
14
+ scale_gp_beta/_version.py,sha256=PVHPnDC4m4CLgie5tfMTyuGdRwriv_lcwpf658BXOZ8,174
15
15
  scale_gp_beta/pagination.py,sha256=t-U86PYxl20VRsz8VXOMJJDe7HxkX7ISFMvRNbBNy9s,4054
16
16
  scale_gp_beta/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  scale_gp_beta/_utils/__init__.py,sha256=PNZ_QJuzZEgyYXqkO1HVhGkj5IU9bglVUcw7H-Knjzw,2062
@@ -28,11 +28,11 @@ scale_gp_beta/lib/.keep,sha256=wuNrz-5SXo3jJaJOJgz4vFHM41YH_g20F5cRQo0vLes,224
28
28
  scale_gp_beta/lib/tracing/__init__.py,sha256=UgyExbqAA2ljDEF4X4YFhtbBZuoQJ2IF4hkGs_xQEc0,226
29
29
  scale_gp_beta/lib/tracing/exceptions.py,sha256=vL2_GAfWEy8EfLhrBkDClLYTasOLnL-5zUpdCQnSzcs,107
30
30
  scale_gp_beta/lib/tracing/scope.py,sha256=kHrd0his8L2K_KXn2E6J9d565PliEdFoKRQ1d5ALTyk,3901
31
- scale_gp_beta/lib/tracing/span.py,sha256=_XocyodHFJsIihEOyFKtdojdsUR2wayqoRL7Kj60PVQ,9671
32
- scale_gp_beta/lib/tracing/trace.py,sha256=GEzE78sulYKooz46vtZ7JI77_KDCOpQBfYsahZE_7HU,5084
31
+ scale_gp_beta/lib/tracing/span.py,sha256=VVibUzWAjENw80JH7JCMF2LbXr0aN9HNudduZBW0rx0,11260
32
+ scale_gp_beta/lib/tracing/trace.py,sha256=sdLUnvByLaMbV2TgI-MdKKs7If1-6GKz5j9A6scnDoI,6205
33
33
  scale_gp_beta/lib/tracing/trace_exporter.py,sha256=bE6hS-Qu9KknEUTdsfIQMQwauah125mEavTDqEenBRA,3779
34
34
  scale_gp_beta/lib/tracing/trace_queue_manager.py,sha256=xywP3myhaHX52i52ZfC2_-ONrd-4_aL-f3-3jNhh2XY,5961
35
- scale_gp_beta/lib/tracing/tracing.py,sha256=kGoUo3Kf172iJudzFIomXvQ_2aiWPr_38wqbKFX4rGo,8837
35
+ scale_gp_beta/lib/tracing/tracing.py,sha256=piSl0HsC442wcgjyBU7FLJszY0EoYaGxyRIy_uocR_o,8835
36
36
  scale_gp_beta/lib/tracing/types.py,sha256=fnU7XGiyfF3UEIx-iqyHRjNHlOV7s75tP0b5efvt2sk,1156
37
37
  scale_gp_beta/lib/tracing/util.py,sha256=8Oq4wLXRNOzh3CC1zRaBEr0h_WdXLrk536BUNKRddVE,1527
38
38
  scale_gp_beta/resources/__init__.py,sha256=Fyo05_2_pc5orfyTSIpxa3btmBTd45VasgibwSqbbKo,4942
@@ -117,7 +117,7 @@ scale_gp_beta/types/chat/completion_models_params.py,sha256=ETxafJIUx4tTvkiR-ZCr
117
117
  scale_gp_beta/types/chat/completion_models_response.py,sha256=Ctgj6o-QWPSdjBKzG9J4Id0-DjXu4UGGw1NR6-840Ec,403
118
118
  scale_gp_beta/types/chat/model_definition.py,sha256=NNgopTm900GD0Zs2YHkcvoW67uKaWUKVyPbhKBHvKdQ,817
119
119
  scale_gp_beta/types/files/__init__.py,sha256=OKfJYcKb4NObdiRObqJV_dOyDQ8feXekDUge2o_4pXQ,122
120
- scale_gp_beta-0.1.0a21.dist-info/METADATA,sha256=ZSHBKPl86WyhjRcUXYbMKDvPUAmeodrSMGKQ6S9QAQo,16881
121
- scale_gp_beta-0.1.0a21.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
122
- scale_gp_beta-0.1.0a21.dist-info/licenses/LICENSE,sha256=x49Bj8r_ZpqfzThbmfHyZ_bE88XvHdIMI_ANyLHFFRE,11338
123
- scale_gp_beta-0.1.0a21.dist-info/RECORD,,
120
+ scale_gp_beta-0.1.0a23.dist-info/METADATA,sha256=EUWqFlefgJo-cCYXL1QNdQ-zhzw6XZaM1k8k0a9cmqw,27611
121
+ scale_gp_beta-0.1.0a23.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
122
+ scale_gp_beta-0.1.0a23.dist-info/licenses/LICENSE,sha256=x49Bj8r_ZpqfzThbmfHyZ_bE88XvHdIMI_ANyLHFFRE,11338
123
+ scale_gp_beta-0.1.0a23.dist-info/RECORD,,