app
Fusion - the Fusion 360 Bridge
Public Made by Adomby adom
Drive Autodesk Fusion 360 from the cloud via Adom Bridge: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.
← Commit history
tests/glenn_drill.py+14−1@@ -60,7 +60,7 @@ if want('142') or want('143'): check('the zip has the inner layers', any(n.upper().endswith(('.G1', '.G2', '.GP1', '.GP2')) for n in names), names) if want('143'): print('--- #143 the panel')- PV = "import adsk.core\\nui=adsk.core.Application.get().userInterface\\np=ui.palettes.itemById('AdomActivityPalette')\\nresult=bool(p and p.isVisible)"+ PV = "import adsk.core\nui=adsk.core.Application.get().userInterface\np=ui.palettes.itemById('AdomActivityPalette')\nresult=bool(p and p.isVisible)" call('fusion_export_gerbers', {'outputDir': out + 'b'}, 300); call('fusion_export_gerbers', {'outputDir': out + 'c'}, 300) print(' right after two exports in a row:', script(PV)[0]); time.sleep(8); check('panel gone 8 s after the verb answered', script(PV)[0] is False, script(PV)) closeall()@@ -88,6 +88,19 @@ result={'hidden':z.name if z else None,'visible':z.isVisible if z else None} r = call('fusion_board_source', {'expectDocument': doc}); check('board_source too', r.get('success') is not False, r.get('error')) print(' ', script("import adsk.core\nfor i in range(app.documents.count):\n d=app.documents.item(i)\n if not d.isVisible:\n d.close(False)\n break\nresult=app.documents.count")); closeall() +if want('138'):+ print('--- #138 stable pour ids')+ doc = board('GPour'); s = st(doc); OUT = [[1, 1], [49, 1], [49, 39], [1, 39]]; OUT2 = [[2, 2], [48, 2], [48, 38], [2, 38]]+ r = call('fusion_apply_pours', {'expectDocument': doc, 'boardId': s.get('boardId'), 'expectedRevision': s.get('revision'), 'pours': [{'net': 'NB', 'layer': 'B.Cu', 'points': OUT}]}); check('a pour', r.get('success'), r.get('error'))+ ps = call('fusion_pour_state', {'expectDocument': doc}).get('pours') or []; one = ps[0].get('id') if ps else None; check('it has an id', str(one).startswith('pour:'), ps[:1])+ s = st(doc); r = call('fusion_apply_pours', {'expectDocument': doc, 'boardId': s.get('boardId'), 'expectedRevision': s.get('revision'), 'pours': [{'net': 'NC', 'layer': 'F.Cu', 'points': OUT2}]}); check('a second pour', r.get('success'), r.get('error'))+ ps = call('fusion_pour_state', {'expectDocument': doc}).get('pours') or []; check('the first keeps its id', one in [p.get('id') for p in ps] and len(ps) == 2, [p.get('id') for p in ps])+ s = st(doc); r = call('fusion_edit_pours', {'expectDocument': doc, 'boardId': s.get('boardId'), 'expectedRevision': s.get('revision'), 'pours': [{'id': one, 'isolate': 0.35}]}); ps = call('fusion_pour_state', {'expectDocument': doc}).get('pours') or []+ check('edit by id', r.get('success') and abs(next(p for p in ps if p.get('id') == one)['isolate'] - 0.35) < 1e-3, (r.get('errorCode'), r.get('error')))+ s = st(doc); r = call('fusion_remove_pours', {'expectDocument': doc, 'boardId': s.get('boardId'), 'expectedRevision': s.get('revision'), 'pours': [{'id': one}]}); ps = call('fusion_pour_state', {'expectDocument': doc}).get('pours') or []+ check('remove by id takes only that one', r.get('removed') == 1 and [p.get('net') for p in ps] == ['NC'], (r.get('errorCode'), r.get('error'), [p.get('net') for p in ps]))+ s = st(doc); r = call('fusion_remove_pours', {'expectDocument': doc, 'boardId': s.get('boardId'), 'expectedRevision': s.get('revision'), 'pours': [{'id': 'pour:x:1:nope'}]}); check('an unknown id is refused', r.get('errorCode') == 'unknown_pour', r.get('errorCode')); nodialog('after the pours'); closeall()+ if want('145'): print('--- #145 fusion_change_vias') doc = board('GVia'); s = st(doc)
tests/open_refusal_drill.py+2−1@@ -6,6 +6,7 @@ anyway is reported, and a library name clash answers with both files rather than import argparse, json, subprocess, sys, threading, time ap = argparse.ArgumentParser() for k in ('target', 'dir', 'lib', 'clash', 'other'): ap.add_argument('--' + k, required=True)+ap.add_argument('--symbol', default='3X1_JUMP', help='a part in the clash library') a = ap.parse_args(); A = ['adom-bridge', '--target', a.target, '--ai-thread', 'fusion-lane']; D = a.dir def call(v, args=None): o = subprocess.run(A + [v, json.dumps(args or {})], capture_output=True, text=True).stdout@@ -41,7 +42,7 @@ for n in [x for x in docs()[len(before):]]: call('fusion_close_document', {'name print('--- a library name clash') r = call('fusion_project_create', {'name': 'OClash', 'parentDir': D, 'overwrite': True}); check('new design', r.get('success'), r.get('error')); call('fusion_show_schematic', {}) call('fusion_execute_text_command', {'command': "Electron.run USE '%s';" % a.other})-t0 = time.time(); r = call('fusion_sch_place_part', {'library': a.clash, 'symbol': '3X1_JUMP', 'designator': 'A1', 'x': 3000, 'y': 3000})+t0 = time.time(); r = call('fusion_sch_place_part', {'library': a.clash, 'symbol': a.symbol, 'designator': 'A1', 'x': 3000, 'y': 3000}) print(' answered in %.0f s: %s %s' % (time.time() - t0, r.get('errorCode'), (r.get('error') or '')[:200])) check('answers library_name_in_use with both files', r.get('errorCode') == 'library_name_in_use' and len(r.get('librariesInUse') or []) == 2, {k: r.get(k) for k in ('success', 'errorCode', 'librariesInUse', 'error')}) check('the picker closed', r.get('pickerClosed') is True, r.get('pickerClosed')); time.sleep(3); no_dialogs('after the clash')