Skip to content

Commit

Permalink
Merge pull request #360 from XpressAI/fahreza/recursive-compile
Browse files Browse the repository at this point in the history
✨ Add Recursive Compile
  • Loading branch information
MFA-X-AI authored Oct 21, 2024
2 parents e3876c3 + d34159c commit e4d2ad9
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 45 deletions.
14 changes: 10 additions & 4 deletions src/XircuitsFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
import { Signal } from '@lumino/signaling';
import { XircuitsPanel } from './XircuitsWidget';
import {
checkIcon,
copyIcon,
cutIcon,
listIcon,
Expand All @@ -26,7 +25,14 @@ import { ToolbarButton } from '@jupyterlab/apputils';
import { LoggerCommandIDs } from './log/LogPlugin';
import { ServiceManager } from '@jupyterlab/services';
import { RunSwitcher } from './components/runner/RunSwitcher';
import { lockIcon, reloadAllIcon, xircuitsIcon, toggleAnimationIcon } from './ui-components/icons';
import {
lockIcon,
compileIcon,
reloadAllIcon,
xircuitsIcon,
toggleAnimationIcon,
compileRunIcon
} from './ui-components/icons';
import { commandIDs } from "./commands/CommandIDs";
const XIRCUITS_CLASS = 'xircuits-editor';

Expand Down Expand Up @@ -115,8 +121,8 @@ export class XircuitsFactory extends ABCWidgetFactory<DocumentWidget> {
let logButton = CommandButton(LoggerCommandIDs.openLog, listIcon, 'Open log');
let reloadAllNodesButton = CommandButton(commandIDs.reloadAllNodes, reloadAllIcon, 'Reload all nodes');
let toggleAllLinkAnimationButton = CommandButton(commandIDs.toggleAllLinkAnimation, toggleAnimationIcon, 'Toggle low power mode by disabling link animation');
let compileButton = CommandButton(commandIDs.compileXircuit, checkIcon, 'Compile Xircuits');
let compileAndRunButton = CommandButton(commandIDs.runXircuit, runIcon,'Compile and Run Xircuits');
let compileButton = CommandButton(commandIDs.compileXircuit, compileIcon, 'Compile Xircuits');
let compileAndRunButton = CommandButton(commandIDs.runXircuit, compileRunIcon,'Compile and Run Xircuits');

widget.toolbar.insertItem(0, 'xircuits-add-undo', undoButton);
widget.toolbar.insertItem(1, 'xircuits-add-redo', redoButton);
Expand Down
11 changes: 5 additions & 6 deletions src/components/XircuitsBodyWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ export const BodyWidget: FC<BodyWidgetProps> = ({
await commands.execute(commandIDs.saveDocManager);
}

const handleCompileClick = () => {
const handleCompileClick = async() => {
// Only compile xircuit if it is currently in focus
// This must be first to avoid unnecessary complication
if (shell.currentWidget?.id !== widgetId) {
Expand All @@ -545,16 +545,15 @@ export const BodyWidget: FC<BodyWidgetProps> = ({

let allNodesConnected = checkAllNodesConnected();

if (!saved) {
alert("Please save before compiling.");
return;
}
// if (!saved) {
// alert("Please save before compiling.");
// return;
// }

if (!allNodesConnected) {
alert("Please connect all the nodes before compiling.");
return;
}

let showOutput = true;
setCompiled(true);
commands.execute(commandIDs.compileFile, { showOutput, componentList });
Expand Down
7 changes: 4 additions & 3 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -236,14 +236,14 @@ const xircuits: JupyterFrontEndPlugin<void> = {
};

try {
return await requestAPI<any>('file/compile', {
return await requestAPI<any>('file/compile-recursive', {
body: JSON.stringify(data),
method: 'POST',
});

} catch (reason) {
console.error(
'Error on POST /xircuits/file/compile', data, reason
'Error on POST /xircuits/file/compile-recursive', data, reason
);
}
}
Expand Down Expand Up @@ -371,6 +371,7 @@ const xircuits: JupyterFrontEndPlugin<void> = {
await compileXircuitsFile(xircuitsFile.path);
}
}
browserFactory.tracker.currentWidget.model.refresh();
}
});

Expand Down Expand Up @@ -474,4 +475,4 @@ const plugins: JupyterFrontEndPlugin<any>[] = [
logPlugin
];

export default plugins;
export default plugins;
4 changes: 4 additions & 0 deletions src/ui-components/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import lockSvg from '../../style/icons/lock.svg';
import breakpointSvg from '../../style/icons/breakpoint.svg';
import nextSvg from '../../style/icons/next.svg';
import revertSvg from '../../style/icons/revert.svg';
import compileSvg from '../../style/icons/compile.svg';
import compileRunSvg from '../../style/icons/compile-run.svg';
import componentLibSvg from '../../style/icons/component-library.svg';
import reloadAllSvg from '../../style/icons/reload-all.svg';
import toggleAnimationSvg from '../../style/icons/low-power.svg';
Expand All @@ -25,6 +27,8 @@ export const lockIcon = new LabIcon({ name: 'xircuits:lockIcon', svgstr: lockSvg
export const breakpointIcon = new LabIcon({ name: 'xircuits:breakpointIcon', svgstr: breakpointSvg });
export const nextIcon = new LabIcon({ name: 'xircuits:nextIcon', svgstr: nextSvg });
export const revertIcon = new LabIcon({ name: 'xircuits:revertIcon', svgstr: revertSvg });
export const compileIcon = new LabIcon({ name: 'xircuits:compileIcon', svgstr: compileSvg });
export const compileRunIcon = new LabIcon({ name: 'xircuits:compileRunIcon', svgstr: compileRunSvg });
export const reloadAllIcon = new LabIcon({ name: 'xircuits:reloadAllIcon', svgstr: reloadAllSvg });
export const toggleAnimationIcon = new LabIcon({ name: 'xircuits:toggleAnimationIcon', svgstr: toggleAnimationSvg });
export const componentLibIcon = new LabIcon({ name: 'xircuits:componentLibIcon', svgstr: componentLibSvg });
Expand Down
29 changes: 29 additions & 0 deletions style/icons/compile-run.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions style/icons/compile.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion xircuits/compiler/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .compiler import compile
from .compiler import compile, recursive_compile
60 changes: 54 additions & 6 deletions xircuits/compiler/compiler.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,62 @@
import json

import os
from xircuits.compiler.parser import XircuitsFileParser
from xircuits.compiler.generator import CodeGenerator


def compile(input_file, output_file, component_python_paths=None):
def compile(input_file_path, output_file_path, component_python_paths=None):
if component_python_paths is None:
component_python_paths = {}

parser = XircuitsFileParser()
graph = parser.parse(input_file)
with open(input_file_path, 'r', encoding='utf-8') as in_f:
graph = parser.parse(in_f)
generator = CodeGenerator(graph, component_python_paths)
generator.generate(output_file)
with open(output_file_path, 'w', encoding='utf-8') as out_f:
generator.generate(out_f)

def recursive_compile(input_file_path, component_python_paths=None, visited_files=None):
if component_python_paths is None:
component_python_paths = {}
if visited_files is None:
visited_files = set()

# Normalize file path
input_file_path = os.path.abspath(input_file_path)

if input_file_path in visited_files:
return

visited_files.add(input_file_path)

# Read the Xircuits workflow file
try:
with open(input_file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
except Exception as e:
print(f"Error reading {input_file_path}: {e}")
return

# Traverse layers to find nested workflows
if 'layers' in data:
for layer in data['layers']:
if 'models' in layer and isinstance(layer['models'], dict):
for model in layer['models'].values():
extras = model.get('extras', {})
if extras.get('type') == "xircuits_workflow":
# Extract and transform the path from .py to .xircuits
py_path = extras.get('path')
if py_path:
nested_xircuits_path = py_path.replace('.py', '.xircuits')
# Resolve relative paths
nested_xircuits_path = os.path.join(os.path.dirname(input_file_path), nested_xircuits_path)
# Recursively compile the nested workflow
recursive_compile(nested_xircuits_path, component_python_paths, visited_files)

# Compile the current workflow
py_output_path = input_file_path.replace('.xircuits', '.py')
# print(f"Compiling {input_file_path} to {py_output_path}")

try:
compile(input_file_path, py_output_path, component_python_paths=component_python_paths)
print(f"Compiled {input_file_path} to {py_output_path}")
except Exception as e:
print(f"Failed to compile {input_file_path}: {e}")
6 changes: 5 additions & 1 deletion xircuits/handlers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from jupyter_server.utils import url_path_join

from .compile_xircuits import CompileXircuitsFileRouteHandler
from .compile_xircuits import CompileXircuitsFileRouteHandler, CompileRecursiveXircuitsFileRouteHandler
from .components import ComponentsRouteHandler
from .config import RunConfigRouteHandler, SplitModeConfigHandler
from .debugger import DebuggerRouteHandler
Expand Down Expand Up @@ -38,6 +38,10 @@ def setup_handlers(web_app, url_path):
url_path_join(base_url, url_path, "file/compile"),
CompileXircuitsFileRouteHandler
),
(
url_path_join(base_url, url_path, "file/compile-recursive"),
CompileRecursiveXircuitsFileRouteHandler
),
(
url_path_join(base_url, url_path, "library/reload_config"),
ReloadComponentLibraryConfigHandler
Expand Down
40 changes: 33 additions & 7 deletions xircuits/handlers/compile_xircuits.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from pathlib import Path

from xircuits.compiler import compile
from xircuits.compiler import compile, recursive_compile
import traceback


Expand All @@ -21,18 +21,45 @@ def get(self):
def post(self):
input_data = self.get_json_body()

input_file_path = input_data["filePath"]
output_file_path = input_data["outPath"]
input_file_path = self.__get_notebook_absolute_path__(input_data["filePath"])
output_file_path = self.__get_notebook_absolute_path__(input_data["outPath"])

component_python_paths = input_data["pythonPaths"]

msg = ""

try:
with open(self.__get_notebook_absolute_path__(input_file_path), 'r', encoding='utf-8') as infile:
with open(self.__get_notebook_absolute_path__(output_file_path), 'w') as outfile:
compile(infile, outfile, component_python_paths)
compile(str(input_file_path), str(output_file_path), component_python_paths)
msg = "completed"

except Exception:
msg = traceback.format_exc()
print(msg)
pass

finally:
data = {"message": msg}
self.finish(json.dumps(data))

class CompileRecursiveXircuitsFileRouteHandler(APIHandler):
def __get_notebook_absolute_path__(self, path):
return (Path(self.application.settings['server_root_dir']) / path).expanduser().resolve()

@tornado.web.authenticated
def get(self):
self.finish(json.dumps({"data": "This is file/compile-recursive endpoint!"}))

@tornado.web.authenticated
def post(self):
input_data = self.get_json_body()

input_file_path = self.__get_notebook_absolute_path__(input_data["filePath"])
component_python_paths = input_data["pythonPaths"]

msg = ""

try:
recursive_compile(str(input_file_path), component_python_paths=component_python_paths)
msg = "completed"

except Exception:
Expand All @@ -41,6 +68,5 @@ def post(self):
pass

finally:

data = {"message": msg}
self.finish(json.dumps(data))
Loading

0 comments on commit e4d2ad9

Please sign in to comment.