wandb 0.17.0rc1__py3-none-win_amd64.whl → 0.17.1__py3-none-win_amd64.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. wandb/__init__.py +1 -2
  2. wandb/apis/importers/internals/internal.py +0 -1
  3. wandb/apis/importers/wandb.py +12 -7
  4. wandb/apis/internal.py +0 -3
  5. wandb/apis/public/api.py +213 -79
  6. wandb/apis/public/artifacts.py +335 -100
  7. wandb/apis/public/files.py +9 -9
  8. wandb/apis/public/jobs.py +16 -4
  9. wandb/apis/public/projects.py +26 -28
  10. wandb/apis/public/query_generator.py +1 -1
  11. wandb/apis/public/runs.py +163 -65
  12. wandb/apis/public/sweeps.py +2 -2
  13. wandb/apis/reports/__init__.py +1 -7
  14. wandb/apis/reports/v1/__init__.py +5 -27
  15. wandb/apis/reports/v2/__init__.py +7 -19
  16. wandb/apis/workspaces/__init__.py +8 -0
  17. wandb/beta/workflows.py +8 -3
  18. wandb/bin/wandb-core +0 -0
  19. wandb/cli/cli.py +131 -59
  20. wandb/data_types.py +6 -3
  21. wandb/docker/__init__.py +2 -2
  22. wandb/env.py +3 -3
  23. wandb/errors/term.py +10 -2
  24. wandb/filesync/step_checksum.py +1 -4
  25. wandb/filesync/step_prepare.py +4 -24
  26. wandb/filesync/step_upload.py +5 -107
  27. wandb/filesync/upload_job.py +0 -76
  28. wandb/integration/gym/__init__.py +35 -15
  29. wandb/integration/huggingface/resolver.py +2 -2
  30. wandb/integration/keras/callbacks/metrics_logger.py +1 -1
  31. wandb/integration/keras/keras.py +1 -1
  32. wandb/integration/openai/fine_tuning.py +21 -3
  33. wandb/integration/prodigy/prodigy.py +1 -1
  34. wandb/jupyter.py +16 -17
  35. wandb/old/summary.py +1 -1
  36. wandb/plot/confusion_matrix.py +1 -1
  37. wandb/plot/pr_curve.py +2 -1
  38. wandb/plot/roc_curve.py +2 -1
  39. wandb/{plots → plot}/utils.py +13 -25
  40. wandb/proto/v3/wandb_internal_pb2.py +54 -54
  41. wandb/proto/v3/wandb_settings_pb2.py +2 -2
  42. wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
  43. wandb/proto/v4/wandb_internal_pb2.py +54 -54
  44. wandb/proto/v4/wandb_settings_pb2.py +2 -2
  45. wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
  46. wandb/proto/v5/wandb_base_pb2.py +30 -0
  47. wandb/proto/v5/wandb_internal_pb2.py +355 -0
  48. wandb/proto/v5/wandb_server_pb2.py +63 -0
  49. wandb/proto/v5/wandb_settings_pb2.py +45 -0
  50. wandb/proto/v5/wandb_telemetry_pb2.py +41 -0
  51. wandb/proto/wandb_base_pb2.py +2 -0
  52. wandb/proto/wandb_deprecated.py +9 -1
  53. wandb/proto/wandb_generate_deprecated.py +34 -0
  54. wandb/proto/{wandb_internal_codegen.py → wandb_generate_proto.py} +1 -35
  55. wandb/proto/wandb_internal_pb2.py +2 -0
  56. wandb/proto/wandb_server_pb2.py +2 -0
  57. wandb/proto/wandb_settings_pb2.py +2 -0
  58. wandb/proto/wandb_telemetry_pb2.py +2 -0
  59. wandb/sdk/artifacts/artifact.py +68 -22
  60. wandb/sdk/artifacts/artifact_manifest.py +1 -1
  61. wandb/sdk/artifacts/artifact_manifest_entry.py +6 -3
  62. wandb/sdk/artifacts/artifact_manifests/artifact_manifest_v1.py +1 -1
  63. wandb/sdk/artifacts/artifact_saver.py +1 -10
  64. wandb/sdk/artifacts/storage_handlers/local_file_handler.py +6 -2
  65. wandb/sdk/artifacts/storage_handlers/multi_handler.py +1 -1
  66. wandb/sdk/artifacts/storage_handlers/tracking_handler.py +6 -4
  67. wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +2 -42
  68. wandb/sdk/artifacts/storage_policy.py +1 -12
  69. wandb/sdk/data_types/_dtypes.py +8 -8
  70. wandb/sdk/data_types/image.py +2 -2
  71. wandb/sdk/data_types/video.py +5 -3
  72. wandb/sdk/integration_utils/data_logging.py +5 -5
  73. wandb/sdk/interface/interface.py +14 -1
  74. wandb/sdk/interface/interface_shared.py +1 -1
  75. wandb/sdk/internal/file_pusher.py +2 -5
  76. wandb/sdk/internal/file_stream.py +6 -19
  77. wandb/sdk/internal/internal_api.py +148 -136
  78. wandb/sdk/internal/job_builder.py +208 -136
  79. wandb/sdk/internal/progress.py +0 -28
  80. wandb/sdk/internal/sender.py +102 -39
  81. wandb/sdk/internal/settings_static.py +8 -1
  82. wandb/sdk/internal/system/assets/trainium.py +3 -3
  83. wandb/sdk/internal/system/system_info.py +4 -2
  84. wandb/sdk/internal/update.py +1 -1
  85. wandb/sdk/launch/__init__.py +9 -1
  86. wandb/sdk/launch/_launch.py +4 -24
  87. wandb/sdk/launch/_launch_add.py +1 -3
  88. wandb/sdk/launch/_project_spec.py +187 -225
  89. wandb/sdk/launch/agent/agent.py +59 -19
  90. wandb/sdk/launch/agent/config.py +0 -3
  91. wandb/sdk/launch/builder/abstract.py +68 -1
  92. wandb/sdk/launch/builder/build.py +165 -576
  93. wandb/sdk/launch/builder/context_manager.py +235 -0
  94. wandb/sdk/launch/builder/docker_builder.py +7 -23
  95. wandb/sdk/launch/builder/kaniko_builder.py +12 -25
  96. wandb/sdk/launch/builder/templates/dockerfile.py +92 -0
  97. wandb/sdk/launch/create_job.py +51 -45
  98. wandb/sdk/launch/environment/aws_environment.py +26 -1
  99. wandb/sdk/launch/inputs/files.py +148 -0
  100. wandb/sdk/launch/inputs/internal.py +224 -0
  101. wandb/sdk/launch/inputs/manage.py +95 -0
  102. wandb/sdk/launch/registry/google_artifact_registry.py +1 -1
  103. wandb/sdk/launch/runner/abstract.py +2 -2
  104. wandb/sdk/launch/runner/kubernetes_monitor.py +45 -12
  105. wandb/sdk/launch/runner/kubernetes_runner.py +6 -8
  106. wandb/sdk/launch/runner/local_container.py +2 -3
  107. wandb/sdk/launch/runner/local_process.py +8 -29
  108. wandb/sdk/launch/runner/sagemaker_runner.py +20 -14
  109. wandb/sdk/launch/runner/vertex_runner.py +8 -7
  110. wandb/sdk/launch/sweeps/scheduler.py +5 -3
  111. wandb/sdk/launch/sweeps/scheduler_sweep.py +1 -1
  112. wandb/sdk/launch/sweeps/utils.py +4 -4
  113. wandb/sdk/launch/utils.py +16 -138
  114. wandb/sdk/lib/_settings_toposort_generated.py +2 -5
  115. wandb/sdk/lib/apikey.py +4 -2
  116. wandb/sdk/lib/config_util.py +3 -3
  117. wandb/sdk/lib/import_hooks.py +1 -1
  118. wandb/sdk/lib/proto_util.py +22 -1
  119. wandb/sdk/lib/redirect.py +20 -15
  120. wandb/sdk/lib/tracelog.py +1 -1
  121. wandb/sdk/service/service.py +2 -1
  122. wandb/sdk/service/streams.py +5 -5
  123. wandb/sdk/wandb_init.py +25 -59
  124. wandb/sdk/wandb_login.py +28 -25
  125. wandb/sdk/wandb_run.py +123 -53
  126. wandb/sdk/wandb_settings.py +33 -64
  127. wandb/sdk/wandb_setup.py +1 -1
  128. wandb/sdk/wandb_watch.py +1 -1
  129. wandb/sklearn/plot/classifier.py +10 -12
  130. wandb/sklearn/plot/clusterer.py +1 -1
  131. wandb/sync/sync.py +2 -2
  132. wandb/testing/relay.py +32 -17
  133. wandb/util.py +36 -37
  134. wandb/wandb_agent.py +3 -3
  135. wandb/wandb_controller.py +5 -4
  136. {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/METADATA +8 -10
  137. {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/RECORD +140 -162
  138. wandb/apis/reports/v1/_blocks.py +0 -1406
  139. wandb/apis/reports/v1/_helpers.py +0 -70
  140. wandb/apis/reports/v1/_panels.py +0 -1282
  141. wandb/apis/reports/v1/_templates.py +0 -478
  142. wandb/apis/reports/v1/blocks.py +0 -27
  143. wandb/apis/reports/v1/helpers.py +0 -2
  144. wandb/apis/reports/v1/mutations.py +0 -66
  145. wandb/apis/reports/v1/panels.py +0 -17
  146. wandb/apis/reports/v1/report.py +0 -268
  147. wandb/apis/reports/v1/runset.py +0 -144
  148. wandb/apis/reports/v1/templates.py +0 -7
  149. wandb/apis/reports/v1/util.py +0 -406
  150. wandb/apis/reports/v1/validators.py +0 -131
  151. wandb/apis/reports/v2/blocks.py +0 -25
  152. wandb/apis/reports/v2/expr_parsing.py +0 -257
  153. wandb/apis/reports/v2/gql.py +0 -68
  154. wandb/apis/reports/v2/interface.py +0 -1911
  155. wandb/apis/reports/v2/internal.py +0 -867
  156. wandb/apis/reports/v2/metrics.py +0 -6
  157. wandb/apis/reports/v2/panels.py +0 -15
  158. wandb/catboost/__init__.py +0 -9
  159. wandb/fastai/__init__.py +0 -9
  160. wandb/keras/__init__.py +0 -19
  161. wandb/lightgbm/__init__.py +0 -9
  162. wandb/plots/__init__.py +0 -6
  163. wandb/plots/explain_text.py +0 -36
  164. wandb/plots/heatmap.py +0 -81
  165. wandb/plots/named_entity.py +0 -43
  166. wandb/plots/part_of_speech.py +0 -50
  167. wandb/plots/plot_definitions.py +0 -768
  168. wandb/plots/precision_recall.py +0 -121
  169. wandb/plots/roc.py +0 -103
  170. wandb/sacred/__init__.py +0 -3
  171. wandb/xgboost/__init__.py +0 -9
  172. {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/WHEEL +0 -0
  173. {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/entry_points.txt +0 -0
  174. {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,1406 +0,0 @@
1
- import inspect
2
- import re
3
- import urllib
4
- from typing import List as LList
5
- from typing import Optional, Union
6
-
7
- from .... import __version__ as wandb_ver
8
- from .... import termwarn
9
- from ...public import Api as PublicApi
10
- from ._panels import UnknownPanel, WeavePanel, panel_mapping, weave_panels
11
- from .runset import Runset
12
- from .util import (
13
- Attr,
14
- Base,
15
- Block,
16
- InlineCode,
17
- InlineLaTeX,
18
- Link,
19
- Panel,
20
- coalesce,
21
- fix_collisions,
22
- nested_get,
23
- nested_set,
24
- weave_inputs,
25
- )
26
- from .validators import OneOf, TypeValidator
27
-
28
-
29
- class UnknownBlock(Block):
30
- pass
31
-
32
-
33
- class PanelGrid(Block):
34
- runsets: list = Attr(
35
- json_path="spec.metadata.runSets",
36
- validators=[TypeValidator(Runset, how="keys")],
37
- )
38
- panels: list = Attr(
39
- json_path="spec.metadata.panelBankSectionConfig.panels",
40
- validators=[TypeValidator(Panel, how="keys")],
41
- )
42
- custom_run_colors: dict = Attr(
43
- json_path="spec.metadata.customRunColors",
44
- validators=[
45
- TypeValidator(Union[str, tuple], how="keys"),
46
- TypeValidator(str, how="values"),
47
- ],
48
- )
49
- active_runset: Union[str, None] = Attr(json_path="spec.metadata.openRunSet")
50
-
51
- def __init__(
52
- self,
53
- runsets=None,
54
- panels=None,
55
- custom_run_colors=None,
56
- active_runset=None,
57
- *args,
58
- **kwargs,
59
- ):
60
- super().__init__(*args, **kwargs)
61
- self._spec = self._default_panel_grid_spec()
62
- self.runsets = coalesce(runsets, self._default_runsets())
63
- self.panels = coalesce(panels, self._default_panels())
64
- self.custom_run_colors = coalesce(custom_run_colors, {})
65
- self.active_runset = active_runset
66
-
67
- @active_runset.getter
68
- def active_runset(self):
69
- json_path = self._get_path("active_runset")
70
- index = nested_get(self, json_path)
71
- if index is None:
72
- return None
73
- else:
74
- return self.runsets[index].name
75
-
76
- @active_runset.setter
77
- def active_runset(self, name):
78
- json_path = self._get_path("active_runset")
79
- index = None
80
- for i, rs in enumerate(self.runsets):
81
- if rs.name == name:
82
- index = i
83
- break
84
- nested_set(self, json_path, index)
85
-
86
- @panels.getter
87
- def panels(self):
88
- json_path = self._get_path("panels")
89
- specs = nested_get(self, json_path)
90
- panels = []
91
- for pspec in specs:
92
- cls = panel_mapping.get(pspec["viewType"], UnknownPanel)
93
- if cls is UnknownPanel:
94
- termwarn(
95
- inspect.cleandoc(
96
- f"""
97
- UNKNOWN PANEL DETECTED
98
- This can happen if we have added new panels, but you are using an older version of the SDK.
99
- If your report is loading normally, you can safely ignore this message (but we recommend not touching UnknownPanel)
100
- If you think this is an error, please file a bug report including your SDK version ({wandb_ver}) and this spec ({pspec})
101
- """
102
- )
103
- )
104
- if cls is WeavePanel:
105
- for cls in weave_panels:
106
- try:
107
- cls.from_json(pspec)
108
- except Exception:
109
- pass
110
- else:
111
- break
112
- panels.append(cls.from_json(pspec))
113
- return panels
114
-
115
- @panels.setter
116
- def panels(self, new_panels):
117
- json_path = self._get_path("panels")
118
- new_specs = [p.spec for p in fix_collisions(new_panels)]
119
- nested_set(self, json_path, new_specs)
120
-
121
- @runsets.getter
122
- def runsets(self):
123
- json_path = self._get_path("runsets")
124
- specs = nested_get(self, json_path)
125
- return [Runset.from_json(spec) for spec in specs]
126
-
127
- @runsets.setter
128
- def runsets(self, new_runsets):
129
- json_path = self._get_path("runsets")
130
- new_specs = [rs.spec for rs in new_runsets]
131
- nested_set(self, json_path, new_specs)
132
-
133
- @custom_run_colors.getter
134
- def custom_run_colors(self):
135
- json_path = self._get_path("custom_run_colors")
136
- id_colors = nested_get(self, json_path)
137
-
138
- def is_groupid(s):
139
- for rs in self.runsets:
140
- if rs.spec["id"] in s:
141
- return True
142
- return False
143
-
144
- def groupid_to_ordertuple(groupid):
145
- rs = self.runsets[0]
146
- if "-run:" in groupid:
147
- id, rest = groupid.split("-run:", 1)
148
- else:
149
- id, rest = groupid.split("-", 1)
150
- kvs = rest.split("-")
151
- kvs = [rs.pm_query_generator.pc_back_to_front(v) for v in kvs]
152
- keys, ordertuple = zip(*[kv.split(":") for kv in kvs])
153
- rs_name = self._get_rs_by_id(id).name
154
- return (rs_name, *ordertuple)
155
-
156
- def run_id_to_name(id):
157
- for rs in self.runsets:
158
- try:
159
- run = PublicApi().run(f"{rs.entity}/{rs.project}/{id}")
160
- except Exception:
161
- pass
162
- else:
163
- return run.name
164
- raise ValueError("Unable to find this run!")
165
-
166
- color_settings = {}
167
- for id, c in id_colors.items():
168
- if id == "ref":
169
- continue
170
- if is_groupid(id):
171
- key = groupid_to_ordertuple(id)
172
- else:
173
- key = run_id_to_name(id)
174
- color_settings[key] = c
175
- return color_settings
176
-
177
- @custom_run_colors.setter
178
- def custom_run_colors(self, new_custom_run_colors):
179
- json_path = self._get_path("custom_run_colors")
180
- color_settings = {}
181
-
182
- def ordertuple_to_groupid(ordertuple):
183
- rs_name, rest = ordertuple[0], ordertuple[1:]
184
- rs = self._get_rs_by_name(rs_name)
185
- id = rs.spec["id"]
186
- keys = [rs.pm_query_generator.pc_front_to_back(k) for k in rs.groupby]
187
- kvs = [f"{k}:{v}" for k, v in zip(keys, rest)]
188
- linked = "-".join(kvs)
189
- return f"{id}-{linked}"
190
-
191
- def run_name_to_id(name):
192
- for rs in self.runsets:
193
- runs = PublicApi().runs(
194
- path=f"{rs.entity}/{rs.project}", filters={"display_name": name}
195
- )
196
- if len(runs) > 1:
197
- termwarn(
198
- "Multiple runs with the same name found! Using the first one."
199
- )
200
- for run in runs:
201
- if run.name == name:
202
- return run.id
203
- raise ValueError("Unable to find this run!")
204
-
205
- for name, c in new_custom_run_colors.items():
206
- if isinstance(name, tuple):
207
- key = ordertuple_to_groupid(name)
208
- else:
209
- key = run_name_to_id(name)
210
- color_settings[key] = c
211
- nested_set(self, json_path, color_settings)
212
-
213
- def _get_rs_by_id(self, id):
214
- for rs in self.runsets:
215
- if rs.spec["id"] == id:
216
- return rs
217
-
218
- def _get_rs_by_name(self, name):
219
- for rs in self.runsets:
220
- if rs.name == name:
221
- return rs
222
-
223
- @staticmethod
224
- def _default_panel_grid_spec():
225
- return {
226
- "type": "panel-grid",
227
- "children": [{"text": ""}],
228
- "metadata": {
229
- "openViz": True,
230
- "panels": {
231
- "views": {"0": {"name": "Panels", "defaults": [], "config": []}},
232
- "tabs": ["0"],
233
- },
234
- "panelBankConfig": {
235
- "state": 0,
236
- "settings": {
237
- "autoOrganizePrefix": 2,
238
- "showEmptySections": False,
239
- "sortAlphabetically": False,
240
- },
241
- "sections": [
242
- {
243
- "name": "Hidden Panels",
244
- "isOpen": False,
245
- "panels": [],
246
- "type": "flow",
247
- "flowConfig": {
248
- "snapToColumns": True,
249
- "columnsPerPage": 3,
250
- "rowsPerPage": 2,
251
- "gutterWidth": 16,
252
- "boxWidth": 460,
253
- "boxHeight": 300,
254
- },
255
- "sorted": 0,
256
- "localPanelSettings": {
257
- "xAxis": "_step",
258
- "smoothingWeight": 0,
259
- "smoothingType": "exponential",
260
- "ignoreOutliers": False,
261
- "xAxisActive": False,
262
- "smoothingActive": False,
263
- },
264
- }
265
- ],
266
- },
267
- "panelBankSectionConfig": {
268
- "name": "Report Panels",
269
- "isOpen": False,
270
- "panels": [],
271
- "type": "grid",
272
- "flowConfig": {
273
- "snapToColumns": True,
274
- "columnsPerPage": 3,
275
- "rowsPerPage": 2,
276
- "gutterWidth": 16,
277
- "boxWidth": 460,
278
- "boxHeight": 300,
279
- },
280
- "sorted": 0,
281
- "localPanelSettings": {
282
- "xAxis": "_step",
283
- "smoothingWeight": 0,
284
- "smoothingType": "exponential",
285
- "ignoreOutliers": False,
286
- "xAxisActive": False,
287
- "smoothingActive": False,
288
- },
289
- },
290
- "customRunColors": {},
291
- "runSets": [],
292
- "openRunSet": 0,
293
- "name": "unused-name",
294
- },
295
- }
296
-
297
- @staticmethod
298
- def _default_runsets():
299
- return [Runset()]
300
-
301
- @staticmethod
302
- def _default_panels():
303
- return []
304
-
305
-
306
- class List(Base):
307
- @classmethod
308
- def from_json(cls, spec: dict) -> "Union[CheckedList, OrderedList, UnorderedList]":
309
- items = []
310
- for item in spec["children"]:
311
- text = []
312
- for elem in item["children"][0]["children"]:
313
- if elem.get("type") == "latex":
314
- text.append(InlineLaTeX(elem["content"]))
315
- elif elem.get("type") == "link":
316
- text.append(Link(elem["children"][0]["text"], elem["url"]))
317
- elif elem.get("inlineCode"):
318
- text.append(InlineCode(elem["text"]))
319
- elif elem.get("text"):
320
- text.append(elem["text"])
321
- items.append(text)
322
- checked = [item.get("checked") for item in spec["children"]]
323
- ordered = spec.get("ordered")
324
-
325
- # NAND: Either checked or ordered or neither (unordered), never both
326
- if all(x is None for x in checked):
327
- checked = None
328
- if checked is not None and ordered is not None:
329
- raise ValueError(
330
- "Lists can be checked, ordered or neither (unordered), but not both!"
331
- )
332
-
333
- if checked:
334
- return CheckedList(items, checked)
335
- elif ordered:
336
- return OrderedList(items)
337
- else:
338
- return UnorderedList(items)
339
-
340
-
341
- class CheckedList(Block, List):
342
- items: list = Attr()
343
- checked: list = Attr()
344
-
345
- def __init__(self, items=None, checked=None, *args, **kwargs):
346
- super().__init__(*args, **kwargs)
347
- if items is not None and checked is not None and len(items) != len(checked):
348
- raise ValueError("Items and checked lists must be the same length!")
349
-
350
- self.items = coalesce(items, [""])
351
- self.checked = coalesce(checked, [False for _ in self.items])
352
-
353
- @property
354
- def spec(self) -> dict:
355
- children = []
356
- for item, check in zip(self.items, self.checked):
357
- if isinstance(item, list):
358
- content = [
359
- t.spec if not isinstance(t, str) else {"text": t} for t in item
360
- ]
361
- else:
362
- content = [{"text": item}]
363
- children.append(
364
- {
365
- "type": "list-item",
366
- "children": [{"type": "paragraph", "children": content}],
367
- "checked": check,
368
- }
369
- )
370
-
371
- return {"type": "list", "children": children}
372
-
373
-
374
- class OrderedList(Block, List):
375
- items: list = Attr()
376
-
377
- def __init__(self, items=None, *args, **kwargs):
378
- super().__init__(*args, **kwargs)
379
- self.items = coalesce(items, [""])
380
-
381
- @property
382
- def spec(self) -> dict:
383
- children = []
384
- for item in self.items:
385
- if isinstance(item, list):
386
- content = [
387
- t.spec if not isinstance(t, str) else {"text": t} for t in item
388
- ]
389
- else:
390
- content = [{"text": item}]
391
- children.append(
392
- {
393
- "type": "list-item",
394
- "children": [{"type": "paragraph", "children": content}],
395
- "ordered": True,
396
- }
397
- )
398
-
399
- return {"type": "list", "ordered": True, "children": children}
400
-
401
-
402
- class UnorderedList(Block, List):
403
- items: list = Attr()
404
-
405
- def __init__(self, items=None, *args, **kwargs):
406
- super().__init__(*args, **kwargs)
407
- self.items = coalesce(items, [""])
408
-
409
- @property
410
- def spec(self) -> dict:
411
- children = []
412
- for item in self.items:
413
- if isinstance(item, list):
414
- content = [
415
- t.spec if not isinstance(t, str) else {"text": t} for t in item
416
- ]
417
- else:
418
- content = [{"text": item}]
419
- children.append(
420
- {
421
- "type": "list-item",
422
- "children": [{"type": "paragraph", "children": content}],
423
- }
424
- )
425
-
426
- return {"type": "list", "children": children}
427
-
428
-
429
- class Heading(Base):
430
- @classmethod
431
- def from_json(cls, spec: dict) -> "Union[H1,H2,H3]":
432
- level = spec["level"]
433
- level_mapping = {1: H1, 2: H2, 3: H3}
434
- if level not in level_mapping:
435
- raise ValueError(f"`level` must be one of {list(level_mapping.keys())}")
436
-
437
- if isinstance(spec["children"], str):
438
- text = spec["children"]
439
- else:
440
- text = []
441
- for elem in spec["children"]:
442
- if elem.get("type") == "latex":
443
- text.append(InlineLaTeX(elem["content"]))
444
- elif elem.get("type") == "link":
445
- text.append(Link(elem["children"][0]["text"], elem["url"]))
446
- elif elem.get("inlineCode"):
447
- text.append(InlineCode(elem["text"]))
448
- elif elem.get("text"):
449
- text.append(elem["text"])
450
- if not isinstance(text, list):
451
- text = [text]
452
- return level_mapping[level](text)
453
-
454
-
455
- class H1(Block, Heading):
456
- text: Union[str, list, Link] = Attr()
457
-
458
- def __init__(self, text="", *args, **kwargs):
459
- super().__init__(*args, **kwargs)
460
- self.text = text
461
-
462
- @property
463
- def spec(self) -> dict:
464
- if isinstance(self.text, list):
465
- content = [
466
- t.spec if not isinstance(t, str) else {"text": t} for t in self.text
467
- ]
468
- else:
469
- content = [{"text": self.text}]
470
- return {
471
- "type": "heading",
472
- "children": content,
473
- "level": 1,
474
- }
475
-
476
-
477
- class H2(Block, Heading):
478
- text: Union[str, list, Link] = Attr()
479
-
480
- def __init__(self, text="", *args, **kwargs):
481
- super().__init__(*args, **kwargs)
482
- self.text = text
483
-
484
- @property
485
- def spec(self) -> dict:
486
- if isinstance(self.text, list):
487
- content = [
488
- t.spec if not isinstance(t, str) else {"text": t} for t in self.text
489
- ]
490
- else:
491
- content = [{"text": self.text}]
492
- return {
493
- "type": "heading",
494
- "children": content,
495
- "level": 2,
496
- }
497
-
498
-
499
- class H3(Block, Heading):
500
- text: Union[str, list, Link] = Attr()
501
-
502
- def __init__(self, text="", *args, **kwargs):
503
- super().__init__(*args, **kwargs)
504
- self.text = text
505
-
506
- @property
507
- def spec(self) -> dict:
508
- if isinstance(self.text, list):
509
- content = [
510
- t.spec if not isinstance(t, str) else {"text": t} for t in self.text
511
- ]
512
- else:
513
- content = [{"text": self.text}]
514
- return {
515
- "type": "heading",
516
- "children": content,
517
- "level": 3,
518
- }
519
-
520
-
521
- class BlockQuote(Block):
522
- text: str = Attr()
523
-
524
- def __init__(self, text="", *args, **kwargs):
525
- super().__init__(*args, **kwargs)
526
- self.text = text
527
-
528
- @classmethod
529
- def from_json(cls, spec: dict) -> "BlockQuote":
530
- text = spec["children"][0]["text"]
531
- return cls(text)
532
-
533
- @property
534
- def spec(self) -> dict:
535
- return {"type": "block-quote", "children": [{"text": self.text}]}
536
-
537
-
538
- class CalloutBlock(Block):
539
- text: Union[str, list] = Attr()
540
-
541
- def __init__(self, text=" ", *args, **kwargs):
542
- super().__init__(*args, **kwargs)
543
- self.text = text
544
-
545
- def __post_init__(self) -> None:
546
- if isinstance(self.text, str):
547
- self.text = self.text.split("\n")
548
-
549
- @classmethod
550
- def from_json(cls, spec: dict) -> "CalloutBlock":
551
- text = [child["children"][0]["text"] for child in spec["children"]]
552
- return cls(text)
553
-
554
- @property
555
- def spec(self) -> dict:
556
- return {
557
- "type": "callout-block",
558
- "children": [
559
- {"type": "callout-line", "children": [{"text": text}]}
560
- for text in self.text
561
- ],
562
- }
563
-
564
-
565
- class CodeBlock(Block):
566
- code: Union[str, list] = Attr()
567
- language: str = Attr()
568
-
569
- def __init__(self, code=" ", language=None, *args, **kwargs):
570
- super().__init__(*args, **kwargs)
571
- self.code = code
572
- self.language = coalesce(language, "python")
573
-
574
- def __post_init__(self) -> None:
575
- if isinstance(self.code, str):
576
- self.code = self.code.split("\n")
577
-
578
- @classmethod
579
- def from_json(cls, spec: dict) -> "CodeBlock":
580
- code = [child["children"][0]["text"] for child in spec["children"]]
581
- language = spec.get("language", "python")
582
- return cls(code, language)
583
-
584
- @property
585
- def spec(self) -> dict:
586
- language = self.language.lower()
587
- return {
588
- "type": "code-block",
589
- "children": [
590
- {
591
- "type": "code-line",
592
- "children": [{"text": text}],
593
- "language": language,
594
- }
595
- for text in self.code
596
- ],
597
- "language": language,
598
- }
599
-
600
-
601
- class MarkdownBlock(Block):
602
- text: Union[str, list] = Attr()
603
-
604
- def __init__(self, text="", *args, **kwargs):
605
- super().__init__(*args, **kwargs)
606
- self.text = text
607
- if isinstance(self.text, list):
608
- self.text = "\n".join(self.text)
609
-
610
- @classmethod
611
- def from_json(cls, spec: dict) -> "MarkdownBlock":
612
- text = spec["content"]
613
- return cls(text)
614
-
615
- @property
616
- def spec(self) -> dict:
617
- return {
618
- "type": "markdown-block",
619
- "children": [{"text": ""}],
620
- "content": self.text,
621
- }
622
-
623
-
624
- class LaTeXBlock(Block):
625
- text: Union[str, list] = Attr()
626
-
627
- def __init__(self, text="", *args, **kwargs):
628
- super().__init__(*args, **kwargs)
629
- self.text = text
630
- if isinstance(self.text, list):
631
- self.text = "\n".join(self.text)
632
-
633
- @classmethod
634
- def from_json(cls, spec: dict) -> "LaTeXBlock":
635
- text = spec["content"]
636
- return cls(text)
637
-
638
- @property
639
- def spec(self) -> dict:
640
- return {
641
- "type": "latex",
642
- "children": [{"text": ""}],
643
- "content": self.text,
644
- "block": True,
645
- }
646
-
647
-
648
- class Gallery(Block):
649
- ids: list = Attr(validators=[TypeValidator(str, how="keys")])
650
-
651
- def __init__(self, ids, *args, **kwargs):
652
- super().__init__(*args, **kwargs)
653
- self.ids = ids
654
-
655
- @classmethod
656
- def from_json(cls, spec: dict) -> "Gallery":
657
- ids = spec["ids"]
658
- return cls(ids)
659
-
660
- @classmethod
661
- def from_report_urls(cls, urls: LList[str]) -> "Gallery":
662
- from .report import Report
663
-
664
- ids = [Report._url_to_report_id(url) for url in urls]
665
- return cls(ids)
666
-
667
- @property
668
- def spec(self) -> dict:
669
- return {"type": "gallery", "children": [{"text": ""}], "ids": self.ids}
670
-
671
-
672
- class Image(Block):
673
- url: str = Attr()
674
- caption: Optional[str] = Attr()
675
-
676
- def __init__(self, url, caption=None, *args, **kwargs):
677
- super().__init__(*args, **kwargs)
678
- self.url = url
679
- self.caption = caption
680
-
681
- @classmethod
682
- def from_json(cls, spec: dict) -> "Image":
683
- url = spec["url"]
684
- caption = spec["children"][0]["text"] if spec.get("hasCaption") else None
685
- return cls(url, caption)
686
-
687
- @property
688
- def spec(self) -> dict:
689
- if self.caption:
690
- return {
691
- "type": "image",
692
- "children": [{"text": self.caption}],
693
- "url": self.url,
694
- "hasCaption": True,
695
- }
696
- else:
697
- return {"type": "image", "children": [{"text": ""}], "url": self.url}
698
-
699
-
700
- class WeaveBlockSummaryTable(Block):
701
- """This is a hacky solution to support the most common way of getting Weave tables for now..."""
702
-
703
- entity: str = Attr()
704
- project: str = Attr()
705
- table_name: str = Attr()
706
-
707
- def __init__(self, entity, project, table_name, *args, **kwargs):
708
- super().__init__(*args, **kwargs)
709
- self.entity = entity
710
- self.project = project
711
- self.table_name = table_name
712
-
713
- @classmethod
714
- def from_json(cls, spec: dict) -> "WeaveBlockSummaryTable":
715
- entity = spec["config"]["panelConfig"]["exp"]["fromOp"]["inputs"]["obj"][
716
- "fromOp"
717
- ]["inputs"]["run"]["fromOp"]["inputs"]["project"]["fromOp"]["inputs"][
718
- "entityName"
719
- ]["val"]
720
- project = spec["config"]["panelConfig"]["exp"]["fromOp"]["inputs"]["obj"][
721
- "fromOp"
722
- ]["inputs"]["run"]["fromOp"]["inputs"]["project"]["fromOp"]["inputs"][
723
- "projectName"
724
- ]["val"]
725
- table_name = spec["config"]["panelConfig"]["exp"]["fromOp"]["inputs"]["key"][
726
- "val"
727
- ]
728
- return cls(entity, project, table_name)
729
-
730
- @property
731
- def spec(self) -> dict:
732
- return {
733
- "type": "weave-panel",
734
- "children": [{"text": ""}],
735
- "config": {
736
- "panelConfig": {
737
- "exp": {
738
- "nodeType": "output",
739
- "type": {
740
- "type": "tagged",
741
- "tag": {
742
- "type": "tagged",
743
- "tag": {
744
- "type": "typedDict",
745
- "propertyTypes": {
746
- "entityName": "string",
747
- "projectName": "string",
748
- },
749
- },
750
- "value": {
751
- "type": "typedDict",
752
- "propertyTypes": {"project": "project"},
753
- },
754
- },
755
- "value": {
756
- "type": "list",
757
- "objectType": {
758
- "type": "tagged",
759
- "tag": {
760
- "type": "typedDict",
761
- "propertyTypes": {"run": "run"},
762
- },
763
- "value": {
764
- "type": "union",
765
- "members": [
766
- {
767
- "type": "file",
768
- "extension": "json",
769
- "wbObjectType": {
770
- "type": "table",
771
- "columnTypes": {},
772
- },
773
- },
774
- "none",
775
- ],
776
- },
777
- },
778
- },
779
- },
780
- "fromOp": {
781
- "name": "pick",
782
- "inputs": {
783
- "obj": {
784
- "nodeType": "output",
785
- "type": {
786
- "type": "tagged",
787
- "tag": {
788
- "type": "tagged",
789
- "tag": {
790
- "type": "typedDict",
791
- "propertyTypes": {
792
- "entityName": "string",
793
- "projectName": "string",
794
- },
795
- },
796
- "value": {
797
- "type": "typedDict",
798
- "propertyTypes": {"project": "project"},
799
- },
800
- },
801
- "value": {
802
- "type": "list",
803
- "objectType": {
804
- "type": "tagged",
805
- "tag": {
806
- "type": "typedDict",
807
- "propertyTypes": {"run": "run"},
808
- },
809
- "value": {
810
- "type": "union",
811
- "members": [
812
- {
813
- "type": "typedDict",
814
- "propertyTypes": {
815
- "_wandb": {
816
- "type": "typedDict",
817
- "propertyTypes": {
818
- "runtime": "number"
819
- },
820
- }
821
- },
822
- },
823
- {
824
- "type": "typedDict",
825
- "propertyTypes": {
826
- "_step": "number",
827
- "table": {
828
- "type": "file",
829
- "extension": "json",
830
- "wbObjectType": {
831
- "type": "table",
832
- "columnTypes": {},
833
- },
834
- },
835
- "_wandb": {
836
- "type": "typedDict",
837
- "propertyTypes": {
838
- "runtime": "number"
839
- },
840
- },
841
- "_runtime": "number",
842
- "_timestamp": "number",
843
- },
844
- },
845
- {
846
- "type": "typedDict",
847
- "propertyTypes": {},
848
- },
849
- ],
850
- },
851
- },
852
- },
853
- },
854
- "fromOp": {
855
- "name": "run-summary",
856
- "inputs": {
857
- "run": {
858
- "nodeType": "output",
859
- "type": {
860
- "type": "tagged",
861
- "tag": {
862
- "type": "tagged",
863
- "tag": {
864
- "type": "typedDict",
865
- "propertyTypes": {
866
- "entityName": "string",
867
- "projectName": "string",
868
- },
869
- },
870
- "value": {
871
- "type": "typedDict",
872
- "propertyTypes": {
873
- "project": "project"
874
- },
875
- },
876
- },
877
- "value": {
878
- "type": "list",
879
- "objectType": "run",
880
- },
881
- },
882
- "fromOp": {
883
- "name": "project-runs",
884
- "inputs": {
885
- "project": {
886
- "nodeType": "output",
887
- "type": {
888
- "type": "tagged",
889
- "tag": {
890
- "type": "typedDict",
891
- "propertyTypes": {
892
- "entityName": "string",
893
- "projectName": "string",
894
- },
895
- },
896
- "value": "project",
897
- },
898
- "fromOp": {
899
- "name": "root-project",
900
- "inputs": {
901
- "entityName": {
902
- "nodeType": "const",
903
- "type": "string",
904
- "val": self.entity,
905
- },
906
- "projectName": {
907
- "nodeType": "const",
908
- "type": "string",
909
- "val": self.project,
910
- },
911
- },
912
- },
913
- }
914
- },
915
- },
916
- }
917
- },
918
- },
919
- },
920
- "key": {
921
- "nodeType": "const",
922
- "type": "string",
923
- "val": self.table_name,
924
- },
925
- },
926
- },
927
- "__userInput": True,
928
- }
929
- }
930
- },
931
- }
932
-
933
-
934
- class WeaveBlockArtifact(Block):
935
- """This is a hacky solution to support the most common way of getting Weave artifacts for now..."""
936
-
937
- entity: str = Attr()
938
- project: str = Attr()
939
- artifact: str = Attr()
940
- tab: str = Attr(
941
- validators=[OneOf(["overview", "metadata", "usage", "files", "lineage"])]
942
- )
943
-
944
- def __init__(self, entity, project, artifact, tab="overview", *args, **kwargs):
945
- super().__init__(*args, **kwargs)
946
- self.entity = entity
947
- self.project = project
948
- self.artifact = artifact
949
- self.tab = tab
950
-
951
- @classmethod
952
- def from_json(cls, spec: dict) -> "WeaveBlockSummaryTable":
953
- inputs = weave_inputs(spec)
954
- entity = inputs["project"]["fromOp"]["inputs"]["entityName"]["val"]
955
- project = inputs["project"]["fromOp"]["inputs"]["projectName"]["val"]
956
- artifact = inputs["artifactName"]["val"]
957
- tab = spec["config"]["panelConfig"]["panelConfig"]["tabConfigs"]["overview"][
958
- "selectedTab"
959
- ]
960
- return cls(entity, project, artifact, tab)
961
-
962
- @property
963
- def spec(self) -> dict:
964
- return {
965
- "type": "weave-panel",
966
- "children": [{"text": ""}],
967
- "config": {
968
- "panelConfig": {
969
- "exp": {
970
- "nodeType": "output",
971
- "type": {
972
- "type": "tagged",
973
- "tag": {
974
- "type": "tagged",
975
- "tag": {
976
- "type": "typedDict",
977
- "propertyTypes": {
978
- "entityName": "string",
979
- "projectName": "string",
980
- },
981
- },
982
- "value": {
983
- "type": "typedDict",
984
- "propertyTypes": {
985
- "project": "project",
986
- "artifactName": "string",
987
- },
988
- },
989
- },
990
- "value": "artifact",
991
- },
992
- "fromOp": {
993
- "name": "project-artifact",
994
- "inputs": {
995
- "project": {
996
- "nodeType": "output",
997
- "type": {
998
- "type": "tagged",
999
- "tag": {
1000
- "type": "typedDict",
1001
- "propertyTypes": {
1002
- "entityName": "string",
1003
- "projectName": "string",
1004
- },
1005
- },
1006
- "value": "project",
1007
- },
1008
- "fromOp": {
1009
- "name": "root-project",
1010
- "inputs": {
1011
- "entityName": {
1012
- "nodeType": "const",
1013
- "type": "string",
1014
- "val": self.entity,
1015
- },
1016
- "projectName": {
1017
- "nodeType": "const",
1018
- "type": "string",
1019
- "val": self.project,
1020
- },
1021
- },
1022
- },
1023
- },
1024
- "artifactName": {
1025
- "nodeType": "const",
1026
- "type": "string",
1027
- "val": self.artifact,
1028
- },
1029
- },
1030
- },
1031
- "__userInput": True,
1032
- },
1033
- "panelInputType": {
1034
- "type": "tagged",
1035
- "tag": {
1036
- "type": "tagged",
1037
- "tag": {
1038
- "type": "typedDict",
1039
- "propertyTypes": {
1040
- "entityName": "string",
1041
- "projectName": "string",
1042
- },
1043
- },
1044
- "value": {
1045
- "type": "typedDict",
1046
- "propertyTypes": {
1047
- "project": "project",
1048
- "artifactName": "string",
1049
- },
1050
- },
1051
- },
1052
- "value": "artifact",
1053
- },
1054
- "panelConfig": {
1055
- "tabConfigs": {"overview": {"selectedTab": self.tab}}
1056
- },
1057
- }
1058
- },
1059
- }
1060
-
1061
-
1062
- class WeaveBlockArtifactVersionedFile(Block):
1063
- """This is a hacky solution to support the most common way of getting Weave artifact verions for now..."""
1064
-
1065
- entity: str = Attr()
1066
- project: str = Attr()
1067
- artifact: str = Attr()
1068
- version: str = Attr()
1069
- file: str = Attr()
1070
-
1071
- def __init__(self, entity, project, artifact, version, file, *args, **kwargs):
1072
- super().__init__(*args, **kwargs)
1073
- self.entity = entity
1074
- self.project = project
1075
- self.artifact = artifact
1076
- self.version = version
1077
- self.file = file
1078
-
1079
- @classmethod
1080
- def from_json(cls, spec: dict) -> "WeaveBlockSummaryTable":
1081
- inputs = weave_inputs(spec)
1082
- entity = inputs["artifactVersion"]["fromOp"]["inputs"]["project"]["fromOp"][
1083
- "inputs"
1084
- ]["entityName"]["val"]
1085
- project = inputs["artifactVersion"]["fromOp"]["inputs"]["project"]["fromOp"][
1086
- "inputs"
1087
- ]["projectName"]["val"]
1088
- artifact = inputs["artifactVersion"]["fromOp"]["inputs"]["artifactName"]["val"]
1089
- version = inputs["artifactVersion"]["fromOp"]["inputs"]["artifactVersionAlias"][
1090
- "val"
1091
- ]
1092
- file = inputs["path"]["val"]
1093
- return cls(entity, project, artifact, version, file)
1094
-
1095
- @property
1096
- def spec(self) -> dict:
1097
- return {
1098
- "type": "weave-panel",
1099
- "children": [{"text": ""}],
1100
- "config": {
1101
- "panelConfig": {
1102
- "exp": {
1103
- "nodeType": "output",
1104
- "type": {
1105
- "type": "tagged",
1106
- "tag": {
1107
- "type": "tagged",
1108
- "tag": {
1109
- "type": "typedDict",
1110
- "propertyTypes": {
1111
- "entityName": "string",
1112
- "projectName": "string",
1113
- },
1114
- },
1115
- "value": {
1116
- "type": "typedDict",
1117
- "propertyTypes": {
1118
- "project": "project",
1119
- "artifactName": "string",
1120
- "artifactVersionAlias": "string",
1121
- },
1122
- },
1123
- },
1124
- "value": {
1125
- "type": "file",
1126
- "extension": "json",
1127
- "wbObjectType": {"type": "table", "columnTypes": {}},
1128
- },
1129
- },
1130
- "fromOp": {
1131
- "name": "artifactVersion-file",
1132
- "inputs": {
1133
- "artifactVersion": {
1134
- "nodeType": "output",
1135
- "type": {
1136
- "type": "tagged",
1137
- "tag": {
1138
- "type": "tagged",
1139
- "tag": {
1140
- "type": "typedDict",
1141
- "propertyTypes": {
1142
- "entityName": "string",
1143
- "projectName": "string",
1144
- },
1145
- },
1146
- "value": {
1147
- "type": "typedDict",
1148
- "propertyTypes": {
1149
- "project": "project",
1150
- "artifactName": "string",
1151
- "artifactVersionAlias": "string",
1152
- },
1153
- },
1154
- },
1155
- "value": "artifactVersion",
1156
- },
1157
- "fromOp": {
1158
- "name": "project-artifactVersion",
1159
- "inputs": {
1160
- "project": {
1161
- "nodeType": "output",
1162
- "type": {
1163
- "type": "tagged",
1164
- "tag": {
1165
- "type": "typedDict",
1166
- "propertyTypes": {
1167
- "entityName": "string",
1168
- "projectName": "string",
1169
- },
1170
- },
1171
- "value": "project",
1172
- },
1173
- "fromOp": {
1174
- "name": "root-project",
1175
- "inputs": {
1176
- "entityName": {
1177
- "nodeType": "const",
1178
- "type": "string",
1179
- "val": self.entity,
1180
- },
1181
- "projectName": {
1182
- "nodeType": "const",
1183
- "type": "string",
1184
- "val": self.project,
1185
- },
1186
- },
1187
- },
1188
- },
1189
- "artifactName": {
1190
- "nodeType": "const",
1191
- "type": "string",
1192
- "val": self.artifact,
1193
- },
1194
- "artifactVersionAlias": {
1195
- "nodeType": "const",
1196
- "type": "string",
1197
- "val": self.version,
1198
- },
1199
- },
1200
- },
1201
- },
1202
- "path": {
1203
- "nodeType": "const",
1204
- "type": "string",
1205
- "val": self.file,
1206
- },
1207
- },
1208
- },
1209
- "__userInput": True,
1210
- }
1211
- }
1212
- },
1213
- }
1214
-
1215
-
1216
- class HorizontalRule(Block):
1217
- @classmethod
1218
- def from_json(cls, spec: dict) -> "HorizontalRule":
1219
- return cls()
1220
-
1221
- @property
1222
- def spec(self):
1223
- return {"type": "horizontal-rule", "children": [{"text": ""}]}
1224
-
1225
-
1226
- class TableOfContents(Block):
1227
- @classmethod
1228
- def from_json(cls, spec: dict) -> "TableOfContents":
1229
- return cls()
1230
-
1231
- @property
1232
- def spec(self) -> dict:
1233
- return {"type": "table-of-contents", "children": [{"text": ""}]}
1234
-
1235
-
1236
- class SoundCloud(Block):
1237
- url: str = Attr()
1238
-
1239
- def __init__(self, url, *args, **kwargs):
1240
- super().__init__(*args, **kwargs)
1241
- self.url = url
1242
-
1243
- @classmethod
1244
- def from_json(cls, spec: dict) -> "SoundCloud":
1245
- quoted_url = spec["html"].split("url=")[-1].split("&show_artwork")[0]
1246
- url = urllib.parse.unquote(quoted_url)
1247
- return cls(url)
1248
-
1249
- @property
1250
- def spec(self) -> dict:
1251
- quoted_url = urllib.parse.quote(self.url)
1252
- return {
1253
- "type": "soundcloud",
1254
- "html": f'<iframe width="100%" height="400" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?visual=true&url={quoted_url}&show_artwork=true"></iframe>',
1255
- "children": [{"text": ""}],
1256
- }
1257
-
1258
-
1259
- class Twitter(Block):
1260
- embed_html: str = Attr()
1261
-
1262
- def __init__(self, embed_html, *args, **kwargs):
1263
- super().__init__(*args, **kwargs)
1264
- self.embed_html = embed_html
1265
- if self.embed_html:
1266
- pattern = r" <script[\s\S]+?/script>"
1267
- self.embed_html = re.sub(pattern, "\n", self.embed_html)
1268
-
1269
- @classmethod
1270
- def from_json(cls, spec: dict) -> "Twitter":
1271
- embed_html = spec["html"]
1272
- return cls(embed_html)
1273
-
1274
- @property
1275
- def spec(self) -> dict:
1276
- return {"type": "twitter", "html": self.embed_html, "children": [{"text": ""}]}
1277
-
1278
-
1279
- class Spotify(Block):
1280
- spotify_id: str = Attr()
1281
-
1282
- def __init__(self, spotify_id, *args, **kwargs):
1283
- super().__init__(*args, **kwargs)
1284
- self.spotify_id = spotify_id
1285
-
1286
- @classmethod
1287
- def from_json(cls, spec: dict) -> "Spotify":
1288
- return cls(spec["spotifyID"])
1289
-
1290
- @classmethod
1291
- def from_url(cls, url: str) -> "Spotify":
1292
- spotify_id = url.split("/")[-1].split("?")[0]
1293
- return cls(spotify_id)
1294
-
1295
- @property
1296
- def spec(self) -> dict:
1297
- return {
1298
- "type": "spotify",
1299
- "spotifyType": "track",
1300
- "spotifyID": self.spotify_id,
1301
- "children": [{"text": ""}],
1302
- }
1303
-
1304
-
1305
- class Video(Block):
1306
- url: str = Attr()
1307
-
1308
- def __init__(self, url, *args, **kwargs):
1309
- super().__init__(*args, **kwargs)
1310
- self.url = url
1311
-
1312
- @classmethod
1313
- def from_json(cls, spec: dict) -> "Video":
1314
- return cls(spec["url"])
1315
-
1316
- @property
1317
- def spec(self) -> dict:
1318
- return {
1319
- "type": "video",
1320
- "url": self.url,
1321
- "children": [{"text": ""}],
1322
- }
1323
-
1324
-
1325
- class P(Block):
1326
- text: Union[str, InlineLaTeX, InlineCode, Link, list] = Attr()
1327
-
1328
- def __init__(self, text="", *args, **kwargs):
1329
- super().__init__(*args, **kwargs)
1330
- self.text = text
1331
-
1332
- @classmethod
1333
- def from_json(cls, spec):
1334
- if isinstance(spec["children"], str):
1335
- text = spec["children"]
1336
- else:
1337
- text = []
1338
- for elem in spec["children"]:
1339
- if elem.get("type") == "latex":
1340
- text.append(InlineLaTeX(elem["content"]))
1341
- elif elem.get("type") == "link":
1342
- text.append(Link(elem["children"][0]["text"], elem["url"]))
1343
- elif elem.get("inlineCode"):
1344
- text.append(InlineCode(elem["text"]))
1345
- elif elem.get("text"):
1346
- text.append(elem["text"])
1347
-
1348
- if not isinstance(text, list):
1349
- text = [text]
1350
- return cls(text)
1351
-
1352
- @property
1353
- def spec(self) -> dict:
1354
- if isinstance(self.text, list):
1355
- content = [
1356
- t.spec if not isinstance(t, str) else {"text": t} for t in self.text
1357
- ]
1358
- else:
1359
- content = [{"text": self.text}]
1360
-
1361
- return {"type": "paragraph", "children": content}
1362
-
1363
-
1364
- class WeaveBlock(Block):
1365
- def __init__(self, spec, *args, **kwargs):
1366
- super().__init__(*args, **kwargs)
1367
- self._spec = spec
1368
-
1369
- @classmethod
1370
- def from_json(cls, spec):
1371
- obj = cls(spec=spec)
1372
- obj._spec = spec
1373
- return obj
1374
-
1375
- @property
1376
- def spec(self):
1377
- return self._spec
1378
-
1379
-
1380
- block_mapping = {
1381
- "block-quote": BlockQuote,
1382
- "callout-block": CalloutBlock,
1383
- "code-block": CodeBlock,
1384
- "gallery": Gallery,
1385
- "heading": Heading,
1386
- "horizontal-rule": HorizontalRule,
1387
- "image": Image,
1388
- "latex": LaTeXBlock,
1389
- "list": List,
1390
- "markdown-block": MarkdownBlock,
1391
- "panel-grid": PanelGrid,
1392
- "paragraph": P,
1393
- "table-of-contents": TableOfContents,
1394
- "weave-panel": WeaveBlock,
1395
- "video": Video,
1396
- "spotify": Spotify,
1397
- "twitter": Twitter,
1398
- "soundcloud": SoundCloud,
1399
- }
1400
-
1401
- weave_blocks = [
1402
- WeaveBlockSummaryTable,
1403
- WeaveBlockArtifactVersionedFile,
1404
- WeaveBlockArtifact,
1405
- WeaveBlock,
1406
- ]