wandb 0.19.9__py3-none-win32.whl → 0.19.10__py3-none-win32.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.
Files changed (128) hide show
  1. wandb/__init__.py +1 -1
  2. wandb/__init__.pyi +4 -1
  3. wandb/_pydantic/__init__.py +14 -7
  4. wandb/_pydantic/base.py +44 -9
  5. wandb/_pydantic/utils.py +66 -0
  6. wandb/_pydantic/v1_compat.py +78 -56
  7. wandb/apis/public/__init__.py +2 -2
  8. wandb/apis/public/api.py +114 -2
  9. wandb/apis/public/artifacts.py +365 -673
  10. wandb/apis/public/automations.py +69 -0
  11. wandb/apis/public/integrations.py +168 -0
  12. wandb/apis/public/projects.py +29 -0
  13. wandb/apis/public/utils.py +107 -1
  14. wandb/automations/__init__.py +81 -0
  15. wandb/automations/_filters/__init__.py +40 -0
  16. wandb/automations/_filters/expressions.py +179 -0
  17. wandb/automations/_filters/operators.py +267 -0
  18. wandb/automations/_filters/run_metrics.py +183 -0
  19. wandb/automations/_generated/__init__.py +184 -0
  20. wandb/automations/_generated/create_filter_trigger.py +21 -0
  21. wandb/automations/_generated/create_generic_webhook_integration.py +43 -0
  22. wandb/automations/_generated/delete_trigger.py +19 -0
  23. wandb/automations/_generated/enums.py +33 -0
  24. wandb/automations/_generated/fragments.py +343 -0
  25. wandb/automations/_generated/generic_webhook_integrations_by_entity.py +22 -0
  26. wandb/automations/_generated/get_triggers.py +24 -0
  27. wandb/automations/_generated/get_triggers_by_entity.py +24 -0
  28. wandb/automations/_generated/input_types.py +104 -0
  29. wandb/automations/_generated/integrations_by_entity.py +22 -0
  30. wandb/automations/_generated/operations.py +710 -0
  31. wandb/automations/_generated/slack_integrations_by_entity.py +22 -0
  32. wandb/automations/_generated/update_filter_trigger.py +21 -0
  33. wandb/automations/_utils.py +123 -0
  34. wandb/automations/_validators.py +73 -0
  35. wandb/automations/actions.py +205 -0
  36. wandb/automations/automations.py +109 -0
  37. wandb/automations/events.py +235 -0
  38. wandb/automations/integrations.py +26 -0
  39. wandb/automations/scopes.py +76 -0
  40. wandb/beta/workflows.py +9 -10
  41. wandb/bin/gpu_stats.exe +0 -0
  42. wandb/bin/wandb-core +0 -0
  43. wandb/cli/cli.py +3 -3
  44. wandb/integration/keras/keras.py +2 -1
  45. wandb/integration/langchain/wandb_tracer.py +2 -1
  46. wandb/jupyter.py +137 -118
  47. wandb/old/summary.py +0 -2
  48. wandb/proto/v3/wandb_internal_pb2.py +293 -292
  49. wandb/proto/v3/wandb_settings_pb2.py +2 -2
  50. wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
  51. wandb/proto/v4/wandb_internal_pb2.py +292 -292
  52. wandb/proto/v4/wandb_settings_pb2.py +2 -2
  53. wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
  54. wandb/proto/v5/wandb_internal_pb2.py +292 -292
  55. wandb/proto/v5/wandb_settings_pb2.py +2 -2
  56. wandb/proto/v5/wandb_telemetry_pb2.py +10 -10
  57. wandb/proto/v6/wandb_base_pb2.py +41 -0
  58. wandb/proto/v6/wandb_internal_pb2.py +393 -0
  59. wandb/proto/v6/wandb_server_pb2.py +78 -0
  60. wandb/proto/v6/wandb_settings_pb2.py +58 -0
  61. wandb/proto/v6/wandb_telemetry_pb2.py +52 -0
  62. wandb/proto/wandb_base_pb2.py +2 -0
  63. wandb/proto/wandb_deprecated.py +8 -0
  64. wandb/proto/wandb_internal_pb2.py +3 -1
  65. wandb/proto/wandb_server_pb2.py +2 -0
  66. wandb/proto/wandb_settings_pb2.py +2 -0
  67. wandb/proto/wandb_telemetry_pb2.py +2 -0
  68. wandb/sdk/artifacts/_generated/__init__.py +248 -0
  69. wandb/sdk/artifacts/_generated/artifact_collection_membership_files.py +43 -0
  70. wandb/sdk/artifacts/_generated/artifact_version_files.py +36 -0
  71. wandb/sdk/artifacts/_generated/create_artifact_collection_tag_assignments.py +36 -0
  72. wandb/sdk/artifacts/_generated/delete_artifact_collection_tag_assignments.py +25 -0
  73. wandb/sdk/artifacts/_generated/delete_artifact_portfolio.py +35 -0
  74. wandb/sdk/artifacts/_generated/delete_artifact_sequence.py +35 -0
  75. wandb/sdk/artifacts/_generated/enums.py +17 -0
  76. wandb/sdk/artifacts/_generated/fragments.py +186 -0
  77. wandb/sdk/artifacts/_generated/input_types.py +16 -0
  78. wandb/sdk/artifacts/_generated/move_artifact_collection.py +35 -0
  79. wandb/sdk/artifacts/_generated/operations.py +510 -0
  80. wandb/sdk/artifacts/_generated/project_artifact_collection.py +101 -0
  81. wandb/sdk/artifacts/_generated/project_artifact_collections.py +33 -0
  82. wandb/sdk/artifacts/_generated/project_artifact_type.py +24 -0
  83. wandb/sdk/artifacts/_generated/project_artifact_types.py +24 -0
  84. wandb/sdk/artifacts/_generated/project_artifacts.py +42 -0
  85. wandb/sdk/artifacts/_generated/run_input_artifacts.py +51 -0
  86. wandb/sdk/artifacts/_generated/run_output_artifacts.py +51 -0
  87. wandb/sdk/artifacts/_generated/update_artifact_portfolio.py +35 -0
  88. wandb/sdk/artifacts/_generated/update_artifact_sequence.py +35 -0
  89. wandb/sdk/artifacts/_graphql_fragments.py +56 -79
  90. wandb/sdk/artifacts/artifact.py +40 -13
  91. wandb/sdk/artifacts/artifact_manifest_entry.py +2 -1
  92. wandb/sdk/artifacts/storage_handlers/azure_handler.py +1 -0
  93. wandb/sdk/data_types/base_types/media.py +2 -3
  94. wandb/sdk/data_types/base_types/wb_value.py +34 -11
  95. wandb/sdk/data_types/html.py +36 -9
  96. wandb/sdk/data_types/image.py +12 -12
  97. wandb/sdk/data_types/table.py +5 -0
  98. wandb/sdk/data_types/trace_tree.py +2 -0
  99. wandb/sdk/data_types/utils.py +1 -1
  100. wandb/sdk/data_types/video.py +14 -26
  101. wandb/sdk/interface/interface.py +2 -0
  102. wandb/sdk/internal/profiler.py +6 -5
  103. wandb/sdk/internal/run.py +13 -6
  104. wandb/sdk/lib/apikey.py +25 -4
  105. wandb/sdk/lib/asyncio_compat.py +1 -1
  106. wandb/sdk/lib/deprecate.py +13 -22
  107. wandb/sdk/lib/disabled.py +2 -1
  108. wandb/sdk/lib/printer.py +37 -8
  109. wandb/sdk/lib/printer_asyncio.py +46 -0
  110. wandb/sdk/lib/redirect.py +10 -5
  111. wandb/sdk/service/server_sock.py +19 -14
  112. wandb/sdk/service/service.py +9 -7
  113. wandb/sdk/service/streams.py +5 -0
  114. wandb/sdk/verify/verify.py +6 -3
  115. wandb/sdk/wandb_init.py +185 -65
  116. wandb/sdk/wandb_login.py +13 -4
  117. wandb/sdk/wandb_run.py +382 -286
  118. wandb/sdk/wandb_settings.py +21 -3
  119. wandb/sdk/wandb_setup.py +49 -0
  120. wandb/util.py +29 -29
  121. {wandb-0.19.9.dist-info → wandb-0.19.10.dist-info}/METADATA +5 -5
  122. {wandb-0.19.9.dist-info → wandb-0.19.10.dist-info}/RECORD +125 -72
  123. wandb/_globals.py +0 -19
  124. wandb/sdk/internal/_generated/base.py +0 -226
  125. wandb/sdk/internal/_generated/typing_compat.py +0 -14
  126. {wandb-0.19.9.dist-info → wandb-0.19.10.dist-info}/WHEEL +0 -0
  127. {wandb-0.19.9.dist-info → wandb-0.19.10.dist-info}/entry_points.txt +0 -0
  128. {wandb-0.19.9.dist-info → wandb-0.19.10.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,42 @@
1
+ # Generated by ariadne-codegen
2
+ # Source: tools/graphql_codegen/artifacts/
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import Literal, Optional
7
+
8
+ from pydantic import Field
9
+
10
+ from wandb._pydantic import GQLBase, Typename
11
+
12
+ from .fragments import ArtifactsFragment
13
+
14
+
15
+ class ProjectArtifacts(GQLBase):
16
+ project: Optional[ProjectArtifactsProject]
17
+
18
+
19
+ class ProjectArtifactsProject(GQLBase):
20
+ artifact_type: Optional[ProjectArtifactsProjectArtifactType] = Field(
21
+ alias="artifactType"
22
+ )
23
+
24
+
25
+ class ProjectArtifactsProjectArtifactType(GQLBase):
26
+ artifact_collection: Optional[
27
+ ProjectArtifactsProjectArtifactTypeArtifactCollection
28
+ ] = Field(alias="artifactCollection")
29
+
30
+
31
+ class ProjectArtifactsProjectArtifactTypeArtifactCollection(GQLBase):
32
+ typename__: Typename[
33
+ Literal["ArtifactCollection", "ArtifactPortfolio", "ArtifactSequence"]
34
+ ]
35
+ name: str
36
+ artifacts: Optional[ArtifactsFragment]
37
+
38
+
39
+ ProjectArtifacts.model_rebuild()
40
+ ProjectArtifactsProject.model_rebuild()
41
+ ProjectArtifactsProjectArtifactType.model_rebuild()
42
+ ProjectArtifactsProjectArtifactTypeArtifactCollection.model_rebuild()
@@ -0,0 +1,51 @@
1
+ # Generated by ariadne-codegen
2
+ # Source: tools/graphql_codegen/artifacts/
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import List, Optional
7
+
8
+ from pydantic import Field
9
+
10
+ from wandb._pydantic import GQLBase
11
+
12
+ from .fragments import ArtifactFragment
13
+
14
+
15
+ class RunInputArtifacts(GQLBase):
16
+ project: Optional[RunInputArtifactsProject]
17
+
18
+
19
+ class RunInputArtifactsProject(GQLBase):
20
+ run: Optional[RunInputArtifactsProjectRun]
21
+
22
+
23
+ class RunInputArtifactsProjectRun(GQLBase):
24
+ input_artifacts: Optional[RunInputArtifactsProjectRunInputArtifacts] = Field(
25
+ alias="inputArtifacts"
26
+ )
27
+
28
+
29
+ class RunInputArtifactsProjectRunInputArtifacts(GQLBase):
30
+ total_count: int = Field(alias="totalCount")
31
+ edges: List[RunInputArtifactsProjectRunInputArtifactsEdges]
32
+ page_info: RunInputArtifactsProjectRunInputArtifactsPageInfo = Field(
33
+ alias="pageInfo"
34
+ )
35
+
36
+
37
+ class RunInputArtifactsProjectRunInputArtifactsEdges(GQLBase):
38
+ node: Optional[ArtifactFragment]
39
+ cursor: str
40
+
41
+
42
+ class RunInputArtifactsProjectRunInputArtifactsPageInfo(GQLBase):
43
+ end_cursor: Optional[str] = Field(alias="endCursor")
44
+ has_next_page: bool = Field(alias="hasNextPage")
45
+
46
+
47
+ RunInputArtifacts.model_rebuild()
48
+ RunInputArtifactsProject.model_rebuild()
49
+ RunInputArtifactsProjectRun.model_rebuild()
50
+ RunInputArtifactsProjectRunInputArtifacts.model_rebuild()
51
+ RunInputArtifactsProjectRunInputArtifactsEdges.model_rebuild()
@@ -0,0 +1,51 @@
1
+ # Generated by ariadne-codegen
2
+ # Source: tools/graphql_codegen/artifacts/
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import List, Optional
7
+
8
+ from pydantic import Field
9
+
10
+ from wandb._pydantic import GQLBase
11
+
12
+ from .fragments import ArtifactFragment
13
+
14
+
15
+ class RunOutputArtifacts(GQLBase):
16
+ project: Optional[RunOutputArtifactsProject]
17
+
18
+
19
+ class RunOutputArtifactsProject(GQLBase):
20
+ run: Optional[RunOutputArtifactsProjectRun]
21
+
22
+
23
+ class RunOutputArtifactsProjectRun(GQLBase):
24
+ output_artifacts: Optional[RunOutputArtifactsProjectRunOutputArtifacts] = Field(
25
+ alias="outputArtifacts"
26
+ )
27
+
28
+
29
+ class RunOutputArtifactsProjectRunOutputArtifacts(GQLBase):
30
+ total_count: int = Field(alias="totalCount")
31
+ edges: List[RunOutputArtifactsProjectRunOutputArtifactsEdges]
32
+ page_info: RunOutputArtifactsProjectRunOutputArtifactsPageInfo = Field(
33
+ alias="pageInfo"
34
+ )
35
+
36
+
37
+ class RunOutputArtifactsProjectRunOutputArtifactsEdges(GQLBase):
38
+ node: Optional[ArtifactFragment]
39
+ cursor: str
40
+
41
+
42
+ class RunOutputArtifactsProjectRunOutputArtifactsPageInfo(GQLBase):
43
+ end_cursor: Optional[str] = Field(alias="endCursor")
44
+ has_next_page: bool = Field(alias="hasNextPage")
45
+
46
+
47
+ RunOutputArtifacts.model_rebuild()
48
+ RunOutputArtifactsProject.model_rebuild()
49
+ RunOutputArtifactsProjectRun.model_rebuild()
50
+ RunOutputArtifactsProjectRunOutputArtifacts.model_rebuild()
51
+ RunOutputArtifactsProjectRunOutputArtifactsEdges.model_rebuild()
@@ -0,0 +1,35 @@
1
+ # Generated by ariadne-codegen
2
+ # Source: tools/graphql_codegen/artifacts/
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import Literal, Optional
7
+
8
+ from pydantic import Field
9
+
10
+ from wandb._pydantic import GQLBase, GQLId, Typename
11
+
12
+
13
+ class UpdateArtifactPortfolio(GQLBase):
14
+ update_artifact_portfolio: Optional[
15
+ UpdateArtifactPortfolioUpdateArtifactPortfolio
16
+ ] = Field(alias="updateArtifactPortfolio")
17
+
18
+
19
+ class UpdateArtifactPortfolioUpdateArtifactPortfolio(GQLBase):
20
+ artifact_collection: UpdateArtifactPortfolioUpdateArtifactPortfolioArtifactCollection = Field(
21
+ alias="artifactCollection"
22
+ )
23
+
24
+
25
+ class UpdateArtifactPortfolioUpdateArtifactPortfolioArtifactCollection(GQLBase):
26
+ typename__: Typename[
27
+ Literal["ArtifactCollection", "ArtifactPortfolio", "ArtifactSequence"]
28
+ ]
29
+ id: GQLId
30
+ name: str
31
+ description: Optional[str]
32
+
33
+
34
+ UpdateArtifactPortfolio.model_rebuild()
35
+ UpdateArtifactPortfolioUpdateArtifactPortfolio.model_rebuild()
@@ -0,0 +1,35 @@
1
+ # Generated by ariadne-codegen
2
+ # Source: tools/graphql_codegen/artifacts/
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import Literal, Optional
7
+
8
+ from pydantic import Field
9
+
10
+ from wandb._pydantic import GQLBase, GQLId, Typename
11
+
12
+
13
+ class UpdateArtifactSequence(GQLBase):
14
+ update_artifact_sequence: Optional[UpdateArtifactSequenceUpdateArtifactSequence] = (
15
+ Field(alias="updateArtifactSequence")
16
+ )
17
+
18
+
19
+ class UpdateArtifactSequenceUpdateArtifactSequence(GQLBase):
20
+ artifact_collection: UpdateArtifactSequenceUpdateArtifactSequenceArtifactCollection = Field(
21
+ alias="artifactCollection"
22
+ )
23
+
24
+
25
+ class UpdateArtifactSequenceUpdateArtifactSequenceArtifactCollection(GQLBase):
26
+ typename__: Typename[
27
+ Literal["ArtifactCollection", "ArtifactPortfolio", "ArtifactSequence"]
28
+ ]
29
+ id: GQLId
30
+ name: str
31
+ description: Optional[str]
32
+
33
+
34
+ UpdateArtifactSequence.model_rebuild()
35
+ UpdateArtifactSequenceUpdateArtifactSequence.model_rebuild()
@@ -1,62 +1,57 @@
1
+ from __future__ import annotations
2
+
3
+ from textwrap import dedent
4
+
5
+ from wandb_graphql.language.printer import print_ast
6
+
7
+ from wandb.apis.public.utils import gql_compat
1
8
  from wandb.sdk.internal.internal_api import Api as InternalApi
2
9
 
3
- ARTIFACTS_TYPES_FRAGMENT = """
4
- fragment ArtifactTypesFragment on ArtifactTypeConnection {
5
- edges {
6
- node {
7
- id
8
- name
9
- description
10
- createdAt
11
- }
12
- cursor
10
+ OMITTABLE_ARTIFACT_FIELDS = frozenset(
11
+ {
12
+ "ttlDurationSeconds",
13
+ "ttlIsInherited",
14
+ "aliases",
15
+ "tags",
16
+ "historyStep",
13
17
  }
14
- pageInfo {
15
- endCursor
16
- hasNextPage
17
- }
18
- }
19
- """
18
+ )
20
19
 
21
- ARTIFACT_FILES_FRAGMENT = """fragment FilesFragment on FileConnection {
22
- edges {
23
- node {
24
- id
25
- name: displayName
26
- url
27
- sizeBytes
28
- storagePath
29
- mimetype
30
- updatedAt
31
- digest
32
- md5
33
- directUrl
34
- }
35
- cursor
36
- }
37
- pageInfo {
38
- endCursor
39
- hasNextPage
40
- }
41
- }"""
20
+
21
+ def omit_artifact_fields(api: InternalApi) -> set[str]:
22
+ """Return names of Artifact fields to remove from GraphQL requests (for server compatibility)."""
23
+ allowed_fields = set(api.server_artifact_introspection())
24
+ return set(OMITTABLE_ARTIFACT_FIELDS - allowed_fields)
42
25
 
43
26
 
44
27
  def _gql_artifact_fragment(include_aliases: bool = True) -> str:
45
28
  """Return a GraphQL query fragment with all parseable Artifact attributes."""
46
- allowed_fields = set(InternalApi().server_artifact_introspection())
29
+ omit_fields = omit_artifact_fields(api=InternalApi())
47
30
 
48
- supports_ttl = "ttlIsInherited" in allowed_fields
49
- supports_tags = "tags" in allowed_fields
31
+ # Respect the `include_aliases` flag
32
+ if not include_aliases:
33
+ omit_fields.add("aliases")
50
34
 
51
- ttl_duration_seconds = "ttlDurationSeconds" if supports_ttl else ""
52
- ttl_is_inherited = "ttlIsInherited" if supports_ttl else ""
53
-
54
- tags = "tags {name}" if supports_tags else ""
55
-
56
- # The goal is to move all artifact aliases fetches to the membership level in the future
57
- # but this is a quick fix to unblock the registry work
58
- aliases = (
59
- """aliases {
35
+ artifact_fragment_str = dedent(
36
+ """\
37
+ fragment ArtifactFragment on Artifact {
38
+ id
39
+ artifactSequence {
40
+ project {
41
+ entityName
42
+ name
43
+ }
44
+ name
45
+ }
46
+ versionIndex
47
+ artifactType {
48
+ name
49
+ }
50
+ description
51
+ metadata
52
+ ttlDurationSeconds
53
+ ttlIsInherited
54
+ aliases {
60
55
  artifactCollection {
61
56
  project {
62
57
  entityName
@@ -65,43 +60,25 @@ def _gql_artifact_fragment(include_aliases: bool = True) -> str:
65
60
  name
66
61
  }
67
62
  alias
68
- }"""
69
- if include_aliases
70
- else ""
71
- )
72
-
73
- return f"""
74
- fragment ArtifactFragment on Artifact {{
75
- id
76
- artifactSequence {{
77
- project {{
78
- entityName
79
- name
80
- }}
81
- name
82
- }}
83
- versionIndex
84
- artifactType {{
63
+ }
64
+ tags {
85
65
  name
86
- }}
87
- description
88
- metadata
89
- {ttl_duration_seconds}
90
- {ttl_is_inherited}
91
- {aliases}
92
- {tags}
66
+ }
67
+ historyStep
93
68
  state
94
- currentManifest {{
95
- file {{
69
+ currentManifest {
70
+ file {
96
71
  directUrl
97
- }}
98
- }}
72
+ }
73
+ }
99
74
  commitHash
100
75
  fileCount
101
76
  createdAt
102
77
  updatedAt
103
- }}
104
- """
78
+ }"""
79
+ )
80
+ compat_doc = gql_compat(artifact_fragment_str, omit_fields=omit_fields)
81
+ return print_ast(compat_doc)
105
82
 
106
83
 
107
84
  def _gql_registry_fragment() -> str:
@@ -31,6 +31,8 @@ from wandb.apis.public import ArtifactCollection, ArtifactFiles, RetryingClient,
31
31
  from wandb.data_types import WBValue
32
32
  from wandb.errors.term import termerror, termlog, termwarn
33
33
  from wandb.proto import wandb_internal_pb2 as pb
34
+ from wandb.proto.wandb_deprecated import Deprecated
35
+ from wandb.sdk import wandb_setup
34
36
  from wandb.sdk.artifacts._graphql_fragments import _gql_artifact_fragment
35
37
  from wandb.sdk.artifacts._validators import (
36
38
  ensure_logged,
@@ -59,7 +61,7 @@ from wandb.sdk.data_types._dtypes import TypeRegistry
59
61
  from wandb.sdk.internal.internal_api import Api as InternalApi
60
62
  from wandb.sdk.internal.thread_local_settings import _thread_local_api_settings
61
63
  from wandb.sdk.lib import filesystem, retry, runid, telemetry
62
- from wandb.sdk.lib.deprecate import Deprecated, deprecate
64
+ from wandb.sdk.lib.deprecate import deprecate
63
65
  from wandb.sdk.lib.hashutil import B64MD5, b64_to_hex_id, md5_file_b64
64
66
  from wandb.sdk.lib.paths import FilePathStr, LogicalPath, StrPath, URIStr
65
67
  from wandb.sdk.lib.runid import generate_id
@@ -189,6 +191,7 @@ class Artifact:
189
191
  self._created_at: str | None = None
190
192
  self._updated_at: str | None = None
191
193
  self._final: bool = False
194
+ self._history_step: int | None = None
192
195
 
193
196
  # Cache.
194
197
  artifact_instance_cache[self._client_id] = self
@@ -409,6 +412,7 @@ class Artifact:
409
412
  self._file_count = attrs["fileCount"]
410
413
  self._created_at = attrs["createdAt"]
411
414
  self._updated_at = attrs["updatedAt"]
415
+ self._history_step = attrs.get("historyStep", None)
412
416
 
413
417
  @ensure_logged
414
418
  def new_draft(self) -> Artifact:
@@ -886,6 +890,26 @@ class Artifact:
886
890
  assert self._created_at is not None
887
891
  return self._updated_at or self._created_at
888
892
 
893
+ @property
894
+ @ensure_logged
895
+ def history_step(self) -> int | None:
896
+ """The nearest step at which history metrics were logged for the source run of the artifact.
897
+
898
+ Examples:
899
+ ```python
900
+ run = artifact.logged_by()
901
+ if run and (artifact.history_step is not None):
902
+ history = run.sample_history(
903
+ min_step=artifact.history_step,
904
+ max_step=artifact.history_step + 1,
905
+ keys=["my_metric"],
906
+ )
907
+ ```
908
+ """
909
+ if self._history_step is None:
910
+ return None
911
+ return max(0, self._history_step - 1)
912
+
889
913
  # State management.
890
914
 
891
915
  def finalize(self) -> None:
@@ -931,7 +955,12 @@ class Artifact:
931
955
  with telemetry.context() as tel:
932
956
  tel.feature.artifact_incremental = True
933
957
 
934
- if wandb.run is None:
958
+ singleton = wandb_setup._setup(start_service=False)
959
+
960
+ if run := singleton.most_recent_active_run:
961
+ # TODO: Deprecate and encourage explicit log_artifact().
962
+ run.log_artifact(self)
963
+ else:
935
964
  if settings is None:
936
965
  settings = wandb.Settings(silent="true")
937
966
  with wandb.init( # type: ignore
@@ -946,8 +975,6 @@ class Artifact:
946
975
  with telemetry.context(run=run) as tel:
947
976
  tel.feature.artifact_incremental = True
948
977
  run.log_artifact(self)
949
- else:
950
- wandb.run.log_artifact(self)
951
978
 
952
979
  def _set_save_handle(
953
980
  self,
@@ -1771,15 +1798,10 @@ class Artifact:
1771
1798
 
1772
1799
  Raises:
1773
1800
  ArtifactNotLoggedError: If the artifact is not logged.
1774
- RuntimeError: If the artifact is attempted to be downloaded in offline mode.
1775
1801
  """
1776
1802
  root = FilePathStr(str(root or self._default_root()))
1777
1803
  self._add_download_root(root)
1778
1804
 
1779
- # TODO: we need a better way to check for offline mode across the app, as this is an anti-pattern
1780
- if env.is_offline() or util._is_offline():
1781
- raise RuntimeError("Cannot download artifacts in offline mode.")
1782
-
1783
1805
  # TODO: download artifacts using core when implemented
1784
1806
  # if is_require_core():
1785
1807
  # return self._download_using_core(
@@ -1806,6 +1828,7 @@ class Artifact:
1806
1828
 
1807
1829
  from wandb.sdk.backend.backend import Backend
1808
1830
 
1831
+ # TODO: Create a special stream instead of relying on an existing run.
1809
1832
  if wandb.run is None:
1810
1833
  wl = wandb.setup()
1811
1834
 
@@ -2227,16 +2250,20 @@ class Artifact:
2227
2250
  Raises:
2228
2251
  ArtifactNotLoggedError: If the artifact is not logged.
2229
2252
  """
2230
- if wandb.run is None:
2231
- with wandb.init( # type: ignore
2253
+ singleton = wandb_setup._setup(start_service=False)
2254
+
2255
+ if run := singleton.most_recent_active_run:
2256
+ # TODO: Deprecate and encourage explicit link_artifact().
2257
+ run.link_artifact(self, target_path, aliases)
2258
+
2259
+ else:
2260
+ with wandb.init(
2232
2261
  entity=self._source_entity,
2233
2262
  project=self._source_project,
2234
2263
  job_type="auto",
2235
2264
  settings=wandb.Settings(silent="true"),
2236
2265
  ) as run:
2237
2266
  run.link_artifact(self, target_path, aliases)
2238
- else:
2239
- wandb.run.link_artifact(self, target_path, aliases)
2240
2267
 
2241
2268
  @ensure_logged
2242
2269
  def unlink(self) -> None:
@@ -9,8 +9,9 @@ from pathlib import Path
9
9
  from typing import TYPE_CHECKING
10
10
  from urllib.parse import urlparse
11
11
 
12
+ from wandb.proto.wandb_deprecated import Deprecated
12
13
  from wandb.sdk.lib import filesystem
13
- from wandb.sdk.lib.deprecate import Deprecated, deprecate
14
+ from wandb.sdk.lib.deprecate import deprecate
14
15
  from wandb.sdk.lib.hashutil import (
15
16
  B64MD5,
16
17
  ETag,
@@ -171,6 +171,7 @@ class AzureHandler(StorageHandler):
171
171
  def _get_credential(
172
172
  self, account_url: str
173
173
  ) -> azure.identity.DefaultAzureCredential | str:
174
+ # NOTE: Always returns default credential for reinit="create_new" runs.
174
175
  if (
175
176
  wandb.run
176
177
  and wandb.run.settings.azure_account_url_to_access_key is not None
@@ -7,7 +7,6 @@ from typing import TYPE_CHECKING, Any, Dict, Optional, Sequence, Type, Union, ca
7
7
 
8
8
  import wandb
9
9
  from wandb import util
10
- from wandb._globals import _datatypes_callback
11
10
  from wandb.sdk.lib import filesystem
12
11
  from wandb.sdk.lib.paths import LogicalPath
13
12
 
@@ -192,7 +191,7 @@ class Media(WBValue):
192
191
  shutil.move(self._path, new_path)
193
192
  self._path = new_path
194
193
  self._is_tmp = False
195
- _datatypes_callback(media_path)
194
+ run._publish_file(media_path)
196
195
  else:
197
196
  try:
198
197
  shutil.copy(self._path, new_path)
@@ -200,7 +199,7 @@ class Media(WBValue):
200
199
  if not ignore_copy_err:
201
200
  raise e
202
201
  self._path = new_path
203
- _datatypes_callback(media_path)
202
+ run._publish_file(media_path)
204
203
 
205
204
  def to_json(self, run: Union["LocalRun", "Artifact"]) -> dict:
206
205
  """Serialize the object into a JSON blob.
@@ -1,7 +1,7 @@
1
1
  from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Optional, Type, Union
2
2
 
3
- import wandb
4
3
  from wandb import util
4
+ from wandb.sdk import wandb_setup
5
5
 
6
6
  if TYPE_CHECKING: # pragma: no cover
7
7
  from wandb.sdk.artifacts.artifact import Artifact
@@ -11,6 +11,31 @@ if TYPE_CHECKING: # pragma: no cover
11
11
  TypeMappingType = Dict[str, Type["WBValue"]]
12
12
 
13
13
 
14
+ def _is_maybe_offline() -> bool:
15
+ """Guess whether wandb is configured to be offline.
16
+
17
+ This is an anti-pattern because there is no library-level "offline" mode:
18
+ only runs can be offline. Online and offline runs can exist in the same
19
+ process. This function is a heuristic that works only if there is at most
20
+ one run in the process, and could otherwise produce unexpected results.
21
+
22
+ Returns:
23
+ Whether the user likely configured wandb to be offline.
24
+ """
25
+ singleton = wandb_setup._setup(start_service=False)
26
+
27
+ # First check: if there's a run, check if it is offline.
28
+ #
29
+ # This covers uses like `wandb.init(mode="offline")` which don't modify
30
+ # the singleton's settings.
31
+ if run := singleton.most_recent_active_run:
32
+ return run.offline
33
+
34
+ # Second check: default to global defaults derived from environment
35
+ # variables or passed explicitly to `wandb.setup()`.
36
+ return singleton.settings._offline
37
+
38
+
14
39
  def _server_accepts_client_ids() -> bool:
15
40
  from wandb.util import parse_version
16
41
 
@@ -25,15 +50,13 @@ def _server_accepts_client_ids() -> bool:
25
50
  # AS OF NOW, 2024/11/06, we assume that all customer's server deployments accept
26
51
  # client IDs.
27
52
 
28
- if util._is_offline():
29
- # If there are any users with issues on an older backend, customers can disable the
30
- # setting `allow_offline_artifacts` to revert the SDK's behavior back to not
31
- # using client IDs in offline mode.
32
- if wandb.run and not wandb.run.settings.allow_offline_artifacts:
33
- return False
34
- # Assume client IDs are accepted
53
+ if _is_maybe_offline():
54
+ singleton = wandb_setup._setup(start_service=False)
55
+
56
+ if run := singleton.most_recent_active_run:
57
+ return run._settings.allow_offline_artifacts
35
58
  else:
36
- return True
59
+ return singleton.settings.allow_offline_artifacts
37
60
 
38
61
  # If the script is online, request the max_cli_version and ensure the server
39
62
  # is of a high enough version.
@@ -240,7 +263,7 @@ class WBValue:
240
263
  self._artifact_target
241
264
  and self._artifact_target.name
242
265
  and self._artifact_target.artifact._is_draft_save_started()
243
- and not util._is_offline()
266
+ and not _is_maybe_offline()
244
267
  and not _server_accepts_client_ids()
245
268
  ):
246
269
  self._artifact_target.artifact.wait()
@@ -271,7 +294,7 @@ class WBValue:
271
294
  self._artifact_target
272
295
  and self._artifact_target.name
273
296
  and self._artifact_target.artifact._is_draft_save_started()
274
- and not util._is_offline()
297
+ and not _is_maybe_offline()
275
298
  and not _server_accepts_client_ids()
276
299
  ):
277
300
  self._artifact_target.artifact.wait()