Evaluate Manchester syntax
This module compiles restrictions and logical constructs in Manchester
syntax into Owlready2 classes. The main function in this module is
manchester.evaluate()
, see its docstring for usage example.
Pyparsing is used under the hood for parsing.
ManchesterError
Bases: EMMOntoPyException
Raised on invalid Manchester notation.
Source code in ontopy/manchester.py
| class ManchesterError(EMMOntoPyException):
"""Raised on invalid Manchester notation."""
|
evaluate(ontology, expr)
Evaluate expression in Manchester syntax.
Parameters:
Name |
Type |
Description |
Default |
ontology |
owlready2.Ontology
|
The ontology within which the expression will be evaluated. |
required
|
expr |
str
|
Manchester expression to be evaluated. |
required
|
Returns:
Type |
Description |
owlready2.Construct
|
An Owlready2 construct that corresponds to the expression. |
Example:
from ontopy.manchester import evaluate
from ontopy import get_ontology
emmo = get_ontology.load()
restriction = evaluate(emmo, 'hasPart some Atom')
cls = evaluate(emmo, 'Atom')
expr = evaluate(emmo, 'Atom or Molecule')
Note
Logical expressions (with not
, and
and or
) are supported as
well as object property restrictions. For data properterties are
only value restrictions supported so far.
Source code in ontopy/manchester.py
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191 | def evaluate(ontology: owlready2.Ontology, expr: str) -> owlready2.Construct:
"""Evaluate expression in Manchester syntax.
Args:
ontology: The ontology within which the expression will be evaluated.
expr: Manchester expression to be evaluated.
Returns:
An Owlready2 construct that corresponds to the expression.
Example:
>>> from ontopy.manchester import evaluate
>>> from ontopy import get_ontology
>>> emmo = get_ontology.load()
>>> restriction = evaluate(emmo, 'hasPart some Atom')
>>> cls = evaluate(emmo, 'Atom')
>>> expr = evaluate(emmo, 'Atom or Molecule')
Note:
Logical expressions (with `not`, `and` and `or`) are supported as
well as object property restrictions. For data properterties are
only value restrictions supported so far.
"""
# pylint: disable=invalid-name
def _parse_literal(r):
"""Compiles literal to Owlready2 type."""
if r.language:
v = owlready2.locstr(r.string, r.language)
elif r.number:
v = r.number
else:
v = r.string
return v
# pylint: disable=invalid-name,no-else-return,too-many-return-statements
# pylint: disable=too-many-branches
def _eval(r):
"""Recursively evaluate expression produced by pyparsing into an
Owlready2 construct."""
def fneg(x):
"""Negates the argument if `neg` is true."""
return owlready2.Not(x) if neg else x
if isinstance(r, str): # r is atomic, returns its owlready2 repr
return ontology[r]
neg = False # whether the expression starts with "not"
while r[0] == "not":
r.pop(0) # strip off the "not" and proceed
neg = not neg
if len(r) == 1: # r is either a atomic or a parenthesised
# subexpression that should be further evaluated
if isinstance(r[0], str):
return fneg(ontology[r[0]])
else:
return fneg(_eval(r[0]))
elif r.op: # r contains a logical operator: and/or
ops = {"and": owlready2.And, "or": owlready2.Or}
op = ops[r.op]
if len(r) == 3:
return op([fneg(_eval(r[0])), _eval(r[2])])
else:
arg1 = fneg(_eval(r[0]))
r.pop(0)
r.pop(0)
return op([arg1, _eval(r)])
elif r.objProp: # r is a restriction
if r[0] == "inverse":
r.pop(0)
prop = owlready2.Inverse(ontology[r[0]])
else:
prop = ontology[r[0]]
rtype = r[1]
if rtype == "Self":
return fneg(prop.has_self())
r.pop(0)
r.pop(0)
f = getattr(prop, rtype)
if rtype == "value":
return fneg(f(_eval(r)))
elif rtype in ("some", "only"):
return fneg(f(_eval(r)))
elif rtype in ("min", "max", "exactly"):
cardinality = r.pop(0)
return fneg(f(cardinality, _eval(r)))
else:
raise ManchesterError(f"invalid restriction type: {rtype}")
elif r.dataProp: # r is a data property restriction
prop = ontology[r[0]]
rtype = r[1]
r.pop(0)
r.pop(0)
f = getattr(prop, rtype)
if rtype == "value":
return f(_parse_literal(r))
else:
raise ManchesterError(
f"unimplemented data property restriction: "
f"{prop} {rtype} {r}"
)
else:
raise ManchesterError(f"invalid expression: {r}")
grammar = manchester_expression()
return _eval(grammar.parseString(expr, parseAll=True))
|
manchester_expression()
Returns pyparsing grammar for a Manchester expression.
This function is mostly for internal use.
See also: https://www.w3.org/TR/owl2-manchester-syntax/
Source code in ontopy/manchester.py
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 | def manchester_expression():
"""Returns pyparsing grammar for a Manchester expression.
This function is mostly for internal use.
See also: https://www.w3.org/TR/owl2-manchester-syntax/
"""
# pylint: disable=global-statement,invalid-name,too-many-locals
global GRAMMAR
if GRAMMAR:
return GRAMMAR
# Subset of the Manchester grammar for expressions
# It is based on https://www.w3.org/TR/owl2-manchester-syntax/
# but allows logical constructs within restrictions (like Protege)
ident = pp.Word(pp.alphas + "_:-", pp.alphanums + "_:-", asKeyword=True)
uint = pp.Word(pp.nums)
alphas = pp.Word(pp.alphas)
string = pp.Word(pp.alphanums + ":")
quotedString = (
pp.QuotedString('"""', multiline=True) | pp.QuotedString('"')
)("string")
typedLiteral = pp.Combine(quotedString + "^^" + string("datatype"))
stringLanguageLiteral = pp.Combine(quotedString + "@" + alphas("language"))
stringLiteral = quotedString
numberLiteral = pp.pyparsing_common.number("number")
literal = (
typedLiteral | stringLanguageLiteral | stringLiteral | numberLiteral
)
logOp = pp.oneOf(["and", "or"], asKeyword=True)
expr = pp.Forward()
restriction = pp.Forward()
primary = pp.Keyword("not")[...] + (
restriction | ident("cls") | pp.nestedExpr("(", ")", expr)
)
objPropExpr = (
pp.Literal("inverse")
+ pp.Suppress("(")
+ ident("objProp")
+ pp.Suppress(")")
| pp.Literal("inverse") + ident("objProp")
| ident("objProp")
)
dataPropExpr = ident("dataProp")
restriction <<= (
objPropExpr + pp.Keyword("some") + expr
| objPropExpr + pp.Keyword("only") + expr
| objPropExpr + pp.Keyword("Self")
| objPropExpr + pp.Keyword("value") + ident("individual")
| objPropExpr + pp.Keyword("min") + uint + expr
| objPropExpr + pp.Keyword("max") + uint + expr
| objPropExpr + pp.Keyword("exactly") + uint + expr
| dataPropExpr + pp.Keyword("value") + literal
)
expr <<= primary + (logOp("op") + expr)[...]
GRAMMAR = expr
return expr
|