modelverse.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  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:
  226. raise CompilationError()
  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 model_delete(model_name):
  234. """Delete an existing model."""
  235. _goto_mode(MODE_MODELLING)
  236. _input(["model_delete", model_name])
  237. _handle_output("Success")
  238. def model_modify(model_name):
  239. """Modify an existing model."""
  240. # raises UnknownModel
  241. # raises PermissionDenied
  242. # raises UnknownError
  243. global mode
  244. global prev_mode
  245. if mode == MODE_MANUAL:
  246. prev_mode = MODE_MANUAL
  247. mode = MODE_MODIFY
  248. return None
  249. _goto_mode(MODE_MODELLING)
  250. prev_mode = MODE_MODELLING
  251. _input(["model_modify", model_name])
  252. _handle_output("Success")
  253. global current_model
  254. current_model = model_name
  255. # Mode has changed
  256. mode = MODE_MODIFY
  257. _output("Model loaded, ready for commands!")
  258. def model_list():
  259. """List all models."""
  260. # return [(model1, metamodel1), (model2, metamodel2), ...]
  261. # raises UnknownError
  262. _goto_mode(MODE_MODELLING)
  263. _input("model_list")
  264. output = _handle_output("Success: ", split=" ")
  265. if output == "":
  266. return set([])
  267. lst = set([])
  268. value = output.strip().split("\n")
  269. for v in value:
  270. m, mm = v.split(":")
  271. m = m.strip()
  272. mm = mm.strip()
  273. lst.add((m, mm))
  274. return lst
  275. def model_list_full():
  276. """List full information on all models."""
  277. # return [(model1, metamodel1, owner1, group1, permissions1), (model2, metamodel2, owner2, group2, permissions2), ...]
  278. # raises UnknownError
  279. _goto_mode(MODE_MODELLING)
  280. _input("model_list_full")
  281. output = _handle_output("Success: ", split=" ")
  282. if output == "":
  283. return set([])
  284. lst = set([])
  285. value = output.strip().split("\n")
  286. for v in value:
  287. m, mm = v.split(":")
  288. m = m.strip()
  289. mm = mm.strip()
  290. perm, own, grp, m = m.split(" ")
  291. lst.add((m, mm, own, grp, perm))
  292. return lst
  293. def verify(model):
  294. """Verify if a model conforms to its metamodel."""
  295. # return "verification_result"
  296. # raises UnknownError
  297. # raises UnknownModel
  298. _goto_mode(MODE_MODELLING)
  299. _input(["verify", model])
  300. return _handle_output("Success: ", split=" ")
  301. def model_overwrite(model_name, new_model=None):
  302. """Upload a new model and overwrite an existing model."""
  303. # return None
  304. # raises UnknownModel
  305. # raises PermissionDenied
  306. # raises CompilationError
  307. # raises UnknownError
  308. if mode not in [MODE_MODELLING, MODE_MODIFY, MODE_MANUAL]:
  309. raise InvalidMode()
  310. if new_model is not None:
  311. try:
  312. compiled = _compile_model(new_model)
  313. except Exception as e:
  314. raise CompilationError(e)
  315. else:
  316. compiled = ["exit"]
  317. if mode == MODE_MODIFY:
  318. _goto_mode(MODE_MODELLING)
  319. if mode == MODE_MODELLING:
  320. _input(["model_overwrite", model_name])
  321. elif mode == MODE_MANUAL:
  322. _input("upload")
  323. else:
  324. raise InvalidMode()
  325. _handle_output("Waiting for model constructors...")
  326. _input(compiled)
  327. _output("Success")
  328. def user_logout():
  329. """Log out the current user and break the connection."""
  330. # return None
  331. # raises UnknownError
  332. global mode
  333. _goto_mode(MODE_MODELLING)
  334. _input("exit")
  335. mode = MODE_UNCONNECTED
  336. def user_delete():
  337. """Removes the current user and break the connection."""
  338. # return None
  339. # raises UnknownError
  340. global mode
  341. _goto_mode(MODE_MODELLING)
  342. _input("self-destruct")
  343. mode = MODE_UNCONNECTED
  344. def model_render(model, mapper):
  345. """Fetch a rendered verion of a model."""
  346. # return JSON_representation
  347. # raises UnknownError
  348. # raises UnknownIdentifier
  349. # raises InterfaceMismatch
  350. _goto_mode(MODE_MODELLING)
  351. _input(["model_render", model, mapper])
  352. return _handle_output("Success: ", split=" ")
  353. def transformation_between(source, target):
  354. _goto_mode(MODE_MODELLING)
  355. _input(["transformation_between", source, target])
  356. output = _handle_output("Success: ", split=" ")
  357. if output == "":
  358. return set([])
  359. lst = set([v for v in output.split("\n")])
  360. def transformation_add_MT_language(metamodels, RAMified_name):
  361. """Create a new Model Transformation language out of a set of metamodels."""
  362. _goto_mode(MODE_MODELLING)
  363. _input(["transformation_add_MT_language"] + metamodels + ["", RAMified_name])
  364. _handle_output("Success")
  365. def transformation_add_MT(RAMified_metamodel, source_metamodels, target_metamodels, operation_name, code):
  366. """Create a new model transformation."""
  367. _goto_mode(MODE_MODELLING)
  368. try:
  369. compiled = _compile_model(code)
  370. except Exception as e:
  371. raise CompilationError(e)
  372. _input(["transformation_add_MT", RAMified_metamodel] + source_metamodels + [""] + target_metamodels + ["", operation_name])
  373. _handle_output("Waiting for model constructors...")
  374. _input(compiled)
  375. _handle_output("Success")
  376. def transformation_add_AL(source_metamodels, target_metamodels, operation_name, code):
  377. """Create a new action language model, which can be executed."""
  378. _goto_mode(MODE_MODELLING)
  379. try:
  380. compiled = _compile_AL(code)
  381. except Exception as e:
  382. raise CompilationError(e)
  383. _input(["transformation_add_AL"] + source_metamodels + [""] + target_metamodels + [""] + [operation_name])
  384. _handle_output("Waiting for code constructors...")
  385. _input(compiled)
  386. _output("Success")
  387. def transformation_add_MANUAL(source_metamodels, target_metamodels, operation_name):
  388. """Create a new manual model operation."""
  389. _goto_mode(MODE_MODELLING)
  390. _input(["transformation_add_MANUAL"] + source_metamodels + [""] + target_metamodels + [""] + [operation_name])
  391. _handle_output("Success")
  392. def transformation_execute_AL(operation_name, input_models_dict, output_models_dict, callback=lambda i: None):
  393. """Execute an existing model operation."""
  394. global mode
  395. _goto_mode(MODE_MODELLING)
  396. mv_dict_rep = []
  397. for key, value in input_models_dict.items():
  398. mv_dict_rep += [key, value]
  399. mv_dict_rep += [""]
  400. for key, value in output_models_dict.items():
  401. mv_dict_rep += [key, value]
  402. mv_dict_rep += [""]
  403. _input(["transformation_execute", operation_name] + mv_dict_rep)
  404. _handle_output("Success: ready for AL execution")
  405. # We are now executing, so everything we get is part of the dialog, except if it is the string for transformation termination
  406. while _output() not in ["Success", "Failure"]:
  407. mode = MODE_DIALOG
  408. reply = callback(_last_output())
  409. mode = MODE_MODELLING
  410. if reply is not None:
  411. _input(reply)
  412. # Got termination message, so we are done!
  413. if _last_output() == "Success":
  414. return True
  415. else:
  416. return False
  417. def transformation_execute_MANUAL(operation_name, input_models_dict, output_models_dict, callback=lambda i: None):
  418. """Execute an existing model operation."""
  419. global mode
  420. _goto_mode(MODE_MODELLING)
  421. mv_dict_rep = []
  422. for key, value in input_models_dict.items():
  423. mv_dict_rep += [key, value]
  424. mv_dict_rep += [""]
  425. for key, value in output_models_dict.items():
  426. mv_dict_rep += [key, value]
  427. mv_dict_rep += [""]
  428. _input(["transformation_execute", operation_name] + mv_dict_rep)
  429. _handle_output("Success: ready for MANUAL execution")
  430. # Skip over the begin of mini_modify
  431. _output() # Please perform manual operation X
  432. _output() # Model loaded, ready for commands
  433. # We are now executing, so everything we get is part of the dialog, except if it is the string for transformation termination
  434. mode = MODE_MANUAL
  435. callback()
  436. # Finished, so leave
  437. _input("exit")
  438. mode = MODE_MODELLING
  439. # Got termination message, so we are done!
  440. if _output() == "Success":
  441. return True
  442. else:
  443. return False
  444. def transformation_execute_MT(operation_name, input_models_dict, output_models_dict, callback=lambda i: None):
  445. """Execute an existing model operation."""
  446. global mode
  447. _goto_mode(MODE_MODELLING)
  448. mv_dict_rep = []
  449. for key, value in input_models_dict.items():
  450. mv_dict_rep += [key, value]
  451. mv_dict_rep += [""]
  452. for key, value in output_models_dict.items():
  453. mv_dict_rep += [key, value]
  454. mv_dict_rep += [""]
  455. _input(["transformation_execute", operation_name] + mv_dict_rep)
  456. _handle_output("Success: ready for MT execution")
  457. # We are now executing, so everything we get is part of the dialog, except if it is the string for transformation termination
  458. while _output() not in ["Success", "Failure"]:
  459. mode = MODE_DIALOG
  460. reply = callback(_last_output())
  461. mode = MODE_MODELLING
  462. if reply is not None:
  463. _input(reply)
  464. # Got termination message, so we are done!
  465. if _last_output() == "Success":
  466. return True
  467. else:
  468. return False
  469. def transformation_list():
  470. """List existing model operations."""
  471. _goto_mode(MODE_MODELLING)
  472. _input("transformation_list")
  473. output = _handle_output("Success: ", split=" ")
  474. if output == "":
  475. return set([])
  476. lst = set([])
  477. value = output.strip().split("\n")
  478. for v in value:
  479. t, m = v.strip().split(" ", 1)
  480. t = t[1:-1].strip()
  481. m = m.strip().split(":")[0].strip()
  482. lst.add((t, m))
  483. return lst
  484. def transformation_RAMify(metamodel_name, RAMified_metamodel_name):
  485. """Ramify an existing metamodel."""
  486. _goto_mode(MODE_MODELLING)
  487. _input(["transformation_RAMify", metamodel_name, RAMified_metamodel_name])
  488. _handle_output("Success")
  489. def process_execute(process_name, prefix, callbacks):
  490. """Execute a process model."""
  491. global mode
  492. _goto_mode(MODE_MODELLING)
  493. _input(["process_execute", process_name, prefix])
  494. _handle_output("Success")
  495. while _output() != "Success":
  496. output = _last_output()
  497. if output.startswith("Enacting "):
  498. # Next activity!
  499. t = output.split(" ", 1)[1].split(":", 1)[0]
  500. name = output.split(": ", 1)[1]
  501. if name in callbacks:
  502. callback = callbacks[name]
  503. if t == "ModelTransformation" or t == "ActionLanguage":
  504. while not (_output().startswith("Enacting ") or _last_output() == "Success"):
  505. mode = MODE_DIALOG
  506. reply = callback(_last_output())
  507. mode = MODE_MODELLING
  508. if reply is not None:
  509. _input(reply)
  510. elif t == "ManualOperation":
  511. _output() # Please perform manual operation X
  512. _output() # Model loaded, ready for commands
  513. mode = MODE_MANUAL
  514. callback()
  515. _input("exit")
  516. mode = MODE_MODELLING
  517. def permission_modify():
  518. """Modify permissions of a model."""
  519. raise NotImplementedError()
  520. def permission_owner():
  521. """Modify the owning user of a model."""
  522. raise NotImplementedError()
  523. def permission_group():
  524. """Modify the owning group of a model."""
  525. raise NotImplementedError()
  526. def group_create():
  527. """Create a new group."""
  528. raise NotImplementedError()
  529. def group_delete():
  530. """Delete a group of which you are an owner."""
  531. raise NotImplementedError()
  532. def group_owner_add():
  533. """Add a new owning user to a group you own."""
  534. raise NotImplementedError()
  535. def group_owner_delete():
  536. """Delete an owning user to a group you own."""
  537. raise NotImplementedError()
  538. def group_join():
  539. """Add a new user to a group you own."""
  540. raise NotImplementedError()
  541. def group_kick():
  542. """Delete a user from a group you own."""
  543. raise NotImplementedError()
  544. def group_list():
  545. """List existing groups."""
  546. raise NotImplementedError()
  547. def admin_promote():
  548. """Promote a user to admin status."""
  549. raise NotImplementedError()
  550. def admin_demote():
  551. """Demote a user from admin status."""
  552. raise NotImplementedError()
  553. # Actual operations on the model
  554. def element_list(model_name):
  555. """Return a list of all IDs and the type of the element"""
  556. # return [(name1, type1), (name2, type2), ...]
  557. # raises UnknownError
  558. _goto_mode(MODE_MODIFY, model_name)
  559. _input("list_full")
  560. lst = set([])
  561. output = _handle_output("Success: ", split=" ")
  562. if output == "":
  563. return set([])
  564. for v in output.split("\n"):
  565. m, mm = v.split(":")
  566. m = m.strip()
  567. mm = mm.strip()
  568. lst.add((m, mm))
  569. return lst
  570. def types(model_name):
  571. """Return a list of all types usable in the model"""
  572. # return [type1, type2, ...]
  573. # raises UnknownError
  574. _goto_mode(MODE_MODIFY, model_name)
  575. _input("types")
  576. lst = set([])
  577. output = _handle_output("Success: ", split=" ")
  578. if output == "":
  579. return set([])
  580. for v in output.split("\n"):
  581. m, mm = v.split(":")
  582. m = m.strip()
  583. lst.add(m)
  584. return lst
  585. def types_full(model_name):
  586. """Return a list of full types usable in the model"""
  587. # return [(type1, typetype1), (type2, typetype2), ...]
  588. # raises UnknownError
  589. _goto_mode(MODE_MODIFY, model_name)
  590. _input("types")
  591. lst = set([])
  592. output = _handle_output("Success: ", split=" ")
  593. if output == "":
  594. return set([])
  595. for v in output.split("\n"):
  596. m, mm = v.split(":")
  597. m = m.strip()
  598. mm = mm.strip()
  599. lst.add((m, mm))
  600. return lst
  601. def read(model_name, ID):
  602. """Return a tuple of information on the element: its type and source/target (None if not an edge)"""
  603. # return (type, (source, target))
  604. # raises UnknownError
  605. # raises UnknownIdentifier
  606. _goto_mode(MODE_MODIFY, model_name)
  607. _input(["read", ID])
  608. output = _handle_output("Success: ", split=" ")
  609. v = output.split("\n")
  610. t = v[1].split(":")[1].strip()
  611. if (not v[0].startswith("Source:")):
  612. rval = (t, None)
  613. else:
  614. src = v[0].split(":")[1].strip()
  615. trg = v[1].split(":")[1].strip()
  616. rval = (t, (src, trg))
  617. return rval
  618. def read_attrs(model_name, ID):
  619. """Return a dictionary of attribute value pairs"""
  620. # return {attr1: value1, attr2: value2, ...}
  621. # raises UnknownError
  622. # raises UnknownIdentifier
  623. _goto_mode(MODE_MODIFY, model_name)
  624. _input(["read", ID])
  625. output = _handle_output("Success: ", split=" ")
  626. v = output.split("\n")
  627. searching = True
  628. rval = {}
  629. for r in v:
  630. if searching:
  631. if r == "Attributes:":
  632. # Start working on attributes
  633. searching = False
  634. else:
  635. key, value = r.split(":", 1)
  636. _, value = value.split("=", 1)
  637. key = json.loads(key.strip())
  638. value = value.strip()
  639. if value == "None":
  640. value = None
  641. elif value == "True":
  642. value = True
  643. elif value == "False":
  644. value = False
  645. else:
  646. value = json.loads(value)
  647. rval[key] = value
  648. return rval
  649. def instantiate(model_name, typename, edge=None, ID=""):
  650. """Create a new instance of the specified typename, between the selected elements (if not None), and with the provided ID (if any)"""
  651. # return instantiated_ID
  652. # raises UnknownError
  653. # raises UnknownType
  654. # raises UnknownIdentifier
  655. # raises NotAnEdge
  656. _goto_mode(MODE_MODIFY, model_name)
  657. if edge is None:
  658. _input(["instantiate_node", typename, ID])
  659. else:
  660. _input(["instantiate_edge", typename, ID, edge[0], edge[1]])
  661. return _handle_output("Success: ", split=" ")
  662. def delete_element(model_name, ID):
  663. """Delete the element with the given ID"""
  664. # return None
  665. # raises UnknownError
  666. # raises UnknownIdentifier
  667. _goto_mode(MODE_MODIFY, model_name)
  668. _input(["delete", ID])
  669. _handle_output("Success")
  670. def attr_assign(model_name, ID, attr, value):
  671. """Assign a value to an attribute"""
  672. # return None
  673. # raises UnknownError
  674. # raises UnknownIdentifier
  675. # raises NoSuchAttribute
  676. # raises UnsupportedValue
  677. _goto_mode(MODE_MODIFY, model_name)
  678. _input(["attr_add", ID, attr, value])
  679. _handle_output("Success")
  680. def attr_assign_code(model_name, ID, attr, code):
  681. """Assign a piece of Action Language code to the attribute"""
  682. # return None
  683. # raises UnknownError
  684. # raises UnknownIdentifier
  685. # raises NoSuchAttribute
  686. # raises UnsupportedValue
  687. try:
  688. compiled = _compile_AL(code)
  689. except Exception as e:
  690. raise CompilationError(e)
  691. _goto_mode(MODE_MODIFY, model_name)
  692. _input(["attr_add", ID, attr])
  693. _handle_output("Waiting for code constructors...")
  694. _input(compiled)
  695. _output("Success")
  696. def attr_delete(model_name, ID, attr):
  697. """Remove an attribute."""
  698. _goto_mode(MODE_MODIFY, model_name)
  699. _input(["attr_del", ID, attr])
  700. _handle_output("Success")
  701. def read_outgoing(model_name, ID, typename):
  702. """Returns a list of all outgoing associations of a specific type ("" = all)"""
  703. # return [name1, name2, ...]
  704. # raises UnknownError
  705. # raises UnknownIdentifier
  706. _goto_mode(MODE_MODIFY, model_name)
  707. _input(["read_outgoing", ID, typename])
  708. output = _handle_output("Success: ", split=" ")
  709. if output == "":
  710. return set([])
  711. else:
  712. return set(output.split("\n"))
  713. def read_incoming(model_name, ID, typename):
  714. """Returns a list of all incoming associations of a specific type ("" = all)"""
  715. # return [name1, name2, ...]
  716. # raises UnknownError
  717. # raises UnknownIdentifier
  718. # raises UnknownType
  719. _goto_mode(MODE_MODIFY, model_name)
  720. _input(["read_incoming", ID, typename])
  721. output = _handle_output("Success: ", split=" ")
  722. if output == "":
  723. return set([])
  724. else:
  725. return set(output.split("\n"))
  726. def read_association_source(model_name, ID):
  727. """Returns the source of an association."""
  728. # returns name
  729. # raises UnknownError
  730. # raises UnknownIdentifier
  731. # raises NotAnAssociation
  732. _goto_mode(MODE_MODIFY, model_name)
  733. _input(["read_association_source", ID])
  734. return _handle_output("Success: ", split=" ")
  735. def read_association_destination(model_name, ID):
  736. """Returns the destination of an association."""
  737. # returns name
  738. # raises UnknownError
  739. # raises UnknownIdentifier
  740. # raises NotAnAssociation
  741. _goto_mode(MODE_MODIFY, model_name)
  742. _input(["read_association_destination", ID])
  743. return _handle_output("Success: ", split=" ")
  744. def model_exit():
  745. """Leave model modify mode."""
  746. # return None
  747. # raises UnknownError
  748. global mode
  749. global prev_mode
  750. if prev_mode == MODE_MANUAL:
  751. mode = MODE_MANUAL
  752. return
  753. if mode != MODE_MODIFY:
  754. raise InvalidMode()
  755. _input("exit")
  756. _output("Success")
  757. mode = MODE_MODELLING