-
Notifications
You must be signed in to change notification settings - Fork 944
Add IS_BROWSER to ENV; add scheme-based URL router to tf.io.* modules #1034
Conversation
The currently supported schemes are: - localstorage:// for browser local storage - indexeddb:// for browser IndexedDB - downloads:// for browser file downloads - http:// and https:// fro browser HTTP requests Since browserLocalStorage, browserIndexedDB and browserDownloads are methods without any optional arguments and can be copmletely replaced by the URL-like strings, they are removed from the tf.io.* exports. Also: - Export tf.io.getSaveHandler, tf.io.getLoadHandler - Export tf.io.registerSaveRouter and tf.io.registerLoadRouter
src/environment.ts
Outdated
@@ -30,6 +30,8 @@ export enum Type { | |||
export interface Features { | |||
// Whether to enable debug mode. | |||
'DEBUG'?: boolean; | |||
// Whether we are in a node.js (i.e., non-browser) environment. | |||
'IS_NODE'?: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems a little worrisome to me. We have IS_NODE here and BACKEND below, shouldn't IS_NODE be derivable from BACKEND?
If this were a "List of features that current backend supports, then I would expect to not see the BACKEND token in this list, and IS_NODE might be ok.
src/environment.ts
Outdated
@@ -302,6 +304,8 @@ export class Environment { | |||
private evaluateFeature<K extends keyof Features>(feature: K): Features[K] { | |||
if (feature === 'DEBUG') { | |||
return false; | |||
} else if (feature === 'IS_NODE') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given this stanza it seems like it should be IS_BROWSER not IS_NODE. You're checking if the window object exists, not whether we authoritatively know that we're in node.
src/io/browser_files.ts
Outdated
// tslint:enable:max-line-length | ||
|
||
const DEFAULT_FILE_NAME_PREFIX = 'model'; | ||
const DEFAULT_JSON_EXTENSION_NAME = '.json'; | ||
const DEFAULT_WEIGHT_DATA_EXTENSION_NAME = '.weights.bin'; | ||
|
||
class BrowserDownloads implements IOHandler { | ||
export class BrowserDownloads implements IOHandler { | ||
private readonly modelTopologyFileName: string; | ||
private readonly weightDataFileName: string; | ||
private readonly jsonAnchor: HTMLAnchorElement; | ||
private readonly weightDataAnchor: HTMLAnchorElement; | ||
|
||
constructor(fileNamePrefix?: string) { | ||
// TODO(cais): Use central environment flag when it's available. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove this todo?
src/io/browser_files.ts
Outdated
@@ -233,6 +240,20 @@ class BrowserFiles implements IOHandler { | |||
} | |||
} | |||
|
|||
const URL_SCHEME = 'downloads://'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can/should this be a property of the IOHandler?
src/io/browser_http.ts
Outdated
@@ -100,6 +107,25 @@ class BrowserHTTPRequest implements IOHandler { | |||
// See: https://github.com/tensorflow/tfjs/issues/290 | |||
} | |||
|
|||
const URL_SCHEMES = ['http://', 'https://']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Property of the Handler?
src/io/indexed_db.ts
Outdated
@@ -40,7 +44,7 @@ export async function deleteDatabase(): Promise<void> { | |||
function getIndexedDBFactory(): IDBFactory { | |||
// TODO(cais): Use central environment flag when it's available. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this todo.
src/io/io.ts
Outdated
export { | ||
browserDownloads, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we might still want to export these for symmetry purpose. I think its useful to the mental model to expose the non-sugared version that matches the pattern that the non-sugared handlers use.
src/io/router_registry.ts
Outdated
} | ||
} | ||
if (validHandlers.length === 0) { | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why null? This feels like it should also be an error?
Review status: 0 of 12 files reviewed at latest revision, 7 unresolved discussions, some commit checks failed. src/environment.ts, line 34 at r1 (raw file): Previously, ericdnielsen wrote…
re point 1: It's not, they have different semantics. You could be in Node and use a JS CPU backend. src/environment.ts, line 307 at r1 (raw file): Previously, ericdnielsen wrote…
+1 this is a good point. There are other headless settings (react native, etc) src/io/browser_files.ts, line 277 at r1 (raw file):
maybe make downloads singular so this is in line with the other prefixes src/io/browser_files_test.ts, line 107 at r1 (raw file):
dont use async here and below, async tests dont work src/io/browser_http.ts, line 110 at r1 (raw file): Previously, ericdnielsen wrote…
+1 src/io/io.ts, line 28 at r1 (raw file):
what happened to these? src/io/local_storage_test.ts, line 111 at r1 (raw file):
In general I prefer importing the public facing API from unit tests (it helps you understand what the API looks like) -- can we do that here? src/io/router_registry.ts, line 22 at r1 (raw file):
just for my understanding, we need this registry because we want the node IO handlers to not live in this repository? src/io/router_registry.ts, line 23 at r1 (raw file):
Singleton src/io/router_registry.ts, line 24 at r1 (raw file):
no need to initialize to null src/io/router_registry.ts, line 88 at r1 (raw file):
use forEach for arrays src/io/router_registry_test.ts, line 48 at r1 (raw file):
reaching into the private variable is a code smell, maybe expose a reset() method Comments from Reviewable |
Thanks for the review, Eric and Nikhil. Review status: 0 of 12 files reviewed at latest revision, 16 unresolved discussions, some commit checks failed. src/environment.ts, line 34 at r1 (raw file): Previously, nsthorat (Nikhil Thorat) wrote…
+1 to Nikhil. So I'll leave it as is. But I'll change it from src/environment.ts, line 307 at r1 (raw file): Previously, nsthorat (Nikhil Thorat) wrote…
Replaced src/io/browser_files.ts, line 43 at r1 (raw file): Previously, ericdnielsen wrote…
Done. src/io/browser_files.ts, line 243 at r1 (raw file): Previously, ericdnielsen wrote…
Done throughout indexed_db.ts, local_storage.ts, browser_files.ts and browser_http.ts. src/io/browser_files.ts, line 277 at r1 (raw file): Previously, nsthorat (Nikhil Thorat) wrote…
I think plural makes more sense, because for both tf.Model and FrozenModel, this will end up being two or three files. src/io/browser_files_test.ts, line 107 at r1 (raw file): Previously, nsthorat (Nikhil Thorat) wrote…
Done. src/io/browser_http.ts, line 110 at r1 (raw file): Previously, nsthorat (Nikhil Thorat) wrote…
Done. src/io/indexed_db.ts, line 45 at r1 (raw file): Previously, ericdnielsen wrote…
Done. src/io/io.ts, line 28 at r1 (raw file): Previously, nsthorat (Nikhil Thorat) wrote…
See PR description. With these URL schemes, Model.save() and tf.loadModel() can work with only a string argument for browser downloads, local storage and indexedDB. So there is no point keeping these around. They don't have any optional fields, unlike the browserHTTPRequest being kept. I want to follow the principle of "there should be only one way to do it". If we add options to browserDownloads, browserLocalStorage in the future, we can add them back to the exports. src/io/local_storage_test.ts, line 111 at r1 (raw file): Previously, nsthorat (Nikhil Thorat) wrote…
Done using the router registry. src/io/router_registry.ts, line 22 at r1 (raw file): Previously, nsthorat (Nikhil Thorat) wrote…
Yes: it is for tfjs-node. But it can also be used by users to define custom URL schemes. src/io/router_registry.ts, line 23 at r1 (raw file): Previously, nsthorat (Nikhil Thorat) wrote…
Done. src/io/router_registry.ts, line 24 at r1 (raw file): Previously, nsthorat (Nikhil Thorat) wrote…
Done. src/io/router_registry.ts, line 97 at r1 (raw file): Previously, ericdnielsen wrote…
I think returning But actually coming to think about it, I think in this case it should just return an empty array. And in case there are >1 handlers available, return them all as an array. This was the API is cleaner: it always returns arrays and it delegates the responsibility of deciding what to do when there is 0, 1, or more handlers available to clients. Done. src/io/router_registry_test.ts, line 48 at r1 (raw file): Previously, nsthorat (Nikhil Thorat) wrote…
I considered that. But here we not only want to reset the registry, but also want to restore the state back to its original state once the tests are done. For doing that, doing it the way here feels better than adding two methods. This is just a test file. Comments from Reviewable |
Review status: 0 of 12 files reviewed at latest revision, 16 unresolved discussions. src/environment.ts, line 33 at r2 (raw file):
update this comment Comments from Reviewable |
Review status: 0 of 12 files reviewed at latest revision, 17 unresolved discussions, some commit checks pending. src/environment.ts, line 33 at r2 (raw file): Previously, nsthorat (Nikhil Thorat) wrote…
Done. Comments from Reviewable |
The currently supported schemes are:
Since browserLocalStorage, browserIndexedDB and browserDownloads
are methods without any optional arguments and can be copmletely
replaced by the URL-like strings, they are removed from the tf.io.*
exports.
Also:
Fixes: tensorflow/tfjs#282
Towards: tensorflow/tfjs#13
This change is