wandb 0.17.6__py3-none-any.whl → 0.17.8__py3-none-any.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.
- package_readme.md +47 -53
- wandb/__init__.py +10 -19
- wandb/__init__.pyi +964 -0
- wandb/agents/pyagent.py +1 -2
- wandb/bin/nvidia_gpu_stats +0 -0
- wandb/cli/cli.py +21 -0
- wandb/data_types.py +4 -3
- wandb/env.py +13 -0
- wandb/integration/keras/__init__.py +2 -5
- wandb/integration/keras/callbacks/metrics_logger.py +10 -4
- wandb/integration/keras/callbacks/model_checkpoint.py +0 -5
- wandb/integration/keras/keras.py +11 -0
- wandb/integration/kfp/wandb_logging.py +1 -1
- wandb/integration/lightning/fabric/logger.py +1 -1
- wandb/integration/openai/fine_tuning.py +13 -5
- wandb/integration/ultralytics/pose_utils.py +0 -1
- wandb/proto/v3/wandb_internal_pb2.py +24 -24
- wandb/proto/v3/wandb_settings_pb2.py +2 -2
- wandb/proto/v3/wandb_telemetry_pb2.py +12 -12
- wandb/proto/v4/wandb_internal_pb2.py +24 -24
- wandb/proto/v4/wandb_settings_pb2.py +2 -2
- wandb/proto/v4/wandb_telemetry_pb2.py +12 -12
- wandb/proto/v5/wandb_internal_pb2.py +24 -24
- wandb/proto/v5/wandb_settings_pb2.py +2 -2
- wandb/proto/v5/wandb_telemetry_pb2.py +12 -12
- wandb/proto/wandb_deprecated.py +2 -0
- wandb/sdk/artifacts/artifact.py +22 -26
- wandb/sdk/artifacts/artifact_manifest_entry.py +10 -2
- wandb/sdk/artifacts/storage_handlers/gcs_handler.py +31 -0
- wandb/sdk/data_types/_dtypes.py +5 -5
- wandb/sdk/data_types/base_types/media.py +3 -1
- wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +3 -1
- wandb/sdk/data_types/helper_types/image_mask.py +3 -1
- wandb/sdk/data_types/image.py +3 -1
- wandb/sdk/data_types/saved_model.py +3 -1
- wandb/sdk/data_types/video.py +2 -2
- wandb/sdk/interface/interface.py +17 -16
- wandb/sdk/interface/interface_shared.py +6 -9
- wandb/sdk/internal/datastore.py +1 -1
- wandb/sdk/internal/handler.py +5 -3
- wandb/sdk/internal/internal.py +1 -1
- wandb/sdk/internal/job_builder.py +5 -2
- wandb/sdk/internal/tb_watcher.py +2 -2
- wandb/sdk/internal/update.py +2 -2
- wandb/sdk/launch/builder/kaniko_builder.py +13 -5
- wandb/sdk/launch/create_job.py +2 -0
- wandb/sdk/lib/_settings_toposort_generated.py +1 -0
- wandb/sdk/lib/apikey.py +1 -1
- wandb/sdk/service/service.py +7 -2
- wandb/sdk/service/streams.py +2 -4
- wandb/sdk/wandb_config.py +4 -1
- wandb/sdk/wandb_init.py +59 -8
- wandb/sdk/wandb_manager.py +0 -3
- wandb/sdk/wandb_require.py +22 -1
- wandb/sdk/wandb_run.py +137 -92
- wandb/sdk/wandb_settings.py +26 -2
- wandb/sdk/wandb_setup.py +69 -3
- wandb/sdk/wandb_sweep.py +5 -2
- wandb/testing/relay.py +7 -1
- {wandb-0.17.6.dist-info → wandb-0.17.8.dist-info}/METADATA +48 -54
- {wandb-0.17.6.dist-info → wandb-0.17.8.dist-info}/RECORD +64 -63
- {wandb-0.17.6.dist-info → wandb-0.17.8.dist-info}/WHEEL +0 -0
- {wandb-0.17.6.dist-info → wandb-0.17.8.dist-info}/entry_points.txt +0 -0
- {wandb-0.17.6.dist-info → wandb-0.17.8.dist-info}/licenses/LICENSE +0 -0
    
        wandb/sdk/data_types/_dtypes.py
    CHANGED
    
    | @@ -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__  | 
| 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__  | 
| 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__  | 
| 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__  | 
| 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__  | 
| 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 | 
            -
             | 
| 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 | 
            -
                     | 
| 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,  | 
| 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):
         | 
    
        wandb/sdk/data_types/image.py
    CHANGED
    
    | @@ -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,  | 
| 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 | 
            -
                     | 
| 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 = {
         | 
    
        wandb/sdk/data_types/video.py
    CHANGED
    
    | @@ -214,9 +214,9 @@ class Video(BatchableMedia): | |
| 214 214 | 
             
                    n_rows = 2 ** ((b.bit_length() - 1) // 2)
         | 
| 215 215 | 
             
                    n_cols = video.shape[0] // n_rows
         | 
| 216 216 |  | 
| 217 | 
            -
                    video =  | 
| 217 | 
            +
                    video = video.reshape(n_rows, n_cols, t, c, h, w)
         | 
| 218 218 | 
             
                    video = np.transpose(video, axes=(2, 0, 4, 1, 5, 3))
         | 
| 219 | 
            -
                    video =  | 
| 219 | 
            +
                    video = video.reshape(t, n_rows * h, n_cols * w, c)
         | 
| 220 220 | 
             
                    return video
         | 
| 221 221 |  | 
| 222 222 | 
             
                @classmethod
         | 
    
        wandb/sdk/interface/interface.py
    CHANGED
    
    | @@ -54,18 +54,20 @@ MANIFEST_FILE_SIZE_THRESHOLD = 100_000 | |
| 54 54 |  | 
| 55 55 | 
             
            GlobStr = NewType("GlobStr", str)
         | 
| 56 56 |  | 
| 57 | 
            -
            if  | 
| 58 | 
            -
                from  | 
| 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 | 
            -
             | 
| 65 | 
            +
            class FilesDict(TypedDict):
         | 
| 66 | 
            +
                files: Iterable[Tuple[GlobStr, PolicyName]]
         | 
| 66 67 |  | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 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  | 
| 116 | 
            -
                     | 
| 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  | 
| 122 | 
            -
                    self, | 
| 123 | 
            -
             | 
| 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] =  | 
| 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  | 
| 425 | 
            -
                    self, | 
| 426 | 
            -
             | 
| 424 | 
            +
                def _deliver_status(
         | 
| 425 | 
            +
                    self,
         | 
| 426 | 
            +
                    status: pb.StatusRequest,
         | 
| 427 | 
            +
                ) -> MailboxHandle:
         | 
| 427 428 | 
             
                    req = self._make_request(status=status)
         | 
| 428 | 
            -
                     | 
| 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)
         | 
    
        wandb/sdk/internal/datastore.py
    CHANGED
    
    
    
        wandb/sdk/internal/handler.py
    CHANGED
    
    | @@ -660,7 +660,11 @@ class HandleManager: | |
| 660 660 | 
             
                    self._dispatch_record(record)
         | 
| 661 661 |  | 
| 662 662 | 
             
                def handle_request_check_version(self, record: Record) -> None:
         | 
| 663 | 
            -
                    self. | 
| 663 | 
            +
                    if self._settings._offline:
         | 
| 664 | 
            +
                        result = proto_util._result_from_record(record)
         | 
| 665 | 
            +
                        self._respond_result(result)
         | 
| 666 | 
            +
                    else:
         | 
| 667 | 
            +
                        self._dispatch_record(record)
         | 
| 664 668 |  | 
| 665 669 | 
             
                def handle_request_attach(self, record: Record) -> None:
         | 
| 666 670 | 
             
                    result = proto_util._result_from_record(record)
         | 
| @@ -745,8 +749,6 @@ class HandleManager: | |
| 745 749 | 
             
                    self._respond_result(result)
         | 
| 746 750 |  | 
| 747 751 | 
             
                def handle_request_status(self, record: Record) -> None:
         | 
| 748 | 
            -
                    # TODO(mempressure): do something better?
         | 
| 749 | 
            -
                    assert record.control.req_resp
         | 
| 750 752 | 
             
                    result = proto_util._result_from_record(record)
         | 
| 751 753 | 
             
                    self._respond_result(result)
         | 
| 752 754 |  | 
    
        wandb/sdk/internal/internal.py
    CHANGED
    
    
| @@ -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
         | 
    
        wandb/sdk/internal/tb_watcher.py
    CHANGED
    
    | @@ -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,
         | 
    
        wandb/sdk/internal/update.py
    CHANGED
    
    | @@ -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 =  | 
| 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 | 
| 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 | 
            -
                             | 
| 331 | 
            -
             | 
| 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}"
         | 
    
        wandb/sdk/launch/create_job.py
    CHANGED
    
    | @@ -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
         | 
    
        wandb/sdk/service/service.py
    CHANGED
    
    | @@ -15,7 +15,12 @@ import time | |
| 15 15 | 
             
            from typing import TYPE_CHECKING, Any, Dict, Optional
         | 
| 16 16 |  | 
| 17 17 | 
             
            from wandb import _sentry, termlog
         | 
| 18 | 
            -
            from wandb.env import  | 
| 18 | 
            +
            from wandb.env import (
         | 
| 19 | 
            +
                core_debug,
         | 
| 20 | 
            +
                core_error_reporting_enabled,
         | 
| 21 | 
            +
                is_require_core,
         | 
| 22 | 
            +
                is_require_legacy_service,
         | 
| 23 | 
            +
            )
         | 
| 19 24 | 
             
            from wandb.errors import Error, WandbCoreNotAvailableError
         | 
| 20 25 | 
             
            from wandb.sdk.lib.wburls import wburls
         | 
| 21 26 | 
             
            from wandb.util import get_core_path, get_module
         | 
| @@ -164,7 +169,7 @@ class _Service: | |
| 164 169 |  | 
| 165 170 | 
             
                        service_args = []
         | 
| 166 171 |  | 
| 167 | 
            -
                        if is_require_core():
         | 
| 172 | 
            +
                        if is_require_core() and not is_require_legacy_service():
         | 
| 168 173 | 
             
                            try:
         | 
| 169 174 | 
             
                                core_path = get_core_path()
         | 
| 170 175 | 
             
                            except WandbCoreNotAvailableError as e:
         | 
    
        wandb/sdk/service/streams.py
    CHANGED
    
    | @@ -81,9 +81,7 @@ class StreamRecord: | |
| 81 81 | 
             
                    self._wait_thread_active()
         | 
| 82 82 |  | 
| 83 83 | 
             
                def _wait_thread_active(self) -> None:
         | 
| 84 | 
            -
                     | 
| 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( | 
| 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 |  | 
| @@ -129,6 +129,9 @@ class Config: | |
| 129 129 | 
             
                def __getitem__(self, key):
         | 
| 130 130 | 
             
                    return self._items[key]
         | 
| 131 131 |  | 
| 132 | 
            +
                def __iter__(self):
         | 
| 133 | 
            +
                    return iter(self._items)
         | 
| 134 | 
            +
             | 
| 132 135 | 
             
                def _check_locked(self, key, ignore_locked=False) -> bool:
         | 
| 133 136 | 
             
                    locked = self._locked.get(key)
         | 
| 134 137 | 
             
                    if locked is not None:
         | 
    
        wandb/sdk/wandb_init.py
    CHANGED
    
    | @@ -15,6 +15,7 @@ import os | |
| 15 15 | 
             
            import platform
         | 
| 16 16 | 
             
            import sys
         | 
| 17 17 | 
             
            import tempfile
         | 
| 18 | 
            +
            import time
         | 
| 18 19 | 
             
            from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Union
         | 
| 19 20 |  | 
| 20 21 | 
             
            import wandb
         | 
| @@ -174,7 +175,9 @@ class _WandbInit: | |
| 174 175 | 
             
                    # we add this logic to be backward compatible with the old behavior of disable
         | 
| 175 176 | 
             
                    # where it would disable the service if the mode was set to disabled
         | 
| 176 177 | 
             
                    mode = kwargs.get("mode")
         | 
| 177 | 
            -
                    settings_mode = (kwargs.get("settings") or {}).get("mode")
         | 
| 178 | 
            +
                    settings_mode = (kwargs.get("settings") or {}).get("mode") or os.environ.get(
         | 
| 179 | 
            +
                        "WANDB_MODE"
         | 
| 180 | 
            +
                    )
         | 
| 178 181 | 
             
                    _disable_service = mode == "disabled" or settings_mode == "disabled"
         | 
| 179 182 | 
             
                    setup_settings = {"_disable_service": _disable_service}
         | 
| 180 183 |  | 
| @@ -262,7 +265,7 @@ class _WandbInit: | |
| 262 265 |  | 
| 263 266 | 
             
                    monitor_gym = kwargs.pop("monitor_gym", None)
         | 
| 264 267 | 
             
                    if monitor_gym and len(wandb.patched["gym"]) == 0:
         | 
| 265 | 
            -
                        wandb.gym.monitor()
         | 
| 268 | 
            +
                        wandb.gym.monitor()  # type: ignore
         | 
| 266 269 |  | 
| 267 270 | 
             
                    if wandb.patched["tensorboard"]:
         | 
| 268 271 | 
             
                        with telemetry.context(obj=self._init_telemetry_obj) as tel:
         | 
| @@ -271,7 +274,7 @@ class _WandbInit: | |
| 271 274 | 
             
                    tensorboard = kwargs.pop("tensorboard", None)
         | 
| 272 275 | 
             
                    sync_tensorboard = kwargs.pop("sync_tensorboard", None)
         | 
| 273 276 | 
             
                    if tensorboard or sync_tensorboard and len(wandb.patched["tensorboard"]) == 0:
         | 
| 274 | 
            -
                        wandb.tensorboard.patch()
         | 
| 277 | 
            +
                        wandb.tensorboard.patch()  # type: ignore
         | 
| 275 278 | 
             
                        with telemetry.context(obj=self._init_telemetry_obj) as tel:
         | 
| 276 279 | 
             
                            tel.feature.tensorboard_sync = True
         | 
| 277 280 |  | 
| @@ -459,7 +462,7 @@ class _WandbInit: | |
| 459 462 |  | 
| 460 463 | 
             
                def _jupyter_setup(self, settings: Settings) -> None:
         | 
| 461 464 | 
             
                    """Add hooks, and session history saving."""
         | 
| 462 | 
            -
                    self.notebook = wandb.jupyter.Notebook(settings)
         | 
| 465 | 
            +
                    self.notebook = wandb.jupyter.Notebook(settings)  # type: ignore
         | 
| 463 466 | 
             
                    ipython = self.notebook.shell
         | 
| 464 467 |  | 
| 465 468 | 
             
                    # Monkey patch ipython publish to capture displayed outputs
         | 
| @@ -522,17 +525,62 @@ class _WandbInit: | |
| 522 525 | 
             
                    logger.info(f"Logging internal logs to {settings.log_internal}")
         | 
| 523 526 |  | 
| 524 527 | 
             
                def _make_run_disabled(self) -> Run:
         | 
| 528 | 
            +
                    """Returns a Run-like object where all methods are no-ops.
         | 
| 529 | 
            +
             | 
| 530 | 
            +
                    This method is used when wandb.init(mode="disabled") is called or WANDB_MODE=disabled
         | 
| 531 | 
            +
                    is set. It creates a Run object that mimics the behavior of a normal Run but doesn't
         | 
| 532 | 
            +
                    communicate with the W&B servers.
         | 
| 533 | 
            +
             | 
| 534 | 
            +
                    The returned Run object has all expected attributes and methods, but they are
         | 
| 535 | 
            +
                    no-op versions that don't perform any actual logging or communication.
         | 
| 536 | 
            +
                    """
         | 
| 525 537 | 
             
                    drun = Run(settings=Settings(mode="disabled", files_dir=tempfile.gettempdir()))
         | 
| 526 | 
            -
                     | 
| 538 | 
            +
                    # config and summary objects
         | 
| 539 | 
            +
                    drun._config = wandb.sdk.wandb_config.Config()
         | 
| 527 540 | 
             
                    drun._config.update(self.sweep_config)
         | 
| 528 541 | 
             
                    drun._config.update(self.config)
         | 
| 529 542 | 
             
                    drun.summary = SummaryDisabled()  # type: ignore
         | 
| 543 | 
            +
                    # methods
         | 
| 530 544 | 
             
                    drun.log = lambda data, *_, **__: drun.summary.update(data)  # type: ignore
         | 
| 531 545 | 
             
                    drun.finish = lambda *_, **__: module.unset_globals()  # type: ignore
         | 
| 546 | 
            +
                    drun.join = drun.finish  # type: ignore
         | 
| 547 | 
            +
                    drun.define_metric = lambda *_, **__: wandb.sdk.wandb_metric.Metric("dummy")  # type: ignore
         | 
| 548 | 
            +
                    drun.save = lambda *_, **__: False  # type: ignore
         | 
| 549 | 
            +
                    for symbol in (
         | 
| 550 | 
            +
                        "alert",
         | 
| 551 | 
            +
                        "finish_artifact",
         | 
| 552 | 
            +
                        "get_project_url",
         | 
| 553 | 
            +
                        "get_sweep_url",
         | 
| 554 | 
            +
                        "get_url",
         | 
| 555 | 
            +
                        "link_artifact",
         | 
| 556 | 
            +
                        "link_model",
         | 
| 557 | 
            +
                        "use_artifact",
         | 
| 558 | 
            +
                        "log_artifact",
         | 
| 559 | 
            +
                        "log_code",
         | 
| 560 | 
            +
                        "log_model",
         | 
| 561 | 
            +
                        "use_model",
         | 
| 562 | 
            +
                        "mark_preempting",
         | 
| 563 | 
            +
                        "plot_table",
         | 
| 564 | 
            +
                        "restore",
         | 
| 565 | 
            +
                        "status",
         | 
| 566 | 
            +
                        "watch",
         | 
| 567 | 
            +
                        "unwatch",
         | 
| 568 | 
            +
                        "upsert_artifact",
         | 
| 569 | 
            +
                    ):
         | 
| 570 | 
            +
                        setattr(drun, symbol, lambda *_, **__: None)  # type: ignore
         | 
| 571 | 
            +
                    # attributes
         | 
| 532 572 | 
             
                    drun._step = 0
         | 
| 573 | 
            +
                    drun._attach_id = None
         | 
| 533 574 | 
             
                    drun._run_obj = None
         | 
| 534 575 | 
             
                    drun._run_id = runid.generate_id()
         | 
| 535 576 | 
             
                    drun._name = "dummy-" + drun.id
         | 
| 577 | 
            +
                    drun._project = "dummy"
         | 
| 578 | 
            +
                    drun._entity = "dummy"
         | 
| 579 | 
            +
                    drun._tags = tuple()
         | 
| 580 | 
            +
                    drun._notes = None
         | 
| 581 | 
            +
                    drun._group = None
         | 
| 582 | 
            +
                    drun._start_time = time.time()
         | 
| 583 | 
            +
                    drun._starting_step = 0
         | 
| 536 584 | 
             
                    module.set_global(
         | 
| 537 585 | 
             
                        run=drun,
         | 
| 538 586 | 
             
                        config=drun.config,
         | 
| @@ -688,7 +736,10 @@ class _WandbInit: | |
| 688 736 | 
             
                            tel.feature.flow_control_disabled = True
         | 
| 689 737 | 
             
                        if self.settings._flow_control_custom:
         | 
| 690 738 | 
             
                            tel.feature.flow_control_custom = True
         | 
| 691 | 
            -
                        if  | 
| 739 | 
            +
                        if (
         | 
| 740 | 
            +
                            self.settings._require_core
         | 
| 741 | 
            +
                            and not self.settings._require_legacy_service
         | 
| 742 | 
            +
                        ):
         | 
| 692 743 | 
             
                            tel.feature.core = True
         | 
| 693 744 | 
             
                        if self.settings._shared:
         | 
| 694 745 | 
             
                            wandb.termwarn(
         | 
| @@ -868,7 +919,7 @@ def _attach( | |
| 868 919 | 
             
                    raise UsageError(
         | 
| 869 920 | 
             
                        "Either `attach_id` or `run_id` must be specified or `run` must have `_attach_id`"
         | 
| 870 921 | 
             
                    )
         | 
| 871 | 
            -
                wandb._assert_is_user_process()
         | 
| 922 | 
            +
                wandb._assert_is_user_process()  # type: ignore
         | 
| 872 923 |  | 
| 873 924 | 
             
                _wl = wandb_setup._setup()
         | 
| 874 925 | 
             
                assert _wl
         | 
| @@ -1157,7 +1208,7 @@ def init( | |
| 1157 1208 | 
             
                Returns:
         | 
| 1158 1209 | 
             
                    A `Run` object.
         | 
| 1159 1210 | 
             
                """
         | 
| 1160 | 
            -
                wandb._assert_is_user_process()
         | 
| 1211 | 
            +
                wandb._assert_is_user_process()  # type: ignore
         | 
| 1161 1212 |  | 
| 1162 1213 | 
             
                kwargs = dict(locals())
         | 
| 1163 1214 |  | 
    
        wandb/sdk/wandb_manager.py
    CHANGED
    
    | @@ -13,7 +13,6 @@ import wandb | |
| 13 13 | 
             
            from wandb import env, trigger
         | 
| 14 14 | 
             
            from wandb.errors import Error
         | 
| 15 15 | 
             
            from wandb.sdk.lib.exit_hooks import ExitHooks
         | 
| 16 | 
            -
            from wandb.sdk.lib.import_hooks import unregister_all_post_import_hooks
         | 
| 17 16 |  | 
| 18 17 | 
             
            if TYPE_CHECKING:
         | 
| 19 18 | 
             
                from wandb.proto import wandb_settings_pb2
         | 
| @@ -163,8 +162,6 @@ class _Manager: | |
| 163 162 | 
             
                    This sends a teardown record to the process. An exception is raised if
         | 
| 164 163 | 
             
                    the process has already been shut down.
         | 
| 165 164 | 
             
                    """
         | 
| 166 | 
            -
                    unregister_all_post_import_hooks()
         | 
| 167 | 
            -
             | 
| 168 165 | 
             
                    if self._atexit_lambda:
         | 
| 169 166 | 
             
                        atexit.unregister(self._atexit_lambda)
         | 
| 170 167 | 
             
                        self._atexit_lambda = None
         | 
    
        wandb/sdk/wandb_require.py
    CHANGED
    
    | @@ -13,7 +13,12 @@ import os | |
| 13 13 | 
             
            from typing import Optional, Sequence, Union
         | 
| 14 14 |  | 
| 15 15 | 
             
            import wandb
         | 
| 16 | 
            -
            from wandb.env import  | 
| 16 | 
            +
            from wandb.env import (
         | 
| 17 | 
            +
                _REQUIRE_CORE,
         | 
| 18 | 
            +
                _REQUIRE_LEGACY_SERVICE,
         | 
| 19 | 
            +
                is_require_core,
         | 
| 20 | 
            +
                is_require_legacy_service,
         | 
| 21 | 
            +
            )
         | 
| 17 22 | 
             
            from wandb.errors import UnsupportedError
         | 
| 18 23 | 
             
            from wandb.sdk import wandb_run
         | 
| 19 24 | 
             
            from wandb.sdk.lib.wburls import wburls
         | 
| @@ -41,8 +46,24 @@ class _Requires: | |
| 41 46 | 
             
                    self._require_service()
         | 
| 42 47 |  | 
| 43 48 | 
             
                def require_core(self) -> None:
         | 
| 49 | 
            +
                    if is_require_legacy_service():
         | 
| 50 | 
            +
                        raise UnsupportedError(
         | 
| 51 | 
            +
                            'Cannot use wandb.require("core") because legacy-service'
         | 
| 52 | 
            +
                            " is already required--did you use"
         | 
| 53 | 
            +
                            ' wandb.require("legacy-service") or set the'
         | 
| 54 | 
            +
                            " WANDB__REQUIRE_LEGACY_SERVICE environment variable?"
         | 
| 55 | 
            +
                        )
         | 
| 44 56 | 
             
                    os.environ[_REQUIRE_CORE] = "true"
         | 
| 45 57 |  | 
| 58 | 
            +
                def require_legacy_service(self) -> None:
         | 
| 59 | 
            +
                    if is_require_core():
         | 
| 60 | 
            +
                        raise UnsupportedError(
         | 
| 61 | 
            +
                            'Cannot use wandb.require("legacy-service") because core'
         | 
| 62 | 
            +
                            ' is already required--did you use wandb.require("core")'
         | 
| 63 | 
            +
                            " or set the WANDB__REQUIRE_CORE environment variable?"
         | 
| 64 | 
            +
                        )
         | 
| 65 | 
            +
                    os.environ[_REQUIRE_LEGACY_SERVICE] = "true"
         | 
| 66 | 
            +
             | 
| 46 67 | 
             
                def apply(self) -> None:
         | 
| 47 68 | 
             
                    """Call require_* method for supported features."""
         | 
| 48 69 | 
             
                    last_message: str = ""
         |