wandb 0.17.0rc1__py3-none-macosx_11_0_arm64.whl → 0.17.1__py3-none-macosx_11_0_arm64.whl
Sign up to get free protection for your applications and to get access to all the features.
- wandb/__init__.py +1 -2
- wandb/apis/importers/internals/internal.py +0 -1
- wandb/apis/importers/wandb.py +12 -7
- wandb/apis/internal.py +0 -3
- wandb/apis/public/api.py +213 -79
- wandb/apis/public/artifacts.py +335 -100
- wandb/apis/public/files.py +9 -9
- wandb/apis/public/jobs.py +16 -4
- wandb/apis/public/projects.py +26 -28
- wandb/apis/public/query_generator.py +1 -1
- wandb/apis/public/runs.py +163 -65
- wandb/apis/public/sweeps.py +2 -2
- wandb/apis/reports/__init__.py +1 -7
- wandb/apis/reports/v1/__init__.py +5 -27
- wandb/apis/reports/v2/__init__.py +7 -19
- wandb/apis/workspaces/__init__.py +8 -0
- wandb/beta/workflows.py +8 -3
- wandb/bin/apple_gpu_stats +0 -0
- wandb/bin/wandb-core +0 -0
- wandb/cli/cli.py +131 -59
- wandb/data_types.py +6 -3
- wandb/docker/__init__.py +2 -2
- wandb/env.py +3 -3
- wandb/errors/term.py +10 -2
- wandb/filesync/step_checksum.py +1 -4
- wandb/filesync/step_prepare.py +4 -24
- wandb/filesync/step_upload.py +5 -107
- wandb/filesync/upload_job.py +0 -76
- wandb/integration/gym/__init__.py +35 -15
- wandb/integration/huggingface/resolver.py +2 -2
- wandb/integration/keras/callbacks/metrics_logger.py +1 -1
- wandb/integration/keras/keras.py +1 -1
- wandb/integration/openai/fine_tuning.py +21 -3
- wandb/integration/prodigy/prodigy.py +1 -1
- wandb/jupyter.py +16 -17
- wandb/old/summary.py +1 -1
- wandb/plot/confusion_matrix.py +1 -1
- wandb/plot/pr_curve.py +2 -1
- wandb/plot/roc_curve.py +2 -1
- wandb/{plots → plot}/utils.py +13 -25
- wandb/proto/v3/wandb_internal_pb2.py +54 -54
- wandb/proto/v3/wandb_settings_pb2.py +2 -2
- wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v4/wandb_internal_pb2.py +54 -54
- wandb/proto/v4/wandb_settings_pb2.py +2 -2
- wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v5/wandb_base_pb2.py +30 -0
- wandb/proto/v5/wandb_internal_pb2.py +355 -0
- wandb/proto/v5/wandb_server_pb2.py +63 -0
- wandb/proto/v5/wandb_settings_pb2.py +45 -0
- wandb/proto/v5/wandb_telemetry_pb2.py +41 -0
- wandb/proto/wandb_base_pb2.py +2 -0
- wandb/proto/wandb_deprecated.py +9 -1
- wandb/proto/wandb_generate_deprecated.py +34 -0
- wandb/proto/{wandb_internal_codegen.py → wandb_generate_proto.py} +1 -35
- wandb/proto/wandb_internal_pb2.py +2 -0
- wandb/proto/wandb_server_pb2.py +2 -0
- wandb/proto/wandb_settings_pb2.py +2 -0
- wandb/proto/wandb_telemetry_pb2.py +2 -0
- wandb/sdk/artifacts/artifact.py +68 -22
- wandb/sdk/artifacts/artifact_manifest.py +1 -1
- wandb/sdk/artifacts/artifact_manifest_entry.py +6 -3
- wandb/sdk/artifacts/artifact_manifests/artifact_manifest_v1.py +1 -1
- wandb/sdk/artifacts/artifact_saver.py +1 -10
- wandb/sdk/artifacts/storage_handlers/local_file_handler.py +6 -2
- wandb/sdk/artifacts/storage_handlers/multi_handler.py +1 -1
- wandb/sdk/artifacts/storage_handlers/tracking_handler.py +6 -4
- wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +2 -42
- wandb/sdk/artifacts/storage_policy.py +1 -12
- wandb/sdk/data_types/_dtypes.py +8 -8
- wandb/sdk/data_types/image.py +2 -2
- wandb/sdk/data_types/video.py +5 -3
- wandb/sdk/integration_utils/data_logging.py +5 -5
- wandb/sdk/interface/interface.py +14 -1
- wandb/sdk/interface/interface_shared.py +1 -1
- wandb/sdk/internal/file_pusher.py +2 -5
- wandb/sdk/internal/file_stream.py +6 -19
- wandb/sdk/internal/internal_api.py +148 -136
- wandb/sdk/internal/job_builder.py +208 -136
- wandb/sdk/internal/progress.py +0 -28
- wandb/sdk/internal/sender.py +102 -39
- wandb/sdk/internal/settings_static.py +8 -1
- wandb/sdk/internal/system/assets/trainium.py +3 -3
- wandb/sdk/internal/system/system_info.py +4 -2
- wandb/sdk/internal/update.py +1 -1
- wandb/sdk/launch/__init__.py +9 -1
- wandb/sdk/launch/_launch.py +4 -24
- wandb/sdk/launch/_launch_add.py +1 -3
- wandb/sdk/launch/_project_spec.py +187 -225
- wandb/sdk/launch/agent/agent.py +59 -19
- wandb/sdk/launch/agent/config.py +0 -3
- wandb/sdk/launch/builder/abstract.py +68 -1
- wandb/sdk/launch/builder/build.py +165 -576
- wandb/sdk/launch/builder/context_manager.py +235 -0
- wandb/sdk/launch/builder/docker_builder.py +7 -23
- wandb/sdk/launch/builder/kaniko_builder.py +12 -25
- wandb/sdk/launch/builder/templates/dockerfile.py +92 -0
- wandb/sdk/launch/create_job.py +51 -45
- wandb/sdk/launch/environment/aws_environment.py +26 -1
- wandb/sdk/launch/inputs/files.py +148 -0
- wandb/sdk/launch/inputs/internal.py +224 -0
- wandb/sdk/launch/inputs/manage.py +95 -0
- wandb/sdk/launch/registry/google_artifact_registry.py +1 -1
- wandb/sdk/launch/runner/abstract.py +2 -2
- wandb/sdk/launch/runner/kubernetes_monitor.py +45 -12
- wandb/sdk/launch/runner/kubernetes_runner.py +6 -8
- wandb/sdk/launch/runner/local_container.py +2 -3
- wandb/sdk/launch/runner/local_process.py +8 -29
- wandb/sdk/launch/runner/sagemaker_runner.py +20 -14
- wandb/sdk/launch/runner/vertex_runner.py +8 -7
- wandb/sdk/launch/sweeps/scheduler.py +5 -3
- wandb/sdk/launch/sweeps/scheduler_sweep.py +1 -1
- wandb/sdk/launch/sweeps/utils.py +4 -4
- wandb/sdk/launch/utils.py +16 -138
- wandb/sdk/lib/_settings_toposort_generated.py +2 -5
- wandb/sdk/lib/apikey.py +4 -2
- wandb/sdk/lib/config_util.py +3 -3
- wandb/sdk/lib/import_hooks.py +1 -1
- wandb/sdk/lib/proto_util.py +22 -1
- wandb/sdk/lib/redirect.py +20 -15
- wandb/sdk/lib/tracelog.py +1 -1
- wandb/sdk/service/service.py +2 -1
- wandb/sdk/service/streams.py +5 -5
- wandb/sdk/wandb_init.py +25 -59
- wandb/sdk/wandb_login.py +28 -25
- wandb/sdk/wandb_run.py +123 -53
- wandb/sdk/wandb_settings.py +33 -64
- wandb/sdk/wandb_setup.py +1 -1
- wandb/sdk/wandb_watch.py +1 -1
- wandb/sklearn/plot/classifier.py +10 -12
- wandb/sklearn/plot/clusterer.py +1 -1
- wandb/sync/sync.py +2 -2
- wandb/testing/relay.py +32 -17
- wandb/util.py +36 -37
- wandb/wandb_agent.py +3 -3
- wandb/wandb_controller.py +5 -4
- {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/METADATA +8 -10
- {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/RECORD +141 -163
- {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/WHEEL +1 -1
- wandb/apis/reports/v1/_blocks.py +0 -1406
- wandb/apis/reports/v1/_helpers.py +0 -70
- wandb/apis/reports/v1/_panels.py +0 -1282
- wandb/apis/reports/v1/_templates.py +0 -478
- wandb/apis/reports/v1/blocks.py +0 -27
- wandb/apis/reports/v1/helpers.py +0 -2
- wandb/apis/reports/v1/mutations.py +0 -66
- wandb/apis/reports/v1/panels.py +0 -17
- wandb/apis/reports/v1/report.py +0 -268
- wandb/apis/reports/v1/runset.py +0 -144
- wandb/apis/reports/v1/templates.py +0 -7
- wandb/apis/reports/v1/util.py +0 -406
- wandb/apis/reports/v1/validators.py +0 -131
- wandb/apis/reports/v2/blocks.py +0 -25
- wandb/apis/reports/v2/expr_parsing.py +0 -257
- wandb/apis/reports/v2/gql.py +0 -68
- wandb/apis/reports/v2/interface.py +0 -1911
- wandb/apis/reports/v2/internal.py +0 -867
- wandb/apis/reports/v2/metrics.py +0 -6
- wandb/apis/reports/v2/panels.py +0 -15
- wandb/catboost/__init__.py +0 -9
- wandb/fastai/__init__.py +0 -9
- wandb/keras/__init__.py +0 -19
- wandb/lightgbm/__init__.py +0 -9
- wandb/plots/__init__.py +0 -6
- wandb/plots/explain_text.py +0 -36
- wandb/plots/heatmap.py +0 -81
- wandb/plots/named_entity.py +0 -43
- wandb/plots/part_of_speech.py +0 -50
- wandb/plots/plot_definitions.py +0 -768
- wandb/plots/precision_recall.py +0 -121
- wandb/plots/roc.py +0 -103
- wandb/sacred/__init__.py +0 -3
- wandb/xgboost/__init__.py +0 -9
- {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/entry_points.txt +0 -0
- {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,257 +0,0 @@
|
|
1
|
-
import ast
|
2
|
-
import sys
|
3
|
-
from typing import Any
|
4
|
-
|
5
|
-
from .internal import Filters, Key
|
6
|
-
|
7
|
-
section_map = {
|
8
|
-
"Config": "config",
|
9
|
-
"SummaryMetric": "summary",
|
10
|
-
"KeysInfo": "keys_info",
|
11
|
-
"Tags": "tags",
|
12
|
-
"Metric": "run",
|
13
|
-
}
|
14
|
-
section_map_reversed = {v: k for k, v in section_map.items()}
|
15
|
-
|
16
|
-
fe_name_map = {
|
17
|
-
"ID": "name",
|
18
|
-
"Name": "displayName",
|
19
|
-
"Tags": "tags",
|
20
|
-
"State": "state",
|
21
|
-
"CreatedTimestamp": "createdAt",
|
22
|
-
"Runtime": "duration",
|
23
|
-
"User": "username",
|
24
|
-
"Sweep": "sweep",
|
25
|
-
"Group": "group",
|
26
|
-
"JobType": "jobType",
|
27
|
-
"Hostname": "host",
|
28
|
-
"UsingArtifact": "inputArtifacts",
|
29
|
-
"OutputtingArtifact": "outputArtifacts",
|
30
|
-
"Step": "_step",
|
31
|
-
"RelativeTime(Wall)": "_absolute_runtime",
|
32
|
-
"RelativeTime(Process)": "_runtime",
|
33
|
-
"WallTime": "_timestamp",
|
34
|
-
# "GroupedRuns": "__wb_group_by_all"
|
35
|
-
}
|
36
|
-
fe_name_map_reversed = {v: k for k, v in fe_name_map.items()}
|
37
|
-
|
38
|
-
|
39
|
-
def expr_to_filters(expr: str) -> Filters:
|
40
|
-
if not expr:
|
41
|
-
filters = []
|
42
|
-
else:
|
43
|
-
parsed_expr = ast.parse(expr, mode="eval")
|
44
|
-
filters = [_parse_node(parsed_expr.body)]
|
45
|
-
|
46
|
-
return Filters(op="OR", filters=[Filters(op="AND", filters=filters)])
|
47
|
-
|
48
|
-
|
49
|
-
def _parse_node(node) -> Filters:
|
50
|
-
if isinstance(node, ast.Compare):
|
51
|
-
# Check if left side is a function call
|
52
|
-
if isinstance(node.left, ast.Call):
|
53
|
-
func_call_data = _handle_function_call(node.left)
|
54
|
-
# Process the function call data
|
55
|
-
if func_call_data:
|
56
|
-
section = section_map.get(func_call_data["type"], "default_section")
|
57
|
-
key = Key(section=section, name=func_call_data["value"])
|
58
|
-
# Construct the Filters object
|
59
|
-
op = _map_op(node.ops[0])
|
60
|
-
right_operand = _extract_value(node.comparators[0])
|
61
|
-
return Filters(op=op, key=key, value=right_operand, disabled=False)
|
62
|
-
else:
|
63
|
-
# Handle other cases, e.g., when left side is not a function call
|
64
|
-
return _handle_comparison(node)
|
65
|
-
elif isinstance(node, ast.BoolOp):
|
66
|
-
return _handle_logical_op(node)
|
67
|
-
else:
|
68
|
-
raise ValueError(f"Unsupported expression type: {type(node)}")
|
69
|
-
|
70
|
-
|
71
|
-
def _map_op(op_node) -> str:
|
72
|
-
# Map the AST operation node to a string repr
|
73
|
-
op_map = {
|
74
|
-
ast.Gt: ">",
|
75
|
-
ast.Lt: "<",
|
76
|
-
ast.Eq: "==",
|
77
|
-
ast.NotEq: "!=",
|
78
|
-
ast.GtE: ">=",
|
79
|
-
ast.LtE: "<=",
|
80
|
-
ast.In: "IN",
|
81
|
-
ast.NotIn: "NIN",
|
82
|
-
}
|
83
|
-
return op_map[type(op_node)]
|
84
|
-
|
85
|
-
|
86
|
-
def _handle_comparison(node) -> Filters:
|
87
|
-
op_map = {
|
88
|
-
"Gt": ">",
|
89
|
-
"Lt": "<",
|
90
|
-
"Eq": "==",
|
91
|
-
"NotEq": "!=",
|
92
|
-
"GtE": ">=",
|
93
|
-
"LtE": "<=",
|
94
|
-
"In": "IN",
|
95
|
-
"NotIn": "NIN",
|
96
|
-
}
|
97
|
-
|
98
|
-
left_operand = node.left.id if isinstance(node.left, ast.Name) else None
|
99
|
-
left_operand_mapped = to_frontend_name(left_operand)
|
100
|
-
right_operand = _extract_value(node.comparators[0])
|
101
|
-
operation = type(node.ops[0]).__name__
|
102
|
-
|
103
|
-
return Filters(
|
104
|
-
op=op_map.get(operation),
|
105
|
-
key=_server_path_to_key(left_operand) if left_operand_mapped else None,
|
106
|
-
value=right_operand,
|
107
|
-
disabled=False,
|
108
|
-
)
|
109
|
-
|
110
|
-
|
111
|
-
def _handle_function_call(node) -> dict:
|
112
|
-
if isinstance(node.func, ast.Name):
|
113
|
-
func_name = node.func.id
|
114
|
-
if func_name in ["Config", "SummaryMetric", "KeysInfo", "Tags", "Metric"]:
|
115
|
-
if len(node.args) == 1 and isinstance(node.args[0], ast.Str):
|
116
|
-
arg_value = node.args[0].s
|
117
|
-
return {"type": func_name, "value": arg_value}
|
118
|
-
else:
|
119
|
-
raise ValueError(f"Invalid arguments for {func_name}")
|
120
|
-
else:
|
121
|
-
raise ValueError("Unsupported function call")
|
122
|
-
|
123
|
-
|
124
|
-
def _extract_value(node) -> Any:
|
125
|
-
if sys.version_info < (3, 8) and isinstance(node, ast.Num):
|
126
|
-
return node.n
|
127
|
-
if isinstance(node, ast.Constant):
|
128
|
-
return node.n
|
129
|
-
if isinstance(node, ast.List) or isinstance(node, ast.Tuple):
|
130
|
-
return [_extract_value(element) for element in node.elts]
|
131
|
-
if isinstance(node, ast.Name):
|
132
|
-
return node.id
|
133
|
-
raise ValueError(f"Unsupported value type: {type(node)}")
|
134
|
-
|
135
|
-
|
136
|
-
def _handle_logical_op(node) -> Filters:
|
137
|
-
op = "AND" if isinstance(node.op, ast.And) else "OR"
|
138
|
-
filters = [_parse_node(n) for n in node.values]
|
139
|
-
|
140
|
-
return Filters(op=op, filters=filters)
|
141
|
-
|
142
|
-
|
143
|
-
def filters_to_expr(filter_obj: Any, is_root=True) -> str:
|
144
|
-
op_map = {
|
145
|
-
">": ">",
|
146
|
-
"<": "<",
|
147
|
-
"=": "==",
|
148
|
-
"==": "==",
|
149
|
-
"!=": "!=",
|
150
|
-
">=": ">=",
|
151
|
-
"<=": "<=",
|
152
|
-
"IN": "in",
|
153
|
-
"NIN": "not in",
|
154
|
-
"AND": "and",
|
155
|
-
"OR": "or",
|
156
|
-
}
|
157
|
-
|
158
|
-
def _convert_filter(filter: Any, is_root: bool) -> str:
|
159
|
-
if hasattr(filter, "filters") and filter.filters is not None:
|
160
|
-
sub_expressions = [
|
161
|
-
_convert_filter(f, False)
|
162
|
-
for f in filter.filters
|
163
|
-
if f.filters is not None or (f.key and f.key.name)
|
164
|
-
]
|
165
|
-
if not sub_expressions:
|
166
|
-
return ""
|
167
|
-
|
168
|
-
joint = " and " if filter.op == "AND" else " or "
|
169
|
-
expr = joint.join(sub_expressions)
|
170
|
-
return f"({expr})" if not is_root and sub_expressions else expr
|
171
|
-
else:
|
172
|
-
if not filter.key or not filter.key.name:
|
173
|
-
# Skip filters with empty key names
|
174
|
-
return ""
|
175
|
-
|
176
|
-
key_name = filter.key.name
|
177
|
-
section = filter.key.section
|
178
|
-
|
179
|
-
# Prepend the function name if the section matches
|
180
|
-
if section in section_map_reversed:
|
181
|
-
function_name = section_map_reversed[section]
|
182
|
-
key_name = f'{function_name}("{key_name}")'
|
183
|
-
|
184
|
-
value = filter.value
|
185
|
-
if value is None:
|
186
|
-
value = "None"
|
187
|
-
elif isinstance(value, list):
|
188
|
-
value = f"[{', '.join(map(str, value))}]"
|
189
|
-
elif isinstance(value, str):
|
190
|
-
value = f"'{value}'"
|
191
|
-
|
192
|
-
return f"{key_name} {op_map[filter.op]} {value}"
|
193
|
-
|
194
|
-
return _convert_filter(filter_obj, is_root)
|
195
|
-
|
196
|
-
|
197
|
-
def _key_to_server_path(key: Key):
|
198
|
-
name = key.name
|
199
|
-
section = key.section
|
200
|
-
if section == "config":
|
201
|
-
return f"config.{name}"
|
202
|
-
elif section == "summary":
|
203
|
-
return f"summary_metrics.{name}"
|
204
|
-
elif section == "keys_info":
|
205
|
-
return f"keys_info.keys.{name}"
|
206
|
-
elif section == "tags":
|
207
|
-
return f"tags.{name}"
|
208
|
-
elif section == "runs":
|
209
|
-
return name
|
210
|
-
raise ValueError(f"Invalid key ({key})")
|
211
|
-
# raise ValueError(f"Invalid {key=}")
|
212
|
-
|
213
|
-
|
214
|
-
def _server_path_to_key(path):
|
215
|
-
if path.startswith("config."):
|
216
|
-
return Key(section="config", name=path.split("config.", 1)[1])
|
217
|
-
elif path.startswith("summary_metrics."):
|
218
|
-
return Key(section="summary", name=path.split("summary_metrics.", 1)[1])
|
219
|
-
elif path.startswith("keys_info.keys."):
|
220
|
-
return Key(section="keys_info", name=path.split("keys_info.keys.", 1)[1])
|
221
|
-
elif path.startswith("tags."):
|
222
|
-
return Key(section="tags", name=path.split("tags.", 1)[1])
|
223
|
-
else:
|
224
|
-
return Key(section="run", name=path)
|
225
|
-
|
226
|
-
|
227
|
-
class CustomNodeVisitor(ast.NodeVisitor):
|
228
|
-
def visit_Compare(self, node): # noqa: N802
|
229
|
-
left = self.handle_expression(node.left)
|
230
|
-
print(f"Expression type: {left}")
|
231
|
-
# Continue to handle the comparison operators and right side as needed
|
232
|
-
self.generic_visit(node)
|
233
|
-
|
234
|
-
def handle_expression(self, node):
|
235
|
-
if isinstance(node, ast.Call) and isinstance(node.func, ast.Name):
|
236
|
-
func_name = node.func.id
|
237
|
-
if func_name in ["Config", "SummaryMetric", "KeysInfo", "Tags", "Metric"]:
|
238
|
-
if len(node.args) == 1 and isinstance(node.args[0], ast.Str):
|
239
|
-
arg_value = node.args[0].s
|
240
|
-
return func_name, arg_value
|
241
|
-
return self.get_full_expression(node)
|
242
|
-
|
243
|
-
def get_full_expression(self, node):
|
244
|
-
if isinstance(node, ast.Attribute):
|
245
|
-
return self.get_full_expression(node.value) + "." + node.attr
|
246
|
-
elif isinstance(node, ast.Name):
|
247
|
-
return node.id
|
248
|
-
else:
|
249
|
-
return "ArbitraryExpression"
|
250
|
-
|
251
|
-
|
252
|
-
def to_frontend_name(name):
|
253
|
-
return fe_name_map_reversed.get(name, name)
|
254
|
-
|
255
|
-
|
256
|
-
def to_backend_name(name):
|
257
|
-
return fe_name_map.get(name, name)
|
wandb/apis/reports/v2/gql.py
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
"""GraphQL queries and mutations."""
|
2
|
-
|
3
|
-
from wandb_gql import gql
|
4
|
-
|
5
|
-
view_report = gql(
|
6
|
-
"""
|
7
|
-
query SpecificReport($reportId: ID!) {
|
8
|
-
view(id: $reportId) {
|
9
|
-
id
|
10
|
-
name
|
11
|
-
displayName
|
12
|
-
description
|
13
|
-
project {
|
14
|
-
id
|
15
|
-
name
|
16
|
-
entityName
|
17
|
-
}
|
18
|
-
createdAt
|
19
|
-
updatedAt
|
20
|
-
spec
|
21
|
-
}
|
22
|
-
}
|
23
|
-
"""
|
24
|
-
)
|
25
|
-
upsert_view = gql(
|
26
|
-
"""
|
27
|
-
mutation upsertView(
|
28
|
-
$id: ID
|
29
|
-
$entityName: String
|
30
|
-
$projectName: String
|
31
|
-
$type: String
|
32
|
-
$name: String
|
33
|
-
$displayName: String
|
34
|
-
$description: String
|
35
|
-
$spec: String!
|
36
|
-
) {
|
37
|
-
upsertView(
|
38
|
-
input: {
|
39
|
-
id: $id
|
40
|
-
entityName: $entityName
|
41
|
-
projectName: $projectName
|
42
|
-
name: $name
|
43
|
-
displayName: $displayName
|
44
|
-
description: $description
|
45
|
-
type: $type
|
46
|
-
createdUsing: WANDB_SDK
|
47
|
-
spec: $spec
|
48
|
-
}
|
49
|
-
) {
|
50
|
-
view {
|
51
|
-
id
|
52
|
-
type
|
53
|
-
name
|
54
|
-
displayName
|
55
|
-
description
|
56
|
-
project {
|
57
|
-
id
|
58
|
-
name
|
59
|
-
entityName
|
60
|
-
}
|
61
|
-
spec
|
62
|
-
updatedAt
|
63
|
-
}
|
64
|
-
inserted
|
65
|
-
}
|
66
|
-
}
|
67
|
-
"""
|
68
|
-
)
|