Skip to content
Merged
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
19 changes: 19 additions & 0 deletions tensorboard/uploader/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ py_library(
":auth",
":dev_creds",
":exporter_lib",
":flags_parser",
":server_info",
":uploader_lib",
":util",
Expand Down Expand Up @@ -222,3 +223,21 @@ py_test(
"@org_pocoo_werkzeug",
],
)

py_library(
name = "flags_parser",
srcs = ["flags_parser.py"],
visibility = ["//tensorboard:internal"],
deps = [
"//tensorboard:expect_absl_flags_argparse_flags_installed",
],
)

py_test(
name = "flags_parser_test",
srcs = ["flags_parser_test.py"],
deps = [
":flags_parser",
"//tensorboard:test",
],
)
203 changes: 203 additions & 0 deletions tensorboard/uploader/flags_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
# Copyright 2020 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Flags parser for TensorBoard.dev uploader."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from absl.flags import argparse_flags

SUBCOMMAND_FLAG = "_uploader__subcommand"
SUBCOMMAND_KEY_UPLOAD = "UPLOAD"
SUBCOMMAND_KEY_DELETE = "DELETE"
SUBCOMMAND_KEY_LIST = "LIST"
SUBCOMMAND_KEY_EXPORT = "EXPORT"
SUBCOMMAND_KEY_UPDATE_METADATA = "UPDATEMETADATA"
SUBCOMMAND_KEY_AUTH = "AUTH"
AUTH_SUBCOMMAND_FLAG = "_uploader__subcommand_auth"
AUTH_SUBCOMMAND_KEY_REVOKE = "REVOKE"

DEFAULT_ORIGIN = "https://tensorboard.dev"


def parse_flags(argv):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK: For what it’s worth, this function is vestigial, and we can really
remove the entire //tensorboard/uploader entry point in favor of
//tensorboard/uploader:uploader_main_lib (which should probably be
renamed; it’s pretty confusing). But fine with me to keep deferring that
change, as it’s not hurting anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do it in a followup PR. But first I'll warn the TensorBoard team that we'll be getting rid of //tensorboard/uploader just in case anybody is still using it. And this function would essentially be moved into the test.

"""Parse flags for TensorBoard.dev uploader.

Exits if flag values are invalid.

Args:
argv: CLI arguments, as with `sys.argv`, where the first argument is taken
to be the name of the program being executed.
"""
parser = argparse_flags.ArgumentParser(
prog="uploader",
description=("Upload your TensorBoard experiments to TensorBoard.dev"),
)
define_flags(parser)
return parser.parse_args(argv[1:])


def define_flags(parser):
"""Configures flags on the provided argument parser.

Integration point for `tensorboard.program`'s subcommand system.

Args:
parser: An `argparse.ArgumentParser` to be mutated.
"""

subparsers = parser.add_subparsers()

parser.add_argument(
"--origin",
type=str,
default="",
help="Experimental. Origin for TensorBoard.dev service to which "
"to connect. If not set, defaults to %r." % DEFAULT_ORIGIN,
)

parser.add_argument(
"--api_endpoint",
type=str,
default="",
help="Experimental. Direct URL for the API server accepting "
"write requests. If set, will skip initial server handshake "
"unless `--origin` is also set.",
)

parser.add_argument(
"--grpc_creds_type",
type=str,
default="ssl",
choices=("local", "ssl", "ssl_dev"),
help="The type of credentials to use for the gRPC client",
)

parser.add_argument(
"--auth_force_console",
action="store_true",
help="Set to true to force authentication flow to use the "
"--console rather than a browser redirect to localhost.",
)

upload = subparsers.add_parser(
"upload", help="upload an experiment to TensorBoard.dev"
)
upload.set_defaults(**{SUBCOMMAND_FLAG: SUBCOMMAND_KEY_UPLOAD})
upload.add_argument(
"--logdir",
metavar="PATH",
type=str,
default=None,
help="Directory containing the logs to process",
)
upload.add_argument(
"--name",
type=str,
default=None,
help="Title of the experiment. Max 100 characters.",
)
upload.add_argument(
"--description",
type=str,
default=None,
help="Experiment description. Markdown format. Max 600 characters.",
)
upload.add_argument(
"--plugins",
type=str,
nargs="*",
default=[],
help="List of plugins for which data should be uploaded. If "
"unspecified then data will be uploaded for all plugins supported by "
"the server.",
)

update_metadata = subparsers.add_parser(
"update-metadata",
help="change the name, description, or other user "
"metadata associated with an experiment.",
)
update_metadata.set_defaults(
**{SUBCOMMAND_FLAG: SUBCOMMAND_KEY_UPDATE_METADATA}
)
update_metadata.add_argument(
"--experiment_id",
metavar="EXPERIMENT_ID",
type=str,
default=None,
help="ID of the experiment on which to modify the metadata.",
)
update_metadata.add_argument(
"--name",
type=str,
default=None,
help="Title of the experiment. Max 100 characters.",
)
update_metadata.add_argument(
"--description",
type=str,
default=None,
help="Experiment description. Markdown format. Max 600 characters.",
)

delete = subparsers.add_parser(
"delete",
help="permanently delete an experiment",
inherited_absl_flags=None,
)
delete.set_defaults(**{SUBCOMMAND_FLAG: SUBCOMMAND_KEY_DELETE})
# We would really like to call this next flag `--experiment` rather
# than `--experiment_id`, but this is broken inside Google due to a
# long-standing Python bug: <https://bugs.python.org/issue14365>
# (Some Google-internal dependencies define `--experimental_*` flags.)
# This isn't exactly a principled fix, but it gets the job done.
delete.add_argument(
"--experiment_id",
metavar="EXPERIMENT_ID",
type=str,
default=None,
help="ID of an experiment to delete permanently",
)

list_parser = subparsers.add_parser(
"list", help="list previously uploaded experiments"
)
list_parser.set_defaults(**{SUBCOMMAND_FLAG: SUBCOMMAND_KEY_LIST})

export = subparsers.add_parser(
"export", help="download all your experiment data"
)
export.set_defaults(**{SUBCOMMAND_FLAG: SUBCOMMAND_KEY_EXPORT})
export.add_argument(
"--outdir",
metavar="OUTPUT_PATH",
type=str,
default=None,
help="Directory into which to download all experiment data; "
"must not yet exist",
)

auth_parser = subparsers.add_parser("auth", help="log in, log out")
auth_parser.set_defaults(**{SUBCOMMAND_FLAG: SUBCOMMAND_KEY_AUTH})
auth_subparsers = auth_parser.add_subparsers()

auth_revoke = auth_subparsers.add_parser(
"revoke", help="revoke all existing credentials and log out"
)
auth_revoke.set_defaults(
**{AUTH_SUBCOMMAND_FLAG: AUTH_SUBCOMMAND_KEY_REVOKE}
)
61 changes: 61 additions & 0 deletions tensorboard/uploader/flags_parser_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Copyright 2020 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for tensorboard.uploader.flags_parser."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse

from tensorboard.uploader import flags_parser
from tensorboard import test as tb_test


class FlagsParserTest(tb_test.TestCase):
def test_unknown_command(self):
with self.assertRaises(SystemExit):
flags_parser.parse_flags(["uploader", "unknown"])

def test_list(self):
flags = flags_parser.parse_flags(["uploader", "list"])
self.assertEqual(
flags_parser.SUBCOMMAND_KEY_LIST,
getattr(flags, flags_parser.SUBCOMMAND_FLAG),
)

def test_upload_logdir(self):
flags = flags_parser.parse_flags(
["uploader", "upload", "--logdir", "some/log/dir"]
)
self.assertEqual(
flags_parser.SUBCOMMAND_KEY_UPLOAD,
getattr(flags, flags_parser.SUBCOMMAND_FLAG),
)
self.assertEqual("some/log/dir", flags.logdir)

def test_upload_with_plugins(self):
flags = flags_parser.parse_flags(
["uploader", "upload", "--plugins", "plugin1", "plugin2"]
)
self.assertEqual(
flags_parser.SUBCOMMAND_KEY_UPLOAD,
getattr(flags, flags_parser.SUBCOMMAND_FLAG),
)
self.assertEqual(["plugin1", "plugin2"], flags.plugins)


if __name__ == "__main__":
tb_test.main()
Loading