wandb 0.17.0rc1__py3-none-any.whl → 0.17.1__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- wandb/__init__.py +1 -2
- wandb/apis/importers/internals/internal.py +0 -1
- wandb/apis/importers/wandb.py +12 -7
- wandb/apis/internal.py +0 -3
- wandb/apis/public/api.py +213 -79
- wandb/apis/public/artifacts.py +335 -100
- wandb/apis/public/files.py +9 -9
- wandb/apis/public/jobs.py +16 -4
- wandb/apis/public/projects.py +26 -28
- wandb/apis/public/query_generator.py +1 -1
- wandb/apis/public/runs.py +163 -65
- wandb/apis/public/sweeps.py +2 -2
- wandb/apis/reports/__init__.py +1 -7
- wandb/apis/reports/v1/__init__.py +5 -27
- wandb/apis/reports/v2/__init__.py +7 -19
- wandb/apis/workspaces/__init__.py +8 -0
- wandb/beta/workflows.py +8 -3
- wandb/cli/cli.py +131 -59
- wandb/data_types.py +6 -3
- wandb/docker/__init__.py +2 -2
- wandb/env.py +3 -3
- wandb/errors/term.py +10 -2
- wandb/filesync/step_checksum.py +1 -4
- wandb/filesync/step_prepare.py +4 -24
- wandb/filesync/step_upload.py +5 -107
- wandb/filesync/upload_job.py +0 -76
- wandb/integration/gym/__init__.py +35 -15
- wandb/integration/huggingface/resolver.py +2 -2
- wandb/integration/keras/callbacks/metrics_logger.py +1 -1
- wandb/integration/keras/keras.py +1 -1
- wandb/integration/openai/fine_tuning.py +21 -3
- wandb/integration/prodigy/prodigy.py +1 -1
- wandb/jupyter.py +16 -17
- wandb/old/summary.py +1 -1
- wandb/plot/confusion_matrix.py +1 -1
- wandb/plot/pr_curve.py +2 -1
- wandb/plot/roc_curve.py +2 -1
- wandb/{plots → plot}/utils.py +13 -25
- wandb/proto/v3/wandb_internal_pb2.py +54 -54
- wandb/proto/v3/wandb_settings_pb2.py +2 -2
- wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v4/wandb_internal_pb2.py +54 -54
- wandb/proto/v4/wandb_settings_pb2.py +2 -2
- wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v5/wandb_base_pb2.py +30 -0
- wandb/proto/v5/wandb_internal_pb2.py +355 -0
- wandb/proto/v5/wandb_server_pb2.py +63 -0
- wandb/proto/v5/wandb_settings_pb2.py +45 -0
- wandb/proto/v5/wandb_telemetry_pb2.py +41 -0
- wandb/proto/wandb_base_pb2.py +2 -0
- wandb/proto/wandb_deprecated.py +9 -1
- wandb/proto/wandb_generate_deprecated.py +34 -0
- wandb/proto/{wandb_internal_codegen.py → wandb_generate_proto.py} +1 -35
- wandb/proto/wandb_internal_pb2.py +2 -0
- wandb/proto/wandb_server_pb2.py +2 -0
- wandb/proto/wandb_settings_pb2.py +2 -0
- wandb/proto/wandb_telemetry_pb2.py +2 -0
- wandb/sdk/artifacts/artifact.py +68 -22
- wandb/sdk/artifacts/artifact_manifest.py +1 -1
- wandb/sdk/artifacts/artifact_manifest_entry.py +6 -3
- wandb/sdk/artifacts/artifact_manifests/artifact_manifest_v1.py +1 -1
- wandb/sdk/artifacts/artifact_saver.py +1 -10
- wandb/sdk/artifacts/storage_handlers/local_file_handler.py +6 -2
- wandb/sdk/artifacts/storage_handlers/multi_handler.py +1 -1
- wandb/sdk/artifacts/storage_handlers/tracking_handler.py +6 -4
- wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +2 -42
- wandb/sdk/artifacts/storage_policy.py +1 -12
- wandb/sdk/data_types/_dtypes.py +8 -8
- wandb/sdk/data_types/image.py +2 -2
- wandb/sdk/data_types/video.py +5 -3
- wandb/sdk/integration_utils/data_logging.py +5 -5
- wandb/sdk/interface/interface.py +14 -1
- wandb/sdk/interface/interface_shared.py +1 -1
- wandb/sdk/internal/file_pusher.py +2 -5
- wandb/sdk/internal/file_stream.py +6 -19
- wandb/sdk/internal/internal_api.py +148 -136
- wandb/sdk/internal/job_builder.py +208 -136
- wandb/sdk/internal/progress.py +0 -28
- wandb/sdk/internal/sender.py +102 -39
- wandb/sdk/internal/settings_static.py +8 -1
- wandb/sdk/internal/system/assets/trainium.py +3 -3
- wandb/sdk/internal/system/system_info.py +4 -2
- wandb/sdk/internal/update.py +1 -1
- wandb/sdk/launch/__init__.py +9 -1
- wandb/sdk/launch/_launch.py +4 -24
- wandb/sdk/launch/_launch_add.py +1 -3
- wandb/sdk/launch/_project_spec.py +187 -225
- wandb/sdk/launch/agent/agent.py +59 -19
- wandb/sdk/launch/agent/config.py +0 -3
- wandb/sdk/launch/builder/abstract.py +68 -1
- wandb/sdk/launch/builder/build.py +165 -576
- wandb/sdk/launch/builder/context_manager.py +235 -0
- wandb/sdk/launch/builder/docker_builder.py +7 -23
- wandb/sdk/launch/builder/kaniko_builder.py +12 -25
- wandb/sdk/launch/builder/templates/dockerfile.py +92 -0
- wandb/sdk/launch/create_job.py +51 -45
- wandb/sdk/launch/environment/aws_environment.py +26 -1
- wandb/sdk/launch/inputs/files.py +148 -0
- wandb/sdk/launch/inputs/internal.py +224 -0
- wandb/sdk/launch/inputs/manage.py +95 -0
- wandb/sdk/launch/registry/google_artifact_registry.py +1 -1
- wandb/sdk/launch/runner/abstract.py +2 -2
- wandb/sdk/launch/runner/kubernetes_monitor.py +45 -12
- wandb/sdk/launch/runner/kubernetes_runner.py +6 -8
- wandb/sdk/launch/runner/local_container.py +2 -3
- wandb/sdk/launch/runner/local_process.py +8 -29
- wandb/sdk/launch/runner/sagemaker_runner.py +20 -14
- wandb/sdk/launch/runner/vertex_runner.py +8 -7
- wandb/sdk/launch/sweeps/scheduler.py +5 -3
- wandb/sdk/launch/sweeps/scheduler_sweep.py +1 -1
- wandb/sdk/launch/sweeps/utils.py +4 -4
- wandb/sdk/launch/utils.py +16 -138
- wandb/sdk/lib/_settings_toposort_generated.py +2 -5
- wandb/sdk/lib/apikey.py +4 -2
- wandb/sdk/lib/config_util.py +3 -3
- wandb/sdk/lib/import_hooks.py +1 -1
- wandb/sdk/lib/proto_util.py +22 -1
- wandb/sdk/lib/redirect.py +20 -15
- wandb/sdk/lib/tracelog.py +1 -1
- wandb/sdk/service/service.py +2 -1
- wandb/sdk/service/streams.py +5 -5
- wandb/sdk/wandb_init.py +25 -59
- wandb/sdk/wandb_login.py +28 -25
- wandb/sdk/wandb_run.py +123 -53
- wandb/sdk/wandb_settings.py +33 -64
- wandb/sdk/wandb_setup.py +1 -1
- wandb/sdk/wandb_watch.py +1 -1
- wandb/sklearn/plot/classifier.py +10 -12
- wandb/sklearn/plot/clusterer.py +1 -1
- wandb/sync/sync.py +2 -2
- wandb/testing/relay.py +32 -17
- wandb/util.py +36 -37
- wandb/wandb_agent.py +3 -3
- wandb/wandb_controller.py +5 -4
- {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/METADATA +8 -10
- {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/RECORD +139 -161
- {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/WHEEL +1 -1
- wandb/apis/reports/v1/_blocks.py +0 -1406
- wandb/apis/reports/v1/_helpers.py +0 -70
- wandb/apis/reports/v1/_panels.py +0 -1282
- wandb/apis/reports/v1/_templates.py +0 -478
- wandb/apis/reports/v1/blocks.py +0 -27
- wandb/apis/reports/v1/helpers.py +0 -2
- wandb/apis/reports/v1/mutations.py +0 -66
- wandb/apis/reports/v1/panels.py +0 -17
- wandb/apis/reports/v1/report.py +0 -268
- wandb/apis/reports/v1/runset.py +0 -144
- wandb/apis/reports/v1/templates.py +0 -7
- wandb/apis/reports/v1/util.py +0 -406
- wandb/apis/reports/v1/validators.py +0 -131
- wandb/apis/reports/v2/blocks.py +0 -25
- wandb/apis/reports/v2/expr_parsing.py +0 -257
- wandb/apis/reports/v2/gql.py +0 -68
- wandb/apis/reports/v2/interface.py +0 -1911
- wandb/apis/reports/v2/internal.py +0 -867
- wandb/apis/reports/v2/metrics.py +0 -6
- wandb/apis/reports/v2/panels.py +0 -15
- wandb/catboost/__init__.py +0 -9
- wandb/fastai/__init__.py +0 -9
- wandb/keras/__init__.py +0 -19
- wandb/lightgbm/__init__.py +0 -9
- wandb/plots/__init__.py +0 -6
- wandb/plots/explain_text.py +0 -36
- wandb/plots/heatmap.py +0 -81
- wandb/plots/named_entity.py +0 -43
- wandb/plots/part_of_speech.py +0 -50
- wandb/plots/plot_definitions.py +0 -768
- wandb/plots/precision_recall.py +0 -121
- wandb/plots/roc.py +0 -103
- wandb/sacred/__init__.py +0 -3
- wandb/xgboost/__init__.py +0 -9
- {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/entry_points.txt +0 -0
- {wandb-0.17.0rc1.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
|
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
|
-
|
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.
|
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
|
|
@@ -276,7 +341,7 @@ class JobBuilder:
|
|
276
341
|
return source, name
|
277
342
|
|
278
343
|
def _make_job_name(self, input_str: str) -> str:
|
279
|
-
"""Use job name from settings if provided, else use
|
344
|
+
"""Use job name from settings if provided, else use programmatic name."""
|
280
345
|
if self._settings.job_name:
|
281
346
|
return self._settings.job_name
|
282
347
|
|
@@ -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
|
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
|
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
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
#
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
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
|
381
|
-
"warn",
|
499
|
+
"No source type found, not creating job artifact", "warn"
|
382
500
|
)
|
383
|
-
|
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
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
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
|
wandb/sdk/internal/progress.py
CHANGED
@@ -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()
|