modelverse.py 27 KB

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