wandb 0.21.2__py3-none-macosx_12_0_arm64.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 (904) hide show
  1. package_readme.md +97 -0
  2. wandb/__init__.py +248 -0
  3. wandb/__init__.pyi +1230 -0
  4. wandb/__main__.py +3 -0
  5. wandb/_iterutils.py +65 -0
  6. wandb/_pydantic/__init__.py +30 -0
  7. wandb/_pydantic/base.py +128 -0
  8. wandb/_pydantic/utils.py +80 -0
  9. wandb/_pydantic/v1_compat.py +284 -0
  10. wandb/agents/__init__.py +0 -0
  11. wandb/agents/pyagent.py +386 -0
  12. wandb/analytics/__init__.py +3 -0
  13. wandb/analytics/sentry.py +267 -0
  14. wandb/apis/__init__.py +48 -0
  15. wandb/apis/attrs.py +50 -0
  16. wandb/apis/importers/__init__.py +1 -0
  17. wandb/apis/importers/internals/internal.py +382 -0
  18. wandb/apis/importers/internals/protocols.py +103 -0
  19. wandb/apis/importers/internals/util.py +78 -0
  20. wandb/apis/importers/mlflow.py +254 -0
  21. wandb/apis/importers/validation.py +108 -0
  22. wandb/apis/importers/wandb.py +1608 -0
  23. wandb/apis/internal.py +239 -0
  24. wandb/apis/normalize.py +81 -0
  25. wandb/apis/paginator.py +138 -0
  26. wandb/apis/public/__init__.py +35 -0
  27. wandb/apis/public/api.py +2449 -0
  28. wandb/apis/public/artifacts.py +1046 -0
  29. wandb/apis/public/automations.py +85 -0
  30. wandb/apis/public/const.py +4 -0
  31. wandb/apis/public/files.py +402 -0
  32. wandb/apis/public/history.py +201 -0
  33. wandb/apis/public/integrations.py +203 -0
  34. wandb/apis/public/jobs.py +742 -0
  35. wandb/apis/public/projects.py +276 -0
  36. wandb/apis/public/query_generator.py +176 -0
  37. wandb/apis/public/registries/__init__.py +0 -0
  38. wandb/apis/public/registries/_freezable_list.py +179 -0
  39. wandb/apis/public/registries/_utils.py +138 -0
  40. wandb/apis/public/registries/registries_search.py +347 -0
  41. wandb/apis/public/registries/registry.py +358 -0
  42. wandb/apis/public/reports.py +595 -0
  43. wandb/apis/public/runs.py +1216 -0
  44. wandb/apis/public/sweeps.py +440 -0
  45. wandb/apis/public/teams.py +235 -0
  46. wandb/apis/public/users.py +177 -0
  47. wandb/apis/public/utils.py +210 -0
  48. wandb/apis/reports/__init__.py +1 -0
  49. wandb/apis/reports/v1/__init__.py +8 -0
  50. wandb/apis/reports/v2/__init__.py +8 -0
  51. wandb/apis/workspaces/__init__.py +8 -0
  52. wandb/automations/__init__.py +73 -0
  53. wandb/automations/_filters/__init__.py +40 -0
  54. wandb/automations/_filters/expressions.py +181 -0
  55. wandb/automations/_filters/operators.py +258 -0
  56. wandb/automations/_filters/run_metrics.py +330 -0
  57. wandb/automations/_generated/__init__.py +177 -0
  58. wandb/automations/_generated/create_automation.py +17 -0
  59. wandb/automations/_generated/create_generic_webhook_integration.py +43 -0
  60. wandb/automations/_generated/delete_automation.py +15 -0
  61. wandb/automations/_generated/enums.py +35 -0
  62. wandb/automations/_generated/fragments.py +358 -0
  63. wandb/automations/_generated/generic_webhook_integrations_by_entity.py +22 -0
  64. wandb/automations/_generated/get_automations.py +24 -0
  65. wandb/automations/_generated/get_automations_by_entity.py +26 -0
  66. wandb/automations/_generated/input_types.py +104 -0
  67. wandb/automations/_generated/integrations_by_entity.py +22 -0
  68. wandb/automations/_generated/operations.py +647 -0
  69. wandb/automations/_generated/slack_integrations_by_entity.py +22 -0
  70. wandb/automations/_generated/update_automation.py +17 -0
  71. wandb/automations/_utils.py +235 -0
  72. wandb/automations/_validators.py +165 -0
  73. wandb/automations/actions.py +218 -0
  74. wandb/automations/automations.py +85 -0
  75. wandb/automations/events.py +285 -0
  76. wandb/automations/integrations.py +45 -0
  77. wandb/automations/scopes.py +78 -0
  78. wandb/beta/workflows.py +324 -0
  79. wandb/bin/gpu_stats +0 -0
  80. wandb/bin/wandb-core +0 -0
  81. wandb/cli/__init__.py +0 -0
  82. wandb/cli/beta.py +175 -0
  83. wandb/cli/cli.py +2883 -0
  84. wandb/data_types.py +66 -0
  85. wandb/docker/__init__.py +290 -0
  86. wandb/docker/names.py +40 -0
  87. wandb/docker/wandb-entrypoint.sh +33 -0
  88. wandb/env.py +535 -0
  89. wandb/errors/__init__.py +17 -0
  90. wandb/errors/errors.py +40 -0
  91. wandb/errors/links.py +73 -0
  92. wandb/errors/term.py +415 -0
  93. wandb/errors/util.py +57 -0
  94. wandb/errors/warnings.py +2 -0
  95. wandb/filesync/__init__.py +0 -0
  96. wandb/filesync/dir_watcher.py +404 -0
  97. wandb/filesync/stats.py +100 -0
  98. wandb/filesync/step_checksum.py +142 -0
  99. wandb/filesync/step_prepare.py +179 -0
  100. wandb/filesync/step_upload.py +287 -0
  101. wandb/filesync/upload_job.py +142 -0
  102. wandb/integration/__init__.py +0 -0
  103. wandb/integration/catboost/__init__.py +5 -0
  104. wandb/integration/catboost/catboost.py +182 -0
  105. wandb/integration/cohere/__init__.py +3 -0
  106. wandb/integration/cohere/cohere.py +21 -0
  107. wandb/integration/cohere/resolver.py +347 -0
  108. wandb/integration/diffusers/__init__.py +3 -0
  109. wandb/integration/diffusers/autologger.py +76 -0
  110. wandb/integration/diffusers/pipeline_resolver.py +50 -0
  111. wandb/integration/diffusers/resolvers/__init__.py +9 -0
  112. wandb/integration/diffusers/resolvers/multimodal.py +881 -0
  113. wandb/integration/diffusers/resolvers/utils.py +102 -0
  114. wandb/integration/fastai/__init__.py +243 -0
  115. wandb/integration/gym/__init__.py +98 -0
  116. wandb/integration/huggingface/__init__.py +3 -0
  117. wandb/integration/huggingface/huggingface.py +18 -0
  118. wandb/integration/huggingface/resolver.py +213 -0
  119. wandb/integration/keras/__init__.py +11 -0
  120. wandb/integration/keras/callbacks/__init__.py +5 -0
  121. wandb/integration/keras/callbacks/metrics_logger.py +129 -0
  122. wandb/integration/keras/callbacks/model_checkpoint.py +188 -0
  123. wandb/integration/keras/callbacks/tables_builder.py +228 -0
  124. wandb/integration/keras/keras.py +1086 -0
  125. wandb/integration/kfp/__init__.py +6 -0
  126. wandb/integration/kfp/helpers.py +28 -0
  127. wandb/integration/kfp/kfp_patch.py +335 -0
  128. wandb/integration/kfp/wandb_logging.py +182 -0
  129. wandb/integration/langchain/__init__.py +3 -0
  130. wandb/integration/langchain/wandb_tracer.py +49 -0
  131. wandb/integration/lightgbm/__init__.py +239 -0
  132. wandb/integration/lightning/__init__.py +0 -0
  133. wandb/integration/lightning/fabric/__init__.py +3 -0
  134. wandb/integration/lightning/fabric/logger.py +763 -0
  135. wandb/integration/metaflow/__init__.py +9 -0
  136. wandb/integration/metaflow/data_pandas.py +74 -0
  137. wandb/integration/metaflow/data_pytorch.py +75 -0
  138. wandb/integration/metaflow/data_sklearn.py +76 -0
  139. wandb/integration/metaflow/errors.py +13 -0
  140. wandb/integration/metaflow/metaflow.py +327 -0
  141. wandb/integration/openai/__init__.py +3 -0
  142. wandb/integration/openai/fine_tuning.py +480 -0
  143. wandb/integration/openai/openai.py +22 -0
  144. wandb/integration/openai/resolver.py +240 -0
  145. wandb/integration/prodigy/__init__.py +3 -0
  146. wandb/integration/prodigy/prodigy.py +291 -0
  147. wandb/integration/sacred/__init__.py +117 -0
  148. wandb/integration/sagemaker/__init__.py +14 -0
  149. wandb/integration/sagemaker/auth.py +29 -0
  150. wandb/integration/sagemaker/config.py +58 -0
  151. wandb/integration/sagemaker/files.py +2 -0
  152. wandb/integration/sagemaker/resources.py +63 -0
  153. wandb/integration/sb3/__init__.py +3 -0
  154. wandb/integration/sb3/sb3.py +147 -0
  155. wandb/integration/sklearn/__init__.py +37 -0
  156. wandb/integration/sklearn/calculate/__init__.py +32 -0
  157. wandb/integration/sklearn/calculate/calibration_curves.py +125 -0
  158. wandb/integration/sklearn/calculate/class_proportions.py +68 -0
  159. wandb/integration/sklearn/calculate/confusion_matrix.py +93 -0
  160. wandb/integration/sklearn/calculate/decision_boundaries.py +40 -0
  161. wandb/integration/sklearn/calculate/elbow_curve.py +55 -0
  162. wandb/integration/sklearn/calculate/feature_importances.py +67 -0
  163. wandb/integration/sklearn/calculate/learning_curve.py +64 -0
  164. wandb/integration/sklearn/calculate/outlier_candidates.py +69 -0
  165. wandb/integration/sklearn/calculate/residuals.py +86 -0
  166. wandb/integration/sklearn/calculate/silhouette.py +118 -0
  167. wandb/integration/sklearn/calculate/summary_metrics.py +62 -0
  168. wandb/integration/sklearn/plot/__init__.py +35 -0
  169. wandb/integration/sklearn/plot/classifier.py +329 -0
  170. wandb/integration/sklearn/plot/clusterer.py +146 -0
  171. wandb/integration/sklearn/plot/regressor.py +121 -0
  172. wandb/integration/sklearn/plot/shared.py +91 -0
  173. wandb/integration/sklearn/utils.py +184 -0
  174. wandb/integration/tensorboard/__init__.py +10 -0
  175. wandb/integration/tensorboard/log.py +351 -0
  176. wandb/integration/tensorboard/monkeypatch.py +186 -0
  177. wandb/integration/tensorflow/__init__.py +5 -0
  178. wandb/integration/tensorflow/estimator_hook.py +54 -0
  179. wandb/integration/torch/__init__.py +0 -0
  180. wandb/integration/torch/wandb_torch.py +554 -0
  181. wandb/integration/ultralytics/__init__.py +11 -0
  182. wandb/integration/ultralytics/bbox_utils.py +215 -0
  183. wandb/integration/ultralytics/callback.py +528 -0
  184. wandb/integration/ultralytics/classification_utils.py +83 -0
  185. wandb/integration/ultralytics/mask_utils.py +202 -0
  186. wandb/integration/ultralytics/pose_utils.py +103 -0
  187. wandb/integration/weave/__init__.py +6 -0
  188. wandb/integration/weave/interface.py +49 -0
  189. wandb/integration/weave/weave.py +63 -0
  190. wandb/integration/xgboost/__init__.py +11 -0
  191. wandb/integration/xgboost/xgboost.py +189 -0
  192. wandb/integration/yolov8/__init__.py +0 -0
  193. wandb/integration/yolov8/yolov8.py +284 -0
  194. wandb/jupyter.py +538 -0
  195. wandb/mpmain/__init__.py +0 -0
  196. wandb/mpmain/__main__.py +1 -0
  197. wandb/old/__init__.py +0 -0
  198. wandb/old/core.py +53 -0
  199. wandb/old/settings.py +176 -0
  200. wandb/old/summary.py +438 -0
  201. wandb/plot/__init__.py +30 -0
  202. wandb/plot/bar.py +71 -0
  203. wandb/plot/confusion_matrix.py +185 -0
  204. wandb/plot/custom_chart.py +147 -0
  205. wandb/plot/histogram.py +66 -0
  206. wandb/plot/line.py +75 -0
  207. wandb/plot/line_series.py +173 -0
  208. wandb/plot/pr_curve.py +186 -0
  209. wandb/plot/roc_curve.py +163 -0
  210. wandb/plot/scatter.py +66 -0
  211. wandb/plot/utils.py +184 -0
  212. wandb/plot/viz.py +41 -0
  213. wandb/proto/__init__.py +0 -0
  214. wandb/proto/v3/__init__.py +0 -0
  215. wandb/proto/v3/wandb_base_pb2.py +55 -0
  216. wandb/proto/v3/wandb_internal_pb2.py +1728 -0
  217. wandb/proto/v3/wandb_server_pb2.py +228 -0
  218. wandb/proto/v3/wandb_settings_pb2.py +122 -0
  219. wandb/proto/v3/wandb_telemetry_pb2.py +106 -0
  220. wandb/proto/v4/__init__.py +0 -0
  221. wandb/proto/v4/wandb_base_pb2.py +30 -0
  222. wandb/proto/v4/wandb_internal_pb2.py +382 -0
  223. wandb/proto/v4/wandb_server_pb2.py +67 -0
  224. wandb/proto/v4/wandb_settings_pb2.py +47 -0
  225. wandb/proto/v4/wandb_telemetry_pb2.py +41 -0
  226. wandb/proto/v5/wandb_base_pb2.py +31 -0
  227. wandb/proto/v5/wandb_internal_pb2.py +383 -0
  228. wandb/proto/v5/wandb_server_pb2.py +68 -0
  229. wandb/proto/v5/wandb_settings_pb2.py +48 -0
  230. wandb/proto/v5/wandb_telemetry_pb2.py +42 -0
  231. wandb/proto/v6/wandb_base_pb2.py +41 -0
  232. wandb/proto/v6/wandb_internal_pb2.py +393 -0
  233. wandb/proto/v6/wandb_server_pb2.py +78 -0
  234. wandb/proto/v6/wandb_settings_pb2.py +58 -0
  235. wandb/proto/v6/wandb_telemetry_pb2.py +52 -0
  236. wandb/proto/wandb_base_pb2.py +12 -0
  237. wandb/proto/wandb_deprecated.py +59 -0
  238. wandb/proto/wandb_generate_deprecated.py +30 -0
  239. wandb/proto/wandb_generate_proto.py +49 -0
  240. wandb/proto/wandb_internal_pb2.py +18 -0
  241. wandb/proto/wandb_server_pb2.py +12 -0
  242. wandb/proto/wandb_settings_pb2.py +12 -0
  243. wandb/proto/wandb_telemetry_pb2.py +12 -0
  244. wandb/py.typed +0 -0
  245. wandb/sdk/__init__.py +37 -0
  246. wandb/sdk/artifacts/__init__.py +0 -0
  247. wandb/sdk/artifacts/_factories.py +17 -0
  248. wandb/sdk/artifacts/_generated/__init__.py +508 -0
  249. wandb/sdk/artifacts/_generated/add_aliases.py +21 -0
  250. wandb/sdk/artifacts/_generated/artifact_by_id.py +17 -0
  251. wandb/sdk/artifacts/_generated/artifact_by_name.py +22 -0
  252. wandb/sdk/artifacts/_generated/artifact_collection_membership_file_urls.py +43 -0
  253. wandb/sdk/artifacts/_generated/artifact_collection_membership_files.py +43 -0
  254. wandb/sdk/artifacts/_generated/artifact_created_by.py +47 -0
  255. wandb/sdk/artifacts/_generated/artifact_file_urls.py +22 -0
  256. wandb/sdk/artifacts/_generated/artifact_type.py +31 -0
  257. wandb/sdk/artifacts/_generated/artifact_used_by.py +43 -0
  258. wandb/sdk/artifacts/_generated/artifact_version_files.py +36 -0
  259. wandb/sdk/artifacts/_generated/artifact_via_membership_by_name.py +26 -0
  260. wandb/sdk/artifacts/_generated/create_artifact_collection_tag_assignments.py +36 -0
  261. wandb/sdk/artifacts/_generated/delete_aliases.py +21 -0
  262. wandb/sdk/artifacts/_generated/delete_artifact.py +28 -0
  263. wandb/sdk/artifacts/_generated/delete_artifact_collection_tag_assignments.py +25 -0
  264. wandb/sdk/artifacts/_generated/delete_artifact_portfolio.py +35 -0
  265. wandb/sdk/artifacts/_generated/delete_artifact_sequence.py +35 -0
  266. wandb/sdk/artifacts/_generated/enums.py +22 -0
  267. wandb/sdk/artifacts/_generated/fetch_artifact_manifest.py +38 -0
  268. wandb/sdk/artifacts/_generated/fetch_linked_artifacts.py +67 -0
  269. wandb/sdk/artifacts/_generated/fetch_registries.py +32 -0
  270. wandb/sdk/artifacts/_generated/fragments.py +459 -0
  271. wandb/sdk/artifacts/_generated/input_types.py +46 -0
  272. wandb/sdk/artifacts/_generated/link_artifact.py +27 -0
  273. wandb/sdk/artifacts/_generated/move_artifact_collection.py +35 -0
  274. wandb/sdk/artifacts/_generated/operations.py +1223 -0
  275. wandb/sdk/artifacts/_generated/project_artifact_collection.py +101 -0
  276. wandb/sdk/artifacts/_generated/project_artifact_collections.py +33 -0
  277. wandb/sdk/artifacts/_generated/project_artifact_type.py +24 -0
  278. wandb/sdk/artifacts/_generated/project_artifact_types.py +24 -0
  279. wandb/sdk/artifacts/_generated/project_artifacts.py +42 -0
  280. wandb/sdk/artifacts/_generated/registry_collections.py +34 -0
  281. wandb/sdk/artifacts/_generated/registry_versions.py +34 -0
  282. wandb/sdk/artifacts/_generated/run_input_artifacts.py +51 -0
  283. wandb/sdk/artifacts/_generated/run_output_artifacts.py +51 -0
  284. wandb/sdk/artifacts/_generated/unlink_artifact.py +25 -0
  285. wandb/sdk/artifacts/_generated/update_artifact.py +26 -0
  286. wandb/sdk/artifacts/_generated/update_artifact_portfolio.py +35 -0
  287. wandb/sdk/artifacts/_generated/update_artifact_sequence.py +35 -0
  288. wandb/sdk/artifacts/_graphql_fragments.py +19 -0
  289. wandb/sdk/artifacts/_internal_artifact.py +54 -0
  290. wandb/sdk/artifacts/_validators.py +309 -0
  291. wandb/sdk/artifacts/artifact.py +2702 -0
  292. wandb/sdk/artifacts/artifact_download_logger.py +45 -0
  293. wandb/sdk/artifacts/artifact_file_cache.py +251 -0
  294. wandb/sdk/artifacts/artifact_instance_cache.py +17 -0
  295. wandb/sdk/artifacts/artifact_manifest.py +76 -0
  296. wandb/sdk/artifacts/artifact_manifest_entry.py +258 -0
  297. wandb/sdk/artifacts/artifact_manifests/__init__.py +0 -0
  298. wandb/sdk/artifacts/artifact_manifests/artifact_manifest_v1.py +94 -0
  299. wandb/sdk/artifacts/artifact_saver.py +277 -0
  300. wandb/sdk/artifacts/artifact_state.py +13 -0
  301. wandb/sdk/artifacts/artifact_ttl.py +9 -0
  302. wandb/sdk/artifacts/exceptions.py +71 -0
  303. wandb/sdk/artifacts/staging.py +27 -0
  304. wandb/sdk/artifacts/storage_handler.py +62 -0
  305. wandb/sdk/artifacts/storage_handlers/__init__.py +0 -0
  306. wandb/sdk/artifacts/storage_handlers/azure_handler.py +214 -0
  307. wandb/sdk/artifacts/storage_handlers/gcs_handler.py +224 -0
  308. wandb/sdk/artifacts/storage_handlers/http_handler.py +114 -0
  309. wandb/sdk/artifacts/storage_handlers/local_file_handler.py +142 -0
  310. wandb/sdk/artifacts/storage_handlers/multi_handler.py +56 -0
  311. wandb/sdk/artifacts/storage_handlers/s3_handler.py +339 -0
  312. wandb/sdk/artifacts/storage_handlers/tracking_handler.py +68 -0
  313. wandb/sdk/artifacts/storage_handlers/wb_artifact_handler.py +131 -0
  314. wandb/sdk/artifacts/storage_handlers/wb_local_artifact_handler.py +74 -0
  315. wandb/sdk/artifacts/storage_layout.py +8 -0
  316. wandb/sdk/artifacts/storage_policies/__init__.py +4 -0
  317. wandb/sdk/artifacts/storage_policies/register.py +1 -0
  318. wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +580 -0
  319. wandb/sdk/artifacts/storage_policy.py +75 -0
  320. wandb/sdk/backend/__init__.py +0 -0
  321. wandb/sdk/backend/backend.py +57 -0
  322. wandb/sdk/data_types/__init__.py +0 -0
  323. wandb/sdk/data_types/_dtypes.py +914 -0
  324. wandb/sdk/data_types/_private.py +10 -0
  325. wandb/sdk/data_types/audio.py +208 -0
  326. wandb/sdk/data_types/base_types/__init__.py +0 -0
  327. wandb/sdk/data_types/base_types/json_metadata.py +55 -0
  328. wandb/sdk/data_types/base_types/media.py +339 -0
  329. wandb/sdk/data_types/base_types/wb_value.py +295 -0
  330. wandb/sdk/data_types/bokeh.py +87 -0
  331. wandb/sdk/data_types/graph.py +439 -0
  332. wandb/sdk/data_types/helper_types/__init__.py +0 -0
  333. wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +327 -0
  334. wandb/sdk/data_types/helper_types/classes.py +159 -0
  335. wandb/sdk/data_types/helper_types/image_mask.py +251 -0
  336. wandb/sdk/data_types/histogram.py +107 -0
  337. wandb/sdk/data_types/html.py +165 -0
  338. wandb/sdk/data_types/image.py +974 -0
  339. wandb/sdk/data_types/molecule.py +250 -0
  340. wandb/sdk/data_types/object_3d.py +495 -0
  341. wandb/sdk/data_types/plotly.py +95 -0
  342. wandb/sdk/data_types/saved_model.py +435 -0
  343. wandb/sdk/data_types/table.py +1468 -0
  344. wandb/sdk/data_types/table_decorators.py +108 -0
  345. wandb/sdk/data_types/trace_tree.py +440 -0
  346. wandb/sdk/data_types/utils.py +260 -0
  347. wandb/sdk/data_types/video.py +303 -0
  348. wandb/sdk/integration_utils/__init__.py +0 -0
  349. wandb/sdk/integration_utils/auto_logging.py +232 -0
  350. wandb/sdk/integration_utils/data_logging.py +475 -0
  351. wandb/sdk/interface/__init__.py +0 -0
  352. wandb/sdk/interface/constants.py +4 -0
  353. wandb/sdk/interface/interface.py +1056 -0
  354. wandb/sdk/interface/interface_queue.py +40 -0
  355. wandb/sdk/interface/interface_shared.py +471 -0
  356. wandb/sdk/interface/interface_sock.py +49 -0
  357. wandb/sdk/interface/summary_record.py +67 -0
  358. wandb/sdk/internal/__init__.py +0 -0
  359. wandb/sdk/internal/_generated/__init__.py +15 -0
  360. wandb/sdk/internal/_generated/enums.py +4 -0
  361. wandb/sdk/internal/_generated/input_types.py +4 -0
  362. wandb/sdk/internal/_generated/operations.py +15 -0
  363. wandb/sdk/internal/_generated/server_features_query.py +27 -0
  364. wandb/sdk/internal/context.py +89 -0
  365. wandb/sdk/internal/datastore.py +293 -0
  366. wandb/sdk/internal/file_pusher.py +177 -0
  367. wandb/sdk/internal/file_stream.py +686 -0
  368. wandb/sdk/internal/handler.py +854 -0
  369. wandb/sdk/internal/incremental_table_util.py +53 -0
  370. wandb/sdk/internal/internal_api.py +4723 -0
  371. wandb/sdk/internal/job_builder.py +639 -0
  372. wandb/sdk/internal/profiler.py +79 -0
  373. wandb/sdk/internal/progress.py +77 -0
  374. wandb/sdk/internal/run.py +27 -0
  375. wandb/sdk/internal/sample.py +70 -0
  376. wandb/sdk/internal/sender.py +1692 -0
  377. wandb/sdk/internal/sender_config.py +203 -0
  378. wandb/sdk/internal/settings_static.py +120 -0
  379. wandb/sdk/internal/tb_watcher.py +519 -0
  380. wandb/sdk/internal/thread_local_settings.py +18 -0
  381. wandb/sdk/launch/__init__.py +15 -0
  382. wandb/sdk/launch/_launch.py +331 -0
  383. wandb/sdk/launch/_launch_add.py +255 -0
  384. wandb/sdk/launch/_project_spec.py +565 -0
  385. wandb/sdk/launch/agent/__init__.py +5 -0
  386. wandb/sdk/launch/agent/agent.py +931 -0
  387. wandb/sdk/launch/agent/config.py +296 -0
  388. wandb/sdk/launch/agent/job_status_tracker.py +55 -0
  389. wandb/sdk/launch/agent/run_queue_item_file_saver.py +39 -0
  390. wandb/sdk/launch/builder/__init__.py +0 -0
  391. wandb/sdk/launch/builder/abstract.py +156 -0
  392. wandb/sdk/launch/builder/build.py +296 -0
  393. wandb/sdk/launch/builder/context_manager.py +235 -0
  394. wandb/sdk/launch/builder/docker_builder.py +177 -0
  395. wandb/sdk/launch/builder/kaniko_builder.py +595 -0
  396. wandb/sdk/launch/builder/noop.py +58 -0
  397. wandb/sdk/launch/builder/templates/_wandb_bootstrap.py +188 -0
  398. wandb/sdk/launch/builder/templates/dockerfile.py +92 -0
  399. wandb/sdk/launch/create_job.py +541 -0
  400. wandb/sdk/launch/environment/abstract.py +29 -0
  401. wandb/sdk/launch/environment/aws_environment.py +322 -0
  402. wandb/sdk/launch/environment/azure_environment.py +105 -0
  403. wandb/sdk/launch/environment/gcp_environment.py +334 -0
  404. wandb/sdk/launch/environment/local_environment.py +65 -0
  405. wandb/sdk/launch/errors.py +13 -0
  406. wandb/sdk/launch/git_reference.py +109 -0
  407. wandb/sdk/launch/inputs/files.py +148 -0
  408. wandb/sdk/launch/inputs/internal.py +314 -0
  409. wandb/sdk/launch/inputs/manage.py +113 -0
  410. wandb/sdk/launch/inputs/schema.py +40 -0
  411. wandb/sdk/launch/loader.py +249 -0
  412. wandb/sdk/launch/registry/abstract.py +48 -0
  413. wandb/sdk/launch/registry/anon.py +29 -0
  414. wandb/sdk/launch/registry/azure_container_registry.py +124 -0
  415. wandb/sdk/launch/registry/elastic_container_registry.py +192 -0
  416. wandb/sdk/launch/registry/google_artifact_registry.py +219 -0
  417. wandb/sdk/launch/registry/local_registry.py +65 -0
  418. wandb/sdk/launch/runner/__init__.py +0 -0
  419. wandb/sdk/launch/runner/abstract.py +185 -0
  420. wandb/sdk/launch/runner/kubernetes_monitor.py +473 -0
  421. wandb/sdk/launch/runner/kubernetes_runner.py +1285 -0
  422. wandb/sdk/launch/runner/local_container.py +301 -0
  423. wandb/sdk/launch/runner/local_process.py +78 -0
  424. wandb/sdk/launch/runner/sagemaker_runner.py +424 -0
  425. wandb/sdk/launch/runner/vertex_runner.py +225 -0
  426. wandb/sdk/launch/sweeps/__init__.py +37 -0
  427. wandb/sdk/launch/sweeps/scheduler.py +739 -0
  428. wandb/sdk/launch/sweeps/scheduler_sweep.py +90 -0
  429. wandb/sdk/launch/sweeps/utils.py +324 -0
  430. wandb/sdk/launch/utils.py +746 -0
  431. wandb/sdk/launch/wandb_reference.py +138 -0
  432. wandb/sdk/lib/__init__.py +5 -0
  433. wandb/sdk/lib/apikey.py +334 -0
  434. wandb/sdk/lib/asyncio_compat.py +213 -0
  435. wandb/sdk/lib/asyncio_manager.py +252 -0
  436. wandb/sdk/lib/capped_dict.py +26 -0
  437. wandb/sdk/lib/config_util.py +101 -0
  438. wandb/sdk/lib/console_capture.py +219 -0
  439. wandb/sdk/lib/credentials.py +141 -0
  440. wandb/sdk/lib/deprecate.py +27 -0
  441. wandb/sdk/lib/disabled.py +30 -0
  442. wandb/sdk/lib/exit_hooks.py +54 -0
  443. wandb/sdk/lib/file_stream_utils.py +118 -0
  444. wandb/sdk/lib/filenames.py +64 -0
  445. wandb/sdk/lib/filesystem.py +372 -0
  446. wandb/sdk/lib/fsm.py +165 -0
  447. wandb/sdk/lib/gitlib.py +240 -0
  448. wandb/sdk/lib/gql_request.py +65 -0
  449. wandb/sdk/lib/handler_util.py +21 -0
  450. wandb/sdk/lib/hashutil.py +106 -0
  451. wandb/sdk/lib/import_hooks.py +275 -0
  452. wandb/sdk/lib/interrupt.py +37 -0
  453. wandb/sdk/lib/ipython.py +126 -0
  454. wandb/sdk/lib/json_util.py +75 -0
  455. wandb/sdk/lib/lazyloader.py +63 -0
  456. wandb/sdk/lib/module.py +72 -0
  457. wandb/sdk/lib/paths.py +106 -0
  458. wandb/sdk/lib/preinit.py +42 -0
  459. wandb/sdk/lib/printer.py +571 -0
  460. wandb/sdk/lib/printer_asyncio.py +48 -0
  461. wandb/sdk/lib/progress.py +320 -0
  462. wandb/sdk/lib/proto_util.py +90 -0
  463. wandb/sdk/lib/redirect.py +876 -0
  464. wandb/sdk/lib/retry.py +395 -0
  465. wandb/sdk/lib/run_moment.py +82 -0
  466. wandb/sdk/lib/runid.py +12 -0
  467. wandb/sdk/lib/server.py +58 -0
  468. wandb/sdk/lib/service/ipc_support.py +13 -0
  469. wandb/sdk/lib/service/service_client.py +106 -0
  470. wandb/sdk/lib/service/service_connection.py +192 -0
  471. wandb/sdk/lib/service/service_port_file.py +105 -0
  472. wandb/sdk/lib/service/service_process.py +111 -0
  473. wandb/sdk/lib/service/service_token.py +181 -0
  474. wandb/sdk/lib/sparkline.py +44 -0
  475. wandb/sdk/lib/telemetry.py +100 -0
  476. wandb/sdk/lib/timed_input.py +133 -0
  477. wandb/sdk/lib/timer.py +19 -0
  478. wandb/sdk/lib/wb_logging.py +161 -0
  479. wandb/sdk/mailbox/__init__.py +23 -0
  480. wandb/sdk/mailbox/mailbox.py +143 -0
  481. wandb/sdk/mailbox/mailbox_handle.py +132 -0
  482. wandb/sdk/mailbox/response_handle.py +99 -0
  483. wandb/sdk/mailbox/wait_with_progress.py +100 -0
  484. wandb/sdk/projects/_generated/__init__.py +47 -0
  485. wandb/sdk/projects/_generated/delete_project.py +22 -0
  486. wandb/sdk/projects/_generated/enums.py +4 -0
  487. wandb/sdk/projects/_generated/fetch_registry.py +22 -0
  488. wandb/sdk/projects/_generated/fragments.py +41 -0
  489. wandb/sdk/projects/_generated/input_types.py +13 -0
  490. wandb/sdk/projects/_generated/operations.py +88 -0
  491. wandb/sdk/projects/_generated/rename_project.py +27 -0
  492. wandb/sdk/projects/_generated/upsert_registry_project.py +27 -0
  493. wandb/sdk/verify/__init__.py +0 -0
  494. wandb/sdk/verify/verify.py +555 -0
  495. wandb/sdk/wandb_alerts.py +12 -0
  496. wandb/sdk/wandb_config.py +323 -0
  497. wandb/sdk/wandb_helper.py +54 -0
  498. wandb/sdk/wandb_init.py +1581 -0
  499. wandb/sdk/wandb_login.py +332 -0
  500. wandb/sdk/wandb_metric.py +112 -0
  501. wandb/sdk/wandb_require.py +88 -0
  502. wandb/sdk/wandb_require_helpers.py +44 -0
  503. wandb/sdk/wandb_run.py +4088 -0
  504. wandb/sdk/wandb_settings.py +2105 -0
  505. wandb/sdk/wandb_setup.py +560 -0
  506. wandb/sdk/wandb_summary.py +150 -0
  507. wandb/sdk/wandb_sweep.py +120 -0
  508. wandb/sdk/wandb_sync.py +71 -0
  509. wandb/sdk/wandb_watch.py +146 -0
  510. wandb/sklearn.py +35 -0
  511. wandb/sync/__init__.py +3 -0
  512. wandb/sync/sync.py +452 -0
  513. wandb/trigger.py +29 -0
  514. wandb/util.py +2040 -0
  515. wandb/vendor/__init__.py +0 -0
  516. wandb/vendor/gql-0.2.0/setup.py +40 -0
  517. wandb/vendor/gql-0.2.0/tests/__init__.py +0 -0
  518. wandb/vendor/gql-0.2.0/tests/starwars/__init__.py +0 -0
  519. wandb/vendor/gql-0.2.0/tests/starwars/fixtures.py +96 -0
  520. wandb/vendor/gql-0.2.0/tests/starwars/schema.py +146 -0
  521. wandb/vendor/gql-0.2.0/tests/starwars/test_dsl.py +293 -0
  522. wandb/vendor/gql-0.2.0/tests/starwars/test_query.py +355 -0
  523. wandb/vendor/gql-0.2.0/tests/starwars/test_validation.py +171 -0
  524. wandb/vendor/gql-0.2.0/tests/test_client.py +31 -0
  525. wandb/vendor/gql-0.2.0/tests/test_transport.py +89 -0
  526. wandb/vendor/gql-0.2.0/wandb_gql/__init__.py +4 -0
  527. wandb/vendor/gql-0.2.0/wandb_gql/client.py +75 -0
  528. wandb/vendor/gql-0.2.0/wandb_gql/dsl.py +152 -0
  529. wandb/vendor/gql-0.2.0/wandb_gql/gql.py +10 -0
  530. wandb/vendor/gql-0.2.0/wandb_gql/transport/__init__.py +0 -0
  531. wandb/vendor/gql-0.2.0/wandb_gql/transport/http.py +6 -0
  532. wandb/vendor/gql-0.2.0/wandb_gql/transport/local_schema.py +15 -0
  533. wandb/vendor/gql-0.2.0/wandb_gql/transport/requests.py +46 -0
  534. wandb/vendor/gql-0.2.0/wandb_gql/utils.py +21 -0
  535. wandb/vendor/graphql-core-1.1/setup.py +86 -0
  536. wandb/vendor/graphql-core-1.1/wandb_graphql/__init__.py +287 -0
  537. wandb/vendor/graphql-core-1.1/wandb_graphql/error/__init__.py +6 -0
  538. wandb/vendor/graphql-core-1.1/wandb_graphql/error/base.py +42 -0
  539. wandb/vendor/graphql-core-1.1/wandb_graphql/error/format_error.py +11 -0
  540. wandb/vendor/graphql-core-1.1/wandb_graphql/error/located_error.py +29 -0
  541. wandb/vendor/graphql-core-1.1/wandb_graphql/error/syntax_error.py +36 -0
  542. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/__init__.py +26 -0
  543. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/base.py +311 -0
  544. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/executor.py +398 -0
  545. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/executors/__init__.py +0 -0
  546. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/executors/asyncio.py +53 -0
  547. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/executors/gevent.py +22 -0
  548. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/executors/process.py +32 -0
  549. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/executors/sync.py +7 -0
  550. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/executors/thread.py +35 -0
  551. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/executors/utils.py +6 -0
  552. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/experimental/__init__.py +0 -0
  553. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/experimental/executor.py +66 -0
  554. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/experimental/fragment.py +252 -0
  555. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/experimental/resolver.py +151 -0
  556. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/experimental/utils.py +7 -0
  557. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/middleware.py +57 -0
  558. wandb/vendor/graphql-core-1.1/wandb_graphql/execution/values.py +145 -0
  559. wandb/vendor/graphql-core-1.1/wandb_graphql/graphql.py +60 -0
  560. wandb/vendor/graphql-core-1.1/wandb_graphql/language/__init__.py +0 -0
  561. wandb/vendor/graphql-core-1.1/wandb_graphql/language/ast.py +1349 -0
  562. wandb/vendor/graphql-core-1.1/wandb_graphql/language/base.py +19 -0
  563. wandb/vendor/graphql-core-1.1/wandb_graphql/language/lexer.py +435 -0
  564. wandb/vendor/graphql-core-1.1/wandb_graphql/language/location.py +30 -0
  565. wandb/vendor/graphql-core-1.1/wandb_graphql/language/parser.py +779 -0
  566. wandb/vendor/graphql-core-1.1/wandb_graphql/language/printer.py +193 -0
  567. wandb/vendor/graphql-core-1.1/wandb_graphql/language/source.py +18 -0
  568. wandb/vendor/graphql-core-1.1/wandb_graphql/language/visitor.py +222 -0
  569. wandb/vendor/graphql-core-1.1/wandb_graphql/language/visitor_meta.py +82 -0
  570. wandb/vendor/graphql-core-1.1/wandb_graphql/pyutils/__init__.py +0 -0
  571. wandb/vendor/graphql-core-1.1/wandb_graphql/pyutils/cached_property.py +17 -0
  572. wandb/vendor/graphql-core-1.1/wandb_graphql/pyutils/contain_subset.py +28 -0
  573. wandb/vendor/graphql-core-1.1/wandb_graphql/pyutils/default_ordered_dict.py +40 -0
  574. wandb/vendor/graphql-core-1.1/wandb_graphql/pyutils/ordereddict.py +8 -0
  575. wandb/vendor/graphql-core-1.1/wandb_graphql/pyutils/pair_set.py +43 -0
  576. wandb/vendor/graphql-core-1.1/wandb_graphql/pyutils/version.py +78 -0
  577. wandb/vendor/graphql-core-1.1/wandb_graphql/type/__init__.py +67 -0
  578. wandb/vendor/graphql-core-1.1/wandb_graphql/type/definition.py +619 -0
  579. wandb/vendor/graphql-core-1.1/wandb_graphql/type/directives.py +132 -0
  580. wandb/vendor/graphql-core-1.1/wandb_graphql/type/introspection.py +440 -0
  581. wandb/vendor/graphql-core-1.1/wandb_graphql/type/scalars.py +131 -0
  582. wandb/vendor/graphql-core-1.1/wandb_graphql/type/schema.py +100 -0
  583. wandb/vendor/graphql-core-1.1/wandb_graphql/type/typemap.py +145 -0
  584. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/__init__.py +0 -0
  585. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/assert_valid_name.py +9 -0
  586. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/ast_from_value.py +65 -0
  587. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/ast_to_code.py +49 -0
  588. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/ast_to_dict.py +24 -0
  589. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/base.py +75 -0
  590. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/build_ast_schema.py +291 -0
  591. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/build_client_schema.py +250 -0
  592. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/concat_ast.py +9 -0
  593. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/extend_schema.py +357 -0
  594. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/get_field_def.py +27 -0
  595. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/get_operation_ast.py +21 -0
  596. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/introspection_query.py +90 -0
  597. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/is_valid_literal_value.py +67 -0
  598. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/is_valid_value.py +66 -0
  599. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/quoted_or_list.py +21 -0
  600. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/schema_printer.py +168 -0
  601. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/suggestion_list.py +56 -0
  602. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/type_comparators.py +69 -0
  603. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/type_from_ast.py +21 -0
  604. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/type_info.py +149 -0
  605. wandb/vendor/graphql-core-1.1/wandb_graphql/utils/value_from_ast.py +69 -0
  606. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/__init__.py +4 -0
  607. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/__init__.py +79 -0
  608. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/arguments_of_correct_type.py +24 -0
  609. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/base.py +8 -0
  610. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/default_values_of_correct_type.py +44 -0
  611. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/fields_on_correct_type.py +113 -0
  612. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/fragments_on_composite_types.py +33 -0
  613. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/known_argument_names.py +70 -0
  614. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/known_directives.py +97 -0
  615. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/known_fragment_names.py +19 -0
  616. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/known_type_names.py +43 -0
  617. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/lone_anonymous_operation.py +23 -0
  618. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/no_fragment_cycles.py +59 -0
  619. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/no_undefined_variables.py +36 -0
  620. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/no_unused_fragments.py +38 -0
  621. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/no_unused_variables.py +37 -0
  622. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/overlapping_fields_can_be_merged.py +529 -0
  623. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/possible_fragment_spreads.py +44 -0
  624. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/provided_non_null_arguments.py +46 -0
  625. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/scalar_leafs.py +33 -0
  626. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/unique_argument_names.py +32 -0
  627. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/unique_fragment_names.py +28 -0
  628. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/unique_input_field_names.py +33 -0
  629. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/unique_operation_names.py +31 -0
  630. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/unique_variable_names.py +27 -0
  631. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/variables_are_input_types.py +21 -0
  632. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/rules/variables_in_allowed_position.py +53 -0
  633. wandb/vendor/graphql-core-1.1/wandb_graphql/validation/validation.py +158 -0
  634. wandb/vendor/promise-2.3.0/conftest.py +30 -0
  635. wandb/vendor/promise-2.3.0/setup.py +64 -0
  636. wandb/vendor/promise-2.3.0/tests/__init__.py +0 -0
  637. wandb/vendor/promise-2.3.0/tests/conftest.py +8 -0
  638. wandb/vendor/promise-2.3.0/tests/test_awaitable.py +32 -0
  639. wandb/vendor/promise-2.3.0/tests/test_awaitable_35.py +47 -0
  640. wandb/vendor/promise-2.3.0/tests/test_benchmark.py +116 -0
  641. wandb/vendor/promise-2.3.0/tests/test_complex_threads.py +23 -0
  642. wandb/vendor/promise-2.3.0/tests/test_dataloader.py +452 -0
  643. wandb/vendor/promise-2.3.0/tests/test_dataloader_awaitable_35.py +99 -0
  644. wandb/vendor/promise-2.3.0/tests/test_dataloader_extra.py +65 -0
  645. wandb/vendor/promise-2.3.0/tests/test_extra.py +670 -0
  646. wandb/vendor/promise-2.3.0/tests/test_issues.py +132 -0
  647. wandb/vendor/promise-2.3.0/tests/test_promise_list.py +70 -0
  648. wandb/vendor/promise-2.3.0/tests/test_spec.py +584 -0
  649. wandb/vendor/promise-2.3.0/tests/test_thread_safety.py +115 -0
  650. wandb/vendor/promise-2.3.0/tests/utils.py +3 -0
  651. wandb/vendor/promise-2.3.0/wandb_promise/__init__.py +38 -0
  652. wandb/vendor/promise-2.3.0/wandb_promise/async_.py +135 -0
  653. wandb/vendor/promise-2.3.0/wandb_promise/compat.py +32 -0
  654. wandb/vendor/promise-2.3.0/wandb_promise/dataloader.py +326 -0
  655. wandb/vendor/promise-2.3.0/wandb_promise/iterate_promise.py +12 -0
  656. wandb/vendor/promise-2.3.0/wandb_promise/promise.py +848 -0
  657. wandb/vendor/promise-2.3.0/wandb_promise/promise_list.py +151 -0
  658. wandb/vendor/promise-2.3.0/wandb_promise/pyutils/__init__.py +0 -0
  659. wandb/vendor/promise-2.3.0/wandb_promise/pyutils/version.py +83 -0
  660. wandb/vendor/promise-2.3.0/wandb_promise/schedulers/__init__.py +0 -0
  661. wandb/vendor/promise-2.3.0/wandb_promise/schedulers/asyncio.py +22 -0
  662. wandb/vendor/promise-2.3.0/wandb_promise/schedulers/gevent.py +21 -0
  663. wandb/vendor/promise-2.3.0/wandb_promise/schedulers/immediate.py +27 -0
  664. wandb/vendor/promise-2.3.0/wandb_promise/schedulers/thread.py +18 -0
  665. wandb/vendor/promise-2.3.0/wandb_promise/utils.py +56 -0
  666. wandb/vendor/pygments/__init__.py +90 -0
  667. wandb/vendor/pygments/cmdline.py +568 -0
  668. wandb/vendor/pygments/console.py +74 -0
  669. wandb/vendor/pygments/filter.py +74 -0
  670. wandb/vendor/pygments/filters/__init__.py +350 -0
  671. wandb/vendor/pygments/formatter.py +95 -0
  672. wandb/vendor/pygments/formatters/__init__.py +153 -0
  673. wandb/vendor/pygments/formatters/_mapping.py +85 -0
  674. wandb/vendor/pygments/formatters/bbcode.py +109 -0
  675. wandb/vendor/pygments/formatters/html.py +851 -0
  676. wandb/vendor/pygments/formatters/img.py +600 -0
  677. wandb/vendor/pygments/formatters/irc.py +182 -0
  678. wandb/vendor/pygments/formatters/latex.py +482 -0
  679. wandb/vendor/pygments/formatters/other.py +160 -0
  680. wandb/vendor/pygments/formatters/rtf.py +147 -0
  681. wandb/vendor/pygments/formatters/svg.py +153 -0
  682. wandb/vendor/pygments/formatters/terminal.py +136 -0
  683. wandb/vendor/pygments/formatters/terminal256.py +309 -0
  684. wandb/vendor/pygments/lexer.py +871 -0
  685. wandb/vendor/pygments/lexers/__init__.py +329 -0
  686. wandb/vendor/pygments/lexers/_asy_builtins.py +1645 -0
  687. wandb/vendor/pygments/lexers/_cl_builtins.py +232 -0
  688. wandb/vendor/pygments/lexers/_cocoa_builtins.py +72 -0
  689. wandb/vendor/pygments/lexers/_csound_builtins.py +1346 -0
  690. wandb/vendor/pygments/lexers/_lasso_builtins.py +5327 -0
  691. wandb/vendor/pygments/lexers/_lua_builtins.py +295 -0
  692. wandb/vendor/pygments/lexers/_mapping.py +500 -0
  693. wandb/vendor/pygments/lexers/_mql_builtins.py +1172 -0
  694. wandb/vendor/pygments/lexers/_openedge_builtins.py +2547 -0
  695. wandb/vendor/pygments/lexers/_php_builtins.py +4756 -0
  696. wandb/vendor/pygments/lexers/_postgres_builtins.py +621 -0
  697. wandb/vendor/pygments/lexers/_scilab_builtins.py +3094 -0
  698. wandb/vendor/pygments/lexers/_sourcemod_builtins.py +1163 -0
  699. wandb/vendor/pygments/lexers/_stan_builtins.py +532 -0
  700. wandb/vendor/pygments/lexers/_stata_builtins.py +419 -0
  701. wandb/vendor/pygments/lexers/_tsql_builtins.py +1004 -0
  702. wandb/vendor/pygments/lexers/_vim_builtins.py +1939 -0
  703. wandb/vendor/pygments/lexers/actionscript.py +240 -0
  704. wandb/vendor/pygments/lexers/agile.py +24 -0
  705. wandb/vendor/pygments/lexers/algebra.py +221 -0
  706. wandb/vendor/pygments/lexers/ambient.py +76 -0
  707. wandb/vendor/pygments/lexers/ampl.py +87 -0
  708. wandb/vendor/pygments/lexers/apl.py +101 -0
  709. wandb/vendor/pygments/lexers/archetype.py +318 -0
  710. wandb/vendor/pygments/lexers/asm.py +641 -0
  711. wandb/vendor/pygments/lexers/automation.py +374 -0
  712. wandb/vendor/pygments/lexers/basic.py +500 -0
  713. wandb/vendor/pygments/lexers/bibtex.py +160 -0
  714. wandb/vendor/pygments/lexers/business.py +612 -0
  715. wandb/vendor/pygments/lexers/c_cpp.py +252 -0
  716. wandb/vendor/pygments/lexers/c_like.py +541 -0
  717. wandb/vendor/pygments/lexers/capnproto.py +78 -0
  718. wandb/vendor/pygments/lexers/chapel.py +102 -0
  719. wandb/vendor/pygments/lexers/clean.py +288 -0
  720. wandb/vendor/pygments/lexers/compiled.py +34 -0
  721. wandb/vendor/pygments/lexers/configs.py +833 -0
  722. wandb/vendor/pygments/lexers/console.py +114 -0
  723. wandb/vendor/pygments/lexers/crystal.py +393 -0
  724. wandb/vendor/pygments/lexers/csound.py +366 -0
  725. wandb/vendor/pygments/lexers/css.py +689 -0
  726. wandb/vendor/pygments/lexers/d.py +251 -0
  727. wandb/vendor/pygments/lexers/dalvik.py +125 -0
  728. wandb/vendor/pygments/lexers/data.py +555 -0
  729. wandb/vendor/pygments/lexers/diff.py +165 -0
  730. wandb/vendor/pygments/lexers/dotnet.py +691 -0
  731. wandb/vendor/pygments/lexers/dsls.py +878 -0
  732. wandb/vendor/pygments/lexers/dylan.py +289 -0
  733. wandb/vendor/pygments/lexers/ecl.py +125 -0
  734. wandb/vendor/pygments/lexers/eiffel.py +65 -0
  735. wandb/vendor/pygments/lexers/elm.py +121 -0
  736. wandb/vendor/pygments/lexers/erlang.py +533 -0
  737. wandb/vendor/pygments/lexers/esoteric.py +277 -0
  738. wandb/vendor/pygments/lexers/ezhil.py +69 -0
  739. wandb/vendor/pygments/lexers/factor.py +344 -0
  740. wandb/vendor/pygments/lexers/fantom.py +250 -0
  741. wandb/vendor/pygments/lexers/felix.py +273 -0
  742. wandb/vendor/pygments/lexers/forth.py +177 -0
  743. wandb/vendor/pygments/lexers/fortran.py +205 -0
  744. wandb/vendor/pygments/lexers/foxpro.py +428 -0
  745. wandb/vendor/pygments/lexers/functional.py +21 -0
  746. wandb/vendor/pygments/lexers/go.py +101 -0
  747. wandb/vendor/pygments/lexers/grammar_notation.py +213 -0
  748. wandb/vendor/pygments/lexers/graph.py +80 -0
  749. wandb/vendor/pygments/lexers/graphics.py +553 -0
  750. wandb/vendor/pygments/lexers/haskell.py +843 -0
  751. wandb/vendor/pygments/lexers/haxe.py +936 -0
  752. wandb/vendor/pygments/lexers/hdl.py +382 -0
  753. wandb/vendor/pygments/lexers/hexdump.py +103 -0
  754. wandb/vendor/pygments/lexers/html.py +602 -0
  755. wandb/vendor/pygments/lexers/idl.py +270 -0
  756. wandb/vendor/pygments/lexers/igor.py +288 -0
  757. wandb/vendor/pygments/lexers/inferno.py +96 -0
  758. wandb/vendor/pygments/lexers/installers.py +322 -0
  759. wandb/vendor/pygments/lexers/int_fiction.py +1343 -0
  760. wandb/vendor/pygments/lexers/iolang.py +63 -0
  761. wandb/vendor/pygments/lexers/j.py +146 -0
  762. wandb/vendor/pygments/lexers/javascript.py +1525 -0
  763. wandb/vendor/pygments/lexers/julia.py +333 -0
  764. wandb/vendor/pygments/lexers/jvm.py +1573 -0
  765. wandb/vendor/pygments/lexers/lisp.py +2621 -0
  766. wandb/vendor/pygments/lexers/make.py +202 -0
  767. wandb/vendor/pygments/lexers/markup.py +595 -0
  768. wandb/vendor/pygments/lexers/math.py +21 -0
  769. wandb/vendor/pygments/lexers/matlab.py +663 -0
  770. wandb/vendor/pygments/lexers/ml.py +769 -0
  771. wandb/vendor/pygments/lexers/modeling.py +358 -0
  772. wandb/vendor/pygments/lexers/modula2.py +1561 -0
  773. wandb/vendor/pygments/lexers/monte.py +204 -0
  774. wandb/vendor/pygments/lexers/ncl.py +894 -0
  775. wandb/vendor/pygments/lexers/nimrod.py +159 -0
  776. wandb/vendor/pygments/lexers/nit.py +64 -0
  777. wandb/vendor/pygments/lexers/nix.py +136 -0
  778. wandb/vendor/pygments/lexers/oberon.py +105 -0
  779. wandb/vendor/pygments/lexers/objective.py +504 -0
  780. wandb/vendor/pygments/lexers/ooc.py +85 -0
  781. wandb/vendor/pygments/lexers/other.py +41 -0
  782. wandb/vendor/pygments/lexers/parasail.py +79 -0
  783. wandb/vendor/pygments/lexers/parsers.py +835 -0
  784. wandb/vendor/pygments/lexers/pascal.py +644 -0
  785. wandb/vendor/pygments/lexers/pawn.py +199 -0
  786. wandb/vendor/pygments/lexers/perl.py +620 -0
  787. wandb/vendor/pygments/lexers/php.py +267 -0
  788. wandb/vendor/pygments/lexers/praat.py +294 -0
  789. wandb/vendor/pygments/lexers/prolog.py +306 -0
  790. wandb/vendor/pygments/lexers/python.py +939 -0
  791. wandb/vendor/pygments/lexers/qvt.py +152 -0
  792. wandb/vendor/pygments/lexers/r.py +453 -0
  793. wandb/vendor/pygments/lexers/rdf.py +270 -0
  794. wandb/vendor/pygments/lexers/rebol.py +431 -0
  795. wandb/vendor/pygments/lexers/resource.py +85 -0
  796. wandb/vendor/pygments/lexers/rnc.py +67 -0
  797. wandb/vendor/pygments/lexers/roboconf.py +82 -0
  798. wandb/vendor/pygments/lexers/robotframework.py +560 -0
  799. wandb/vendor/pygments/lexers/ruby.py +519 -0
  800. wandb/vendor/pygments/lexers/rust.py +220 -0
  801. wandb/vendor/pygments/lexers/sas.py +228 -0
  802. wandb/vendor/pygments/lexers/scripting.py +1222 -0
  803. wandb/vendor/pygments/lexers/shell.py +794 -0
  804. wandb/vendor/pygments/lexers/smalltalk.py +195 -0
  805. wandb/vendor/pygments/lexers/smv.py +79 -0
  806. wandb/vendor/pygments/lexers/snobol.py +83 -0
  807. wandb/vendor/pygments/lexers/special.py +103 -0
  808. wandb/vendor/pygments/lexers/sql.py +681 -0
  809. wandb/vendor/pygments/lexers/stata.py +108 -0
  810. wandb/vendor/pygments/lexers/supercollider.py +90 -0
  811. wandb/vendor/pygments/lexers/tcl.py +145 -0
  812. wandb/vendor/pygments/lexers/templates.py +2283 -0
  813. wandb/vendor/pygments/lexers/testing.py +207 -0
  814. wandb/vendor/pygments/lexers/text.py +25 -0
  815. wandb/vendor/pygments/lexers/textedit.py +169 -0
  816. wandb/vendor/pygments/lexers/textfmts.py +297 -0
  817. wandb/vendor/pygments/lexers/theorem.py +458 -0
  818. wandb/vendor/pygments/lexers/trafficscript.py +54 -0
  819. wandb/vendor/pygments/lexers/typoscript.py +226 -0
  820. wandb/vendor/pygments/lexers/urbi.py +133 -0
  821. wandb/vendor/pygments/lexers/varnish.py +190 -0
  822. wandb/vendor/pygments/lexers/verification.py +111 -0
  823. wandb/vendor/pygments/lexers/web.py +24 -0
  824. wandb/vendor/pygments/lexers/webmisc.py +988 -0
  825. wandb/vendor/pygments/lexers/whiley.py +116 -0
  826. wandb/vendor/pygments/lexers/x10.py +69 -0
  827. wandb/vendor/pygments/modeline.py +44 -0
  828. wandb/vendor/pygments/plugin.py +68 -0
  829. wandb/vendor/pygments/regexopt.py +92 -0
  830. wandb/vendor/pygments/scanner.py +105 -0
  831. wandb/vendor/pygments/sphinxext.py +158 -0
  832. wandb/vendor/pygments/style.py +155 -0
  833. wandb/vendor/pygments/styles/__init__.py +80 -0
  834. wandb/vendor/pygments/styles/abap.py +29 -0
  835. wandb/vendor/pygments/styles/algol.py +63 -0
  836. wandb/vendor/pygments/styles/algol_nu.py +63 -0
  837. wandb/vendor/pygments/styles/arduino.py +98 -0
  838. wandb/vendor/pygments/styles/autumn.py +65 -0
  839. wandb/vendor/pygments/styles/borland.py +51 -0
  840. wandb/vendor/pygments/styles/bw.py +49 -0
  841. wandb/vendor/pygments/styles/colorful.py +81 -0
  842. wandb/vendor/pygments/styles/default.py +73 -0
  843. wandb/vendor/pygments/styles/emacs.py +72 -0
  844. wandb/vendor/pygments/styles/friendly.py +72 -0
  845. wandb/vendor/pygments/styles/fruity.py +42 -0
  846. wandb/vendor/pygments/styles/igor.py +29 -0
  847. wandb/vendor/pygments/styles/lovelace.py +97 -0
  848. wandb/vendor/pygments/styles/manni.py +75 -0
  849. wandb/vendor/pygments/styles/monokai.py +106 -0
  850. wandb/vendor/pygments/styles/murphy.py +80 -0
  851. wandb/vendor/pygments/styles/native.py +65 -0
  852. wandb/vendor/pygments/styles/paraiso_dark.py +125 -0
  853. wandb/vendor/pygments/styles/paraiso_light.py +125 -0
  854. wandb/vendor/pygments/styles/pastie.py +75 -0
  855. wandb/vendor/pygments/styles/perldoc.py +69 -0
  856. wandb/vendor/pygments/styles/rainbow_dash.py +89 -0
  857. wandb/vendor/pygments/styles/rrt.py +33 -0
  858. wandb/vendor/pygments/styles/sas.py +44 -0
  859. wandb/vendor/pygments/styles/stata.py +40 -0
  860. wandb/vendor/pygments/styles/tango.py +141 -0
  861. wandb/vendor/pygments/styles/trac.py +63 -0
  862. wandb/vendor/pygments/styles/vim.py +63 -0
  863. wandb/vendor/pygments/styles/vs.py +38 -0
  864. wandb/vendor/pygments/styles/xcode.py +51 -0
  865. wandb/vendor/pygments/token.py +213 -0
  866. wandb/vendor/pygments/unistring.py +217 -0
  867. wandb/vendor/pygments/util.py +388 -0
  868. wandb/vendor/watchdog_0_9_0/wandb_watchdog/__init__.py +17 -0
  869. wandb/vendor/watchdog_0_9_0/wandb_watchdog/events.py +615 -0
  870. wandb/vendor/watchdog_0_9_0/wandb_watchdog/observers/__init__.py +98 -0
  871. wandb/vendor/watchdog_0_9_0/wandb_watchdog/observers/api.py +369 -0
  872. wandb/vendor/watchdog_0_9_0/wandb_watchdog/observers/fsevents.py +172 -0
  873. wandb/vendor/watchdog_0_9_0/wandb_watchdog/observers/fsevents2.py +239 -0
  874. wandb/vendor/watchdog_0_9_0/wandb_watchdog/observers/inotify.py +218 -0
  875. wandb/vendor/watchdog_0_9_0/wandb_watchdog/observers/inotify_buffer.py +81 -0
  876. wandb/vendor/watchdog_0_9_0/wandb_watchdog/observers/inotify_c.py +575 -0
  877. wandb/vendor/watchdog_0_9_0/wandb_watchdog/observers/kqueue.py +730 -0
  878. wandb/vendor/watchdog_0_9_0/wandb_watchdog/observers/polling.py +145 -0
  879. wandb/vendor/watchdog_0_9_0/wandb_watchdog/observers/read_directory_changes.py +133 -0
  880. wandb/vendor/watchdog_0_9_0/wandb_watchdog/observers/winapi.py +348 -0
  881. wandb/vendor/watchdog_0_9_0/wandb_watchdog/patterns.py +265 -0
  882. wandb/vendor/watchdog_0_9_0/wandb_watchdog/tricks/__init__.py +174 -0
  883. wandb/vendor/watchdog_0_9_0/wandb_watchdog/utils/__init__.py +151 -0
  884. wandb/vendor/watchdog_0_9_0/wandb_watchdog/utils/bricks.py +249 -0
  885. wandb/vendor/watchdog_0_9_0/wandb_watchdog/utils/compat.py +29 -0
  886. wandb/vendor/watchdog_0_9_0/wandb_watchdog/utils/decorators.py +198 -0
  887. wandb/vendor/watchdog_0_9_0/wandb_watchdog/utils/delayed_queue.py +88 -0
  888. wandb/vendor/watchdog_0_9_0/wandb_watchdog/utils/dirsnapshot.py +293 -0
  889. wandb/vendor/watchdog_0_9_0/wandb_watchdog/utils/echo.py +157 -0
  890. wandb/vendor/watchdog_0_9_0/wandb_watchdog/utils/event_backport.py +41 -0
  891. wandb/vendor/watchdog_0_9_0/wandb_watchdog/utils/importlib2.py +40 -0
  892. wandb/vendor/watchdog_0_9_0/wandb_watchdog/utils/platform.py +57 -0
  893. wandb/vendor/watchdog_0_9_0/wandb_watchdog/utils/unicode_paths.py +64 -0
  894. wandb/vendor/watchdog_0_9_0/wandb_watchdog/utils/win32stat.py +123 -0
  895. wandb/vendor/watchdog_0_9_0/wandb_watchdog/version.py +28 -0
  896. wandb/vendor/watchdog_0_9_0/wandb_watchdog/watchmedo.py +577 -0
  897. wandb/wandb_agent.py +580 -0
  898. wandb/wandb_controller.py +719 -0
  899. wandb/wandb_run.py +8 -0
  900. wandb-0.21.2.dist-info/METADATA +223 -0
  901. wandb-0.21.2.dist-info/RECORD +904 -0
  902. wandb-0.21.2.dist-info/WHEEL +4 -0
  903. wandb-0.21.2.dist-info/entry_points.txt +3 -0
  904. wandb-0.21.2.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1468 @@
1
+ import base64
2
+ import binascii
3
+ import codecs
4
+ import datetime
5
+ import json
6
+ import logging
7
+ import os
8
+ from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Set, Tuple
9
+
10
+ import wandb
11
+ from wandb import util
12
+ from wandb.sdk.lib import runid
13
+
14
+ from . import _dtypes
15
+ from ._private import MEDIA_TMP
16
+ from .base_types.media import Media, _numpy_arrays_to_lists
17
+ from .base_types.wb_value import WBValue
18
+ from .table_decorators import (
19
+ allow_incremental_logging_after_append,
20
+ allow_relogging_after_mutation,
21
+ ensure_not_incremental,
22
+ )
23
+ from .utils import _json_helper
24
+
25
+ if TYPE_CHECKING:
26
+ from wandb.sdk.artifacts import artifact
27
+
28
+ from ...wandb_run import Run as LocalRun
29
+
30
+
31
+ class _TableLinkMixin:
32
+ def set_table(self, table):
33
+ self._table = table
34
+
35
+
36
+ class _TableKey(str, _TableLinkMixin):
37
+ def set_table(self, table, col_name):
38
+ assert col_name in table.columns
39
+ self._table = table
40
+ self._col_name = col_name
41
+
42
+
43
+ class _TableIndex(int, _TableLinkMixin):
44
+ def get_row(self):
45
+ row = {}
46
+ if self._table:
47
+ row = {
48
+ c: self._table.data[self][i] for i, c in enumerate(self._table.columns)
49
+ }
50
+
51
+ return row
52
+
53
+
54
+ class _PrimaryKeyType(_dtypes.Type):
55
+ name = "primaryKey"
56
+ legacy_names = ["wandb.TablePrimaryKey"]
57
+
58
+ def assign_type(self, wb_type=None):
59
+ if isinstance(wb_type, _dtypes.StringType) or isinstance(
60
+ wb_type, _PrimaryKeyType
61
+ ):
62
+ return self
63
+ return _dtypes.InvalidType()
64
+
65
+ @classmethod
66
+ def from_obj(cls, py_obj):
67
+ if not isinstance(py_obj, _TableKey):
68
+ raise TypeError("py_obj must be a wandb.Table")
69
+ else:
70
+ return cls()
71
+
72
+
73
+ class _ForeignKeyType(_dtypes.Type):
74
+ name = "foreignKey"
75
+ legacy_names = ["wandb.TableForeignKey"]
76
+ types = [_TableKey]
77
+
78
+ def __init__(self, table, col_name):
79
+ assert isinstance(table, Table)
80
+ assert isinstance(col_name, str)
81
+ assert col_name in table.columns
82
+ self.params.update({"table": table, "col_name": col_name})
83
+
84
+ def assign_type(self, wb_type=None):
85
+ if isinstance(wb_type, _dtypes.StringType):
86
+ return self
87
+ elif (
88
+ isinstance(wb_type, _ForeignKeyType)
89
+ and id(self.params["table"]) == id(wb_type.params["table"])
90
+ and self.params["col_name"] == wb_type.params["col_name"]
91
+ ):
92
+ return self
93
+
94
+ return _dtypes.InvalidType()
95
+
96
+ @classmethod
97
+ def from_obj(cls, py_obj):
98
+ if not isinstance(py_obj, _TableKey):
99
+ raise TypeError("py_obj must be a _TableKey")
100
+ else:
101
+ return cls(py_obj._table, py_obj._col_name)
102
+
103
+ def to_json(self, artifact=None):
104
+ res = super().to_json(artifact)
105
+ if artifact is not None:
106
+ table_name = f"media/tables/t_{runid.generate_id()}"
107
+ entry = artifact.add(self.params["table"], table_name)
108
+ res["params"]["table"] = entry.path
109
+ else:
110
+ raise AssertionError(
111
+ "_ForeignKeyType does not support serialization without an artifact"
112
+ )
113
+ return res
114
+
115
+ @classmethod
116
+ def from_json(
117
+ cls,
118
+ json_dict,
119
+ artifact,
120
+ ):
121
+ table = None
122
+ col_name = None
123
+ if artifact is None:
124
+ raise AssertionError(
125
+ "_ForeignKeyType does not support deserialization without an artifact"
126
+ )
127
+ else:
128
+ table = artifact.get(json_dict["params"]["table"])
129
+ col_name = json_dict["params"]["col_name"]
130
+
131
+ if table is None:
132
+ raise AssertionError("Unable to deserialize referenced table")
133
+
134
+ return cls(table, col_name)
135
+
136
+
137
+ class _ForeignIndexType(_dtypes.Type):
138
+ name = "foreignIndex"
139
+ legacy_names = ["wandb.TableForeignIndex"]
140
+ types = [_TableIndex]
141
+
142
+ def __init__(self, table):
143
+ assert isinstance(table, Table)
144
+ self.params.update({"table": table})
145
+
146
+ def assign_type(self, wb_type=None):
147
+ if isinstance(wb_type, _dtypes.NumberType):
148
+ return self
149
+ elif isinstance(wb_type, _ForeignIndexType) and id(self.params["table"]) == id(
150
+ wb_type.params["table"]
151
+ ):
152
+ return self
153
+
154
+ return _dtypes.InvalidType()
155
+
156
+ @classmethod
157
+ def from_obj(cls, py_obj):
158
+ if not isinstance(py_obj, _TableIndex):
159
+ raise TypeError("py_obj must be a _TableIndex")
160
+ else:
161
+ return cls(py_obj._table)
162
+
163
+ def to_json(self, artifact=None):
164
+ res = super().to_json(artifact)
165
+ if artifact is not None:
166
+ table_name = f"media/tables/t_{runid.generate_id()}"
167
+ entry = artifact.add(self.params["table"], table_name)
168
+ res["params"]["table"] = entry.path
169
+ else:
170
+ raise AssertionError(
171
+ "_ForeignIndexType does not support serialization without an artifact"
172
+ )
173
+ return res
174
+
175
+ @classmethod
176
+ def from_json(
177
+ cls,
178
+ json_dict,
179
+ artifact,
180
+ ):
181
+ table = None
182
+ if artifact is None:
183
+ raise AssertionError(
184
+ "_ForeignIndexType does not support deserialization without an artifact"
185
+ )
186
+ else:
187
+ table = artifact.get(json_dict["params"]["table"])
188
+
189
+ if table is None:
190
+ raise AssertionError("Unable to deserialize referenced table")
191
+
192
+ return cls(table)
193
+
194
+
195
+ _SUPPORTED_LOGGING_MODES = ["IMMUTABLE", "MUTABLE", "INCREMENTAL"]
196
+
197
+
198
+ class Table(Media):
199
+ """The Table class used to display and analyze tabular data.
200
+
201
+ Unlike traditional spreadsheets, Tables support numerous types of data:
202
+ scalar values, strings, numpy arrays, and most subclasses of `wandb.data_types.Media`.
203
+ This means you can embed `Images`, `Video`, `Audio`, and other sorts of rich, annotated media
204
+ directly in Tables, alongside other traditional scalar values.
205
+
206
+ This class is the primary class used to generate W&B Tables
207
+ https://docs.wandb.ai/guides/models/tables/.
208
+ """
209
+
210
+ MAX_ROWS = 10000
211
+ MAX_ARTIFACT_ROWS = 200000
212
+ _MAX_EMBEDDING_DIMENSIONS = 150
213
+ _log_type = "table"
214
+
215
+ def __init__(
216
+ self,
217
+ columns=None,
218
+ data=None,
219
+ rows=None,
220
+ dataframe=None,
221
+ dtype=None,
222
+ optional=True,
223
+ allow_mixed_types=False,
224
+ log_mode: Optional[
225
+ Literal["IMMUTABLE", "MUTABLE", "INCREMENTAL"]
226
+ ] = "IMMUTABLE",
227
+ ):
228
+ """Initializes a Table object.
229
+
230
+ The rows is available for legacy reasons and should not be used.
231
+ The Table class uses data to mimic the Pandas API.
232
+
233
+ Args:
234
+ columns: (List[str]) Names of the columns in the table.
235
+ Defaults to ["Input", "Output", "Expected"].
236
+ data: (List[List[any]]) 2D row-oriented array of values.
237
+ dataframe: (pandas.DataFrame) DataFrame object used to create the table.
238
+ When set, `data` and `columns` arguments are ignored.
239
+ rows: (List[List[any]]) 2D row-oriented array of values.
240
+ optional: (Union[bool,List[bool]]) Determines if `None` values are allowed. Default to True
241
+ - If a singular bool value, then the optionality is enforced for all
242
+ columns specified at construction time
243
+ - If a list of bool values, then the optionality is applied to each
244
+ column - should be the same length as `columns`
245
+ applies to all columns. A list of bool values applies to each respective column.
246
+ allow_mixed_types: (bool) Determines if columns are allowed to have mixed types
247
+ (disables type validation). Defaults to False
248
+ log_mode: Optional[str] Controls how the Table is logged when mutations occur.
249
+ Options:
250
+ - "IMMUTABLE" (default): Table can only be logged once; subsequent
251
+ logging attempts after the table has been mutated will be no-ops.
252
+ - "MUTABLE": Table can be re-logged after mutations, creating
253
+ a new artifact version each time it's logged.
254
+ - "INCREMENTAL": Table data is logged incrementally, with each log creating
255
+ a new artifact entry containing the new data since the last log.
256
+ """
257
+ super().__init__()
258
+ self._validate_log_mode(log_mode)
259
+ self.log_mode = log_mode
260
+ if self.log_mode == "INCREMENTAL":
261
+ self._increment_num: int | None = None
262
+ self._last_logged_idx: int | None = None
263
+ self._previous_increments_paths: list[str] | None = None
264
+ self._run_target_for_increments: LocalRun | None = None
265
+ self._pk_col = None
266
+ self._fk_cols: set[str] = set()
267
+ if allow_mixed_types:
268
+ dtype = _dtypes.AnyType
269
+
270
+ # This is kept for legacy reasons (tss: personally, I think we should remove this)
271
+ if columns is None:
272
+ columns = ["Input", "Output", "Expected"]
273
+
274
+ # Explicit dataframe option
275
+ if dataframe is not None:
276
+ self._init_from_dataframe(dataframe, columns, optional, dtype)
277
+ else:
278
+ # Expected pattern
279
+ if data is not None:
280
+ if util.is_numpy_array(data):
281
+ self._init_from_ndarray(data, columns, optional, dtype)
282
+ elif util.is_pandas_data_frame(data):
283
+ self._init_from_dataframe(data, columns, optional, dtype)
284
+ else:
285
+ self._init_from_list(data, columns, optional, dtype)
286
+
287
+ # legacy
288
+ elif rows is not None:
289
+ self._init_from_list(rows, columns, optional, dtype)
290
+
291
+ # Default empty case
292
+ else:
293
+ self._init_from_list([], columns, optional, dtype)
294
+
295
+ def _validate_log_mode(self, log_mode):
296
+ assert log_mode in _SUPPORTED_LOGGING_MODES, (
297
+ f"Invalid log_mode: {log_mode}. Must be one of {_SUPPORTED_LOGGING_MODES}"
298
+ )
299
+
300
+ @staticmethod
301
+ def _assert_valid_columns(columns):
302
+ valid_col_types = [str, int]
303
+ assert isinstance(columns, list), "columns argument expects a `list` object"
304
+ assert len(columns) == 0 or all(
305
+ [type(col) in valid_col_types for col in columns]
306
+ ), "columns argument expects list of strings or ints"
307
+
308
+ def _init_from_list(self, data, columns, optional=True, dtype=None):
309
+ assert isinstance(data, list), "data argument expects a `list` object"
310
+ self.data = []
311
+ self._assert_valid_columns(columns)
312
+ self.columns = columns
313
+ self._make_column_types(dtype, optional)
314
+ for row in data:
315
+ self.add_data(*row)
316
+
317
+ def _init_from_ndarray(self, ndarray, columns, optional=True, dtype=None):
318
+ assert util.is_numpy_array(ndarray), (
319
+ "ndarray argument expects a `numpy.ndarray` object"
320
+ )
321
+ self.data = []
322
+ self._assert_valid_columns(columns)
323
+ self.columns = columns
324
+ self._make_column_types(dtype, optional)
325
+ for row in ndarray:
326
+ self.add_data(*row)
327
+
328
+ def _init_from_dataframe(self, dataframe, columns, optional=True, dtype=None):
329
+ assert util.is_pandas_data_frame(dataframe), (
330
+ "dataframe argument expects a `pandas.core.frame.DataFrame` object"
331
+ )
332
+ self.data = []
333
+ columns = list(dataframe.columns)
334
+ self._assert_valid_columns(columns)
335
+ self.columns = columns
336
+ self._make_column_types(dtype, optional)
337
+ for row in range(len(dataframe)):
338
+ self.add_data(*tuple(dataframe[col].values[row] for col in self.columns))
339
+
340
+ def _make_column_types(self, dtype=None, optional=True):
341
+ if dtype is None:
342
+ dtype = _dtypes.UnknownType()
343
+
344
+ if optional.__class__ is not list:
345
+ optional = [optional for _ in range(len(self.columns))]
346
+
347
+ if dtype.__class__ is not list:
348
+ dtype = [dtype for _ in range(len(self.columns))]
349
+
350
+ self._column_types = _dtypes.TypedDictType({})
351
+ for col_name, opt, dt in zip(self.columns, optional, dtype):
352
+ self.cast(col_name, dt, opt)
353
+
354
+ def _load_incremental_table_state_from_resumed_run(self, run: "LocalRun", key: str):
355
+ """Handle updating incremental table state for resumed runs.
356
+
357
+ This method is called when a run is resumed and there are previous
358
+ increments of this table that need to be preserved. It updates the
359
+ table's internal state to track previous increments and the current
360
+ increment number.
361
+ """
362
+ if (
363
+ self._previous_increments_paths is not None
364
+ or self._increment_num is not None
365
+ ):
366
+ raise AssertionError(
367
+ "The table has been initialized for a resumed run already"
368
+ )
369
+
370
+ self._set_incremental_table_run_target(run)
371
+
372
+ summary_from_key = run.summary.get(key)
373
+
374
+ if (
375
+ summary_from_key is None
376
+ or not isinstance(summary_from_key, dict)
377
+ or summary_from_key.get("_type") != "incremental-table-file"
378
+ ):
379
+ # The key was never logged to the run or its last logged
380
+ # value was not an incrementally logged table.
381
+ return
382
+
383
+ previous_increments_paths = summary_from_key.get(
384
+ "previous_increments_paths", []
385
+ )
386
+
387
+ # add the artifact path of the last logged increment
388
+ last_artifact_path = summary_from_key.get("artifact_path")
389
+
390
+ if last_artifact_path:
391
+ previous_increments_paths.append(last_artifact_path)
392
+
393
+ # add 1 because a new increment is being logged
394
+ last_increment_num = summary_from_key.get("increment_num", 0)
395
+
396
+ self._increment_num = last_increment_num + 1
397
+ self._previous_increments_paths = previous_increments_paths
398
+
399
+ def _set_incremental_table_run_target(self, run: "LocalRun") -> None:
400
+ """Associate a Run object with this incremental Table.
401
+
402
+ A Table object in incremental mode can only be logged to a single Run.
403
+ Raises an error if the table is already associated to a different run.
404
+ """
405
+ if self._run_target_for_increments is None:
406
+ self._run_target_for_increments = run
407
+ elif self._run_target_for_increments is not run:
408
+ raise AssertionError("An incremental Table can only be logged to one Run.")
409
+
410
+ @allow_relogging_after_mutation
411
+ def cast(self, col_name, dtype, optional=False):
412
+ """Casts a column to a specific data type.
413
+
414
+ This can be one of the normal python classes, an internal W&B type,
415
+ or an example object, like an instance of wandb.Image or
416
+ wandb.Classes.
417
+
418
+ Args:
419
+ col_name (str): The name of the column to cast.
420
+ dtype (class, wandb.wandb_sdk.interface._dtypes.Type, any): The
421
+ target dtype.
422
+ optional (bool): If the column should allow Nones.
423
+ """
424
+ assert col_name in self.columns
425
+
426
+ wbtype = _dtypes.TypeRegistry.type_from_dtype(dtype)
427
+
428
+ if optional:
429
+ wbtype = _dtypes.OptionalType(wbtype)
430
+
431
+ # Cast each value in the row, raising an error if there are invalid entries.
432
+ col_ndx = self.columns.index(col_name)
433
+ for row in self.data:
434
+ result_type = wbtype.assign(row[col_ndx])
435
+ if isinstance(result_type, _dtypes.InvalidType):
436
+ raise TypeError(
437
+ f"Existing data {row[col_ndx]}, of type {_dtypes.TypeRegistry.type_of(row[col_ndx])} cannot be cast to {wbtype}"
438
+ )
439
+ wbtype = result_type
440
+
441
+ # Assert valid options
442
+ is_pk = isinstance(wbtype, _PrimaryKeyType)
443
+ is_fk = isinstance(wbtype, _ForeignKeyType)
444
+ is_fi = isinstance(wbtype, _ForeignIndexType)
445
+ if is_pk or is_fk or is_fi:
446
+ assert not optional, (
447
+ "Primary keys, foreign keys, and foreign indexes cannot be optional."
448
+ )
449
+
450
+ if (is_fk or is_fk) and id(wbtype.params["table"]) == id(self):
451
+ raise AssertionError("Cannot set a foreign table reference to same table.")
452
+
453
+ if is_pk:
454
+ assert self._pk_col is None, (
455
+ f"Cannot have multiple primary keys - {self._pk_col} is already set as the primary key."
456
+ )
457
+
458
+ # Update the column type
459
+ self._column_types.params["type_map"][col_name] = wbtype
460
+
461
+ # Wrap the data if needed
462
+ self._update_keys()
463
+ return wbtype
464
+
465
+ def __ne__(self, other):
466
+ return not self.__eq__(other)
467
+
468
+ def _eq_debug(self, other, should_assert=False):
469
+ eq = isinstance(other, Table)
470
+ assert not should_assert or eq, (
471
+ f"Found type {other.__class__}, expected {Table}"
472
+ )
473
+ eq = eq and len(self.data) == len(other.data)
474
+ assert not should_assert or eq, (
475
+ f"Found {len(other.data)} rows, expected {len(self.data)}"
476
+ )
477
+ eq = eq and self.columns == other.columns
478
+ assert not should_assert or eq, (
479
+ f"Found columns {other.columns}, expected {self.columns}"
480
+ )
481
+ eq = eq and self._column_types == other._column_types
482
+ assert not should_assert or eq, (
483
+ f"Found column type {other._column_types}, expected column type {self._column_types}"
484
+ )
485
+ if eq:
486
+ for row_ndx in range(len(self.data)):
487
+ for col_ndx in range(len(self.data[row_ndx])):
488
+ _eq = self.data[row_ndx][col_ndx] == other.data[row_ndx][col_ndx]
489
+ # equal if all are equal
490
+ if util.is_numpy_array(_eq):
491
+ _eq = ((_eq * -1) + 1).sum() == 0
492
+ eq = eq and _eq
493
+ assert not should_assert or eq, (
494
+ f"Unequal data at row_ndx {row_ndx} col_ndx {col_ndx}: found {other.data[row_ndx][col_ndx]}, expected {self.data[row_ndx][col_ndx]}"
495
+ )
496
+ if not eq:
497
+ return eq
498
+ return eq
499
+
500
+ def __eq__(self, other):
501
+ return self._eq_debug(other)
502
+
503
+ @allow_relogging_after_mutation
504
+ def add_row(self, *row):
505
+ """Deprecated. Use `Table.add_data` method instead."""
506
+ logging.warning("add_row is deprecated, use add_data")
507
+ self.add_data(*row)
508
+
509
+ @allow_relogging_after_mutation
510
+ @allow_incremental_logging_after_append
511
+ def add_data(self, *data):
512
+ """Adds a new row of data to the table.
513
+
514
+ The maximum amount ofrows in a table is determined by
515
+ `wandb.Table.MAX_ARTIFACT_ROWS`.
516
+
517
+ The length of the data should match the length of the table column.
518
+ """
519
+ if len(data) != len(self.columns):
520
+ raise ValueError(
521
+ f"This table expects {len(self.columns)} columns: {self.columns}, found {len(data)}"
522
+ )
523
+
524
+ # Special case to pre-emptively cast a column as a key.
525
+ # Needed as String.assign(Key) is invalid
526
+ for ndx, item in enumerate(data):
527
+ if isinstance(item, _TableLinkMixin):
528
+ self.cast(
529
+ self.columns[ndx],
530
+ _dtypes.TypeRegistry.type_of(item),
531
+ optional=False,
532
+ )
533
+
534
+ # Update the table's column types
535
+ result_type = self._get_updated_result_type(data)
536
+ self._column_types = result_type
537
+
538
+ # rows need to be mutable
539
+ if isinstance(data, tuple):
540
+ data = list(data)
541
+ # Add the new data
542
+ self.data.append(data)
543
+
544
+ # Update the wrapper values if needed
545
+ self._update_keys(force_last=True)
546
+
547
+ def _get_updated_result_type(self, row):
548
+ """Returns the updated result type based on the inputted row.
549
+
550
+ Raises:
551
+ TypeError: if the assignment is invalid.
552
+ """
553
+ incoming_row_dict = {
554
+ col_key: row[ndx] for ndx, col_key in enumerate(self.columns)
555
+ }
556
+ current_type = self._column_types
557
+ result_type = current_type.assign(incoming_row_dict)
558
+ if isinstance(result_type, _dtypes.InvalidType):
559
+ raise TypeError(
560
+ f"Data row contained incompatible types:\n{current_type.explain(incoming_row_dict)}"
561
+ )
562
+ return result_type
563
+
564
+ def _to_table_json(self, max_rows=None, warn=True):
565
+ # separate this method for easier testing
566
+ if max_rows is None:
567
+ max_rows = Table.MAX_ROWS
568
+ n_rows = len(self.data)
569
+ if n_rows > max_rows and warn:
570
+ # NOTE: Never raises for reinit="create_new" runs.
571
+ # Since this is called by bind_to_run(), this can be fixed by
572
+ # propagating the run. It cannot be fixed for to_json() calls
573
+ # that are given an artifact, other than by deferring to singleton
574
+ # settings.
575
+ if wandb.run and (
576
+ wandb.run.settings.table_raise_on_max_row_limit_exceeded
577
+ or wandb.run.settings.strict
578
+ ):
579
+ raise ValueError(
580
+ f"Table row limit exceeded: table has {n_rows} rows, limit is {max_rows}. "
581
+ f"To increase the maximum number of allowed rows in a wandb.Table, override "
582
+ f"the limit with `wandb.Table.MAX_ARTIFACT_ROWS = X` and try again. Note: "
583
+ f"this may cause slower queries in the W&B UI."
584
+ )
585
+ logging.warning(f"Truncating wandb.Table object to {max_rows} rows.")
586
+
587
+ if self.log_mode == "INCREMENTAL" and self._last_logged_idx is not None:
588
+ return {
589
+ "columns": self.columns,
590
+ "data": self.data[
591
+ self._last_logged_idx + 1 : self._last_logged_idx + 1 + max_rows
592
+ ],
593
+ }
594
+ else:
595
+ return {"columns": self.columns, "data": self.data[:max_rows]}
596
+
597
+ def bind_to_run(self, *args, **kwargs):
598
+ """Bind this object to a run.
599
+
600
+ <!-- lazydoc-ignore: internal -->
601
+ """
602
+ # We set `warn=False` since Tables will now always be logged to both
603
+ # files and artifacts. The file limit will never practically matter and
604
+ # this code path will be ultimately removed. The 10k limit warning confuses
605
+ # users given that we publicly say 200k is the limit.
606
+ data = self._to_table_json(warn=False)
607
+ tmp_path = os.path.join(MEDIA_TMP.name, runid.generate_id() + ".table.json")
608
+ data = _numpy_arrays_to_lists(data)
609
+ with codecs.open(tmp_path, "w", encoding="utf-8") as fp:
610
+ util.json_dump_safer(data, fp)
611
+ self._set_file(tmp_path, is_tmp=True, extension=".table.json")
612
+ super().bind_to_run(*args, **kwargs)
613
+
614
+ @classmethod
615
+ def get_media_subdir(cls):
616
+ """Get media subdirectory.
617
+
618
+ <!-- lazydoc-ignore-classmethod: internal -->
619
+ """
620
+ return os.path.join("media", "table")
621
+
622
+ @classmethod
623
+ def from_json(cls, json_obj, source_artifact: "artifact.Artifact"):
624
+ """Deserialize JSON object into it's class representation.
625
+
626
+ <!-- lazydoc-ignore-classmethod: internal -->
627
+ """
628
+ data = []
629
+ column_types = None
630
+ np_deserialized_columns = {}
631
+ timestamp_column_indices = set()
632
+ log_mode = json_obj.get("log_mode", "IMMUTABLE")
633
+ if json_obj.get("column_types") is not None:
634
+ column_types = _dtypes.TypeRegistry.type_from_dict(
635
+ json_obj["column_types"], source_artifact
636
+ )
637
+ for col_name in column_types.params["type_map"]:
638
+ col_type = column_types.params["type_map"][col_name]
639
+ ndarray_type = None
640
+ if isinstance(col_type, _dtypes.NDArrayType):
641
+ ndarray_type = col_type
642
+ elif isinstance(col_type, _dtypes.UnionType):
643
+ for t in col_type.params["allowed_types"]:
644
+ if isinstance(t, _dtypes.NDArrayType):
645
+ ndarray_type = t
646
+ elif isinstance(t, _dtypes.TimestampType):
647
+ timestamp_column_indices.add(
648
+ json_obj["columns"].index(col_name)
649
+ )
650
+
651
+ elif isinstance(col_type, _dtypes.TimestampType):
652
+ timestamp_column_indices.add(json_obj["columns"].index(col_name))
653
+
654
+ if (
655
+ ndarray_type is not None
656
+ and ndarray_type._get_serialization_path() is not None
657
+ ):
658
+ serialization_path = ndarray_type._get_serialization_path()
659
+
660
+ if serialization_path is None:
661
+ continue
662
+
663
+ np = util.get_module(
664
+ "numpy",
665
+ required="Deserializing NumPy columns requires NumPy to be installed.",
666
+ )
667
+ deserialized = np.load(
668
+ source_artifact.get_entry(serialization_path["path"]).download()
669
+ )
670
+ np_deserialized_columns[json_obj["columns"].index(col_name)] = (
671
+ deserialized[serialization_path["key"]]
672
+ )
673
+ ndarray_type._clear_serialization_path()
674
+
675
+ if log_mode == "INCREMENTAL":
676
+ unprocessed_table_data = _get_data_from_increments(
677
+ json_obj, source_artifact
678
+ )
679
+ else:
680
+ unprocessed_table_data = json_obj["data"]
681
+
682
+ for r_ndx, row in enumerate(unprocessed_table_data):
683
+ data.append(
684
+ _process_table_row(
685
+ row,
686
+ timestamp_column_indices,
687
+ np_deserialized_columns,
688
+ source_artifact,
689
+ r_ndx,
690
+ )
691
+ )
692
+
693
+ # construct Table with dtypes for each column if type information exists
694
+ dtypes = None
695
+ if column_types is not None:
696
+ dtypes = [
697
+ column_types.params["type_map"][str(col)] for col in json_obj["columns"]
698
+ ]
699
+
700
+ new_obj = cls(
701
+ columns=json_obj["columns"], data=data, dtype=dtypes, log_mode=log_mode
702
+ )
703
+
704
+ if column_types is not None:
705
+ new_obj._column_types = column_types
706
+
707
+ new_obj._update_keys()
708
+ return new_obj
709
+
710
+ def to_json(self, run_or_artifact):
711
+ """Returns the JSON representation expected by the backend.
712
+
713
+ <!-- lazydoc-ignore: internal -->
714
+ """
715
+ json_dict = super().to_json(run_or_artifact)
716
+
717
+ if self.log_mode == "INCREMENTAL":
718
+ if self._previous_increments_paths is None:
719
+ self._previous_increments_paths = []
720
+ if self._increment_num is None:
721
+ self._increment_num = 0
722
+
723
+ json_dict.update(
724
+ {
725
+ "increment_num": self._increment_num,
726
+ "previous_increments_paths": self._previous_increments_paths,
727
+ }
728
+ )
729
+
730
+ if isinstance(run_or_artifact, wandb.Run):
731
+ if self.log_mode == "INCREMENTAL":
732
+ wbvalue_type = "incremental-table-file"
733
+ else:
734
+ wbvalue_type = "table-file"
735
+
736
+ json_dict.update(
737
+ {
738
+ "_type": wbvalue_type,
739
+ "ncols": len(self.columns),
740
+ "nrows": len(self.data),
741
+ "log_mode": self.log_mode,
742
+ }
743
+ )
744
+
745
+ elif isinstance(run_or_artifact, wandb.Artifact):
746
+ artifact = run_or_artifact
747
+ mapped_data = []
748
+ data = self._to_table_json(Table.MAX_ARTIFACT_ROWS)["data"]
749
+
750
+ ndarray_col_ndxs = set()
751
+ for col_ndx, col_name in enumerate(self.columns):
752
+ col_type = self._column_types.params["type_map"][col_name]
753
+ ndarray_type = None
754
+ if isinstance(col_type, _dtypes.NDArrayType):
755
+ ndarray_type = col_type
756
+ elif isinstance(col_type, _dtypes.UnionType):
757
+ for t in col_type.params["allowed_types"]:
758
+ if isinstance(t, _dtypes.NDArrayType):
759
+ ndarray_type = t
760
+
761
+ # Do not serialize 1d arrays - these are likely embeddings and
762
+ # will not have the same cost as higher dimensional arrays
763
+ is_1d_array = (
764
+ ndarray_type is not None
765
+ and "shape" in ndarray_type._params
766
+ and isinstance(ndarray_type._params["shape"], list)
767
+ and len(ndarray_type._params["shape"]) == 1
768
+ and ndarray_type._params["shape"][0]
769
+ <= self._MAX_EMBEDDING_DIMENSIONS
770
+ )
771
+ if is_1d_array:
772
+ self._column_types.params["type_map"][col_name] = _dtypes.ListType(
773
+ _dtypes.NumberType, ndarray_type._params["shape"][0]
774
+ )
775
+ elif ndarray_type is not None:
776
+ np = util.get_module(
777
+ "numpy",
778
+ required="Serializing NumPy requires NumPy to be installed.",
779
+ )
780
+ file_name = f"{str(col_name)}_{runid.generate_id()}.npz"
781
+ npz_file_name = os.path.join(MEDIA_TMP.name, file_name)
782
+ np.savez_compressed(
783
+ npz_file_name,
784
+ **{
785
+ str(col_name): self.get_column(col_name, convert_to="numpy")
786
+ },
787
+ )
788
+ entry = artifact.add_file(
789
+ npz_file_name, "media/serialized_data/" + file_name, is_tmp=True
790
+ )
791
+ ndarray_type._set_serialization_path(entry.path, str(col_name))
792
+ ndarray_col_ndxs.add(col_ndx)
793
+
794
+ for row in data:
795
+ mapped_row = []
796
+ for ndx, v in enumerate(row):
797
+ if ndx in ndarray_col_ndxs:
798
+ mapped_row.append(None)
799
+ else:
800
+ mapped_row.append(_json_helper(v, artifact))
801
+ mapped_data.append(mapped_row)
802
+
803
+ json_dict.update(
804
+ {
805
+ "_type": Table._log_type,
806
+ "columns": self.columns,
807
+ "data": mapped_data,
808
+ "ncols": len(self.columns),
809
+ "nrows": len(mapped_data),
810
+ "column_types": self._column_types.to_json(artifact),
811
+ "log_mode": self.log_mode,
812
+ }
813
+ )
814
+ else:
815
+ raise TypeError("to_json accepts wandb_run.Run or wandb_artifact.Artifact")
816
+
817
+ return json_dict
818
+
819
+ def iterrows(self):
820
+ """Returns the table data by row, showing the index of the row and the relevant data.
821
+
822
+ Yields:
823
+ ------
824
+ index: The index of the row. Using this value in other W&B tables
825
+ will automatically build a relationship between the tables
826
+ row: The data of the row.
827
+
828
+ <!-- lazydoc-ignore: internal -->
829
+ """
830
+ for ndx in range(len(self.data)):
831
+ index = _TableIndex(ndx)
832
+ index.set_table(self)
833
+ yield index, self.data[ndx]
834
+
835
+ @allow_relogging_after_mutation
836
+ def set_pk(self, col_name):
837
+ """Set primary key type for Table object.
838
+
839
+ <!-- lazydoc-ignore: internal -->
840
+ """
841
+ # TODO: Docs
842
+ assert col_name in self.columns
843
+ self.cast(col_name, _PrimaryKeyType())
844
+
845
+ @allow_relogging_after_mutation
846
+ def set_fk(self, col_name, table, table_col):
847
+ """Set foreign key type for Table object.
848
+
849
+ <!-- lazydoc-ignore: internal -->
850
+ """
851
+ # TODO: Docs
852
+ assert col_name in self.columns
853
+ assert col_name != self._pk_col
854
+ self.cast(col_name, _ForeignKeyType(table, table_col))
855
+
856
+ def _update_keys(self, force_last=False):
857
+ """Updates the known key-like columns based on current column types.
858
+
859
+ If the state has been updated since the last update, wraps the data
860
+ appropriately in the Key classes.
861
+
862
+ Args:
863
+ force_last: (bool) Wraps the last column of data even if there
864
+ are no key updates.
865
+ """
866
+ _pk_col = None
867
+ _fk_cols = set()
868
+
869
+ # Buildup the known keys from column types
870
+ c_types = self._column_types.params["type_map"]
871
+ for t in c_types:
872
+ if isinstance(c_types[t], _PrimaryKeyType):
873
+ _pk_col = t
874
+ elif isinstance(c_types[t], _ForeignKeyType) or isinstance(
875
+ c_types[t], _ForeignIndexType
876
+ ):
877
+ _fk_cols.add(t)
878
+
879
+ # If there are updates to perform, safely update them
880
+ has_update = _pk_col != self._pk_col or _fk_cols != self._fk_cols
881
+ if has_update:
882
+ # If we removed the PK
883
+ if _pk_col is None and self._pk_col is not None:
884
+ raise AssertionError(
885
+ f"Cannot unset primary key (column {self._pk_col})"
886
+ )
887
+ # If there is a removed FK
888
+ if len(self._fk_cols - _fk_cols) > 0:
889
+ raise AssertionError(
890
+ f"Cannot unset foreign key. Attempted to unset ({self._fk_cols - _fk_cols})"
891
+ )
892
+
893
+ self._pk_col = _pk_col
894
+ self._fk_cols = _fk_cols
895
+
896
+ # Apply updates to data only if there are update or the caller
897
+ # requested the final row to be updated
898
+ if has_update or force_last:
899
+ self._apply_key_updates(not has_update)
900
+
901
+ def _apply_key_updates(self, only_last=False):
902
+ """Appropriately wraps the underlying data in special Key classes.
903
+
904
+ Args:
905
+ only_last: only apply the updates to the last row (used for performance when
906
+ the caller knows that the only new data is the last row and no updates were
907
+ applied to the column types)
908
+ """
909
+ c_types = self._column_types.params["type_map"]
910
+
911
+ # Define a helper function which will wrap the data of a single row
912
+ # in the appropriate class wrapper.
913
+ def update_row(row_ndx):
914
+ for fk_col in self._fk_cols:
915
+ col_ndx = self.columns.index(fk_col)
916
+
917
+ # Wrap the Foreign Keys
918
+ if isinstance(c_types[fk_col], _ForeignKeyType) and not isinstance(
919
+ self.data[row_ndx][col_ndx], _TableKey
920
+ ):
921
+ self.data[row_ndx][col_ndx] = _TableKey(self.data[row_ndx][col_ndx])
922
+ self.data[row_ndx][col_ndx].set_table(
923
+ c_types[fk_col].params["table"],
924
+ c_types[fk_col].params["col_name"],
925
+ )
926
+
927
+ # Wrap the Foreign Indexes
928
+ elif isinstance(c_types[fk_col], _ForeignIndexType) and not isinstance(
929
+ self.data[row_ndx][col_ndx], _TableIndex
930
+ ):
931
+ self.data[row_ndx][col_ndx] = _TableIndex(
932
+ self.data[row_ndx][col_ndx]
933
+ )
934
+ self.data[row_ndx][col_ndx].set_table(
935
+ c_types[fk_col].params["table"]
936
+ )
937
+
938
+ # Wrap the Primary Key
939
+ if self._pk_col is not None:
940
+ col_ndx = self.columns.index(self._pk_col)
941
+ self.data[row_ndx][col_ndx] = _TableKey(self.data[row_ndx][col_ndx])
942
+ self.data[row_ndx][col_ndx].set_table(self, self._pk_col)
943
+
944
+ if only_last:
945
+ update_row(len(self.data) - 1)
946
+ else:
947
+ for row_ndx in range(len(self.data)):
948
+ update_row(row_ndx)
949
+
950
+ @ensure_not_incremental
951
+ @allow_relogging_after_mutation
952
+ def add_column(self, name, data, optional=False):
953
+ """Adds a column of data to the table.
954
+
955
+ Args:
956
+ name: (str) - the unique name of the column
957
+ data: (list | np.array) - a column of homogeneous data
958
+ optional: (bool) - if null-like values are permitted
959
+ """
960
+ assert isinstance(name, str) and name not in self.columns
961
+ is_np = util.is_numpy_array(data)
962
+ assert isinstance(data, list) or is_np
963
+ assert isinstance(optional, bool)
964
+ is_first_col = len(self.columns) == 0
965
+ assert is_first_col or len(data) == len(self.data), (
966
+ f"Expected length {len(self.data)}, found {len(data)}"
967
+ )
968
+
969
+ # Add the new data
970
+ for ndx in range(max(len(data), len(self.data))):
971
+ if is_first_col:
972
+ self.data.append([])
973
+ if is_np:
974
+ self.data[ndx].append(data[ndx])
975
+ else:
976
+ self.data[ndx].append(data[ndx])
977
+ # add the column
978
+ self.columns.append(name)
979
+
980
+ try:
981
+ self.cast(name, _dtypes.UnknownType(), optional=optional)
982
+ except TypeError:
983
+ # Undo the changes
984
+ if is_first_col:
985
+ self.data = []
986
+ self.columns = []
987
+ else:
988
+ for ndx in range(len(self.data)):
989
+ self.data[ndx] = self.data[ndx][:-1]
990
+ self.columns = self.columns[:-1]
991
+ raise
992
+
993
+ def get_column(self, name, convert_to=None):
994
+ """Retrieves a column from the table and optionally converts it to a NumPy object.
995
+
996
+ Args:
997
+ name: (str) - the name of the column
998
+ convert_to: (str, optional)
999
+ - "numpy": will convert the underlying data to numpy object
1000
+ """
1001
+ assert name in self.columns
1002
+ assert convert_to is None or convert_to == "numpy"
1003
+ if convert_to == "numpy":
1004
+ np = util.get_module(
1005
+ "numpy", required="Converting to NumPy requires installing NumPy"
1006
+ )
1007
+ col = []
1008
+ col_ndx = self.columns.index(name)
1009
+ for row in self.data:
1010
+ item = row[col_ndx]
1011
+ if convert_to is not None and isinstance(item, WBValue):
1012
+ item = item.to_data_array()
1013
+ col.append(item)
1014
+ if convert_to == "numpy":
1015
+ col = np.array(col)
1016
+ return col
1017
+
1018
+ def get_index(self):
1019
+ """Returns an array of row indexes for use in other tables to create links."""
1020
+ ndxs = []
1021
+ for ndx in range(len(self.data)):
1022
+ index = _TableIndex(ndx)
1023
+ index.set_table(self)
1024
+ ndxs.append(index)
1025
+ return ndxs
1026
+
1027
+ def get_dataframe(self):
1028
+ """Returns a `pandas.DataFrame` of the table."""
1029
+ pd = util.get_module(
1030
+ "pandas",
1031
+ required="Converting to pandas.DataFrame requires installing pandas",
1032
+ )
1033
+ return pd.DataFrame.from_records(self.data, columns=self.columns)
1034
+
1035
+ def index_ref(self, index):
1036
+ """Gets a reference of the index of a row in the table.
1037
+
1038
+ <!-- lazydoc-ignore: internal -->
1039
+ """
1040
+ assert index < len(self.data)
1041
+ _index = _TableIndex(index)
1042
+ _index.set_table(self)
1043
+ return _index
1044
+
1045
+ @ensure_not_incremental
1046
+ @allow_relogging_after_mutation
1047
+ def add_computed_columns(self, fn):
1048
+ """Adds one or more computed columns based on existing data.
1049
+
1050
+ Args:
1051
+ fn: A function which accepts one or two parameters, ndx (int) and
1052
+ row (dict), which is expected to return a dict representing
1053
+ new columns for that row, keyed by the new column names.
1054
+ - `ndx` is an integer representing the index of the row. Only included if `include_ndx`
1055
+ is set to `True`.
1056
+ - `row` is a dictionary keyed by existing columns
1057
+ """
1058
+ new_columns = {}
1059
+ for ndx, row in self.iterrows():
1060
+ row_dict = {self.columns[i]: row[i] for i in range(len(self.columns))}
1061
+ new_row_dict = fn(ndx, row_dict)
1062
+ assert isinstance(new_row_dict, dict)
1063
+ for key in new_row_dict:
1064
+ new_columns[key] = new_columns.get(key, [])
1065
+ new_columns[key].append(new_row_dict[key])
1066
+ for new_col_name in new_columns:
1067
+ self.add_column(new_col_name, new_columns[new_col_name])
1068
+
1069
+
1070
+ class _PartitionTablePartEntry:
1071
+ """Helper class for PartitionTable to track its parts."""
1072
+
1073
+ def __init__(self, entry, source_artifact):
1074
+ self.entry = entry
1075
+ self.source_artifact = source_artifact
1076
+ self._part = None
1077
+
1078
+ def get_part(self):
1079
+ if self._part is None:
1080
+ self._part = self.source_artifact.get(self.entry.path)
1081
+ return self._part
1082
+
1083
+ def free(self):
1084
+ self._part = None
1085
+
1086
+
1087
+ class PartitionedTable(Media):
1088
+ """A table which is composed of multiple sub-tables.
1089
+
1090
+ Currently, PartitionedTable is designed to point to a directory within an
1091
+ artifact.
1092
+ """
1093
+
1094
+ _log_type = "partitioned-table"
1095
+
1096
+ def __init__(self, parts_path):
1097
+ """Initialize a PartitionedTable.
1098
+
1099
+ Args:
1100
+ parts_path (str): path to a directory of tables in the artifact.
1101
+ """
1102
+ super().__init__()
1103
+ self.parts_path = parts_path
1104
+ self._loaded_part_entries = {}
1105
+
1106
+ def to_json(self, artifact_or_run):
1107
+ json_obj = {
1108
+ "_type": PartitionedTable._log_type,
1109
+ }
1110
+ if isinstance(artifact_or_run, wandb.Run):
1111
+ artifact_entry_url = self._get_artifact_entry_ref_url()
1112
+ if artifact_entry_url is None:
1113
+ raise ValueError(
1114
+ "PartitionedTables must first be added to an Artifact before logging to a Run"
1115
+ )
1116
+ json_obj["artifact_path"] = artifact_entry_url
1117
+ else:
1118
+ json_obj["parts_path"] = self.parts_path
1119
+ return json_obj
1120
+
1121
+ @classmethod
1122
+ def from_json(cls, json_obj, source_artifact):
1123
+ instance = cls(json_obj["parts_path"])
1124
+ entries = source_artifact.manifest.get_entries_in_directory(
1125
+ json_obj["parts_path"]
1126
+ )
1127
+ for entry in entries:
1128
+ instance._add_part_entry(entry, source_artifact)
1129
+ return instance
1130
+
1131
+ def iterrows(self):
1132
+ """Iterate over rows as (ndx, row).
1133
+
1134
+ Args:
1135
+ index (int): The index of the row.
1136
+ row (List[any]): The data of the row.
1137
+ """
1138
+ columns = None
1139
+ ndx = 0
1140
+ for entry_path in self._loaded_part_entries:
1141
+ part = self._loaded_part_entries[entry_path].get_part()
1142
+ if columns is None:
1143
+ columns = part.columns
1144
+ elif columns != part.columns:
1145
+ raise ValueError(
1146
+ f"Table parts have non-matching columns. {columns} != {part.columns}"
1147
+ )
1148
+ for _, row in part.iterrows():
1149
+ yield ndx, row
1150
+ ndx += 1
1151
+
1152
+ self._loaded_part_entries[entry_path].free()
1153
+
1154
+ def _add_part_entry(self, entry, source_artifact):
1155
+ self._loaded_part_entries[entry.path] = _PartitionTablePartEntry(
1156
+ entry, source_artifact
1157
+ )
1158
+
1159
+ def __ne__(self, other):
1160
+ return not self.__eq__(other)
1161
+
1162
+ def __eq__(self, other):
1163
+ return isinstance(other, self.__class__) and self.parts_path == other.parts_path
1164
+
1165
+ def bind_to_run(self, *args, **kwargs):
1166
+ raise ValueError("PartitionedTables cannot be bound to runs")
1167
+
1168
+
1169
+ class JoinedTable(Media):
1170
+ """Join two tables for visualization in the Artifact UI.
1171
+
1172
+ Args:
1173
+ table1 (str, wandb.Table, ArtifactManifestEntry):
1174
+ the path to a wandb.Table in an artifact, the table object, or ArtifactManifestEntry
1175
+ table2 (str, wandb.Table):
1176
+ the path to a wandb.Table in an artifact, the table object, or ArtifactManifestEntry
1177
+ join_key (str, [str, str]):
1178
+ key or keys to perform the join
1179
+ """
1180
+
1181
+ _log_type = "joined-table"
1182
+
1183
+ def __init__(self, table1, table2, join_key):
1184
+ super().__init__()
1185
+
1186
+ if not isinstance(join_key, str) and (
1187
+ not isinstance(join_key, list) or len(join_key) != 2
1188
+ ):
1189
+ raise ValueError(
1190
+ "JoinedTable join_key should be a string or a list of two strings"
1191
+ )
1192
+
1193
+ if not self._validate_table_input(table1):
1194
+ raise ValueError(
1195
+ "JoinedTable table1 should be an artifact path to a table or wandb.Table object"
1196
+ )
1197
+
1198
+ if not self._validate_table_input(table2):
1199
+ raise ValueError(
1200
+ "JoinedTable table2 should be an artifact path to a table or wandb.Table object"
1201
+ )
1202
+
1203
+ self._table1 = table1
1204
+ self._table2 = table2
1205
+ self._join_key = join_key
1206
+
1207
+ @classmethod
1208
+ def from_json(cls, json_obj, source_artifact):
1209
+ t1 = source_artifact.get(json_obj["table1"])
1210
+ if t1 is None:
1211
+ t1 = json_obj["table1"]
1212
+
1213
+ t2 = source_artifact.get(json_obj["table2"])
1214
+ if t2 is None:
1215
+ t2 = json_obj["table2"]
1216
+
1217
+ return cls(
1218
+ t1,
1219
+ t2,
1220
+ json_obj["join_key"],
1221
+ )
1222
+
1223
+ @staticmethod
1224
+ def _validate_table_input(table):
1225
+ """Helper method to validate that the table input is one of the 3 supported types."""
1226
+ return (
1227
+ (isinstance(table, str) and table.endswith(".table.json"))
1228
+ or isinstance(table, Table)
1229
+ or isinstance(table, PartitionedTable)
1230
+ or (hasattr(table, "ref_url") and table.ref_url().endswith(".table.json"))
1231
+ )
1232
+
1233
+ def _ensure_table_in_artifact(self, table, artifact, table_ndx):
1234
+ """Helper method to add the table to the incoming artifact. Returns the path."""
1235
+ if isinstance(table, Table) or isinstance(table, PartitionedTable):
1236
+ table_name = f"t{table_ndx}_{str(id(self))}"
1237
+ if (
1238
+ table._artifact_source is not None
1239
+ and table._artifact_source.name is not None
1240
+ ):
1241
+ table_name = os.path.basename(table._artifact_source.name)
1242
+ entry = artifact.add(table, table_name)
1243
+ table = entry.path
1244
+ # Check if this is an ArtifactManifestEntry
1245
+ elif hasattr(table, "ref_url"):
1246
+ # Give the new object a unique, yet deterministic name
1247
+ name = binascii.hexlify(base64.standard_b64decode(table.digest)).decode(
1248
+ "ascii"
1249
+ )[:20]
1250
+ entry = artifact.add_reference(
1251
+ table.ref_url(), "{}.{}.json".format(name, table.name.split(".")[-2])
1252
+ )[0]
1253
+ table = entry.path
1254
+
1255
+ err_str = "JoinedTable table:{} not found in artifact. Add a table to the artifact using Artifact#add(<table>, {}) before adding this JoinedTable"
1256
+ if table not in artifact._manifest.entries:
1257
+ raise ValueError(err_str.format(table, table))
1258
+
1259
+ return table
1260
+
1261
+ def to_json(self, artifact_or_run):
1262
+ json_obj = {
1263
+ "_type": JoinedTable._log_type,
1264
+ }
1265
+ if isinstance(artifact_or_run, wandb.Run):
1266
+ artifact_entry_url = self._get_artifact_entry_ref_url()
1267
+ if artifact_entry_url is None:
1268
+ raise ValueError(
1269
+ "JoinedTables must first be added to an Artifact before logging to a Run"
1270
+ )
1271
+ json_obj["artifact_path"] = artifact_entry_url
1272
+ else:
1273
+ table1 = self._ensure_table_in_artifact(self._table1, artifact_or_run, 1)
1274
+ table2 = self._ensure_table_in_artifact(self._table2, artifact_or_run, 2)
1275
+ json_obj.update(
1276
+ {
1277
+ "table1": table1,
1278
+ "table2": table2,
1279
+ "join_key": self._join_key,
1280
+ }
1281
+ )
1282
+ return json_obj
1283
+
1284
+ def __ne__(self, other):
1285
+ return not self.__eq__(other)
1286
+
1287
+ def _eq_debug(self, other, should_assert=False):
1288
+ eq = isinstance(other, JoinedTable)
1289
+ assert not should_assert or eq, (
1290
+ f"Found type {other.__class__}, expected {JoinedTable}"
1291
+ )
1292
+ eq = eq and self._join_key == other._join_key
1293
+ assert not should_assert or eq, (
1294
+ f"Found {other._join_key} join key, expected {self._join_key}"
1295
+ )
1296
+ eq = eq and self._table1._eq_debug(other._table1, should_assert)
1297
+ eq = eq and self._table2._eq_debug(other._table2, should_assert)
1298
+ return eq
1299
+
1300
+ def __eq__(self, other):
1301
+ return self._eq_debug(other, False)
1302
+
1303
+ def bind_to_run(self, *args, **kwargs):
1304
+ raise ValueError("JoinedTables cannot be bound to runs")
1305
+
1306
+
1307
+ class _TableType(_dtypes.Type):
1308
+ name = "table"
1309
+ legacy_names = ["wandb.Table"]
1310
+ types = [Table]
1311
+
1312
+ def __init__(self, column_types=None):
1313
+ if column_types is None:
1314
+ column_types = _dtypes.UnknownType()
1315
+ if isinstance(column_types, dict):
1316
+ column_types = _dtypes.TypedDictType(column_types)
1317
+ elif not (
1318
+ isinstance(column_types, _dtypes.TypedDictType)
1319
+ or isinstance(column_types, _dtypes.UnknownType)
1320
+ ):
1321
+ raise TypeError("column_types must be a dict or TypedDictType")
1322
+
1323
+ self.params.update({"column_types": column_types})
1324
+
1325
+ def assign_type(self, wb_type=None):
1326
+ if isinstance(wb_type, _TableType):
1327
+ column_types = self.params["column_types"].assign_type(
1328
+ wb_type.params["column_types"]
1329
+ )
1330
+ if not isinstance(column_types, _dtypes.InvalidType):
1331
+ return _TableType(column_types)
1332
+
1333
+ return _dtypes.InvalidType()
1334
+
1335
+ @classmethod
1336
+ def from_obj(cls, py_obj):
1337
+ if not isinstance(py_obj, Table):
1338
+ raise TypeError("py_obj must be a wandb.Table")
1339
+ else:
1340
+ return cls(py_obj._column_types)
1341
+
1342
+
1343
+ class _JoinedTableType(_dtypes.Type):
1344
+ name = "joined-table"
1345
+ types = [JoinedTable]
1346
+
1347
+
1348
+ class _PartitionedTableType(_dtypes.Type):
1349
+ name = "partitioned-table"
1350
+ types = [PartitionedTable]
1351
+
1352
+
1353
+ _dtypes.TypeRegistry.add(_TableType)
1354
+ _dtypes.TypeRegistry.add(_JoinedTableType)
1355
+ _dtypes.TypeRegistry.add(_PartitionedTableType)
1356
+ _dtypes.TypeRegistry.add(_ForeignKeyType)
1357
+ _dtypes.TypeRegistry.add(_PrimaryKeyType)
1358
+ _dtypes.TypeRegistry.add(_ForeignIndexType)
1359
+
1360
+
1361
+ def _get_data_from_increments(
1362
+ json_obj: Dict[str, Any], source_artifact: "artifact.Artifact"
1363
+ ) -> List[Any]:
1364
+ """Get data from incremental table artifacts.
1365
+
1366
+ Args:
1367
+ json_obj: The JSON object containing table metadata.
1368
+ source_artifact: The source artifact containing the table data.
1369
+
1370
+ Returns:
1371
+ List of table rows from all increments.
1372
+ """
1373
+ if "latest" not in source_artifact.aliases:
1374
+ wandb.termwarn(
1375
+ (
1376
+ "It is recommended to use the latest version of the "
1377
+ "incremental table artifact for ordering guarantees."
1378
+ ),
1379
+ repeat=False,
1380
+ )
1381
+ data: List[Any] = []
1382
+ increment_num = json_obj.get("increment_num", None)
1383
+ if increment_num is None:
1384
+ return data
1385
+
1386
+ # Sort by increment number first, then by timestamp if present
1387
+ # Format of name is: "{incr_num}-{timestamp_ms}.{key}.table.json"
1388
+ def get_sort_key(key: str) -> Tuple[int, int]:
1389
+ try:
1390
+ parts = key.split(".")
1391
+ increment_parts = parts[0].split("-")
1392
+ increment_num = int(increment_parts[0])
1393
+ # If there's a timestamp part, use it for secondary sorting
1394
+ timestamp = int(increment_parts[1]) if len(increment_parts) > 1 else 0
1395
+ except (ValueError, IndexError):
1396
+ wandb.termwarn(
1397
+ (
1398
+ f"Could not parse artifact entry for increment {key}."
1399
+ " The entry name does not follow the naming convention"
1400
+ " <increment_number>-<timestamp>.<key>.table.json"
1401
+ " The data in the table will be out of order."
1402
+ ),
1403
+ repeat=False,
1404
+ )
1405
+ return (0, 0)
1406
+
1407
+ return (increment_num, timestamp)
1408
+
1409
+ sorted_increment_keys = []
1410
+ for entry_key in source_artifact.manifest.entries:
1411
+ if entry_key.endswith(".table.json"):
1412
+ sorted_increment_keys.append(entry_key)
1413
+
1414
+ sorted_increment_keys.sort(key=get_sort_key)
1415
+
1416
+ for entry_key in sorted_increment_keys:
1417
+ try:
1418
+ with open(source_artifact.manifest.entries[entry_key].download()) as f:
1419
+ table_data = json.load(f)
1420
+ data.extend(table_data["data"])
1421
+ except (json.JSONDecodeError, KeyError) as e:
1422
+ raise wandb.Error(f"Invalid table file {entry_key}") from e
1423
+ return data
1424
+
1425
+
1426
+ def _process_table_row(
1427
+ row: List[Any],
1428
+ timestamp_column_indices: Set[_dtypes.TimestampType],
1429
+ np_deserialized_columns: Dict[int, Any],
1430
+ source_artifact: "artifact.Artifact",
1431
+ row_idx: int,
1432
+ ) -> List[Any]:
1433
+ """Convert special columns in a table row to Python types.
1434
+
1435
+ Processes a single row of table data by converting timestamp values to
1436
+ datetime objects, replacing np typed cells with numpy array data,
1437
+ and initializing media objects from their json value.
1438
+
1439
+
1440
+ Args:
1441
+ row: The row data to process.
1442
+ timestamp_column_indices: Set of column indices containing timestamps.
1443
+ np_deserialized_columns: Dictionary mapping column indices to numpy arrays.
1444
+ source_artifact: The source artifact containing the table data.
1445
+ row_idx: The index of the current row.
1446
+
1447
+ Returns:
1448
+ Processed row data.
1449
+ """
1450
+ row_data = []
1451
+ for c_ndx, item in enumerate(row):
1452
+ cell: Any
1453
+ if c_ndx in timestamp_column_indices and isinstance(item, (int, float)):
1454
+ cell = datetime.datetime.fromtimestamp(
1455
+ item / 1000, tz=datetime.timezone.utc
1456
+ )
1457
+ elif c_ndx in np_deserialized_columns:
1458
+ cell = np_deserialized_columns[c_ndx][row_idx]
1459
+ elif (
1460
+ isinstance(item, dict)
1461
+ and "_type" in item
1462
+ and (obj := WBValue.init_from_json(item, source_artifact))
1463
+ ):
1464
+ cell = obj
1465
+ else:
1466
+ cell = item
1467
+ row_data.append(cell)
1468
+ return row_data