Skip to content

Commit cbc3494

Browse files
authored
frontend: use experiment ID from path, not query (#2736)
Summary: This commit changes the frontend experiment ID plumbing from using the query string to using a path component: experiment URLs are now of the form `http://localhost:6006/experiment/123/`. This supersedes the short-term changes from #2580, #2613, and #2627. Test Plan: Apply the below patch to the multiplexer data provider, then launch TensorBoard with `--generic_data=true` and verify that the correct experiment ID is printed for each call, at `/` and at `/experiment/123`. Verify also that no request has an `experiment` query parameter. Patch: ```diff diff --git a/tensorboard/backend/event_processing/data_provider.py b/tensorboard/backend/event_processing/data_provider.py index 0b354aa..1c00b930 100644 --- a/tensorboard/backend/event_processing/data_provider.py +++ b/tensorboard/backend/event_processing/data_provider.py @@ -59,2 +59,3 @@ class MultiplexerDataProvider(provider.DataProvider): def data_location(self, experiment_id): + logger.warn("data_location(%r)", experiment_id) del experiment_id # ignored @@ -63,2 +64,3 @@ class MultiplexerDataProvider(provider.DataProvider): def list_runs(self, experiment_id): + logger.warn("list_runs(%r)", experiment_id) del experiment_id # ignored for now @@ -74,2 +76,3 @@ class MultiplexerDataProvider(provider.DataProvider): def list_scalars(self, experiment_id, plugin_name, run_tag_filter=None): + logger.warn("list_scalars(%r, ...)", experiment_id) del experiment_id # ignored for now @@ -105,2 +108,3 @@ class MultiplexerDataProvider(provider.DataProvider): ): + logger.warn("read_scalars(%r, ...)", experiment_id) # TODO(@wchargin): Downsampling not implemented, as the multiplexer ``` wchargin-branch: eid-frontend
1 parent eddcdbf commit cbc3494

File tree

10 files changed

+32
-61
lines changed

10 files changed

+32
-61
lines changed

tensorboard/components/tf_backend/environmentStore.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ namespace tf_backend {
2222
private environment: Environment;
2323

2424
load() {
25-
const url = tf_backend
26-
.getRouter()
27-
.environment(tf_backend.getExperimentId());
25+
const url = tf_backend.getRouter().environment();
2826
return this.requestManager.request(url).then((result) => {
2927
const environment = {
3028
dataLocation: result.data_location,

tensorboard/components/tf_backend/router.ts

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ limitations under the License.
1414
==============================================================================*/
1515
namespace tf_backend {
1616
export interface Router {
17-
environment: (experiment?: string) => string;
17+
environment: () => string;
1818
experiments: () => string;
1919
pluginRoute: (
2020
pluginName: string,
2121
route: string,
2222
params?: URLSearchParams
2323
) => string;
2424
pluginsListing: () => string;
25-
runs: (experiment?: string) => string;
25+
runs: () => string;
2626
runsForExperiment: (id: tf_backend.ExperimentId) => string;
2727
}
2828

@@ -39,11 +39,7 @@ namespace tf_backend {
3939
dataDir = dataDir.slice(0, dataDir.length - 1);
4040
}
4141
return {
42-
environment: (experiment?: string) => {
43-
const searchParams = new URLSearchParams();
44-
searchParams.set('experiment', experiment || '');
45-
return createDataPath(dataDir, '/environment', searchParams);
46-
},
42+
environment: () => createDataPath(dataDir, '/environment'),
4743
experiments: () => createDataPath(dataDir, '/experiments'),
4844
pluginRoute: (
4945
pluginName: string,
@@ -57,11 +53,7 @@ namespace tf_backend {
5753
);
5854
},
5955
pluginsListing: () => createDataPath(dataDir, '/plugins_listing'),
60-
runs: (experiment?: string) => {
61-
const searchParams = new URLSearchParams();
62-
searchParams.set('experiment', experiment || '');
63-
return createDataPath(dataDir, '/runs', searchParams);
64-
},
56+
runs: () => createDataPath(dataDir, '/runs'),
6557
runsForExperiment: (id) => {
6658
return createDataPath(
6759
dataDir,
@@ -79,13 +71,6 @@ namespace tf_backend {
7971
return _router;
8072
}
8173

82-
/**
83-
* @return {string} the experiment ID for the currently loaded page
84-
*/
85-
export function getExperimentId() {
86-
return new URLSearchParams(window.location.search).get('experiment') || '';
87-
}
88-
8974
/**
9075
* Set the global router, to be returned by future calls to `getRouter`.
9176
* You may wish to invoke this if you are running a demo server with a

tensorboard/components/tf_backend/runsStore.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace tf_backend {
1717
private _runs: string[] = [];
1818

1919
load() {
20-
const url = tf_backend.getRouter().runs(tf_backend.getExperimentId());
20+
const url = tf_backend.getRouter().runs();
2121
return this.requestManager.request(url).then((newRuns) => {
2222
if (!_.isEqual(this._runs, newRuns)) {
2323
this._runs = newRuns;

tensorboard/components/tf_backend/test/backendTests.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,22 +82,22 @@ namespace tf_backend {
8282

8383
it('leading slash in pathPrefix is an absolute path', () => {
8484
const router = createRouter('/data/');
85-
assert.equal(router.runs(), '/data/runs?experiment=');
85+
assert.equal(router.runs(), '/data/runs');
8686
});
8787

8888
it('returns complete pathname when pathPrefix omits slash', () => {
8989
const router = createRouter('data/');
90-
assert.equal(router.runs(), 'data/runs?experiment=');
90+
assert.equal(router.runs(), 'data/runs');
9191
});
9292

9393
it('does not prune many leading slashes that forms full url', () => {
9494
const router = createRouter('///data/hello');
95-
// This becomes 'http://data/hello/runs?experiment='
96-
assert.equal(router.runs(), '///data/hello/runs?experiment=');
95+
// This becomes 'http://data/hello/runs'
96+
assert.equal(router.runs(), '///data/hello/runs');
9797
});
9898

9999
it('returns correct value for #environment', () => {
100-
assert.equal(router.environment(), 'data/environment?experiment=');
100+
assert.equal(router.environment(), 'data/environment');
101101
});
102102

103103
it('returns correct value for #experiments', () => {
@@ -177,7 +177,7 @@ namespace tf_backend {
177177
});
178178

179179
it('returns correct value for #runs', () => {
180-
assert.equal(router.runs(), 'data/runs?experiment=');
180+
assert.equal(router.runs(), 'data/runs');
181181
});
182182

183183
it('returns correct value for #runsForExperiment', () => {

tensorboard/plugins/core/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ py_library(
1616
srcs_version = "PY2AND3",
1717
visibility = ["//visibility:public"],
1818
deps = [
19+
"//tensorboard:plugin_util",
1920
"//tensorboard/backend:http_util",
2021
"//tensorboard/plugins:base_plugin",
2122
"//tensorboard/util:tb_logging",

tensorboard/plugins/core/core_plugin.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from werkzeug import utils
3131
from werkzeug import wrappers
3232

33+
from tensorboard import plugin_util
3334
from tensorboard.backend import http_util
3435
from tensorboard.plugins import base_plugin
3536
from tensorboard.util import tb_logging
@@ -122,7 +123,7 @@ def _serve_environment(self, request):
122123
* window_title is the title of the TensorBoard web page.
123124
"""
124125
if self._data_provider:
125-
experiment = request.args.get('experiment', '')
126+
experiment = plugin_util.experiment_id(request.environ)
126127
data_location = self._data_provider.data_location(experiment)
127128
else:
128129
data_location = self._logdir or self._db_uri
@@ -159,7 +160,7 @@ def _serve_runs(self, request):
159160
last, and then ties are broken by sorting on the run name.
160161
"""
161162
if self._data_provider:
162-
experiment = request.args.get('experiment', '')
163+
experiment = plugin_util.experiment_id(request.environ)
163164
runs = sorted(
164165
self._data_provider.list_runs(experiment_id=experiment),
165166
key=lambda run: (
@@ -235,7 +236,7 @@ def _serve_experiment_runs(self, request):
235236
"""
236237
results = []
237238
if self._db_connection_provider:
238-
exp_id = request.args.get('experiment')
239+
exp_id = plugin_util.experiment_id(request.environ)
239240
runs_dict = collections.OrderedDict()
240241

241242
db = self._db_connection_provider()

tensorboard/plugins/core/core_plugin_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ def testExperimentRuns(self):
189189
[exp1, exp2] = self._get_json(self.db_based_server, '/data/experiments')
190190

191191
exp1_runs = self._get_json(self.db_based_server,
192-
'/data/experiment_runs?experiment=%s' % exp1.get('id'))
192+
'/experiment/%s/data/experiment_runs' % exp1.get('id'))
193193
self.assertEqual(len(exp1_runs), 2);
194194
self.assertEqual(exp1_runs[0].get('name'), 'run1');
195195
self.assertEqual(exp1_runs[1].get('name'), 'run2');
@@ -199,7 +199,7 @@ def testExperimentRuns(self):
199199
self.assertEqual(exp1_runs[1].get('tags')[0].get('name'), 'mytag');
200200

201201
exp2_runs = self._get_json(self.db_based_server,
202-
'/data/experiment_runs?experiment=%s' % exp2.get('id'))
202+
'/experiment/%s/data/experiment_runs' % exp2.get('id'))
203203
self.assertEqual(len(exp2_runs), 1);
204204
self.assertEqual(exp2_runs[0].get('name'), 'run3');
205205

tensorboard/plugins/scalar/scalars_plugin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ def _get_value(self, scalar_data_blob, dtype_enum):
235235

236236
@wrappers.Request.application
237237
def tags_route(self, request):
238-
experiment = request.args.get('experiment', '')
238+
experiment = plugin_util.experiment_id(request.environ)
239239
index = self.index_impl(experiment=experiment)
240240
return http_util.Respond(request, index, 'application/json')
241241

@@ -244,7 +244,7 @@ def scalars_route(self, request):
244244
"""Given a tag and single run, return array of ScalarEvents."""
245245
tag = request.args.get('tag')
246246
run = request.args.get('run')
247-
experiment = request.args.get('experiment', '')
247+
experiment = plugin_util.experiment_id(request.environ)
248248
output_format = request.args.get('format')
249249
(body, mime_type) = self.scalars_impl(tag, run, experiment, output_format)
250250
return http_util.Respond(request, body, mime_type)

tensorboard/plugins/scalar/tf_scalar_dashboard/tf-scalar-card.html

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -234,16 +234,14 @@
234234
getDataLoadUrl: {
235235
type: Function,
236236
value: function() {
237-
return ({tag, run, experiment}) => {
238-
return tf_backend.getRouter().pluginRoute(
239-
'scalars',
240-
'/scalars',
241-
new URLSearchParams({
242-
tag,
243-
run,
244-
experiment: experiment || '',
245-
})
246-
);
237+
return ({tag, run}) => {
238+
return tf_backend
239+
.getRouter()
240+
.pluginRoute(
241+
'scalars',
242+
'/scalars',
243+
new URLSearchParams({tag, run})
244+
);
247245
};
248246
},
249247
},
@@ -252,12 +250,7 @@
252250
_downloadUrlFn: {
253251
type: Function,
254252
value: function() {
255-
return (tag, run) =>
256-
this.getDataLoadUrl({
257-
tag,
258-
run,
259-
experiment: tf_backend.getExperimentId(),
260-
});
253+
return (tag, run) => this.getDataLoadUrl({tag, run});
261254
},
262255
},
263256

tensorboard/plugins/scalar/tf_scalar_dashboard/tf-scalar-dashboard.html

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -309,13 +309,7 @@ <h3>No scalar data was found.</h3>
309309
});
310310
},
311311
_fetchTags() {
312-
const url = tf_backend
313-
.getRouter()
314-
.pluginRoute(
315-
'scalars',
316-
'/tags',
317-
new URLSearchParams({experiment: tf_backend.getExperimentId()})
318-
);
312+
const url = tf_backend.getRouter().pluginRoute('scalars', '/tags');
319313
return this._requestManager.request(url).then((runToTagInfo) => {
320314
if (_.isEqual(runToTagInfo, this._runToTagInfo)) {
321315
// No need to update anything if there are no changes.
@@ -351,11 +345,10 @@ <h3>No scalar data was found.</h3>
351345
selectedRuns,
352346
query
353347
);
354-
const experiment = tf_backend.getExperimentId();
355348
categories.forEach((category) => {
356349
category.items = category.items.map((item) => ({
357350
tag: item.tag,
358-
series: item.runs.map((run) => ({run, tag: item.tag, experiment})),
351+
series: item.runs.map((run) => ({run, tag: item.tag})),
359352
}));
360353
});
361354
this.updateArrayProp('_categories', categories, this._getCategoryKey);

0 commit comments

Comments
 (0)