Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

#psyneu-139 - Load dependencies of model scripts, fix bugs with code loading models. #163

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,8 @@ yalc.lock

.idea

package/.eggs
package/.eggs

psyneulinkviewer-darwin-x64/
package/psyneulinkviewer/__pycache__
package/__pycache__
8 changes: 4 additions & 4 deletions installation.sh
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ else
echo " - please use the option desidered to run the script again."
fi

pip uninstall -y grpcio && pip uninstall -y grpcio-tools
conda install -c -y conda-forge grpcio
pip install -y modeci_mdf
conda install -y python-graphviz
pip uninstall grpcio && pip uninstall grpcio-tools
conda install conda-forge grpcio
pip install modeci_mdf
conda install python-graphviz
Empty file added installers/psyneulinkviewer.dmg
Empty file.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@
"process": "^0.11.10",
"ps-tree": "^1.2.0",
"python-shell": "^5.0.0",
"react": "^17.0.2",
"react": "17.0.2",
"react-app-rewired": "^2.2.1",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^17.0.2",
"react-dom": "17.0.2",
"react-plotly.js": "^2.6.0",
"react-redux": "^7.2.0",
"react-rnd": "^10.3.7",
Expand Down
Empty file modified pre_installation.sh
100644 → 100755
Empty file.
1 change: 1 addition & 0 deletions public/electron.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ async function createWindow() {
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
// WARNING extension has to be loaded before create the window
createWindow();
const isMac = process.platform === 'darwin';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ export class NodeFactory {
);

const link = new MetaLinkModel(Object.fromEntries(options));
link.setSourcePort(sourcePort);
link.setTargetPort(targetPort);
link?.setSourcePort(sourcePort);
link?.setTargetPort(targetPort);

return link;
}
Expand Down
2 changes: 1 addition & 1 deletion src/client/model/Interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ export default class ModelInterpreter {
modelMap[newNode.getType()].set(newNode.getName(), newNode);
this.pnlModel[newNode.getType()].push(newNode);
} else {
throw new Error('Unknown node type, class ' + newNode.getType() + ' not found in modelMap');
//throw new Error('Unknown node type, class ' + newNode.getType() + ' not found in modelMap');
}
return newNode;
}
Expand Down
2 changes: 1 addition & 1 deletion src/client/model/ModelSingleton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export default class ModelSingleton {
static getNodeType(nodeName: string) {
if (ModelSingleton.summaries[nodeName]) {
// Note, the replace below is required due to a transformation done by the library PSNL itself
return ModelSingleton.summaries[nodeName][nodeName.replace('-', '_')].metadata.type;
return ModelSingleton.summaries[nodeName][nodeName.replace('-', '_')]?.metadata?.type;
}
return 'unknown';
}
Expand Down
14 changes: 11 additions & 3 deletions src/client/model/graph/MetaGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,17 @@ export class MetaGraph {
const source = this.getNodeDFS(child.getSourceId());
const target = this.getNodeDFS(child.getTargetId());
if (source && target) {
link.setSourcePort(source.getPort(child.getSourcePortId()));
link.setTargetPort(target.getPort(child.getTargetPortId()));
this.links.push(link);
let sourcePort = source.getPort(child.getSourcePortId());
let targetPort = target.getPort(child.getTargetPortId())
if ( sourcePort != undefined && link != undefined ) {
link?.setSourcePort(sourcePort);
}
if ( targetPort != undefined && link != undefined ) {
link?.setTargetPort(targetPort);
}
if ( sourcePort != undefined && targetPort != undefined ){
this.links.push(link);
}
}
});
this.notify({type: MetaGraphEventTypes.LINK_ADDED, payload: links})
Expand Down
2 changes: 1 addition & 1 deletion src/client/model/links/ProjectionLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export default class ProjectionLink implements IMetaLinkConverter {
}
});
if (result === '') {
throw Error('There is no port with that name.');
//throw Error('There is no port with that name.');
}
return result;
}
Expand Down
24 changes: 19 additions & 5 deletions src/client/model/nodes/composition/CompositionNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,19 @@ export default class CompositionNode extends MechanismNode {

addChild(child: MechanismNode|CompositionNode) {
if (!this.childrenMap.has(child.getName())) {
this.childrenMap.set(child.getName(), child);
this.metaChildren.push(child.getMetaNode());
this.childrenMap?.set(child.getName(), child);
this.metaChildren?.push(child.getMetaNode());
}
this.children[child.getType()].push(child);
this.children[child.getType()]?.push(child);
}

removeChild(child: MechanismNode|CompositionNode) {
if (this.childrenMap.has(child.getName())) {
this.childrenMap.delete(child.getName());
this.metaChildren = this.metaChildren.filter((item: MetaNode) => item.getId() !== child.getName());
this.metaChildren = this.metaChildren?.filter((item: MetaNode) => item.getId() !== child.getName());
}

this.children[child.getType()] = this.children[child.getType()].filter( (item: any) => {
this.children[child.getType()] = this.children[child.getType()]?.filter( (item: any) => {
return item.getName() !== child.getName()
});
}
Expand Down Expand Up @@ -118,6 +118,20 @@ export default class CompositionNode extends MechanismNode {
this.metaChildren,
new Map(Object.entries({
name: this.name,
learning_rate: '',
learn_field_weights : '',
enable_learning : '',
device : '',
field_weights: '',
field_names : [],
softmax_gain : '',
seed : '',
memory_capacity : '',
memory_fill : '',
memory_decay_rate : '',
softmax_threshold : '',
normalize_field_weights : '',
concatenate_keys : '',
variant: 'node-gray',
pnlClass: PNLClasses.COMPOSITION,
shape: PNLClasses.COMPOSITION,
Expand Down
26 changes: 21 additions & 5 deletions src/client/model/nodes/mechanism/MechanismNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,15 @@ export default class MechanismNode implements IMetaDiagramConverter {
}

getOptionsFromType(summaries: any, defaults: any) : Map<string, any> {
let classParams = JSON.parse(JSON.stringify(MetaNodeToOptions[this.innerClass]));
console.log("Summaries ", summaries)
console.log(MetaNodeToOptions[this.innerClass])
let classParams;
try {
classParams = JSON.parse(JSON.stringify(MetaNodeToOptions[this.innerClass]));
} catch (error) {
console.error("Failed to parse MetaNodeToOptions:", error);
classParams = {}; // or some sensible default
}
if (summaries !== undefined && summaries.hasOwnProperty(this.name)) {
const summary = summaries[this.name];
classParams = extractParams(summary[this.name], classParams, true);
Expand Down Expand Up @@ -147,24 +155,32 @@ export default class MechanismNode implements IMetaDiagramConverter {
let summary_inputs: any = {};
let summary_outputs: any = {};
if (summaries !== undefined && summaries.hasOwnProperty(this.name)) {
summary_inputs = summaries[this.name][this.name]['input_ports'];
summary_outputs = summaries[this.name][this.name]['output_ports'];
summary_inputs = summaries[this.name][this.name]?.['input_ports'];
summary_outputs = summaries[this.name][this.name]?.['output_ports'];
for (const inputPort in summary_inputs) {
let portEntries = new Map()
if ( summary_inputs?.[inputPort]?.metadata ){
portEntries = new Map(Object.entries(summary_inputs[inputPort].metadata))
}
ports.push(new MetaPort(
inputPort,
inputPort,
PortTypes.INPUT_PORT,
new Point(0, 0),
new Map(Object.entries(summary_inputs[inputPort].metadata)))
portEntries)
);
}
for (const outputPort in summary_outputs) {
let portEntries = new Map()
if ( summary_outputs?.[outputPort]?.metadata ){
portEntries = new Map(Object.entries(summary_outputs[outputPort].metadata))
}
ports.push(new MetaPort(
outputPort,
outputPort,
PortTypes.OUTPUT_PORT,
new Point(0, 0),
new Map(Object.entries(summary_outputs[outputPort].metadata)))
portEntries)
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/client/model/nodes/mechanism/utils.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FunctionsParams, OptionsTypes } from "../utils";

export const extractParams = (base, params, isThisFromSummary) => {
if (base.hasOwnProperty('functions') && base.hasOwnProperty('metadata')) {
if (base?.hasOwnProperty('functions') && base?.hasOwnProperty('metadata')) {
for (const key in params) {
if (key === 'function') {
params[key] = extractFunction(base.functions[Object.keys(base.functions)[0]], isThisFromSummary)
Expand Down
7 changes: 3 additions & 4 deletions src/client/model/state/CreateLinkState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export class CreateLinkState extends State<DiagramEngine> {
const link = this.sourcePort?.createLinkModel()! as MetaLinkModel;
const id = link.getID().replaceAll('-', '_');
link.setOption('id', 'projection_' + id.substring(id.length - 12));
link.setSourcePort(this.sourcePort);
link?.setSourcePort(this.sourcePort);

isSourceInPort =
!(this.sourcePort as DefaultPortModel).getOptions()['in'] ?? true;
Expand All @@ -132,7 +132,7 @@ export class CreateLinkState extends State<DiagramEngine> {
clientX - (ox + DEFAULT_EXCLUDE),
clientY - (oy + DEFAULT_EXCLUDE)
);

this.link = this.engine.getModel().addLink(link) as MetaLinkModel;
} else if (
(element instanceof MetaPortModel &&
Expand Down Expand Up @@ -216,8 +216,7 @@ export class CreateLinkState extends State<DiagramEngine> {
createMetaLink(link: MetaLinkModel) {
const modelHandler = ModelSingleton.getInstance();
const metaGraph = modelHandler.getMetaGraph();

metaGraph.addLink(link);
metaGraph?.addLink(link);
}

getEngine() {
Expand Down
6 changes: 3 additions & 3 deletions src/client/services/queryService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ export default class QueryService {
if (summary.hasOwnProperty(nodeName)) {
const nodeInfo: any = summary[nodeName][nodeName];
let ports: string = '[';
for (const inputPort in nodeInfo.input_ports) {
for (const inputPort in nodeInfo?.input_ports) {
ports += `(InputPort ${inputPort}), `;
}
for (const outputPort in nodeInfo.output_ports) {
for (const outputPort in nodeInfo?.output_ports) {
ports += `(OutputPort ${outputPort}), `;
}
return ports.slice(0, -2) + ']';
return ports?.slice(0, -2) + ']';
}
return '[]';
}
Expand Down
43 changes: 42 additions & 1 deletion src/server/api/psnl_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
from os.path import expanduser
from xml.etree.cElementTree import fromstring
import ast
import os
import importlib.util
import sys
import json
import threading
import numpy as np
Expand Down Expand Up @@ -83,14 +86,52 @@ def hashable_pnl_objects(self):
}

def loadScript(self, filepath):
# Expand and set the main filepath
filepath = pnls_utils.expand_path(filepath)
self.filepath = filepath

# Preload modules from the same folder
self.preload_dependencies(filepath)

# Load and parse the main script
with open(filepath, 'r') as f:
f.seek(0)
self.ast = f.read()

# Parse the main script (without parsing the dependencies)
self.modelParser.parse_model(self.ast)

# Generate and return the model
model = self.modelParser.get_graphviz()
return model
return model

def preload_dependencies(self, filepath):
folder = os.path.dirname(filepath)

# Load the main file's AST and find imports
with open(filepath, 'r') as f:
script_ast = ast.parse(f.read())

for node in ast.walk(script_ast):
if isinstance(node, ast.ImportFrom) and node.level == 0: # relative import
module_name = node.module.lstrip()
if module_name and module_name != "psyneulink" : # Only process if the module is specified
self.load_module_from_same_folder(module_name, folder)
elif isinstance(node, ast.Import) : # relative import
for alias in node.names:
if alias.name.lstrip() != "psyneulink":
self.load_module_from_same_folder(alias.name, folder)

def load_module_from_same_folder(self, module_name, folder):
# Convert module name to file path (relative imports)
module_file = os.path.join(folder, module_name.replace('.', '/') + '.py')

if os.path.exists(module_file):
# Import the module dynamically without parsing it with modelParser
spec = importlib.util.spec_from_file_location(module_name, module_file)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)

def pnlAPIcall(self, data):
callData = json.loads(data)
Expand Down
Loading
Loading