modelverse.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895
  1. import urllib
  2. import urllib2
  3. import json
  4. import random
  5. from urllib2 import URLError
  6. import sys
  7. import time
  8. COMPILER_PATH = "interface/HUTN"
  9. MODE_UNCONNECTED = 0
  10. MODE_UNAUTHORIZED = 1
  11. MODE_MODELLING = 2
  12. MODE_MODIFY = 3
  13. MODE_DIALOG = 4
  14. MODE_MANUAL = 5
  15. # Bind to the compiler (might have to update path manually!)
  16. sys.path.append(COMPILER_PATH)
  17. from hutn_compiler.compiler import main as do_compile
  18. # Exceptions
  19. class ModelverseException(Exception):
  20. pass
  21. class UnknownError(ModelverseException):
  22. pass
  23. class UnknownIdentifier(ModelverseException):
  24. pass
  25. class UnknownType(ModelverseException):
  26. pass
  27. class NotAnAssociation(ModelverseException):
  28. pass
  29. class UnsupportedValue(ModelverseException):
  30. pass
  31. class CompilationError(ModelverseException):
  32. pass
  33. class NoSuchAttribute(ModelverseException):
  34. pass
  35. class UnknownModel(ModelverseException):
  36. pass
  37. class ConnectionError(ModelverseException):
  38. pass
  39. class ModelExists(ModelverseException):
  40. pass
  41. class PermissionDenied(ModelverseException):
  42. pass
  43. class InvalidMode(ModelverseException):
  44. pass
  45. class InterfaceMismatch(ModelverseException):
  46. pass
  47. # Helper functions and configuration: do not use yourself!
  48. taskname = None
  49. address = None
  50. last_output = None
  51. mode = MODE_UNCONNECTED
  52. prev_mode = None
  53. current_model = None
  54. def _goto_mode(new_mode, model_name=None):
  55. global mode
  56. if mode == MODE_MODELLING and new_mode == MODE_MODIFY:
  57. # Are in root view, but want to modify a model
  58. model_modify(model_name)
  59. elif mode == MODE_MODIFY and new_mode == MODE_MODIFY and model_name != None and current_model != model_name:
  60. # Are in modify mode, but want to modify a different model
  61. model_exit()
  62. model_modify(model_name)
  63. elif mode == MODE_MODIFY and new_mode == MODE_MODELLING:
  64. model_exit()
  65. elif mode == new_mode:
  66. return
  67. else:
  68. # Go to a mode that we have no automatic transfer to: raise exception
  69. raise InvalidMode()
  70. def _input(value):
  71. # Ugly json encoding of primitives
  72. print("[IN] %s" % value)
  73. if isinstance(value, type([])):
  74. value = json.dumps(value)
  75. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "data": value, "taskname": taskname}))).read()
  76. else:
  77. value = json.dumps(value)
  78. #print("Set input: " + str(value))
  79. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": value, "taskname": taskname}))).read()
  80. def _input_raw(value, taskname):
  81. # Ugly json encoding of primitives
  82. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": value, "taskname": taskname}))).read()
  83. def _compile_AL(code):
  84. # Compile an action language file and send the compiled code
  85. code_fragments = code.split("\n")
  86. code_fragments = [i for i in code_fragments if i.strip() != ""]
  87. code_fragments = [i.replace(" ", "\t") for i in code_fragments]
  88. initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
  89. code_fragments = [i[initial_tabs:] for i in code_fragments]
  90. code_fragments.append("")
  91. code = "\n".join(code_fragments)
  92. with open("__constraint.alc", "w") as f:
  93. f.write(code)
  94. f.flush()
  95. return do_compile("__constraint.alc", COMPILER_PATH + "/grammars/actionlanguage.g", "CS")
  96. def _compile_model(code):
  97. # Compile a model and send the compiled graph
  98. # First change multiple spaces to a tab
  99. code_fragments = code.split("\n")
  100. code_fragments = [i for i in code_fragments if i.strip() != ""]
  101. code_fragments = [i.replace(" ", "\t") for i in code_fragments]
  102. initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
  103. code_fragments = [i[initial_tabs:] for i in code_fragments]
  104. code_fragments.append("")
  105. code = "\n".join(code_fragments)
  106. with open("__model.mvc", "w") as f:
  107. f.write(code)
  108. f.flush()
  109. return do_compile("__model.mvc", COMPILER_PATH + "/grammars/modelling.g", "M") + ["exit"]
  110. def _output(expected=None):
  111. try:
  112. global last_output
  113. last_output = json.loads(urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "taskname": taskname}))).read())
  114. print("[OUT] %s" % last_output)
  115. except:
  116. raise UnknownError()
  117. if expected is not None and last_output != expected:
  118. raise InterfaceMismatch(_last_output(), expected)
  119. return last_output
  120. def _last_output():
  121. return last_output
  122. # Raise common exceptions
  123. def _handle_output(requested=None, split=None):
  124. value = _output()
  125. if value.startswith("Model exists: "):
  126. raise ModelExists(value.split(": ", 1)[1])
  127. elif value.startswith("Permission denied"):
  128. raise PermissionDenied(value.split(": ", 1)[1])
  129. elif value.startswith("Model not found: "):
  130. raise UnknownModel(value.split(": ", 1)[1])
  131. elif value.startswith("Element not found: "):
  132. raise UnknownIdentifier(value.split(": ", 1)[1])
  133. elif value.startswith("Element exists: "):
  134. raise ElementExists(value.split(": ", 1)[1])
  135. elif value.startswith("Attribute not found: "):
  136. raise NoSuchAttribute(value.split(": ", 1)[1])
  137. elif requested is not None and value.startswith(requested):
  138. if split is None:
  139. return value
  140. else:
  141. splitted = value.strip().split(split, 1)
  142. if len(splitted) == 1:
  143. return ""
  144. else:
  145. return splitted[1].rstrip()
  146. else:
  147. raise InterfaceMismatch(value)
  148. # Main MvC operations
  149. def init(address_param="http://127.0.0.1:8001", timeout=20.0):
  150. """Starts up the connection to the Modelverse."""
  151. # return None
  152. # raises ConnectionError
  153. # raises UnknownError
  154. # raises InvalidMode
  155. global mode
  156. global address
  157. global taskname
  158. address = address_param
  159. start_time = time.time()
  160. taskname = random.random()
  161. while 1:
  162. try:
  163. _input_raw('"%s"' % taskname, "task_manager")
  164. mode = MODE_UNAUTHORIZED
  165. break
  166. except URLError as e:
  167. if time.time() - start_time > timeout:
  168. raise ConnectionError(e.reason)
  169. else:
  170. time.sleep(0.1)
  171. def login(username, password):
  172. """Log in a user, if user doesn't exist, it is created."""
  173. # return None
  174. # raises UnknownError
  175. # raises PermissionDenied
  176. # raises InterfaceMismatch
  177. global mode
  178. _goto_mode(MODE_UNAUTHORIZED)
  179. _output("Log on as which user?")
  180. _input(username)
  181. if _output() == "Password for existing user?":
  182. _input(password)
  183. if _output() == "Welcome to the Model Management Interface v2.0!":
  184. _output("Use the 'help' command for a list of possible commands")
  185. _input("quiet")
  186. mode = MODE_MODELLING
  187. elif _last_output() == "Wrong password!":
  188. raise PermissionDenied()
  189. else:
  190. raise InterfaceMismatch(_last_output())
  191. elif _last_output() == "This is a new user: please give password!":
  192. _input(password)
  193. _output("Please repeat the password")
  194. _input(password)
  195. if _output() == "Passwords match!":
  196. _output("Welcome to the Model Management Interface v2.0!")
  197. _output("Use the 'help' command for a list of possible commands")
  198. _input("quiet")
  199. mode = MODE_MODELLING
  200. elif _last_output() == "Not the same password!":
  201. # We just sent the same password, so it should be identical, unless the interface changed
  202. raise InterfaceMismatch(_last_output())
  203. else:
  204. raise InterfaceMismatch(_last_output())
  205. else:
  206. raise InterfaceMismatch(_last_output())
  207. def model_add(model_name, metamodel_name, model_code=None):
  208. """Instantiate a new model."""
  209. # return None
  210. # raises UnknownModel
  211. # raises ModelExists
  212. # raises UnknownError
  213. # raises PermissionDenied
  214. # raises CompilationError
  215. _goto_mode(MODE_MODELLING)
  216. # Do this before creating the model, as otherwise compilation errors would make us inconsistent
  217. if model_code is not None:
  218. try:
  219. compiled = _compile_model(model_code)
  220. except:
  221. raise CompilationError()
  222. else:
  223. compiled = ["exit"]
  224. _input(["model_add", metamodel_name, model_name])
  225. _handle_output("Waiting for model constructors...")
  226. _input(compiled)
  227. _output("Success")
  228. def model_delete(model_name):
  229. """Delete an existing model."""
  230. _goto_mode(MODE_MODELLING)
  231. _input(["model_delete", model_name])
  232. _handle_output("Success")
  233. def model_modify(model_name):
  234. """Modify an existing model."""
  235. # raises UnknownModel
  236. # raises PermissionDenied
  237. # raises UnknownError
  238. global mode
  239. global prev_mode
  240. if mode == MODE_MANUAL:
  241. prev_mode = MODE_MANUAL
  242. mode = MODE_MODIFY
  243. return None
  244. _goto_mode(MODE_MODELLING)
  245. prev_mode = MODE_MODELLING
  246. _input(["model_modify", model_name])
  247. _handle_output("Success")
  248. global current_model
  249. current_model = model_name
  250. # Mode has changed
  251. mode = MODE_MODIFY
  252. _output("Model loaded, ready for commands!")
  253. def model_list():
  254. """List all models."""
  255. # return [(model1, metamodel1), (model2, metamodel2), ...]
  256. # raises UnknownError
  257. _goto_mode(MODE_MODELLING)
  258. _input("model_list")
  259. output = _handle_output("Success: ", split=" ")
  260. if output == "":
  261. return set([])
  262. lst = set([])
  263. value = output.strip().split("\n")
  264. for v in value:
  265. m, mm = v.split(":")
  266. m = m.strip()
  267. mm = mm.strip()
  268. lst.add((m, mm))
  269. return lst
  270. def model_list_full():
  271. """List full information on all models."""
  272. # return [(model1, metamodel1, owner1, group1, permissions1), (model2, metamodel2, owner2, group2, permissions2), ...]
  273. # raises UnknownError
  274. _goto_mode(MODE_MODELLING)
  275. _input("model_list_full")
  276. output = _handle_output("Success: ", split=" ")
  277. if output == "":
  278. return set([])
  279. lst = set([])
  280. value = output.strip().split("\n")
  281. for v in value:
  282. m, mm = v.split(":")
  283. m = m.strip()
  284. mm = mm.strip()
  285. perm, own, grp, m = m.split(" ")
  286. lst.add((m, mm, own, grp, perm))
  287. return lst
  288. def verify(model):
  289. """Verify if a model conforms to its metamodel."""
  290. # return "verification_result"
  291. # raises UnknownError
  292. # raises UnknownModel
  293. _goto_mode(MODE_MODELLING)
  294. _input(["verify", model])
  295. return _handle_output("Success: ", split=" ")
  296. def model_overwrite(model_name, new_model=None):
  297. """Upload a new model and overwrite an existing model."""
  298. # return None
  299. # raises UnknownModel
  300. # raises PermissionDenied
  301. # raises CompilationError
  302. # raises UnknownError
  303. if mode not in [MODE_MODELLING, MODE_MODIFY, MODE_MANUAL]:
  304. raise InvalidMode()
  305. if new_model is not None:
  306. try:
  307. compiled = _compile_model(new_model)
  308. except Exception as e:
  309. raise CompilationError(e)
  310. else:
  311. compiled = ["exit"]
  312. if mode == MODE_MODELLING:
  313. _input(["model_overwrite", model_name])
  314. elif mode == MODE_MODIFY or mode == MODE_MANUAL:
  315. _input("upload")
  316. else:
  317. raise InvalidMode()
  318. _handle_output("Waiting for model constructors...")
  319. _input(compiled)
  320. _output("Success")
  321. def user_logout():
  322. """Log out the current user and break the connection."""
  323. # return None
  324. # raises UnknownError
  325. global mode
  326. _goto_mode(MODE_MODELLING)
  327. _input("exit")
  328. mode = MODE_UNCONNECTED
  329. def user_delete():
  330. """Removes the current user and break the connection."""
  331. # return None
  332. # raises UnknownError
  333. global mode
  334. _goto_mode(MODE_MODELLING)
  335. _input("self-destruct")
  336. mode = MODE_UNCONNECTED
  337. def model_render(model, mapper):
  338. """Fetch a rendered verion of a model."""
  339. # return JSON_representation
  340. # raises UnknownError
  341. # raises UnknownIdentifier
  342. # raises InterfaceMismatch
  343. _goto_mode(MODE_MODELLING)
  344. _input(["model_render", model, mapper])
  345. return _handle_output("Success: ", split=" ")
  346. def transformation_between(source, target):
  347. _goto_mode(MODE_MODELLING)
  348. _input(["transformation_between", source, target])
  349. output = _handle_output("Success: ", split=" ")
  350. if output == "":
  351. return set([])
  352. lst = set([v for v in output.split("\n")])
  353. def transformation_add_MT_language(metamodels, RAMified_name):
  354. """Create a new Model Transformation language out of a set of metamodels."""
  355. _goto_mode(MODE_MODELLING)
  356. _input(["transformation_add_MT_language"] + metamodels + ["", RAMified_name])
  357. _handle_output("Success")
  358. def transformation_add_MT(RAMified_metamodel, source_metamodels, target_metamodels, operation_name, code):
  359. """Create a new model transformation."""
  360. _goto_mode(MODE_MODELLING)
  361. try:
  362. compiled = _compile_model(code)
  363. except Exception as e:
  364. raise CompilationError(e)
  365. _input(["transformation_add_MT", RAMified_metamodel] + source_metamodels + [""] + target_metamodels + ["", operation_name])
  366. _handle_output("Waiting for model constructors...")
  367. _input(compiled)
  368. _handle_output("Success")
  369. def transformation_add_AL(source_metamodels, target_metamodels, operation_name, code):
  370. """Create a new action language model, which can be executed."""
  371. _goto_mode(MODE_MODELLING)
  372. try:
  373. compiled = _compile_AL(code)
  374. except Exception as e:
  375. raise CompilationError(e)
  376. _input(["transformation_add_AL"] + source_metamodels + [""] + target_metamodels + [""] + [operation_name])
  377. _handle_output("Waiting for code constructors...")
  378. _input(compiled)
  379. _output("Success")
  380. def transformation_add_MANUAL(source_metamodels, target_metamodels, operation_name):
  381. """Create a new manual model operation."""
  382. _goto_mode(MODE_MODELLING)
  383. _input(["transformation_add_MANUAL"] + source_metamodels + [""] + target_metamodels + [""] + [operation_name])
  384. _handle_output("Success")
  385. def transformation_execute_AL(operation_name, input_models_dict, output_models_dict, callback=lambda i: None):
  386. """Execute an existing model operation."""
  387. global mode
  388. _goto_mode(MODE_MODELLING)
  389. mv_dict_rep = []
  390. for key, value in input_models_dict.items():
  391. mv_dict_rep += [key, value]
  392. mv_dict_rep += [""]
  393. for key, value in output_models_dict.items():
  394. mv_dict_rep += [key, value]
  395. mv_dict_rep += [""]
  396. _input(["transformation_execute", operation_name] + mv_dict_rep)
  397. _handle_output("Success: ready for AL execution")
  398. # We are now executing, so everything we get is part of the dialog, except if it is the string for transformation termination
  399. while _output() not in ["Success", "Failure"]:
  400. mode = MODE_DIALOG
  401. reply = callback(_last_output())
  402. mode = MODE_MODELLING
  403. if reply is not None:
  404. _input(reply)
  405. # Got termination message, so we are done!
  406. if _last_output() == "Success":
  407. return True
  408. else:
  409. return False
  410. def transformation_execute_MANUAL(operation_name, input_models_dict, output_models_dict, callback=lambda i: None):
  411. """Execute an existing model operation."""
  412. global mode
  413. _goto_mode(MODE_MODELLING)
  414. mv_dict_rep = []
  415. for key, value in input_models_dict.items():
  416. mv_dict_rep += [key, value]
  417. mv_dict_rep += [""]
  418. for key, value in output_models_dict.items():
  419. mv_dict_rep += [key, value]
  420. mv_dict_rep += [""]
  421. _input(["transformation_execute", operation_name] + mv_dict_rep)
  422. _handle_output("Success: ready for MANUAL execution")
  423. # Skip over the begin of mini_modify
  424. _output()
  425. _output()
  426. _output()
  427. _output()
  428. # We are now executing, so everything we get is part of the dialog, except if it is the string for transformation termination
  429. mode = MODE_MANUAL
  430. callback()
  431. # Finished, so leave
  432. _input("exit")
  433. mode = MODE_MODELLING
  434. # Got termination message, so we are done!
  435. if _output() == "Success":
  436. return True
  437. else:
  438. return False
  439. def transformation_execute_MT(operation_name, input_models_dict, output_models_dict, callback=lambda i: None):
  440. """Execute an existing model operation."""
  441. global mode
  442. _goto_mode(MODE_MODELLING)
  443. mv_dict_rep = []
  444. for key, value in input_models_dict.items():
  445. mv_dict_rep += [key, value]
  446. mv_dict_rep += [""]
  447. for key, value in output_models_dict.items():
  448. mv_dict_rep += [key, value]
  449. mv_dict_rep += [""]
  450. _input(["transformation_execute", operation_name] + mv_dict_rep)
  451. _handle_output("Success: ready for MT execution")
  452. # We are now executing, so everything we get is part of the dialog, except if it is the string for transformation termination
  453. while _output() not in ["Success", "Failure"]:
  454. mode = MODE_DIALOG
  455. reply = callback(_last_output())
  456. mode = MODE_MODELLING
  457. if reply is not None:
  458. _input(reply)
  459. # Got termination message, so we are done!
  460. if _last_output() == "Success":
  461. return True
  462. else:
  463. return False
  464. def transformation_list():
  465. """List existing model operations."""
  466. _goto_mode(MODE_MODELLING)
  467. _input("transformation_list")
  468. output = _handle_output("Success: ", split=" ")
  469. if output == "":
  470. return set([])
  471. lst = set([])
  472. value = output.strip().split("\n")
  473. for v in value:
  474. t, m = v.strip().split(" ", 1)
  475. t = t[1:-1].strip()
  476. m = m.strip().split(":")[0].strip()
  477. lst.add((t, m))
  478. return lst
  479. def transformation_RAMify(metamodel_name, RAMified_metamodel_name):
  480. """Ramify an existing metamodel."""
  481. _goto_mode(MODE_MODELLING)
  482. _input(["transformation_RAMify", metamodel_name, RAMified_metamodel_name])
  483. _handle_output("Success")
  484. def process_execute(process_name, prefix, callbacks):
  485. """Execute a process model."""
  486. global mode
  487. _goto_mode(MODE_MODELLING)
  488. _input(["process_execute", process_name, prefix])
  489. _handle_output("Success")
  490. while _output() != "Success":
  491. output = _last_output()
  492. if output.startswith("Enacting "):
  493. # Next activity!
  494. t = output.split(" ", 1)[1].split(":", 1)[0]
  495. name = output.split(": ", 1)[1]
  496. if name in callbacks:
  497. callback = callbacks[name]
  498. if t == "ModelTransformation" or t == "ActionLanguage":
  499. while not (_output().startswith("Enacting ") or _last_output() == "Success"):
  500. mode = MODE_DIALOG
  501. reply = callback(_last_output())
  502. mode = MODE_MODELLING
  503. if reply is not None:
  504. _input(reply)
  505. elif t == "ManualOperation":
  506. _output()
  507. _output()
  508. _output()
  509. _output()
  510. mode = MODE_MANUAL
  511. callback()
  512. _input("exit")
  513. mode = MODE_MODELLING
  514. def permission_modify():
  515. """Modify permissions of a model."""
  516. raise NotImplementedError()
  517. def permission_owner():
  518. """Modify the owning user of a model."""
  519. raise NotImplementedError()
  520. def permission_group():
  521. """Modify the owning group of a model."""
  522. raise NotImplementedError()
  523. def group_create():
  524. """Create a new group."""
  525. raise NotImplementedError()
  526. def group_delete():
  527. """Delete a group of which you are an owner."""
  528. raise NotImplementedError()
  529. def group_owner_add():
  530. """Add a new owning user to a group you own."""
  531. raise NotImplementedError()
  532. def group_owner_delete():
  533. """Delete an owning user to a group you own."""
  534. raise NotImplementedError()
  535. def group_join():
  536. """Add a new user to a group you own."""
  537. raise NotImplementedError()
  538. def group_kick():
  539. """Delete a user from a group you own."""
  540. raise NotImplementedError()
  541. def group_list():
  542. """List existing groups."""
  543. raise NotImplementedError()
  544. def admin_promote():
  545. """Promote a user to admin status."""
  546. raise NotImplementedError()
  547. def admin_demote():
  548. """Demote a user from admin status."""
  549. raise NotImplementedError()
  550. # Actual operations on the model
  551. def element_list(model_name):
  552. """Return a list of all IDs and the type of the element"""
  553. # return [(name1, type1), (name2, type2), ...]
  554. # raises UnknownError
  555. _goto_mode(MODE_MODIFY, model_name)
  556. _input("list_full")
  557. lst = set([])
  558. output = _handle_output("Success: ", split=" ")
  559. if output == "":
  560. return set([])
  561. for v in output.split("\n"):
  562. m, mm = v.split(":")
  563. m = m.strip()
  564. mm = mm.strip()
  565. lst.add((m, mm))
  566. return lst
  567. def types(model_name):
  568. """Return a list of all types usable in the model"""
  569. # return [type1, type2, ...]
  570. # raises UnknownError
  571. _goto_mode(MODE_MODIFY, model_name)
  572. _input("types")
  573. lst = set([])
  574. output = _handle_output("Success: ", split=" ")
  575. if output == "":
  576. return set([])
  577. for v in output.split("\n"):
  578. m, mm = v.split(":")
  579. m = m.strip()
  580. lst.add(m)
  581. return lst
  582. def types_full(model_name):
  583. """Return a list of full types usable in the model"""
  584. # return [(type1, typetype1), (type2, typetype2), ...]
  585. # raises UnknownError
  586. _goto_mode(MODE_MODIFY, model_name)
  587. _input("types")
  588. lst = set([])
  589. output = _handle_output("Success: ", split=" ")
  590. if output == "":
  591. return set([])
  592. for v in output.split("\n"):
  593. m, mm = v.split(":")
  594. m = m.strip()
  595. mm = mm.strip()
  596. lst.add((m, mm))
  597. return lst
  598. def read(model_name, ID):
  599. """Return a tuple of information on the element: its type and source/target (None if not an edge)"""
  600. # return (type, (source, target))
  601. # raises UnknownError
  602. # raises UnknownIdentifier
  603. _goto_mode(MODE_MODIFY, model_name)
  604. _input(["read", ID])
  605. output = _handle_output("Success: ", split=" ")
  606. v = output.split("\n")
  607. t = v[1].split(":")[1].strip()
  608. if (not v[0].startswith("Source:")):
  609. rval = (t, None)
  610. else:
  611. src = v[0].split(":")[1].strip()
  612. trg = v[1].split(":")[1].strip()
  613. rval = (t, (src, trg))
  614. return rval
  615. def read_attrs(model_name, ID):
  616. """Return a dictionary of attribute value pairs"""
  617. # return {attr1: value1, attr2: value2, ...}
  618. # raises UnknownError
  619. # raises UnknownIdentifier
  620. _goto_mode(MODE_MODIFY, model_name)
  621. _input(["read", ID])
  622. output = _handle_output("Success: ", split=" ")
  623. v = output.split("\n")
  624. searching = True
  625. rval = {}
  626. for r in v:
  627. if searching:
  628. if r == "Attributes:":
  629. # Start working on attributes
  630. searching = False
  631. else:
  632. key, value = r.split(":", 1)
  633. _, value = value.split("=", 1)
  634. key = json.loads(key.strip())
  635. value = value.strip()
  636. if value == "None":
  637. value = None
  638. elif value == "True":
  639. value = True
  640. elif value == "False":
  641. value = False
  642. else:
  643. value = json.loads(value)
  644. rval[key] = value
  645. return rval
  646. def instantiate(model_name, typename, edge=None, ID=""):
  647. """Create a new instance of the specified typename, between the selected elements (if not None), and with the provided ID (if any)"""
  648. # return instantiated_ID
  649. # raises UnknownError
  650. # raises UnknownType
  651. # raises UnknownIdentifier
  652. # raises NotAnEdge
  653. _goto_mode(MODE_MODIFY, model_name)
  654. if edge is None:
  655. _input(["instantiate_node", typename, ID])
  656. else:
  657. _input(["instantiate_edge", typename, ID, edge[0], edge[1]])
  658. return _handle_output("Success: ", split=" ")
  659. def delete_element(model_name, ID):
  660. """Delete the element with the given ID"""
  661. # return None
  662. # raises UnknownError
  663. # raises UnknownIdentifier
  664. _goto_mode(MODE_MODIFY, model_name)
  665. _input(["delete", ID])
  666. _handle_output("Success")
  667. def attr_assign(model_name, ID, attr, value):
  668. """Assign a value to an attribute"""
  669. # return None
  670. # raises UnknownError
  671. # raises UnknownIdentifier
  672. # raises NoSuchAttribute
  673. # raises UnsupportedValue
  674. _goto_mode(MODE_MODIFY, model_name)
  675. _input(["attr_add", ID, attr, value])
  676. _handle_output("Success")
  677. def attr_assign_code(model_name, ID, attr, code):
  678. """Assign a piece of Action Language code to the attribute"""
  679. # return None
  680. # raises UnknownError
  681. # raises UnknownIdentifier
  682. # raises NoSuchAttribute
  683. # raises UnsupportedValue
  684. try:
  685. compiled = _compile_AL(code)
  686. except Exception as e:
  687. raise CompilationError(e)
  688. _goto_mode(MODE_MODIFY, model_name)
  689. _input(["attr_add", ID, attr])
  690. _handle_output("Waiting for code constructors...")
  691. _input(compiled)
  692. _output("Success")
  693. def attr_delete(model_name, ID, attr):
  694. """Remove an attribute."""
  695. _goto_mode(MODE_MODIFY, model_name)
  696. _input(["attr_del", ID, attr])
  697. _handle_output("Success")
  698. def read_outgoing(model_name, ID, typename):
  699. """Returns a list of all outgoing associations of a specific type ("" = all)"""
  700. # return [name1, name2, ...]
  701. # raises UnknownError
  702. # raises UnknownIdentifier
  703. _goto_mode(MODE_MODIFY, model_name)
  704. _input(["read_outgoing", ID, typename])
  705. output = _handle_output("Success: ", split=" ")
  706. if output == "":
  707. return set([])
  708. else:
  709. return set(output.split("\n"))
  710. def read_incoming(model_name, ID, typename):
  711. """Returns a list of all incoming associations of a specific type ("" = all)"""
  712. # return [name1, name2, ...]
  713. # raises UnknownError
  714. # raises UnknownIdentifier
  715. # raises UnknownType
  716. _goto_mode(MODE_MODIFY, model_name)
  717. _input(["read_incoming", ID, typename])
  718. output = _handle_output("Success: ", split=" ")
  719. if output == "":
  720. return set([])
  721. else:
  722. return set(output.split("\n"))
  723. def read_association_source(model_name, ID):
  724. """Returns the source of an association."""
  725. # returns name
  726. # raises UnknownError
  727. # raises UnknownIdentifier
  728. # raises NotAnAssociation
  729. _goto_mode(MODE_MODIFY, model_name)
  730. _input(["read_association_source", ID])
  731. return _handle_output("Success: ", split=" ")
  732. def read_association_destination(model_name, ID):
  733. """Returns the destination of an association."""
  734. # returns name
  735. # raises UnknownError
  736. # raises UnknownIdentifier
  737. # raises NotAnAssociation
  738. _goto_mode(MODE_MODIFY, model_name)
  739. _input(["read_association_destination", ID])
  740. return _handle_output("Success: ", split=" ")
  741. def model_exit():
  742. """Leave model modify mode."""
  743. # return None
  744. # raises UnknownError
  745. global mode
  746. global prev_mode
  747. if prev_mode == MODE_MANUAL:
  748. mode = MODE_MANUAL
  749. return
  750. if mode != MODE_MODIFY:
  751. raise InvalidMode()
  752. _input("exit")
  753. _output("Success")
  754. mode = MODE_MODELLING