lightningrod-ai 0.1.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. lightningrod/__init__.py +66 -0
  2. lightningrod/_display.py +204 -0
  3. lightningrod/_errors.py +67 -0
  4. lightningrod/_generated/__init__.py +8 -0
  5. lightningrod/_generated/api/__init__.py +1 -0
  6. lightningrod/_generated/api/datasets/__init__.py +1 -0
  7. lightningrod/_generated/api/datasets/create_dataset_datasets_post.py +133 -0
  8. lightningrod/_generated/api/datasets/get_dataset_datasets_dataset_id_get.py +168 -0
  9. lightningrod/_generated/api/datasets/get_dataset_samples_datasets_dataset_id_samples_get.py +209 -0
  10. lightningrod/_generated/api/datasets/upload_samples_datasets_dataset_id_samples_post.py +190 -0
  11. lightningrod/_generated/api/file_sets/__init__.py +1 -0
  12. lightningrod/_generated/api/file_sets/add_file_to_set_filesets_file_set_id_files_post.py +190 -0
  13. lightningrod/_generated/api/file_sets/create_file_set_filesets_post.py +174 -0
  14. lightningrod/_generated/api/file_sets/get_file_set_filesets_file_set_id_get.py +168 -0
  15. lightningrod/_generated/api/file_sets/list_file_sets_filesets_get.py +173 -0
  16. lightningrod/_generated/api/file_sets/list_files_in_set_filesets_file_set_id_files_get.py +209 -0
  17. lightningrod/_generated/api/files/__init__.py +1 -0
  18. lightningrod/_generated/api/files/create_file_upload_files_post.py +174 -0
  19. lightningrod/_generated/api/open_ai_compatible/__init__.py +1 -0
  20. lightningrod/_generated/api/open_ai_compatible/chat_completions_openai_chat_completions_post.py +174 -0
  21. lightningrod/_generated/api/organizations/__init__.py +1 -0
  22. lightningrod/_generated/api/organizations/get_balance_organizations_balance_get.py +131 -0
  23. lightningrod/_generated/api/samples/__init__.py +1 -0
  24. lightningrod/_generated/api/samples/validate_sample_samples_validate_post.py +174 -0
  25. lightningrod/_generated/api/transform_jobs/__init__.py +1 -0
  26. lightningrod/_generated/api/transform_jobs/cost_estimation_transform_jobs_cost_estimation_post.py +174 -0
  27. lightningrod/_generated/api/transform_jobs/create_transform_job_transform_jobs_post.py +174 -0
  28. lightningrod/_generated/api/transform_jobs/get_transform_job_metrics_transform_jobs_job_id_metrics_get.py +172 -0
  29. lightningrod/_generated/api/transform_jobs/get_transform_job_transform_jobs_job_id_get.py +168 -0
  30. lightningrod/_generated/client.py +268 -0
  31. lightningrod/_generated/errors.py +16 -0
  32. lightningrod/_generated/models/__init__.py +147 -0
  33. lightningrod/_generated/models/answer_type.py +129 -0
  34. lightningrod/_generated/models/answer_type_enum.py +11 -0
  35. lightningrod/_generated/models/balance_response.py +61 -0
  36. lightningrod/_generated/models/chat_completion_request.py +216 -0
  37. lightningrod/_generated/models/chat_completion_response.py +146 -0
  38. lightningrod/_generated/models/chat_message.py +69 -0
  39. lightningrod/_generated/models/choice.py +97 -0
  40. lightningrod/_generated/models/create_dataset_response.py +61 -0
  41. lightningrod/_generated/models/create_file_set_file_request.py +101 -0
  42. lightningrod/_generated/models/create_file_set_file_request_metadata_type_0.py +46 -0
  43. lightningrod/_generated/models/create_file_set_request.py +83 -0
  44. lightningrod/_generated/models/create_file_upload_request.py +91 -0
  45. lightningrod/_generated/models/create_file_upload_response.py +165 -0
  46. lightningrod/_generated/models/create_file_upload_response_metadata_type_0.py +46 -0
  47. lightningrod/_generated/models/create_transform_job_request.py +312 -0
  48. lightningrod/_generated/models/dataset_metadata.py +69 -0
  49. lightningrod/_generated/models/estimate_cost_request.py +243 -0
  50. lightningrod/_generated/models/estimate_cost_response.py +117 -0
  51. lightningrod/_generated/models/event_usage_summary.py +80 -0
  52. lightningrod/_generated/models/file_set.py +128 -0
  53. lightningrod/_generated/models/file_set_file.py +203 -0
  54. lightningrod/_generated/models/file_set_file_metadata_type_0.py +57 -0
  55. lightningrod/_generated/models/file_set_query_seed_generator.py +136 -0
  56. lightningrod/_generated/models/file_set_seed_generator.py +126 -0
  57. lightningrod/_generated/models/filter_criteria.py +83 -0
  58. lightningrod/_generated/models/forward_looking_question.py +130 -0
  59. lightningrod/_generated/models/forward_looking_question_generator.py +217 -0
  60. lightningrod/_generated/models/gdelt_seed_generator.py +103 -0
  61. lightningrod/_generated/models/http_validation_error.py +79 -0
  62. lightningrod/_generated/models/job_usage.py +185 -0
  63. lightningrod/_generated/models/job_usage_by_step_type_0.py +59 -0
  64. lightningrod/_generated/models/label.py +143 -0
  65. lightningrod/_generated/models/list_file_set_files_response.py +113 -0
  66. lightningrod/_generated/models/list_file_sets_response.py +75 -0
  67. lightningrod/_generated/models/llm_model_usage_summary.py +98 -0
  68. lightningrod/_generated/models/mock_transform_config.py +243 -0
  69. lightningrod/_generated/models/mock_transform_config_metadata_additions.py +46 -0
  70. lightningrod/_generated/models/model_config.py +316 -0
  71. lightningrod/_generated/models/model_source_type.py +16 -0
  72. lightningrod/_generated/models/news_context.py +82 -0
  73. lightningrod/_generated/models/news_context_generator.py +127 -0
  74. lightningrod/_generated/models/news_seed_generator.py +220 -0
  75. lightningrod/_generated/models/paginated_samples_response.py +113 -0
  76. lightningrod/_generated/models/pipeline_metrics_response.py +99 -0
  77. lightningrod/_generated/models/question.py +74 -0
  78. lightningrod/_generated/models/question_and_label_generator.py +217 -0
  79. lightningrod/_generated/models/question_generator.py +217 -0
  80. lightningrod/_generated/models/question_pipeline.py +417 -0
  81. lightningrod/_generated/models/question_renderer.py +123 -0
  82. lightningrod/_generated/models/rag_context.py +82 -0
  83. lightningrod/_generated/models/response_message.py +69 -0
  84. lightningrod/_generated/models/rollout.py +130 -0
  85. lightningrod/_generated/models/rollout_generator.py +139 -0
  86. lightningrod/_generated/models/rollout_parsed_output_type_0.py +46 -0
  87. lightningrod/_generated/models/sample.py +323 -0
  88. lightningrod/_generated/models/sample_meta.py +46 -0
  89. lightningrod/_generated/models/seed.py +135 -0
  90. lightningrod/_generated/models/step_cost_breakdown.py +109 -0
  91. lightningrod/_generated/models/transform_job.py +268 -0
  92. lightningrod/_generated/models/transform_job_status.py +11 -0
  93. lightningrod/_generated/models/transform_step_metrics_response.py +131 -0
  94. lightningrod/_generated/models/transform_type.py +25 -0
  95. lightningrod/_generated/models/upload_samples_request.py +75 -0
  96. lightningrod/_generated/models/upload_samples_response.py +69 -0
  97. lightningrod/_generated/models/usage.py +77 -0
  98. lightningrod/_generated/models/usage_summary.py +102 -0
  99. lightningrod/_generated/models/usage_summary_events.py +59 -0
  100. lightningrod/_generated/models/usage_summary_llm_by_model.py +59 -0
  101. lightningrod/_generated/models/validate_sample_response.py +69 -0
  102. lightningrod/_generated/models/validation_error.py +90 -0
  103. lightningrod/_generated/models/web_search_labeler.py +120 -0
  104. lightningrod/_generated/py.typed +1 -0
  105. lightningrod/_generated/types.py +54 -0
  106. lightningrod/client.py +48 -0
  107. lightningrod/datasets/__init__.py +4 -0
  108. lightningrod/datasets/client.py +174 -0
  109. lightningrod/datasets/dataset.py +255 -0
  110. lightningrod/files/__init__.py +0 -0
  111. lightningrod/files/client.py +58 -0
  112. lightningrod/filesets/__init__.py +0 -0
  113. lightningrod/filesets/client.py +106 -0
  114. lightningrod/organization/__init__.py +0 -0
  115. lightningrod/organization/client.py +17 -0
  116. lightningrod/py.typed +0 -0
  117. lightningrod/transforms/__init__.py +0 -0
  118. lightningrod/transforms/client.py +154 -0
  119. lightningrod_ai-0.1.6.dist-info/METADATA +122 -0
  120. lightningrod_ai-0.1.6.dist-info/RECORD +123 -0
  121. lightningrod_ai-0.1.6.dist-info/WHEEL +5 -0
  122. lightningrod_ai-0.1.6.dist-info/licenses/LICENSE +23 -0
  123. lightningrod_ai-0.1.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,220 @@
1
+ from __future__ import annotations
2
+
3
+ import datetime
4
+ from collections.abc import Mapping
5
+ from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast
6
+
7
+ from attrs import define as _attrs_define
8
+ from attrs import field as _attrs_field
9
+ from dateutil.parser import isoparse
10
+
11
+ from ..types import UNSET, Unset
12
+
13
+ if TYPE_CHECKING:
14
+ from ..models.filter_criteria import FilterCriteria
15
+
16
+
17
+ T = TypeVar("T", bound="NewsSeedGenerator")
18
+
19
+
20
+ @_attrs_define
21
+ class NewsSeedGenerator:
22
+ """
23
+ Attributes:
24
+ start_date (datetime.datetime): Start date for seed search
25
+ end_date (datetime.datetime): End date for seed search
26
+ search_query (list[str] | str): Search query for news articles. If multiple queries are provided, a separate
27
+ search will be done for each query.
28
+ config_type (Literal['NEWS_SEED_GENERATOR'] | Unset): Type of transform configuration Default:
29
+ 'NEWS_SEED_GENERATOR'.
30
+ interval_duration_days (int | Unset): Duration of each interval in days Default: 7.
31
+ articles_per_search (int | Unset): Number of articles to fetch per search (max 100). Each query/domain
32
+ combination is a separate search. Default: 10.
33
+ filter_criteria (FilterCriteria | list[FilterCriteria] | None | Unset): Optional criteria for filtering news
34
+ snippets before scraping
35
+ source_domain (list[str] | None | str | Unset): Optional URL source of the news articles, e.g.
36
+ 'https://reuters.com/business', if multiple sources are provided, multiple searchers will be done for each
37
+ interval
38
+ """
39
+
40
+ start_date: datetime.datetime
41
+ end_date: datetime.datetime
42
+ search_query: list[str] | str
43
+ config_type: Literal["NEWS_SEED_GENERATOR"] | Unset = "NEWS_SEED_GENERATOR"
44
+ interval_duration_days: int | Unset = 7
45
+ articles_per_search: int | Unset = 10
46
+ filter_criteria: FilterCriteria | list[FilterCriteria] | None | Unset = UNSET
47
+ source_domain: list[str] | None | str | Unset = UNSET
48
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
49
+
50
+ def to_dict(self) -> dict[str, Any]:
51
+ from ..models.filter_criteria import FilterCriteria
52
+
53
+ start_date = self.start_date.isoformat()
54
+
55
+ end_date = self.end_date.isoformat()
56
+
57
+ search_query: list[str] | str
58
+ if isinstance(self.search_query, list):
59
+ search_query = self.search_query
60
+
61
+ else:
62
+ search_query = self.search_query
63
+
64
+ config_type = self.config_type
65
+
66
+ interval_duration_days = self.interval_duration_days
67
+
68
+ articles_per_search = self.articles_per_search
69
+
70
+ filter_criteria: dict[str, Any] | list[dict[str, Any]] | None | Unset
71
+ if isinstance(self.filter_criteria, Unset):
72
+ filter_criteria = UNSET
73
+ elif isinstance(self.filter_criteria, FilterCriteria):
74
+ filter_criteria = self.filter_criteria.to_dict()
75
+ elif isinstance(self.filter_criteria, list):
76
+ filter_criteria = []
77
+ for filter_criteria_type_1_item_data in self.filter_criteria:
78
+ filter_criteria_type_1_item = filter_criteria_type_1_item_data.to_dict()
79
+ filter_criteria.append(filter_criteria_type_1_item)
80
+
81
+ else:
82
+ filter_criteria = self.filter_criteria
83
+
84
+ source_domain: list[str] | None | str | Unset
85
+ if isinstance(self.source_domain, Unset):
86
+ source_domain = UNSET
87
+ elif isinstance(self.source_domain, list):
88
+ source_domain = self.source_domain
89
+
90
+ else:
91
+ source_domain = self.source_domain
92
+
93
+ field_dict: dict[str, Any] = {}
94
+ field_dict.update(self.additional_properties)
95
+ field_dict.update(
96
+ {
97
+ "start_date": start_date,
98
+ "end_date": end_date,
99
+ "search_query": search_query,
100
+ }
101
+ )
102
+ if config_type is not UNSET:
103
+ field_dict["config_type"] = config_type
104
+ if interval_duration_days is not UNSET:
105
+ field_dict["interval_duration_days"] = interval_duration_days
106
+ if articles_per_search is not UNSET:
107
+ field_dict["articles_per_search"] = articles_per_search
108
+ if filter_criteria is not UNSET:
109
+ field_dict["filter_criteria"] = filter_criteria
110
+ if source_domain is not UNSET:
111
+ field_dict["source_domain"] = source_domain
112
+
113
+ return field_dict
114
+
115
+ @classmethod
116
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
117
+ from ..models.filter_criteria import FilterCriteria
118
+
119
+ d = dict(src_dict)
120
+ start_date = isoparse(d.pop("start_date"))
121
+
122
+ end_date = isoparse(d.pop("end_date"))
123
+
124
+ def _parse_search_query(data: object) -> list[str] | str:
125
+ try:
126
+ if not isinstance(data, list):
127
+ raise TypeError()
128
+ search_query_type_1 = cast(list[str], data)
129
+
130
+ return search_query_type_1
131
+ except (TypeError, ValueError, AttributeError, KeyError):
132
+ pass
133
+ return cast(list[str] | str, data)
134
+
135
+ search_query = _parse_search_query(d.pop("search_query"))
136
+
137
+ config_type = cast(Literal["NEWS_SEED_GENERATOR"] | Unset, d.pop("config_type", UNSET))
138
+ if config_type != "NEWS_SEED_GENERATOR" and not isinstance(config_type, Unset):
139
+ raise ValueError(f"config_type must match const 'NEWS_SEED_GENERATOR', got '{config_type}'")
140
+
141
+ interval_duration_days = d.pop("interval_duration_days", UNSET)
142
+
143
+ articles_per_search = d.pop("articles_per_search", UNSET)
144
+
145
+ def _parse_filter_criteria(data: object) -> FilterCriteria | list[FilterCriteria] | None | Unset:
146
+ if data is None:
147
+ return data
148
+ if isinstance(data, Unset):
149
+ return data
150
+ try:
151
+ if not isinstance(data, dict):
152
+ raise TypeError()
153
+ filter_criteria_type_0 = FilterCriteria.from_dict(data)
154
+
155
+ return filter_criteria_type_0
156
+ except (TypeError, ValueError, AttributeError, KeyError):
157
+ pass
158
+ try:
159
+ if not isinstance(data, list):
160
+ raise TypeError()
161
+ filter_criteria_type_1 = []
162
+ _filter_criteria_type_1 = data
163
+ for filter_criteria_type_1_item_data in _filter_criteria_type_1:
164
+ filter_criteria_type_1_item = FilterCriteria.from_dict(filter_criteria_type_1_item_data)
165
+
166
+ filter_criteria_type_1.append(filter_criteria_type_1_item)
167
+
168
+ return filter_criteria_type_1
169
+ except (TypeError, ValueError, AttributeError, KeyError):
170
+ pass
171
+ return cast(FilterCriteria | list[FilterCriteria] | None | Unset, data)
172
+
173
+ filter_criteria = _parse_filter_criteria(d.pop("filter_criteria", UNSET))
174
+
175
+ def _parse_source_domain(data: object) -> list[str] | None | str | Unset:
176
+ if data is None:
177
+ return data
178
+ if isinstance(data, Unset):
179
+ return data
180
+ try:
181
+ if not isinstance(data, list):
182
+ raise TypeError()
183
+ source_domain_type_1 = cast(list[str], data)
184
+
185
+ return source_domain_type_1
186
+ except (TypeError, ValueError, AttributeError, KeyError):
187
+ pass
188
+ return cast(list[str] | None | str | Unset, data)
189
+
190
+ source_domain = _parse_source_domain(d.pop("source_domain", UNSET))
191
+
192
+ news_seed_generator = cls(
193
+ start_date=start_date,
194
+ end_date=end_date,
195
+ search_query=search_query,
196
+ config_type=config_type,
197
+ interval_duration_days=interval_duration_days,
198
+ articles_per_search=articles_per_search,
199
+ filter_criteria=filter_criteria,
200
+ source_domain=source_domain,
201
+ )
202
+
203
+ news_seed_generator.additional_properties = d
204
+ return news_seed_generator
205
+
206
+ @property
207
+ def additional_keys(self) -> list[str]:
208
+ return list(self.additional_properties.keys())
209
+
210
+ def __getitem__(self, key: str) -> Any:
211
+ return self.additional_properties[key]
212
+
213
+ def __setitem__(self, key: str, value: Any) -> None:
214
+ self.additional_properties[key] = value
215
+
216
+ def __delitem__(self, key: str) -> None:
217
+ del self.additional_properties[key]
218
+
219
+ def __contains__(self, key: str) -> bool:
220
+ return key in self.additional_properties
@@ -0,0 +1,113 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import TYPE_CHECKING, Any, TypeVar, cast
5
+
6
+ from attrs import define as _attrs_define
7
+ from attrs import field as _attrs_field
8
+
9
+ from ..types import UNSET, Unset
10
+
11
+ if TYPE_CHECKING:
12
+ from ..models.sample import Sample
13
+
14
+
15
+ T = TypeVar("T", bound="PaginatedSamplesResponse")
16
+
17
+
18
+ @_attrs_define
19
+ class PaginatedSamplesResponse:
20
+ """
21
+ Attributes:
22
+ samples (list[Sample]):
23
+ has_more (bool):
24
+ total (int):
25
+ next_cursor (None | str | Unset):
26
+ """
27
+
28
+ samples: list[Sample]
29
+ has_more: bool
30
+ total: int
31
+ next_cursor: None | str | Unset = UNSET
32
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
33
+
34
+ def to_dict(self) -> dict[str, Any]:
35
+ samples = []
36
+ for samples_item_data in self.samples:
37
+ samples_item = samples_item_data.to_dict()
38
+ samples.append(samples_item)
39
+
40
+ has_more = self.has_more
41
+
42
+ total = self.total
43
+
44
+ next_cursor: None | str | Unset
45
+ if isinstance(self.next_cursor, Unset):
46
+ next_cursor = UNSET
47
+ else:
48
+ next_cursor = self.next_cursor
49
+
50
+ field_dict: dict[str, Any] = {}
51
+ field_dict.update(self.additional_properties)
52
+ field_dict.update(
53
+ {
54
+ "samples": samples,
55
+ "has_more": has_more,
56
+ "total": total,
57
+ }
58
+ )
59
+ if next_cursor is not UNSET:
60
+ field_dict["next_cursor"] = next_cursor
61
+
62
+ return field_dict
63
+
64
+ @classmethod
65
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
66
+ from ..models.sample import Sample
67
+
68
+ d = dict(src_dict)
69
+ samples = []
70
+ _samples = d.pop("samples")
71
+ for samples_item_data in _samples:
72
+ samples_item = Sample.from_dict(samples_item_data)
73
+
74
+ samples.append(samples_item)
75
+
76
+ has_more = d.pop("has_more")
77
+
78
+ total = d.pop("total")
79
+
80
+ def _parse_next_cursor(data: object) -> None | str | Unset:
81
+ if data is None:
82
+ return data
83
+ if isinstance(data, Unset):
84
+ return data
85
+ return cast(None | str | Unset, data)
86
+
87
+ next_cursor = _parse_next_cursor(d.pop("next_cursor", UNSET))
88
+
89
+ paginated_samples_response = cls(
90
+ samples=samples,
91
+ has_more=has_more,
92
+ total=total,
93
+ next_cursor=next_cursor,
94
+ )
95
+
96
+ paginated_samples_response.additional_properties = d
97
+ return paginated_samples_response
98
+
99
+ @property
100
+ def additional_keys(self) -> list[str]:
101
+ return list(self.additional_properties.keys())
102
+
103
+ def __getitem__(self, key: str) -> Any:
104
+ return self.additional_properties[key]
105
+
106
+ def __setitem__(self, key: str, value: Any) -> None:
107
+ self.additional_properties[key] = value
108
+
109
+ def __delitem__(self, key: str) -> None:
110
+ del self.additional_properties[key]
111
+
112
+ def __contains__(self, key: str) -> bool:
113
+ return key in self.additional_properties
@@ -0,0 +1,99 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import TYPE_CHECKING, Any, TypeVar
5
+
6
+ from attrs import define as _attrs_define
7
+ from attrs import field as _attrs_field
8
+
9
+ if TYPE_CHECKING:
10
+ from ..models.transform_step_metrics_response import TransformStepMetricsResponse
11
+
12
+
13
+ T = TypeVar("T", bound="PipelineMetricsResponse")
14
+
15
+
16
+ @_attrs_define
17
+ class PipelineMetricsResponse:
18
+ """
19
+ Attributes:
20
+ total_input_rows (int):
21
+ total_output_rows (int):
22
+ total_duration_seconds (float):
23
+ steps (list[TransformStepMetricsResponse]):
24
+ """
25
+
26
+ total_input_rows: int
27
+ total_output_rows: int
28
+ total_duration_seconds: float
29
+ steps: list[TransformStepMetricsResponse]
30
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
31
+
32
+ def to_dict(self) -> dict[str, Any]:
33
+ total_input_rows = self.total_input_rows
34
+
35
+ total_output_rows = self.total_output_rows
36
+
37
+ total_duration_seconds = self.total_duration_seconds
38
+
39
+ steps = []
40
+ for steps_item_data in self.steps:
41
+ steps_item = steps_item_data.to_dict()
42
+ steps.append(steps_item)
43
+
44
+ field_dict: dict[str, Any] = {}
45
+ field_dict.update(self.additional_properties)
46
+ field_dict.update(
47
+ {
48
+ "total_input_rows": total_input_rows,
49
+ "total_output_rows": total_output_rows,
50
+ "total_duration_seconds": total_duration_seconds,
51
+ "steps": steps,
52
+ }
53
+ )
54
+
55
+ return field_dict
56
+
57
+ @classmethod
58
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
59
+ from ..models.transform_step_metrics_response import TransformStepMetricsResponse
60
+
61
+ d = dict(src_dict)
62
+ total_input_rows = d.pop("total_input_rows")
63
+
64
+ total_output_rows = d.pop("total_output_rows")
65
+
66
+ total_duration_seconds = d.pop("total_duration_seconds")
67
+
68
+ steps = []
69
+ _steps = d.pop("steps")
70
+ for steps_item_data in _steps:
71
+ steps_item = TransformStepMetricsResponse.from_dict(steps_item_data)
72
+
73
+ steps.append(steps_item)
74
+
75
+ pipeline_metrics_response = cls(
76
+ total_input_rows=total_input_rows,
77
+ total_output_rows=total_output_rows,
78
+ total_duration_seconds=total_duration_seconds,
79
+ steps=steps,
80
+ )
81
+
82
+ pipeline_metrics_response.additional_properties = d
83
+ return pipeline_metrics_response
84
+
85
+ @property
86
+ def additional_keys(self) -> list[str]:
87
+ return list(self.additional_properties.keys())
88
+
89
+ def __getitem__(self, key: str) -> Any:
90
+ return self.additional_properties[key]
91
+
92
+ def __setitem__(self, key: str, value: Any) -> None:
93
+ self.additional_properties[key] = value
94
+
95
+ def __delitem__(self, key: str) -> None:
96
+ del self.additional_properties[key]
97
+
98
+ def __contains__(self, key: str) -> bool:
99
+ return key in self.additional_properties
@@ -0,0 +1,74 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import Any, Literal, TypeVar, cast
5
+
6
+ from attrs import define as _attrs_define
7
+ from attrs import field as _attrs_field
8
+
9
+ from ..types import UNSET, Unset
10
+
11
+ T = TypeVar("T", bound="Question")
12
+
13
+
14
+ @_attrs_define
15
+ class Question:
16
+ """
17
+ Attributes:
18
+ question_text (str):
19
+ question_type (Literal['QUESTION'] | Unset): Default: 'QUESTION'.
20
+ """
21
+
22
+ question_text: str
23
+ question_type: Literal["QUESTION"] | Unset = "QUESTION"
24
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
25
+
26
+ def to_dict(self) -> dict[str, Any]:
27
+ question_text = self.question_text
28
+
29
+ question_type = self.question_type
30
+
31
+ field_dict: dict[str, Any] = {}
32
+ field_dict.update(self.additional_properties)
33
+ field_dict.update(
34
+ {
35
+ "question_text": question_text,
36
+ }
37
+ )
38
+ if question_type is not UNSET:
39
+ field_dict["question_type"] = question_type
40
+
41
+ return field_dict
42
+
43
+ @classmethod
44
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
45
+ d = dict(src_dict)
46
+ question_text = d.pop("question_text")
47
+
48
+ question_type = cast(Literal["QUESTION"] | Unset, d.pop("question_type", UNSET))
49
+ if question_type != "QUESTION" and not isinstance(question_type, Unset):
50
+ raise ValueError(f"question_type must match const 'QUESTION', got '{question_type}'")
51
+
52
+ question = cls(
53
+ question_text=question_text,
54
+ question_type=question_type,
55
+ )
56
+
57
+ question.additional_properties = d
58
+ return question
59
+
60
+ @property
61
+ def additional_keys(self) -> list[str]:
62
+ return list(self.additional_properties.keys())
63
+
64
+ def __getitem__(self, key: str) -> Any:
65
+ return self.additional_properties[key]
66
+
67
+ def __setitem__(self, key: str, value: Any) -> None:
68
+ self.additional_properties[key] = value
69
+
70
+ def __delitem__(self, key: str) -> None:
71
+ del self.additional_properties[key]
72
+
73
+ def __contains__(self, key: str) -> bool:
74
+ return key in self.additional_properties