bocl 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
bocl-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,91 @@
1
+ Metadata-Version: 2.1
2
+ Name: bocl
3
+ Version: 0.2.0
4
+ Summary: B-OCL
5
+ Author: Luxembourg Institute of Science and Technology
6
+ License: MIT
7
+ Project-URL: Documentation, https://b-ocl-interpreter.readthedocs.io/en/latest/
8
+ Project-URL: Source Code, https://github.com/BESSER-PEARL/B-OCL-Interpreter
9
+ Project-URL: Bug Tracker, https://github.com/BESSER-PEARL/B-OCL-Interpreter/issues
10
+ Keywords: uml,code generation,python
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: Arpeggio==2.0.2
14
+ Requires-Dist: colorama==0.4.6
15
+ Requires-Dist: iniconfig==2.0.0
16
+ Requires-Dist: packaging
17
+ Requires-Dist: pluggy==1.2.0
18
+ Requires-Dist: pytest==7.4.0
19
+ Requires-Dist: setuptools==68.2.2
20
+ Requires-Dist: textX==3.1.1
21
+ Requires-Dist: jinja2==3.1.2
22
+ Requires-Dist: antlr4-python3-runtime==4.13.1
23
+ Requires-Dist: requests==2.31.0
24
+ Requires-Dist: fastapi==0.110.0
25
+ Requires-Dist: pydantic==2.6.3
26
+ Requires-Dist: uvicorn==0.28.0
27
+ Requires-Dist: besser
28
+
29
+ # BESSER Object Constraint Language Interpreter
30
+
31
+ **B-OCL** is a tool designed to parse and evaluate the OCL constraints designed on **BESSER** models.
32
+ It is a python based implementation, that utilises parser and listener generated with the ANTLR4 grammer.
33
+
34
+ **BESSER** is a low-modeling low-code open-source platform built on top
35
+ of our Python-based personal interpretation of a "Universal Modeling Language"
36
+
37
+ ## Basic Installation
38
+ We have tested B-OCL with python 3.9+. We recommend creating a virtual environment using `venv <https://docs.python.org/3/tutorial/venv.html>`_, or
39
+ `conda <https://docs.conda.io/en/latest/>`_).
40
+
41
+ Dependencies
42
+ ************
43
+ B-OCL depends on BESSER for parsing the OCL constraints and providing a concrete syntax tree (CST) to evaluate. The latest stable version of BESSER is available in the Python Package Index (PyPi) and can be installed using
44
+
45
+
46
+ $ pip install besser
47
+
48
+
49
+ # B-OCL Installation
50
+
51
+
52
+ Stable version of B-OCL interpreter can be installed via
53
+
54
+ $ pip install bocl
55
+
56
+ ## Building From Source
57
+
58
+ To obtain the full code, including examples and tests, you can clone the git repository.
59
+
60
+ $ git clone https://github.com/BESSER-PEARL/b-ocl-Interpreter
61
+ $ cd b-ocl-Interpreter
62
+
63
+ To install the reqs please run the following commands in virtual environment (recommended)
64
+
65
+ $ pip install -r requirements.txt
66
+
67
+ ## Contributing
68
+
69
+ We encourage contributions from the community and any comment is welcome!
70
+
71
+ If you are interested in contributing to this project, please read the [CONTRIBUTING.md](CONTRIBUTING.md) file.
72
+
73
+ ## Code of Conduct
74
+
75
+ At BESSER, our commitment is centered on establishing and maintaining development environments that are welcoming, inclusive, safe and free from all forms of harassment. All participants are expected to voluntarily respect and support our [Code of Conduct](CODE_OF_CONDUCT.md).
76
+
77
+ ## Governance
78
+
79
+ The development of this project follows the governance rules described in the [GOVERNANCE.md](GOVERNANCE.md) document.
80
+
81
+ ## Contact
82
+ You can reach us at: [info@besser-pearl.org](mailto:info@besser-pearl-org)
83
+
84
+ Website: https://besser-pearl.github.io/website/
85
+
86
+ ## Documentation
87
+ More details about B-OCL can be found here https://b-ocl-interpreter.readthedocs.io/en/latest/
88
+
89
+ ## License
90
+
91
+ This project is licensed under the [MIT](https://mit-license.org/) license.
bocl-0.2.0/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # BESSER Object Constraint Language Interpreter
2
+
3
+ **B-OCL** is a tool designed to parse and evaluate the OCL constraints designed on **BESSER** models.
4
+ It is a python based implementation, that utilises parser and listener generated with the ANTLR4 grammer.
5
+
6
+ **BESSER** is a low-modeling low-code open-source platform built on top
7
+ of our Python-based personal interpretation of a "Universal Modeling Language"
8
+
9
+ ## Basic Installation
10
+ We have tested B-OCL with python 3.9+. We recommend creating a virtual environment using `venv <https://docs.python.org/3/tutorial/venv.html>`_, or
11
+ `conda <https://docs.conda.io/en/latest/>`_).
12
+
13
+ Dependencies
14
+ ************
15
+ B-OCL depends on BESSER for parsing the OCL constraints and providing a concrete syntax tree (CST) to evaluate. The latest stable version of BESSER is available in the Python Package Index (PyPi) and can be installed using
16
+
17
+
18
+ $ pip install besser
19
+
20
+
21
+ # B-OCL Installation
22
+
23
+
24
+ Stable version of B-OCL interpreter can be installed via
25
+
26
+ $ pip install bocl
27
+
28
+ ## Building From Source
29
+
30
+ To obtain the full code, including examples and tests, you can clone the git repository.
31
+
32
+ $ git clone https://github.com/BESSER-PEARL/b-ocl-Interpreter
33
+ $ cd b-ocl-Interpreter
34
+
35
+ To install the reqs please run the following commands in virtual environment (recommended)
36
+
37
+ $ pip install -r requirements.txt
38
+
39
+ ## Contributing
40
+
41
+ We encourage contributions from the community and any comment is welcome!
42
+
43
+ If you are interested in contributing to this project, please read the [CONTRIBUTING.md](CONTRIBUTING.md) file.
44
+
45
+ ## Code of Conduct
46
+
47
+ At BESSER, our commitment is centered on establishing and maintaining development environments that are welcoming, inclusive, safe and free from all forms of harassment. All participants are expected to voluntarily respect and support our [Code of Conduct](CODE_OF_CONDUCT.md).
48
+
49
+ ## Governance
50
+
51
+ The development of this project follows the governance rules described in the [GOVERNANCE.md](GOVERNANCE.md) document.
52
+
53
+ ## Contact
54
+ You can reach us at: [info@besser-pearl.org](mailto:info@besser-pearl-org)
55
+
56
+ Website: https://besser-pearl.github.io/website/
57
+
58
+ ## Documentation
59
+ More details about B-OCL can be found here https://b-ocl-interpreter.readthedocs.io/en/latest/
60
+
61
+ ## License
62
+
63
+ This project is licensed under the [MIT](https://mit-license.org/) license.
@@ -0,0 +1,46 @@
1
+ """Including imports from BESSER and ANTLR4"""
2
+ from antlr4 import InputStream,CommonTokenStream,ParseTreeWalker
3
+ from besser.BUML.notations.ocl.BOCLLexer import BOCLLexer
4
+ from besser.BUML.notations.ocl.BOCLParser import BOCLParser
5
+ from besser.BUML.notations.ocl.BOCLListener import BOCLListener
6
+ from besser.BUML.notations.ocl.RootHandler import Root_Handler
7
+ from bocl.evaluator import Evaluator
8
+
9
+ class OCLWrapper:
10
+ """The OCLWrapper class is the wrapper around the evaluator
11
+ class to prepare the construct needed by evaluator.
12
+
13
+ Args:
14
+ dm: Domain model in BUML
15
+ om: object model in BUML
16
+ Attributes:
17
+ dm: Domain model in BUML
18
+ om: object model in BUML
19
+ """
20
+ def __init__(self,dm,om):
21
+ self.dm = dm
22
+ self.om = om
23
+ def __str__(self):
24
+ return str(self.dm)+ str(self.om)
25
+
26
+
27
+ def evaluate(self,ocl):
28
+ """the evaluate function takes the OCL constraint and evaluate using evaluator
29
+ Args:
30
+ ocl: Object of OCL class that constaints the OCL expression and context class
31
+ """
32
+
33
+ # self.preprocess(ocl.expression)
34
+ input_stream = InputStream(ocl.expression)
35
+ root_handler = Root_Handler(ocl,self.dm,self.om)
36
+ lexer = BOCLLexer(input_stream)
37
+ stream = CommonTokenStream(lexer)
38
+ parser = BOCLParser(stream)
39
+ tree = parser.oclFile()
40
+ listener = BOCLListener(root_handler)
41
+ walker = ParseTreeWalker()
42
+ walker.walk(listener,tree)
43
+
44
+ evalualor = Evaluator()
45
+
46
+ return evalualor.evaluate(root_handler, self.om)
File without changes
@@ -0,0 +1,486 @@
1
+ """Importing OCL from main BESSER repository"""
2
+ from besser.BUML.metamodel.ocl.ocl import *
3
+ from besser.BUML.metamodel.structural.structural import Property
4
+
5
+
6
+ class Evaluator:
7
+ """The Evaluator class evaluates the OCL constraints based on the object model.
8
+
9
+ Args:
10
+
11
+ Attributes:
12
+ debug = this attribute is used for debugging purposes and with default value false
13
+ allObjSat = list of all objects that satisfy the contraint
14
+ """
15
+
16
+ def __init__(self):
17
+ self.debug = False
18
+ self.all_obj_sat = []
19
+ self.om = None
20
+ self.root_handler = None
21
+
22
+ def get_value(self, name, obj):
23
+ """The get_value function to retrieve value of attribute from class_object.
24
+
25
+ Args:
26
+ name: name of the attribute
27
+ obj: Object from object model
28
+ """
29
+ for slot in obj.slots:
30
+ if name == slot.attribute.name:
31
+ if slot.attribute.type.name == 'str':
32
+ return '"' + slot.value.value + '"'
33
+ return slot.value.value
34
+ return None
35
+
36
+ def check_in_obj(self, obj, source):
37
+ """The check_in_obj function identifies the class_object that contains the source in slots.
38
+
39
+ Args:
40
+ obj: Object from object model
41
+ source: source of the current object in the CSTree
42
+ """
43
+ for s in obj.slots:
44
+ if s.attribute.name == source.name:
45
+ return obj
46
+ return None
47
+
48
+ def check_in_link_ends(self, obj, source):
49
+ """The check_in_link_ends function identifies the source in the linkend of the object.
50
+
51
+ Args:
52
+ obj: Object from object model
53
+ source: source of the current object in the CSTree
54
+ """
55
+ to_ret = []
56
+ for link in obj.links:
57
+ for connection in link.connections:
58
+ if connection.association_end.name == source.name:
59
+ to_ret.append(connection.object)
60
+
61
+ return to_ret
62
+
63
+ def handle_for_all(self, tree, all_objs, logical_exp):
64
+ """The handle_for_all function handles forAll expression from OCL MM.
65
+
66
+ Args:
67
+ tree: Tree that is constructed using OCL Parser
68
+ all_objs: all objects from object model
69
+ logical_exp: Expression to evaluate at the end to get the result
70
+ """
71
+ logical_exp[0] = logical_exp[0] + " ("
72
+ for index in range(len(all_objs)):
73
+ if len(tree.get_body) > 0:
74
+ self.update_logical_exp(tree.get_body[0], logical_exp, all_objs[index])
75
+ if index < len(all_objs) - 1:
76
+ logical_exp[0] = logical_exp[0] + " and "
77
+ logical_exp[0] = logical_exp[0] + " )"
78
+
79
+ def handle(self, source, obj, logical_exp, right_side=False):
80
+ """The handle function handles Property Call expression from OCL MM.
81
+
82
+ Args:
83
+ source: one child in OCL CST
84
+ obj: one object from object model
85
+ logical_exp: Expression to evaluate at the end to get the result
86
+ right_side: to identify the side of logical expression
87
+ """
88
+
89
+ if isinstance(source, (PropertyCallExpression,Property)):
90
+ # if len(source.name.split('.'))==2:
91
+ all_objs = self.check_in_obj(obj, source)
92
+ if all_objs is None:
93
+ all_objs = self.check_in_link_ends(obj, source)
94
+ for index in range(len(all_objs)):
95
+ objs = all_objs[index]
96
+ if len(all_objs) > 1 or right_side:
97
+ logical_exp[0] = logical_exp[0] + " [ "
98
+ for i in range(len(objs.slots)):
99
+ logical_exp[0] = logical_exp[0] + "\"" + str(objs.slots[i].attribute.name) + str(
100
+ objs.slots[i].value.value) + "\""
101
+ if i < len(objs.slots) - 1:
102
+ logical_exp[0] = logical_exp[0] + ","
103
+ if not right_side:
104
+ if len(all_objs) > 1 and index < len(all_objs) - 1:
105
+ logical_exp[0] = logical_exp[0] + " ], "
106
+ else:
107
+ logical_exp[0] = logical_exp[0] + " ] "
108
+ if len(all_objs) > 1 and index < len(all_objs) - 1:
109
+ logical_exp[0] = logical_exp[0] + " , "
110
+
111
+
112
+
113
+
114
+ def handle_excludes(self, tree, obj, logical_exp):
115
+ """The handle_excludes function handles excludes construct.
116
+
117
+ Args:
118
+ tree: Tree that is constructed using OCL Parser
119
+ obj: one object from object model
120
+ logical_exp: Expression to evaluate at the end to get the result
121
+ """
122
+ # tempLogicalExp =[""]
123
+ args = tree.arguments
124
+ self.check_and_add(logical_exp, " and ")
125
+ logical_exp[0] = logical_exp[0] + " [ "
126
+ self.handle(tree.source, obj, logical_exp)
127
+ logical_exp[0] = logical_exp[0] + " ] not in "
128
+ if len(args) == 1: # Property
129
+ logical_exp[0] = logical_exp[0] + " [ "
130
+ self.handle(args[0], obj, logical_exp, True)
131
+ logical_exp[0] = logical_exp[0] + " ]"
132
+
133
+
134
+ def handle_includes(self, tree, obj, logical_exp):
135
+ """The handle_includes function handles includes construct.
136
+
137
+ Args:
138
+ tree: Tree that is constructed using OCL Parser
139
+ obj: one object from object model
140
+ logical_exp: Expression to evaluate at the end to get the result
141
+ """
142
+
143
+ # tempLogicalExp =[""]
144
+ args = tree.arguments
145
+ self.check_and_add(logical_exp, " and ")
146
+ logical_exp[0] = logical_exp[0] + " [ "
147
+ self.handle(tree.source, obj, logical_exp)
148
+ logical_exp[0] = logical_exp[0] + " ] in "
149
+ if len(args) == 1: # Property
150
+ logical_exp[0] = logical_exp[0] + " [ "
151
+ self.handle(args[0], obj, logical_exp, True)
152
+ logical_exp[0] = logical_exp[0] + " ]"
153
+
154
+
155
+ def handle_exists(self, tree, all_objs, logical_exp):
156
+ """The handle_exists function handles exists construct.
157
+
158
+ Args:
159
+ tree: Tree that is constructed using OCL Parser
160
+ all_objs: all objects from object model
161
+ logical_exp: Expression to evaluate at the end to get the result
162
+ """
163
+ logical_exp[0] = logical_exp[0] + " ( "
164
+ temp = logical_exp[0]
165
+ for index in range(len(all_objs)):
166
+ if len(tree.get_body) > 0:
167
+ self.update_logical_exp(tree.get_body[0], logical_exp, all_objs[index])
168
+ if index < len(all_objs) - 1:
169
+ logical_exp[0] = logical_exp[0] + " or "
170
+ if temp == logical_exp[0]:
171
+ logical_exp[0] = logical_exp[0] + " False "
172
+
173
+ logical_exp[0] = logical_exp[0] + " )"
174
+
175
+ def handle_select(self, tree, all_objs):
176
+ """The handle_select function handles select construct.
177
+
178
+ Args:
179
+ tree: Tree that is constructed using OCL Parser
180
+ all_objs: all objects from object model
181
+ """
182
+ self.all_obj_sat.append([])
183
+ for obj in all_objs:
184
+ expression = [""]
185
+ if len(tree.get_body) > 0:
186
+ self.update_logical_exp(tree.get_body[0], expression, obj)
187
+ self.preprocess_logical_exp(expression)
188
+ if eval(expression[0]) is True:
189
+ self.all_obj_sat[-1].append(obj)
190
+
191
+ def handle_collect(self, tree, all_objs):
192
+ """The handle_collect function handles collect construct.
193
+
194
+ Args:
195
+ tree: Tree that is constructed using OCL Parser
196
+ all_objs: all objects from object model
197
+ """
198
+ self.all_obj_sat.append([])
199
+ for obj in all_objs:
200
+ expression = [""]
201
+ if len(tree.get_body) > 0:
202
+ self.update_logical_exp(tree.get_body[0], expression, obj)
203
+ self.preprocess_logical_exp(expression)
204
+ if eval(expression[0]) is True:
205
+ self.all_obj_sat[-1].append(obj)
206
+
207
+ def verify_body(self, tree, obj, logical_exp, source, all_objs = None):
208
+ """The verify_body function verifies the body of different
209
+ constructs (e.g., forAll, exists).
210
+
211
+ Args:
212
+ tree: Tree that is constructed using OCL Parser
213
+ obj: one object from object model
214
+ logical_exp: Expression to evaluate at the end to get the result
215
+ source: source of the obj in CSTree
216
+ """
217
+ expression_type = tree.name
218
+ if all_objs is None:
219
+ all_objs = self.check_in_obj(obj, source)
220
+ if all_objs is None:
221
+ all_objs = self.check_in_link_ends(obj, source)
222
+ if source.name == "ALLInstances":
223
+ class_name = source.source.name
224
+ all_objs = self.get_valid_objects(class_name, self.om)
225
+
226
+ if expression_type == "forAll":
227
+ self.handle_for_all(tree, all_objs, logical_exp)
228
+ elif expression_type == "exists":
229
+ self.handle_exists(tree, all_objs, logical_exp)
230
+ elif expression_type == "collect":
231
+ self.handle_collect(tree, all_objs)
232
+ elif expression_type == "select":
233
+ self.handle_select(tree, all_objs)
234
+
235
+
236
+ def get_id(self, slots):
237
+ """The get_id function gets the ID attribute from the Object.
238
+
239
+ Args:
240
+ slots: slots of the object
241
+ """
242
+ for s in slots:
243
+ if s.get_attribute.is_id:
244
+ return s
245
+ return None
246
+
247
+ def add_to_exp(self, item, logical_exp):
248
+ """The add_to_exp function adds the item to logicalExpression.
249
+
250
+ Args:
251
+ item: item to add in Logical Expression
252
+ logical_exp: logical Expression
253
+ """
254
+ if logical_exp[0] == "":
255
+ logical_exp[0] = logical_exp[0] + item
256
+ else:
257
+ logical_exp[0] = logical_exp[0] + " and " + item
258
+
259
+ def handle_size(self, tree, obj, logical_exp):
260
+ """The handle_size function handles the size construct.
261
+
262
+ Args:
263
+ tree: Tree that is constructed using OCL Parser
264
+ obj: one object from object model
265
+ logical_exp: Expression to evaluate at the end to get the result
266
+ """
267
+ self.check_and_add(logical_exp, " and ")
268
+ logical_exp[0] = logical_exp[0] + "("
269
+ if isinstance(tree.source, Property):
270
+ all_objs = self.check_in_obj(obj, tree.source)
271
+ if all_objs is None:
272
+ all_objs = self.check_in_link_ends(obj, tree.source)
273
+ logical_exp[0] = logical_exp[0] + str(len(all_objs))
274
+ for arg in tree.arguments:
275
+ if isinstance(arg, (IntegerLiteralExpression, RealLiteralExpression, BooleanLiteralExpression)):
276
+ logical_exp[0] = logical_exp[0] + str(arg.value)
277
+ else:
278
+ logical_exp[0] = logical_exp[0] + str(arg)
279
+ elif isinstance(tree.source, LoopExp):
280
+ source = None
281
+ if tree.source.source is not None:
282
+ source = tree.source.source
283
+ if source is not None and source.name == "ALLInstances":
284
+ class_name = source.source.name
285
+ all_objs = self.get_valid_objects(class_name, self.om)
286
+ else:
287
+ all_objs = self.check_in_obj(obj, source)
288
+ if all_objs is None:
289
+ all_objs = self.check_in_link_ends(obj, source)
290
+ self.handle_collect(tree.source, all_objs)
291
+ if len(self.all_obj_sat) > 0:
292
+ logical_exp[0] = logical_exp[0] + str(len(self.all_obj_sat[-1]))
293
+ self.all_obj_sat.pop()
294
+ for arg in tree.arguments:
295
+
296
+ if isinstance(arg, (IntegerLiteralExpression,RealLiteralExpression,BooleanLiteralExpression)):
297
+ logical_exp[0] = logical_exp[0] + str(arg.value)
298
+ else:
299
+ logical_exp[0] = logical_exp[0] + str(arg)
300
+ logical_exp[0] = logical_exp[0] + ")"
301
+
302
+ def handle_if_exp(self, tree, obj, logical_exp):
303
+ """The handle_if_exp function handles the If construct.
304
+
305
+ Args:
306
+ tree: Tree that is constructed using OCL Parser
307
+ obj: one object from object model
308
+ logical_exp: Expression to evaluate at the end to get the result
309
+ """
310
+
311
+ temp_exp = [""]
312
+ self.update_logical_exp(tree.ifCondition, temp_exp, obj)
313
+ self.preprocess_logical_exp(temp_exp)
314
+ self.check_and_add(logical_exp, " and ")
315
+ if eval(temp_exp[0]) is True:
316
+ self.update_logical_exp(tree.thenExpression, logical_exp, obj)
317
+ else:
318
+ self.update_logical_exp(tree.elseCondition, logical_exp, obj)
319
+
320
+
321
+
322
+ def handle_ocl_is_type_of(self, tree, logical_exp):
323
+ """The handle_ocl_is_type_of function handles the OCLIsTypeOf construct.
324
+
325
+ Args:
326
+ tree: Tree that is constructed using OCL Parser
327
+ obj: one object from object model
328
+ logical_exp: Expression to evaluate at the end to get the result
329
+ """
330
+ if isinstance(tree.source, Property):
331
+ source_type = tree.source.type.name
332
+ self.check_and_add(logical_exp, " and ")
333
+ for index in range(len(tree.arguments)):
334
+ arg = tree.arguments[index].name
335
+ if arg == "String":
336
+ logical_exp[0] = logical_exp[0] + '\"' + source_type + '\"' + " = \"str\""
337
+ elif arg == "Integer":
338
+ logical_exp[0] = logical_exp[0] + '\"' + source_type + '\"' + " = \"int\""
339
+ elif arg == "Boolean":
340
+ logical_exp[0] = logical_exp[0] + '\"' + source_type + '\"' + " = \"bool\""
341
+ elif arg == "Real":
342
+ logical_exp[0] = logical_exp[0] + '\"' + source_type + '\"' + " = \"float\""
343
+ if index > 0 and index < len(tree.arguments) - 1:
344
+ self.check_and_add(logical_exp, "and")
345
+
346
+ def update_logical_exp(self, tree, logical_exp, obj):
347
+ """The update_logical_exp function updates the logical expression.
348
+
349
+ Args:
350
+ tree: Tree that is constructed using OCL Parser
351
+ obj: one object from object model
352
+ logical_exp: Expression to evaluate at the end to get the result
353
+ """
354
+
355
+ if isinstance(tree, PropertyCallExpression):
356
+ if tree.source is None:
357
+ pass
358
+
359
+ if isinstance(tree, LoopExp): # forAll, select,..etc
360
+ source = tree.source
361
+ if obj.classifier.name == self.root_handler.get_context_name():
362
+ self.verify_body(tree, obj, logical_exp, source)
363
+ if isinstance(tree, IfExp):
364
+ self.handle_if_exp(tree, obj, logical_exp)
365
+ if isinstance(tree, OperationCallExpression):
366
+
367
+ if tree.name == "EXCLUDES":
368
+ self.handle_excludes(tree, obj, logical_exp)
369
+ elif tree.name == "INCLUDES":
370
+ self.handle_includes(tree, obj, logical_exp)
371
+ elif tree.name == "Size":
372
+ self.handle_size(tree, obj, logical_exp)
373
+ self.check_and_add(logical_exp, " and ")
374
+ elif tree.name == "OCLISTYPEOF":
375
+ self.handle_ocl_is_type_of(tree, logical_exp)
376
+ elif tree.name == "ALLInstances":
377
+ pass # handled elsewhere
378
+ else:
379
+ args = tree.arguments
380
+ for arg in args:
381
+ if hasattr(arg, 'name'):
382
+ if isinstance(arg, (IntegerLiteralExpression, RealLiteralExpression, BooleanLiteralExpression)):
383
+ logical_exp[0] = logical_exp[0] + str(arg.value)
384
+ elif isinstance(arg, StringLiteralExpression):
385
+ logical_exp[0] = logical_exp[0] + '"' + str(arg.value) + '"'
386
+ else:
387
+ logical_exp[0] = logical_exp[0] + str(self.get_value(arg.name, obj))
388
+ else:
389
+ if str(arg).lower() == "and" or str(arg).lower() == 'or':
390
+ self.check_and_add(logical_exp[0], str(arg))
391
+ else:
392
+ logical_exp[0] = logical_exp[0] + " " + str(arg) + " "
393
+ if tree.referredOperation is not None and (
394
+ tree.referredOperation.get_infix_operator() == "and" or tree.referredOperation.get_infix_operator() == "or"):
395
+ self.check_and_add(logical_exp[0], tree.referredOperation.get_infix_operator())
396
+ if hasattr(tree, "source"):
397
+ if tree.source is not None:
398
+ self.update_logical_exp(tree.source, logical_exp, obj)
399
+
400
+ def check_and_add(self, logical_exp_template, to_add):
401
+ """The check_and_add function checks and updates the logical expression.
402
+
403
+ Args:
404
+ to_add: item to add in the logical expression
405
+ logical_exp_template: Expression to evaluate at the end to get the result
406
+ """
407
+ if len(logical_exp_template[0]) > 5:
408
+ if to_add == " and ":
409
+ if logical_exp_template[0][-5:] != " and ":
410
+ logical_exp_template[0] = logical_exp_template[0] + to_add
411
+ elif to_add == " and ":
412
+ if len(logical_exp_template[0]) > 0 and len(logical_exp_template[0]) <= 5:
413
+ logical_exp_template[0] = logical_exp_template[0] + to_add
414
+
415
+ if len(logical_exp_template[0]) > 4:
416
+ if to_add == " or ":
417
+ if logical_exp_template[0][-4:] != " or ":
418
+ logical_exp_template[0] = logical_exp_template[0] + to_add
419
+
420
+ def valid_object(self, context_name, class_object):
421
+ """the valid_object verifies if the current object is the one constraint is applied on
422
+
423
+ Args:
424
+ context_name: name of the context of OCL constraint
425
+ class_object: Object from object model to check
426
+
427
+ """
428
+ id_slot = self.get_id(class_object.slots)
429
+ if id_slot.get_attribute.name == context_name:
430
+ return True
431
+ return False
432
+
433
+ def get_valid_objects(self, context_name, objs):
434
+ """the get_valid_objects returns all the objects the constraint should be applied on
435
+
436
+ Args:
437
+ context_name: name of the context of OCL constraint
438
+ objs: all objects from object model
439
+
440
+ """
441
+
442
+ to_ret = []
443
+ for obj in objs.instances:
444
+ # if self.valid_object(context_name,obj):
445
+ if obj.classifier.name == context_name:
446
+ to_ret.append(obj)
447
+ return to_ret
448
+
449
+ def preprocess_logical_exp(self, exp):
450
+ """the preprocess_logical_exp function preprocesses before evaluating to correct the syntax.
451
+
452
+ Args:
453
+ exp: logical expression to be evaluated
454
+
455
+ """
456
+ exp[0] = exp[0].replace(' = ', ' == ').replace('<>', ' != ')
457
+ if len(exp[0]) > 5:
458
+ if exp[0][-5:] == " and ":
459
+ exp[0] = exp[0][:-5]
460
+ if len(exp[0]) > 4:
461
+ if exp[0][-4:] == " or ":
462
+ exp[0] = exp[0][:-4]
463
+
464
+ def evaluate(self, root_handler, object_model):
465
+ """the evaluate function is the main function to be called for evaluating any contraint.
466
+
467
+ Args:
468
+ root_handler: Object of class RootHandler that handles the tree
469
+ object_model: Object Model from BUML models
470
+ """
471
+ self.om = object_model
472
+ self.root_handler = root_handler
473
+
474
+ objs = self.get_valid_objects(self.root_handler.get_context_name(), self.om)
475
+ tree = root_handler.get_root()
476
+ logical_exp_template = [""]
477
+ for i in range(len(objs)):
478
+ self.update_logical_exp(tree, logical_exp_template, objs[i])
479
+ if len(objs) > 1 and i < len(objs) - 1:
480
+ self.check_and_add(logical_exp_template, " and ")
481
+
482
+ if self.debug:
483
+ print("Logical Expression")
484
+ print(logical_exp_template[0])
485
+ self.preprocess_logical_exp(logical_exp_template)
486
+ return eval(logical_exp_template[0])
@@ -0,0 +1,91 @@
1
+ Metadata-Version: 2.1
2
+ Name: bocl
3
+ Version: 0.2.0
4
+ Summary: B-OCL
5
+ Author: Luxembourg Institute of Science and Technology
6
+ License: MIT
7
+ Project-URL: Documentation, https://b-ocl-interpreter.readthedocs.io/en/latest/
8
+ Project-URL: Source Code, https://github.com/BESSER-PEARL/B-OCL-Interpreter
9
+ Project-URL: Bug Tracker, https://github.com/BESSER-PEARL/B-OCL-Interpreter/issues
10
+ Keywords: uml,code generation,python
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: Arpeggio==2.0.2
14
+ Requires-Dist: colorama==0.4.6
15
+ Requires-Dist: iniconfig==2.0.0
16
+ Requires-Dist: packaging
17
+ Requires-Dist: pluggy==1.2.0
18
+ Requires-Dist: pytest==7.4.0
19
+ Requires-Dist: setuptools==68.2.2
20
+ Requires-Dist: textX==3.1.1
21
+ Requires-Dist: jinja2==3.1.2
22
+ Requires-Dist: antlr4-python3-runtime==4.13.1
23
+ Requires-Dist: requests==2.31.0
24
+ Requires-Dist: fastapi==0.110.0
25
+ Requires-Dist: pydantic==2.6.3
26
+ Requires-Dist: uvicorn==0.28.0
27
+ Requires-Dist: besser
28
+
29
+ # BESSER Object Constraint Language Interpreter
30
+
31
+ **B-OCL** is a tool designed to parse and evaluate the OCL constraints designed on **BESSER** models.
32
+ It is a python based implementation, that utilises parser and listener generated with the ANTLR4 grammer.
33
+
34
+ **BESSER** is a low-modeling low-code open-source platform built on top
35
+ of our Python-based personal interpretation of a "Universal Modeling Language"
36
+
37
+ ## Basic Installation
38
+ We have tested B-OCL with python 3.9+. We recommend creating a virtual environment using `venv <https://docs.python.org/3/tutorial/venv.html>`_, or
39
+ `conda <https://docs.conda.io/en/latest/>`_).
40
+
41
+ Dependencies
42
+ ************
43
+ B-OCL depends on BESSER for parsing the OCL constraints and providing a concrete syntax tree (CST) to evaluate. The latest stable version of BESSER is available in the Python Package Index (PyPi) and can be installed using
44
+
45
+
46
+ $ pip install besser
47
+
48
+
49
+ # B-OCL Installation
50
+
51
+
52
+ Stable version of B-OCL interpreter can be installed via
53
+
54
+ $ pip install bocl
55
+
56
+ ## Building From Source
57
+
58
+ To obtain the full code, including examples and tests, you can clone the git repository.
59
+
60
+ $ git clone https://github.com/BESSER-PEARL/b-ocl-Interpreter
61
+ $ cd b-ocl-Interpreter
62
+
63
+ To install the reqs please run the following commands in virtual environment (recommended)
64
+
65
+ $ pip install -r requirements.txt
66
+
67
+ ## Contributing
68
+
69
+ We encourage contributions from the community and any comment is welcome!
70
+
71
+ If you are interested in contributing to this project, please read the [CONTRIBUTING.md](CONTRIBUTING.md) file.
72
+
73
+ ## Code of Conduct
74
+
75
+ At BESSER, our commitment is centered on establishing and maintaining development environments that are welcoming, inclusive, safe and free from all forms of harassment. All participants are expected to voluntarily respect and support our [Code of Conduct](CODE_OF_CONDUCT.md).
76
+
77
+ ## Governance
78
+
79
+ The development of this project follows the governance rules described in the [GOVERNANCE.md](GOVERNANCE.md) document.
80
+
81
+ ## Contact
82
+ You can reach us at: [info@besser-pearl.org](mailto:info@besser-pearl-org)
83
+
84
+ Website: https://besser-pearl.github.io/website/
85
+
86
+ ## Documentation
87
+ More details about B-OCL can be found here https://b-ocl-interpreter.readthedocs.io/en/latest/
88
+
89
+ ## License
90
+
91
+ This project is licensed under the [MIT](https://mit-license.org/) license.
@@ -0,0 +1,16 @@
1
+ README.md
2
+ pyproject.toml
3
+ requirements.txt
4
+ setup.cfg
5
+ bocl/OCLWrapper.py
6
+ bocl/__init__.py
7
+ bocl/evaluator.py
8
+ bocl.egg-info/PKG-INFO
9
+ bocl.egg-info/SOURCES.txt
10
+ bocl.egg-info/dependency_links.txt
11
+ bocl.egg-info/requires.txt
12
+ bocl.egg-info/top_level.txt
13
+ models/__init__.py
14
+ models/library_object.py
15
+ models/researcher_object.py
16
+ models/team_player_object.py
@@ -0,0 +1,15 @@
1
+ Arpeggio==2.0.2
2
+ colorama==0.4.6
3
+ iniconfig==2.0.0
4
+ packaging
5
+ pluggy==1.2.0
6
+ pytest==7.4.0
7
+ setuptools==68.2.2
8
+ textX==3.1.1
9
+ jinja2==3.1.2
10
+ antlr4-python3-runtime==4.13.1
11
+ requests==2.31.0
12
+ fastapi==0.110.0
13
+ pydantic==2.6.3
14
+ uvicorn==0.28.0
15
+ besser
@@ -0,0 +1,2 @@
1
+ bocl
2
+ models
File without changes
@@ -0,0 +1,161 @@
1
+
2
+ from besser.BUML.metamodel.structural import DomainModel, Class, Property, \
3
+ PrimitiveDataType, Multiplicity, BinaryAssociation,Constraint
4
+ from besser.BUML.metamodel.object import *
5
+ import datetime
6
+
7
+ #############################################
8
+ # Library - structural model definition #
9
+ #############################################
10
+
11
+ # Primitive DataTypes
12
+ t_int: PrimitiveDataType = PrimitiveDataType("int")
13
+ t_str: PrimitiveDataType = PrimitiveDataType("str")
14
+ t_date: PrimitiveDataType = PrimitiveDataType("date")
15
+
16
+ # Library attributes definition
17
+ library_name: Property = Property(name="name", type=t_str)
18
+ address: Property = Property(name="address", type=t_str)
19
+ # Library class definition
20
+ library: Class = Class (name="Library", attributes={library_name, address})
21
+
22
+ # Book attributes definition
23
+ title: Property = Property(name="title", type=t_str)
24
+ pages: Property = Property(name="pages", type=t_int)
25
+ release: Property = Property(name="release", type=t_date)
26
+ # Book class definition
27
+ book: Class = Class (name="Book", attributes={title, pages, release})
28
+
29
+ # Author attributes definition
30
+ author_name: Property = Property(name="name", type=t_str)
31
+ email: Property = Property(name="email", type=t_str)
32
+ # Author class definition
33
+ author: Class = Class (name="Author", attributes={author_name, email})
34
+
35
+ # Library-Book association definition
36
+ located_in: Property = Property(name="locatedIn",type=library, multiplicity=Multiplicity(1, 1))
37
+ has: Property = Property(name="has", type=book, multiplicity=Multiplicity(0, "*"))
38
+ lib_book_association: BinaryAssociation = BinaryAssociation(name="lib_book_assoc", ends={located_in, has})
39
+
40
+ # Book-Author association definition
41
+ publishes: Property = Property(name="publishes", type=book, multiplicity=Multiplicity(0, "*"))
42
+ writed_by: Property = Property(name="writedBy", type=author, multiplicity=Multiplicity(1, "*"))
43
+ book_author_association: BinaryAssociation = BinaryAssociation(name="book_author_assoc", ends={writed_by, publishes})
44
+
45
+ constraintPageNumber: Constraint = Constraint(name = "libraryPageNumber",context=library,expression="context Library inv inv1: self.has ->forAll(b:Book|b.pages>0)",language="OCL")
46
+
47
+ constraintBookPageNumber: Constraint = Constraint(name = "BookPageNumber",context=book,expression="context Book inv inv2: self.pages>0",language="OCL")
48
+
49
+ constraintTitleIncorrect: Constraint = Constraint(name = "BookTitleInc",context=book,expression="context Book inv inv2: self.title= 'NI')",language="OCL")
50
+
51
+ constraintTitleCorrect: Constraint = Constraint(name = "BookTitle",context=book,expression="context Book inv inv2: self.title <> 'NI'",language="OCL")
52
+
53
+ constraintLibraryExists: Constraint = Constraint(name = "LibarayExistsConst",context=library,expression="context Library inv inv3: self.has->exists( i_book : Book | i_book.pages <= 110 )",language="OCL")
54
+
55
+ # constraintLibraryExclude: Constraint = Constraint(name = "LibarayExclude",context=library,expression="context Library inv inv3: self.has->excludes()",language="OCL")
56
+ constraintLibrarySize: Constraint = Constraint(name = "LibaraySize",context=library,expression="context Library inv inv3: self.has->size()>1",language="OCL")
57
+
58
+ constraintLibraryCollect: Constraint = Constraint(name = "LibaryCollect",context=library,
59
+ expression="context Library inv inv3: self.has->collect(i_book : Book | i_book.pages <= 110)"
60
+ "->size()>0",language="OCL")
61
+
62
+ constraintLibraryIf: Constraint = Constraint(name ="LibaryIf", context=library,
63
+ expression="context Library inv inv3: if self.name <> 'NI' then self.has->exists"
64
+ "( i_book : Book | i_book.pages <= 110 ) else self.has->forAll(b:Book|b.pages>0)"
65
+ " endif", language="OCL")
66
+
67
+ constraintLibraryElse: Constraint = Constraint(name ="LibaryElse", context=library,
68
+ expression="context Library inv inv3: if self.name = 'NI' then self.has->exists"
69
+ "( i_book : Book | i_book.pages <= 110 ) else self.has->forAll(b:Book|b.pages>0)"
70
+ " endif", language="OCL")
71
+
72
+ constraintLibraryElseFalse: Constraint = Constraint(name ="LibaryElseFalse", context=library, expression="context Library inv inv3: if self.name = 'NI' then self.has->exists( i_book : Book | i_book.pages <= 110 ) else self.has->forAll(b:Book|b.pages<0) endif", language="OCL")
73
+
74
+
75
+ constraintNameOCLIsTypeOf: Constraint = Constraint(name ="BookIsTypeOfStr", context=book, expression="context Book inv inv3: self.title.oclIsTypeOf(String)", language="OCL")
76
+
77
+ constraintNameOCLIsTypeOfInt: Constraint = Constraint(name ="BookIsTypeOfInt", context=book, expression="context Book inv inv3: self.pages.oclIsTypeOf(Integer)", language="OCL")
78
+
79
+ constraintNameOCLIsTypeOfIntFalse: Constraint = Constraint(name ="BookIsTypeOfIntFalse", context=book, expression="context Book inv inv3: self.pages.oclIsTypeOf(String)", language="OCL")
80
+ constraintifElseSize: Constraint = Constraint(name ="constraintifElseSize", context=library, expression="context Library inv inv3: if self.name <> 'NI' then self.has->exists( i_book : Book | i_book.pages <= 110 )->size()<3 else self.has->forAll(b:Book|b.pages>0) endif", language="OCL")
81
+
82
+
83
+ # Domain model definition
84
+ library_model : DomainModel = DomainModel(name="Library model", types={library, book, author},
85
+ associations={lib_book_association, book_author_association},
86
+ constraints={
87
+ constraintBookPageNumber,
88
+ # constraintTitleIncorrect,
89
+ constraintPageNumber,
90
+ constraintTitleCorrect,
91
+ constraintLibraryExists,
92
+ constraintLibrarySize,
93
+ constraintLibraryCollect,
94
+ constraintLibraryIf,
95
+ constraintLibraryElse,
96
+ # constraintLibraryElseFalse,
97
+ constraintNameOCLIsTypeOf,
98
+ constraintNameOCLIsTypeOfInt,
99
+ # constraintNameOCLIsTypeOfIntFalse
100
+ }
101
+
102
+ # constraints={constraintLibrarySize}
103
+ )
104
+
105
+
106
+ #########################################
107
+ # Library - object model definition #
108
+ #########################################
109
+
110
+
111
+ # Library object attributes
112
+ library_obj_name: AttributeLink = AttributeLink(attribute=library_name, value=DataValue(classifier=t_str, value="Library test"))
113
+ library_obj_address: AttributeLink = AttributeLink(attribute=address, value=DataValue(classifier=t_str, value="street 123"))
114
+ # Library object
115
+ library_obj: Object = Object(name="Library Object", classifier=library, slots=[library_obj_name, library_obj_address])
116
+
117
+ # Book object attributes
118
+ book_obj_name: AttributeLink = AttributeLink(attribute=title, value=DataValue(classifier=t_str, value="Book tittle"))
119
+ book_obj_pages: AttributeLink = AttributeLink(attribute=pages, value=DataValue(classifier=t_int, value=100))
120
+ book_obj_release: AttributeLink = AttributeLink(attribute=release, value=DataValue(classifier=t_date, value=datetime.datetime(2020, 3, 15)))
121
+ # Book object
122
+ book_obj: Object = Object(name="Book Object", classifier=book, slots=[book_obj_name, book_obj_pages])
123
+
124
+ # Book_2 object attributes
125
+
126
+ book_obj_name_2: AttributeLink = AttributeLink(attribute=title, value=DataValue(classifier=t_str, value="Book tittle_2"))
127
+ book_obj_pages_2: AttributeLink = AttributeLink(attribute=pages, value=DataValue(classifier=t_int, value=400))
128
+ book_obj_release_2: AttributeLink = AttributeLink(attribute=release, value=DataValue(classifier=t_date, value=datetime.datetime(2024, 3, 15)))
129
+ # Book object
130
+ book_obj_2: Object = Object(name="Book 2 Object", classifier=book, slots=[book_obj_name_2, book_obj_pages_2])
131
+
132
+ # Author object attributes
133
+ author_obj_name: AttributeLink = AttributeLink(attribute=author_name, value=DataValue(classifier=t_str, value="John Doe"))
134
+ author_obj_email: AttributeLink = AttributeLink(attribute=email, value=DataValue(classifier=t_str, value="john@doe.com"))
135
+ # Author object
136
+ author_obj: Object = Object(name="Author Object", classifier=author, slots=[author_obj_name, author_obj_email])
137
+
138
+ # Book object and Author object link
139
+ book_link_end1: LinkEnd = LinkEnd(name="book_end1", association_end=publishes, object=book_obj)
140
+ author_link_end: LinkEnd = LinkEnd(name="author_end", association_end=writed_by, object=author_obj)
141
+ author_book_link: Link = Link(name="author_book_link", association=book_author_association, connections=[book_link_end1,author_link_end])
142
+
143
+ # Book Library and Book object link
144
+ book_link_end2: LinkEnd = LinkEnd(name="book_end2", association_end=has, object=book_obj)
145
+ library_link_end: LinkEnd = LinkEnd(name="library_end", association_end=located_in, object=library_obj)
146
+ library_book_link: Link = Link(name="library_book_link", association=book_author_association, connections=[book_link_end2,library_link_end])
147
+
148
+ # Book object and Author object link
149
+ book_link_end2: LinkEnd = LinkEnd(name="book_end3", association_end=publishes, object=book_obj_2)
150
+ author_link_end2: LinkEnd = LinkEnd(name="author_end2", association_end=writed_by, object=author_obj)
151
+ author_book_link2: Link = Link(name="author_book_link2", association=book_author_association, connections=[book_link_end2,author_link_end2])
152
+
153
+ # Book Library and Book object link
154
+ book_link_end3: LinkEnd = LinkEnd(name="book_end4", association_end=has, object=book_obj_2)
155
+ library_link_end3: LinkEnd = LinkEnd(name="library_end3", association_end=located_in, object=library_obj)
156
+ library_book_link3: Link = Link(name="library_book_link3", association=book_author_association, connections=[book_link_end3,library_link_end3])
157
+
158
+
159
+
160
+ # Object model definition
161
+ object_model: ObjectModel = ObjectModel(name="Object model", instances={library_obj, author_obj, book_obj,book_obj_2}, links={author_book_link, library_book_link,author_book_link2,library_book_link3})
@@ -0,0 +1,136 @@
1
+ from besser.BUML.metamodel.structural import *
2
+ from besser.BUML.metamodel.object import *
3
+
4
+ #########################################
5
+ # Structural Model #
6
+ #########################################
7
+
8
+ # Primitive DataTypes
9
+ t_int: PrimitiveDataType = PrimitiveDataType("int")
10
+ t_str: PrimitiveDataType = PrimitiveDataType("str")
11
+ t_bool: PrimitiveDataType = PrimitiveDataType("bool")
12
+
13
+ # Paper class
14
+ tittle: Property = Property(name="tittle", type=t_str)
15
+ wordCount: Property = Property(name="wordcount", type=t_int)
16
+ studentPaper: Property = Property(name="studentPaper", type=t_bool)
17
+ paper: Class = Class(name="Paper", attributes={tittle, wordCount, studentPaper})
18
+
19
+ # Researcher class
20
+ name: Property = Property(name="name", type=t_str)
21
+ isStudent: Property = Property(name="isStudent", type=t_bool)
22
+ researcher: Class = Class(name="Researcher", attributes={name, isStudent})
23
+
24
+ # paper-researcher association
25
+ manuscript: Property = Property(name="manuscript", type=paper, multiplicity=Multiplicity(1, 1))
26
+ author: Property = Property(name="author", type=researcher, multiplicity=Multiplicity(1, 2))
27
+ writes: BinaryAssociation = BinaryAssociation(name="writes", ends={manuscript, author})
28
+
29
+ # researcher-paper association
30
+ submission: Property = Property(name="submission", type=paper, multiplicity=Multiplicity(1, 1))
31
+ referee: Property = Property(name="referee", type=researcher, multiplicity=Multiplicity(3, 3))
32
+ reviews: BinaryAssociation = BinaryAssociation(name="reviews", ends={submission, referee})
33
+
34
+ constraintResearcher: Constraint = Constraint(name="NoSelfReviews", context=researcher,
35
+ expression="context Researcher inv NoSelfReviews: self.submission->excludes(self.manuscript)", language="OCL")
36
+
37
+ constraintPaper: Constraint = Constraint(name="PaperLength", context=paper,
38
+ expression="context Paper inv :self.wordcount < 10000", language="OCL")
39
+
40
+ constraintAuthorsOfStudentPaper: Constraint = Constraint(name="AuthorsOfStudentPaper", context=paper,
41
+ expression="context Paper inv AuthorsOfStudentPaper: self.author->exists(x:Researcher | x.isStudent =True)", language="OCL")
42
+
43
+ constraintNoStudentReviewers: Constraint = Constraint(name="NoStudentReviewers", context=paper,
44
+ expression="context Paper inv NoStudentReviewers:self.referee->forAll(r:Researcher | r.isStudent =False)", language="OCL")
45
+
46
+ constraintLimitsOnStudentPapers: Constraint = Constraint(name="LimitsOnStudentPapers", context=paper,
47
+ expression="context Paper inv LimitsOnStudentPapers: Paper::allInstances()->exists(p:Paper | p.studentPaper = True) and Paper::allInstances()->select(p:Paper | p.studentPaper=True) ->size() < 5", language="OCL")
48
+
49
+ constraintPaperTitle: Constraint = Constraint(name="constraintPaperTitle", context=paper,
50
+ expression="context Paper inv title: self.tittle<> 'test'", language="OCL")
51
+ constraintResearcherName:Constraint = Constraint(name="consResearcherName", context=researcher,
52
+ expression="context Researcher inv title: self.name<> 'test'", language="OCL")
53
+
54
+ constraintPaperWordCountgreater: Constraint = Constraint(name="PaperLength100", context=paper,
55
+ expression="context Paper inv :self.wordcount > 1000", language="OCL")
56
+
57
+
58
+ # Structural model
59
+ domain_model: DomainModel = DomainModel(name="my_model", types={paper, researcher}, associations={writes, reviews}, constraints = {
60
+ constraintResearcher,
61
+ constraintPaper,
62
+ constraintAuthorsOfStudentPaper,
63
+ constraintNoStudentReviewers,
64
+ constraintLimitsOnStudentPapers,
65
+ constraintPaperTitle,
66
+ constraintResearcherName,
67
+ constraintPaperWordCountgreater
68
+ })
69
+
70
+
71
+ ###################################
72
+ # Object model #
73
+ ###################################
74
+
75
+ # paper object
76
+ paper_name: AttributeLink = AttributeLink(value=DataValue(value="besser lowcode platform", classifier=None), attribute=tittle)
77
+ paper_words: AttributeLink = AttributeLink(value=DataValue(value=5000, classifier=None), attribute=wordCount)
78
+ paper_student_paper: AttributeLink = AttributeLink(value=DataValue(value=True, classifier=None), attribute=studentPaper)
79
+ paper_obj: Object = Object(name="besser paper", classifier=paper, slots=[paper_name, paper_words, paper_student_paper])
80
+
81
+ # researcher 1 object
82
+ r1_name: AttributeLink = AttributeLink(value=DataValue(value="Marc", classifier=None), attribute=name)
83
+ r1_is_student: AttributeLink = AttributeLink(value=DataValue(value=True, classifier=None), attribute=isStudent)
84
+ researcher_1: Object = Object(name="Marc researcher", classifier=researcher, slots=[r1_name, r1_is_student])
85
+
86
+ # researcher 2 object
87
+ r2_name: AttributeLink = AttributeLink(value=DataValue(value="James", classifier=None), attribute=name)
88
+ r2_is_student: AttributeLink = AttributeLink(value=DataValue(value=True, classifier=None), attribute=isStudent)
89
+ researcher_2: Object = Object(name="James researcher", classifier=researcher, slots=[r2_name, r2_is_student])
90
+
91
+ # researcher 3 object
92
+ r3_name: AttributeLink = AttributeLink(value=DataValue(value="Adam", classifier=None), attribute=name)
93
+ r3_is_student: AttributeLink = AttributeLink(value=DataValue(value=False, classifier=None), attribute=isStudent)
94
+ researcher_3: Object = Object(name="Adam researcher", classifier=researcher, slots=[r3_name, r3_is_student])
95
+
96
+ # researcher 4 object
97
+ r4_name: AttributeLink = AttributeLink(value=DataValue(value="Lola", classifier=None), attribute=name)
98
+ r4_is_student: AttributeLink = AttributeLink(value=DataValue(value=False, classifier=None), attribute=isStudent)
99
+ researcher_4: Object = Object(name="Lola researcher", classifier=researcher, slots=[r4_name, r4_is_student])
100
+
101
+ # researcher 5 object
102
+ r5_name: AttributeLink = AttributeLink(value=DataValue(value="Sarah", classifier=None), attribute=name)
103
+ r5_is_student: AttributeLink = AttributeLink(value=DataValue(value=False, classifier=None), attribute=isStudent)
104
+ researcher_5: Object = Object(name="Sarah researcher", classifier=researcher, slots=[r5_name, r5_is_student])
105
+
106
+ # Links definition
107
+ writes_1: Link = Link(name="writes", association=writes, connections=[
108
+ LinkEnd(name="manuscript", association_end=manuscript, object=paper_obj),
109
+ LinkEnd(name="author", association_end=author, object=researcher_1)
110
+ ])
111
+
112
+ writes_2: Link = Link(name="writes", association=writes, connections=[
113
+ LinkEnd(name="researcher", association_end=manuscript, object=paper_obj),
114
+ LinkEnd(name="author", association_end=author, object=researcher_2)
115
+ ])
116
+
117
+ reviews_1: Link = Link(name="writes", association=writes, connections=[
118
+ LinkEnd(name="submission", association_end=submission, object=paper_obj),
119
+ LinkEnd(name="referee", association_end=referee, object=researcher_3)
120
+ ])
121
+
122
+ reviews_2: Link = Link(name="writes", association=writes, connections=[
123
+ LinkEnd(name="submission", association_end=submission, object=paper_obj),
124
+ LinkEnd(name="referee", association_end=referee, object=researcher_4)
125
+ ])
126
+
127
+ reviews_3: Link = Link(name="writes", association=writes, connections=[
128
+ LinkEnd(name="submission", association_end=submission, object=paper_obj),
129
+ LinkEnd(name="referee", association_end=referee, object=researcher_5)
130
+ ])
131
+
132
+
133
+
134
+ # object model
135
+ object_model: ObjectModel = ObjectModel(name="Object_model", instances={paper_obj, researcher_1, researcher_2, researcher_3, researcher_4, researcher_5},
136
+ links={writes_1, writes_2, reviews_1, reviews_2, reviews_3})
@@ -0,0 +1,95 @@
1
+
2
+ from besser.BUML.metamodel.structural import DomainModel, Class, Property, \
3
+ PrimitiveDataType, Multiplicity, BinaryAssociation,Constraint
4
+ from besser.BUML.metamodel.object import *
5
+ import datetime
6
+
7
+ #############################################
8
+ # Team Player - structural model definition #
9
+ #############################################
10
+
11
+ # Primitive DataTypes
12
+ t_int: PrimitiveDataType = PrimitiveDataType("int")
13
+ t_str: PrimitiveDataType = PrimitiveDataType("str")
14
+ t_date: PrimitiveDataType = PrimitiveDataType("date")
15
+
16
+ # Team attributes definition
17
+ team_name: Property = Property(name="name", type=t_str)
18
+ team_city: Property = Property(name="city", type=t_str)
19
+ team_division: Property = Property(name="division", type=t_str)
20
+ # Team class definition
21
+ team: Class = Class (name="team", attributes={team_name,team_city,team_division})
22
+
23
+ # Player attributes definition
24
+ name: Property = Property(name="name", type=t_str)
25
+ age: Property = Property(name="age", type=t_int)
26
+ position: Property = Property(name="position", type=t_str)
27
+ jerseyNumber: Property = Property(name="jerseyNumber", type=t_int)
28
+
29
+ # Player class definition
30
+ player: Class = Class (name="player", attributes={name, age, position,jerseyNumber})
31
+
32
+
33
+ # team-player association definition
34
+ hasteam: Property = Property(name="many",type=team, multiplicity=Multiplicity(1, 1))
35
+ many: Property = Property(name="has", type=player, multiplicity=Multiplicity(0, "*"))
36
+ team_player_association: BinaryAssociation = BinaryAssociation(name="team_player_asso", ends={hasteam, many})
37
+
38
+
39
+ constraintPlayerAge: Constraint = Constraint(name = "playerAge",context=player,expression="context player inv inv1: self.age > 10",language="OCL")
40
+
41
+ constraintTeamCenter: Constraint = Constraint(name = "teamCenter",context=team,expression="context team inv inv2: self.many -> collect(p:player| p.position = 'center')->size()<3",language="OCL")
42
+
43
+ # Domain model definition
44
+ team_player_model : DomainModel = DomainModel(name="Team-Player model", types={team,player},
45
+ associations={team_player_association },
46
+ constraints={
47
+ constraintPlayerAge,
48
+ constraintTeamCenter
49
+ }
50
+ )
51
+
52
+
53
+ #########################################
54
+ # TeamPlayer - object model definition #
55
+ #########################################
56
+
57
+
58
+ # Team object attributes
59
+ teamObjectName: AttributeLink = AttributeLink(attribute=team_name, value=DataValue(classifier=t_str, value="test-3"))
60
+ teamcity: AttributeLink = AttributeLink(attribute=team_city, value=DataValue(classifier=t_str, value="not important"))
61
+ teamDivision: AttributeLink = AttributeLink(attribute=team_division, value=DataValue(classifier=t_str, value="junior"))
62
+ # Team object
63
+ teamObject: Object = Object(name="team object", classifier=team, slots=[teamObjectName,teamcity,teamDivision])
64
+
65
+ # player object attributes
66
+ player1_obj_name: AttributeLink = AttributeLink(attribute=name, value=DataValue(classifier=t_str, value="test"))
67
+ player1_obj_age: AttributeLink = AttributeLink(attribute=age, value=DataValue(classifier=t_int, value=12))
68
+ player1_obj_position: AttributeLink = AttributeLink(attribute=position, value=DataValue(classifier=t_str, value="center"))
69
+ player1_obj_JN: AttributeLink = AttributeLink(attribute=jerseyNumber, value=DataValue(classifier=t_int, value=10))
70
+
71
+ # Player object
72
+ player_1_obj: Object = Object(name="playerTest1", classifier=player, slots=[player1_obj_name, player1_obj_age,player1_obj_position,player1_obj_JN])
73
+
74
+
75
+ # player 2 object attributes
76
+ player2_obj_name: AttributeLink = AttributeLink(attribute=name, value=DataValue(classifier=t_str, value="test-2"))
77
+ player2_obj_age: AttributeLink = AttributeLink(attribute=age, value=DataValue(classifier=t_int, value=15))
78
+ player2_obj_position: AttributeLink = AttributeLink(attribute=position, value=DataValue(classifier=t_str, value="center"))
79
+ player2_obj_JN: AttributeLink = AttributeLink(attribute=jerseyNumber, value=DataValue(classifier=t_int, value=11))
80
+
81
+ # Player object
82
+ player_2_obj: Object = Object(name="playerTest2", classifier=player, slots=[player2_obj_name, player2_obj_age,player2_obj_position,player2_obj_JN])
83
+
84
+ # player1 team object link
85
+ player_1_link_end: LinkEnd = LinkEnd(name="many", association_end=hasteam, object=player_1_obj)
86
+ team_1_link_end: LinkEnd = LinkEnd(name="has", association_end=many, object=teamObject)
87
+ team_player_link_1: Link = Link(name="team_player_link_1", association=team_player_association, connections=[player_1_link_end,team_1_link_end])
88
+
89
+ # player2 team object link
90
+ player_2_link_end: LinkEnd = LinkEnd(name="many", association_end=hasteam, object=player_2_obj)
91
+ team_2_link_end: LinkEnd = LinkEnd(name="has", association_end=many, object=teamObject)
92
+ team_player_link_2: Link = Link(name="team_player_link_2", association=team_player_association, connections=[player_2_link_end,team_2_link_end])
93
+
94
+ # Object model definition
95
+ object_model: ObjectModel = ObjectModel(name="Object model", instances={teamObject, player_1_obj,player_2_obj}, links={team_player_link_1,team_player_link_2})
@@ -0,0 +1,3 @@
1
+ [build-system]
2
+ requires = ["setuptools>=42", "wheel"]
3
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,15 @@
1
+ Arpeggio==2.0.2
2
+ colorama==0.4.6
3
+ iniconfig==2.0.0
4
+ packaging
5
+ pluggy==1.2.0
6
+ pytest==7.4.0
7
+ setuptools==68.2.2
8
+ textX==3.1.1
9
+ jinja2==3.1.2
10
+ antlr4-python3-runtime==4.13.1
11
+ requests==2.31.0
12
+ fastapi==0.110.0
13
+ pydantic==2.6.3
14
+ uvicorn==0.28.0
15
+ besser
bocl-0.2.0/setup.cfg ADDED
@@ -0,0 +1,27 @@
1
+ [metadata]
2
+ name = bocl
3
+ version = 0.2.0
4
+ author = Luxembourg Institute of Science and Technology
5
+ description = B-OCL
6
+ long_description = file: README.md
7
+ long_description_content_type = text/markdown
8
+ project_urls =
9
+ Documentation = https://b-ocl-interpreter.readthedocs.io/en/latest/
10
+ Source Code = https://github.com/BESSER-PEARL/B-OCL-Interpreter
11
+ Bug Tracker = https://github.com/BESSER-PEARL/B-OCL-Interpreter/issues
12
+ keywords = uml, code generation, python
13
+ license = MIT
14
+ license_files = LICENSE
15
+
16
+ [options]
17
+ python_requires = >=3.9
18
+ install_requires = file: requirements.txt
19
+ packages = find:
20
+
21
+ [options.package_data]
22
+ * = *.j2
23
+
24
+ [egg_info]
25
+ tag_build =
26
+ tag_date = 0
27
+