scale-gp-beta 0.1.0a20__tar.gz → 0.1.0a22__tar.gz
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-0.1.0a22/.release-please-manifest.json +3 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/CHANGELOG.md +21 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/PKG-INFO +239 -1
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/README.md +238 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/pyproject.toml +1 -1
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_base_client.py +16 -2
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_version.py +1 -1
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/lib/tracing/span.py +8 -2
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/lib/tracing/trace.py +22 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/lib/tracing/tracing.py +12 -1
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/lib/test_trace_exporter.py +1 -1
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/lib/test_tracing.py +15 -2
- scale_gp_beta-0.1.0a20/.release-please-manifest.json +0 -3
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/.gitignore +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/CONTRIBUTING.md +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/LICENSE +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/SECURITY.md +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/api.md +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/bin/check-release-environment +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/bin/publish-pypi +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/examples/.keep +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/examples/tracing/0_primitives_fibonacci.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/examples/tracing/1_explicit_use_case.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/examples/tracing/2_direct_upload.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/mypy.ini +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/noxfile.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/release-please-config.json +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/requirements-dev.lock +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/requirements.lock +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp/lib/.keep +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/__init__.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_client.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_compat.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_constants.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_exceptions.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_files.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_models.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_qs.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_resource.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_response.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_streaming.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_types.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_utils/__init__.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_utils/_logs.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_utils/_proxy.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_utils/_reflection.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_utils/_resources_proxy.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_utils/_streams.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_utils/_sync.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_utils/_transform.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_utils/_typing.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/_utils/_utils.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/lib/.keep +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/lib/tracing/__init__.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/lib/tracing/exceptions.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/lib/tracing/scope.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/lib/tracing/trace_exporter.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/lib/tracing/trace_queue_manager.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/lib/tracing/types.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/lib/tracing/util.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/pagination.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/py.typed +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/resources/__init__.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/resources/chat/__init__.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/resources/chat/chat.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/resources/chat/completions.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/resources/completions.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/resources/dataset_items.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/resources/datasets.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/resources/evaluation_items.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/resources/evaluations.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/resources/files/__init__.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/resources/files/content.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/resources/files/files.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/resources/inference.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/resources/models.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/resources/spans.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/__init__.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/chat/__init__.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/chat/chat_completion.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/chat/chat_completion_chunk.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/chat/completion_create_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/chat/completion_create_response.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/chat/completion_models_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/chat/completion_models_response.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/chat/model_definition.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/completion.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/completion_create_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/component.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/component_param.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/container.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/container_param.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/dataset.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/dataset_create_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/dataset_delete_response.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/dataset_item.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/dataset_item_batch_create_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/dataset_item_batch_create_response.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/dataset_item_delete_response.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/dataset_item_list_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/dataset_item_retrieve_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/dataset_item_update_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/dataset_list_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/dataset_retrieve_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/dataset_update_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/evaluation.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/evaluation_create_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/evaluation_delete_response.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/evaluation_item.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/evaluation_item_list_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/evaluation_item_retrieve_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/evaluation_list_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/evaluation_retrieve_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/evaluation_task.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/evaluation_task_param.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/evaluation_update_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/file.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/file_create_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/file_delete_response.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/file_list.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/file_list_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/file_update_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/files/__init__.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/inference_create_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/inference_create_response.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/inference_model.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/inference_model_list.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/inference_response.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/inference_response_chunk.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/item_locator.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/item_locator_template.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/model_create_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/model_delete_response.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/model_list_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/model_update_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/span.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/span_batch_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/span_batch_response.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/span_create_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/span_search_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/span_search_response.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/span_update_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/span_upsert_batch_params.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/scale_gp_beta/types/span_upsert_batch_response.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/src/sgp_dev/lib/.keep +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/__init__.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/api_resources/__init__.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/api_resources/chat/__init__.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/api_resources/chat/test_completions.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/api_resources/files/__init__.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/api_resources/files/test_content.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/api_resources/test_completions.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/api_resources/test_dataset_items.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/api_resources/test_datasets.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/api_resources/test_evaluation_items.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/api_resources/test_evaluations.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/api_resources/test_files.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/api_resources/test_inference.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/api_resources/test_models.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/api_resources/test_spans.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/conftest.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/lib/test_span.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/lib/test_trace.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/sample_file.txt +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/test_client.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/test_deepcopy.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/test_extract_files.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/test_files.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/test_models.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/test_qs.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/test_required_args.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/test_response.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/test_streaming.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/test_transform.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/test_utils/test_proxy.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/test_utils/test_typing.py +0 -0
- {scale_gp_beta-0.1.0a20 → scale_gp_beta-0.1.0a22}/tests/utils.py +0 -0
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.0-alpha.22 (2025-06-16)
|
|
4
|
+
|
|
5
|
+
Full Changelog: [v0.1.0-alpha.21...v0.1.0-alpha.22](https://github.com/scaleapi/sgp-python-beta/compare/v0.1.0-alpha.21...v0.1.0-alpha.22)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* Updated README.md to include tracing information ([#111](https://github.com/scaleapi/sgp-python-beta/issues/111)) ([e2d0d8d](https://github.com/scaleapi/sgp-python-beta/commit/e2d0d8de22d347b830771fdf7a7fd4be954f30f0))
|
|
10
|
+
|
|
11
|
+
## 0.1.0-alpha.21 (2025-06-13)
|
|
12
|
+
|
|
13
|
+
Full Changelog: [v0.1.0-alpha.20...v0.1.0-alpha.21](https://github.com/scaleapi/sgp-python-beta/compare/v0.1.0-alpha.20...v0.1.0-alpha.21)
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* Group id support ([#110](https://github.com/scaleapi/sgp-python-beta/issues/110)) ([d934d91](https://github.com/scaleapi/sgp-python-beta/commit/d934d9136db1210e934e2c34b754200678ea60ca))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* **client:** correctly parse binary response | stream ([f802181](https://github.com/scaleapi/sgp-python-beta/commit/f80218120e7f6780461ee0eac836139241532421))
|
|
23
|
+
|
|
3
24
|
## 0.1.0-alpha.20 (2025-06-12)
|
|
4
25
|
|
|
5
26
|
Full Changelog: [v0.1.0-alpha.19...v0.1.0-alpha.20](https://github.com/scaleapi/sgp-python-beta/compare/v0.1.0-alpha.19...v0.1.0-alpha.20)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: scale-gp-beta
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.0a22
|
|
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
|
|
@@ -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:
|
|
@@ -46,6 +46,244 @@ we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)
|
|
|
46
46
|
to add `SGP_API_KEY="My API Key"` to your `.env` file
|
|
47
47
|
so that your API Key is not stored in source control.
|
|
48
48
|
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Tracing & Spans
|
|
52
|
+
|
|
53
|
+
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.
|
|
54
|
+
|
|
55
|
+
### Quick Start Examples
|
|
56
|
+
|
|
57
|
+
For runnable examples, see the [examples/tracing](https://github.com/scaleapi/sgp-python-beta/tree/main/examples/tracing) directory in the repository.
|
|
58
|
+
|
|
59
|
+
### Using the SDK
|
|
60
|
+
|
|
61
|
+
#### Initialization
|
|
62
|
+
|
|
63
|
+
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.
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
import scale_gp_beta.lib.tracing as tracing
|
|
67
|
+
from scale_gp_beta import SGPClient
|
|
68
|
+
|
|
69
|
+
client = SGPClient(api_key="YOUR_API_KEY", account_id="YOUR_ACCOUNT_ID")
|
|
70
|
+
tracing.init(client=client)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Tracing uses the `SGPClient` for all requests. You can edit the `base_url` or any other parameters via the client you pass to `init()`.
|
|
74
|
+
|
|
75
|
+
#### Disabling Tracing
|
|
76
|
+
|
|
77
|
+
You can disable tracing by setting the environment variable `DISABLE_SCALE_TRACING` or programmatically via the `disabled` parameter in `init()`.
|
|
78
|
+
|
|
79
|
+
#### Core Concepts
|
|
80
|
+
|
|
81
|
+
The SDK revolves around two primary concepts: **Traces** and **Spans**.
|
|
82
|
+
|
|
83
|
+
* **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**.
|
|
84
|
+
* **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.
|
|
85
|
+
|
|
86
|
+
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.
|
|
87
|
+
|
|
88
|
+
#### Creating Traces and Spans
|
|
89
|
+
|
|
90
|
+
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.
|
|
91
|
+
|
|
92
|
+
##### 1\. Using Context Managers (Recommended)
|
|
93
|
+
|
|
94
|
+
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.
|
|
95
|
+
|
|
96
|
+
**Creating a Trace with a Root Span:**
|
|
97
|
+
|
|
98
|
+
Use `tracing.create_trace()` as a context manager to define a new trace. This automatically creates a root span for your trace.
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
import scale_gp_beta.lib.tracing as tracing
|
|
102
|
+
|
|
103
|
+
def my_workflow():
|
|
104
|
+
with tracing.create_trace(name="my_application_workflow", metadata={"env": "production"}):
|
|
105
|
+
# All spans created within this block will belong to "my_application_workflow" trace
|
|
106
|
+
print("Starting my application workflow...")
|
|
107
|
+
# ... your workflow logic
|
|
108
|
+
print("Application workflow completed.")
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Creating Spans within a Trace:**
|
|
112
|
+
|
|
113
|
+
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).
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
import time
|
|
117
|
+
import scale_gp_beta.lib.tracing as tracing
|
|
118
|
+
|
|
119
|
+
def fibonacci(curr: int) -> int:
|
|
120
|
+
with tracing.create_span("fibonacci_calculation", input={"curr": curr}) as span:
|
|
121
|
+
time.sleep(0.1) # Simulate some work
|
|
122
|
+
if curr < 2:
|
|
123
|
+
span.output = {"res": curr}
|
|
124
|
+
return curr
|
|
125
|
+
res = fibonacci(curr - 1) + fibonacci(curr - 2)
|
|
126
|
+
span.output = {"res": res}
|
|
127
|
+
return res
|
|
128
|
+
|
|
129
|
+
def main_traced_example():
|
|
130
|
+
with tracing.create_trace("my_fibonacci_trace"): # Creates a root span
|
|
131
|
+
# This span will be a child of the "my_fibonacci_trace" root span
|
|
132
|
+
with tracing.create_span("main_execution", metadata={"version": "1.0"}) as main_span:
|
|
133
|
+
fib_result = fibonacci(5)
|
|
134
|
+
main_span.output = {"final_fib_result": fib_result}
|
|
135
|
+
print(f"Fibonacci(5) = {fib_result}")
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
##### 2\. Explicit Control
|
|
139
|
+
|
|
140
|
+
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.
|
|
141
|
+
|
|
142
|
+
**Manually Managing Spans (without an explicit Trace context):**
|
|
143
|
+
|
|
144
|
+
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.
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
import uuid
|
|
148
|
+
import time
|
|
149
|
+
import random
|
|
150
|
+
from typing import Any, Dict
|
|
151
|
+
import scale_gp_beta.lib.tracing as tracing
|
|
152
|
+
|
|
153
|
+
class MockDatabase:
|
|
154
|
+
def __init__(self) -> None:
|
|
155
|
+
self._data = {
|
|
156
|
+
"SELECT * FROM users WHERE id = 1;": {"id": 1, "name": "Alice"},
|
|
157
|
+
"SELECT * FROM users WHERE id = 2;": {"id": 2, "name": "Bob"},
|
|
158
|
+
}
|
|
159
|
+
def execute_query(self, query: str, trace_id: str) -> Dict[str, Any]:
|
|
160
|
+
db_span = tracing.create_span("db_query", input={"query": query}, trace_id=trace_id)
|
|
161
|
+
db_span.start()
|
|
162
|
+
try:
|
|
163
|
+
time.sleep(random.uniform(0.1, 0.3)) # Simulate delay
|
|
164
|
+
result = self._data.get(query, {})
|
|
165
|
+
db_span.output = {"result": result}
|
|
166
|
+
return result
|
|
167
|
+
finally:
|
|
168
|
+
db_span.end()
|
|
169
|
+
|
|
170
|
+
def get_user_from_db_explicit(db: MockDatabase, user_id: int, trace_id: str) -> Dict[str, Any]:
|
|
171
|
+
with tracing.create_span("get_user_from_db", input={"user_id": user_id}, trace_id=trace_id):
|
|
172
|
+
query = f"SELECT * FROM users WHERE id = {user_id};"
|
|
173
|
+
return db.execute_query(query, trace_id)
|
|
174
|
+
|
|
175
|
+
def main_explicit_control_example():
|
|
176
|
+
db = MockDatabase()
|
|
177
|
+
my_trace_id = str(uuid.uuid4())
|
|
178
|
+
# Manually create a root span
|
|
179
|
+
main_span = tracing.create_span("main_explicit_call", metadata={"env": "local"}, trace_id=my_trace_id)
|
|
180
|
+
main_span.start()
|
|
181
|
+
try:
|
|
182
|
+
user = get_user_from_db_explicit(db, 1, my_trace_id)
|
|
183
|
+
print(f"Retrieved user: {user.get('name')}")
|
|
184
|
+
finally:
|
|
185
|
+
main_span.end()
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Exporting Existing Tracing Data (Manual Timestamps)**
|
|
189
|
+
|
|
190
|
+
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.
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
import uuid
|
|
194
|
+
from datetime import datetime, timezone, timedelta
|
|
195
|
+
import scale_gp_beta.lib.tracing as tracing
|
|
196
|
+
|
|
197
|
+
parent_span_id = str(uuid.uuid4())
|
|
198
|
+
trace_id = str(uuid.uuid4())
|
|
199
|
+
child_span_id = str(uuid.uuid4())
|
|
200
|
+
|
|
201
|
+
now = datetime.now(timezone.utc)
|
|
202
|
+
|
|
203
|
+
# Parent Span
|
|
204
|
+
parent_span = tracing.create_span(
|
|
205
|
+
"my_parent_span_name",
|
|
206
|
+
input={"test": "input"},
|
|
207
|
+
output={"test": "output"},
|
|
208
|
+
metadata={"test": "metadata"},
|
|
209
|
+
span_id=parent_span_id,
|
|
210
|
+
trace_id=trace_id,
|
|
211
|
+
)
|
|
212
|
+
parent_span.start_time = (now - timedelta(minutes=10)).isoformat()
|
|
213
|
+
parent_span.end_time = now.isoformat()
|
|
214
|
+
parent_span.flush(blocking=True)
|
|
215
|
+
|
|
216
|
+
# Child Span
|
|
217
|
+
child_span = tracing.create_span(
|
|
218
|
+
"my_child_span_name",
|
|
219
|
+
input={"test": "another input"},
|
|
220
|
+
output={"test": "another output"},
|
|
221
|
+
metadata={"test": "another metadata"},
|
|
222
|
+
span_id=child_span_id,
|
|
223
|
+
trace_id=trace_id,
|
|
224
|
+
parent_id=parent_span_id,
|
|
225
|
+
)
|
|
226
|
+
child_span.start_time = (now - timedelta(minutes=6)).isoformat()
|
|
227
|
+
child_span.end_time = (now - timedelta(minutes=2)).isoformat()
|
|
228
|
+
child_span.flush()
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
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.
|
|
232
|
+
|
|
233
|
+
#### Helper Methods
|
|
234
|
+
|
|
235
|
+
You can retrieve the currently active span or trace in the execution context using `current_span()` and `current_trace()`:
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
import scale_gp_beta.lib.tracing as tracing
|
|
239
|
+
|
|
240
|
+
def nested_function():
|
|
241
|
+
with tracing.create_span("nested_operation"):
|
|
242
|
+
current = tracing.current_span()
|
|
243
|
+
if current:
|
|
244
|
+
print(f"Currently active span: {current.name} (ID: {current.span_id})")
|
|
245
|
+
current_t = tracing.current_trace()
|
|
246
|
+
if current_t:
|
|
247
|
+
print(f"Currently active trace: (ID: {current_t.trace_id})")
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
#### Flushing Tracing Data
|
|
251
|
+
|
|
252
|
+
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).
|
|
253
|
+
|
|
254
|
+
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()`.
|
|
255
|
+
|
|
256
|
+
```python
|
|
257
|
+
import scale_gp_beta.lib.tracing as tracing
|
|
258
|
+
|
|
259
|
+
# ... (create some spans) ...
|
|
260
|
+
|
|
261
|
+
# Ensure all spans are sent before continuing
|
|
262
|
+
tracing.flush_queue()
|
|
263
|
+
print("All pending spans have been flushed.")
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
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.
|
|
267
|
+
|
|
268
|
+
#### Configuration Options
|
|
269
|
+
|
|
270
|
+
| ENV Variable | Description |
|
|
271
|
+
|:------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------|
|
|
272
|
+
| `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. |
|
|
273
|
+
| `SGP_API_KEY` | SGP API Key. Used by `SGPClient`. |
|
|
274
|
+
| `SGP_ACCOUNT_ID` | SGP Account ID. Used by `SGPClient`. |
|
|
275
|
+
|
|
276
|
+
#### Multi-Process / Multi-Worker Tracing
|
|
277
|
+
|
|
278
|
+
> **_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.
|
|
279
|
+
|
|
280
|
+
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`.
|
|
281
|
+
|
|
282
|
+
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.
|
|
283
|
+
|
|
284
|
+
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.
|
|
285
|
+
|
|
286
|
+
|
|
49
287
|
## Async usage
|
|
50
288
|
|
|
51
289
|
Simply import `AsyncSGPClient` instead of `SGPClient` and use `await` with each API call:
|
|
@@ -1071,7 +1071,14 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
|
|
|
1071
1071
|
) -> ResponseT:
|
|
1072
1072
|
origin = get_origin(cast_to) or cast_to
|
|
1073
1073
|
|
|
1074
|
-
if
|
|
1074
|
+
if (
|
|
1075
|
+
inspect.isclass(origin)
|
|
1076
|
+
and issubclass(origin, BaseAPIResponse)
|
|
1077
|
+
# we only want to actually return the custom BaseAPIResponse class if we're
|
|
1078
|
+
# returning the raw response, or if we're not streaming SSE, as if we're streaming
|
|
1079
|
+
# SSE then `cast_to` doesn't actively reflect the type we need to parse into
|
|
1080
|
+
and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
|
|
1081
|
+
):
|
|
1075
1082
|
if not issubclass(origin, APIResponse):
|
|
1076
1083
|
raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}")
|
|
1077
1084
|
|
|
@@ -1574,7 +1581,14 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
|
|
|
1574
1581
|
) -> ResponseT:
|
|
1575
1582
|
origin = get_origin(cast_to) or cast_to
|
|
1576
1583
|
|
|
1577
|
-
if
|
|
1584
|
+
if (
|
|
1585
|
+
inspect.isclass(origin)
|
|
1586
|
+
and issubclass(origin, BaseAPIResponse)
|
|
1587
|
+
# we only want to actually return the custom BaseAPIResponse class if we're
|
|
1588
|
+
# returning the raw response, or if we're not streaming SSE, as if we're streaming
|
|
1589
|
+
# SSE then `cast_to` doesn't actively reflect the type we need to parse into
|
|
1590
|
+
and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
|
|
1591
|
+
):
|
|
1578
1592
|
if not issubclass(origin, AsyncAPIResponse):
|
|
1579
1593
|
raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}")
|
|
1580
1594
|
|
|
@@ -53,6 +53,7 @@ class BaseSpan:
|
|
|
53
53
|
queue_manager: Optional[TraceQueueManager] = None,
|
|
54
54
|
span_id: Optional[str] = None,
|
|
55
55
|
parent_span_id: Optional[str] = None,
|
|
56
|
+
group_id: Optional[str] = None,
|
|
56
57
|
input: Optional[SpanInputParam] = None,
|
|
57
58
|
output: Optional[SpanOutputParam] = None,
|
|
58
59
|
metadata: Optional[SpanMetadataParam] = None,
|
|
@@ -60,6 +61,7 @@ class BaseSpan:
|
|
|
60
61
|
):
|
|
61
62
|
self.name = name
|
|
62
63
|
self.trace_id = trace_id or "no_trace_id"
|
|
64
|
+
self.group_id = group_id
|
|
63
65
|
self.span_id: str = span_id or generate_span_id()
|
|
64
66
|
self.parent_span_id = parent_span_id
|
|
65
67
|
self.start_time: Optional[str] = None
|
|
@@ -124,6 +126,9 @@ class BaseSpan:
|
|
|
124
126
|
if self.parent_span_id is not None:
|
|
125
127
|
request_data["parent_id"] = self.parent_span_id
|
|
126
128
|
|
|
129
|
+
if self.group_id is not None:
|
|
130
|
+
request_data["group_id"] = self.group_id
|
|
131
|
+
|
|
127
132
|
return request_data
|
|
128
133
|
|
|
129
134
|
@override
|
|
@@ -134,6 +139,7 @@ class BaseSpan:
|
|
|
134
139
|
f"span_id='{self.span_id}', "
|
|
135
140
|
f"trace_id='{self.trace_id}', "
|
|
136
141
|
f"parent_span_id='{self.parent_span_id}', "
|
|
142
|
+
f"group_id='{self.group_id}', "
|
|
137
143
|
f"start_time='{self.start_time}', "
|
|
138
144
|
f"end_time='{self.end_time}', "
|
|
139
145
|
f"input='{self.input}', "
|
|
@@ -189,12 +195,13 @@ class Span(BaseSpan):
|
|
|
189
195
|
queue_manager: TraceQueueManager,
|
|
190
196
|
span_id: Optional[str] = None,
|
|
191
197
|
parent_span_id: Optional[str] = None,
|
|
198
|
+
group_id: Optional[str] = None,
|
|
192
199
|
input: Optional[SpanInputParam] = None,
|
|
193
200
|
output: Optional[SpanOutputParam] = None,
|
|
194
201
|
metadata: Optional[SpanMetadataParam] = None,
|
|
195
202
|
span_type: SpanTypeLiterals = "STANDALONE",
|
|
196
203
|
):
|
|
197
|
-
super().__init__(name, trace_id, queue_manager, span_id, parent_span_id, input, output, metadata, span_type)
|
|
204
|
+
super().__init__(name, trace_id, queue_manager, span_id, parent_span_id, group_id, input, output, metadata, span_type)
|
|
198
205
|
self._queue_manager: TraceQueueManager = queue_manager
|
|
199
206
|
self.trace_id: str = trace_id
|
|
200
207
|
|
|
@@ -206,7 +213,6 @@ class Span(BaseSpan):
|
|
|
206
213
|
The background worker batches and sends asynchronously.
|
|
207
214
|
:param blocking:
|
|
208
215
|
"""
|
|
209
|
-
# TODO: implement flush() for trace
|
|
210
216
|
if blocking:
|
|
211
217
|
self._queue_manager.export_now(self)
|
|
212
218
|
else:
|