Skip to content

Instantly share code, notes, and snippets.

@jeremyherbert
Created March 16, 2020 02:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeremyherbert/c82e2733f0d8e3a1621684bfd38ddb3d to your computer and use it in GitHub Desktop.
Save jeremyherbert/c82e2733f0d8e3a1621684bfd38ddb3d to your computer and use it in GitHub Desktop.
fusion360 addin to run python scripts from json
import adsk.core
import adsk.fusion
import importlib
import inspect
import traceback
import os
import sys
import gettext
import types
import tempfile
import threading
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
pydevd_path = None
ui = None
handlers = []
saved_context = None
custom_event = None
custom_event_name = 'fusion_idea_run_script'
THREAD_HANDLE = None
script_run_log_path = os.path.join(tempfile.gettempdir(), "f360_script_run_log.txt")
class ThreadEventHandler(adsk.core.CustomEventHandler):
def __init__(self):
super().__init__()
def notify(self, args):
try:
args = json.loads(args.additionalInfo)
script_path = os.path.abspath(args['script'])
detach = args['detach']
if os.path.isfile(script_path):
script_name = os.path.splitext(os.path.basename(script_path))[0]
script_dir = os.path.dirname(script_path)
sys.path.append(script_dir)
try:
import attach_script
attach_script.attach(args['debug_port'], 'localhost')
module = importlib.import_module(script_name)
importlib.reload(module)
module.run({'isApplicationStartup': False})
finally:
del sys.path[-1]
if detach:
try:
import pydevd
pydevd.stoptrace()
except:
pass
except:
with open(script_run_log_path, 'a') as f:
f.write(traceback.format_exc())
class FusionInjectorHTTPRequestHandler(BaseHTTPRequestHandler):
def __init__(self, *args, **kwargs):
self._pydevd_path = None
super().__init__(*args, **kwargs)
def do_POST(self):
content_length = int(self.headers['Content-Length'])
body = self.rfile.read(content_length)
try:
request_data = json.loads(body.decode())
assert "jetbrains_pydevd_path" in request_data
assert "script" in request_data
assert "detach" in request_data
assert "debug_port" in request_data
if self._pydevd_path is None:
self._pydevd_path = request_data['jetbrains_pydevd_path']
sys.path.append(os.path.join(self._pydevd_path, 'pydevd_attach_to_process'))
sys.path.append(self._pydevd_path)
adsk.core.Application.get().fireCustomEvent("fusion_idea_run_script", json.dumps(request_data))
self.send_response(200)
self.end_headers()
self.wfile.write(b"done")
except:
self.send_response(500)
self.end_headers()
self.wfile.write(traceback.format_exc().encode())
def run_server():
server_address = ('localhost', 8181)
httpd = HTTPServer(server_address, FusionInjectorHTTPRequestHandler)
httpd.serve_forever()
def run(context):
try:
app = adsk.core.Application.get()
ui = app.userInterface
try:
app.unregisterCustomEvent(custom_event_name)
except:
pass
custom_event = app.registerCustomEvent(custom_event_name)
event_handler = ThreadEventHandler()
custom_event.add(event_handler)
handlers.append(event_handler)
THREAD_HANDLE = threading.Thread(target=run_server, daemon=True)
THREAD_HANDLE.start()
ui.messageBox('AddIn Started')
except:
if ui:
ui.messageBox(('AddIn Start Failed: {}').format(traceback.format_exc()))
def stop(context):
ui = None
try:
app = adsk.core.Application.get()
ui = app.userInterface
except:
if ui:
ui.messageBox(('AddIn Stop Failed: {}').format(traceback.format_exc()))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment