wandb 0.22.0__py3-none-macosx_12_0_arm64.whl → 0.22.2__py3-none-macosx_12_0_arm64.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.
- wandb/__init__.py +1 -1
- wandb/__init__.pyi +8 -5
- wandb/_pydantic/__init__.py +12 -11
- wandb/_pydantic/base.py +49 -19
- wandb/apis/__init__.py +2 -0
- wandb/apis/attrs.py +2 -0
- wandb/apis/importers/internals/internal.py +16 -23
- wandb/apis/internal.py +2 -0
- wandb/apis/normalize.py +2 -0
- wandb/apis/public/__init__.py +3 -2
- wandb/apis/public/api.py +215 -164
- wandb/apis/public/artifacts.py +23 -20
- wandb/apis/public/const.py +2 -0
- wandb/apis/public/files.py +33 -24
- wandb/apis/public/history.py +2 -0
- wandb/apis/public/jobs.py +20 -18
- wandb/apis/public/projects.py +4 -2
- wandb/apis/public/query_generator.py +3 -0
- wandb/apis/public/registries/__init__.py +7 -0
- wandb/apis/public/registries/_freezable_list.py +9 -12
- wandb/apis/public/registries/registries_search.py +8 -6
- wandb/apis/public/registries/registry.py +22 -17
- wandb/apis/public/reports.py +2 -0
- wandb/apis/public/runs.py +261 -57
- wandb/apis/public/sweeps.py +10 -9
- wandb/apis/public/teams.py +2 -0
- wandb/apis/public/users.py +2 -0
- wandb/apis/public/utils.py +16 -15
- wandb/automations/_generated/__init__.py +54 -127
- wandb/automations/_generated/create_generic_webhook_integration.py +1 -7
- wandb/automations/_generated/fragments.py +26 -91
- wandb/bin/gpu_stats +0 -0
- wandb/bin/wandb-core +0 -0
- wandb/cli/beta.py +16 -2
- wandb/cli/beta_leet.py +74 -0
- wandb/cli/beta_sync.py +9 -11
- wandb/cli/cli.py +34 -7
- wandb/errors/errors.py +3 -3
- wandb/proto/v3/wandb_api_pb2.py +86 -0
- wandb/proto/v3/wandb_internal_pb2.py +352 -351
- wandb/proto/v3/wandb_settings_pb2.py +2 -2
- wandb/proto/v3/wandb_sync_pb2.py +19 -6
- wandb/proto/v4/wandb_api_pb2.py +37 -0
- wandb/proto/v4/wandb_internal_pb2.py +352 -351
- wandb/proto/v4/wandb_settings_pb2.py +2 -2
- wandb/proto/v4/wandb_sync_pb2.py +10 -6
- wandb/proto/v5/wandb_api_pb2.py +38 -0
- wandb/proto/v5/wandb_internal_pb2.py +352 -351
- wandb/proto/v5/wandb_settings_pb2.py +2 -2
- wandb/proto/v5/wandb_sync_pb2.py +10 -6
- wandb/proto/v6/wandb_api_pb2.py +48 -0
- wandb/proto/v6/wandb_internal_pb2.py +352 -351
- wandb/proto/v6/wandb_settings_pb2.py +2 -2
- wandb/proto/v6/wandb_sync_pb2.py +10 -6
- wandb/proto/wandb_api_pb2.py +18 -0
- wandb/proto/wandb_generate_proto.py +1 -0
- wandb/sdk/artifacts/_factories.py +7 -2
- wandb/sdk/artifacts/_generated/__init__.py +112 -412
- wandb/sdk/artifacts/_generated/fragments.py +65 -0
- wandb/sdk/artifacts/_generated/operations.py +52 -22
- wandb/sdk/artifacts/_generated/run_input_artifacts.py +3 -23
- wandb/sdk/artifacts/_generated/run_output_artifacts.py +3 -23
- wandb/sdk/artifacts/_generated/type_info.py +19 -0
- wandb/sdk/artifacts/_gqlutils.py +47 -0
- wandb/sdk/artifacts/_models/__init__.py +4 -0
- wandb/sdk/artifacts/_models/base_model.py +20 -0
- wandb/sdk/artifacts/_validators.py +40 -12
- wandb/sdk/artifacts/artifact.py +99 -118
- wandb/sdk/artifacts/artifact_file_cache.py +6 -1
- wandb/sdk/artifacts/artifact_manifest_entry.py +67 -14
- wandb/sdk/artifacts/storage_handler.py +18 -12
- wandb/sdk/artifacts/storage_handlers/azure_handler.py +11 -6
- wandb/sdk/artifacts/storage_handlers/gcs_handler.py +9 -6
- wandb/sdk/artifacts/storage_handlers/http_handler.py +9 -4
- wandb/sdk/artifacts/storage_handlers/local_file_handler.py +10 -6
- wandb/sdk/artifacts/storage_handlers/multi_handler.py +5 -4
- wandb/sdk/artifacts/storage_handlers/s3_handler.py +10 -8
- wandb/sdk/artifacts/storage_handlers/tracking_handler.py +6 -4
- wandb/sdk/artifacts/storage_handlers/wb_artifact_handler.py +24 -21
- wandb/sdk/artifacts/storage_handlers/wb_local_artifact_handler.py +4 -2
- wandb/sdk/artifacts/storage_policies/_multipart.py +187 -0
- wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +71 -242
- wandb/sdk/artifacts/storage_policy.py +25 -12
- wandb/sdk/data_types/bokeh.py +5 -1
- wandb/sdk/data_types/image.py +17 -6
- wandb/sdk/data_types/object_3d.py +67 -2
- wandb/sdk/interface/interface.py +31 -4
- wandb/sdk/interface/interface_queue.py +10 -0
- wandb/sdk/interface/interface_shared.py +0 -7
- wandb/sdk/interface/interface_sock.py +9 -3
- wandb/sdk/internal/_generated/__init__.py +2 -12
- wandb/sdk/internal/job_builder.py +27 -10
- wandb/sdk/internal/sender.py +5 -2
- wandb/sdk/internal/settings_static.py +2 -82
- wandb/sdk/launch/create_job.py +2 -1
- wandb/sdk/launch/runner/kubernetes_runner.py +25 -20
- wandb/sdk/launch/utils.py +82 -1
- wandb/sdk/lib/progress.py +8 -74
- wandb/sdk/lib/service/service_client.py +5 -9
- wandb/sdk/lib/service/service_connection.py +39 -23
- wandb/sdk/mailbox/mailbox_handle.py +2 -0
- wandb/sdk/projects/_generated/__init__.py +12 -33
- wandb/sdk/wandb_init.py +23 -3
- wandb/sdk/wandb_login.py +53 -27
- wandb/sdk/wandb_run.py +10 -5
- wandb/sdk/wandb_settings.py +63 -25
- wandb/sync/sync.py +7 -2
- wandb/util.py +1 -1
- {wandb-0.22.0.dist-info → wandb-0.22.2.dist-info}/METADATA +1 -1
- {wandb-0.22.0.dist-info → wandb-0.22.2.dist-info}/RECORD +113 -103
- wandb/sdk/artifacts/_graphql_fragments.py +0 -19
- {wandb-0.22.0.dist-info → wandb-0.22.2.dist-info}/WHEEL +0 -0
- {wandb-0.22.0.dist-info → wandb-0.22.2.dist-info}/entry_points.txt +0 -0
- {wandb-0.22.0.dist-info → wandb-0.22.2.dist-info}/licenses/LICENSE +0 -0
@@ -33,6 +33,7 @@ __all__ = [
|
|
33
33
|
"REGISTRY_VERSIONS_GQL",
|
34
34
|
"RUN_INPUT_ARTIFACTS_GQL",
|
35
35
|
"RUN_OUTPUT_ARTIFACTS_GQL",
|
36
|
+
"TYPE_INFO_GQL",
|
36
37
|
"UNLINK_ARTIFACT_GQL",
|
37
38
|
"UPDATE_ARTIFACT_GQL",
|
38
39
|
"UPDATE_ARTIFACT_PORTFOLIO_GQL",
|
@@ -456,17 +457,7 @@ query RunOutputArtifacts($entity: String!, $project: String!, $runName: String!,
|
|
456
457
|
project(name: $project, entityName: $entity) {
|
457
458
|
run(name: $runName) {
|
458
459
|
outputArtifacts(after: $cursor, first: $perPage) {
|
459
|
-
|
460
|
-
edges {
|
461
|
-
node {
|
462
|
-
...ArtifactFragment
|
463
|
-
}
|
464
|
-
cursor
|
465
|
-
}
|
466
|
-
pageInfo {
|
467
|
-
endCursor
|
468
|
-
hasNextPage
|
469
|
-
}
|
460
|
+
...RunOutputArtifactConnectionFragment
|
470
461
|
}
|
471
462
|
}
|
472
463
|
}
|
@@ -519,6 +510,20 @@ fragment ArtifactFragmentWithoutAliases on Artifact {
|
|
519
510
|
createdAt
|
520
511
|
updatedAt
|
521
512
|
}
|
513
|
+
|
514
|
+
fragment RunOutputArtifactConnectionFragment on ArtifactConnection {
|
515
|
+
totalCount
|
516
|
+
edges {
|
517
|
+
node {
|
518
|
+
...ArtifactFragment
|
519
|
+
}
|
520
|
+
cursor
|
521
|
+
}
|
522
|
+
pageInfo {
|
523
|
+
endCursor
|
524
|
+
hasNextPage
|
525
|
+
}
|
526
|
+
}
|
522
527
|
"""
|
523
528
|
|
524
529
|
RUN_INPUT_ARTIFACTS_GQL = """
|
@@ -526,17 +531,7 @@ query RunInputArtifacts($entity: String!, $project: String!, $runName: String!,
|
|
526
531
|
project(name: $project, entityName: $entity) {
|
527
532
|
run(name: $runName) {
|
528
533
|
inputArtifacts(after: $cursor, first: $perPage) {
|
529
|
-
|
530
|
-
edges {
|
531
|
-
node {
|
532
|
-
...ArtifactFragment
|
533
|
-
}
|
534
|
-
cursor
|
535
|
-
}
|
536
|
-
pageInfo {
|
537
|
-
endCursor
|
538
|
-
hasNextPage
|
539
|
-
}
|
534
|
+
...RunInputArtifactConnectionFragment
|
540
535
|
}
|
541
536
|
}
|
542
537
|
}
|
@@ -589,6 +584,20 @@ fragment ArtifactFragmentWithoutAliases on Artifact {
|
|
589
584
|
createdAt
|
590
585
|
updatedAt
|
591
586
|
}
|
587
|
+
|
588
|
+
fragment RunInputArtifactConnectionFragment on InputArtifactConnection {
|
589
|
+
totalCount
|
590
|
+
edges {
|
591
|
+
node {
|
592
|
+
...ArtifactFragment
|
593
|
+
}
|
594
|
+
cursor
|
595
|
+
}
|
596
|
+
pageInfo {
|
597
|
+
endCursor
|
598
|
+
hasNextPage
|
599
|
+
}
|
600
|
+
}
|
592
601
|
"""
|
593
602
|
|
594
603
|
FETCH_LINKED_ARTIFACTS_GQL = """
|
@@ -1040,6 +1049,27 @@ mutation UnlinkArtifact($artifactID: ID!, $artifactPortfolioID: ID!) {
|
|
1040
1049
|
}
|
1041
1050
|
"""
|
1042
1051
|
|
1052
|
+
TYPE_INFO_GQL = """
|
1053
|
+
query TypeInfo($name: String!) {
|
1054
|
+
__type(name: $name) {
|
1055
|
+
...TypeInfoFragment
|
1056
|
+
}
|
1057
|
+
}
|
1058
|
+
|
1059
|
+
fragment TypeInfoFragment on __Type {
|
1060
|
+
name
|
1061
|
+
fields {
|
1062
|
+
name
|
1063
|
+
args {
|
1064
|
+
name
|
1065
|
+
}
|
1066
|
+
}
|
1067
|
+
inputFields {
|
1068
|
+
name
|
1069
|
+
}
|
1070
|
+
}
|
1071
|
+
"""
|
1072
|
+
|
1043
1073
|
REGISTRY_VERSIONS_GQL = """
|
1044
1074
|
query RegistryVersions($organization: String!, $registryFilter: JSONString, $collectionFilter: JSONString, $artifactFilter: JSONString, $cursor: String, $perPage: Int) {
|
1045
1075
|
organization(name: $organization) {
|
@@ -3,13 +3,13 @@
|
|
3
3
|
|
4
4
|
from __future__ import annotations
|
5
5
|
|
6
|
-
from typing import
|
6
|
+
from typing import Optional
|
7
7
|
|
8
8
|
from pydantic import Field
|
9
9
|
|
10
10
|
from wandb._pydantic import GQLBase
|
11
11
|
|
12
|
-
from .fragments import
|
12
|
+
from .fragments import RunInputArtifactConnectionFragment
|
13
13
|
|
14
14
|
|
15
15
|
class RunInputArtifacts(GQLBase):
|
@@ -21,31 +21,11 @@ class RunInputArtifactsProject(GQLBase):
|
|
21
21
|
|
22
22
|
|
23
23
|
class RunInputArtifactsProjectRun(GQLBase):
|
24
|
-
input_artifacts: Optional[
|
24
|
+
input_artifacts: Optional[RunInputArtifactConnectionFragment] = Field(
|
25
25
|
alias="inputArtifacts"
|
26
26
|
)
|
27
27
|
|
28
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
29
|
RunInputArtifacts.model_rebuild()
|
48
30
|
RunInputArtifactsProject.model_rebuild()
|
49
31
|
RunInputArtifactsProjectRun.model_rebuild()
|
50
|
-
RunInputArtifactsProjectRunInputArtifacts.model_rebuild()
|
51
|
-
RunInputArtifactsProjectRunInputArtifactsEdges.model_rebuild()
|
@@ -3,13 +3,13 @@
|
|
3
3
|
|
4
4
|
from __future__ import annotations
|
5
5
|
|
6
|
-
from typing import
|
6
|
+
from typing import Optional
|
7
7
|
|
8
8
|
from pydantic import Field
|
9
9
|
|
10
10
|
from wandb._pydantic import GQLBase
|
11
11
|
|
12
|
-
from .fragments import
|
12
|
+
from .fragments import RunOutputArtifactConnectionFragment
|
13
13
|
|
14
14
|
|
15
15
|
class RunOutputArtifacts(GQLBase):
|
@@ -21,31 +21,11 @@ class RunOutputArtifactsProject(GQLBase):
|
|
21
21
|
|
22
22
|
|
23
23
|
class RunOutputArtifactsProjectRun(GQLBase):
|
24
|
-
output_artifacts: Optional[
|
24
|
+
output_artifacts: Optional[RunOutputArtifactConnectionFragment] = Field(
|
25
25
|
alias="outputArtifacts"
|
26
26
|
)
|
27
27
|
|
28
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
29
|
RunOutputArtifacts.model_rebuild()
|
48
30
|
RunOutputArtifactsProject.model_rebuild()
|
49
31
|
RunOutputArtifactsProjectRun.model_rebuild()
|
50
|
-
RunOutputArtifactsProjectRunOutputArtifacts.model_rebuild()
|
51
|
-
RunOutputArtifactsProjectRunOutputArtifactsEdges.model_rebuild()
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Generated by ariadne-codegen
|
2
|
+
# Source: tools/graphql_codegen/artifacts/
|
3
|
+
|
4
|
+
from __future__ import annotations
|
5
|
+
|
6
|
+
from typing import Optional
|
7
|
+
|
8
|
+
from pydantic import Field
|
9
|
+
|
10
|
+
from wandb._pydantic import GQLBase
|
11
|
+
|
12
|
+
from .fragments import TypeInfoFragment
|
13
|
+
|
14
|
+
|
15
|
+
class TypeInfo(GQLBase):
|
16
|
+
type: Optional[TypeInfoFragment] = Field(alias="__type")
|
17
|
+
|
18
|
+
|
19
|
+
TypeInfo.model_rebuild()
|
@@ -0,0 +1,47 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from functools import lru_cache
|
4
|
+
|
5
|
+
from wandb_gql import Client, gql
|
6
|
+
|
7
|
+
from ._generated import TYPE_INFO_GQL, TypeInfo, TypeInfoFragment
|
8
|
+
|
9
|
+
OMITTABLE_ARTIFACT_FIELDS = frozenset(
|
10
|
+
{
|
11
|
+
"ttlDurationSeconds",
|
12
|
+
"ttlIsInherited",
|
13
|
+
"aliases",
|
14
|
+
"tags",
|
15
|
+
"historyStep",
|
16
|
+
}
|
17
|
+
)
|
18
|
+
|
19
|
+
|
20
|
+
@lru_cache(maxsize=16)
|
21
|
+
def type_info(client: Client, typename: str) -> TypeInfoFragment | None:
|
22
|
+
"""Returns the type info for a given GraphQL type."""
|
23
|
+
data = client.execute(gql(TYPE_INFO_GQL), variable_values={"name": typename})
|
24
|
+
return TypeInfo.model_validate(data).type
|
25
|
+
|
26
|
+
|
27
|
+
def supports_enable_tracking_var(client: Client) -> bool:
|
28
|
+
"""Returns True if the server supports the `enableTracking` variable for the `Project.artifact(...)` field."""
|
29
|
+
typ = type_info(client, "Project")
|
30
|
+
if (
|
31
|
+
typ
|
32
|
+
and typ.fields
|
33
|
+
and (art_field := next((f for f in typ.fields if f.name == "artifact"), None))
|
34
|
+
):
|
35
|
+
return any("enableTracking" == arg.name for arg in art_field.args)
|
36
|
+
return False
|
37
|
+
|
38
|
+
|
39
|
+
def allowed_fields(client: Client, typename: str) -> set[str]:
|
40
|
+
"""Returns the allowed field names for a given GraphQL type."""
|
41
|
+
typ = type_info(client, typename)
|
42
|
+
return {f.name for f in typ.fields} if (typ and typ.fields) else set()
|
43
|
+
|
44
|
+
|
45
|
+
def omit_artifact_fields(client: Client) -> set[str]:
|
46
|
+
"""Return names of Artifact fields to remove from GraphQL requests (for server compatibility)."""
|
47
|
+
return set(OMITTABLE_ARTIFACT_FIELDS) - allowed_fields(client, "Artifact")
|
@@ -0,0 +1,20 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from abc import ABC
|
4
|
+
|
5
|
+
from pydantic import ConfigDict
|
6
|
+
|
7
|
+
from wandb._pydantic import JsonableModel
|
8
|
+
|
9
|
+
|
10
|
+
# Abstract base class with a common default configuration that's shared by all
|
11
|
+
# pydantic classes in artifacts code (excluding GraphQL-generated types).
|
12
|
+
class ArtifactsBase(JsonableModel, ABC):
|
13
|
+
# See: https://docs.pydantic.dev/latest/api/config/#pydantic.config.ConfigDict
|
14
|
+
model_config = ConfigDict(
|
15
|
+
# Most likely, some fields won't be pydantic types
|
16
|
+
arbitrary_types_allowed=True,
|
17
|
+
# Assume instances of the same class have already been validated to save time,
|
18
|
+
# but validate subclasses in case they override the default behavior.
|
19
|
+
revalidate_instances="subclass-instances",
|
20
|
+
)
|
@@ -4,7 +4,7 @@ from __future__ import annotations
|
|
4
4
|
|
5
5
|
import json
|
6
6
|
import re
|
7
|
-
from dataclasses import
|
7
|
+
from dataclasses import dataclass, field, replace
|
8
8
|
from functools import wraps
|
9
9
|
from typing import TYPE_CHECKING, Any, Callable, Dict, Literal, Optional, TypeVar, cast
|
10
10
|
|
@@ -277,34 +277,62 @@ def remove_registry_prefix(project: str) -> str:
|
|
277
277
|
|
278
278
|
@pydantic_dataclass
|
279
279
|
class ArtifactPath:
|
280
|
-
#: The collection name.
|
281
280
|
name: str
|
282
|
-
|
281
|
+
"""The collection or artifact version name."""
|
283
282
|
project: Optional[str] = None # noqa: UP045
|
284
|
-
|
283
|
+
"""The project name."""
|
285
284
|
prefix: Optional[str] = None # noqa: UP045
|
285
|
+
"""Typically the entity or org name."""
|
286
286
|
|
287
287
|
@classmethod
|
288
288
|
def from_str(cls, path: str) -> Self:
|
289
|
-
"""Instantiate by parsing
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
289
|
+
"""Instantiate by parsing a string artifact path.
|
290
|
+
|
291
|
+
Raises:
|
292
|
+
ValueError: If the string is not a valid artifact path.
|
293
|
+
"""
|
294
|
+
# Separate the alias first, which may itself contain slashes.
|
295
|
+
# If there's no alias, note that both sep and alias will be empty.
|
296
|
+
collection_path, sep, alias = path.partition(":")
|
297
|
+
|
298
|
+
prefix, project = None, None # defaults, if missing
|
299
|
+
if len(parts := collection_path.split("/")) == 1:
|
300
|
+
name = parts[0]
|
301
|
+
elif len(parts) == 2:
|
302
|
+
project, name = parts
|
303
|
+
elif len(parts) == 3:
|
304
|
+
prefix, project, name = parts
|
305
|
+
else:
|
306
|
+
raise ValueError(f"Invalid artifact path: {path!r}")
|
307
|
+
return cls(prefix=prefix, project=project, name=f"{name}{sep}{alias}")
|
295
308
|
|
296
309
|
def to_str(self) -> str:
|
297
310
|
"""Returns the slash-separated string representation of the path."""
|
298
|
-
|
311
|
+
ordered_parts = (self.prefix, self.project, self.name)
|
312
|
+
return "/".join(part for part in ordered_parts if part)
|
299
313
|
|
300
314
|
def with_defaults(
|
301
315
|
self,
|
316
|
+
*,
|
302
317
|
prefix: str | None = None,
|
303
318
|
project: str | None = None,
|
304
319
|
) -> Self:
|
305
|
-
"""Returns this path with missing values set to the given defaults."""
|
320
|
+
"""Returns a copy of this path with missing values set to the given defaults."""
|
306
321
|
return replace(
|
307
322
|
self,
|
308
323
|
prefix=self.prefix or prefix,
|
309
324
|
project=self.project or project,
|
310
325
|
)
|
326
|
+
|
327
|
+
def is_registry_path(self) -> bool:
|
328
|
+
"""Returns True if this path appears to be a registry path."""
|
329
|
+
return bool((p := self.project) and is_artifact_registry_project(p))
|
330
|
+
|
331
|
+
|
332
|
+
@pydantic_dataclass
|
333
|
+
class FullArtifactPath(ArtifactPath):
|
334
|
+
"""Same as ArtifactPath, but with all parts required."""
|
335
|
+
|
336
|
+
name: str
|
337
|
+
project: str
|
338
|
+
prefix: str
|