Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions tests/wandb_interface/test_project_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import pytest

from weave.compat.wandb import AuthenticationError, CommError
from weave.trace.settings import override_settings
from weave.wandb_interface.project_creator import (
UnableToCreateProjectError,
ensure_project_exists,
Expand Down Expand Up @@ -138,6 +139,30 @@ def test_ensure_project_exists_authentication_error(mock_api_with_no_project):
)


def test_ensure_project_exists_autocreate_disabled_existing_project_ok(
mock_api_with_existing_project,
):
"""With autocreate disabled, an existing project still resolves normally."""
with override_settings(autocreate_project=False):
result = ensure_project_exists("test_entity", "test_project")

assert result == {"project_name": "existing_project"}
mock_api_with_existing_project.upsert_project.assert_not_called()


def test_ensure_project_exists_autocreate_disabled_missing_project_errors(
mock_api_with_no_project,
):
"""With autocreate disabled, a missing project raises without upserting."""
with (
override_settings(autocreate_project=False),
pytest.raises(UnableToCreateProjectError, match="autocreate_project is disabled"),
):
ensure_project_exists("test_entity", "test_project")

mock_api_with_no_project.upsert_project.assert_not_called()


@pytest.mark.disable_logging_error_check
def test_ensure_project_exists_comm_error(mock_api_with_no_project):
"""Test project creation with communication error."""
Expand Down
3 changes: 3 additions & 0 deletions weave/trace/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ def init(
call data (start and end) into a single request instead of separate start/end requests.
This reduces server load and improves performance, especially for short-lived ops.
Default: `True`
- `autocreate_project` (bool): Allows `weave.init` to create the project on the
server if it does not already exist. When `False`, `weave.init` raises an
error instead of creating the project. Default: `True`
autopatch_settings: (Deprecated) Configuration for autopatch integrations. Use explicit patching instead.
postprocess_inputs: A function applied to the inputs of every op traced by this client.
postprocess_output: A function applied to the output of every op traced by this client.
Expand Down
18 changes: 18 additions & 0 deletions weave/trace/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,16 @@ class UserSettings:
Can be overridden with the environment variable `WEAVE_USE_OTEL_V2`
"""

autocreate_project: bool = True
"""Toggles automatic project creation on `weave.init()`.

If True (default), `weave.init('entity/project')` upserts the project,
creating it on the server if it does not yet exist. If False, `weave.init`
raises `UnableToCreateProjectError` when the project does not exist; the
project must be created out-of-band (e.g. via the W&B UI).
Can be overridden with the environment variable `WEAVE_AUTOCREATE_PROJECT`
"""


class _SettingsOverrides(TypedDict, total=False):
"""Typed kwargs accepted by :func:`override_settings`.
Expand Down Expand Up @@ -360,6 +370,7 @@ class _SettingsOverrides(TypedDict, total=False):
enable_wal: bool
disable_wal_sender: bool
use_otel_v2: bool
autocreate_project: bool


# Resolve string annotations once at import; used for env-var coercion.
Expand Down Expand Up @@ -634,3 +645,10 @@ def should_disable_wal_sender() -> bool:
def should_use_otel_v2() -> bool:
"""Returns whether OTel-capable integrations should use their OTel variant."""
return _env_or_default("use_otel_v2", _current_settings.get().use_otel_v2)


def should_autocreate_project() -> bool:
"""Returns whether `weave.init` may create the project if it does not exist."""
return _env_or_default(
"autocreate_project", _current_settings.get().autocreate_project
)
13 changes: 12 additions & 1 deletion weave/wandb_interface/project_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@

from weave.compat import wandb
from weave.compat.wandb import wandb_logger
from weave.trace.settings import retry_max_attempts, retry_max_interval
from weave.trace.settings import (
retry_max_attempts,
retry_max_interval,
should_autocreate_project,
)


class UnableToCreateProjectError(Exception): ...
Expand Down Expand Up @@ -120,6 +124,13 @@ def _ensure_project_exists(entity_name: str, project_name: str) -> dict[str, str
if project_exception is not None:
_raise_project_access_error(entity_name, project_name, project_exception)

if not should_autocreate_project():
raise UnableToCreateProjectError(
f"Project `{entity_name}/{project_name}` does not exist and "
"autocreate_project is disabled. Create the project in the W&B UI "
"or set WEAVE_AUTOCREATE_PROJECT=true."
)

# Try to create the project
exception = None
try:
Expand Down
Loading