modelverse.py 29 KB

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