Skip to content

Commit 23f19ec

Browse files
authored
Merge pull request #2 from dfki-ric/owl_support
Added new entities for ontology based planning
2 parents bba3fb4 + 288f823 commit 23f19ec

File tree

4 files changed

+350
-0
lines changed

4 files changed

+350
-0
lines changed

bin/xdbi-editor.py

+314
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
#!/usr/bin/python3
2+
3+
import sys
4+
import argparse
5+
import os
6+
import xtypes_py # TODO: Generatable
7+
import xdbi_py
8+
import json
9+
10+
def proceed(msg):
11+
print(msg)
12+
choice = input("Do you want to proceed or skip? [s: skip, other: proceed]: ")
13+
choice = choice.lower()
14+
if choice == "s":
15+
return False
16+
return True
17+
18+
def select_class_from(reg):
19+
print("*** Select class ***")
20+
known_classes = sorted(list(reg.get_classnames()))
21+
for i, x in enumerate(known_classes):
22+
print(f"{i}. {x}")
23+
selected_class_index = input("Which class of XTypes do you want to add/edit? [0-{len(known_classes)-1}]: ")
24+
if not selected_class_index:
25+
return None
26+
selected_class_index = int(selected_class_index)
27+
if selected_class_index < 0 or selected_class_index >= len(known_classes):
28+
return None
29+
return known_classes[selected_class_index]
30+
31+
def edit_properties(xtype):
32+
print("*** Edit properties ***")
33+
current_props = xtype.get_properties()
34+
while 1:
35+
for k,v in current_props.items():
36+
print(f" {k} = {v}")
37+
k = input("Which property do you want to modify? ENTER will skip: ")
38+
if not k:
39+
print("Done")
40+
break
41+
if k not in current_props:
42+
print(f"{k} is not a valid key!")
43+
continue
44+
allowed_values = sorted(xtype.get_allowed_property_values(k), reverse=True)
45+
user_input = None
46+
if len(allowed_values) > 0:
47+
for i, value in enumerate(allowed_values):
48+
print(f"{i}. {value}")
49+
option = input(f"Please select a value for '{k}' [0-{len(allowed_values)-1}] or press ENTER: ")
50+
try:
51+
option = int(option)
52+
if option < 0 or option >= len(allowed_values):
53+
raise ValueError
54+
user_input = allowed_values[option]
55+
except ValueError:
56+
print("Invalid selection, using default value")
57+
else:
58+
user_input = input(f"Please provide value for '{k}' or press ENTER: ")
59+
if user_input:
60+
try:
61+
current_props[k] = json.loads(user_input)
62+
except:
63+
current_props[k] = json.loads('\"' + user_input + '\"')
64+
xtype.set_properties(current_props)
65+
66+
def select_target(dbi, classnames):
67+
all_targets = []
68+
for classname in classnames:
69+
all_targets.extend(dbi.find(classname=classname))
70+
for i, t in enumerate(all_targets):
71+
print(f" {i}. {t.uri()}")
72+
choice = input(f"Select a target XType [0-{len(all_targets)-1}]: ")
73+
if not choice:
74+
return None
75+
choice = int(choice)
76+
if choice < 0 or choice >= len(all_targets):
77+
return None
78+
return all_targets[choice]
79+
80+
def select_fact(xtype, relname):
81+
if xtype.has_facts(relname):
82+
current_facts = xtype.get_facts(relname)
83+
for i,f in enumerate(current_facts):
84+
print(f" {i}. {f.target.uri()} {f.edge_properties}")
85+
choice = input(f"Select a fact [0-{len(current_facts)-1}]: ")
86+
if not choice:
87+
return None
88+
choice = int(choice)
89+
if choice < 0 or choice >= len(current_facts):
90+
return None
91+
return current_facts[choice]
92+
return None
93+
94+
def edit_facts(dbi, xtype):
95+
print("*** Edit facts ***")
96+
relations = xtype.get_relations()
97+
while 1:
98+
for relname in relations:
99+
print(f" {relname}:")
100+
if not xtype.has_facts(relname):
101+
print("UNKNOWN")
102+
facts = xtype.get_facts(relname)
103+
if len(facts) < 1:
104+
print("EMPTY")
105+
for fact in facts:
106+
print(f" - {fact.edge_properties} -> {fact.target.uri()}")
107+
relname = input("Which relation do you want to modify? ENTER will skip: ")
108+
if not relname:
109+
print("Done")
110+
break
111+
if relname not in relations:
112+
print(f"{relname} is not a valid relation name!")
113+
continue
114+
choice = input(f"[a: add a new fact, e: edit an existing fact, r: remove a fact, d: delete all facts, u: set unknown facts to empty, ENTER: skip]: ")
115+
if not choice:
116+
continue
117+
choice = choice.lower()
118+
if choice == "a":
119+
# Add a new fact
120+
target = select_target(dbi, relations[relname].to_classnames if xtype.get_relations_dir(relname) else relations[relname].from_classnames)
121+
if not target:
122+
continue
123+
add_method = getattr(xtype, f"add_{relname}")
124+
if not callable(add_method):
125+
print("ERROR: Found non-callable add method!")
126+
continue
127+
try:
128+
add_method(target)
129+
print(f"Fact added")
130+
except Exception as e:
131+
print(f"Failed to add fact")
132+
print(e)
133+
elif choice == "e":
134+
# Edit a fact
135+
to_edit = select_fact(xtype, relname)
136+
if not to_edit:
137+
continue
138+
add_method = getattr(xtype, f"add_{relname}")
139+
if not callable(add_method):
140+
print("ERROR: Found non-callable add method!")
141+
continue
142+
# Edit edge properties
143+
current_props = to_edit.edge_properties
144+
while 1:
145+
for k,v in current_props.items():
146+
print(f" {k} = {v}")
147+
k = input("Which property do you want to modify? ENTER will skip: ")
148+
if not k:
149+
break
150+
if k not in current_props:
151+
print(f"{k} is not a valid key!")
152+
continue
153+
new_v = input(f"Please provide a new value for {k}: ")
154+
current_props[k] = type(current_props[k])(new_v)
155+
try:
156+
add_method(to_edit.target, current_props)
157+
print(f"Fact updated")
158+
except Exception as e:
159+
print(f"Failed to update fact")
160+
print(e)
161+
elif choice == "r":
162+
# Delete fact
163+
to_be_removed = select_fact(xtype, relname)
164+
if not to_be_removed:
165+
continue
166+
xtype.remove_fact(relname, to_be_removed.target)
167+
elif choice == "d":
168+
# Delete all facts
169+
if xtype.has_facts(relname):
170+
current_facts = xtype.get_facts(relname)
171+
for other,_ in current_facts:
172+
xtype.remove_fact(relname, other)
173+
elif choice == "u":
174+
# Set facts to empty
175+
xtype.set_unknown_fact_empty(relname)
176+
else:
177+
print("W00t?!")
178+
continue
179+
180+
def info_of(xtype):
181+
print("*** XType info ***")
182+
print("Properties:")
183+
for k,v in xtype.get_properties().items():
184+
print(f" {k} = {v}")
185+
print("Facts:")
186+
relations = xtype.get_relations()
187+
for relname in relations:
188+
print(f" {relname}:")
189+
if not xtype.has_facts(relname):
190+
print("UNKNOWN")
191+
facts = xtype.get_facts(relname)
192+
if len(facts) < 1:
193+
print("EMPTY")
194+
for fact in facts:
195+
print(f" - {fact.edge_properties} -> {fact.target.uri()}")
196+
197+
def main():
198+
backends = xdbi_py.get_available_backends()
199+
200+
config = {
201+
"type": "MultiDbClient",
202+
"config":
203+
{
204+
"import_servers": [],
205+
"main_server":
206+
{
207+
"type": None,
208+
"address": None,
209+
"graph": None
210+
}
211+
}
212+
}
213+
214+
parser = argparse.ArgumentParser(description='Interactive CLI to add/edit Xtype(s) in an XROCK database')
215+
# xdbi specific args
216+
parser.add_argument('-b', '--db_backend', help="Database backend to be used", choices=backends, default=backends[0])
217+
parser.add_argument('-a', '--db_address', help="The url/local path to the db", required=True)
218+
parser.add_argument('-g', '--db_graph', help="The name of the database graph to be used", required=True)
219+
parser.add_argument('-l', '--no_lookup', help="If set, the main server will NOT be used for lookup", action="store_true")
220+
parser.add_argument('-i', '--import_server', help="Specify an import server for additional lookup (format: <backend>,<address>,<graph>)", action="append", type=str)
221+
222+
args = None
223+
try:
224+
args = parser.parse_args()
225+
except SystemExit:
226+
sys.exit(1)
227+
228+
config["config"]["main_server"]["type"] = args.db_backend
229+
config["config"]["main_server"]["address"] = args.db_address
230+
config["config"]["main_server"]["graph"] = args.db_graph
231+
import_servers = args.import_server
232+
if import_servers:
233+
for import_server in import_servers:
234+
b,a,g = import_server.split(",", 2)
235+
config["config"]["import_servers"].append( {"type": b.strip(), "address": a.strip(), "graph": g.strip() } )
236+
if not args.no_lookup:
237+
config["config"]["import_servers"].append( { "name": "main", "type": args.db_backend, "address": args.db_address, "graph": args.db_graph } )
238+
239+
240+
# Acesss the database
241+
registry = xtypes_py.ProjectRegistry()
242+
dbi = xdbi_py.db_interface_from_config(registry, config=config, read_only=False)
243+
244+
print(f"{parser.description}")
245+
246+
# Editor loop
247+
while True:
248+
# Ask the user if he wants to create a new XType or edit an existing one
249+
add_or_edit = input("Do you want to create a new or edit an existing XType? [c: create, e: edit, ENTER: quit]: ")
250+
if not add_or_edit:
251+
break
252+
if add_or_edit == "c":
253+
# Select class
254+
selected_class = select_class_from(registry)
255+
if not selected_class:
256+
continue
257+
# Create new
258+
new_xtype = registry.instantiate_from(selected_class)
259+
# Edit properties
260+
if proceed("Up next: Property editing"):
261+
edit_properties(new_xtype)
262+
# Edit relations
263+
if proceed("Up next: Fact editing"):
264+
edit_facts(dbi, new_xtype)
265+
# Save or discard
266+
info_of(new_xtype)
267+
if proceed(f"Shall the new XType be stored into database?"):
268+
if dbi.add([new_xtype]):
269+
print("Stored :)")
270+
else:
271+
print("Could not store to database :(")
272+
elif add_or_edit == "e":
273+
# Select class
274+
selected_class = select_class_from(registry)
275+
if not selected_class:
276+
continue
277+
# Select xtype to edit
278+
existing_xtypes = dbi.find(classname=selected_class)
279+
if len(existing_xtypes) < 1:
280+
print(f"No XType of class {selected_class} exist in the database")
281+
continue
282+
for i, xtype in enumerate(existing_xtypes):
283+
print(f"{i}. {xtype.uri()}")
284+
index = input(f"Please select one of the XTypes above to edit by number [0-{len(existing_xtypes)-1}]: ")
285+
if not index:
286+
continue
287+
index = int(index)
288+
if index < 0 or index >= len(existing_xtypes):
289+
continue
290+
selected_xtype = existing_xtypes[index]
291+
info_of(selected_xtype)
292+
# Edit properties
293+
if proceed("Up next: Property editing"):
294+
edit_properties(selected_xtype)
295+
# Edit relations
296+
if proceed("Up next: Fact editing"):
297+
edit_facts(dbi, selected_xtype)
298+
# Save or discard
299+
info_of(selected_xtype)
300+
if proceed(f"Shall the modified XType be stored into database?"):
301+
if dbi.update([selected_xtype]):
302+
print("Stored :)")
303+
else:
304+
print("Could not store to database :(")
305+
else:
306+
# Start over
307+
print("W00t?")
308+
continue
309+
310+
print("Bye :)")
311+
sys.exit(0)
312+
313+
if __name__ == '__main__':
314+
main()

templates/capability.yml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: Capability
2+
properties:
3+
name:
4+
type: STRING
5+
default: "\"UNKNOWN\""
6+
cardinality:
7+
type: INTEGER
8+
default: 0
9+
uri:
10+
# This should build "http://rock-robotics.org/2014/01/om-schema/<name>"
11+
scheme: "http"
12+
root_path: "//rock-robotics.org/2014/01/om-schema"
13+
from:
14+
- name: name

templates/component_model.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ relations:
7575
properties:
7676
optional: true
7777
inverse: True
78+
capabilites:
79+
type: has
80+
other_classnames:
81+
- Capability
7882
uri:
7983
scheme: drock
8084
root_path: /

templates/service.yml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: Service
2+
properties:
3+
name:
4+
type: STRING
5+
default: "\"UNKNOWN\""
6+
relations:
7+
needed_capabilities:
8+
type: needs
9+
other_classnames:
10+
- Capability
11+
properties:
12+
cardinality: 1
13+
uri:
14+
# This should build "http://rock-robotics.org/2014/01/om-schema/<name>"
15+
scheme: "http"
16+
root_path: "//rock-robotics.org/2014/01/om-schema"
17+
from:
18+
- name: name

0 commit comments

Comments
 (0)