diff --git a/.gitignore b/.gitignore
index d5d7392f4e8..f6cb4550e08 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,4 +57,8 @@ packages/**/generated
**/.idea/*
-.python-version
\ No newline at end of file
+.python-version
+
+# This file is too large to be included in the repository without LFS
+seed/python-sdk/trace/snippet-templates.json
+seed/python-sdk/**/output.prof
diff --git a/generators/python/sdk/Dockerfile b/generators/python/sdk/Dockerfile
index 007d317219a..314e94c8db0 100644
--- a/generators/python/sdk/Dockerfile
+++ b/generators/python/sdk/Dockerfile
@@ -30,14 +30,14 @@ COPY ./src ./src
RUN poetry install
-# ENTRYPOINT ["python", "-m", "src.fern_python.generators.sdk.cli"]
+ENTRYPOINT ["python", "-m", "src.fern_python.generators.sdk.cli"]
## NOTE: Uncomment the below to generate a flame graph for the python generator.
## To visualize the flamegraph you can run:
## - poetry add snakeviz
## - poetry run snakeviz output.prof
-RUN mkdir -p /fern/output
+# RUN mkdir -p /fern/output
## For a time-limited run, uncomment the below line and comment the next line.
-ENTRYPOINT ["timeout", "-s", "INT", "10m", "python", "-m", "cProfile", "-o", "/fern/output/output.prof", "/src/fern_python/generators/sdk/cli.py"]
+# ENTRYPOINT ["timeout", "-s", "INT", "5m", "python", "-m", "cProfile", "-o", "/fern/output/output.prof", "/src/fern_python/generators/sdk/cli.py"]
## For a regularly profiled run, uncomment the below line and comment the previous line.
# ENTRYPOINT ["python", "-m", "cProfile", "-o", "/fern/output/output.prof", "/src/fern_python/generators/sdk/cli.py"]
diff --git a/generators/python/sdk/VERSION b/generators/python/sdk/VERSION
index 40c341bdcdb..7c69a55dbb1 100644
--- a/generators/python/sdk/VERSION
+++ b/generators/python/sdk/VERSION
@@ -1 +1 @@
-3.6.0
+3.7.0
diff --git a/generators/python/src/fern_python/generators/pydantic_model/fern_aware_pydantic_model.py b/generators/python/src/fern_python/generators/pydantic_model/fern_aware_pydantic_model.py
index eefc5f3e7fd..aed5317abc9 100644
--- a/generators/python/src/fern_python/generators/pydantic_model/fern_aware_pydantic_model.py
+++ b/generators/python/src/fern_python/generators/pydantic_model/fern_aware_pydantic_model.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from types import TracebackType
-from typing import List, Optional, Sequence, Set, Tuple, Type
+from typing import List, Optional, Sequence, Tuple, Type
import fern.ir.resources as ir_types
@@ -181,7 +181,9 @@ def _must_import_after_current_declaration(self, type_name: ir_types.DeclaredTyp
type_id_to_reference = self._type_id_for_forward_ref()
is_circular_reference = False
if type_id_to_reference is not None:
- is_circular_reference = self._context.does_type_reference_other_type(type_id=type_name.type_id, other_type_id=type_id_to_reference)
+ is_circular_reference = self._context.does_type_reference_other_type(
+ type_id=type_name.type_id, other_type_id=type_id_to_reference
+ )
if is_circular_reference:
self._model_contains_forward_refs = True
diff --git a/generators/python/src/fern_python/generators/pydantic_model/type_declaration_handler/discriminated_union/discriminated_union_with_utils_generator.py b/generators/python/src/fern_python/generators/pydantic_model/type_declaration_handler/discriminated_union/discriminated_union_with_utils_generator.py
index 5eecbc42dba..2e2a33d372e 100644
--- a/generators/python/src/fern_python/generators/pydantic_model/type_declaration_handler/discriminated_union/discriminated_union_with_utils_generator.py
+++ b/generators/python/src/fern_python/generators/pydantic_model/type_declaration_handler/discriminated_union/discriminated_union_with_utils_generator.py
@@ -278,7 +278,9 @@ def generate(self) -> None:
forward_refed_types = [
referenced_type_id
for referenced_type_id in referenced_type_ids
- if self._context.does_type_reference_other_type(type_id=referenced_type_id, other_type_id=self._name.type_id)
+ if self._context.does_type_reference_other_type(
+ type_id=referenced_type_id, other_type_id=self._name.type_id
+ )
]
if len(forward_refed_types) > 0:
diff --git a/generators/python/src/fern_python/generators/pydantic_model/type_declaration_handler/pydantic_models/pydantic_model_simple_discriminated_union_generator.py b/generators/python/src/fern_python/generators/pydantic_model/type_declaration_handler/pydantic_models/pydantic_model_simple_discriminated_union_generator.py
index 70ba97a8f81..df43df1de7a 100644
--- a/generators/python/src/fern_python/generators/pydantic_model/type_declaration_handler/pydantic_models/pydantic_model_simple_discriminated_union_generator.py
+++ b/generators/python/src/fern_python/generators/pydantic_model/type_declaration_handler/pydantic_models/pydantic_model_simple_discriminated_union_generator.py
@@ -159,7 +159,7 @@ def _finish(self, type_alias_declaration: AST.TypeAliasDeclaration) -> None:
# There are some types that will not cause their dependent types to rebuild
# for example other unions, and so to make sure those types are rebuilt
# we import them all here.
- for type_id in (self._context.maybe_get_type_ids_for_type_reference(referenced_type) or []):
+ for type_id in self._context.maybe_get_type_ids_for_type_reference(referenced_type) or []:
type_alias_declaration.add_ghost_reference(
self._context.get_class_reference_for_type_id(
type_id,
@@ -184,9 +184,9 @@ def _update_forward_refs_for_single_property_member(
) -> None:
referenced_type_ids: Set[ir_types.TypeId] = single_union_type.shape.visit(
same_properties_as_object=lambda _: set(),
- single_property=lambda single_property: set(self._context.get_referenced_types_of_type_reference(
- single_property.type
- ) or []),
+ single_property=lambda single_property: set(
+ self._context.get_referenced_types_of_type_reference(single_property.type) or []
+ ),
no_properties=lambda: set(),
)
diff --git a/seed/python-sdk/trace/.mock/generators.yml b/seed/python-sdk/trace/.mock/generators.yml
new file mode 100644
index 00000000000..0967ef424bc
--- /dev/null
+++ b/seed/python-sdk/trace/.mock/generators.yml
@@ -0,0 +1 @@
+{}
diff --git a/seed/python-sdk/trace/reference.md b/seed/python-sdk/trace/reference.md
new file mode 100644
index 00000000000..c5d8f615bd6
--- /dev/null
+++ b/seed/python-sdk/trace/reference.md
@@ -0,0 +1,2849 @@
+# Reference
+## V2
+client.v_2.test()
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.v_2.test()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Admin
+client.admin.update_test_submission_status(...)
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+import uuid
+
+from seed import SeedTrace
+from seed.submission import TestSubmissionStatus
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.admin.update_test_submission_status(
+ submission_id=uuid.UUID(
+ "d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32",
+ ),
+ request=TestSubmissionStatus(),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**submission_id:** `SubmissionId`
+
+
+
+
+
+-
+
+**request:** `TestSubmissionStatus`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.admin.send_test_submission_update(...)
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+import datetime
+import uuid
+
+from seed import SeedTrace
+from seed.submission import TestSubmissionUpdateInfo_Running
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.admin.send_test_submission_update(
+ submission_id=uuid.UUID(
+ "d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32",
+ ),
+ update_time=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ update_info=TestSubmissionUpdateInfo_Running(value="QUEUEING_SUBMISSION"),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**submission_id:** `SubmissionId`
+
+
+
+
+
+-
+
+**update_time:** `dt.datetime`
+
+
+
+
+
+-
+
+**update_info:** `TestSubmissionUpdateInfo`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.admin.update_workspace_submission_status(...)
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+import uuid
+
+from seed import SeedTrace
+from seed.submission import WorkspaceSubmissionStatus
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.admin.update_workspace_submission_status(
+ submission_id=uuid.UUID(
+ "d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32",
+ ),
+ request=WorkspaceSubmissionStatus(),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**submission_id:** `SubmissionId`
+
+
+
+
+
+-
+
+**request:** `WorkspaceSubmissionStatus`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.admin.send_workspace_submission_update(...)
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+import datetime
+import uuid
+
+from seed import SeedTrace
+from seed.submission import WorkspaceSubmissionUpdateInfo_Running
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.admin.send_workspace_submission_update(
+ submission_id=uuid.UUID(
+ "d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32",
+ ),
+ update_time=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ update_info=WorkspaceSubmissionUpdateInfo_Running(
+ value="QUEUEING_SUBMISSION"
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**submission_id:** `SubmissionId`
+
+
+
+
+
+-
+
+**update_time:** `dt.datetime`
+
+
+
+
+
+-
+
+**update_info:** `WorkspaceSubmissionUpdateInfo`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.admin.store_traced_test_case(...)
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+import uuid
+
+from seed import SeedTrace
+from seed.commons import DebugVariableValue_IntegerValue
+from seed.submission import (
+ ExpressionLocation,
+ StackInformation,
+ TestCaseResult,
+ TestCaseResultWithStdout,
+ TraceResponse,
+)
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.admin.store_traced_test_case(
+ submission_id=uuid.UUID(
+ "d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32",
+ ),
+ test_case_id="string",
+ result=TestCaseResultWithStdout(
+ result=TestCaseResult(),
+ stdout="string",
+ ),
+ trace_responses=[
+ TraceResponse(
+ submission_id=uuid.UUID(
+ "d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32",
+ ),
+ line_number=1,
+ return_value=DebugVariableValue_IntegerValue(value=1),
+ expression_location=ExpressionLocation(),
+ stack=StackInformation(),
+ stdout="string",
+ )
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**submission_id:** `SubmissionId`
+
+
+
+
+
+-
+
+**test_case_id:** `str`
+
+
+
+
+
+-
+
+**result:** `TestCaseResultWithStdout`
+
+
+
+
+
+-
+
+**trace_responses:** `typing.Sequence[TraceResponse]`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.admin.store_traced_test_case_v_2(...)
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+import uuid
+
+from seed import SeedTrace
+from seed.commons import DebugVariableValue_IntegerValue
+from seed.submission import (
+ ExpressionLocation,
+ StackInformation,
+ TracedFile,
+ TraceResponseV2,
+)
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.admin.store_traced_test_case_v_2(
+ submission_id=uuid.UUID(
+ "d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32",
+ ),
+ test_case_id="string",
+ request=[
+ TraceResponseV2(
+ submission_id=uuid.UUID(
+ "d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32",
+ ),
+ line_number=1,
+ file=TracedFile(),
+ return_value=DebugVariableValue_IntegerValue(value=1),
+ expression_location=ExpressionLocation(),
+ stack=StackInformation(),
+ stdout="string",
+ )
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**submission_id:** `SubmissionId`
+
+
+
+
+
+-
+
+**test_case_id:** `TestCaseId`
+
+
+
+
+
+-
+
+**request:** `typing.Sequence[TraceResponseV2]`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.admin.store_traced_workspace(...)
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+import uuid
+
+from seed import SeedTrace
+from seed.commons import DebugVariableValue_IntegerValue
+from seed.submission import (
+ ExceptionInfo,
+ ExceptionV2_Generic,
+ ExpressionLocation,
+ StackInformation,
+ TraceResponse,
+ WorkspaceRunDetails,
+)
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.admin.store_traced_workspace(
+ submission_id=uuid.UUID(
+ "d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32",
+ ),
+ workspace_run_details=WorkspaceRunDetails(
+ exception_v_2=ExceptionV2_Generic(),
+ exception=ExceptionInfo(),
+ stdout="string",
+ ),
+ trace_responses=[
+ TraceResponse(
+ submission_id=uuid.UUID(
+ "d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32",
+ ),
+ line_number=1,
+ return_value=DebugVariableValue_IntegerValue(value=1),
+ expression_location=ExpressionLocation(),
+ stack=StackInformation(),
+ stdout="string",
+ )
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**submission_id:** `SubmissionId`
+
+
+
+
+
+-
+
+**workspace_run_details:** `WorkspaceRunDetails`
+
+
+
+
+
+-
+
+**trace_responses:** `typing.Sequence[TraceResponse]`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.admin.store_traced_workspace_v_2(...)
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+import uuid
+
+from seed import SeedTrace
+from seed.commons import DebugVariableValue_IntegerValue
+from seed.submission import (
+ ExpressionLocation,
+ StackInformation,
+ TracedFile,
+ TraceResponseV2,
+)
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.admin.store_traced_workspace_v_2(
+ submission_id=uuid.UUID(
+ "d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32",
+ ),
+ request=[
+ TraceResponseV2(
+ submission_id=uuid.UUID(
+ "d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32",
+ ),
+ line_number=1,
+ file=TracedFile(),
+ return_value=DebugVariableValue_IntegerValue(value=1),
+ expression_location=ExpressionLocation(),
+ stack=StackInformation(),
+ stdout="string",
+ )
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**submission_id:** `SubmissionId`
+
+
+
+
+
+-
+
+**request:** `typing.Sequence[TraceResponseV2]`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Homepage
+client.homepage.get_homepage_problems()
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.homepage.get_homepage_problems()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.homepage.set_homepage_problems(...)
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.homepage.set_homepage_problems(
+ request=["string"],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request:** `typing.Sequence[ProblemId]`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Migration
+client.migration.get_attempted_migrations(...)
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.migration.get_attempted_migrations(
+ admin_key_header="string",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**admin_key_header:** `str`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Playlist
+client.playlist.create_playlist(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Create a new playlist
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+import datetime
+
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.playlist.create_playlist(
+ service_param=1,
+ datetime=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ optional_datetime=datetime.datetime.fromisoformat(
+ "2024-01-15 09:30:00+00:00",
+ ),
+ name="string",
+ problems=["string"],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**service_param:** `int`
+
+
+
+
+
+-
+
+**datetime:** `dt.datetime`
+
+
+
+
+
+-
+
+**name:** `str`
+
+
+
+
+
+-
+
+**problems:** `typing.Sequence[ProblemId]`
+
+
+
+
+
+-
+
+**optional_datetime:** `typing.Optional[dt.datetime]`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.playlist.get_playlists(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns the user's playlists
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.playlist.get_playlists(
+ service_param=1,
+ limit=1,
+ other_field="string",
+ multi_line_docs="string",
+ optional_multiple_field="string",
+ multiple_field="string",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**service_param:** `int`
+
+
+
+
+
+-
+
+**other_field:** `str` — i'm another field
+
+
+
+
+
+-
+
+**multi_line_docs:** `str`
+
+I'm a multiline
+description
+
+
+
+
+
+-
+
+**multiple_field:** `typing.Union[str, typing.Sequence[str]]`
+
+
+
+
+
+-
+
+**limit:** `typing.Optional[int]`
+
+
+
+
+
+-
+
+**optional_multiple_field:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.playlist.get_playlist(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns a playlist
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.playlist.get_playlist(
+ service_param=1,
+ playlist_id="string",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**service_param:** `int`
+
+
+
+
+
+-
+
+**playlist_id:** `PlaylistId`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.playlist.update_playlist(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Updates a playlist
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+from seed.playlist import UpdatePlaylistRequest
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.playlist.update_playlist(
+ service_param=1,
+ playlist_id="string",
+ request=UpdatePlaylistRequest(
+ name="string",
+ problems=["string"],
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**service_param:** `int`
+
+
+
+
+
+-
+
+**playlist_id:** `PlaylistId`
+
+
+
+
+
+-
+
+**request:** `typing.Optional[UpdatePlaylistRequest]`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.playlist.delete_playlist(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Deletes a playlist
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.playlist.delete_playlist(
+ service_param=1,
+ playlist_id="string",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**service_param:** `int`
+
+
+
+
+
+-
+
+**playlist_id:** `PlaylistId`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Problem
+client.problem.create_problem(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Creates a problem
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+from seed.commons import (
+ FileInfo,
+ TestCase,
+ TestCaseWithExpectedResult,
+ VariableType,
+ VariableValue_IntegerValue,
+)
+from seed.problem import (
+ ProblemDescription,
+ ProblemDescriptionBoard_Html,
+ ProblemFiles,
+ VariableTypeAndName,
+)
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.problem.create_problem(
+ problem_name="string",
+ problem_description=ProblemDescription(
+ boards=[ProblemDescriptionBoard_Html(value="string")],
+ ),
+ files={
+ "JAVA": ProblemFiles(
+ solution_file=FileInfo(
+ filename="string",
+ contents="string",
+ ),
+ read_only_files=[
+ FileInfo(
+ filename="string",
+ contents="string",
+ )
+ ],
+ )
+ },
+ input_params=[
+ VariableTypeAndName(
+ variable_type=VariableType(),
+ name="string",
+ )
+ ],
+ output_type=VariableType(),
+ testcases=[
+ TestCaseWithExpectedResult(
+ test_case=TestCase(
+ id="string",
+ params=[VariableValue_IntegerValue(value=1)],
+ ),
+ expected_result=VariableValue_IntegerValue(value=1),
+ )
+ ],
+ method_name="string",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**problem_name:** `str`
+
+
+
+
+
+-
+
+**problem_description:** `ProblemDescription`
+
+
+
+
+
+-
+
+**files:** `typing.Dict[Language, ProblemFiles]`
+
+
+
+
+
+-
+
+**input_params:** `typing.Sequence[VariableTypeAndName]`
+
+
+
+
+
+-
+
+**output_type:** `VariableType`
+
+
+
+
+
+-
+
+**testcases:** `typing.Sequence[TestCaseWithExpectedResult]`
+
+
+
+
+
+-
+
+**method_name:** `str`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.problem.update_problem(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Updates a problem
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+from seed.commons import (
+ FileInfo,
+ TestCase,
+ TestCaseWithExpectedResult,
+ VariableType,
+ VariableValue_IntegerValue,
+)
+from seed.problem import (
+ ProblemDescription,
+ ProblemDescriptionBoard_Html,
+ ProblemFiles,
+ VariableTypeAndName,
+)
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.problem.update_problem(
+ problem_id="string",
+ problem_name="string",
+ problem_description=ProblemDescription(
+ boards=[ProblemDescriptionBoard_Html(value="string")],
+ ),
+ files={
+ "JAVA": ProblemFiles(
+ solution_file=FileInfo(
+ filename="string",
+ contents="string",
+ ),
+ read_only_files=[
+ FileInfo(
+ filename="string",
+ contents="string",
+ )
+ ],
+ )
+ },
+ input_params=[
+ VariableTypeAndName(
+ variable_type=VariableType(),
+ name="string",
+ )
+ ],
+ output_type=VariableType(),
+ testcases=[
+ TestCaseWithExpectedResult(
+ test_case=TestCase(
+ id="string",
+ params=[VariableValue_IntegerValue(value=1)],
+ ),
+ expected_result=VariableValue_IntegerValue(value=1),
+ )
+ ],
+ method_name="string",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**problem_id:** `ProblemId`
+
+
+
+
+
+-
+
+**problem_name:** `str`
+
+
+
+
+
+-
+
+**problem_description:** `ProblemDescription`
+
+
+
+
+
+-
+
+**files:** `typing.Dict[Language, ProblemFiles]`
+
+
+
+
+
+-
+
+**input_params:** `typing.Sequence[VariableTypeAndName]`
+
+
+
+
+
+-
+
+**output_type:** `VariableType`
+
+
+
+
+
+-
+
+**testcases:** `typing.Sequence[TestCaseWithExpectedResult]`
+
+
+
+
+
+-
+
+**method_name:** `str`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.problem.delete_problem(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Soft deletes a problem
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.problem.delete_problem(
+ problem_id="string",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**problem_id:** `ProblemId`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.problem.get_default_starter_files(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns default starter files for problem
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+from seed.commons import VariableType
+from seed.problem import VariableTypeAndName
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.problem.get_default_starter_files(
+ input_params=[
+ VariableTypeAndName(
+ variable_type=VariableType(),
+ name="string",
+ )
+ ],
+ output_type=VariableType(),
+ method_name="string",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**input_params:** `typing.Sequence[VariableTypeAndName]`
+
+
+
+
+
+-
+
+**output_type:** `VariableType`
+
+
+
+
+
+-
+
+**method_name:** `str`
+
+The name of the `method` that the student has to complete.
+The method name cannot include the following characters:
+ - Greater Than `>`
+ - Less Than `<``
+ - Equals `=`
+ - Period `.`
+
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Submission
+client.submission.create_execution_session(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns sessionId and execution server URL for session. Spins up server.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.submission.create_execution_session(
+ language="JAVA",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**language:** `Language`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.submission.get_execution_session(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns execution server URL for session. Returns empty if session isn't registered.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.submission.get_execution_session(
+ session_id="string",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**session_id:** `str`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.submission.stop_execution_session(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Stops execution session.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.submission.stop_execution_session(
+ session_id="string",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**session_id:** `str`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.submission.get_execution_sessions_state()
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.submission.get_execution_sessions_state()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Sysprop
+client.sysprop.set_num_warm_instances(...)
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.sysprop.set_num_warm_instances(
+ language="JAVA",
+ num_warm_instances=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**language:** `Language`
+
+
+
+
+
+-
+
+**num_warm_instances:** `int`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sysprop.get_num_warm_instances()
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.sysprop.get_num_warm_instances()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## V2 Problem
+client.v_2.problem.get_lightweight_problems()
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns lightweight versions of all problems
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.v_2.problem.get_lightweight_problems()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.v_2.problem.get_problems()
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns latest versions of all problems
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.v_2.problem.get_problems()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.v_2.problem.get_latest_problem(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns latest version of a problem
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.v_2.problem.get_latest_problem(
+ problem_id="string",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**problem_id:** `ProblemId`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.v_2.problem.get_problem_version(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns requested version of a problem
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.v_2.problem.get_problem_version(
+ problem_id="string",
+ problem_version=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**problem_id:** `ProblemId`
+
+
+
+
+
+-
+
+**problem_version:** `int`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## V2 V3 Problem
+client.v_2.v_3.problem.get_lightweight_problems()
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns lightweight versions of all problems
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.v_2.v_3.problem.get_lightweight_problems()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.v_2.v_3.problem.get_problems()
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns latest versions of all problems
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.v_2.v_3.problem.get_problems()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.v_2.v_3.problem.get_latest_problem(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns latest version of a problem
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.v_2.v_3.problem.get_latest_problem(
+ problem_id="string",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**problem_id:** `ProblemId`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.v_2.v_3.problem.get_problem_version(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Returns requested version of a problem
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from seed import SeedTrace
+
+client = SeedTrace(
+ x_random_header="YOUR_X_RANDOM_HEADER",
+ token="YOUR_TOKEN",
+)
+client.v_2.v_3.problem.get_problem_version(
+ problem_id="string",
+ problem_version=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**problem_id:** `ProblemId`
+
+
+
+
+
+-
+
+**problem_version:** `int`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/seed/python-sdk/trace/src/seed/core/query_encoder.py b/seed/python-sdk/trace/src/seed/core/query_encoder.py
new file mode 100644
index 00000000000..24076d72ee9
--- /dev/null
+++ b/seed/python-sdk/trace/src/seed/core/query_encoder.py
@@ -0,0 +1,33 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from collections import ChainMap
+from typing import Any, Dict, Optional
+
+import pydantic
+
+
+# Flattens dicts to be of the form {"key[subkey][subkey2]": value} where value is not a dict
+def traverse_query_dict(dict_flat: Dict[str, Any], key_prefix: Optional[str] = None) -> Dict[str, Any]:
+ result = {}
+ for k, v in dict_flat.items():
+ key = f"{key_prefix}[{k}]" if key_prefix is not None else k
+ if isinstance(v, dict):
+ result.update(traverse_query_dict(v, key))
+ else:
+ result[key] = v
+ return result
+
+
+def single_query_encoder(query_key: str, query_value: Any) -> Dict[str, Any]:
+ if isinstance(query_value, pydantic.BaseModel) or isinstance(query_value, dict):
+ if isinstance(query_value, pydantic.BaseModel):
+ obj_dict = query_value.dict(by_alias=True)
+ else:
+ obj_dict = query_value
+ return traverse_query_dict(obj_dict, query_key)
+
+ return {query_key: query_value}
+
+
+def encode_query(query: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
+ return dict(ChainMap(*[single_query_encoder(k, v) for k, v in query.items()])) if query is not None else None
diff --git a/seed/python-sdk/trace/src/seed/core/serialization.py b/seed/python-sdk/trace/src/seed/core/serialization.py
new file mode 100644
index 00000000000..8ad5cf8125f
--- /dev/null
+++ b/seed/python-sdk/trace/src/seed/core/serialization.py
@@ -0,0 +1,167 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import collections
+import typing
+
+import typing_extensions
+
+
+class FieldMetadata:
+ """
+ Metadata class used to annotate fields to provide additional information.
+
+ Example:
+ class MyDict(TypedDict):
+ field: typing.Annotated[str, FieldMetadata(alias="field_name")]
+
+ Will serialize: `{"field": "value"}`
+ To: `{"field_name": "value"}`
+ """
+
+ alias: str
+
+ def __init__(self, *, alias: str) -> None:
+ self.alias = alias
+
+
+def convert_and_respect_annotation_metadata(
+ *, object_: typing.Any, annotation: typing.Any, inner_type: typing.Optional[typing.Any] = None
+) -> typing.Any:
+ """
+ Respect the metadata annotations on a field, such as aliasing. This function effectively
+ manipulates the dict-form of an object to respect the metadata annotations. This is primarily used for
+ TypedDicts, which cannot support aliasing out of the box, and can be extended for additional
+ utilities, such as defaults.
+
+ Parameters
+ ----------
+ object_ : typing.Any
+
+ annotation : type
+ The type we're looking to apply typing annotations from
+
+ inner_type : typing.Optional[type]
+
+ Returns
+ -------
+ typing.Any
+ """
+
+ if object_ is None:
+ return None
+ if inner_type is None:
+ inner_type = annotation
+
+ clean_type = _remove_annotations(inner_type)
+ if typing_extensions.is_typeddict(clean_type) and isinstance(object_, typing.Mapping):
+ return _convert_typeddict(object_, clean_type)
+
+ if (
+ # If you're iterating on a string, do not bother to coerce it to a sequence.
+ (not isinstance(object_, str))
+ and (
+ (
+ (
+ typing_extensions.get_origin(clean_type) == typing.List
+ or typing_extensions.get_origin(clean_type) == list
+ or clean_type == typing.List
+ )
+ and isinstance(object_, typing.List)
+ )
+ or (
+ (
+ typing_extensions.get_origin(clean_type) == typing.Set
+ or typing_extensions.get_origin(clean_type) == set
+ or clean_type == typing.Set
+ )
+ and isinstance(object_, typing.Set)
+ )
+ or (
+ (
+ typing_extensions.get_origin(clean_type) == typing.Sequence
+ or typing_extensions.get_origin(clean_type) == collections.abc.Sequence
+ or clean_type == typing.Sequence
+ )
+ and isinstance(object_, typing.Sequence)
+ )
+ )
+ ):
+ inner_type = typing_extensions.get_args(clean_type)[0]
+ return [
+ convert_and_respect_annotation_metadata(object_=item, annotation=annotation, inner_type=inner_type)
+ for item in object_
+ ]
+
+ if typing_extensions.get_origin(clean_type) == typing.Union:
+ # We should be able to ~relatively~ safely try to convert keys against all
+ # member types in the union, the edge case here is if one member aliases a field
+ # of the same name to a different name from another member
+ # Or if another member aliases a field of the same name that another member does not.
+ for member in typing_extensions.get_args(clean_type):
+ object_ = convert_and_respect_annotation_metadata(object_=object_, annotation=annotation, inner_type=member)
+ return object_
+
+ annotated_type = _get_annotation(annotation)
+ if annotated_type is None:
+ return object_
+
+ # If the object is not a TypedDict, a Union, or other container (list, set, sequence, etc.)
+ # Then we can safely call it on the recursive conversion.
+ return object_
+
+
+def _convert_typeddict(object_: typing.Mapping[str, object], expected_type: typing.Any) -> typing.Mapping[str, object]:
+ converted_object: typing.Dict[str, object] = {}
+ annotations = typing_extensions.get_type_hints(expected_type, include_extras=True)
+ for key, value in object_.items():
+ type_ = annotations.get(key)
+ if type_ is None:
+ converted_object[key] = value
+ else:
+ converted_object[_alias_key(key, type_)] = convert_and_respect_annotation_metadata(
+ object_=value, annotation=type_
+ )
+ return converted_object
+
+
+def _get_annotation(type_: typing.Any) -> typing.Optional[typing.Any]:
+ maybe_annotated_type = typing_extensions.get_origin(type_)
+ if maybe_annotated_type is None:
+ return None
+
+ if maybe_annotated_type == typing_extensions.NotRequired:
+ type_ = typing_extensions.get_args(type_)[0]
+ maybe_annotated_type = typing_extensions.get_origin(type_)
+
+ if maybe_annotated_type == typing_extensions.Annotated:
+ return type_
+
+ return None
+
+
+def _remove_annotations(type_: typing.Any) -> typing.Any:
+ maybe_annotated_type = typing_extensions.get_origin(type_)
+ if maybe_annotated_type is None:
+ return type_
+
+ if maybe_annotated_type == typing_extensions.NotRequired:
+ return _remove_annotations(typing_extensions.get_args(type_)[0])
+
+ if maybe_annotated_type == typing_extensions.Annotated:
+ return _remove_annotations(typing_extensions.get_args(type_)[0])
+
+ return type_
+
+
+def _alias_key(key: str, type_: typing.Any) -> str:
+ maybe_annotated_type = _get_annotation(type_)
+
+ if maybe_annotated_type is not None:
+ # The actual annotations are 1 onward, the first is the annotated type
+ annotations = typing_extensions.get_args(maybe_annotated_type)[1:]
+
+ for annotation in annotations:
+ if isinstance(annotation, FieldMetadata) and annotation.alias is not None:
+ return annotation.alias
+
+ return key
diff --git a/seed/python-sdk/trace/tests/utils/__init__.py b/seed/python-sdk/trace/tests/utils/__init__.py
new file mode 100644
index 00000000000..f3ea2659bb1
--- /dev/null
+++ b/seed/python-sdk/trace/tests/utils/__init__.py
@@ -0,0 +1,2 @@
+# This file was auto-generated by Fern from our API Definition.
+
diff --git a/seed/python-sdk/trace/tests/utils/assets/models/__init__.py b/seed/python-sdk/trace/tests/utils/assets/models/__init__.py
new file mode 100644
index 00000000000..2cf01263529
--- /dev/null
+++ b/seed/python-sdk/trace/tests/utils/assets/models/__init__.py
@@ -0,0 +1,21 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+from .circle import CircleParams
+from .object_with_defaults import ObjectWithDefaultsParams
+from .object_with_optional_field import ObjectWithOptionalFieldParams
+from .shape import Shape_CircleParams, Shape_SquareParams, ShapeParams
+from .square import SquareParams
+from .undiscriminated_shape import UndiscriminatedShapeParams
+
+__all__ = [
+ "CircleParams",
+ "ObjectWithDefaultsParams",
+ "ObjectWithOptionalFieldParams",
+ "ShapeParams",
+ "Shape_CircleParams",
+ "Shape_SquareParams",
+ "SquareParams",
+ "UndiscriminatedShapeParams",
+]
diff --git a/seed/python-sdk/trace/tests/utils/assets/models/circle.py b/seed/python-sdk/trace/tests/utils/assets/models/circle.py
new file mode 100644
index 00000000000..af7a1bf8a8e
--- /dev/null
+++ b/seed/python-sdk/trace/tests/utils/assets/models/circle.py
@@ -0,0 +1,10 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+import typing_extensions
+from seed.core.serialization import FieldMetadata
+
+
+class CircleParams(typing_extensions.TypedDict):
+ radius_measurement: typing_extensions.Annotated[float, FieldMetadata(alias="radiusMeasurement")]
diff --git a/seed/python-sdk/trace/tests/utils/assets/models/color.py b/seed/python-sdk/trace/tests/utils/assets/models/color.py
new file mode 100644
index 00000000000..2aa2c4c52f0
--- /dev/null
+++ b/seed/python-sdk/trace/tests/utils/assets/models/color.py
@@ -0,0 +1,7 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+Color = typing.Union[typing.Literal["red", "blue"], typing.Any]
diff --git a/seed/python-sdk/trace/tests/utils/assets/models/object_with_defaults.py b/seed/python-sdk/trace/tests/utils/assets/models/object_with_defaults.py
new file mode 100644
index 00000000000..a977b1d2aa1
--- /dev/null
+++ b/seed/python-sdk/trace/tests/utils/assets/models/object_with_defaults.py
@@ -0,0 +1,15 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+import typing_extensions
+
+
+class ObjectWithDefaultsParams(typing_extensions.TypedDict):
+ """
+ Defines properties with default values and validation rules.
+ """
+
+ decimal: typing_extensions.NotRequired[float]
+ string: typing_extensions.NotRequired[str]
+ required_string: str
diff --git a/seed/python-sdk/trace/tests/utils/assets/models/object_with_optional_field.py b/seed/python-sdk/trace/tests/utils/assets/models/object_with_optional_field.py
new file mode 100644
index 00000000000..3ad93d5f305
--- /dev/null
+++ b/seed/python-sdk/trace/tests/utils/assets/models/object_with_optional_field.py
@@ -0,0 +1,35 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+import uuid
+
+import typing_extensions
+from seed.core.serialization import FieldMetadata
+
+from .color import Color
+from .shape import ShapeParams
+from .undiscriminated_shape import UndiscriminatedShapeParams
+
+
+class ObjectWithOptionalFieldParams(typing_extensions.TypedDict):
+ literal: typing.Literal["lit_one"]
+ string: typing_extensions.NotRequired[str]
+ integer: typing_extensions.NotRequired[int]
+ long_: typing_extensions.NotRequired[typing_extensions.Annotated[int, FieldMetadata(alias="long")]]
+ double: typing_extensions.NotRequired[float]
+ bool_: typing_extensions.NotRequired[typing_extensions.Annotated[bool, FieldMetadata(alias="bool")]]
+ datetime: typing_extensions.NotRequired[dt.datetime]
+ date: typing_extensions.NotRequired[dt.date]
+ uuid_: typing_extensions.NotRequired[typing_extensions.Annotated[uuid.UUID, FieldMetadata(alias="uuid")]]
+ base_64: typing_extensions.NotRequired[typing_extensions.Annotated[str, FieldMetadata(alias="base64")]]
+ list_: typing_extensions.NotRequired[typing_extensions.Annotated[typing.Sequence[str], FieldMetadata(alias="list")]]
+ set_: typing_extensions.NotRequired[typing_extensions.Annotated[typing.Set[str], FieldMetadata(alias="set")]]
+ map_: typing_extensions.NotRequired[typing_extensions.Annotated[typing.Dict[int, str], FieldMetadata(alias="map")]]
+ enum: typing_extensions.NotRequired[Color]
+ union: typing_extensions.NotRequired[ShapeParams]
+ second_union: typing_extensions.NotRequired[ShapeParams]
+ undiscriminated_union: typing_extensions.NotRequired[UndiscriminatedShapeParams]
+ any: typing.Any
diff --git a/seed/python-sdk/trace/tests/utils/assets/models/shape.py b/seed/python-sdk/trace/tests/utils/assets/models/shape.py
new file mode 100644
index 00000000000..2c33c877951
--- /dev/null
+++ b/seed/python-sdk/trace/tests/utils/assets/models/shape.py
@@ -0,0 +1,27 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+from __future__ import annotations
+
+import typing
+
+import typing_extensions
+from seed.core.serialization import FieldMetadata
+
+
+class Base(typing_extensions.TypedDict):
+ id: str
+
+
+class Shape_CircleParams(Base):
+ shape_type: typing_extensions.Annotated[typing.Literal["circle"], FieldMetadata(alias="shapeType")]
+ radius_measurement: typing_extensions.Annotated[float, FieldMetadata(alias="radiusMeasurement")]
+
+
+class Shape_SquareParams(Base):
+ shape_type: typing_extensions.Annotated[typing.Literal["square"], FieldMetadata(alias="shapeType")]
+ length_measurement: typing_extensions.Annotated[float, FieldMetadata(alias="lengthMeasurement")]
+
+
+ShapeParams = typing.Union[Shape_CircleParams, Shape_SquareParams]
diff --git a/seed/python-sdk/trace/tests/utils/assets/models/square.py b/seed/python-sdk/trace/tests/utils/assets/models/square.py
new file mode 100644
index 00000000000..b9b7dd319bc
--- /dev/null
+++ b/seed/python-sdk/trace/tests/utils/assets/models/square.py
@@ -0,0 +1,10 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+import typing_extensions
+from seed.core.serialization import FieldMetadata
+
+
+class SquareParams(typing_extensions.TypedDict):
+ length_measurement: typing_extensions.Annotated[float, FieldMetadata(alias="lengthMeasurement")]
diff --git a/seed/python-sdk/trace/tests/utils/assets/models/undiscriminated_shape.py b/seed/python-sdk/trace/tests/utils/assets/models/undiscriminated_shape.py
new file mode 100644
index 00000000000..99f12b300d1
--- /dev/null
+++ b/seed/python-sdk/trace/tests/utils/assets/models/undiscriminated_shape.py
@@ -0,0 +1,10 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from .circle import CircleParams
+from .square import SquareParams
+
+UndiscriminatedShapeParams = typing.Union[CircleParams, SquareParams]
diff --git a/seed/python-sdk/trace/tests/utils/test_http_client.py b/seed/python-sdk/trace/tests/utils/test_http_client.py
new file mode 100644
index 00000000000..edd11ca7afb
--- /dev/null
+++ b/seed/python-sdk/trace/tests/utils/test_http_client.py
@@ -0,0 +1,47 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from seed.core.http_client import get_request_body
+from seed.core.request_options import RequestOptions
+
+
+def get_request_options() -> RequestOptions:
+ return {"additional_body_parameters": {"see you": "later"}}
+
+
+def test_get_json_request_body() -> None:
+ json_body, data_body = get_request_body(json={"hello": "world"}, data=None, request_options=None, omit=None)
+ assert json_body == {"hello": "world"}
+ assert data_body is None
+
+ json_body_extras, data_body_extras = get_request_body(
+ json={"goodbye": "world"}, data=None, request_options=get_request_options(), omit=None
+ )
+
+ assert json_body_extras == {"goodbye": "world", "see you": "later"}
+ assert data_body_extras is None
+
+
+def test_get_files_request_body() -> None:
+ json_body, data_body = get_request_body(json=None, data={"hello": "world"}, request_options=None, omit=None)
+ assert data_body == {"hello": "world"}
+ assert json_body is None
+
+ json_body_extras, data_body_extras = get_request_body(
+ json=None, data={"goodbye": "world"}, request_options=get_request_options(), omit=None
+ )
+
+ assert data_body_extras == {"goodbye": "world", "see you": "later"}
+ assert json_body_extras is None
+
+
+def test_get_none_request_body() -> None:
+ json_body, data_body = get_request_body(json=None, data=None, request_options=None, omit=None)
+ assert data_body is None
+ assert json_body is None
+
+ json_body_extras, data_body_extras = get_request_body(
+ json=None, data=None, request_options=get_request_options(), omit=None
+ )
+
+ assert json_body_extras == {"see you": "later"}
+ assert data_body_extras is None
diff --git a/seed/python-sdk/trace/tests/utils/test_query_encoding.py b/seed/python-sdk/trace/tests/utils/test_query_encoding.py
new file mode 100644
index 00000000000..247e1551b46
--- /dev/null
+++ b/seed/python-sdk/trace/tests/utils/test_query_encoding.py
@@ -0,0 +1,18 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from seed.core.query_encoder import encode_query
+
+
+def test_query_encoding() -> None:
+ assert encode_query({"hello world": "hello world"}) == {"hello world": "hello world"}
+ assert encode_query({"hello_world": {"hello": "world"}}) == {"hello_world[hello]": "world"}
+ assert encode_query({"hello_world": {"hello": {"world": "today"}, "test": "this"}, "hi": "there"}) == {
+ "hello_world[hello][world]": "today",
+ "hello_world[test]": "this",
+ "hi": "there",
+ }
+
+
+def test_encode_query_with_none() -> None:
+ encoded = encode_query(None)
+ assert encoded == None
diff --git a/seed/python-sdk/trace/tests/utils/test_serialization.py b/seed/python-sdk/trace/tests/utils/test_serialization.py
new file mode 100644
index 00000000000..58b1ed66e6d
--- /dev/null
+++ b/seed/python-sdk/trace/tests/utils/test_serialization.py
@@ -0,0 +1,66 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from typing import Any, List
+
+from seed.core.serialization import convert_and_respect_annotation_metadata
+
+from .assets.models import ObjectWithOptionalFieldParams, ShapeParams
+
+UNION_TEST: ShapeParams = {"radius_measurement": 1.0, "shape_type": "circle", "id": "1"}
+UNION_TEST_CONVERTED = {"shapeType": "circle", "radiusMeasurement": 1.0, "id": "1"}
+
+
+def test_convert_and_respect_annotation_metadata() -> None:
+ data: ObjectWithOptionalFieldParams = {
+ "string": "string",
+ "long_": 12345,
+ "bool_": True,
+ "literal": "lit_one",
+ "any": "any",
+ }
+ converted = convert_and_respect_annotation_metadata(object_=data, annotation=ObjectWithOptionalFieldParams)
+ assert converted == {"string": "string", "long": 12345, "bool": True, "literal": "lit_one", "any": "any"}
+
+
+def test_convert_and_respect_annotation_metadata_in_list() -> None:
+ data: List[ObjectWithOptionalFieldParams] = [
+ {"string": "string", "long_": 12345, "bool_": True, "literal": "lit_one", "any": "any"},
+ {"string": "another string", "long_": 67890, "list_": [], "literal": "lit_one", "any": "any"},
+ ]
+ converted = convert_and_respect_annotation_metadata(object_=data, annotation=List[ObjectWithOptionalFieldParams])
+
+ assert converted == [
+ {"string": "string", "long": 12345, "bool": True, "literal": "lit_one", "any": "any"},
+ {"string": "another string", "long": 67890, "list": [], "literal": "lit_one", "any": "any"},
+ ]
+
+
+def test_convert_and_respect_annotation_metadata_in_nested_object() -> None:
+ data: ObjectWithOptionalFieldParams = {
+ "string": "string",
+ "long_": 12345,
+ "union": UNION_TEST,
+ "literal": "lit_one",
+ "any": "any",
+ }
+ converted = convert_and_respect_annotation_metadata(object_=data, annotation=ObjectWithOptionalFieldParams)
+
+ assert converted == {
+ "string": "string",
+ "long": 12345,
+ "union": UNION_TEST_CONVERTED,
+ "literal": "lit_one",
+ "any": "any",
+ }
+
+
+def test_convert_and_respect_annotation_metadata_in_union() -> None:
+ converted = convert_and_respect_annotation_metadata(object_=UNION_TEST, annotation=ShapeParams)
+
+ assert converted == UNION_TEST_CONVERTED
+
+
+def test_convert_and_respect_annotation_metadata_with_empty_object() -> None:
+ data: Any = {}
+ converted = convert_and_respect_annotation_metadata(object_=data, annotation=ShapeParams)
+ assert converted == data