Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

plugins: add sample dynamically loaded plugin #2354

Merged
merged 37 commits into from
Jun 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9d48d06
plugins: add sample dynamically loaded plugin
wchargin Jun 17, 2019
cbe9900
[update patch]
wchargin Jun 18, 2019
6b7e05f
build: add tool to create deterministic tarballs
wchargin Jun 19, 2019
85d0506
build: promote Pip wheels to Bazel target
wchargin Jun 19, 2019
c26bbed
[update patch]
wchargin Jun 19, 2019
108311c
[update patch]
wchargin Jun 19, 2019
520d6af
[update diffbase]
wchargin Jun 19, 2019
ad7525b
[update patch]
wchargin Jun 19, 2019
e5c46c1
[update diffbase]
wchargin Jun 20, 2019
c926824
[update diffbase]
wchargin Jun 20, 2019
31f983c
[update patch]
wchargin Jun 20, 2019
8f8969a
[update diffbase]
wchargin Jun 20, 2019
3a275b3
[update diffbase]
wchargin Jun 21, 2019
0a2ac6f
[update patch]
wchargin Jun 21, 2019
b21fab7
[update diffbase]
wchargin Jun 21, 2019
34ad6f2
[update diffbase]
wchargin Jun 21, 2019
a54bc1f
[update patch]
wchargin Jun 21, 2019
96e5f3e
[update diffbase]
wchargin Jun 21, 2019
c4dbf87
[update diffbase]
wchargin Jun 21, 2019
fd52361
[update patch]
wchargin Jun 21, 2019
bfa68da
[update diffbase]
wchargin Jun 21, 2019
7a36bfb
[update diffbase]
wchargin Jun 21, 2019
84fca45
[update diffbase]
wchargin Jun 21, 2019
1ac66bf
[update patch]
wchargin Jun 21, 2019
e449e0a
[update diffbase]
wchargin Jun 21, 2019
ec7c8ed
[update diffbase]
wchargin Jun 21, 2019
ab53019
[update diffbase]
wchargin Jun 21, 2019
ae637d6
[update patch]
wchargin Jun 21, 2019
ff926b3
[update diffbase]
wchargin Jun 21, 2019
88addad
[update patch]
wchargin Jun 21, 2019
5177e0f
[update diffbase]
wchargin Jun 21, 2019
0b6e008
[update patch]
wchargin Jun 21, 2019
8e978a8
[update diffbase]
wchargin Jun 21, 2019
9589be3
[update patch]
wchargin Jun 21, 2019
b8b25e1
[update diffbase]
wchargin Jun 21, 2019
83935c4
[update diffbase]
wchargin Jun 24, 2019
3d46cd7
[update diffbase]
wchargin Jun 24, 2019
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
21 changes: 21 additions & 0 deletions tensorboard/plugins/example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2019 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.
# ==============================================================================

# Generated by running `python setup.py develop`.
tensorboard_plugin_example.egg-info/

# Generated by running `python setup.py bdist_wheel`.
build/
dist/
25 changes: 25 additions & 0 deletions tensorboard/plugins/example/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Description:
# TensorBoard example plugin

# This plugin is not primarily built with Bazel (intentionally, to
# demonstrate that Bazel is not required); we use this BUILD file only
# to define integration tests for TensorBoard itself.

package(default_visibility = ["//tensorboard:internal"])

licenses(["notice"]) # Apache 2.0

sh_test(
name = "smoke_test",
size = "large",
timeout = "short",
srcs = ["smoke_test.sh"],
# Don't just `glob(["**"])` because `setup.py` creates artifacts
# like wheels and a `tensorboard_plugin_example.egg-info` directory,
# and we want to make sure that those don't interfere with the test.
data = [
"setup.py",
"tensorboard_plugin_example/__init__.py",
"//tensorboard/pip_package",
] + glob(["tensorboard_plugin_example/static/**"]),
)
48 changes: 48 additions & 0 deletions tensorboard/plugins/example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Example plugin

## Overview

A sample plugin using TensorBoard’s dynamic plugin loading mechanism. It
doesn’t do anything useful at the moment, but a stock TensorBoard binary
(1.14+) will automatically load and display it.

This code happens to live in the TensorBoard repository, but is intended
to stand in for a third-party plugin developer’s separate repository. It
is not built with Bazel, and it only depends on TensorBoard through its
public APIs (under the assumption that TensorBoard is installed in an
active virtualenv).

## Usage

In this directory (`tensorboard/plugins/example`), in a virtualenv with
TensorBoard installed, run:

```
python setup.py develop
```

This will link the plugin into your virtualenv. You can edit the
plugin’s source code and data files and see changes reflected without
having to reinstall the plugin.

Then, just run

```
tensorboard --logdir /tmp/whatever
```

and open TensorBoard to see the plugin’s “hello world” screen.

After making changes to the Python code, you must restart TensorBoard
for your changes to take effect. If your plugin reads data files at
runtime, you can edit those and see changes reflected immediately.

You can run

```
python setup.py develop --uninstall
```

to unlink the plugin from your virtualenv, after which you can also
delete the `tensorboard_plugin_example.egg-info/` directory that the
original `setup.py` invocation created.
36 changes: 36 additions & 0 deletions tensorboard/plugins/example/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright 2019 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.
# ==============================================================================

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

import setuptools


setuptools.setup(
name="tensorboard_plugin_example",
version="0.1.0",
description="Sample TensorBoard plugin.",
packages=["tensorboard_plugin_example"],
package_data={
"tensorboard_plugin_example": ["static/**"],
},
entry_points={
"tensorboard_plugins": [
"example = tensorboard_plugin_example:ExamplePlugin",
],
},
)
61 changes: 61 additions & 0 deletions tensorboard/plugins/example/smoke_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/bin/sh
# Copyright 2019 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.

set -eux
command -v virtualenv >/dev/null

workdir="$(mktemp -d)"
cd "${workdir}"

cleanup() {
rm -r "${workdir}"
}
trap cleanup EXIT

cp -LR "${TEST_SRCDIR}/org_tensorflow_tensorboard/tensorboard/plugins/example/" \
./example-plugin/

mkdir tensorboard-wheels
tar xzvf \
"${TEST_SRCDIR}/org_tensorflow_tensorboard/tensorboard/pip_package/pip_packages.tar.gz" \
-C ./tensorboard-wheels/

virtualenv venv
export VIRTUAL_ENV=venv
export PATH="${PWD}/venv/bin:${PATH}"
unset PYTHON_HOME

# Require wheel for bdist_wheel command, and setuptools 36.2.0+ so that
# env markers are handled (https://github.com/pypa/setuptools/pull/1081)
pip install -qU wheel 'setuptools>=36.2.0'

(cd ./example-plugin && python setup.py bdist_wheel)
[ -f ./example-plugin/dist/*.whl ] # just one wheel

# This plugin doesn't require TensorFlow, so we don't install it.
py_major_version="$(python -c 'import sys; print(sys.version_info[0])')"
pip install ./tensorboard-wheels/*py"${py_major_version}"*.whl
pip install ./example-plugin/dist/*.whl

# Test tensorboard + tensorboard_plugin_example integration.
mkfifo pipe
tensorboard --port=0 --logdir=smokedir 2>pipe &
perl -ne 'print STDERR;/http:.*:(\d+)/ and print $1.v10 and exit 0' <pipe >port
curl -fs "http://localhost:$(cat port)/data/plugins_listing" >plugins_listing
grep -F '"example":' plugins_listing
grep -F '"/data/plugin/example/index.js"' plugins_listing
curl -fs "http://localhost:$(cat port)/data/plugin/example/index.js" >index.js
diff -u example-plugin/tensorboard_plugin_example/static/index.js index.js
kill $!
60 changes: 60 additions & 0 deletions tensorboard/plugins/example/tensorboard_plugin_example/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Copyright 2019 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.
# ==============================================================================
"""A sample plugin to demonstrate dynamic loading."""

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

import os

from tensorboard.plugins import base_plugin
import werkzeug
from werkzeug import wrappers


class ExamplePlugin(base_plugin.TBPlugin):
plugin_name = 'example'

def __init__(self, context):
# A real plugin would likely save the `context.multiplexer` and/or
# `context.db_connection_provider` attributes for later use, but we
# don't actually need any of that.
pass

def is_active(self):
return True

def get_plugin_apps(self):
return {
"/index.js": self._serve_js,
}

def frontend_metadata(self):
return super(ExamplePlugin, self).frontend_metadata()._replace(
es_module_path="/index.js",
)

@wrappers.Request.application
def _serve_js(self, request):
del request # unused
filepath = os.path.join(os.path.dirname(__file__), "static", "index.js")
with open(filepath) as infile:
contents = infile.read()
return werkzeug.Response(
contents,
status=200,
content_type="application/javascript",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2019 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.
// ==============================================================================

export function render() {
const msg = document.createElement("span");
msg.innerText = "Hello TensorBoard!";
document.body.appendChild(msg);
}