modelverse.py 28 KB

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