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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. wandb/__init__.py +1 -2
  2. wandb/apis/importers/internals/internal.py +0 -1
  3. wandb/apis/importers/wandb.py +12 -7
  4. wandb/apis/internal.py +0 -3
  5. wandb/apis/public/api.py +213 -79
  6. wandb/apis/public/artifacts.py +335 -100
  7. wandb/apis/public/files.py +9 -9
  8. wandb/apis/public/jobs.py +16 -4
  9. wandb/apis/public/projects.py +26 -28
  10. wandb/apis/public/query_generator.py +1 -1
  11. wandb/apis/public/runs.py +163 -65
  12. wandb/apis/public/sweeps.py +2 -2
  13. wandb/apis/reports/__init__.py +1 -7
  14. wandb/apis/reports/v1/__init__.py +5 -27
  15. wandb/apis/reports/v2/__init__.py +7 -19
  16. wandb/apis/workspaces/__init__.py +8 -0
  17. wandb/beta/workflows.py +8 -3
  18. wandb/bin/wandb-core +0 -0
  19. wandb/cli/cli.py +131 -59
  20. wandb/docker/__init__.py +1 -1
  21. wandb/errors/term.py +10 -2
  22. wandb/filesync/step_checksum.py +1 -4
  23. wandb/filesync/step_prepare.py +4 -24
  24. wandb/filesync/step_upload.py +5 -107
  25. wandb/filesync/upload_job.py +0 -76
  26. wandb/integration/gym/__init__.py +35 -15
  27. wandb/integration/openai/fine_tuning.py +21 -3
  28. wandb/integration/prodigy/prodigy.py +1 -1
  29. wandb/jupyter.py +16 -17
  30. wandb/plot/pr_curve.py +2 -1
  31. wandb/plot/roc_curve.py +2 -1
  32. wandb/{plots → plot}/utils.py +13 -25
  33. wandb/proto/v3/wandb_internal_pb2.py +54 -54
  34. wandb/proto/v3/wandb_settings_pb2.py +2 -2
  35. wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
  36. wandb/proto/v4/wandb_internal_pb2.py +54 -54
  37. wandb/proto/v4/wandb_settings_pb2.py +2 -2
  38. wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
  39. wandb/proto/v5/wandb_base_pb2.py +30 -0
  40. wandb/proto/v5/wandb_internal_pb2.py +355 -0
  41. wandb/proto/v5/wandb_server_pb2.py +63 -0
  42. wandb/proto/v5/wandb_settings_pb2.py +45 -0
  43. wandb/proto/v5/wandb_telemetry_pb2.py +41 -0
  44. wandb/proto/wandb_base_pb2.py +2 -0
  45. wandb/proto/wandb_deprecated.py +9 -1
  46. wandb/proto/wandb_generate_deprecated.py +34 -0
  47. wandb/proto/{wandb_internal_codegen.py → wandb_generate_proto.py} +1 -35
  48. wandb/proto/wandb_internal_pb2.py +2 -0
  49. wandb/proto/wandb_server_pb2.py +2 -0
  50. wandb/proto/wandb_settings_pb2.py +2 -0
  51. wandb/proto/wandb_telemetry_pb2.py +2 -0
  52. wandb/sdk/artifacts/artifact.py +68 -22
  53. wandb/sdk/artifacts/artifact_manifest.py +1 -1
  54. wandb/sdk/artifacts/artifact_manifest_entry.py +6 -3
  55. wandb/sdk/artifacts/artifact_manifests/artifact_manifest_v1.py +1 -1
  56. wandb/sdk/artifacts/artifact_saver.py +1 -10
  57. wandb/sdk/artifacts/storage_handlers/local_file_handler.py +6 -2
  58. wandb/sdk/artifacts/storage_handlers/multi_handler.py +1 -1
  59. wandb/sdk/artifacts/storage_handlers/tracking_handler.py +6 -4
  60. wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +2 -42
  61. wandb/sdk/artifacts/storage_policy.py +1 -12
  62. wandb/sdk/data_types/image.py +1 -1
  63. wandb/sdk/data_types/video.py +4 -2
  64. wandb/sdk/interface/interface.py +13 -0
  65. wandb/sdk/interface/interface_shared.py +1 -1
  66. wandb/sdk/internal/file_pusher.py +2 -5
  67. wandb/sdk/internal/file_stream.py +6 -19
  68. wandb/sdk/internal/internal_api.py +148 -136
  69. wandb/sdk/internal/job_builder.py +207 -135
  70. wandb/sdk/internal/progress.py +0 -28
  71. wandb/sdk/internal/sender.py +102 -39
  72. wandb/sdk/internal/settings_static.py +8 -1
  73. wandb/sdk/internal/system/assets/trainium.py +3 -3
  74. wandb/sdk/internal/system/system_info.py +4 -2
  75. wandb/sdk/internal/update.py +1 -1
  76. wandb/sdk/launch/__init__.py +9 -1
  77. wandb/sdk/launch/_launch.py +4 -24
  78. wandb/sdk/launch/_launch_add.py +1 -3
  79. wandb/sdk/launch/_project_spec.py +184 -224
  80. wandb/sdk/launch/agent/agent.py +58 -18
  81. wandb/sdk/launch/agent/config.py +0 -3
  82. wandb/sdk/launch/builder/abstract.py +67 -0
  83. wandb/sdk/launch/builder/build.py +165 -576
  84. wandb/sdk/launch/builder/context_manager.py +235 -0
  85. wandb/sdk/launch/builder/docker_builder.py +7 -23
  86. wandb/sdk/launch/builder/kaniko_builder.py +10 -23
  87. wandb/sdk/launch/builder/templates/dockerfile.py +92 -0
  88. wandb/sdk/launch/create_job.py +51 -45
  89. wandb/sdk/launch/environment/aws_environment.py +26 -1
  90. wandb/sdk/launch/inputs/files.py +148 -0
  91. wandb/sdk/launch/inputs/internal.py +224 -0
  92. wandb/sdk/launch/inputs/manage.py +95 -0
  93. wandb/sdk/launch/runner/abstract.py +2 -2
  94. wandb/sdk/launch/runner/kubernetes_monitor.py +45 -12
  95. wandb/sdk/launch/runner/kubernetes_runner.py +6 -8
  96. wandb/sdk/launch/runner/local_container.py +2 -3
  97. wandb/sdk/launch/runner/local_process.py +8 -29
  98. wandb/sdk/launch/runner/sagemaker_runner.py +20 -14
  99. wandb/sdk/launch/runner/vertex_runner.py +8 -7
  100. wandb/sdk/launch/sweeps/scheduler.py +2 -0
  101. wandb/sdk/launch/sweeps/utils.py +2 -2
  102. wandb/sdk/launch/utils.py +16 -138
  103. wandb/sdk/lib/_settings_toposort_generated.py +2 -5
  104. wandb/sdk/lib/apikey.py +4 -2
  105. wandb/sdk/lib/config_util.py +3 -3
  106. wandb/sdk/lib/proto_util.py +22 -1
  107. wandb/sdk/lib/redirect.py +1 -1
  108. wandb/sdk/service/service.py +2 -1
  109. wandb/sdk/service/streams.py +5 -5
  110. wandb/sdk/wandb_init.py +25 -59
  111. wandb/sdk/wandb_login.py +28 -25
  112. wandb/sdk/wandb_run.py +112 -45
  113. wandb/sdk/wandb_settings.py +33 -64
  114. wandb/sdk/wandb_watch.py +1 -1
  115. wandb/sklearn/plot/classifier.py +4 -6
  116. wandb/sync/sync.py +2 -2
  117. wandb/testing/relay.py +32 -17
  118. wandb/util.py +36 -37
  119. wandb/wandb_agent.py +3 -3
  120. wandb/wandb_controller.py +3 -2
  121. {wandb-0.17.0rc2.dist-info → wandb-0.17.1.dist-info}/METADATA +7 -9
  122. {wandb-0.17.0rc2.dist-info → wandb-0.17.1.dist-info}/RECORD +125 -147
  123. wandb/apis/reports/v1/_blocks.py +0 -1406
  124. wandb/apis/reports/v1/_helpers.py +0 -70
  125. wandb/apis/reports/v1/_panels.py +0 -1282
  126. wandb/apis/reports/v1/_templates.py +0 -478
  127. wandb/apis/reports/v1/blocks.py +0 -27
  128. wandb/apis/reports/v1/helpers.py +0 -2
  129. wandb/apis/reports/v1/mutations.py +0 -66
  130. wandb/apis/reports/v1/panels.py +0 -17
  131. wandb/apis/reports/v1/report.py +0 -268
  132. wandb/apis/reports/v1/runset.py +0 -144
  133. wandb/apis/reports/v1/templates.py +0 -7
  134. wandb/apis/reports/v1/util.py +0 -406
  135. wandb/apis/reports/v1/validators.py +0 -131
  136. wandb/apis/reports/v2/blocks.py +0 -25
  137. wandb/apis/reports/v2/expr_parsing.py +0 -257
  138. wandb/apis/reports/v2/gql.py +0 -68
  139. wandb/apis/reports/v2/interface.py +0 -1911
  140. wandb/apis/reports/v2/internal.py +0 -867
  141. wandb/apis/reports/v2/metrics.py +0 -6
  142. wandb/apis/reports/v2/panels.py +0 -15
  143. wandb/catboost/__init__.py +0 -9
  144. wandb/fastai/__init__.py +0 -9
  145. wandb/keras/__init__.py +0 -19
  146. wandb/lightgbm/__init__.py +0 -9
  147. wandb/plots/__init__.py +0 -6
  148. wandb/plots/explain_text.py +0 -36
  149. wandb/plots/heatmap.py +0 -81
  150. wandb/plots/named_entity.py +0 -43
  151. wandb/plots/part_of_speech.py +0 -50
  152. wandb/plots/plot_definitions.py +0 -768
  153. wandb/plots/precision_recall.py +0 -121
  154. wandb/plots/roc.py +0 -103
  155. wandb/sacred/__init__.py +0 -3
  156. wandb/xgboost/__init__.py +0 -9
  157. {wandb-0.17.0rc2.dist-info → wandb-0.17.1.dist-info}/WHEEL +0 -0
  158. {wandb-0.17.0rc2.dist-info → wandb-0.17.1.dist-info}/entry_points.txt +0 -0
  159. {wandb-0.17.0rc2.dist-info → wandb-0.17.1.dist-info}/licenses/LICENSE +0 -0
@@ -10,6 +10,7 @@ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Un
10
10
  import wandb
11
11
  from wandb.sdk.artifacts.artifact import Artifact
12
12
  from wandb.sdk.data_types._dtypes import TypeRegistry
13
+ from wandb.sdk.internal.internal_api import Api
13
14
  from wandb.sdk.lib.filenames import DIFF_FNAME, METADATA_FNAME, REQUIREMENTS_FNAME
14
15
  from wandb.util import make_artifact_name_safe
15
16
 
@@ -23,7 +24,7 @@ else:
23
24
  _logger = logging.getLogger(__name__)
24
25
 
25
26
  if TYPE_CHECKING:
26
- from wandb.proto.wandb_internal_pb2 import ArtifactRecord, UseArtifactRecord
27
+ from wandb.proto.wandb_internal_pb2 import ArtifactRecord
27
28
 
28
29
  FROZEN_REQUIREMENTS_FNAME = "requirements.frozen.txt"
29
30
  JOB_FNAME = "wandb-job.json"
@@ -32,6 +33,43 @@ JOB_ARTIFACT_TYPE = "job"
32
33
  LOG_LEVEL = Literal["log", "warn", "error"]
33
34
 
34
35
 
36
+ class Version:
37
+ def __init__(self, major: int, minor: int, patch: int):
38
+ self._major = major
39
+ self._minor = minor
40
+ self._patch = patch
41
+
42
+ def __repr__(self) -> str:
43
+ return f"{self._major}.{self._minor}.{self._patch}"
44
+
45
+ def __lt__(self, other: "Version") -> bool:
46
+ if self._major < other._major:
47
+ return True
48
+ elif self._major == other._major:
49
+ if self._minor < other._minor:
50
+ return True
51
+ elif self._minor == other._minor:
52
+ if self._patch < other._patch:
53
+ return True
54
+ return False
55
+
56
+ def __eq__(self, other: object) -> bool:
57
+ if not isinstance(other, Version):
58
+ return NotImplemented
59
+ return (
60
+ self._major == other._major
61
+ and self._minor == other._minor
62
+ and self._patch == other._patch
63
+ )
64
+
65
+
66
+ # Minimum supported wandb version for keys in the source dict of wandb-job.json
67
+ SOURCE_KEYS_MIN_SUPPORTED_VERSION = {
68
+ "dockerfile": Version(0, 17, 0),
69
+ "build_context": Version(0, 17, 0),
70
+ }
71
+
72
+
35
73
  class GitInfo(TypedDict):
36
74
  remote: str
37
75
  commit: str
@@ -41,12 +79,16 @@ class GitSourceDict(TypedDict):
41
79
  git: GitInfo
42
80
  entrypoint: List[str]
43
81
  notebook: bool
82
+ build_context: Optional[str]
83
+ dockerfile: Optional[str]
44
84
 
45
85
 
46
86
  class ArtifactSourceDict(TypedDict):
47
87
  artifact: str
48
88
  entrypoint: List[str]
49
89
  notebook: bool
90
+ build_context: Optional[str]
91
+ dockerfile: Optional[str]
50
92
 
51
93
 
52
94
  class ImageSourceDict(TypedDict):
@@ -60,12 +102,6 @@ class JobSourceDict(TypedDict, total=False):
60
102
  input_types: Dict[str, Any]
61
103
  output_types: Dict[str, Any]
62
104
  runtime: Optional[str]
63
- _partial: Optional[str] # flag to indicate incomplete job
64
-
65
-
66
- class PartialJobSourceDict(TypedDict):
67
- job_name: str
68
- job_source_info: JobSourceDict
69
105
 
70
106
 
71
107
  class ArtifactInfoForJob(TypedDict):
@@ -73,6 +109,19 @@ class ArtifactInfoForJob(TypedDict):
73
109
  name: str
74
110
 
75
111
 
112
+ def get_min_supported_for_source_dict(
113
+ source: Union[GitSourceDict, ArtifactSourceDict, ImageSourceDict],
114
+ ) -> Optional[Version]:
115
+ """Get the minimum supported wandb version the source dict of wandb-job.json."""
116
+ min_seen = None
117
+ for key in source:
118
+ new_ver = SOURCE_KEYS_MIN_SUPPORTED_VERSION.get(key)
119
+ if new_ver:
120
+ if min_seen is None or new_ver < min_seen:
121
+ min_seen = new_ver
122
+ return min_seen
123
+
124
+
76
125
  class JobArtifact(Artifact):
77
126
  def __init__(self, name: str, *args: Any, **kwargs: Any):
78
127
  super().__init__(name, "placeholder", *args, **kwargs)
@@ -87,7 +136,7 @@ class JobBuilder:
87
136
  _summary: Optional[Dict[str, Any]]
88
137
  _logged_code_artifact: Optional[ArtifactInfoForJob]
89
138
  _disable: bool
90
- _partial_source: Optional[PartialJobSourceDict]
139
+ _partial_source_id: Optional[str] # Partial job source artifact id.
91
140
  _aliases: List[str]
92
141
  _job_seq_id: Optional[str]
93
142
  _job_version_alias: Optional[str]
@@ -104,13 +153,14 @@ class JobBuilder:
104
153
  self._job_seq_id = None
105
154
  self._job_version_alias = None
106
155
  self._disable = settings.disable_job_creation
107
- self._partial_source = None
156
+ self._partial_source_id = None
108
157
  self._aliases = []
109
158
  self._source_type: Optional[Literal["repo", "artifact", "image"]] = (
110
159
  settings.job_source # type: ignore[assignment]
111
160
  )
112
161
  self._is_notebook_run = self._get_is_notebook_run()
113
162
  self._verbose = verbose
163
+ self._partial = False
114
164
 
115
165
  def set_config(self, config: Dict[str, Any]) -> None:
116
166
  self._config = config
@@ -126,6 +176,17 @@ class JobBuilder:
126
176
  def disable(self, val: bool) -> None:
127
177
  self._disable = val
128
178
 
179
+ @property
180
+ def input_types(self) -> Dict[str, Any]:
181
+ return TypeRegistry.type_of(self._config).to_json()
182
+
183
+ @property
184
+ def output_types(self) -> Dict[str, Any]:
185
+ return TypeRegistry.type_of(self._summary).to_json()
186
+
187
+ def set_partial_source_id(self, source_id: str) -> None:
188
+ self._partial_source_id = source_id
189
+
129
190
  def _handle_server_artifact(
130
191
  self, res: Optional[Dict], artifact: "ArtifactRecord"
131
192
  ) -> None:
@@ -197,6 +258,8 @@ class JobBuilder:
197
258
  "git": {"remote": remote, "commit": commit},
198
259
  "entrypoint": entrypoint,
199
260
  "notebook": self._is_notebook_run,
261
+ "build_context": metadata.get("build_context"),
262
+ "dockerfile": metadata.get("dockerfile"),
200
263
  }
201
264
  name = self._make_job_name(f"{remote}_{program_relpath}")
202
265
 
@@ -247,6 +310,8 @@ class JobBuilder:
247
310
  "entrypoint": entrypoint,
248
311
  "notebook": self._is_notebook_run,
249
312
  "artifact": f"wandb-artifact://_id/{self._logged_code_artifact['id']}",
313
+ "build_context": metadata.get("build_context"),
314
+ "dockerfile": metadata.get("dockerfile"),
250
315
  }
251
316
  name = self._make_job_name(self._logged_code_artifact["name"])
252
317
 
@@ -289,21 +354,10 @@ class JobBuilder:
289
354
  ) -> List[str]:
290
355
  # if building a partial job from CLI, overwrite entrypoint and notebook
291
356
  # should already be in metadata from create_job
292
- if metadata.get("_partial"):
357
+ if self._partial:
293
358
  if metadata.get("entrypoint"):
294
359
  entrypoint: List[str] = metadata["entrypoint"]
295
360
  return entrypoint
296
-
297
- # if entrypoint is not in metadata, then construct from python
298
- assert metadata.get("python")
299
-
300
- python = metadata["python"]
301
- if python.count(".") > 1:
302
- python = ".".join(python.split(".")[:2])
303
-
304
- entrypoint = [f"python{python}", program_relpath]
305
- return entrypoint
306
-
307
361
  # job is being built from a run
308
362
  entrypoint = [os.path.basename(sys.executable), program_relpath]
309
363
 
@@ -315,8 +369,89 @@ class JobBuilder:
315
369
  def _is_colab_run(self) -> bool:
316
370
  return hasattr(self._settings, "_colab") and bool(self._settings._colab)
317
371
 
318
- def build(self) -> Optional[Artifact]:
372
+ def _build_job_source(
373
+ self,
374
+ source_type: str,
375
+ program_relpath: Optional[str],
376
+ metadata: Dict[str, Any],
377
+ ) -> Tuple[
378
+ Union[GitSourceDict, ArtifactSourceDict, ImageSourceDict, None],
379
+ Optional[str],
380
+ ]:
381
+ """Construct a job source dict and name from the current run.
382
+
383
+ Arguments:
384
+ source_type (str): The type of source to build the job from. One of
385
+ "repo", "artifact", or "image".
386
+ """
387
+ source: Union[
388
+ GitSourceDict,
389
+ ArtifactSourceDict,
390
+ ImageSourceDict,
391
+ None,
392
+ ] = None
393
+
394
+ if source_type == "repo":
395
+ source, name = self._build_repo_job_source(
396
+ program_relpath or "",
397
+ metadata,
398
+ )
399
+ elif source_type == "artifact":
400
+ source, name = self._build_artifact_job_source(
401
+ program_relpath or "",
402
+ metadata,
403
+ )
404
+ elif source_type == "image" and self._has_image_job_ingredients(metadata):
405
+ source, name = self._build_image_job_source(metadata)
406
+ else:
407
+ source = None
408
+
409
+ if source is None:
410
+ if source_type:
411
+ self._log_if_verbose(
412
+ f"Source type is set to '{source_type}' but some required information is missing "
413
+ "from the environment. A job will not be created from this run. See "
414
+ "https://docs.wandb.ai/guides/launch/create-job",
415
+ "warn",
416
+ )
417
+ return None, None
418
+
419
+ return source, name
420
+
421
+ def build(
422
+ self,
423
+ api: Api,
424
+ build_context: Optional[str] = None,
425
+ dockerfile: Optional[str] = None,
426
+ ) -> Optional[Artifact]:
427
+ """Build a job artifact from the current run.
428
+
429
+ Arguments:
430
+ build_context (Optional[str]): Path within the job source code to
431
+ the image build context. Saved as part of the job for future
432
+ builds.
433
+ dockerfile (Optional[str]): Path within the build context the
434
+ Dockerfile. Saved as part of the job for future builds.
435
+
436
+ Returns:
437
+ Optional[Artifact]: The job artifact if it was successfully built,
438
+ otherwise None.
439
+ """
319
440
  _logger.info("Attempting to build job artifact")
441
+
442
+ # If a partial job was used, write the input/output types to the metadata
443
+ # rather than building a new job version.
444
+ if self._partial_source_id is not None:
445
+ new_metadata = {
446
+ "input_types": {"@wandb.config": self.input_types},
447
+ "output_types": self.output_types,
448
+ }
449
+ api.update_artifact_metadata(
450
+ self._partial_source_id,
451
+ new_metadata,
452
+ )
453
+ return None
454
+
320
455
  if not os.path.exists(
321
456
  os.path.join(self._settings.files_dir, REQUIREMENTS_FNAME)
322
457
  ):
@@ -332,6 +467,8 @@ class JobBuilder:
332
467
  "warn",
333
468
  )
334
469
  return None
470
+ metadata["dockerfile"] = dockerfile
471
+ metadata["build_context"] = build_context
335
472
 
336
473
  runtime: Optional[str] = metadata.get("python")
337
474
  # can't build a job without a python version
@@ -348,84 +485,60 @@ class JobBuilder:
348
485
  name: Optional[str] = None
349
486
  source_info: Optional[JobSourceDict] = None
350
487
 
351
- if self._partial_source is not None:
352
- # construct source from downloaded partial job metadata
353
- name = self._partial_source["job_name"]
354
- source_info = self._partial_source["job_source_info"]
355
- # add input/output types now that we are actually running a run
356
- source_info.update(
357
- {"input_types": input_types, "output_types": output_types}
358
- )
359
- # set source_type to determine whether to add diff file to artifact
360
- source_type = source_info.get("source_type")
361
- else:
362
- # configure job from environment
363
- source_type = self._get_source_type(metadata)
364
- if not source_type:
365
- # if source_type is None, then we don't have enough information to build a job
366
- # if the user intended to create a job, warn.
367
- if (
368
- self._settings.job_name
369
- or self._settings.job_source
370
- or self._source_type
371
- ):
372
- self._log_if_verbose(
373
- "No source type found, not creating job artifact", "warn"
374
- )
375
- return None
376
-
377
- program_relpath = self._get_program_relpath(source_type, metadata)
378
- if source_type != "image" and not program_relpath:
488
+ # configure job from environment
489
+ source_type = self._get_source_type(metadata)
490
+ if not source_type:
491
+ # if source_type is None, then we don't have enough information to build a job
492
+ # if the user intended to create a job, warn.
493
+ if (
494
+ self._settings.job_name
495
+ or self._settings.job_source
496
+ or self._source_type
497
+ ):
379
498
  self._log_if_verbose(
380
- "No program path found, not creating job artifact. See https://docs.wandb.ai/guides/launch/create-job",
381
- "warn",
499
+ "No source type found, not creating job artifact", "warn"
382
500
  )
383
- return None
384
-
385
- source: Union[
386
- Optional[GitSourceDict],
387
- Optional[ArtifactSourceDict],
388
- Optional[ImageSourceDict],
389
- ] = None
390
-
391
- # make source dict
392
- if source_type == "repo":
393
- assert program_relpath
394
- source, name = self._build_repo_job_source(program_relpath, metadata)
395
- elif source_type == "artifact":
396
- assert program_relpath
397
- source, name = self._build_artifact_job_source(
398
- program_relpath, metadata
399
- )
400
- elif source_type == "image" and self._has_image_job_ingredients(metadata):
401
- source, name = self._build_image_job_source(metadata)
402
- else:
403
- source = None
501
+ return None
404
502
 
405
- if source is None:
406
- if source_type:
407
- self._log_if_verbose(
408
- f"Source type is set to '{source_type}' but some required information is missing "
409
- "from the environment. A job will not be created from this run. See "
410
- "https://docs.wandb.ai/guides/launch/create-job",
411
- "warn",
412
- )
413
- return None
414
-
415
- source_info = {
416
- "_version": "v0",
417
- "source_type": source_type,
418
- "source": source,
419
- "input_types": input_types,
420
- "output_types": output_types,
421
- "runtime": runtime,
422
- }
503
+ program_relpath = self._get_program_relpath(source_type, metadata)
504
+ if not self._partial and source_type != "image" and not program_relpath:
505
+ self._log_if_verbose(
506
+ "No program path found, not creating job artifact. See https://docs.wandb.ai/guides/launch/create-job",
507
+ "warn",
508
+ )
509
+ return None
510
+
511
+ source, name = self._build_job_source(
512
+ source_type,
513
+ program_relpath,
514
+ metadata,
515
+ )
516
+ if source is None:
517
+ return None
518
+
519
+ if build_context:
520
+ source["build_context"] = build_context # type: ignore[typeddict-item]
521
+ if dockerfile:
522
+ source["dockerfile"] = dockerfile # type: ignore[typeddict-item]
523
+
524
+ # Pop any keys that are initialized to None. The current TypedDict
525
+ # system for source dicts requires all keys to be present, but we
526
+ # don't want to include keys that are None in the final dict.
527
+ for key in list(source.keys()):
528
+ if source[key] is None: # type: ignore[literal-required]
529
+ source.pop(key) # type: ignore[literal-require,misc]
530
+
531
+ source_info = {
532
+ "_version": str(get_min_supported_for_source_dict(source) or "v0"),
533
+ "source_type": source_type,
534
+ "source": source,
535
+ "input_types": input_types,
536
+ "output_types": output_types,
537
+ "runtime": runtime,
538
+ }
423
539
 
424
540
  assert source_info is not None
425
541
  assert name is not None
426
- if metadata.get("_partial"):
427
- assert not self._partial_source, "partial job has partial output"
428
- source_info.update({"_partial": metadata["_partial"]})
429
542
 
430
543
  artifact = JobArtifact(name)
431
544
 
@@ -511,44 +624,3 @@ class JobBuilder:
511
624
 
512
625
  def _has_image_job_ingredients(self, metadata: Dict[str, Any]) -> bool:
513
626
  return metadata.get("docker") is not None
514
-
515
-
516
- def convert_use_artifact_to_job_source(
517
- use_artifact: "UseArtifactRecord",
518
- ) -> PartialJobSourceDict:
519
- source_info = use_artifact.partial.source_info
520
- source_info_dict: JobSourceDict = {
521
- "_version": "v0",
522
- "source_type": source_info.source_type,
523
- "runtime": source_info.runtime,
524
- }
525
- if source_info.source_type == "repo":
526
- entrypoint = [str(x) for x in source_info.source.git.entrypoint]
527
- git_source: GitSourceDict = {
528
- "git": {
529
- "remote": source_info.source.git.git_info.remote,
530
- "commit": source_info.source.git.git_info.commit,
531
- },
532
- "entrypoint": entrypoint,
533
- "notebook": source_info.source.git.notebook,
534
- }
535
- source_info_dict.update({"source": git_source})
536
- elif source_info.source_type == "artifact":
537
- entrypoint = [str(x) for x in source_info.source.artifact.entrypoint]
538
- artifact_source: ArtifactSourceDict = {
539
- "artifact": source_info.source.artifact.artifact,
540
- "entrypoint": entrypoint,
541
- "notebook": source_info.source.artifact.notebook,
542
- }
543
- source_info_dict.update({"source": artifact_source})
544
- elif source_info.source_type == "image":
545
- image_source: ImageSourceDict = {
546
- "image": source_info.source.image.image,
547
- }
548
- source_info_dict.update({"source": image_source})
549
-
550
- partal_job_source_dict: PartialJobSourceDict = {
551
- "job_name": use_artifact.partial.job_name.split(":")[0],
552
- "job_source_info": source_info_dict,
553
- }
554
- return partal_job_source_dict
@@ -81,31 +81,3 @@ class Progress:
81
81
  return self.len
82
82
 
83
83
  next = __next__
84
-
85
-
86
- class AsyncProgress:
87
- """Wrapper around Progress, to make it async iterable.
88
-
89
- httpx, for streaming uploads, requires the data source to be an async iterable.
90
- If we pass in a sync iterable (like a bare `Progress` instance), httpx will
91
- get confused, think we're trying to make a synchronous request, and raise.
92
- So we need this wrapper class to be an async iterable but *not* a sync iterable.
93
- """
94
-
95
- def __init__(self, progress: Progress) -> None:
96
- self._progress = progress
97
-
98
- def __aiter__(self):
99
- return self
100
-
101
- async def __anext__(self):
102
- try:
103
- return next(self._progress)
104
- except StopIteration:
105
- raise StopAsyncIteration
106
-
107
- def __len__(self):
108
- return len(self._progress)
109
-
110
- def rewind(self) -> None:
111
- self._progress.rewind()