Skip to content

Commit c3cd9f5

Browse files
committed
Acknowledge emptyable self
1 parent d512e31 commit c3cd9f5

2 files changed

Lines changed: 630 additions & 574 deletions

File tree

generate/generate.py

Lines changed: 110 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ def is_restriction(document: dict) -> bool:
3636

3737

3838
def is_single_cardinality_restriction(document: dict) -> bool:
39-
return document.get("owl:cardinality") == 1
39+
return is_restriction(document) and document.get("owl:cardinality") == 1
40+
41+
42+
def is_emptyable_cardinality_restriction(document: dict) -> bool:
43+
return is_restriction(document) and document.get("owl:minCardinality") == 0
4044

4145

4246
def is_property(document: dict) -> bool:
@@ -114,6 +118,83 @@ def get_domains(_property: dict) -> Iterator[dict]:
114118
yield domain
115119

116120

121+
def add_method(
122+
module,
123+
class_def,
124+
step_class,
125+
properties,
126+
is_path_step,
127+
single_properties,
128+
method_name,
129+
):
130+
mapping: List[Tuple[ast.Constant, ast.Expr]] = [
131+
(ast.Constant("@type"), ast.Constant(step_class["@id"]))
132+
]
133+
is_method: bool = False
134+
sorted_properties = sorted(
135+
properties,
136+
key=lambda _property: ""
137+
if _property["@id"] == "linkedql:from"
138+
else _property["@id"],
139+
)
140+
positional_args = []
141+
kwonlyargs = []
142+
for _property in sorted_properties:
143+
argument_name = remove_linked_ql(_property["@id"])
144+
if argument_name == "from":
145+
is_method = True
146+
positional_args.append(ast.arg(arg="self", annotation=None))
147+
value = ast.Attribute(value=ast.Name(id="self"), attr="step")
148+
mapping.append((ast.Constant(_property["@id"]), value))
149+
continue
150+
mapping.append((ast.Constant(_property["@id"]), ast.Name(argument_name)))
151+
_type = range_to_type(_property["rdfs:range"])
152+
if _property["@id"] not in single_properties:
153+
_type = ast.Subscript(
154+
value=ast.Attribute(value=ast.Name(id="typing"), attr="List"),
155+
slice=ast.Index(value=_type),
156+
)
157+
arg = ast.arg(arg=argument_name, annotation=_type)
158+
if len(properties) <= 2:
159+
positional_args.append(arg)
160+
else:
161+
kwonlyargs.append(arg)
162+
args = ast.arguments(
163+
args=positional_args,
164+
vararg=None,
165+
kwonlyargs=kwonlyargs or None,
166+
kw_defaults=[],
167+
kwarg=None,
168+
defaults=[],
169+
)
170+
keys, values = zip(*mapping)
171+
step_dict = ast.Dict(keys=keys, values=values)
172+
return_type = ast.Name("Path" if is_path_step else "FinalPath")
173+
returns = ast.Constant("Path") if is_path_step else ast.Name(id="FinalPath")
174+
comment = step_class["rdfs:comment"]
175+
if is_method:
176+
docstring_indent = " " * 8
177+
else:
178+
docstring_indent = " " * 4
179+
docstring = ast.Expr(
180+
ast.Constant(f"\n{docstring_indent + comment}\n{docstring_indent}")
181+
)
182+
function_def = ast.FunctionDef(
183+
name=method_name,
184+
args=args,
185+
returns=returns,
186+
decorator_list=[],
187+
body=[
188+
docstring,
189+
ast.Return(value=ast.Call(func=return_type, args=[step_dict], keywords=[])),
190+
],
191+
)
192+
if is_method:
193+
class_def.body.append(function_def)
194+
else:
195+
module.body.append(function_def)
196+
197+
117198
def generate(module_path: Path) -> str:
118199
module = astor.code_to_ast.parse_file(header_path)
119200
# print(astor.dump_tree(tree))
@@ -138,87 +219,46 @@ def generate(module_path: Path) -> str:
138219

139220
for step_class in step_classes:
140221
single_properties: Set[str] = set()
222+
emptyable_properties: Set[str] = set()
141223
is_path_step: bool = False
142224
for super_class in normalize_list(step_class["rdfs:subClassOf"]):
143225
if super_class["@id"] == "linkedql:PathStep":
144226
is_path_step = True
145-
if is_restriction(super_class) and is_single_cardinality_restriction(
146-
super_class
147-
):
227+
if is_single_cardinality_restriction(super_class):
148228
_property = super_class["owl:onProperty"]
149229
single_properties.add(_property["@id"])
230+
if is_emptyable_cardinality_restriction(super_class):
231+
_property = super_class["owl:onProperty"]
232+
emptyable_properties.add(_property["@id"])
150233
method_name = normalize_keywords(
151234
snake_case.convert(remove_linked_ql(step_class["@id"]))
152235
)
153-
is_method: bool = False
154-
mapping: List[Tuple[ast.Constant, ast.Expr]] = [
155-
(ast.Constant("@type"), ast.Constant(step_class["@id"]))
156-
]
157236
properties = properties_by_domain.get(step_class["@id"], [])
158-
sorted_properties = sorted(
237+
add_method(
238+
module,
239+
class_def,
240+
step_class,
159241
properties,
160-
key=lambda _property: ""
161-
if _property["@id"] == "linkedql:from"
162-
else _property["@id"],
242+
is_path_step,
243+
single_properties,
244+
method_name,
163245
)
164-
positional_args = []
165-
kwonlyargs = []
166-
for _property in sorted_properties:
167-
argument_name = remove_linked_ql(_property["@id"])
168-
if argument_name == "from":
169-
is_method = True
170-
positional_args.append(ast.arg(arg="self", annotation=None))
171-
value = ast.Attribute(value=ast.Name(id="self"), attr="step")
172-
mapping.append((ast.Constant(_property["@id"]), value))
173-
continue
174-
mapping.append((ast.Constant(_property["@id"]), ast.Name(argument_name)))
175-
_type = range_to_type(_property["rdfs:range"])
176-
if _property["@id"] not in single_properties:
177-
_type = ast.Subscript(
178-
value=ast.Attribute(value=ast.Name(id="typing"), attr="List"),
179-
slice=ast.Index(value=_type),
180-
)
181-
arg = ast.arg(arg=argument_name, annotation=_type)
182-
if len(properties) <= 2:
183-
positional_args.append(arg)
184-
else:
185-
kwonlyargs.append(arg)
186-
args = ast.arguments(
187-
args=positional_args,
188-
vararg=None,
189-
kwonlyargs=kwonlyargs or None,
190-
kw_defaults=[],
191-
kwarg=None,
192-
defaults=[],
193-
)
194-
keys, values = zip(*mapping)
195-
step_dict = ast.Dict(keys=keys, values=values)
196-
return_type = ast.Name("Path" if is_path_step else "FinalPath")
197-
returns = ast.Constant("Path") if is_path_step else ast.Name(id="FinalPath")
198-
comment = step_class["rdfs:comment"]
199-
if is_method:
200-
docstring_indent = " " * 8
201-
else:
202-
docstring_indent = " " * 4
203-
docstring = ast.Expr(
204-
ast.Constant(f"\n{docstring_indent + comment}\n{docstring_indent}")
205-
)
206-
function_def = ast.FunctionDef(
207-
name=method_name,
208-
args=args,
209-
returns=returns,
210-
decorator_list=[],
211-
body=[
212-
docstring,
213-
ast.Return(
214-
value=ast.Call(func=return_type, args=[step_dict], keywords=[])
215-
),
216-
],
217-
)
218-
if is_method:
219-
class_def.body.append(function_def)
220-
else:
221-
module.body.append(function_def)
246+
if "linkedql:from" in emptyable_properties:
247+
properties = [
248+
_property
249+
for _property in properties
250+
if _property["@id"] != "linkedql:from"
251+
]
252+
add_method(
253+
module,
254+
class_def,
255+
step_class,
256+
properties,
257+
is_path_step,
258+
single_properties,
259+
method_name,
260+
)
261+
222262
generated_code = astor.to_source(module)
223263
with module_path.open("w+") as file:
224264
file.write(generated_code)

0 commit comments

Comments
 (0)