Skip to content

Commit 1c275c4

Browse files
authored
(TensorBoard.dev) Uploader delete functionality supports more than one experiment_id at a time. (#5471)
1 parent d8dd761 commit 1c275c4

File tree

4 files changed

+299
-30
lines changed

4 files changed

+299
-30
lines changed

tensorboard/uploader/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ py_test(
9292
":uploader",
9393
":uploader_subcommand",
9494
"//tensorboard:expect_grpc_testing_installed",
95+
"//tensorboard/plugins:base_plugin",
9596
],
9697
)
9798

tensorboard/uploader/flags_parser.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,10 @@ def define_flags(parser):
180180
delete.add_argument(
181181
"--experiment_id",
182182
metavar="EXPERIMENT_ID",
183-
type=str,
184-
default=None,
185-
help="ID of an experiment to delete permanently",
183+
type=lambda option: option.split(","),
184+
default=[],
185+
help="ID of an experiment to delete permanently. Comma separated list"
186+
"of experiment ids is also supported.",
186187
)
187188

188189
list_parser = subparsers.add_parser(

tensorboard/uploader/uploader_subcommand.py

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -178,47 +178,82 @@ class _DeleteExperimentIntent(_Intent):
178178

179179
_MESSAGE_TEMPLATE = textwrap.dedent(
180180
"""\
181-
This will delete the experiment on https://tensorboard.dev with the
182-
following experiment ID:
181+
This will delete the {num} experiment(s) on
182+
https://tensorboard.dev with the following experiment ID(s):
183183
184-
{experiment_id}
184+
{experiment_id_list}
185185
186186
You have chosen to delete an experiment. All experiments uploaded
187187
to TensorBoard.dev are publicly visible. Do not upload sensitive
188188
data.
189189
"""
190190
)
191191

192-
def __init__(self, experiment_id):
193-
self.experiment_id = experiment_id
192+
def __init__(self, experiment_id_list):
193+
self.experiment_id_list = experiment_id_list
194194

195195
def get_ack_message_body(self):
196-
return self._MESSAGE_TEMPLATE.format(experiment_id=self.experiment_id)
196+
return self._MESSAGE_TEMPLATE.format(
197+
num=len(self.experiment_id_list),
198+
experiment_id_list=self.experiment_id_list,
199+
)
197200

198201
def execute(self, server_info, channel):
199202
api_client = write_service_pb2_grpc.TensorBoardWriterServiceStub(
200203
channel
201204
)
202-
experiment_id = self.experiment_id
203-
if not experiment_id:
205+
if not self.experiment_id_list:
204206
raise base_plugin.FlagsError(
205-
"Must specify a non-empty experiment ID to delete."
206-
)
207-
try:
208-
uploader_lib.delete_experiment(api_client, experiment_id)
209-
except uploader_lib.ExperimentNotFoundError:
210-
_die(
211-
"No such experiment %s. Either it never existed or it has "
212-
"already been deleted." % experiment_id
213-
)
214-
except uploader_lib.PermissionDeniedError:
215-
_die(
216-
"Cannot delete experiment %s because it is owned by a "
217-
"different user." % experiment_id
207+
"Must specify at least one experiment ID to delete."
218208
)
219-
except grpc.RpcError as e:
220-
_die("Internal error deleting experiment: %s" % e)
221-
print("Deleted experiment %s." % experiment_id)
209+
# Map from eid to (msg, action) pair.
210+
results = {}
211+
NO_ACTION = "NO_ACTION"
212+
DIE_ACTION = "DIE_ACTION"
213+
for experiment_id in set(self.experiment_id_list):
214+
if not experiment_id:
215+
results[experiment_id] = (
216+
"Skipping empty experiment_id.",
217+
NO_ACTION,
218+
)
219+
continue
220+
try:
221+
uploader_lib.delete_experiment(api_client, experiment_id)
222+
results[experiment_id] = (
223+
"Deleted experiment %s." % experiment_id,
224+
NO_ACTION,
225+
)
226+
except uploader_lib.ExperimentNotFoundError:
227+
results[experiment_id] = (
228+
"No such experiment %s. Either it never existed or it has "
229+
"already been deleted." % experiment_id,
230+
DIE_ACTION,
231+
)
232+
except uploader_lib.PermissionDeniedError:
233+
results[experiment_id] = (
234+
"Cannot delete experiment %s because it is owned by a "
235+
"different user." % experiment_id,
236+
DIE_ACTION,
237+
)
238+
except grpc.RpcError as e:
239+
results[experiment_id] = (
240+
(
241+
"Internal error deleting experiment %s: %s."
242+
% (experiment_id, e)
243+
),
244+
DIE_ACTION,
245+
)
246+
# business logic on the receipt
247+
any_die_action = False
248+
err_msg = ""
249+
for (msg, action) in results.values():
250+
if action == NO_ACTION:
251+
print(msg)
252+
if action == DIE_ACTION:
253+
err_msg += msg + "\n"
254+
any_die_action = True
255+
if any_die_action:
256+
_die(err_msg)
222257

223258

224259
class _UpdateMetadataIntent(_Intent):
@@ -576,7 +611,7 @@ def _get_intent(flags, experiment_url_callback=None):
576611
return _DeleteExperimentIntent(flags.experiment_id)
577612
else:
578613
raise base_plugin.FlagsError(
579-
"Must specify experiment to delete via `--experiment_id`."
614+
"Must specify experiment(s) to delete via `--experiment_id`."
580615
)
581616
elif cmd == flags_parser.SUBCOMMAND_KEY_LIST:
582617
return _ListIntent(json=flags.json)

0 commit comments

Comments
 (0)