Comparar commits

..

9 Commits

Autor SHA1 Mensagem Data
Brian Broll d12ab2a352 v1.4.1 2017-08-11 00:57:30 -05:00
Brian Broll 149be7cd18 Fixed node unload in table layer children. Fixes #1033 (#1034) 2017-08-11 15:54:52 +10:00
Brian Broll e84a946302 updated quickstart in docs to use docker-compose 2017-08-09 01:10:19 -05:00
Brian Broll ce5f890cec Added dependencies to compose file. Fixes #1031 (#1032)
* WIP #1031 added container dependency info

* WIP #1031 updated quickstart
2017-08-09 11:41:46 +10:00
yogeshVU f9551b18c9 Added docker-compose file (#1030) 2017-07-25 18:21:23 -05:00
Chandan Rai 66b794cdbe corrected typo (#1029) 2017-07-23 22:56:09 -04:00
Brian Broll 89edea8c15 updated install instructions to include nvm 2017-07-22 18:41:56 -05:00
Brian Broll a533669dd9 v1.4.0 2017-06-02 18:04:38 -05:00
Brian Broll c9935b52a3 minor updates to gitignore and npmignore 2017-06-02 18:02:52 -05:00
65 arquivos alterados com 3124 adições e 15005 exclusões
+3
Ver Arquivo
@@ -35,3 +35,6 @@ test-tmp/
blob-local-storage/
src/seeds/nn/hash.txt
src/seeds/pipeline/hash.txt
notes/
src/worker
+3
Ver Arquivo
@@ -38,3 +38,6 @@ src/seeds/pipeline/hash.txt
# docs
images/
notes/
src/worker
+4 -14
Ver Arquivo
@@ -21,23 +21,13 @@ Additional features include:
- Facilitates defining custom layers
## Quick Start
Simply run the following command to install deepforge with its dependencies:
The easiest way to start deepforge is using [docker-compose](https://docs.docker.com/compose/). Using docker-compose, deepforge can be started with
```
curl -o- https://raw.githubusercontent.com/dfst/deepforge/master/install.sh | bash
wget https://raw.githubusercontent.com/deepforge-dev/deepforge/master/docker-compose.yml
docker-compose up
```
Or, if you already have NodeJS (v6) installed, simply run
```
npm install -g deepforge
```
Finally, start deepforge with `deepforge start`and navigate to [http://localhost:8888](http://localhost:8888) to start using DeepForge! For more, detailed instructions, check out the [wiki](https://github.com/dfst/deepforge/wiki/Installation-Guide).
**Note**: running deepforge w/ `deepforge start` will also require [MongoDB](https://www.mongodb.com/download-center?jmp=nav#community) to be installed locally.
Also, be sure to check out the other available features of the `deepforge` cli; it can be used to update, manage your torch installation, uninstall deepforge and run individual components!
Finally, navigate to [http://localhost:8888](http://localhost:8888) to start using DeepForge! For more detailed instructions and other installation options, check out the [docs](http://deepforge.readthedocs.io/en/latest/deployment/overview.html).
## Additional Resources
- [Intro to DeepForge Slides](https://docs.google.com/presentation/d/10_y5O3gHXSATfjHVLJg7dOdrz-tAXNWjlxhJ5SlA0ic/edit?usp=sharing)
-1
Ver Arquivo
@@ -185,7 +185,6 @@ var startMongo = function(args, port, silent) {
};
var hasTorch = function() {
return true;
var result = childProcess.spawnSync('th', ['--help']);
return !result.error;
};
+7 -7
Ver Arquivo
@@ -39,13 +39,13 @@ try {
}
// Check torch support
//var result = childProcess.spawnSync('th', ['--help']);
//if (result.error) {
//console.error('Checking Torch7 dependency failed. Do you have Torch7 installed ' +
//'and in your PATH?\n\nFor Torch7 installation instructions, check out ' +
//'http://torch.ch/docs/getting-started.html');
//process.exit(1);
//}
var result = childProcess.spawnSync('th', ['--help']);
if (result.error) {
console.error('Checking Torch7 dependency failed. Do you have Torch7 installed ' +
'and in your PATH?\n\nFor Torch7 installation instructions, check out ' +
'http://torch.ch/docs/getting-started.html');
process.exit(1);
}
var cleanUp = function() {
console.log('removing worker directory ', workerPath);
+1 -2
Ver Arquivo
@@ -9,8 +9,7 @@ var config = require('./config.default'),
path = require('path');
config.server.port = 9001;
config.mongo.uri = process.env.MONGO_URI || 'mongodb://127.0.0.1:27017';
config.mongo.uri = config.mongo.uri.replace(/\/[a-zA-Z_\-]*$/, '') + '/deepforge_tests';
config.mongo.uri = 'mongodb://127.0.0.1:27017/webgme_tests';
config.blob.fsDir = path.join(__dirname, '..', 'test-tmp', 'blob');
module.exports = config;
-1
Ver Arquivo
@@ -22,7 +22,6 @@ config.seedProjects.basePaths.push(__dirname + '/../src/seeds/project');
config.seedProjects.basePaths.push(__dirname + '/../src/seeds/cifar10');
config.seedProjects.basePaths.push(__dirname + '/../src/seeds/xor');
config.seedProjects.basePaths.push(__dirname + '/../src/seeds/devProject');
config.seedProjects.basePaths.push(__dirname + '/../src/seeds/minimal');
+22
Ver Arquivo
@@ -0,0 +1,22 @@
---
services:
mongo:
image: mongo
volumes:
- "$HOME/.deepforge/data:/data/db"
server:
environment:
- "MONGO_URI=mongodb://mongo:27017/deepforge"
image: deepforge/server
ports:
- "8888:8888"
volumes:
- "$HOME/.deepforge/blob:/data/blob"
depends_on:
- mongo
worker:
command: "http://server:8888"
image: deepforge/worker
depends_on:
- server
version: "2"
+24
Ver Arquivo
@@ -1,6 +1,30 @@
Native Installation
===================
Dependencies
------------
First, install `NodeJS <https://nodejs.org/en/>`_ (v6) and `MongoDB <https://www.mongodb.org/>`_. You may also need to install git if you haven't already.
Next, you can install DeepForge using npm:
.. code-block:: bash
npm install -g deepforge
Now, you can check that it installed correctly:
.. code-block:: bash
deepforge --version
DeepForge can now be started with:
.. code-block:: bash
deepforge start
However, the first time DeepForge is started, it will make sure that the deep learning framework is installed (if it isn't found on the host system). This may require you to start DeepForge a couple times; the first time it starts it will install Torch7 and require a terminal restart to update a couple environment variables (like `PATH`). The second time it starts it will install additional torch packages but will not require a terminal restart. Finally, DeepForge will start with all the required dependencies.
Database
~~~~~~~~
Download and install MongoDB from the `website <https://www.mongodb.org/>`_. If you are planning on running MongoDB locally on the same machine as DeepForge, simply start `mongod` and continue to setting up DeepForge.
+1 -1
Ver Arquivo
@@ -28,7 +28,7 @@ In this example, we have three main pipelines: :code:`download-normalize`, :code
First, we will have to retrieve and prepare the data by running the :code:`download-normalize` pipeline. This can be done by opening the given pipeline then selecting the `Execute Pipeline` option from the action button in the lower right. As soon as that pipeline finishes, we can now use this data to train a neural network.
Next, we can open the :code:`train` pipeline. Before we execute the pipeline we have to set the input trainning data that we will be using. This is done by selecting the :code:`Input` operation then clicking the value for the :code:`artifact` field. This will provide all the possible options for the input data; for this example, we will want to select the "trainingdata" artifact. After setting the input, we can click on the :code:`train` operation to inspect the hyperparameters we are using and the architecture we are training. Selecting the :code:`Output` operation will allow you to change the name of the resulting artifact of this operation (in this case, a trained model). Finally, we can execute this pipeline like before to train the model.
Next, we can open the :code:`train` pipeline. Before we execute the pipeline we have to set the input training data that we will be using. This is done by selecting the :code:`Input` operation then clicking the value for the :code:`artifact` field. This will provide all the possible options for the input data; for this example, we will want to select the "trainingdata" artifact. After setting the input, we can click on the :code:`train` operation to inspect the hyperparameters we are using and the architecture we are training. Selecting the :code:`Output` operation will allow you to change the name of the resulting artifact of this operation (in this case, a trained model). Finally, we can execute this pipeline like before to train the model.
.. figure:: select_train_data.png
:align: center
+6 -16
Ver Arquivo
@@ -1,29 +1,19 @@
Quick Start
===========
Before we can start with the examples, we will first install DeepForge locally.
The easiest way to get started quickly with DeepForge is using docker-compose. First, install `docker <https://docs.docker.com/engine/installation/>`_ and `docker-compose <https://docs.docker.com/compose/install/>`_.
Dependencies
------------
First, install `NodeJS <https://nodejs.org/en/>`_ (v6) and `MongoDB <https://www.mongodb.org/>`_. You may also need to install git if you haven't already.
Next, you can install DeepForge using npm:
Next, download the docker-compose file for DeepForge:
.. code-block:: bash
npm install -g deepforge
wget https://raw.githubusercontent.com/deepforge-dev/deepforge/master/docker-compose.yml
Now, you can check that it installed correctly:
Then start DeepForge using docker-compose:
.. code-block:: bash
deepforge --version
docker-compose up
DeepForge can now be started with:
.. code-block:: bash
deepforge start
However, the first time DeepForge is started, it will make sure that the deep learning framework is installed (if it isn't found on the host system). This may require you to start DeepForge a couple times; the first time it starts it will install Torch7 and require a terminal restart to update a couple environment variables (like `PATH`). The second time it starts it will install additional torch packages but will not require a terminal restart. Finally, DeepForge will start with all the required dependencies.
and now DeepForge can be used by opening a browser to `http://localhost:8888 <http://localhost:8888>`_!
For detailed instructions about deployment installations, check out our `deployment installation instructions <getting_started/configuration.rst>`_
+1 -2
Ver Arquivo
@@ -17,7 +17,7 @@
"watch-test": "nodemon --exec 'mocha --recursive test'",
"build-nn": "node ./utils/nn-parser.js"
},
"version": "1.3.0",
"version": "1.4.1",
"dependencies": {
"commander": "^2.9.0",
"dotenv": "^2.0.0",
@@ -43,7 +43,6 @@
"webgme-simple-nodes": "^2.1.0"
},
"devDependencies": {
"brython": "^3.2.7",
"chai": "^3.0.0",
"jszip": "^2.5.0",
"mocha": "^2.2.5",
+348 -97
Ver Arquivo
@@ -1,127 +1,378 @@
/* globals define*/
(function(root, factory){
if(typeof define === 'function' && define.amd) {
// TODO: Load the brython script
define(['./lua'], function(brython){
return (root.LayerParser = factory(brython, console.assert));
define(['./lua'], function(luajs){
return (root.LayerParser = factory(luajs));
});
} else if(typeof module === 'object' && module.exports) {
var brython = require('./node-brython'),
assert = require('assert');
module.exports = (root.LayerParser = factory(brython, assert));
var luajs = require('./lua');
module.exports = (root.LayerParser = factory(luajs));
}
}(this, function(brython, assert) {
}(this, function(luajs) {
var LayerParser = {};
function build_ast(src) {
brython.$py_module_path['__main__']='./'
return brython.py2js(src,'__main__', '__main__', '__builtins__')
}
//////////////////////// Setters ////////////////////////
var returnsSelf = function(fnNode){
var stats = fnNode.block.stats,
last = stats[stats.length-1];
// The provided tree gives us contexts which can have associated 'C'
function traverse(node, fn) {
var i;
if (node.children) {
for (i = node.children.length; i--;) {
traverse(node.children[i], fn);
fn(node.children[i]);
if (last.type === 'stat.return') {
return last.nret[0].type === 'variable' && last.nret[0].val === 'self';
}
return false;
};
var isAttrSetter = function(node){
if (node.type === 'stat.assignment' && node.lefts.length === 1) {
var left = node.lefts[0];
return left.type === 'expr.index' && left.self.val === 'self';
}
return false;
};
var getSettingAttrName = function(node){
if (isAttrSetter(node)) {
var left = node.lefts[0];
return left.key.val;
}
return null;
};
var getSettingAttrValue = function(node){
if (isAttrSetter(node)) {
return node.right;
}
return null;
};
var isSetterMethod = function(curr, parent, className){
if (parent && parent.type === 'stat.method') {
// is it a fn w/ two statements (stats)
if (parent.self.val === className && curr.type === 'function' &&
curr.block.stats.length === 2) {
// Is the first statement setting a value?
return returnsSelf(curr) && getSettingAttrName(curr.block.stats[0]); // does it return itself?
}
}
if (node.C && node.C.tree) {
for (i = node.C.tree.length; i--;) {
traverse(node.C.tree[i], fn);
fn(node.C.tree[i]);
return false;
};
var isFnArg = function(method, name) {
return method.args.indexOf(name) !== -1;
};
var getSetterSchema = function(node, method) {
var setterType,
setterFn,
value = getSettingAttrValue(node);
if (value[0].type === 'variable' && isFnArg(method.func, value[0].val)) {
setterType = 'arg';
setterFn = method.key.val;
} else {
setterType = 'const';
setterFn = {};
setterFn[value[0].val] = method.key.val;
}
return {
setterType,
setterFn
};
};
//////////////////////// Setters END ////////////////////////
var isInitFn = function(node, className) {
if (node.type === 'stat.method' && node.self.val === className) {
return node.key.val === '__init';
}
return false;
};
var getClassAttrDefs = function(method) {
var fn = method.func,
dict = {},
attr,
right,
value;
luajs.codegen.traverse(curr => {
if (isAttrSetter(curr)) {
// Store the value if it is set to a constant
attr = curr.lefts[0].key.val;
right = curr.right[0];
if (right.type.indexOf('const.') !== -1) {
value = right.val;
if (right.type === 'const.nil') {
value = null;
}
dict[attr] = value;
}
}
})(fn);
return dict;
};
var getAttrsAndVals = function(method) {
// Given a method, get the 'self' attributes and the default values
var fn = method.func,
dict = {},
varName,
value,
varUsageCnt = {};
// Get the variables that are used only once (or updating themselves)
luajs.codegen.traverse(curr => {
if (curr.type === 'variable') {
varUsageCnt[curr.val] = varUsageCnt[curr.val] ?
varUsageCnt[curr.val] + 1 : 1;
}
})(method);
luajs.codegen.traverse(curr => {
// If the variable is only used once and is 'or'-ed w/ a constant
// during this use, we can infer that this is the default value
if (curr.type === 'expr.op' && curr.op === 'op.or' &&
curr.left.type === 'variable' && curr.right.type.indexOf('const') !== -1) {
varName = curr.left.val;
if (varUsageCnt[varName] === 1) {
value = curr.right.type === 'const.nil' ? null : curr.right;
dict[varName] = value;
}
}
})(fn);
return dict;
};
var copyNodeValues = function(attrs, from, to) {
var value;
for (var i = attrs.length; i--;) {
value = from[attrs[i]] || null;
if (value) {
value = (value && value.hasOwnProperty('val')) ? value.val : value;
to[attrs[i]] = value;
}
}
}
return to;
};
var types = {},
layers = [],
pCtx,
classNode,
params;
var getTypeCheckInfo = function(cond) {
var caller,
method,
target,
expType;
function isClass(node) {
return node.type === 'class';
}
// Check for torch.isTypeOf:
if (cond.type === 'expr.call' && cond.func.type === 'expr.index') {
caller = cond.func.self.val;
method = cond.func.key.val;
function isInitFn(node) {
return node.type === 'def' && node.name === '__init__';
}
if (cond.type === 'expr.call' && caller === 'torch') {
target = cond.args[0].val;
if (method === 'isTypeOf' && target) {
expType = cond.args[1].val;
return {
target,
type: expType
};
}
}
} else if (cond.type === 'expr.op') { // torch.type() === ''
// Check right side, too!
var sides = [cond.left, cond.right],
side,
otherSide;
function getBaseClass(node) {
assert(node.type === 'class');
return node.args.tree[0].tree[0].tree[0].value;
}
for (var i = sides.length; i--;) {
side = sides[i];
otherSide = sides[(i+1)%2];
if (side.type === 'expr.call' && side.func.type === 'expr.index') {
// Is it torch?
caller = side.func.self.val;
method = side.func.key.val;
if (caller === 'torch' && method === 'type') {
if (side.args[0].type === 'variable') {
target = side.args[0].val;
if (otherSide.type === 'const.string') {
expType = otherSide.val;
function findTorchLayers(root) {
var defaults = {},
layers = [],
defTypes,
args,
def;
traverse(root, node => {
// Get the class for the given function
if (isInitFn(node)) {
// TODO: What if there is no constructor? Is this a potential problem?
pCtx = node.parent.node.parent;
classNode = pCtx.C.tree[0];
if (isClass(classNode)) {
// remove the 'self' variable
// TODO: May need to update this for kwargs
// (use positional_list)
args = node.tree[1].tree;
defaults = {};
params = node.args.slice(1);
defTypes = {};
for (var i = args.length; i--;) {
if (args[i].tree[0]) {
def = args[i].tree[0].tree[0];
if (def.type === 'int') {
defaults[params[i-1]] = parseInt.apply(null, def.value.reverse());
} else {
defaults[params[i-1]] = def.value;
}
if (/^(True|False)$/.test(defaults[params[i-1]])) {
defTypes[params[i-1]] = 'boolean';
} else {
defTypes[params[i-1]] = def.type;
return {
target: target,
type: expType
};
}
}
}
layers.push({
name: classNode.name,
baseType: getBaseClass(classNode),
//doc: classNode.doc_string || '',
defaults: defaults,
types: defTypes,
setters: {},
params: params
});
}
}
return null;
}
};
var isError = function(stat) {
var fn;
if (stat.type === 'stat.expr' && stat.expr.type === 'expr.call') {
fn = stat.expr.func.val;
return fn === 'error';
}
return false;
};
var inferParamTypes = function(node, paramDefs) {
var types = {},
check,
cond;
// Infer from assertions
luajs.codegen.traverse(curr => {
// check for 'assert's that check type
if (curr.type === 'expr.call' && curr.func.val === 'assert') {
cond = curr.args[0];
check = getTypeCheckInfo(cond);
if (check) {
types[check.target] = check.type;
}
} else if (curr.type === 'stat.if' && curr.cond.op === 'uop.not') {
// if statements throwing errors on type mismatch
cond = curr.cond.operand; // non-negated version
// Check that it throws an error on true
if (curr.tblock.stats.some(isError)) {
check = getTypeCheckInfo(cond);
if (check) {
types[check.target] = check.type;
}
}
}
})(node);
// Infer from defaults
Object.keys(paramDefs).forEach(param => {
var val = paramDefs[param];
if (val) { // initialized to 'null' doesn't help us...
types[param] = val.type.replace('const.', '');
}
});
return layers;
}
return types;
};
// Try to find the class definitions...
//
// Need to create:
//
// setters: (I don't think these are used in pytorch!
// types:
// type:
//////////////////////// Setters ////////////////////////
LayerParser.parse = function(src) {
var findTorchClass = function(ast){
var torchClassArgs, // args for `torch.class(...)`
name = '',
alias,
baseType,
params,
setters = {},
defaults = {},
paramDefs,
attrDefs;
if(ast.type == 'function'){
ast.block.stats.forEach(function(func){
if(func.type == 'stat.local' && func.right && func.right[0] &&
func.right[0].func && func.right[0].func.self &&
func.right[0].func.self.val == 'torch' &&
func.right[0].func.key.val == 'class'){
torchClassArgs = func.right[0].args.map(arg => arg.val);
name = torchClassArgs[0];
if(name !== ''){
name = name.replace('nn.', '');
alias = func.names[0] || name;
if (torchClassArgs.length > 1) {
baseType = torchClassArgs[1].replace('nn.', '');
}
}
}
});
}
// Get the setters, defaults and type info (inferred)
var setterNames,
schema,
types,
values;
luajs.codegen.traverse((curr, parent) => {
var firstLine,
attrName;
// Record the setter functions
if (isSetterMethod(curr, parent, alias)) {
firstLine = curr.block.stats[0];
// just use the attribute attrName for now...
attrName = getSettingAttrName(firstLine);
// merge schemas
schema = getSetterSchema(firstLine, parent);
if (setters[attrName] && setters[attrName].setterType === 'const') { // merge
for (var val in schema.setterFn) {
setters[attrName].setterFn[val] = schema.setterFn[val];
}
} else {
setters[attrName] = schema;
}
} else if (isInitFn(curr, alias)) { // Record the defaults
paramDefs = getAttrsAndVals(curr);
attrDefs = getClassAttrDefs(curr);
types = inferParamTypes(curr, paramDefs);
// get ctor args
params = curr.func.args;
if(params.length === 0 && curr.func.varargs){
params.push('params');
}
}
})(ast);
// Get the defaults for the params from defs
if (paramDefs && params) {
copyNodeValues(params, paramDefs, defaults);
}
// Get the defaults for the setters from attrDefs
if (attrDefs) {
setterNames = Object.keys(setters);
copyNodeValues(setterNames, attrDefs, defaults);
}
// Remove any const setters w/ only one value and no default
setterNames = Object.keys(setters);
for (var i = setterNames.length; i--;) {
schema = setters[setterNames[i]];
if (schema.setterType === 'const') {
values = Object.keys(schema.setterFn);
if (values.length === 1 &&
// boolean setters can have the default value inferred
values[0] !== 'true' && values[0] !== 'false' &&
!defaults[setterNames[i]]) {
delete setters[setterNames[i]];
}
}
}
return {
name,
baseType,
params,
setters,
types,
defaults
};
};
LayerParser.parse = function(text) {
try {
brython.$py_module_path['__main__']='./';
var ast = brython.py2js(src,'__main__', '__main__', '__builtins__');
var layers = findTorchLayers(ast);
return layers;
var ast = luajs.parser.parse(text);
return findTorchClass(ast);
} catch (e) {
return null;
}
-331
Ver Arquivo
@@ -1,331 +0,0 @@
/*globals Sk, define*/
var isNodeJs = typeof module === 'object' && module.exports;
(function(root, factory){
if(typeof define === 'function' && define.amd) {
define(['./skulpt.min'], function(){
return (root.OperationParser = factory(Sk));
});
} else if(isNodeJs) {
require('./skulpt.min');
module.exports = (root.OperationParser = factory(Sk));
}
}(this, function(Sk) {
var MAIN_FN = 'execute';
var CTOR_FN = '__init__';
var OperationCode = function(code, filename) {
this._lines = code.split('\n');
this.filename = filename;
};
OperationCode.prototype.getName = function() {
if (!this._schema) this.updateSchema();
return this._schema.name;
};
OperationCode.prototype.getBase = function() {
if (!this._schema) this.updateSchema();
return this._schema.base;
};
OperationCode.prototype.getArguments = function(method) {
if (!this._schema) this.updateSchema();
if (!this._schema.methods[method]) return null;
return this._schema.methods[method].inputs.slice();
};
OperationCode.prototype.getReturnValues = function(method) {
if (!this._schema) this.updateSchema();
if (!this._schema.methods[method]) return null;
return this._schema.methods[method].outputs.slice();
};
OperationCode.prototype.getOutputs = function() {
return this.getReturnValues(MAIN_FN);
};
OperationCode.prototype.getInputs = function() {
return this.getArguments(MAIN_FN);
};
OperationCode.prototype.removeInput = function(name) {
return this._removeIOCode(this.getInputs(), name);
};
OperationCode.prototype.removeOutput = function(name) {
return this._removeIOCode(this.getOutputs(), name);
};
OperationCode.prototype._removeIOCode = function(ios, name) {
var match,
prev,
line,
startIndex,
endIndex;
for (var i = 0; i < ios.length; i++) {
match = ios[i];
prev = ios[i-1];
if (match.name === name) {
line = this._lines[match.pos.line-1];
startIndex = prev ? prev.pos.col + prev.value.toString().length : match.pos.col;
// only remove the following ',' if first input/output
endIndex = i === 0 && i < ios.length-1 ? ios[i+1].pos.col :
match.pos.col + match.value.toString().length;
this._lines[match.pos.line-1] = line.substring(0, startIndex) +
line.substring(endIndex);
this.clearSchema();
return match;
}
}
return null;
};
OperationCode.prototype.addInput = function(name) {
return this.addArgument(MAIN_FN, name);
};
OperationCode.prototype.addOutput = function(name) {
return this.addReturnValue(MAIN_FN, name);
};
OperationCode.prototype.addArgument = function(method, name) {
return this._addIOCode(method, name, true);
};
OperationCode.prototype.addReturnValue = function(method, name) {
return this._addIOCode(method, name, false);
};
OperationCode.prototype.addMethod = function(method) {
// TODO: get the position at the top of the class def
var line = this._schema.body.pos.line - 1,
indentSize = this._schema.body.pos.col,
indent = new Array(indentSize+1).join(' '),
snippet = indent + `def ${method}():`,
body = new Array(indentSize+5).join(' ') + 'return';
this._lines.splice(line-1, 0, '');
this._lines.splice(line-1, 0, snippet);
this._lines.splice(line, 0, body);
this.clearSchema();
};
OperationCode.prototype.hasMethod = function(method) {
if (!this._schema) this.updateSchema();
return this._schema.methods[method];
};
OperationCode.prototype._addIOCode = function(method, name, isInput) {
if (!this.hasMethod(method)) this.addMethod(method);
this.updateSchema();
var ios = this._schema.methods[method][isInput ? 'inputs' : 'outputs'].slice(),
node = this._schema.methods[method].node,
body = node.body,
content = name,
line,
startIndex,
endIndex,
lineIndex;
if (ios.length) {
var pos = ios[ios.length-1].pos;
var argLen = ios[ios.length-1].name.length;
line = this._lines[pos.line-1];
startIndex = pos.col + argLen;
endIndex = pos.col + argLen;
content = ', ' + name;
lineIndex = pos.line - 1;
} else if (isInput) {
var first = body[0];
lineIndex = first.lineno - 2;
line = this._lines[lineIndex];
this._lines[lineIndex] = line.replace(/\).*?:/, name + '):');
return this.clearSchema();
} else {
var ret = body.find(node => this._isNodeType(node, 'Return_'));
if (ret) {
lineIndex = ret.lineno-1;
startIndex = endIndex = ret.col_offset + 6;
content = ' ' + content;
} else { // add to the end of the body (no return statement)
var lastNode = body[body.length-1];
var indent = new Array(lastNode.col_offset+1).join(' ');
lineIndex = lastNode.lineno;
this._lines.splice(lineIndex, 0, '');
startIndex = endIndex = 0;
content = indent + 'return ' + content;
}
}
line = this._lines[lineIndex];
this._lines[lineIndex] = line.substring(0, startIndex) + content +
line.substring(endIndex);
this.clearSchema();
};
OperationCode.prototype.rename = function(oldName, name) {
if (!this.hasMethod(MAIN_FN)) return;
var fnSchema = this._schema.methods[MAIN_FN];
var startLine = fnSchema.bounds.start.line - 1;
var endLine = fnSchema.bounds.end ? fnSchema.bounds.end.line - 1 : this._lines.length;
var pattern = new RegExp('\\b' + oldName + '\\b');
for (var i = startLine; i < endLine; i++) {
this._lines[i] = this._lines[i].replace(pattern, name);
}
this.clearSchema();
};
OperationCode.prototype.getCode = function() {
return this._lines.join('\n');
};
OperationCode.prototype.getAst = function () {
if (this._ast) return this._ast;
var filename = this.filename || 'operation.py';
var cst = Sk.parse(filename, this.getCode()).cst;
var ast = Sk.astFromParse(cst, filename);
return this._ast = ast;
};
OperationCode.prototype._isNodeType = function (node, name) {
return node.constructor.name === name;
};
OperationCode.prototype._parseFn = function (node, schema, next) {
var name = node.name.v;
schema.methods[name] = {};
// add inputs
schema.methods[name].inputs = node.args.args.map(arg => {
return {
name: arg.id.v,
value: arg.id.v,
pos: {
line: arg.lineno,
col: arg.col_offset
}
};
});
// add outputs
var ret = node.body.find(node => this._isNodeType(node, 'Return_'));
var retVals = [];
if (ret) {
retVals = ret.value && this._isNodeType(ret.value, 'Tuple') ?
ret.value.elts : [ret.value];
}
schema.methods[name].outputs = retVals
.filter(node => !!node)
.map((arg, index) => {
var isNameNode = this._isNodeType(arg, 'Name');
var name = isNameNode ? arg.id.v : 'result';
if (!isNameNode && index > 0) {
name += '_' + index;
}
var value = this._isNodeType(arg, 'Num') ? arg.n.v : name;
return {
name: name,
value: value,
pos: {
line: arg.lineno,
col: arg.col_offset
}
};
});
// Get the function location
schema.methods[name].bounds = {};
schema.methods[name].bounds.start = {
line: node.lineno,
col: node.col_offset
};
if (next) {
schema.methods[name].bounds.end = {
line: next.lineno,
col: next.col_offset
};
}
schema.methods[name].node = node;
};
OperationCode.prototype.updateSchema = function () {
if (!this._schema) this._schema = this.getSchema();
};
OperationCode.prototype.clearSchema = function () {
this._ast = null;
this._schema = null;
};
OperationCode.prototype.getSchema = function () {
var schema = {
name: null,
base: null,
methods: {}
};
var ast = this.getAst();
// Find the class definition
var classDef = ast.body.find(node => this._isNodeType(node, 'ClassDef'));
if (classDef) {
schema.name = classDef.name.v;
// TODO: what if fn is inherited?
var nodes = classDef.body;
for (var i = 0; i < nodes.length; i++) {
if (this._isNodeType(nodes[i], 'FunctionDef')) {
this._parseFn(nodes[i], schema, nodes[i+1]);
}
}
schema.body = {
pos: {
line: nodes[0].lineno,
col: nodes[0].col_offset,
}
};
}
schema.ast = ast;
return schema;
};
/////////////////////// Attributes ///////////////////////
OperationCode.prototype.addAttribute = function(name, value) {
return this._addIOCode(CTOR_FN, name, true);
};
OperationCode.prototype.removeAttribute = function(name) {
// TODO
};
OperationCode.prototype.getAttributes = function() {
return this.getArguments(CTOR_FN);
};
return OperationCode;
}));
-126
Ver Arquivo
@@ -1,126 +0,0 @@
/* globals define, Sk*/
var isNodeJs = typeof module === 'object' && module.exports;
(function(root, factory){
if(typeof define === 'function' && define.amd) {
define(['./skulpt.min'], function(){
return (root.OperationParser = factory(Sk));
});
} else if(isNodeJs) {
require('./skulpt.min');
module.exports = (root.OperationParser = factory(Sk));
}
}(this, function(Sk) {
Sk.python3 = true;
var OperationParser = {};
// The provided tree gives us contexts which can have associated 'C'
function traverse(node, fn) {
var i;
if (node.children) {
for (i = node.children.length; i--;) {
traverse(node.children[i], fn);
fn(node.children[i]);
}
}
if (node.C && node.C.tree) {
for (i = node.C.tree.length; i--;) {
traverse(node.C.tree[i], fn);
fn(node.C.tree[i]);
}
}
}
function isNodeType(node, name) {
return node.constructor.name === name;
}
function parseFn(node, schema) {
var name = node.name.v;
schema.methods[name] = {};
// add inputs
schema.methods[name].inputs = node.args.args.map(arg => {
return {
name: arg.id.v,
value: arg.id.v,
pos: {
line: arg.lineno,
col: arg.col_offset
}
};
});
// add outputs
var ret = node.body.find(node => isNodeType(node, 'Return_'));
var retVals = [];
if (ret) {
retVals = ret.value && isNodeType(ret.value, 'Tuple') ?
ret.value.elts : [ret.value];
}
schema.methods[name].outputs = retVals.map((arg, index) => {
var isNameNode = isNodeType(arg, 'Name');
var name = isNameNode ? arg.id.v : 'result';
if (!isNameNode && index > 0) {
name + '_' + index;
}
var value = isNodeType(arg, 'Num') ? arg.n.v : name;
return {
name: name,
value: value,
pos: {
line: arg.lineno,
col: arg.col_offset
}
};
});
}
function parseOperationAst(ast) {
var schema = {
name: null,
base: null,
methods: {}
};
// Find the class definition
var classDef = ast.body.find(node => isNodeType(node, 'ClassDef'));
if (classDef) {
schema.name = classDef.name.v;
// TODO: what if fn is inherited?
classDef.body
.filter(node => isNodeType(node, 'FunctionDef'))
.forEach(node => parseFn(node, schema));
}
schema.inputs = schema.methods.execute.inputs;
schema.outputs = schema.methods.execute.outputs;
schema.ast = ast;
return schema;
}
OperationParser._traverse = traverse;
OperationParser._getAst = function(src, filename) {
filename = filename || 'operation.py';
var cst = Sk.parse(filename, src).cst;
var ast = Sk.astFromParse(cst, filename);
return ast;
};
OperationParser.parse = function(src, filename) {
//try {
var ast = this._getAst(src, filename);
return parseOperationAst(ast);
//} catch (e) {
//console.error('operation parsing failed:', e);
//return null;
//}
};
return OperationParser;
}));
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+2 -8
Ver Arquivo
@@ -59,14 +59,8 @@ define([
var createNamedNode = function(baseId, parentId, isMeta) {
var newId = client.createNode({parentId, baseId}),
baseNode = client.getNode(baseId),
basename,
newName;
basename = 'New';
if (baseNode.getAttribute('name') !== 'Operation') {
basename += baseNode.getAttribute('name');
}
newName = getUniqueName(parentId, basename);
basename = 'New' + baseNode.getAttribute('name'),
newName = getUniqueName(parentId, basename);
// If instance, make the first char lowercase
if (!isMeta) {
+1 -1
Ver Arquivo
@@ -3234,7 +3234,7 @@ function runScripts(){
if (window.addEventListener){
window.addEventListener("DOMContentLoaded", runScripts, false);
} else if (window.attachEvent) {
} else {
window.attachEvent("onload", runScripts);
}
-177
Ver Arquivo
@@ -1,177 +0,0 @@
/*
Author: Billy Earney
Date: 04/19/2013
License: MIT
Description: This file can work as a "bridge" between nodejs and brython
so that client side brython code can be executed on the server side.
Will brython replace Cython one day? Only time will tell.
:)
*/
var fs = require('fs'),
path = require('path'),
//brythonSrcPath = path.join(__dirname, '..', '..', 'node_modules', 'brython', 'www', 'src', 'brython.js');
brythonSrcPath = path.join(__dirname, 'brython.js');
document={};
document.getElementsByTagName = () => [{src: ''}];
window={};
window.location = {href: ''};
window.navigator={}
window.confirm = () => true;
window.console = console;
document.$py_src = {}
document.$debug = 0
self={};
__BRYTHON__={}
__BRYTHON__.$py_module_path = {}
__BRYTHON__.$py_module_alias = {}
__BRYTHON__.$py_next_hash = -Math.pow(2,53)
__BRYTHON__.exception_stack = []
__BRYTHON__.scope = {}
__BRYTHON__.modules = {}
// Read and eval library
jscode = fs.readFileSync(brythonSrcPath, 'utf8');
eval(jscode);
//function node_import(module,alias,names) {
function $import_single(module) {
var search_path=['../src/libs', '../src/Lib'];
var ext=['.js', '.py'];
var mods=[module, module+'/__init__'];
for(var i=0, _len_i = search_path.length; i < _len_i; i++) {
for (var j=0, _len_j = ext.length; j < _len_j; j++) {
for (var k=0, _len_k = mods.length; k < _len_k; k++) {
var path=search_path[i]+'/'+mods[k]+ext[j]
//console.log("searching for " + path);
var module_contents;
try {
module_contents=fs.readFileSync(path, 'utf8')
} catch(err) {}
if (module_contents !== undefined) {
console.log("imported " + module)
//console.log(module_contents);
if (ext[j] == '.js') {
return $import_js_module(module,alias,names,path,module_contents)
}
return $import_py_module(module,alias,names,path,module_contents)
}
}
}
}
console.log("error time!");
res = Error()
res.name = 'NotFoundError'
res.message = "No module named '"+module+"'"
throw res
}
$compile_python=function(module_contents,module) {
var root = __BRYTHON__.py2js(module_contents,module)
var body = root.children
root.children = []
// use the module pattern : module name returns the results of an anonymous function
var mod_node = new $Node('expression')
//if(names!==undefined){alias='$module'}
new $NodeJSCtx(mod_node,'$module=(function()')
root.insert(0,mod_node)
mod_node.children = body
// search for module-level names : functions, classes and variables
var mod_names = []
for(var i=0, _len_i = mod_node.children.length; i < _len_i;i++){
var node = mod_node.children[i]
// use function get_ctx()
// because attribute 'context' is renamed by make_dist...
var ctx = node.get_ctx().tree[0]
if(ctx.type==='def'||ctx.type==='class'){
if(mod_names.indexOf(ctx.name)===-1){mod_names.push(ctx.name)}
} else if(ctx.type==='from') {
for (var j=0, _len_j = ctx.names.length; j < _len_j; j++) {
var name=ctx.names[j];
if (name === '*') {
// just pass, we don't want to include '*'
} else if (ctx.aliases[name] !== undefined) {
if (mod_names.indexOf(ctx.aliases[name])===-1){
mod_names.push(ctx.aliases[name])
}
} else {
if (mod_names.indexOf(ctx.names[j])===-1){
mod_names.push(ctx.names[j])
}
}
}
}else if(ctx.type==='assign'){
var left = ctx.tree[0]
if(left.type==='expr'&&left.tree[0].type==='id'&&left.tree[0].tree.length===0){
var id_name = left.tree[0].value
if(mod_names.indexOf(id_name)===-1){mod_names.push(id_name)}
}
}
}
// create the object that will be returned when the anonymous function is run
var ret_code = 'return {'
for(var i=0, _len_i = mod_names.length; i < _len_i;i++){
ret_code += mod_names[i]+':'+mod_names[i]+','
}
ret_code += '__getattr__:function(attr){return this[attr]},'
ret_code += '__setattr__:function(attr,value){this[attr]=value}'
ret_code += '}'
var ret_node = new $Node('expression')
new $NodeJSCtx(ret_node,ret_code)
mod_node.add(ret_node)
// add parenthesis for anonymous function execution
var ex_node = new $Node('expression')
new $NodeJSCtx(ex_node,')()')
root.add(ex_node)
try{
var js = root.to_js()
return js;
}catch(err){
eval('throw '+err.name+'(err.message)')
}
return undefined;
}
function build_ast(src) {
__BRYTHON__.$py_module_path['__main__']='./'
return __BRYTHON__.py2js(src,'__main__', '__main__', '__builtins__')
}
function execute_python_script(filename) {
_py_src=fs.readFileSync(filename, 'utf8')
var root = build_ast(_py_src)
var js = root.to_js()
//eval(js);
}
//console.log("try to execute compile script");
__BRYTHON__.$py_module_path = __BRYTHON__.$py_module_path || {}
__BRYTHON__.$py_module_alias = __BRYTHON__.$py_module_alias || {}
__BRYTHON__.exception_stack = __BRYTHON__.exception_stack || []
__BRYTHON__.scope = __BRYTHON__.scope || {}
__BRYTHON__.imported = __BRYTHON__.imported || {}
__BRYTHON__.modules = __BRYTHON__.modules || {}
__BRYTHON__.compile_python=$compile_python
__BRYTHON__.debug = 0
__BRYTHON__.$options = {}
__BRYTHON__.$options.debug = 0
// other import algs don't work in node
//import_funcs=[node_import]
if (!module.parent) {
var filename=process.argv[2];
execute_python_script(filename)
}
module.exports = __BRYTHON__;
-1022
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
-98
Ver Arquivo
@@ -38,103 +38,5 @@ define([
return typeId ? this._client.getNode(typeId).getChildrenIds() : [];
};
OperationControl.prototype.createIONode = function(opId, typeId, isInput, baseName, silent) {
var cntrId = this.getDataContainerId(opId, isInput),
name = this._client.getNode(opId).getAttribute('name'),
dataName,
msg;
baseName = baseName || this._client.getNode(typeId).getAttribute('name').toLowerCase();
dataName = this._getDataName(cntrId, baseName);
msg = `Adding ${isInput ? 'input' : 'output'} "${dataName}" to ${name} interface`;
if (!silent) {
this._client.startTransaction(msg);
}
var id = this._client.createNode({
parentId: cntrId,
baseId: typeId
});
// Set the name of the new input
this._client.setAttribute(id, 'name', dataName);
if (!silent) {
this._client.completeTransaction();
}
return id;
};
OperationControl.prototype._getDataName = function(cntrId, baseName) {
var otherNames = this._getDataNames(cntrId),
name = baseName,
i = 1;
while (otherNames.indexOf(name) !== -1) {
i++;
name = baseName + '_' + i;
}
return name;
};
OperationControl.prototype._getDataNames = function(cntrId) {
var otherIds = this._client.getNode(cntrId).getChildrenIds();
return otherIds.map(id => this._client.getNode(id).getAttribute('name'));
};
OperationControl.prototype.getDataNames = function(opId, isInput) {
return this._getDataNames(this.getDataContainerId(opId, isInput));
};
OperationControl.prototype.getDataContainerId = function(opId, isInput) {
var node = this._client.getNode(opId),
cntrs = node.getChildrenIds(),
cntrType = isInput ? 'Inputs' : 'Outputs';
return cntrs.find(id => this.hasMetaName(id, cntrType));
};
OperationControl.prototype.getDataTypeId = function() {
var dataNode = this._client.getAllMetaNodes()
.find(node => node.getAttribute('name') === 'Data');
return dataNode.getId();
};
OperationControl.prototype.addInputData = function(opId, name) {
return this.createIONode(opId, this.getDataTypeId(), true, name, true);
};
OperationControl.prototype.removeInputData = function(opId, name) {
var cntrId = this.getDataContainerId(opId, true),
otherIds = this._client.getNode(cntrId).getChildrenIds(),
dataId = otherIds.find(id => this._client.getNode(id).getAttribute('name') === name);
if (dataId) { // ow, data not found
this._client.deleteNode(dataId);
}
};
OperationControl.prototype.addOutputData = function(opId, name) {
return this.createIONode(opId, this.getDataTypeId(), false, name, true);
};
OperationControl.prototype.removeOutputData = function(opId, name) {
var cntrId = this.getDataContainerId(opId),
otherIds = this._client.getNode(cntrId).getChildrenIds(),
dataId = otherIds.find(id => this._client.getNode(id).getAttribute('name') === name);
if (dataId) { // ow, data not found
this._client.deleteNode(dataId);
}
};
OperationControl.prototype.isInputData = function(nodeId) {
var node = this._client.getNode(nodeId);
return this.hasMetaName(node.getParentId(), 'Inputs');
};
return OperationControl;
});
@@ -42,8 +42,8 @@ define([
embedded: true,
widget: this.widget
});
this.control._onUnload = () => {
ArchEditor.prototype._onUnload.apply(this.control, arguments);
this.control._onUnload = id => {
ArchEditor.prototype._onUnload.call(this.control, id);
// If it was the last node, remove it
var node = this.control._client.getNode(this.id);
if (node.getChildrenIds().length === 0) {
@@ -103,7 +103,6 @@ define([
() => this.deleteAttribute(name));
};
// TODO: implement this in the widget controller (so we can update the op code)
OpIntDecorator.prototype.deleteAttribute = function(name) {
var opName = this._node.attributes.name.value,
msg = `Deleting "${name}" attribute from "${opName}" operation`;
@@ -114,7 +113,6 @@ define([
this.client.completeTransaction();
};
// TODO: implement this in the widget controller (so we can update the op code)
OpIntDecorator.prototype.setAttributeMeta = function(name, desc) {
var schema,
opName = this._node.attributes.name.value,
+3 -9
Ver Arquivo
@@ -205,10 +205,9 @@ define([
};
// Some helper methods w/ attribute handling
var PYTHON_TO_GME = {
var LUA_TO_GME = {
boolean: 'boolean',
float: 'float',
int: 'integer',
number: 'float',
string: 'string'
};
@@ -302,7 +301,7 @@ define([
attrs.forEach(name => {
desc = {};
defVal = defaults.hasOwnProperty(name) ? defaults[name] : '';
type = PYTHON_TO_GME[types[name]];
type = LUA_TO_GME[types[name]];
if (type) {
desc.type = type;
}
@@ -377,11 +376,6 @@ define([
// Set the min, max
schema.max = +schema.max;
}
// Add the enum for booleans so we use python style True/False
if (schema.type === 'boolean') {
schema.enum = ['True', 'False'];
schema.type = 'string';
}
// Create the attribute and set the schema
this.core.setAttributeMeta(node, name, schema);
+1
Ver Arquivo
@@ -17,6 +17,7 @@
"value": "all",
"valueItems": [
"nn",
"rnn",
"all"
],
"valueType": "string",
+6 -3
Ver Arquivo
@@ -1,10 +1,13 @@
/*globals define*/
define([
'text!./nn.json'
'text!./nn.json',
'text!./rnn.json'
], function(
nn
nn,
rnn
) {
return {
nn: nn
nn: nn,
rnn: rnn
};
});
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+178
Ver Arquivo
@@ -0,0 +1,178 @@
[
{
"name": "CopyGrad",
"baseType": "Identity",
"setters": {},
"defaults": {},
"type": "RNN"
},
{
"name": "FastLSTM",
"baseType": "LSTM",
"params": [
"inputSize",
"outputSize",
"rho",
"eps",
"momentum",
"affine"
],
"setters": {},
"types": {
"eps": "number",
"momentum": "number"
},
"defaults": {
"momentum": 0.1,
"eps": 0.1
},
"type": "RNN"
},
{
"name": "LSTM",
"baseType": "AbstractRecurrent",
"params": [
"inputSize",
"outputSize",
"rho",
"cell2gate"
],
"setters": {},
"types": {
"rho": "number"
},
"defaults": {
"rho": 9999
},
"type": "RNN"
},
{
"name": "LinearNoBias",
"baseType": "Linear",
"params": [
"inputSize",
"outputSize"
],
"setters": {},
"types": {},
"defaults": {},
"type": "Simple"
},
{
"name": "LookupTableMaskZero",
"baseType": "LookupTable",
"params": [
"nIndex",
"nOutput"
],
"setters": {},
"types": {},
"defaults": {},
"type": "RNN"
},
{
"name": "NormStabilizer",
"baseType": "AbstractRecurrent",
"params": [
"beta"
],
"setters": {},
"defaults": {},
"type": "RNN"
},
{
"name": "Recurrent",
"baseType": "AbstractRecurrent",
"params": [
"start",
"input",
"feedback",
"transfer",
"rho",
"merge"
],
"setters": {},
"types": {
"start": "nn.Module",
"transfer": "nn.Module",
"feedback": "nn.Module",
"input": "nn.Module"
},
"defaults": {},
"type": "RNN"
},
{
"name": "SAdd",
"baseType": "Module",
"params": [
"addend",
"negate"
],
"setters": {},
"types": {},
"defaults": {},
"type": "RNN"
},
{
"name": "SeqBRNN",
"baseType": "Container",
"params": [
"inputDim",
"hiddenDim",
"batchFirst"
],
"setters": {},
"types": {},
"defaults": {},
"type": "RNN"
},
{
"name": "SeqGRU",
"baseType": "Module",
"params": [
"inputSize",
"outputSize"
],
"setters": {},
"types": {},
"defaults": {},
"type": "RNN"
},
{
"name": "SeqLSTM",
"baseType": "Module",
"params": [
"inputsize",
"hiddensize",
"outputsize"
],
"setters": {},
"types": {},
"defaults": {},
"type": "RNN"
},
{
"name": "SeqLSTMP",
"baseType": "SeqLSTM",
"params": [
"inputsize",
"hiddensize",
"outputsize"
],
"setters": {},
"types": {},
"defaults": {},
"type": "RNN"
},
{
"name": "SeqReverseSequence",
"baseType": "Module",
"params": [
"dim"
],
"setters": {},
"types": {},
"defaults": {},
"type": "RNN"
}
]
@@ -49,6 +49,10 @@ define([
this.LayerDict = createLayerDict(this.core, this.META);
this.uniqueId = 2;
this.varnames = {net: true};
this.definitions = [
'require \'nn\'',
'require \'rnn\''
];
return PluginBase.prototype.main.apply(this, arguments);
};
@@ -72,11 +76,6 @@ define([
result = {},
code = '';
this.definitions = [
'import torch',
'import torch.nn as nn'
];
// Add an index to each layer
layers.forEach((l, index) => l[INDEX] = index);
@@ -86,7 +85,6 @@ define([
code += this.genLayerDefinitions(layers);
}
// TODO: Define the network w/ 'class ARCHITECTURE_NAME'
this.logger.debug('Generating architecture code...');
code += this.genArchCode(layers);
this.logger.debug('Prepending hoisted code...');
+80 -59
Ver Arquivo
@@ -107,24 +107,16 @@ define([
.then(mds => {
// Record the large files
var inputData = {},
runsh = [
'# Bash script to download data files and run job',
'if [ -z "$DEEPFORGE_URL" ]; then',
' echo "Please set DEEPFORGE_URL and re-run:"',
' echo ""',
' echo " DEEPFORGE_URL=http://my.deepforge.server.com:8080 bash run.sh"',
' echo ""',
' exit 1',
'fi',
'mkdir outputs\n'
].join('\n');
runsh = '# Bash script to download data files and run job\n' +
'if [ -z "$DEEPFORGE_URL" ]; then\n echo "Please set DEEPFORGE_URL and' +
' re-run:"\n echo "" \n echo " DEEPFORGE_URL=http://my.' +
'deepforge.server.com:8080 bash run.sh"\n echo ""\n exit 1\nfi\n';
mds.forEach((metadata, i) => {
// add the hashes for each input
var input = inputs[i],
hash = files.inputAssets[input],
dataDir = 'inputs/' + input + '/',
dataPath = dataDir + 'data',
dataPath = 'inputs/' + input + '/data',
url = this.blobClient.getRelativeDownloadURL(hash);
inputData[dataPath] = {
@@ -133,13 +125,12 @@ define([
};
// Add to the run.sh file
runsh += `mkdir -p ${dataDir}\n`;
runsh += `wget $DEEPFORGE_URL${url} -O ${dataPath}\n`;
});
delete files.inputAssets;
files['input-data.json'] = JSON.stringify(inputData, null, 2);
runsh += 'python main.py';
runsh += 'th init.lua';
files['run.sh'] = runsh;
// Add pointer assets
@@ -218,21 +209,23 @@ define([
GenerateJob.prototype.createOperationFiles = function (node) {
var files = {};
// For each operation, generate the output files:
// inputs/<arg-name>/init.py (respective data deserializer)
// pointers/<name>/init.py (result of running the main plugin on pointer target - may need a rename)
// inputs/<arg-name>/init.lua (respective data deserializer)
// pointers/<name>/init.lua (result of running the main plugin on pointer target - may need a rename)
// outputs/<name>/ (make dirs for each of the outputs)
// outputs/init.py (serializers for data outputs)
// outputs/init.lua (serializers for data outputs)
//
// attributes.py (returns py table of operation attributes)
// init.py (main file -> calls main and serializes outputs)
// <name>.py (entry point -> calls main operation code)
// attributes.lua (returns lua table of operation attributes)
// init.lua (main file -> calls main and serializes outputs)
// <name>.lua (entry point -> calls main operation code)
// add the given files
this.logger.info('About to generate operation execution files');
this.logger.info('About to create dist execution files');
files['start.js'] = _.template(Templates.START)(CONSTANTS);
return this.createEntryFile(node, files)
.then(() => this.createClasses(node, files))
.then(() => this.createCustomLayers(node, files))
.then(() => this.createInputs(node, files))
.then(() => this.createOutputs(node, files))
.then(() => this.createMainFile(node, files))
.then(() => {
this.createAttributeFile(node, files);
@@ -245,8 +238,7 @@ define([
};
GenerateJob.prototype.createEntryFile = function (node, files) {
this.logger.info('Creating deepforge.py file...');
files['deepforge.py'] = _.template(Templates.DEEPFORGE)(CONSTANTS);
this.logger.info('Creating entry files...');
return this.getOutputs(node)
.then(outputs => {
var name = this.getAttribute(node, 'name'),
@@ -254,9 +246,12 @@ define([
// inputs and outputs
content.name = name;
content.outputs = outputs.map(output => output[0]);
content.outputs = outputs;
files['init.lua'] = _.template(Templates.ENTRY)(content);
// Create the deepforge file
files['deepforge.lua'] = _.template(Templates.DEEPFORGE)(CONSTANTS);
});
};
@@ -299,18 +294,17 @@ define([
return inheritanceLvl[aId] > inheritanceLvl[bId];
}).map(node =>
// FIXME: update this
`require './${this.getAttribute(node, 'name')}.py'`
`require './${this.getAttribute(node, 'name')}.lua'`
).join('\n');
// Create the class files
classNodes.forEach(node => {
var name = this.getAttribute(node, 'name');
files[`classes/${name}.py`] = this.getAttribute(node, 'code');
files[`classes/${name}.lua`] = this.getAttribute(node, 'code');
});
// Create the custom layers file
files['classes/init.py'] = code;
files['classes/init.lua'] = code;
};
GenerateJob.prototype.getTypeDictFor = function (name, metanodes) {
@@ -324,7 +318,6 @@ define([
return isType;
};
// TODO: update this to nn modules
GenerateJob.prototype.createCustomLayers = function (node, files) {
var metaDict = this.core.getAllMetaNodes(this.rootNode),
isCustomLayer,
@@ -344,7 +337,7 @@ define([
.map(node => this.getAttribute(node, 'code')).join('\n');
// Create the custom layers file
files['custom-layers.py'] = code;
files['custom-layers.lua'] = code;
};
GenerateJob.prototype.getConnectionContainer = function () {
@@ -381,15 +374,11 @@ define([
//
// For each input,
// - create the deserializer
// - put it in inputs/<name>/init.py
// - copy the data asset to /inputs/<name>/init.py
// - put it in inputs/<name>/init.lua
// - copy the data asset to /inputs/<name>/init.lua
inputs = allInputs
.filter(pair => !!this.getAttribute(pair[2], 'data')); // remove empty inputs
files['start.js'] = _.template(Templates.START)({
CONSTANTS,
inputs: inputs.map(pair => pair[0])
});
files.inputAssets = {}; // data assets
return Q.all(inputs.map(pair => {
var name = pair[0],
@@ -425,25 +414,67 @@ define([
})
.then(_tplContents => {
tplContents = _tplContents;
inputs.forEach(pair => {
var hashes = inputs.map(pair => {
var hash = this.getAttribute(pair[2], 'data');
files.inputAssets[pair[0]] = hash;
return {
hash: hash,
name: pair[0]
};
});
return Q.all(hashes.map(pair =>
this.blobClient.getMetadata(pair.hash)
.fail(() => {
throw Error(`BLOB_FETCH_FAILED:${pair.name}`);
})));
})
.then(metadatas => {
// Create the deserializer
tplContents.forEach((ctnt, i) => {
// Get the name of the given asset
ctnt.filename = metadatas[i].name;
files['inputs/' + ctnt.name + '/init.lua'] = _.template(Templates.DESERIALIZE)(ctnt);
});
return files;
});
};
GenerateJob.prototype.createOutputs = function (node, files) {
// For each of the output types, grab their serialization functions and
// create the `outputs/init.lua` file
this.logger.info('Creating outputs/init.lua...');
return this.getOutputs(node)
.then(outputs => {
var outputTypes = outputs
// Get the serialize functions for each
.map(tuple => {
var node = tuple[2],
serFn = this.getAttribute(node, 'serialize');
if (this.isMetaTypeOf(node, this.META.Complex)) {
// Complex objects are expected to define their own
// serialize methods
serFn = 'if data ~= nil then data:serialize(path) end';
}
return [tuple[1], serFn];
});
files['outputs/init.lua'] = _.template(Templates.SERIALIZE)({types: outputTypes});
});
};
GenerateJob.prototype.createMainFile = function (node, files) {
this.logger.info('Creating main file...');
var content = {};
return this.getInputs(node)
.then(inputs => {
var name = this.getAttribute(node, 'name'),
code = this.getAttribute(node, 'code'),
pointers = this.core.getPointerNames(node).filter(ptr => ptr !== 'base');
content.name = name;
pointers = this.core.getPointerNames(node).filter(ptr => ptr !== 'base'),
content = {
name: name
};
// Get input data arguments
content.inputs = inputs
@@ -455,16 +486,11 @@ define([
// Add remaining code
content.code = code;
return this.getOutputs(node);
})
.then(outputs => {
content.outputs = outputs.map(output => output[0]);
files['main.py'] = _.template(Templates.MAIN)(content);
files['operations.py'] = content.code;
files['main.lua'] = _.template(Templates.MAIN)(content);
// Set the line offset
var lineOffset = 0;
var lineOffset = this.getLineOffset(files['main.lua'], code);
this.setAttribute(node, CONSTANTS.LINE_OFFSET, lineOffset);
});
};
@@ -478,7 +504,6 @@ define([
GenerateJob.prototype.createAttributeFile = function (node, files) {
var numOrBool = /^(-?\d+\.?\d*((e|e-)\d+)?|(true|false))$/,
isBool = /^(true|false)$/,
table;
this.logger.info('Creating attributes file...');
@@ -489,16 +514,12 @@ define([
if (!numOrBool.test(value)) {
value = `"${value}"`;
}
if (isBool.test(value)) { // Convert to python bool
value = value.toString();
value = value[0].toUpperCase() + value.slice(1);
}
return [`'${name}'`, value];
return [`['${name}']`, value];
})
.map(pair => pair.join(': '))
.join(',\n ') + '\n}';
.map(pair => pair.join(' = '))
.join(',\n\t') + '\n}';
files['attributes.py'] = `# attributes of ${this.getAttribute(node, 'name')}\nattributes = ${table}`;
files['attributes.lua'] = `-- attributes of ${this.getAttribute(node, 'name')}\nreturn ${table}`;
};
GenerateJob.prototype.createPointers = function (node, files, cb) {
@@ -519,7 +540,7 @@ define([
var name = this.getAttribute(node, 'name');
this.logger.info(`Pointer generation for ${name} FINISHED!`);
resultHashes.forEach((hash, index) => {
files.ptrAssets[`pointers/${pointers[index]}/init.py`] = hash;
files.ptrAssets[`pointers/${pointers[index]}/init.lua`] = hash;
});
return cb(null, files);
})
+103 -103
Ver Arquivo
@@ -1,105 +1,105 @@
# Instantiate the deepforge object
-- Instantiate the deepforge object
deepforge = {}
#class deepforge()
# function deepforge.initialize()
# require 'nn'
# require 'rnn'
# require './classes/init'
# require './custom-layers'
# end
function deepforge.initialize()
require 'nn'
require 'rnn'
require './classes/init'
require './custom-layers'
end
# function deepforge.id()
# if __deepforge_id == nil then
# __deepforge_id = 0
# end
# __deepforge_id = __deepforge_id + 1
# return __deepforge_id
# end
#
# function deepforge._cmd(...)
# local cmd = '<%= START_CMD %>'
# local arg = {...}
# local n = #arg
# for i=1,n do
# cmd = cmd .. ' ' .. tostring(arg[i])
# end
# print(cmd .. ' ') # guarantee ends w/ space
# end
#
# # Graph support
# Graph = torch.class('deepforge.Graph')
#
# function Graph:__init(name)
# self.id = deepforge.id()
# self.name = name
# deepforge._cmd('<%= GRAPH_CREATE %>', self.id, name)
# end
#
# _Line = torch.class('deepforge._Line')
#
# function _Line:__init(graphId, name, opts)
# self.id = deepforge.id()
# self.name = name
# deepforge._cmd('<%= GRAPH_CREATE_LINE %>', graphId, self.id, name)
# end
#
# function _Line:add(x, y)
# assert(type(x) == "number" and type(y) == "number", "adding point (" .. tostring(x) .. ", " .. tostring(y) .. ") to " .. self.name .. " failed: expected (number, number)")
# deepforge._cmd('<%= GRAPH_PLOT %>', self.id, x, y)
# end
#
# function Graph:line(name, opts)
# return deepforge._Line(self.id, name, opts)
# end
#
# function Graph:xlabel(name)
# deepforge._cmd('<%= GRAPH_LABEL_AXIS.X %>', self.id, name)
# end
#
# function Graph:ylabel(name)
# deepforge._cmd('<%= GRAPH_LABEL_AXIS.Y %>', self.id, name)
# end
#
# # Image support
# local function saveImage(name, tensor)
# require 'image'
# require 'paths'
#
# # save it in the tmp directory
# local filename = name .. '.png'
# local path = paths.concat('metadata', filename)
#
# if paths.dir('metadata') == nil then
# paths.mkdir('metadata')
# end
#
# image.save(path, tensor)
# end
#
# function deepforge.image(name, tensor)
# saveImage(name, tensor)
# deepforge._cmd("<%= IMAGE.BASIC %>", deepforge.id(), name)
# end
#
# Image = torch.class('deepforge.Image')
# function Image:__init(name, tensor)
# self.id = deepforge.id()
# self.name = name
#
# if tensor ~= nil then
# saveImage(name, tensor)
# deepforge._cmd('<%= IMAGE.CREATE %>', self.id, self.name)
# end
# end
#
# function Image:update(tensor)
# saveImage(self.name, tensor)
# deepforge._cmd('<%= IMAGE.UPDATE %>', self.id, self.name)
# end
#
# function Image:title(name)
# self.name = name
# deepforge._cmd('<%= IMAGE.NAME %>', self.id, self.name)
# end
#
# return deepforge
function deepforge.id()
if __deepforge_id == nil then
__deepforge_id = 0
end
__deepforge_id = __deepforge_id + 1
return __deepforge_id
end
function deepforge._cmd(...)
local cmd = '<%= START_CMD %>'
local arg = {...}
local n = #arg
for i=1,n do
cmd = cmd .. ' ' .. tostring(arg[i])
end
print(cmd .. ' ') -- guarantee ends w/ space
end
-- Graph support
Graph = torch.class('deepforge.Graph')
function Graph:__init(name)
self.id = deepforge.id()
self.name = name
deepforge._cmd('<%= GRAPH_CREATE %>', self.id, name)
end
_Line = torch.class('deepforge._Line')
function _Line:__init(graphId, name, opts)
self.id = deepforge.id()
self.name = name
deepforge._cmd('<%= GRAPH_CREATE_LINE %>', graphId, self.id, name)
end
function _Line:add(x, y)
assert(type(x) == "number" and type(y) == "number", "adding point (" .. tostring(x) .. ", " .. tostring(y) .. ") to " .. self.name .. " failed: expected (number, number)")
deepforge._cmd('<%= GRAPH_PLOT %>', self.id, x, y)
end
function Graph:line(name, opts)
return deepforge._Line(self.id, name, opts)
end
function Graph:xlabel(name)
deepforge._cmd('<%= GRAPH_LABEL_AXIS.X %>', self.id, name)
end
function Graph:ylabel(name)
deepforge._cmd('<%= GRAPH_LABEL_AXIS.Y %>', self.id, name)
end
-- Image support
local function saveImage(name, tensor)
require 'image'
require 'paths'
-- save it in the tmp directory
local filename = name .. '.png'
local path = paths.concat('metadata', filename)
if paths.dir('metadata') == nil then
paths.mkdir('metadata')
end
image.save(path, tensor)
end
function deepforge.image(name, tensor)
saveImage(name, tensor)
deepforge._cmd("<%= IMAGE.BASIC %>", deepforge.id(), name)
end
Image = torch.class('deepforge.Image')
function Image:__init(name, tensor)
self.id = deepforge.id()
self.name = name
if tensor ~= nil then
saveImage(name, tensor)
deepforge._cmd('<%= IMAGE.CREATE %>', self.id, self.name)
end
end
function Image:update(tensor)
saveImage(self.name, tensor)
deepforge._cmd('<%= IMAGE.UPDATE %>', self.id, self.name)
end
function Image:title(name)
self.name = name
deepforge._cmd('<%= IMAGE.NAME %>', self.id, self.name)
end
return deepforge
+14 -5
Ver Arquivo
@@ -1,7 +1,16 @@
import main
import pickle
-- Instantiate the deepforge object
require './deepforge'
# run the <%= name %> and serialize the results
-- run the <%= name %> and serialize the results
print('\n############### Running "<%= name.replace(/'/g, '\\\'') %>" Operation ############### ')
results = require './main'
print('############### "<%= name.replace(/'/g, '\\\'') %>" Operation Complete! ###############')
# serialize by type
import outputs
-- serialize by type
outputs = require './outputs'
<% outputs.forEach(pair => {
var name = pair[0],
type = pair[1];
%>
outputs.<%= type %>('<%= name %>', results.<%= name %>)
<% }); %>
+3
Ver Arquivo
@@ -1,12 +1,14 @@
/*globals define*/
define([
'text!./start.ejs',
'text!./entry.ejs',
'text!./main.ejs',
'text!./deepforge.ejs',
'text!./serialize.ejs',
'text!./deserialize.ejs'
], function(
START,
ENTRY,
MAIN,
DEEPFORGE,
SERIALIZE,
@@ -15,6 +17,7 @@ define([
return {
START,
ENTRY,
MAIN,
SERIALIZE,
DEEPFORGE,
+9 -26
Ver Arquivo
@@ -1,29 +1,12 @@
import pickle
# load custom layers and classes
# from deepforge import deepforge
-- load custom layers and classes
deepforge.initialize()
# deepforge.initialize()
-- input data<% inputs.forEach(function(pair) { var input = pair[0], isNil = pair[1];%>
local <%= input %> = <% if (isNil) { %>nil<% } else { %>require './inputs/<%= input %>'<%}}); %>
# input data<% inputs.forEach(function(pair) { var input = pair[0], isNil = pair[1];%>
<%= input %> = <% if (isNil) { %>None<% } else { %>pickle.load(open('./inputs/<%= input %>/data', 'rb')) <%}}); %>
-- load references<% pointers.forEach(function(pair) { var pointer = pair[0], isNil = pair[1];%>
local <%= pointer %> = <% if (isNil) { %>nil<% } else { %>require './pointers/<%= pointer %>'<%}}); %>
local attributes = require './attributes'
# load references<% pointers.forEach(function(pair) { var pointer = pair[0], isNil = pair[1];%>
from pointers import <%= pointer %>
<%}); %>
from operations import <%= name %>Operation
from attributes import attributes
# main operation code for <%= name %>
operation = <%= name %>Operation()
print('\n############### Running "<%= name.replace(/'/g, '\\\'') %>" Operation ############### ')
<%= outputs.length ? outputs.join(', ') : 'result' %> = operation.execute(<%= inputs.map(function(pair) {
var name = pair[0],
isNone = pair[1];
return isNone ? 'None' : name;
})%>)
print('############### "<%= name.replace(/'/g, '\\\'') %>" Operation Complete! ###############')
<% outputs.forEach(name => { %>
pickle.dump(<%= name %>, open('outputs/<%= name %>', 'wb'))
<% }); %>
-- main operation code for <%= name %>
<%= code %>
+10 -11
Ver Arquivo
@@ -1,17 +1,16 @@
# Serialization functions for: <%= types.map(function(type) {return type[0];}).join('\n-- ') %>
-- Serialization functions for: <%= types.map(function(type) {return type[0];}).join('\n-- ') %>
require 'paths'
serializer = {}
local serializer = {}
<% types.forEach(function(pair) {
var type = pair[0],
fn = pair[1],
safeType = type.replace(/[^a-zA-Z\d_]/g, '_');
fn = pair[1];
%>
def <%= safeType %> (name, data):
path = 'outputs/' .. name
function serializer.<%= type %> (name, data)
local path = 'outputs/' .. name
local abs_path = paths.concat('outputs', name)
<%= fn.replace('\n', '\n ') %>
serializer['<%= type %>'] = <%= safeType %>
end
<% }); %>
return serializer
+8 -19
Ver Arquivo
@@ -11,8 +11,8 @@ var spawn = require('child_process').spawn,
['error', 'warn', 'info', 'log', 'debug'].forEach(method => logger[method] = log);
// Get the BlobClient...
var COMMAND_PREFIX = '<%= CONSTANTS.START_CMD %>',
IMAGE = '<%= CONSTANTS.IMAGE.PREFIX %>',
var COMMAND_PREFIX = '<%= START_CMD %>',
IMAGE = '<%= IMAGE.PREFIX %>',
requirejs = require('webgme').requirejs,
remainingImageCount = 0,
exitCode = null;
@@ -35,23 +35,14 @@ requirejs([
// Create CACHE_DIR if it doesn't exist
var prepareCache = function() {
var dirs = CACHE_DIR.replace(/\/$/, '').split('/'),
cacheParent;
var dirs = CACHE_DIR.replace(/\/$/, '').split('/'),
cacheParent;
dirs.pop();
cacheParent = dirs.join('/');
return makeIfNeeded(cacheParent).then(() => makeIfNeeded(CACHE_DIR));
};
var prepareInputsOutputs = function() {
var dirs = ['inputs', <% inputs.forEach(function(input) { %>
'inputs/<%= input %>',
<% }) %>
'outputs'];
return Q.all(dirs.map(dir => makeIfNeeded(dir)));
};
var makeIfNeeded = function(dir) {
var deferred = Q.defer(),
job;
@@ -118,7 +109,7 @@ requirejs([
var onStderr = function(data) {
var text = data.toString();
// Filter out directory label from stack traces
process.stdout.write(text.replace(/\.\.\.\/.*\/(main|deepforge|init).py/g, '$1'));
process.stdout.write(text.replace(/\.\.\.\/.*\/(main|deepforge|init).lua/g, '$1'));
};
var onStdout = function(data) {
@@ -238,19 +229,17 @@ requirejs([
cleanup();
process.exit(130);
});
process.on('uncaughtException', err => {
process.on('uncaughtException', () => {
log('received "uncaughtException" event')
log(err);
cleanup();
});
// Request the data from the blob
prepareCache()
.then(prepareInputsOutputs)
.then(() => Q.all(inputPaths.map(ipath => getData(ipath, inputData[ipath]))))
.then(() => {
// Run 'python main.py' and merge the stdout, stderr
job = spawn('python', ['main.py'], {detached: true});
// Run 'th init.lua' and merge the stdout, stderr
job = spawn('th', ['init.lua'], {detached: true});
job.stdout.on('data', onStdout);
job.stderr.on('data', onStderr);
job.on('close', code => {
Arquivo binário não exibido.
Arquivo binário não exibido.
+1 -1
Ver Arquivo
@@ -1 +1 @@
1.0.3
0.5.0
Arquivo binário não exibido.
+1 -1
Ver Arquivo
@@ -1 +1 @@
0.7.1
0.6.0
@@ -15,7 +15,7 @@ define([
'use strict';
var NO_CODE_MESSAGE = '<%= name %> is not an editable layer!',
var NO_CODE_MESSAGE = '-- <%= name %> is not an editable layer!',
LayerEditorControl;
LayerEditorControl = function (options) {
@@ -45,10 +45,10 @@ define([
// Retrieve the template from the mixin
template = node.getMixinPaths()
.map(id => this._client.getNode(id).getAttribute('code'))
.find(code => !!code) || this.comment(NO_CODE_MESSAGE);
.find(code => !!code) || NO_CODE_MESSAGE;
}
} else {
template = this.comment(NO_CODE_MESSAGE);
template = NO_CODE_MESSAGE;
}
if (template) {
@@ -3,17 +3,13 @@
define([
'panels/TextEditor/TextEditorControl',
'text!./boilerplate.ejs',
'deepforge/viz/OperationControl',
'deepforge/OperationCode',
'deepforge/viz/Execute',
'deepforge/Constants',
'underscore'
], function (
TextEditorControl,
CodeTemplate,
OperationControl,
OperationCode,
Execute,
CONSTANTS,
_
@@ -22,7 +18,6 @@ define([
'use strict';
var OperationCodeEditorControl;
var GenerateBoilerplate = _.template(CodeTemplate);
OperationCodeEditorControl = function (options) {
options.attributeName = 'code';
@@ -53,11 +48,6 @@ define([
desc.inputs = this.getOperationInputs(node).map(id => this.formatIO(id));
desc.outputs = this.getOperationOutputs(node).map(id => this.formatIO(id));
desc.references = node.getPointerNames().filter(name => name !== 'base');
// Create the boilerplate operation code, if applicable
if (!desc.ownText) {
desc.text = GenerateBoilerplate(desc);
}
return desc;
};
@@ -78,51 +68,6 @@ define([
}
};
OperationCodeEditorControl.prototype.saveTextFor = function (id, code) {
try {
// Parse the operation implementation and detect change in inputs/outputs
// TODO: Update this to use the code object
var operation = new OperationCode(code),
oldInputs = this.getDataNames(this._currentNodeId, true),
currentInputs = operation.getInputs().map(input => input.name),
name = this._client.getNode(this._currentNodeId).getAttribute('name'),
newInputs,
rmInputs,
oldOutputs = this.getDataNames(this._currentNodeId),
currentOutputs = operation.getOutputs().map(input => input.name),
newOutputs,
rmOutputs;
// Check for input nodes to remove
if (currentInputs[0] === 'self') currentInputs.shift();
newInputs = _.difference(currentInputs, oldInputs);
rmInputs = _.difference(oldInputs, currentInputs);
newOutputs = _.difference(currentOutputs, oldOutputs);
rmOutputs = _.difference(oldOutputs, currentOutputs);
if (rmInputs.length || newInputs.length || rmOutputs.length || newOutputs.length) {
var msg = `Updating operation implementation for ${name}`;
this._client.startTransaction(msg);
TextEditorControl.prototype.saveTextFor.call(this, id, code, true);
// update the inputs
rmInputs.forEach(input => this.removeInputData(this._currentNodeId, input));
newInputs.map(input => this.addInputData(this._currentNodeId, input));
// update the outputs
rmOutputs.forEach(output => this.removeOutputData(this._currentNodeId, output));
newOutputs.map(output => this.addOutputData(this._currentNodeId, output));
this._client.completeTransaction();
} else {
return TextEditorControl.prototype.saveTextFor.call(this, id, code);
}
} catch (e) {
this._logger.debug(`failed parsing operation: ${e}`);
return TextEditorControl.prototype.saveTextFor.call(this, id, code);
}
};
OperationCodeEditorControl.prototype.getOperationAttributes = function () {
var node = this._client.getNode(this._currentNodeId),
attrs = node.getValidAttributeNames(),
@@ -1,4 +0,0 @@
class <%= name %>Operation():
def execute(self):
# Execute your operation here!
@@ -71,33 +71,6 @@ define([
this.setTitle(name || '');
};
OperationEditorPanel.prototype.editTitle = function () {
this.$panelHeaderTitle.editInPlace({
css: {
'z-index': 1000
},
onChange: (oldValue, newValue) => {
var nodeId = this.currentNodeId(),
type = this.currentBaseName(),
words = newValue.split(' '),
msg;
if (words.length > 1) {
newValue = words.map(word => word[0].toUpperCase() + word.substring(1)).join('');
}
newValue = newValue.replace(/Operation$/, '');
msg = `Renamed ${type}: ${oldValue} -> ${newValue}`;
if (!/^\s*$/.test(newValue)) {
this._client.startTransaction(msg);
this._client.setAttribute(nodeId, 'name', newValue);
this._client.completeTransaction();
}
}
});
};
OperationEditorPanel.prototype.getPanels = function () {
return [InterfaceEditor, CodeEditor];
};
@@ -1,11 +1,7 @@
/*globals define*/
define([
'panels/EasyDAG/EasyDAGControl.WidgetEventHandlers',
'deepforge/OperationCode',
'./Colors'
], function(
EasyDAGControlEventHandlers,
OperationCode,
COLORS
) {
'use strict';
@@ -70,14 +66,36 @@ define([
.filter(node => !node.isAbstract());
};
OperationInterfaceEditorEvents.prototype.getValidSuccessors = function(nodeId) {
OperationInterfaceEditorEvents.prototype.getValidSuccessors = function(nodeId, isInput) {
var dataTypeIds;
if (nodeId !== this._currentNodeId) {
return [];
}
return [{
node: this._getObjectDescriptor(this.getDataTypeId())
}];
// Return all data types in the meta
// If input, include abstract types
dataTypeIds = this.allDataTypeIds(isInput);
return dataTypeIds.map(id => {
return {
node: this._getObjectDescriptor(id)
};
});
};
OperationInterfaceEditorEvents.prototype._getDataName = function(cntrId, typeId) {
var otherIds = this._client.getNode(cntrId).getChildrenIds(),
otherNames = otherIds.map(id => this._client.getNode(id).getAttribute('name')),
baseName = this._client.getNode(typeId).getAttribute('name').toLowerCase(),
name = baseName,
i = 1;
while (otherNames.indexOf(name) !== -1) {
i++;
name = baseName + '_' + i;
}
return name;
};
OperationInterfaceEditorEvents.prototype.getRefName = function(node, basename) {
@@ -175,92 +193,26 @@ define([
this._client.completeTransaction();
};
OperationInterfaceEditorEvents.prototype._createConnectedNode = function(typeId, isInput, baseName) {
OperationInterfaceEditorEvents.prototype._createConnectedNode = function(typeId, isInput) {
var node = this._client.getNode(this._currentNodeId),
name = node.getAttribute('name'),
msg = `Updating the interface of ${name}`,
code = node.getAttribute('code'),
id,
operation,
dataName;
// Update the source code if the inputs/outputs changed
// we know that we are adding a node, so we don't need to do
// the comparing and diffing current vs new
this._client.startTransaction(msg);
id = this.createIONode(this._currentNodeId, typeId, isInput, baseName, true);
dataName = this._client.getNode(id).getAttribute('name');
try {
operation = new OperationCode(code);
if (isInput) {
operation.addInput(dataName);
} else {
operation.addOutput(dataName);
}
this._client.setAttribute(this._currentNodeId, 'code', operation.getCode());
} catch(e) {
this.logger.debug(`could not update the code - invalid python!: ${e}`);
}
this._client.completeTransaction();
return id;
};
OperationInterfaceEditorEvents.prototype._deleteNode = function(nodeId) {
var dataName = this._client.getNode(nodeId).getAttribute('name'),
node = this._client.getNode(this._currentNodeId),
name = node.getAttribute('name'),
isInput = this.isInputData(nodeId),
msg = `Updating the interface of ${name}`,
code = node.getAttribute('code'),
operation = new OperationCode(code);
// If the input name is used in the code, maybe just comment it out in the args
this._client.startTransaction(msg);
try {
if (isInput) {
operation.removeInput(dataName);
} else {
operation.removeOutput(dataName);
}
this._client.setAttribute(this._currentNodeId, 'code', operation.getCode());
} catch(e) {
this.logger.debug(`could not update the code - invalid python!: ${e}`);
}
this._client.deleteNode(nodeId);
//EasyDAGControlEventHandlers.prototype._deleteNode.apply(this, nodeId, true);
this._client.completeTransaction();
};
OperationInterfaceEditorEvents.prototype._saveAttributeForNode = function(nodeId, attr, value) {
// If nodeId is an input data node, rename the input
// If nodeId is an output data node, rename the output
var isDataNode = nodeId.indexOf(this._currentNodeId) === 0,
node = this._client.getNode(this._currentNodeId),
code = node.getAttribute('code'),
cntrs = node.getChildrenIds(),
cntrType = isInput ? 'Inputs' : 'Outputs',
cntrId = cntrs.find(id => this.hasMetaName(id, cntrType)),
dataName = this._getDataName(cntrId, typeId),
msg;
if (isDataNode && attr === 'name') { // rename input/output
var operation = new OperationCode(code),
dataNode = this._client.getNode(nodeId),
oldName = dataNode.getAttribute(attr);
msg = `Adding ${isInput ? 'input' : 'output'} "${dataName}" to ${name} interface`;
this._client.startTransaction(msg);
var id = this._client.createNode({
parentId: cntrId,
baseId: typeId
});
operation.rename(oldName, value);
// Set the name of the new input
this._client.setAttribute(id, 'name', dataName);
msg = `Renaming ${oldName}->${value} in ${name}`;
this._client.startTransaction(msg);
EasyDAGControlEventHandlers.prototype._saveAttributeForNode.apply(this, arguments);
this._client.setAttribute(this._currentNodeId, 'code', operation.getCode());
this._client.completeTransaction();
} else if (nodeId === this._currentNodeId) { // edit operation attributes
// TODO: rename operation
// TODO: set operation attribute default
console.log('setting attr', arguments);
EasyDAGControlEventHandlers.prototype._saveAttributeForNode.apply(this, arguments);
}
this._client.completeTransaction();
};
return OperationInterfaceEditorEvents;
@@ -10,6 +10,7 @@ define([
'panels/EasyDAG/EasyDAGControl',
'js/Constants',
'deepforge/Constants',
'deepforge/lua',
'deepforge/viz/OperationControl',
'./OperationInterfaceEditorControl.EventHandlers',
'./Colors',
@@ -18,6 +19,7 @@ define([
EasyDAGControl,
GME_CONSTANTS,
CONSTANTS,
luajs,
OperationControl,
OperationInterfaceEditorControlEvents,
COLORS,
@@ -227,13 +229,20 @@ define([
code = this._client.getNode(this._currentNodeId).getAttribute('code');
try {
// Parse the operation implementation for visual cues
// TODO
// Parse the operation implementation and detect change in inputs/outputs
//var schema = OperationParser.parse(code);
//console.log(schema);
ast = luajs.parser.parse(code);
for (var i = variableIds.length; i--;) {
wasUsed = this._usage[variableIds[i]];
name = this._client.getNode(variableIds[i]).getAttribute('name');
isUsed = this._inputs[variableIds[i]] ?
this.isUsedInput(name, ast) :
this.isUsedOutput(name, ast);
if (isUsed !== wasUsed) {
this._onUpdate(variableIds[i]);
}
}
} catch (e) {
this._logger.debug(`failed parsing operation: ${e}`);
this._logger.debug(`failed parsing lua: ${e}`);
}
} else if (this.containedInCurrent(gmeId) && this.hasMetaName(gmeId, 'Data')) {
@@ -366,13 +375,11 @@ define([
////////////////////// Unused input checking //////////////////////
OperationInterfaceEditorControl.prototype.isUsedInput = function(name, ast) {
return true;
//return this._isUsed(name, true, ast);
return this._isUsed(name, true, ast);
};
OperationInterfaceEditorControl.prototype.isUsedOutput = function(name, ast) {
return true;
//return this._isUsed(name, false, ast);
return this._isUsed(name, false, ast);
};
OperationInterfaceEditorControl.prototype._isUsed = function(name, isInput, ast) {
@@ -383,9 +390,8 @@ define([
// verify that it is not used only in the left side of an assignment
if (hasText) {
try {
return true;
//ast = ast || luajs.parser.parse(code);
//return isInput ? this.isUsedVariable(name, ast) : this.isReturnValue(name, ast);
ast = ast || luajs.parser.parse(code);
return isInput ? this.isUsedVariable(name, ast) : this.isReturnValue(name, ast);
} catch(e) {
this._logger.debug(`failed parsing lua: ${e}`);
return null;
@@ -400,20 +406,19 @@ define([
var isUsed = false,
checker;
return true;
//checker = luajs.codegen.traverse((curr, parent) => {
//if (curr.type === 'variable' && curr.val === name) {
//// Ignore if it is being assigned...
//if (parent.type === 'stat.assignment') {
//isUsed = isUsed || parent.right.indexOf(curr) !== -1;
//} else {
//isUsed = true;
//}
//}
//return curr;
//});
checker = luajs.codegen.traverse((curr, parent) => {
if (curr.type === 'variable' && curr.val === name) {
// Ignore if it is being assigned...
if (parent.type === 'stat.assignment') {
isUsed = isUsed || parent.right.indexOf(curr) !== -1;
} else {
isUsed = true;
}
}
return curr;
});
//checker(node);
checker(node);
return isUsed;
};
@@ -4,17 +4,14 @@
* Generated by VisualizerGenerator 1.7.0 from webgme on Tue May 31 2016 09:16:24 GMT-0500 (CDT).
*/
define([
'js/PanelBase/PanelBaseWithHeader',
define(['js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'widgets/OperationInterfaceEditor/OperationInterfaceEditorWidget',
'./OperationInterfaceEditorControl'
], function (
PanelBaseWithHeader,
IActivePanel,
OperationInterfaceEditorWidget,
OperationInterfaceEditorControl
) {
], function (PanelBaseWithHeader,
IActivePanel,
OperationInterfaceEditorWidget,
OperationInterfaceEditorControl) {
'use strict';
var OperationInterfaceEditorPanel;
@@ -19,7 +19,9 @@ define([
_.extend(ClassCodeEditorWidget.prototype, TextEditorWidget.prototype);
ClassCodeEditorWidget.prototype.getHeader = function(desc) {
return this.comment(`The class definition for ${desc.name}`);
return [
`-- The class definition for ${desc.name}`
].join('\n');
};
ClassCodeEditorWidget.prototype.updateNode = function() {
@@ -26,13 +26,13 @@ define([
DeserializeEditorWidget.prototype.getHeader = function(desc) {
this._name = desc.name;
return this.comment([
`The deserialization function for ${desc.name}`,
'Globals:',
' `path` - target filename to load',
'',
`return the loaded ${desc.name}`
].join('\n'));
return [
`-- The deserialization function for ${desc.name}`,
'-- Globals:',
'-- `path` - target filename to load',
'--',
`-- return the loaded ${desc.name}`
].join('\n');
};
DeserializeEditorWidget.prototype.getNameRegex = function() {
@@ -32,24 +32,24 @@ define([
OperationCodeEditorWidget.prototype.getHeader = function (desc) {
// Add comment about the inputs, attributes and references
var inputs = desc.inputs.map(pair => `${pair[0]} (${pair[1]})`).join('\n'),
refs = desc.references.map(name => `${name}`).join('\n'),
var inputs = desc.inputs.map(pair => `-- ${pair[0]} (${pair[1]})`).join('\n'),
refs = desc.references.map(name => `-- ${name}`).join('\n'),
header = [
`Editing "${desc.name}" Implementation`
`-- Editing "${desc.name}" Implementation`
];
if (inputs.length) {
header.push('');
header.push('Defined variables:');
header.push('--');
header.push('-- Defined variables:');
header.push(inputs);
}
if (refs) {
header.push(refs);
}
header.push('');
header.push('The \'execute\' method will be called when the operation is run');
header.push('--');
header.push('-- The following will be executed when the operation is run:');
return this.comment(header.join('\n'));
return header.join('\n');
};
OperationCodeEditorWidget.prototype.canAddReturnTmpl = function (desc) {
@@ -61,8 +61,31 @@ define([
};
OperationInterfaceEditorWidget.prototype.onAddButtonClicked = function(item, isInput) {
var successorPairs = this.getValidSuccessors(item.id, isInput);
return this.onAddItemSelected(successorPairs[0], isInput);
var successorPairs = this.getValidSuccessors(item.id, isInput),
newClass = this.getCreationNode('Complex', NEW_CLASS_ID),
newPrim = this.getCreationNode('Primitive', NEW_PRIM_ID),
opts = {};
// Add the 'Create Class' node
successorPairs.push(newClass);
successorPairs.push(newPrim);
// Add tabs
opts.tabs = ['Primitive', 'Classes'];
opts.tabFilter = (tab, pair) => {
return pair.node.isPrimitive === (tab === 'Primitive');
};
AddNodeDialog.prompt(successorPairs, opts)
.then(selected => {
if (selected.node.id === NEW_CLASS_ID) {
DeepForge.create.Complex();
} else if (selected.node.id === NEW_PRIM_ID) {
DeepForge.create.Primitive();
} else {
this.onAddItemSelected(selected, isInput);
}
});
};
OperationInterfaceEditorWidget.prototype.onDeactivate = function() {
@@ -121,7 +144,8 @@ define([
// Hover buttons
OperationInterfaceEditorWidget.prototype.showHoverButtons = function(item) {
var refNodes = this.allValidReferences(),
var dataNodes = this.allDataTypeIds(),
refNodes = this.allValidReferences(),
height = item.height,
cx = item.width/2;
@@ -137,6 +161,7 @@ define([
new Buttons.AddOutput({ // Add output data
context: this,
$pEl: this.$hoverBtns,
disabled: dataNodes.length === 0,
item: item,
x: cx,
y: height
@@ -145,6 +170,7 @@ define([
new Buttons.AddInput({ // Add input data
context: this,
$pEl: this.$hoverBtns,
disabled: dataNodes.length === 0,
item: item,
x: item.width/3,
y: 0
@@ -1,4 +1,4 @@
/*globals define, $*/
/*globals define*/
define([
'widgets/EasyDAG/SelectionManager',
@@ -25,10 +25,12 @@ define([
SelectionManager.prototype.createActionButtons = function(width, height) {
var selectedType = this.selectedItem.desc.baseName,
dataNodes,
refNodes,
cx = width/2;
if (selectedType === 'Operation') {
dataNodes = this._widget.allDataTypeIds();
refNodes = this._widget.allValidReferences();
new Buttons.AddOutput({ // Add output data
@@ -36,13 +38,15 @@ define([
$pEl: this.$selection,
item: this.selectedItem,
x: cx,
y: height
y: height,
disabled: dataNodes.length === 0
});
new Buttons.AddInput({ // Add input data
context: this._widget,
$pEl: this.$selection,
item: this.selectedItem,
disabled: dataNodes.length === 0,
x: width/3,
y: 0
});
@@ -23,12 +23,12 @@ define([
SerializeEditorWidget.prototype.getHeader = function(desc) {
this._name = desc.name;
return this.comment([
`The serialization function for ${desc.name}`,
'Globals:',
' `path` - target filename',
` \`data\` - the ${desc.name} to store`
].join('\n'));
return [
`-- The serialization function for ${desc.name}`,
'-- Globals:',
'-- `path` - target filename',
`-- \`data\` - the ${desc.name} to store`
].join('\n');
};
SerializeEditorWidget.prototype.getNameRegex = function () {
@@ -18,10 +18,6 @@ define([
var TextEditorWidget,
WIDGET_CLASS = 'text-editor',
LINE_COMMENT = {
python: '#',
lua: '--'
},
DEFAULT_SETTINGS = {
keybindings: 'default',
theme: 'solarized_dark',
@@ -31,7 +27,6 @@ define([
TextEditorWidget = function (logger, container) {
this._logger = logger.fork('Widget');
this.language = this.language || 'python';
this._el = container;
this._el.css({height: '100%'});
this.$editor = $('<div/>');
@@ -91,8 +86,8 @@ define([
TextEditorWidget.prototype.getSessionOptions = function () {
return {
mode: 'ace/mode/' + this.language,
tabSize: 4,
mode: 'ace/mode/lua',
tabSize: 3,
useSoftTabs: true
};
};
@@ -225,33 +220,18 @@ define([
};
// Adding/Removing/Updating items
TextEditorWidget.prototype.comment = function (text) {
var prefix = LINE_COMMENT[this.language] + ' ';
return text.replace(
new RegExp('^(' + LINE_COMMENT[this.language] + ')?','mg'),
prefix
);
};
TextEditorWidget.prototype.getHeader = function (desc) {
return this.comment(`Editing "${desc.name}"`);
return `-- Editing "${desc.name}"`;
};
TextEditorWidget.prototype.addNode = function (desc) {
// Set the current text based on the given
// Create the header
var header = this.getHeader(desc),
content,
newContent = header + '\n' + desc.text,
//patches = diff.diffChars(content, newContent),
cursorPos;
var header = this.getHeader(desc);
// TODO: if we are updating the value, we should make sure the cursor position
// remains in the same spot (ie, diff the text and update the positions
// based on the size of the patches
this.activeNode = desc.id;
this.silent = true;
this.editor.setValue(newContent, 2);
this.editor.setValue(header + '\n' + desc.text, 2);
this.silent = false;
this.currentHeader = header;
};
-353
Ver Arquivo
@@ -1,353 +0,0 @@
describe.only('OperationCode', function() {
var fs = require('fs');
var path = require('path');
var assert = require('assert');
var OperationCode = require('../../src/common/OperationCode');
var operation;
describe('example', function() {
var code;
before(function() {
// load the example
var filePath = path.join(__dirname, '..', 'test-cases', 'operations', 'example.py');
code = fs.readFileSync(filePath, 'utf8');
});
describe('removeInput', function() {
before(function() {
operation = new OperationCode(code);
operation.removeInput('world');
});
it('should have 2 remaining inputs', function() {
assert.equal(operation.getInputs().length, 2);
});
});
describe('attributes', function() {
describe('add', function() {
beforeEach(function() {
operation = new OperationCode(code);
});
it('should add argument to __init__ method', function() {
operation.addAttribute('number');
var attrs = operation.getAttributes();
// TODO
});
it('should set the default value', function() {
// TODO
});
});
// TODO: add attribute
// TODO: remove attribute
// TODO: rename attribute?
});
describe('rename', function() {
before(function() {
operation = new OperationCode(code);
operation.rename('hello', 'goodbye');
});
it('should rename input arg', function() {
var inputs = operation.getInputs();
var oldInput = inputs.find(input => input.name === 'hello');
var newInput = inputs.find(input => input.name === 'goodbye');
assert(!oldInput);
assert(newInput);
});
it('should rename occurrences in the fn', function() {
assert(!operation.getCode().includes('hello'));
});
});
describe('parsing', function() {
before(function() {
operation = new OperationCode(code);
});
it('should parse the correct name', function() {
assert.equal(operation.getName(), 'ExampleOperation');
});
it.skip('should parse the correct base', function() {
assert.equal(operation.getBase(), 'Operation');
});
it('should parse the input names', function() {
const names = ['hello', 'world', 'count'];
assert.deepEqual(operation.getInputs().map(input => input.name), names);
});
it.skip('should parse the input types', function() {
const types = ['str', 'str', 'int'];
assert.deepEqual(operation.getInputs().map(input => input.type), types);
});
it('should parse the output names', function() {
const names = ['concat', 'count'];
assert.deepEqual(operation.getOutputs().map(output => output.name), names);
});
it.skip('should parse the output types', function() {
const types = ['str', 'int'];
assert.deepEqual(operation.getOutputs().map(output => output.type), types);
});
});
});
describe('multi-anon-results', function() {
before(function() {
var filePath = path.join(__dirname, '..', 'test-cases', 'operations', 'multi-anon-results.py');
var example = fs.readFileSync(filePath, 'utf8');
operation = new OperationCode(example);
});
it('should parse multiple return values', function() {
assert.equal(operation.getOutputs().length, 2);
});
it('should create unique names for each', function() {
var [first, second] = operation.getOutputs();
assert.notEqual(first.name, second.name);
});
});
describe('no-inputs/outputs', function() {
var code;
before(function() {
var filePath = path.join(__dirname, '..', 'test-cases', 'operations', 'no-inputs.py');
code = fs.readFileSync(filePath, 'utf8');
});
describe('parsing', function() {
beforeEach(function() {
operation = new OperationCode(code);
});
it('should not require base class', function() {
assert.equal(operation.getBase(), null);
});
it('should detect zero output', function() {
assert.equal(operation.getOutputs().length, 0);
});
it('should detect zero inputs', function() {
assert.equal(operation.getInputs().length, 0);
});
});
describe('addInput', function() {
var operation;
before(function() {
operation = new OperationCode(code);
operation.addInput('first');
});
it('should clear schema', function() {
assert(!operation._schema);
});
it('should add input to `execute` fn', function() {
var code = operation.getCode();
assert(code.includes('first'));
});
it('should have an additional input arg', function() {
var inputs = operation.getInputs();
assert.equal(inputs.length, 1);
});
});
describe('addOutput', function() {
var operation;
describe('lone return', function() {
before(function() {
operation = new OperationCode(code);
operation.addOutput('myNewOutput');
});
it('should clear schema', function() {
assert(!operation._schema);
});
it('should add input to `execute` fn', function() {
var code = operation.getCode();
assert(code.includes('myNewOutput'));
});
it('should have an additional input arg', function() {
var inputs = operation.getOutputs();
assert.equal(inputs.length, 1);
});
});
describe('no return', function() {
before(function() {
operation = new OperationCode(code);
operation.addReturnValue('no_return', 'myNewOutput');
});
it('should clear schema', function() {
assert(!operation._schema);
});
it('should add input to `execute` fn', function() {
var code = operation.getCode();
assert(code.includes('myNewOutput'));
});
it('should have an additional input arg', function() {
var outputs = operation.getReturnValues('no_return');
assert.equal(outputs.length, 1);
});
});
});
});
describe('simple', function() {
var code;
before(function() {
var filePath = path.join(__dirname, '..', 'test-cases', 'operations', 'simple.py');
code = fs.readFileSync(filePath, 'utf8');
});
describe('parsing', function() {
beforeEach(function() {
operation = new OperationCode(code);
});
it('should not require base class', function() {
assert.equal(operation.getBase(), null);
});
it('should detect one output', function() {
assert.equal(operation.getOutputs().length, 1);
});
it('should provide the value', function() {
assert.equal(operation.getOutputs()[0].value, '20');
});
it('should detect two inputs', function() {
assert.equal(operation.getInputs().length, 2);
});
});
describe('addInput', function() {
var operation;
before(function() {
operation = new OperationCode(code);
operation.addInput('myNewInput');
});
it('should clear schema', function() {
assert(!operation._schema);
});
it('should add input to `execute` fn', function() {
var code = operation.getCode();
assert(code.includes('myNewInput'));
});
it('should have an additional input arg', function() {
var inputs = operation.getInputs();
assert.equal(inputs.length, 3);
});
});
describe('addOutput', function() {
var operation;
before(function() {
operation = new OperationCode(code);
operation.addOutput('myNewOutput');
});
it('should clear schema', function() {
assert(!operation._schema);
});
it('should add input to `execute` fn', function() {
var code = operation.getCode();
assert(code.includes('myNewOutput'));
});
it('should have an additional input arg', function() {
var inputs = operation.getOutputs();
assert.equal(inputs.length, 2);
});
});
describe('removeInput', function() {
var operation,
result;
beforeEach(function() {
operation = new OperationCode(code);
result = operation.removeInput('number');
});
it('should return removed arg', function() {
assert.equal(result.name, 'number');
});
it('should only have one remaining argument', function() {
assert.equal(operation.getInputs().length, 1);
});
it('should only not have removed argument', function() {
assert(!operation.getCode().includes('number'));
});
it('should return null if arg doesn\'t exist', function() {
var result = operation.removeInput('numdasfber');
assert.equal(result, null);
});
});
describe('removeOutput', function() {
var operation,
result;
beforeEach(function() {
operation = new OperationCode(code);
result = operation.removeOutput('result');
});
it('should return removed arg', function() {
assert.equal(result.name, 'result');
});
it('should have no remaining results', function() {
assert.equal(operation.getOutputs().length, 0);
});
it('should only not have removed argument', function() {
assert(!operation.getCode().includes('20'));
});
it('should return null if arg doesn\'t exist', function() {
var result = operation.removeOutput('numdasfber');
assert.equal(result, null);
});
});
});
});
+5 -35
Ver Arquivo
@@ -118,7 +118,7 @@ describe('GenerateJob', function () {
describe('exec files', function() {
describe('attribute file', function() {
var boolString = /['"](True|False)['"]/g;
var boolString = /['"](true|false)['"]/g;
beforeEach(preparePlugin);
@@ -129,38 +129,11 @@ describe('GenerateJob', function () {
plugin.setAttribute(node, 'debug', 'true');
plugin.createAttributeFile(node, files);
content = files['attributes.py'];
content = files['attributes.lua'];
matches = content.match(boolString);
expect(matches).to.equal(null);
});
describe('boolean to python boolean', function() {
it('should convert true to True', function() {
var files = {},
content,
matches;
plugin.setAttribute(node, 'debug', 'true');
plugin.createAttributeFile(node, files);
content = files['attributes.py'];
matches = content.includes('True');
expect(matches).to.equal(true);
});
it('should convert false to False', function() {
var files = {},
content,
matches;
plugin.setAttribute(node, 'debug', 'False');
plugin.createAttributeFile(node, files);
content = files['attributes.py'];
matches = content.includes('False');
expect(matches).to.equal(true);
});
});
it('should not quote true boolean values', function() {
var files = {},
content,
@@ -168,7 +141,7 @@ describe('GenerateJob', function () {
plugin.setAttribute(node, 'debug', true);
plugin.createAttributeFile(node, files);
content = files['attributes.py'];
content = files['attributes.lua'];
matches = content.match(boolString);
expect(matches).to.equal(null);
});
@@ -180,7 +153,7 @@ describe('GenerateJob', function () {
plugin.setAttribute(node, 'debug', 'false');
plugin.createAttributeFile(node, files);
content = files['attributes.py'];
content = files['attributes.lua'];
matches = content.match(boolString);
expect(matches).to.equal(null);
});
@@ -192,14 +165,11 @@ describe('GenerateJob', function () {
plugin.setAttribute(node, 'debug', false);
plugin.createAttributeFile(node, files);
content = files['attributes.py'];
content = files['attributes.lua'];
matches = content.match(boolString);
expect(matches).to.equal(null);
});
});
});
// TODO: What else should I test?
// run a hello world example (use golem?)
});
-14
Ver Arquivo
@@ -1,14 +0,0 @@
from operations import Operation
from typing import Tuple
class ExampleOperation(Operation):
# TODO: add the type hints
def execute(hello, world, count):
# Doing things
concat = hello + world
return concat, count
def other_method(a, b, c):
# Doing things
return a+b/c
@@ -1,10 +0,0 @@
from operations import Operation
from typing import Tuple
class ExampleOperation(Operation):
# TODO: add the type hints
def execute(hello, world, count):
# Doing things
concat = hello + world
return concat+1, count-9
-6
Ver Arquivo
@@ -1,6 +0,0 @@
class ExampleOperation():
def execute():
return
def no_return():
print('hello')
-5
Ver Arquivo
@@ -1,5 +0,0 @@
class TrainOperation():
# TODO: add type hints
def execute(self, number):
return 20
+138 -49
Ver Arquivo
@@ -1,53 +1,142 @@
{
"Transfer": [
"PReLU",
"Softshrink",
"Softplus",
"LeakyReLU",
"Hardshrink",
"ELU",
"ReLU6",
"Hardtanh",
"RReLU",
"ReLU",
"Threshold"
],
"RNN": [
"BiSequencer",
"BiSequencerLM",
"GRU",
"MaskZero",
"MaskZeroCriterion",
"Recurrence",
"Recurrent",
"RecurrentAttention",
"Recursor",
"Repeater",
"RepeaterCriterion",
"Sequencer",
"SequencerCriterion",
"TrimZero",
"Convolution": [
"ConvTranspose3d",
"Conv3d",
"ConvTranspose2d",
"Conv2d",
"Conv1d",
"CopyGrad",
"FastLSTM",
"LSTM",
"LookupTableMaskZero",
"NormStabilizer",
"SAdd",
"SeqBRNN",
"SeqGRU",
"SeqLSTM",
"SeqLSTMP",
"SeqReverseSequence"
],
"Convolution": [
"TemporalConvolution",
"TemporalMaxPooling",
"TemporalSubSampling",
"LookupTable",
"SpatialConvolutionMM",
"SpatialConvolution",
"SpatialConvolutionMap",
"SpatialFullConvolutionMap",
"SpatialLPPooling",
"SpatialMaxPooling",
"SpatialAveragePooling",
"SpatialAdaptiveMaxPooling",
"SpatialSubSampling",
"SpatialUpSamplingNearest",
"SpatialZeroPadding",
"SpatialReflectionPadding",
"SpatialReplicationPadding",
"SpatialSubtractiveNormalization",
"SpatialCrossMapLRN",
"SpatialConvolutionLocal",
"SpatialDropout",
"SpatialDilatedConvolution",
"SpatialFractionalMaxPooling",
"SpatialDivisiveNormalization",
"SpatialContrastiveNormalization",
"SpatialBatchNormalization",
"SpatialFullConvolution",
"SpatialMaxUnpooling",
"VolumetricConvolution",
"VolumetricMaxPooling",
"VolumetricAveragePooling",
"VolumetricBatchNormalization",
"VolumetricDropout",
"FractionalMaxPool2d",
"LPPool2d",
"MaxUnpool3d",
"AvgPool3d",
"MaxPool3d",
"AvgPool2d",
"MaxUnpool2d",
"MaxPool2d",
"MaxPool1d",
"ReplicationPad3d",
"ReplicationPad2d",
"ReflectionPad2d"
],
"Simple": [
"Dropout3d",
"Dropout2d",
"Dropout",
"Linear",
"Embedding"
],
"Criterion": [
"MultiMarginLoss",
"MarginRankingLoss",
"CosineEmbeddingLoss",
"CrossMapLRN2d"
]
"VolumetricFullConvolution",
"VolumetricMaxUnpooling"
],
"Criterion": [
"BCECriterion",
"WeightedMSECriterion",
"SmoothL1Criterion",
"MSECriterion",
"AbsCriterion",
"MultiCriterion",
"DistKLDivCriterion",
"HingeEmbeddingCriterion",
"CriterionTable",
"MultiMarginCriterion",
"MultiLabelMarginCriterion",
"L1HingeEmbeddingCriterion",
"CosineEmbeddingCriterion",
"MarginRankingCriterion",
"CrossEntropyCriterion",
"MarginCriterion",
"ClassNLLCriterion",
"ParallelCriterion",
"SpatialClassNLLCriterion",
"SoftMarginCriterion",
"MultiLabelSoftMarginCriterion"
],
"Simple": [
"Linear",
"LinearNoBias",
"SparseLinear",
"Dropout",
"Concat",
"Abs",
"Add",
"Mul",
"CMul",
"Max",
"Min",
"Mean",
"Sum",
"Euclidean",
"WeightedEuclidean",
"Identity",
"Copy",
"Narrow",
"Replicate",
"Reshape",
"View",
"Select",
"Exp",
"Square",
"Sqrt",
"Power",
"MM",
"AddConstant",
"MulConstant"
],
"Transfer": [
"Threshold",
"HardTanh",
"HardShrink",
"SoftShrink",
"SoftMax",
"SpatialSoftMax",
"SoftMin",
"SoftPlus",
"SoftSign",
"LogSigmoid",
"LogSoftMax",
"Sigmoid",
"Tanh",
"ReLU",
"ReLU6",
"PReLU",
"RReLU",
"LeakyReLU"
]
}
+16 -33
Ver Arquivo
@@ -28,10 +28,7 @@ if (exists.sync(configPath)) { // Check the deepforge config
config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
torchPath = (config.torch && config.torch.dir) || (configDir + 'torch');
}
// FIXME: Get the pytorch root path...
torchPath = process.env.HOME + '/projects/pytorch';
// check 'modules', 'parallel'
torchPath += '/torch/nn/';
torchPath += `/install/share/lua/5.1/${outputName}/`;
console.log(`parsing ${outputName} from ${torchPath}`);
@@ -54,18 +51,14 @@ var lookupType = function(layer){
return layerType || 'Misc';
};
var parseLayerFiles = function(layerDir) {
var files = fs.readdirSync(layerDir),
layers,
fs.readdir(torchPath, function(err,files){
if(err) throw err;
var layers,
layerByName = {};
console.log('parsing', layerDir);
layers = files.filter(filename => path.extname(filename) === '.py' &&
filename[0] !== '_')
.map(filename => fs.readFileSync(layerDir + filename, 'utf8'))
layers = files.filter(filename => path.extname(filename) === '.lua')
.map(filename => fs.readFileSync(torchPath + filename, 'utf8'))
.map(code => LayerParser.parse(code))
.filter(list => list !== null)
.reduce((l1, l2) => l1.concat(l2), [])
.filter(layer => !!layer && layer.name);
layers.forEach(layer => {
@@ -111,27 +104,17 @@ var parseLayerFiles = function(layerDir) {
}
});
layers = layers.filter(layer => !SKIP_LAYERS[layer.name]);
return layers;
};
var layers = ['modules']
.map(dir => torchPath + dir + '/')
.map(path => parseLayerFiles(path))
.reduce((l1, l2) => l1.concat(l2))
.filter(layer => layer.name[0] !== '_'); // skip hidden/abstract layers
outputDst += outputName + '.json';
// eslint-disable-next-line no-console
console.log('Saved nn interface to ' + outputDst);
fs.writeFileSync(outputDst, JSON.stringify(layers, null, 2));
// Update the CreateTorchMeta index
var updateSchemas = `${__dirname}/../src/plugins/CreateTorchMeta/update-schemas.js`,
job = require('child_process').fork(updateSchemas);
// eslint-disable-next-line no-console
console.log('discovered', layers.length, 'layers');
outputDst += outputName + '.json';
// eslint-disable-next-line no-console
console.log('Saved nn interface to ' + outputDst);
fs.writeFileSync(outputDst, JSON.stringify(layers, null, 2));
// Update the CreateTorchMeta index
var updateSchemas = `${__dirname}/../src/plugins/CreateTorchMeta/update-schemas.js`,
job = require('child_process').fork(updateSchemas);
job.on('close', code => {
process.exit(code);
job.on('close', code => {
process.exit(code);
});
});
-104
Ver Arquivo
@@ -1,104 +0,0 @@
var brython = require('./node-brython'),
fs = require('fs'),
assert = require('assert'),
src = fs.readFileSync(process.env.HOME + '/projects/pytorch/torch/nn/modules/conv.py', 'utf8'),
root = build_ast(src);
function build_ast(src) {
brython.$py_module_path['__main__']='./'
return brython.py2js(src,'__main__', '__main__', '__builtins__')
}
// The provided tree gives us contexts which can have associated 'C'
function traverse (node, fn) {
var i;
if (node.children) {
for (i = node.children.length; i--;) {
traverse(node.children[i], fn);
fn(node.children[i]);
}
}
if (node.C && node.C.tree) {
for (i = node.C.tree.length; i--;) {
traverse(node.C.tree[i], fn);
fn(node.C.tree[i]);
}
}
}
var types = {},
layers = [],
pCtx,
classNode,
params;
function isClass(node) {
return node.type === 'class';
}
function isInitFn(node) {
return node.type === 'def' && node.name === '__init__';
}
function getBaseClass(node) {
assert(node.type === 'class');
return node.args.tree[0].tree[0].tree[0].value;
}
var defaults = {},
defTypes,
args,
def;
traverse(root, node => {
if (node.type) types[node.type] = true;
// Get the class for the given function
if (isInitFn(node)) {
pCtx = node.parent.node.parent;
classNode = pCtx.C.tree[0];
if (isClass(classNode)) {
// remove the 'self' variable
// TODO: May need to update this for kwargs
// (use positional_list)
args = node.tree[1].tree;
defaults = {};
params = node.args.slice(1);
defTypes = {};
for (var i = args.length; i--;) {
if (args[i].tree[0]) {
def = args[i].tree[0].tree[0];
console.log('setting type of ', params[i-1], 'to', def.type);
defTypes[params[i-1]] = def.type;
if (def.type === 'int') {
defaults[params[i-1]] = parseInt.apply(null, def.value.reverse());
} else {
defaults[params[i-1]] = def.value;
}
}
}
layers.push({
name: classNode.name,
baseType: getBaseClass(classNode),
//doc: classNode.doc_string || '',
defaults: defaults,
types: defTypes,
params: params
});
}
}
// TODO: What if there is no constructor? Is this a potential problem?
});
console.log('layers:', layers);
fs.writeFileSync('./testPyTorchLayers.json', JSON.stringify(layers, null, 2));
//console.log('layers:', layers.map(l => l.name));
// Try to find the class definitions...
//
// Need to create:
//
// setters: (I don't think these are used in pytorch!
// types:
// defaults:
// type:
-3
Ver Arquivo
@@ -327,9 +327,6 @@
},
"devProject": {
"src": "src/seeds/devProject"
},
"minimal": {
"src": "src/seeds/minimal"
}
},
"routers": {