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 +91 -0
- bocl-0.2.0/README.md +63 -0
- bocl-0.2.0/bocl/OCLWrapper.py +46 -0
- bocl-0.2.0/bocl/__init__.py +0 -0
- bocl-0.2.0/bocl/evaluator.py +486 -0
- bocl-0.2.0/bocl.egg-info/PKG-INFO +91 -0
- bocl-0.2.0/bocl.egg-info/SOURCES.txt +16 -0
- bocl-0.2.0/bocl.egg-info/dependency_links.txt +1 -0
- bocl-0.2.0/bocl.egg-info/requires.txt +15 -0
- bocl-0.2.0/bocl.egg-info/top_level.txt +2 -0
- bocl-0.2.0/models/__init__.py +0 -0
- bocl-0.2.0/models/library_object.py +161 -0
- bocl-0.2.0/models/researcher_object.py +136 -0
- bocl-0.2.0/models/team_player_object.py +95 -0
- bocl-0.2.0/pyproject.toml +3 -0
- bocl-0.2.0/requirements.txt +15 -0
- bocl-0.2.0/setup.cfg +27 -0
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 @@
|
|
|
1
|
+
|
|
@@ -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
|
|
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,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
|
+
|