wandb 0.17.6__py3-none-macosx_11_0_arm64.whl → 0.17.7__py3-none-macosx_11_0_arm64.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. wandb/__init__.py +3 -16
  2. wandb/agents/pyagent.py +1 -2
  3. wandb/bin/apple_gpu_stats +0 -0
  4. wandb/bin/wandb-core +0 -0
  5. wandb/cli/cli.py +21 -0
  6. wandb/data_types.py +3 -3
  7. wandb/integration/kfp/wandb_logging.py +1 -1
  8. wandb/integration/lightning/fabric/logger.py +1 -1
  9. wandb/integration/openai/fine_tuning.py +13 -5
  10. wandb/integration/ultralytics/pose_utils.py +0 -1
  11. wandb/sdk/artifacts/artifact.py +1 -1
  12. wandb/sdk/data_types/_dtypes.py +5 -5
  13. wandb/sdk/data_types/base_types/media.py +3 -1
  14. wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +3 -1
  15. wandb/sdk/data_types/helper_types/image_mask.py +3 -1
  16. wandb/sdk/data_types/image.py +3 -1
  17. wandb/sdk/data_types/saved_model.py +3 -1
  18. wandb/sdk/interface/interface.py +17 -16
  19. wandb/sdk/interface/interface_shared.py +6 -9
  20. wandb/sdk/internal/datastore.py +1 -1
  21. wandb/sdk/internal/handler.py +0 -2
  22. wandb/sdk/internal/internal.py +1 -1
  23. wandb/sdk/internal/job_builder.py +5 -2
  24. wandb/sdk/internal/tb_watcher.py +2 -2
  25. wandb/sdk/internal/update.py +2 -2
  26. wandb/sdk/launch/builder/kaniko_builder.py +13 -5
  27. wandb/sdk/launch/create_job.py +2 -0
  28. wandb/sdk/lib/apikey.py +1 -1
  29. wandb/sdk/service/streams.py +2 -4
  30. wandb/sdk/wandb_config.py +1 -1
  31. wandb/sdk/wandb_init.py +55 -7
  32. wandb/sdk/wandb_run.py +109 -68
  33. wandb/sdk/wandb_settings.py +1 -1
  34. wandb/sdk/wandb_setup.py +66 -3
  35. wandb/sdk/wandb_sweep.py +5 -2
  36. {wandb-0.17.6.dist-info → wandb-0.17.7.dist-info}/METADATA +1 -1
  37. {wandb-0.17.6.dist-info → wandb-0.17.7.dist-info}/RECORD +40 -40
  38. {wandb-0.17.6.dist-info → wandb-0.17.7.dist-info}/WHEEL +0 -0
  39. {wandb-0.17.6.dist-info → wandb-0.17.7.dist-info}/entry_points.txt +0 -0
  40. {wandb-0.17.6.dist-info → wandb-0.17.7.dist-info}/licenses/LICENSE +0 -0
wandb/__init__.py CHANGED
@@ -1,9 +1,6 @@
1
1
  """Use wandb to track machine learning work.
2
2
 
3
- The most commonly used functions/objects are:
4
- - wandb.init — initialize a new run at the top of your training script
5
- - wandb.config — track hyperparameters and metadata
6
- - wandb.log — log metrics and media over time within your training loop
3
+ Train and fine-tune models, manage models from experimentation to production.
7
4
 
8
5
  For guides and examples, see https://docs.wandb.ai.
9
6
 
@@ -11,11 +8,7 @@ For scripts and interactive notebooks, see https://github.com/wandb/examples.
11
8
 
12
9
  For reference documentation, see https://docs.wandb.com/ref/python.
13
10
  """
14
- __version__ = "0.17.6"
15
-
16
-
17
- # Used with pypi checks and other messages related to pip
18
- _wandb_module = "wandb"
11
+ __version__ = "0.17.7"
19
12
 
20
13
  from typing import Optional
21
14
 
@@ -118,13 +111,6 @@ def _assert_is_user_process():
118
111
  assert not _IS_INTERNAL_PROCESS
119
112
 
120
113
 
121
- # toplevel:
122
- # save()
123
- # restore()
124
- # login()
125
- # sweep()
126
- # agent()
127
-
128
114
  # globals
129
115
  Api = PublicApi
130
116
  api = InternalApi()
@@ -254,4 +240,5 @@ __all__ = (
254
240
  "log_model",
255
241
  "use_model",
256
242
  "link_model",
243
+ "define_metric",
257
244
  )
wandb/agents/pyagent.py CHANGED
@@ -14,7 +14,6 @@ import time
14
14
  import traceback
15
15
 
16
16
  import wandb
17
- from wandb import wandb_sdk
18
17
  from wandb.apis import InternalApi
19
18
  from wandb.sdk.launch.sweeps import utils as sweep_utils
20
19
 
@@ -298,7 +297,7 @@ class Agent:
298
297
  sweep_param_path, job.config
299
298
  )
300
299
  os.environ[wandb.env.SWEEP_ID] = self._sweep_id
301
- wandb_sdk.wandb_setup._setup(_reset=True)
300
+ wandb.sdk.wandb_setup._setup(_reset=True)
302
301
 
303
302
  wandb.termlog(f"Agent Starting Run: {run_id} with config:")
304
303
  for k, v in job.config.items():
wandb/bin/apple_gpu_stats CHANGED
Binary file
wandb/bin/wandb-core CHANGED
Binary file
wandb/cli/cli.py CHANGED
@@ -1417,6 +1417,13 @@ def launch_sweep(
1417
1417
  help="""Specific docker image you'd like to use. In the form name:tag.
1418
1418
  If passed in, will override the docker image value passed in using a config file.""",
1419
1419
  )
1420
+ @click.option(
1421
+ "--base-image",
1422
+ "-B",
1423
+ default=None,
1424
+ metavar="BASE IMAGE",
1425
+ help="""Docker image to run job code in. Incompatible with --docker-image.""",
1426
+ )
1420
1427
  @click.option(
1421
1428
  "--config",
1422
1429
  "-c",
@@ -1508,6 +1515,7 @@ def launch(
1508
1515
  entity,
1509
1516
  project,
1510
1517
  docker_image,
1518
+ base_image,
1511
1519
  config,
1512
1520
  cli_template_vars,
1513
1521
  queue,
@@ -1604,6 +1612,7 @@ def launch(
1604
1612
  git_hash=git_version,
1605
1613
  name=job_name,
1606
1614
  project=project,
1615
+ base_image=base_image,
1607
1616
  build_context=build_context,
1608
1617
  dockerfile=dockerfile,
1609
1618
  entity=entity,
@@ -2001,6 +2010,12 @@ def describe(job):
2001
2010
  help="Path to the build context from the root of the job source code. If "
2002
2011
  "provided, this is used as the base path for the Dockerfile and entrypoint.",
2003
2012
  )
2013
+ @click.option(
2014
+ "--base-image",
2015
+ "-B",
2016
+ type=str,
2017
+ help="Base image to use for the job. Incompatible with image jobs.",
2018
+ )
2004
2019
  @click.option(
2005
2020
  "--dockerfile",
2006
2021
  "-D",
@@ -2025,6 +2040,7 @@ def create(
2025
2040
  git_hash,
2026
2041
  runtime,
2027
2042
  build_context,
2043
+ base_image,
2028
2044
  dockerfile,
2029
2045
  ):
2030
2046
  """Create a job from a source, without a wandb run.
@@ -2056,6 +2072,10 @@ def create(
2056
2072
  )
2057
2073
  entrypoint = "main.py"
2058
2074
 
2075
+ if job_type == "image" and base_image:
2076
+ wandb.termerror("Cannot provide --base-image/-B for an `image` job")
2077
+ return
2078
+
2059
2079
  artifact, action, aliases = _create_job(
2060
2080
  api=api,
2061
2081
  path=path,
@@ -2069,6 +2089,7 @@ def create(
2069
2089
  git_hash=git_hash,
2070
2090
  runtime=runtime,
2071
2091
  build_context=build_context,
2092
+ base_image=base_image,
2072
2093
  dockerfile=dockerfile,
2073
2094
  )
2074
2095
  if not artifact:
wandb/data_types.py CHANGED
@@ -104,7 +104,7 @@ class _TableIndex(int, _TableLinkMixin):
104
104
  def _json_helper(val, artifact):
105
105
  if isinstance(val, WBValue):
106
106
  return val.to_json(artifact)
107
- elif val.__class__ == dict:
107
+ elif val.__class__ is dict:
108
108
  res = {}
109
109
  for key in val:
110
110
  res[key] = _json_helper(val[key], artifact)
@@ -270,10 +270,10 @@ class Table(Media):
270
270
  if dtype is None:
271
271
  dtype = _dtypes.UnknownType()
272
272
 
273
- if optional.__class__ != list:
273
+ if optional.__class__ is not list:
274
274
  optional = [optional for _ in range(len(self.columns))]
275
275
 
276
- if dtype.__class__ != list:
276
+ if dtype.__class__ is not list:
277
277
  dtype = [dtype for _ in range(len(self.columns))]
278
278
 
279
279
  self._column_types = _dtypes.TypedDictType({})
@@ -30,7 +30,7 @@ def wandb_log( # noqa: C901
30
30
  def isinstance_namedtuple(x):
31
31
  t = type(x)
32
32
  b = t.__bases__
33
- if len(b) != 1 or b[0] != tuple:
33
+ if len(b) != 1 or b[0] is not tuple:
34
34
  return False
35
35
  f = getattr(t, "_fields", None)
36
36
  if not isinstance(f, tuple):
@@ -312,7 +312,7 @@ class WandbLogger(Logger):
312
312
  self._prefix = prefix
313
313
  self._experiment = experiment
314
314
  self._logged_model_time: Dict[str, float] = {}
315
- self._checkpoint_callback: Optional["ModelCheckpoint"] = None
315
+ self._checkpoint_callback: Optional[ModelCheckpoint] = None
316
316
 
317
317
  # paths are processed as strings
318
318
  if save_dir is not None:
@@ -1,3 +1,4 @@
1
+ import base64
1
2
  import datetime
2
3
  import io
3
4
  import json
@@ -16,13 +17,13 @@ from wandb.util import parse_version
16
17
 
17
18
  openai = util.get_module(
18
19
  name="openai",
19
- required="`openai` not installed. This integration requires `openai`. To fix, please `pip install openai`",
20
- lazy="False",
20
+ required="This integration requires `openai`. To install, please run `pip install openai`",
21
+ lazy=False,
21
22
  )
22
23
 
23
- if parse_version(openai.__version__) < parse_version("1.0.1"):
24
+ if parse_version(openai.__version__) < parse_version("1.12.0"):
24
25
  raise wandb.Error(
25
- f"This integration requires openai version 1.0.1 and above. Your current version is {openai.__version__} "
26
+ f"This integration requires openai version 1.12.0 and above. Your current version is {openai.__version__} "
26
27
  "To fix, please `pip install -U openai`"
27
28
  )
28
29
 
@@ -228,7 +229,14 @@ class WandbLogger:
228
229
  # check results are present
229
230
  try:
230
231
  results_id = fine_tune.result_files[0]
231
- results = cls.openai_client.files.content(file_id=results_id).text
232
+ try:
233
+ encoded_results = cls.openai_client.files.content(
234
+ file_id=results_id
235
+ ).read()
236
+ results = base64.b64decode(encoded_results).decode("utf-8")
237
+ except Exception:
238
+ # attempt to read as text, works for older jobs
239
+ results = cls.openai_client.files.content(file_id=results_id).text
232
240
  except openai.NotFoundError:
233
241
  if show_individual_warnings:
234
242
  wandb.termwarn(
@@ -23,7 +23,6 @@ def annotate_keypoint_results(result: Results, visualize_skeleton: bool):
23
23
 
24
24
 
25
25
  def annotate_keypoint_batch(image_path: str, keypoints: Any, visualize_skeleton: bool):
26
- original_image = None
27
26
  with Image.open(image_path) as original_image:
28
27
  original_image = np.ascontiguousarray(original_image)
29
28
  annotator = Annotator(original_image)
@@ -751,7 +751,7 @@ class Artifact:
751
751
  def save(
752
752
  self,
753
753
  project: Optional[str] = None,
754
- settings: Optional["wandb.wandb_sdk.wandb_settings.Settings"] = None,
754
+ settings: Optional["wandb.sdk.wandb_settings.Settings"] = None,
755
755
  ) -> None:
756
756
  """Persist any changes made to the artifact.
757
757
 
@@ -56,7 +56,7 @@ class TypeRegistry:
56
56
  # but will be ultimately treated as a None. Ignoring type since
57
57
  # mypy does not trust that py_obj is a float by the time it is
58
58
  # passed to isnan.
59
- if py_obj.__class__ == float and math.isnan(py_obj): # type: ignore
59
+ if py_obj.__class__ is float and math.isnan(py_obj): # type: ignore
60
60
  return NoneType()
61
61
 
62
62
  # TODO: generalize this to handle other config input types
@@ -134,7 +134,7 @@ def _params_obj_to_json_obj(
134
134
  artifact: t.Optional["Artifact"] = None,
135
135
  ) -> t.Any:
136
136
  """Helper method."""
137
- if params_obj.__class__ == dict:
137
+ if params_obj.__class__ is dict:
138
138
  return {
139
139
  key: _params_obj_to_json_obj(params_obj[key], artifact)
140
140
  for key in params_obj
@@ -151,7 +151,7 @@ def _json_obj_to_params_obj(
151
151
  json_obj: t.Any, artifact: t.Optional["Artifact"] = None
152
152
  ) -> t.Any:
153
153
  """Helper method."""
154
- if json_obj.__class__ == dict:
154
+ if json_obj.__class__ is dict:
155
155
  if "wb_type" in json_obj:
156
156
  return TypeRegistry.type_from_dict(json_obj, artifact)
157
157
  else:
@@ -159,7 +159,7 @@ def _json_obj_to_params_obj(
159
159
  key: _json_obj_to_params_obj(json_obj[key], artifact)
160
160
  for key in json_obj
161
161
  }
162
- elif json_obj.__class__ == list:
162
+ elif json_obj.__class__ is list:
163
163
  return [_json_obj_to_params_obj(item, artifact) for item in json_obj]
164
164
  else:
165
165
  return json_obj
@@ -533,7 +533,7 @@ class UnionType(Type):
533
533
  self,
534
534
  allowed_types: t.Optional[t.Sequence[ConvertibleToType]] = None,
535
535
  ):
536
- assert allowed_types is None or (allowed_types.__class__ == list)
536
+ assert allowed_types is None or (allowed_types.__class__ is list)
537
537
  if allowed_types is None:
538
538
  wb_types = []
539
539
  else:
@@ -159,9 +159,11 @@ class Media(WBValue):
159
159
  # into Media itself we should get rid of them
160
160
  from wandb import Image
161
161
  from wandb.data_types import Audio
162
+ from wandb.sdk.wandb_run import Run
162
163
 
163
164
  json_obj = {}
164
- if isinstance(run, wandb.wandb_sdk.wandb_run.Run):
165
+
166
+ if isinstance(run, Run):
165
167
  json_obj.update(
166
168
  {
167
169
  "_type": "file", # TODO(adrian): This isn't (yet) a real media type we support on the frontend.
@@ -276,7 +276,9 @@ class BoundingBoxes2D(JSONMetadata):
276
276
  return True
277
277
 
278
278
  def to_json(self, run_or_artifact: Union["LocalRun", "Artifact"]) -> dict:
279
- if isinstance(run_or_artifact, wandb.wandb_sdk.wandb_run.Run):
279
+ from wandb.sdk.wandb_run import Run
280
+
281
+ if isinstance(run_or_artifact, Run):
280
282
  return super().to_json(run_or_artifact)
281
283
  elif isinstance(run_or_artifact, wandb.Artifact):
282
284
  # TODO (tim): I would like to log out a proper dictionary representing this object, but don't
@@ -191,9 +191,11 @@ class ImageMask(Media):
191
191
  )
192
192
 
193
193
  def to_json(self, run_or_artifact: Union["LocalRun", "Artifact"]) -> dict:
194
+ from wandb.sdk.wandb_run import Run
195
+
194
196
  json_dict = super().to_json(run_or_artifact)
195
197
 
196
- if isinstance(run_or_artifact, wandb.wandb_sdk.wandb_run.Run):
198
+ if isinstance(run_or_artifact, Run):
197
199
  json_dict["_type"] = self.type_name()
198
200
  return json_dict
199
201
  elif isinstance(run_or_artifact, wandb.Artifact):
@@ -418,6 +418,8 @@ class Image(BatchableMedia):
418
418
  )
419
419
 
420
420
  def to_json(self, run_or_artifact: Union["LocalRun", "Artifact"]) -> dict:
421
+ from wandb.sdk.wandb_run import Run
422
+
421
423
  json_dict = super().to_json(run_or_artifact)
422
424
  json_dict["_type"] = Image._log_type
423
425
  json_dict["format"] = self.format
@@ -456,7 +458,7 @@ class Image(BatchableMedia):
456
458
  "digest": classes_entry.digest,
457
459
  }
458
460
 
459
- elif not isinstance(run_or_artifact, wandb.wandb_sdk.wandb_run.Run):
461
+ elif not isinstance(run_or_artifact, Run):
460
462
  raise ValueError("to_json accepts wandb_run.Run or wandb_artifact.Artifact")
461
463
 
462
464
  if self._boxes:
@@ -148,7 +148,9 @@ class _SavedModel(WBValue, Generic[SavedModelObjType]):
148
148
  # bit of tech debt in the other data types which requires the input to `to_json`
149
149
  # to accept a Run or Artifact. However, Run additions should be deprecated in the future.
150
150
  # This check helps ensure we do not add to the debt.
151
- if isinstance(run_or_artifact, wandb.wandb_sdk.wandb_run.Run):
151
+ from wandb.sdk.wandb_run import Run
152
+
153
+ if isinstance(run_or_artifact, Run):
152
154
  raise ValueError("SavedModel cannot be added to run - must use artifact")
153
155
  artifact = run_or_artifact
154
156
  json_obj = {
@@ -54,18 +54,20 @@ MANIFEST_FILE_SIZE_THRESHOLD = 100_000
54
54
 
55
55
  GlobStr = NewType("GlobStr", str)
56
56
 
57
- if TYPE_CHECKING:
58
- from ..wandb_run import Run
57
+ if sys.version_info >= (3, 8):
58
+ from typing import Literal, TypedDict
59
+ else:
60
+ from typing_extensions import Literal, TypedDict
61
+
62
+ PolicyName = Literal["now", "live", "end"]
59
63
 
60
- if sys.version_info >= (3, 8):
61
- from typing import Literal, TypedDict
62
- else:
63
- from typing_extensions import Literal, TypedDict
64
64
 
65
- PolicyName = Literal["now", "live", "end"]
65
+ class FilesDict(TypedDict):
66
+ files: Iterable[Tuple[GlobStr, PolicyName]]
66
67
 
67
- class FilesDict(TypedDict):
68
- files: Iterable[Tuple[GlobStr, PolicyName]]
68
+
69
+ if TYPE_CHECKING:
70
+ from ..wandb_run import Run
69
71
 
70
72
 
71
73
  logger = logging.getLogger("wandb")
@@ -112,15 +114,14 @@ class InterfaceBase:
112
114
  def _publish_header(self, header: pb.HeaderRecord) -> None:
113
115
  raise NotImplementedError
114
116
 
115
- def communicate_status(self) -> Optional[pb.StatusResponse]:
116
- status = pb.StatusRequest()
117
- resp = self._communicate_status(status)
118
- return resp
117
+ def deliver_status(self) -> MailboxHandle:
118
+ return self._deliver_status(pb.StatusRequest())
119
119
 
120
120
  @abstractmethod
121
- def _communicate_status(
122
- self, status: pb.StatusRequest
123
- ) -> Optional[pb.StatusResponse]:
121
+ def _deliver_status(
122
+ self,
123
+ status: pb.StatusRequest,
124
+ ) -> MailboxHandle:
124
125
  raise NotImplementedError
125
126
 
126
127
  def _make_config(
@@ -299,7 +299,7 @@ class InterfaceShared(InterfaceBase):
299
299
  raise NotImplementedError
300
300
 
301
301
  def _communicate(
302
- self, rec: pb.Record, timeout: Optional[int] = 5, local: Optional[bool] = None
302
+ self, rec: pb.Record, timeout: Optional[int] = 30, local: Optional[bool] = None
303
303
  ) -> Optional[pb.Result]:
304
304
  return self._communicate_async(rec, local=local).get(timeout=timeout)
305
305
 
@@ -421,15 +421,12 @@ class InterfaceShared(InterfaceBase):
421
421
  rec = self._make_record(alert=proto_alert)
422
422
  self._publish(rec)
423
423
 
424
- def _communicate_status(
425
- self, status: pb.StatusRequest
426
- ) -> Optional[pb.StatusResponse]:
424
+ def _deliver_status(
425
+ self,
426
+ status: pb.StatusRequest,
427
+ ) -> MailboxHandle:
427
428
  req = self._make_request(status=status)
428
- resp = self._communicate(req, local=True)
429
- if resp is None:
430
- return None
431
- assert resp.response.status_response
432
- return resp.response.status_response
429
+ return self._deliver_record(req)
433
430
 
434
431
  def _publish_exit(self, exit_data: pb.RunExitRecord) -> None:
435
432
  rec = self._make_record(exit=exit_data)
@@ -69,7 +69,7 @@ class DataStore:
69
69
 
70
70
  def __init__(self) -> None:
71
71
  self._opened_for_scan = False
72
- self._fp: Optional["IO[Any]"] = None
72
+ self._fp: Optional[IO[Any]] = None
73
73
  self._index = 0
74
74
  self._flush_offset = 0
75
75
  self._size_bytes = 0
@@ -745,8 +745,6 @@ class HandleManager:
745
745
  self._respond_result(result)
746
746
 
747
747
  def handle_request_status(self, record: Record) -> None:
748
- # TODO(mempressure): do something better?
749
- assert record.control.req_resp
750
748
  result = proto_util._result_from_record(record)
751
749
  self._respond_result(result)
752
750
 
@@ -62,7 +62,7 @@ def wandb_internal(
62
62
 
63
63
  """
64
64
  # mark this process as internal
65
- wandb._set_internal_process()
65
+ wandb._set_internal_process() # type: ignore
66
66
  _setup_tracelog()
67
67
  started = time.time()
68
68
 
@@ -423,15 +423,18 @@ class JobBuilder:
423
423
  api: Api,
424
424
  build_context: Optional[str] = None,
425
425
  dockerfile: Optional[str] = None,
426
+ base_image: Optional[str] = None,
426
427
  ) -> Optional[Artifact]:
427
428
  """Build a job artifact from the current run.
428
429
 
429
430
  Arguments:
431
+ api (Api): The API object to use to create the job artifact.
430
432
  build_context (Optional[str]): Path within the job source code to
431
433
  the image build context. Saved as part of the job for future
432
434
  builds.
433
435
  dockerfile (Optional[str]): Path within the build context the
434
436
  Dockerfile. Saved as part of the job for future builds.
437
+ base_image (Optional[str]): The base image used to run the job code.
435
438
 
436
439
  Returns:
437
440
  Optional[Artifact]: The job artifact if it was successfully built,
@@ -467,8 +470,6 @@ class JobBuilder:
467
470
  "warn",
468
471
  )
469
472
  return None
470
- metadata["dockerfile"] = dockerfile
471
- metadata["build_context"] = build_context
472
473
 
473
474
  runtime: Optional[str] = metadata.get("python")
474
475
  # can't build a job without a python version
@@ -520,6 +521,8 @@ class JobBuilder:
520
521
  source["build_context"] = build_context # type: ignore[typeddict-item]
521
522
  if dockerfile:
522
523
  source["dockerfile"] = dockerfile # type: ignore[typeddict-item]
524
+ if base_image:
525
+ source["base_image"] = base_image # type: ignore[typeddict-item]
523
526
 
524
527
  # Pop any keys that are initialized to None. The current TypedDict
525
528
  # system for source dicts requires all keys to be present, but we
@@ -123,7 +123,7 @@ class TBWatcher:
123
123
  self._force = force
124
124
  # TODO(jhr): do we need locking in this queue?
125
125
  self._watcher_queue = queue.PriorityQueue()
126
- wandb.tensorboard.reset_state()
126
+ wandb.tensorboard.reset_state() # type: ignore
127
127
 
128
128
  def _calculate_namespace(self, logdir: str, rootdir: str) -> Optional[str]:
129
129
  namespace: Optional[str]
@@ -430,7 +430,7 @@ class TBEventConsumer:
430
430
  def _handle_event(
431
431
  self, event: "ProtoEvent", history: Optional["TBHistory"] = None
432
432
  ) -> None:
433
- wandb.tensorboard._log(
433
+ wandb.tensorboard._log( # type: ignore
434
434
  event.event,
435
435
  step=event.event.step,
436
436
  namespace=event.namespace,
@@ -10,7 +10,7 @@ def _find_available(
10
10
  ) -> Optional[Tuple[str, bool, bool, bool, Optional[str]]]:
11
11
  from wandb.util import parse_version
12
12
 
13
- pypi_url = f"https://pypi.org/pypi/{wandb._wandb_module}/json"
13
+ pypi_url = "https://pypi.org/pypi/wandb/json"
14
14
 
15
15
  yanked_dict = {}
16
16
  try:
@@ -78,7 +78,7 @@ def check_available(current_version: str) -> Optional[Dict[str, Optional[str]]]:
78
78
  if not package_info:
79
79
  return None
80
80
 
81
- wandb_module_name = wandb._wandb_module
81
+ wandb_module_name = "wandb"
82
82
 
83
83
  latest_version, pip_prerelease, deleted, yanked, yanked_reason = package_info
84
84
  upgrade_message = (
@@ -63,6 +63,13 @@ else:
63
63
  NAMESPACE = "wandb"
64
64
 
65
65
 
66
+ def get_pod_name_safe(job: client.V1Job):
67
+ try:
68
+ return job.spec.template.metadata.name
69
+ except AttributeError:
70
+ return None
71
+
72
+
66
73
  async def _wait_for_completion(
67
74
  batch_client: client.BatchV1Api, job_name: str, deadline_secs: Optional[int] = None
68
75
  ) -> bool:
@@ -319,17 +326,18 @@ class KanikoBuilder(AbstractBuilder):
319
326
  await self._create_docker_ecr_config_map(
320
327
  build_job_name, core_v1, repo_uri
321
328
  )
322
- await batch_v1.create_namespaced_job(NAMESPACE, build_job)
323
-
329
+ k8s_job = await batch_v1.create_namespaced_job(NAMESPACE, build_job)
324
330
  # wait for double the job deadline since it might take time to schedule
325
331
  if not await _wait_for_completion(
326
332
  batch_v1, build_job_name, 3 * _DEFAULT_BUILD_TIMEOUT_SECS
327
333
  ):
328
334
  if job_tracker:
329
335
  job_tracker.set_err_stage("build")
330
- raise Exception(
331
- f"Failed to build image in kaniko for job {run_id}. View logs with `kubectl logs -n {NAMESPACE} {build_job_name}`."
332
- )
336
+ msg = f"Failed to build image in kaniko for job {run_id}."
337
+ pod_name = get_pod_name_safe(k8s_job)
338
+ if pod_name:
339
+ msg += f" View logs with `kubectl logs -n {NAMESPACE} {pod_name}`."
340
+ raise Exception(msg)
333
341
  try:
334
342
  pods_from_job = await core_v1.list_namespaced_pod(
335
343
  namespace=NAMESPACE, label_selector=f"job-name={build_job_name}"
@@ -114,6 +114,7 @@ def _create_job(
114
114
  git_hash: Optional[str] = None,
115
115
  build_context: Optional[str] = None,
116
116
  dockerfile: Optional[str] = None,
117
+ base_image: Optional[str] = None,
117
118
  ) -> Tuple[Optional[Artifact], str, List[str]]:
118
119
  wandb.termlog(f"Creating launch job of type: {job_type}...")
119
120
 
@@ -188,6 +189,7 @@ def _create_job(
188
189
  api.api,
189
190
  dockerfile=dockerfile,
190
191
  build_context=build_context,
192
+ base_image=base_image,
191
193
  )
192
194
  if not artifact:
193
195
  wandb.termerror("JobBuilder failed to build a job")
wandb/sdk/lib/apikey.py CHANGED
@@ -107,7 +107,7 @@ def prompt_api_key( # noqa: C901
107
107
 
108
108
  if jupyter and "google.colab" in sys.modules:
109
109
  log_string = term.LOG_STRING_NOCOLOR
110
- key = wandb.jupyter.attempt_colab_login(app_url)
110
+ key = wandb.jupyter.attempt_colab_login(app_url) # type: ignore
111
111
  if key is not None:
112
112
  write_key(settings, key, api=api)
113
113
  return key # type: ignore
@@ -81,9 +81,7 @@ class StreamRecord:
81
81
  self._wait_thread_active()
82
82
 
83
83
  def _wait_thread_active(self) -> None:
84
- result = self._iface.communicate_status()
85
- # TODO: using the default communicate timeout, is that enough? retries?
86
- assert result
84
+ self._iface.deliver_status().wait(timeout=-1)
87
85
 
88
86
  def join(self) -> None:
89
87
  self._iface.join()
@@ -212,7 +210,7 @@ class StreamMux:
212
210
  # run_id = action.stream_id # will want to fix if a streamid != runid
213
211
  settings = action._data
214
212
  thread = StreamThread(
215
- target=wandb.wandb_sdk.internal.internal.wandb_internal,
213
+ target=wandb.wandb_sdk.internal.internal.wandb_internal, # type: ignore
216
214
  kwargs=dict(
217
215
  settings=settings,
218
216
  record_q=stream._record_q,
wandb/sdk/wandb_config.py CHANGED
@@ -61,7 +61,7 @@ class Config:
61
61
 
62
62
  Using absl flags
63
63
  ```
64
- flags.DEFINE_string(model’, None, model to run) # name, default, help
64
+ flags.DEFINE_string("model", None, "model to run") # name, default, help
65
65
  wandb.config.update(flags.FLAGS) # adds all absl flags to config
66
66
  ```
67
67