semantikon 0.0.8__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.
- semantikon-0.0.8/LICENSE +29 -0
- semantikon-0.0.8/MANIFEST.in +1 -0
- semantikon-0.0.8/PKG-INFO +166 -0
- semantikon-0.0.8/docs/README.md +112 -0
- semantikon-0.0.8/pyproject.toml +37 -0
- semantikon-0.0.8/semantikon/__init__.py +3 -0
- semantikon-0.0.8/semantikon/_version.py +21 -0
- semantikon-0.0.8/semantikon/converter.py +216 -0
- semantikon-0.0.8/semantikon/typing.py +48 -0
- semantikon-0.0.8/semantikon.egg-info/PKG-INFO +166 -0
- semantikon-0.0.8/semantikon.egg-info/SOURCES.txt +14 -0
- semantikon-0.0.8/semantikon.egg-info/dependency_links.txt +1 -0
- semantikon-0.0.8/semantikon.egg-info/requires.txt +2 -0
- semantikon-0.0.8/semantikon.egg-info/top_level.txt +1 -0
- semantikon-0.0.8/setup.cfg +4 -0
- semantikon-0.0.8/setup.py +8 -0
semantikon-0.0.8/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024, Max-Planck-Institut für Nachhaltige Materialien GmbH - Computational Materials Design (CM) Department
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
* Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include LICENSE
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: semantikon
|
|
3
|
+
Version: 0.0.8
|
|
4
|
+
Summary: semantikon - Ontological type system
|
|
5
|
+
Author-email: Sam Waseda <waseda@mpie.de>
|
|
6
|
+
License: BSD 3-Clause License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2024, Max-Planck-Institut für Nachhaltige Materialien GmbH - Computational Materials Design (CM) Department
|
|
9
|
+
All rights reserved.
|
|
10
|
+
|
|
11
|
+
Redistribution and use in source and binary forms, with or without
|
|
12
|
+
modification, are permitted provided that the following conditions are met:
|
|
13
|
+
|
|
14
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
15
|
+
list of conditions and the following disclaimer.
|
|
16
|
+
|
|
17
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
18
|
+
this list of conditions and the following disclaimer in the documentation
|
|
19
|
+
and/or other materials provided with the distribution.
|
|
20
|
+
|
|
21
|
+
* Neither the name of the copyright holder nor the names of its
|
|
22
|
+
contributors may be used to endorse or promote products derived from
|
|
23
|
+
this software without specific prior written permission.
|
|
24
|
+
|
|
25
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
26
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
27
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
28
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
29
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
30
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
31
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
32
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
33
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
34
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
35
|
+
|
|
36
|
+
Project-URL: Homepage, https://pyiron.org/
|
|
37
|
+
Project-URL: Documentation, https://semantikon.readthedocs.io
|
|
38
|
+
Project-URL: Repository, https://github.com/pyiron/semantikon
|
|
39
|
+
Keywords: pyiron
|
|
40
|
+
Classifier: Development Status :: 3 - Alpha
|
|
41
|
+
Classifier: Topic :: Scientific/Engineering
|
|
42
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
43
|
+
Classifier: Intended Audience :: Science/Research
|
|
44
|
+
Classifier: Operating System :: OS Independent
|
|
45
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
46
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
47
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
48
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
49
|
+
Requires-Python: <3.13,>=3.9
|
|
50
|
+
Description-Content-Type: text/markdown
|
|
51
|
+
License-File: LICENSE
|
|
52
|
+
Requires-Dist: numpy<2.3.0,>=2.2.1
|
|
53
|
+
Requires-Dist: pint==0.24.4
|
|
54
|
+
|
|
55
|
+
# semantikon
|
|
56
|
+
|
|
57
|
+
## Overview
|
|
58
|
+
|
|
59
|
+
In the realm of the workflow management systems, there are well defined inputs and outputs for each node. `semantikon` is a Python package to give scientific context to node inputs and outputs by providing type hinting and interpreters. Therefore, it consists of two **fully** separate parts: type hinting and interpreters.
|
|
60
|
+
|
|
61
|
+
### **Type hinting**
|
|
62
|
+
|
|
63
|
+
`semantikon` provides a way to define types for any number of input parameters and any number of output values for function via type hinting, in particular: data type, unit and ontological type. Type hinting is done with the function `u`, which **requires** the type, and **optionally** you can define the units and the ontological type. The type hinting is done in the following way:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from semantikon.typing import u
|
|
67
|
+
|
|
68
|
+
def my_function(
|
|
69
|
+
distance: u(int, units="meter"),
|
|
70
|
+
time: u(int, units="second")
|
|
71
|
+
) -> u(int, units="meter/second", label="speed"):
|
|
72
|
+
return distance / time
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`semantikon`'s type hinting does not require to follow any particular standard. It only needs to be compatible with the interpreter applied.
|
|
76
|
+
|
|
77
|
+
There are two possible ways to store the data for `semantikon`. The standard way is to do it by converting all arguments except for the data type as a string, which is the default behaviour. The other way is to store the data as a list, which is turned on by setting `use_list=True`. In most cases, the default behaviour is the safest option; in some cases, especially when the data cannot be represented as a string, you might want to switch on `use_list`, but `semantikon` is still under intensive development, and therefore there is no guarantee that you can retrieve the data across different versions correctly.
|
|
78
|
+
|
|
79
|
+
You can also type-hint the inputs and outputs of a function using a class, i.e.:
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from semantikon.typing import u
|
|
84
|
+
from semantikon.convert import semantikon_class
|
|
85
|
+
|
|
86
|
+
@semantikon_class
|
|
87
|
+
class MyRecord:
|
|
88
|
+
distance: u(int, units="meter")
|
|
89
|
+
time: u(int, units="second")
|
|
90
|
+
result: u(int, units="meter/second", label="speed")
|
|
91
|
+
|
|
92
|
+
def my_function(distance: MyRecord.distance, time: MyRecord.time) -> MyRecord.result:
|
|
93
|
+
return distance / time
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
This is equivalent to the previous example. Moreover, if you need to modify some parameters, you can use `u` again, e.g. `u(MyRecord.distance, units="kilometer")`.
|
|
97
|
+
|
|
98
|
+
### **Interpreters**
|
|
99
|
+
|
|
100
|
+
#### General interpreter
|
|
101
|
+
|
|
102
|
+
In order to extract argument information, you can use the functions `parse_input_args` and `parse_output_args`. `parse_input_args` parses the input variables and return a dictionary with the variable names as keys and the variable information as values. `parse_output_args` parses the output variables and return a dictionary with the variable information as values if there is one output variable, or a list of dictionaries if it is a tuple.
|
|
103
|
+
|
|
104
|
+
Example:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from semantikon.typing import u
|
|
108
|
+
from semantikon.converter import parse_input_args, parse_output_args
|
|
109
|
+
|
|
110
|
+
def my_function(
|
|
111
|
+
a: u(int, units="meter"),
|
|
112
|
+
b: u(int, units="second")
|
|
113
|
+
) -> u(int, units="meter/second", label="speed"):
|
|
114
|
+
return a / b
|
|
115
|
+
|
|
116
|
+
print(parse_input_args(my_function))
|
|
117
|
+
print(parse_output_args(my_function))
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Output:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
{'distance': {'units': 'meter', 'label': None, 'uri': None, 'shape': None, 'dtype': <class 'float'>}, 'time': {'units': 'second', 'label': None, 'uri': None, 'shape': None, 'dtype': <class 'float'>}}
|
|
124
|
+
{'units': 'meter/second', 'label': 'speed', 'uri': None, 'shape': None, 'dtype': <class 'float'>}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Here the output is the same whether `use_list` is set to `True` or `False`. When `use_list` is `False`, you can use additionally any tag that you want to store. When `use_list` is `True`, you can store only the data type, `units`, `label`, `uri`, `shape` and `dtype`.
|
|
128
|
+
|
|
129
|
+
Future announcement: There will be no distrinction between `use_list=True` and `use_list=False` when the official support of python 3.10 is dropped (i.e. around autumn 2026).
|
|
130
|
+
|
|
131
|
+
#### Unit conversion with `pint`
|
|
132
|
+
|
|
133
|
+
`semantikon` provides a way to interpret the types of inputs and outputs of a function via a decorator, in order to check consistency of the types and to convert them if necessary. Currently, `semantikon` provides an interpreter for `pint.UnitRegistry` objects. The interpreter is applied in the following way:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from semantikon.typing import u
|
|
137
|
+
from semantikon.converters import units
|
|
138
|
+
from pint import UnitRegistry
|
|
139
|
+
|
|
140
|
+
@units
|
|
141
|
+
def my_function(
|
|
142
|
+
a: u(int, units="meter"),
|
|
143
|
+
b: u(int, units="second")
|
|
144
|
+
) -> u(int, units="meter/second", label="speed"):
|
|
145
|
+
return a / b
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
ureg = UnitRegistry()
|
|
149
|
+
|
|
150
|
+
print(my_function(1 * ureg.meter, 1 * ureg.second))
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Output: `1.0 meter / second`
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
The interpreters check all types and, if necessary, convert them to the expected types **before** the function is executed, in order for all possible errors would be raised before the function execution. The interpreters convert the types in the way that the underlying function would receive the raw values.
|
|
157
|
+
|
|
158
|
+
In case there are multiple outputs, the type hints are to be passed as a tuple (e.g. `tuple[u(int, "meter"), u(int, "second"))`).
|
|
159
|
+
|
|
160
|
+
It is not totally garanteed as a functionality, but relative units as given [on this page](https://pint.readthedocs.io/en/0.10.1/wrapping.html#specifying-relations-between-arguments) can be also used.
|
|
161
|
+
|
|
162
|
+
Interpreters can distinguish between annotated arguments and non-anotated arguments. If the argument is annotated, the interpreter will try to convert the argument to the expected type. If the argument is not annotated, the interpreter will pass the argument as is.
|
|
163
|
+
|
|
164
|
+
Regardless of type hints are given or not, the interpreter acts only when the input values contain units and ontological types. If the input values do not contain units and ontological types, the interpreter will pass the input values to the function as is.
|
|
165
|
+
|
|
166
|
+
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# semantikon
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
In the realm of the workflow management systems, there are well defined inputs and outputs for each node. `semantikon` is a Python package to give scientific context to node inputs and outputs by providing type hinting and interpreters. Therefore, it consists of two **fully** separate parts: type hinting and interpreters.
|
|
6
|
+
|
|
7
|
+
### **Type hinting**
|
|
8
|
+
|
|
9
|
+
`semantikon` provides a way to define types for any number of input parameters and any number of output values for function via type hinting, in particular: data type, unit and ontological type. Type hinting is done with the function `u`, which **requires** the type, and **optionally** you can define the units and the ontological type. The type hinting is done in the following way:
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
from semantikon.typing import u
|
|
13
|
+
|
|
14
|
+
def my_function(
|
|
15
|
+
distance: u(int, units="meter"),
|
|
16
|
+
time: u(int, units="second")
|
|
17
|
+
) -> u(int, units="meter/second", label="speed"):
|
|
18
|
+
return distance / time
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`semantikon`'s type hinting does not require to follow any particular standard. It only needs to be compatible with the interpreter applied.
|
|
22
|
+
|
|
23
|
+
There are two possible ways to store the data for `semantikon`. The standard way is to do it by converting all arguments except for the data type as a string, which is the default behaviour. The other way is to store the data as a list, which is turned on by setting `use_list=True`. In most cases, the default behaviour is the safest option; in some cases, especially when the data cannot be represented as a string, you might want to switch on `use_list`, but `semantikon` is still under intensive development, and therefore there is no guarantee that you can retrieve the data across different versions correctly.
|
|
24
|
+
|
|
25
|
+
You can also type-hint the inputs and outputs of a function using a class, i.e.:
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from semantikon.typing import u
|
|
30
|
+
from semantikon.convert import semantikon_class
|
|
31
|
+
|
|
32
|
+
@semantikon_class
|
|
33
|
+
class MyRecord:
|
|
34
|
+
distance: u(int, units="meter")
|
|
35
|
+
time: u(int, units="second")
|
|
36
|
+
result: u(int, units="meter/second", label="speed")
|
|
37
|
+
|
|
38
|
+
def my_function(distance: MyRecord.distance, time: MyRecord.time) -> MyRecord.result:
|
|
39
|
+
return distance / time
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This is equivalent to the previous example. Moreover, if you need to modify some parameters, you can use `u` again, e.g. `u(MyRecord.distance, units="kilometer")`.
|
|
43
|
+
|
|
44
|
+
### **Interpreters**
|
|
45
|
+
|
|
46
|
+
#### General interpreter
|
|
47
|
+
|
|
48
|
+
In order to extract argument information, you can use the functions `parse_input_args` and `parse_output_args`. `parse_input_args` parses the input variables and return a dictionary with the variable names as keys and the variable information as values. `parse_output_args` parses the output variables and return a dictionary with the variable information as values if there is one output variable, or a list of dictionaries if it is a tuple.
|
|
49
|
+
|
|
50
|
+
Example:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from semantikon.typing import u
|
|
54
|
+
from semantikon.converter import parse_input_args, parse_output_args
|
|
55
|
+
|
|
56
|
+
def my_function(
|
|
57
|
+
a: u(int, units="meter"),
|
|
58
|
+
b: u(int, units="second")
|
|
59
|
+
) -> u(int, units="meter/second", label="speed"):
|
|
60
|
+
return a / b
|
|
61
|
+
|
|
62
|
+
print(parse_input_args(my_function))
|
|
63
|
+
print(parse_output_args(my_function))
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Output:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
{'distance': {'units': 'meter', 'label': None, 'uri': None, 'shape': None, 'dtype': <class 'float'>}, 'time': {'units': 'second', 'label': None, 'uri': None, 'shape': None, 'dtype': <class 'float'>}}
|
|
70
|
+
{'units': 'meter/second', 'label': 'speed', 'uri': None, 'shape': None, 'dtype': <class 'float'>}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Here the output is the same whether `use_list` is set to `True` or `False`. When `use_list` is `False`, you can use additionally any tag that you want to store. When `use_list` is `True`, you can store only the data type, `units`, `label`, `uri`, `shape` and `dtype`.
|
|
74
|
+
|
|
75
|
+
Future announcement: There will be no distrinction between `use_list=True` and `use_list=False` when the official support of python 3.10 is dropped (i.e. around autumn 2026).
|
|
76
|
+
|
|
77
|
+
#### Unit conversion with `pint`
|
|
78
|
+
|
|
79
|
+
`semantikon` provides a way to interpret the types of inputs and outputs of a function via a decorator, in order to check consistency of the types and to convert them if necessary. Currently, `semantikon` provides an interpreter for `pint.UnitRegistry` objects. The interpreter is applied in the following way:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from semantikon.typing import u
|
|
83
|
+
from semantikon.converters import units
|
|
84
|
+
from pint import UnitRegistry
|
|
85
|
+
|
|
86
|
+
@units
|
|
87
|
+
def my_function(
|
|
88
|
+
a: u(int, units="meter"),
|
|
89
|
+
b: u(int, units="second")
|
|
90
|
+
) -> u(int, units="meter/second", label="speed"):
|
|
91
|
+
return a / b
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
ureg = UnitRegistry()
|
|
95
|
+
|
|
96
|
+
print(my_function(1 * ureg.meter, 1 * ureg.second))
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Output: `1.0 meter / second`
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
The interpreters check all types and, if necessary, convert them to the expected types **before** the function is executed, in order for all possible errors would be raised before the function execution. The interpreters convert the types in the way that the underlying function would receive the raw values.
|
|
103
|
+
|
|
104
|
+
In case there are multiple outputs, the type hints are to be passed as a tuple (e.g. `tuple[u(int, "meter"), u(int, "second"))`).
|
|
105
|
+
|
|
106
|
+
It is not totally garanteed as a functionality, but relative units as given [on this page](https://pint.readthedocs.io/en/0.10.1/wrapping.html#specifying-relations-between-arguments) can be also used.
|
|
107
|
+
|
|
108
|
+
Interpreters can distinguish between annotated arguments and non-anotated arguments. If the argument is annotated, the interpreter will try to convert the argument to the expected type. If the argument is not annotated, the interpreter will pass the argument as is.
|
|
109
|
+
|
|
110
|
+
Regardless of type hints are given or not, the interpreter acts only when the input values contain units and ontological types. If the input values do not contain units and ontological types, the interpreter will pass the input values to the function as is.
|
|
111
|
+
|
|
112
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = [ "setuptools", "versioneer[toml]==0.29",]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "semantikon"
|
|
7
|
+
description = "semantikon - Ontological type system"
|
|
8
|
+
readme = "docs/README.md"
|
|
9
|
+
keywords = [ "pyiron",]
|
|
10
|
+
requires-python = ">=3.9, <3.13"
|
|
11
|
+
classifiers = [ "Development Status :: 3 - Alpha", "Topic :: Scientific/Engineering", "License :: OSI Approved :: BSD License", "Intended Audience :: Science/Research", "Operating System :: OS Independent", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12",]
|
|
12
|
+
dependencies = [ "numpy>=2.2.1,<2.3.0", "pint==0.24.4",]
|
|
13
|
+
dynamic = [ "version",]
|
|
14
|
+
[[project.authors]]
|
|
15
|
+
name = "Sam Waseda"
|
|
16
|
+
email = "waseda@mpie.de"
|
|
17
|
+
|
|
18
|
+
[project.license]
|
|
19
|
+
file = "LICENSE"
|
|
20
|
+
|
|
21
|
+
[project.urls]
|
|
22
|
+
Homepage = "https://pyiron.org/"
|
|
23
|
+
Documentation = "https://semantikon.readthedocs.io"
|
|
24
|
+
Repository = "https://github.com/pyiron/semantikon"
|
|
25
|
+
|
|
26
|
+
[tool.versioneer]
|
|
27
|
+
VCS = "git"
|
|
28
|
+
style = "pep440-pre"
|
|
29
|
+
versionfile_source = "semantikon/_version.py"
|
|
30
|
+
parentdir_prefix = "semantikon"
|
|
31
|
+
tag_prefix = "semantikon-"
|
|
32
|
+
|
|
33
|
+
[tool.setuptools.packages.find]
|
|
34
|
+
include = [ "semantikon*",]
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.dynamic.version]
|
|
37
|
+
attr = "semantikon.__version__"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
# This file was generated by 'versioneer.py' (0.29) from
|
|
3
|
+
# revision-control system data, or from the parent directory name of an
|
|
4
|
+
# unpacked source archive. Distribution tarballs contain a pre-generated copy
|
|
5
|
+
# of this file.
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
version_json = '''
|
|
10
|
+
{
|
|
11
|
+
"date": "2025-01-16T06:51:49+0100",
|
|
12
|
+
"dirty": true,
|
|
13
|
+
"error": null,
|
|
14
|
+
"full-revisionid": "d21c1688b4b8b2589bfa7e0927afa90e64699575",
|
|
15
|
+
"version": "0.0.8"
|
|
16
|
+
}
|
|
17
|
+
''' # END VERSION_JSON
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_versions():
|
|
21
|
+
return json.loads(version_json)
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# Copyright (c) Max-Planck-Institut für Eisenforschung GmbH - Computational Materials Design (CM) Department
|
|
3
|
+
# Distributed under the terms of "New BSD License", see the LICENSE file.
|
|
4
|
+
|
|
5
|
+
from pint import Quantity
|
|
6
|
+
import inspect
|
|
7
|
+
from functools import wraps
|
|
8
|
+
from pint.registry_helpers import (
|
|
9
|
+
_apply_defaults,
|
|
10
|
+
_parse_wrap_args,
|
|
11
|
+
_to_units_container,
|
|
12
|
+
_replace_units,
|
|
13
|
+
)
|
|
14
|
+
from ast import literal_eval
|
|
15
|
+
from typing import get_origin, get_args
|
|
16
|
+
|
|
17
|
+
__author__ = "Sam Waseda"
|
|
18
|
+
__copyright__ = (
|
|
19
|
+
"Copyright 2021, Max-Planck-Institut für Eisenforschung GmbH "
|
|
20
|
+
"- Computational Materials Design (CM) Department"
|
|
21
|
+
)
|
|
22
|
+
__version__ = "1.0"
|
|
23
|
+
__maintainer__ = "Sam Waseda"
|
|
24
|
+
__email__ = "waseda@mpie.de"
|
|
25
|
+
__status__ = "development"
|
|
26
|
+
__date__ = "Aug 21, 2021"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _get_ureg(args, kwargs):
|
|
30
|
+
for arg in args + tuple(kwargs.values()):
|
|
31
|
+
if isinstance(arg, Quantity):
|
|
32
|
+
return arg._REGISTRY
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def parse_metadata(value):
|
|
37
|
+
"""
|
|
38
|
+
Parse the metadata of a Quantity object.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
value: Quantity object
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
dictionary of the metadata. Available keys are `units`, `label`,
|
|
45
|
+
`triple`, `uri` and `shape`. See `semantikon.typing.u` for more details.
|
|
46
|
+
"""
|
|
47
|
+
# When there is only one metadata `use_list=False` must have been used
|
|
48
|
+
if len(value.__metadata__) == 1 and isinstance(value.__metadata__[0], str):
|
|
49
|
+
return literal_eval(value.__metadata__[0])
|
|
50
|
+
else:
|
|
51
|
+
d = {}
|
|
52
|
+
for ii in range(len(value.__metadata__[0]) // 2):
|
|
53
|
+
d[value.__metadata__[0][2 * ii]] = value.__metadata__[0][2 * ii + 1]
|
|
54
|
+
return d
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _meta_to_dict(value):
|
|
58
|
+
if hasattr(value, "__metadata__"):
|
|
59
|
+
result = parse_metadata(value)
|
|
60
|
+
result["dtype"] = value.__args__[0]
|
|
61
|
+
return result
|
|
62
|
+
elif value is not inspect.Parameter.empty:
|
|
63
|
+
return {
|
|
64
|
+
"units": None,
|
|
65
|
+
"label": None,
|
|
66
|
+
"triple": None,
|
|
67
|
+
"uri": None,
|
|
68
|
+
"shape": None,
|
|
69
|
+
"restriction": None,
|
|
70
|
+
"dtype": value,
|
|
71
|
+
}
|
|
72
|
+
else:
|
|
73
|
+
return None
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def parse_input_args(func: callable):
|
|
77
|
+
"""
|
|
78
|
+
Parse the input arguments of a function.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
func: function to be parsed
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
dictionary of the input arguments. Available keys are `units`, `label`,
|
|
85
|
+
`triple`, `uri` and `shape`. See `semantikon.typing.u` for more details.
|
|
86
|
+
"""
|
|
87
|
+
return {
|
|
88
|
+
key: _meta_to_dict(value.annotation)
|
|
89
|
+
for key, value in inspect.signature(func).parameters.items()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def parse_output_args(func: callable):
|
|
94
|
+
"""
|
|
95
|
+
Parse the output arguments of a function.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
func: function to be parsed
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
dictionary of the output arguments if there is only one output. Otherwise,
|
|
102
|
+
a list of dictionaries is returned. Available keys are `units`,
|
|
103
|
+
`label`, `triple`, `uri` and `shape`. See `semantikon.typing.u` for
|
|
104
|
+
more details.
|
|
105
|
+
"""
|
|
106
|
+
sig = inspect.signature(func)
|
|
107
|
+
if get_origin(sig.return_annotation) is tuple:
|
|
108
|
+
return tuple([_meta_to_dict(ann) for ann in get_args(sig.return_annotation)])
|
|
109
|
+
else:
|
|
110
|
+
return _meta_to_dict(sig.return_annotation)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _get_converter(func):
|
|
114
|
+
args = []
|
|
115
|
+
for value in parse_input_args(func).values():
|
|
116
|
+
if value is not None:
|
|
117
|
+
args.append(value["units"])
|
|
118
|
+
else:
|
|
119
|
+
args.append(None)
|
|
120
|
+
if any([arg is not None for arg in args]):
|
|
121
|
+
return _parse_wrap_args(args)
|
|
122
|
+
else:
|
|
123
|
+
return None
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _get_ret_units(output, ureg, names):
|
|
127
|
+
if output is None:
|
|
128
|
+
return None
|
|
129
|
+
ret = _to_units_container(output["units"], ureg)
|
|
130
|
+
names = {key: 1.0 * value.units for key, value in names.items()}
|
|
131
|
+
return ureg.Quantity(1, _replace_units(ret[0], names) if ret[1] else ret[0])
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _get_output_units(output, ureg, names):
|
|
135
|
+
if isinstance(output, tuple):
|
|
136
|
+
return tuple([_get_ret_units(oo, ureg, names) for oo in output])
|
|
137
|
+
else:
|
|
138
|
+
return _get_ret_units(output, ureg, names)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def units(func):
|
|
142
|
+
"""
|
|
143
|
+
Decorator to convert the output of a function to a Quantity object with
|
|
144
|
+
the specified units.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
func: function to be decorated
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
decorated function
|
|
151
|
+
"""
|
|
152
|
+
sig = inspect.signature(func)
|
|
153
|
+
converter = _get_converter(func)
|
|
154
|
+
|
|
155
|
+
@wraps(func)
|
|
156
|
+
def wrapper(*args, **kwargs):
|
|
157
|
+
ureg = _get_ureg(args, kwargs)
|
|
158
|
+
if converter is None or ureg is None:
|
|
159
|
+
return func(*args, **kwargs)
|
|
160
|
+
args, kwargs = _apply_defaults(sig, args, kwargs)
|
|
161
|
+
args, kwargs, names = converter(ureg, sig, args, kwargs, strict=False)
|
|
162
|
+
try:
|
|
163
|
+
output_units = _get_output_units(parse_output_args(func), ureg, names)
|
|
164
|
+
except AttributeError:
|
|
165
|
+
output_units = None
|
|
166
|
+
if output_units is None:
|
|
167
|
+
return func(*args, **kwargs)
|
|
168
|
+
elif isinstance(output_units, tuple):
|
|
169
|
+
return tuple(
|
|
170
|
+
[oo * ff for oo, ff in zip(output_units, func(*args, **kwargs))]
|
|
171
|
+
)
|
|
172
|
+
else:
|
|
173
|
+
return output_units * func(*args, **kwargs)
|
|
174
|
+
|
|
175
|
+
return wrapper
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def semantikon_class(cls: type):
|
|
179
|
+
"""
|
|
180
|
+
A class decorator to append type hints to class attributes.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
cls: class to be decorated
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
The modified class with type hints appended to its attributes.
|
|
187
|
+
|
|
188
|
+
Comments:
|
|
189
|
+
|
|
190
|
+
>>> from typing import Annotated
|
|
191
|
+
>>> from semantikon.converter import semantikon_class
|
|
192
|
+
|
|
193
|
+
>>> @semantikon_class
|
|
194
|
+
>>> class Pizza:
|
|
195
|
+
>>> price: Annotated[float, "money"]
|
|
196
|
+
>>> size: Annotated[float, "dimension"]
|
|
197
|
+
|
|
198
|
+
>>> class Topping:
|
|
199
|
+
>>> sauce: Annotated[str, "matter"]
|
|
200
|
+
|
|
201
|
+
>>> append_types(Pizza)
|
|
202
|
+
>>> print(Pizza)
|
|
203
|
+
>>> print(Pizza.Topping)
|
|
204
|
+
>>> print(Pizza.size)
|
|
205
|
+
>>> print(Pizza.price)
|
|
206
|
+
>>> print(Pizza.Topping.sauce)
|
|
207
|
+
"""
|
|
208
|
+
for key, value in cls.__dict__.items():
|
|
209
|
+
if isinstance(value, type):
|
|
210
|
+
semantikon_class(getattr(cls, key)) # Recursively apply to nested classes
|
|
211
|
+
try:
|
|
212
|
+
for key, value in cls.__annotations__.items():
|
|
213
|
+
setattr(cls, key, value) # Append type hints to attributes
|
|
214
|
+
except AttributeError:
|
|
215
|
+
pass
|
|
216
|
+
return cls
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from typing import Annotated, Any
|
|
2
|
+
from semantikon.converter import parse_metadata
|
|
3
|
+
|
|
4
|
+
__author__ = "Sam Waseda"
|
|
5
|
+
__copyright__ = (
|
|
6
|
+
"Copyright 2021, Max-Planck-Institut für Eisenforschung GmbH "
|
|
7
|
+
"- Computational Materials Design (CM) Department"
|
|
8
|
+
)
|
|
9
|
+
__version__ = "1.0"
|
|
10
|
+
__maintainer__ = "Sam Waseda"
|
|
11
|
+
__email__ = "waseda@mpie.de"
|
|
12
|
+
__status__ = "development"
|
|
13
|
+
__date__ = "Aug 21, 2021"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def u(
|
|
17
|
+
type_,
|
|
18
|
+
/,
|
|
19
|
+
units: str | None = None,
|
|
20
|
+
label: str | None = None,
|
|
21
|
+
triple: tuple[tuple[str, str, str], ...] | tuple[str, str, str] | None = None,
|
|
22
|
+
uri: str | None = None,
|
|
23
|
+
shape: tuple[int] | None = None,
|
|
24
|
+
restriction: tuple[tuple[str, str]] | None = None,
|
|
25
|
+
use_list: bool = True,
|
|
26
|
+
**kwargs,
|
|
27
|
+
):
|
|
28
|
+
parent_result = {}
|
|
29
|
+
if hasattr(type_, "__metadata__"):
|
|
30
|
+
parent_result = parse_metadata(type_)
|
|
31
|
+
type_ = type_.__origin__
|
|
32
|
+
result = {
|
|
33
|
+
"units": units,
|
|
34
|
+
"label": label,
|
|
35
|
+
"triple": triple,
|
|
36
|
+
"uri": uri,
|
|
37
|
+
"shape": shape,
|
|
38
|
+
"restriction": restriction,
|
|
39
|
+
}
|
|
40
|
+
for key, value in parent_result.items():
|
|
41
|
+
if result[key] is None:
|
|
42
|
+
result[key] = value
|
|
43
|
+
result.update(kwargs)
|
|
44
|
+
if use_list:
|
|
45
|
+
items = [x for k, v in result.items() for x in [k, v]]
|
|
46
|
+
return Annotated[type_, items]
|
|
47
|
+
else:
|
|
48
|
+
return Annotated[type_, str(result)]
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: semantikon
|
|
3
|
+
Version: 0.0.8
|
|
4
|
+
Summary: semantikon - Ontological type system
|
|
5
|
+
Author-email: Sam Waseda <waseda@mpie.de>
|
|
6
|
+
License: BSD 3-Clause License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2024, Max-Planck-Institut für Nachhaltige Materialien GmbH - Computational Materials Design (CM) Department
|
|
9
|
+
All rights reserved.
|
|
10
|
+
|
|
11
|
+
Redistribution and use in source and binary forms, with or without
|
|
12
|
+
modification, are permitted provided that the following conditions are met:
|
|
13
|
+
|
|
14
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
15
|
+
list of conditions and the following disclaimer.
|
|
16
|
+
|
|
17
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
18
|
+
this list of conditions and the following disclaimer in the documentation
|
|
19
|
+
and/or other materials provided with the distribution.
|
|
20
|
+
|
|
21
|
+
* Neither the name of the copyright holder nor the names of its
|
|
22
|
+
contributors may be used to endorse or promote products derived from
|
|
23
|
+
this software without specific prior written permission.
|
|
24
|
+
|
|
25
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
26
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
27
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
28
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
29
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
30
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
31
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
32
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
33
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
34
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
35
|
+
|
|
36
|
+
Project-URL: Homepage, https://pyiron.org/
|
|
37
|
+
Project-URL: Documentation, https://semantikon.readthedocs.io
|
|
38
|
+
Project-URL: Repository, https://github.com/pyiron/semantikon
|
|
39
|
+
Keywords: pyiron
|
|
40
|
+
Classifier: Development Status :: 3 - Alpha
|
|
41
|
+
Classifier: Topic :: Scientific/Engineering
|
|
42
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
43
|
+
Classifier: Intended Audience :: Science/Research
|
|
44
|
+
Classifier: Operating System :: OS Independent
|
|
45
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
46
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
47
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
48
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
49
|
+
Requires-Python: <3.13,>=3.9
|
|
50
|
+
Description-Content-Type: text/markdown
|
|
51
|
+
License-File: LICENSE
|
|
52
|
+
Requires-Dist: numpy<2.3.0,>=2.2.1
|
|
53
|
+
Requires-Dist: pint==0.24.4
|
|
54
|
+
|
|
55
|
+
# semantikon
|
|
56
|
+
|
|
57
|
+
## Overview
|
|
58
|
+
|
|
59
|
+
In the realm of the workflow management systems, there are well defined inputs and outputs for each node. `semantikon` is a Python package to give scientific context to node inputs and outputs by providing type hinting and interpreters. Therefore, it consists of two **fully** separate parts: type hinting and interpreters.
|
|
60
|
+
|
|
61
|
+
### **Type hinting**
|
|
62
|
+
|
|
63
|
+
`semantikon` provides a way to define types for any number of input parameters and any number of output values for function via type hinting, in particular: data type, unit and ontological type. Type hinting is done with the function `u`, which **requires** the type, and **optionally** you can define the units and the ontological type. The type hinting is done in the following way:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from semantikon.typing import u
|
|
67
|
+
|
|
68
|
+
def my_function(
|
|
69
|
+
distance: u(int, units="meter"),
|
|
70
|
+
time: u(int, units="second")
|
|
71
|
+
) -> u(int, units="meter/second", label="speed"):
|
|
72
|
+
return distance / time
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`semantikon`'s type hinting does not require to follow any particular standard. It only needs to be compatible with the interpreter applied.
|
|
76
|
+
|
|
77
|
+
There are two possible ways to store the data for `semantikon`. The standard way is to do it by converting all arguments except for the data type as a string, which is the default behaviour. The other way is to store the data as a list, which is turned on by setting `use_list=True`. In most cases, the default behaviour is the safest option; in some cases, especially when the data cannot be represented as a string, you might want to switch on `use_list`, but `semantikon` is still under intensive development, and therefore there is no guarantee that you can retrieve the data across different versions correctly.
|
|
78
|
+
|
|
79
|
+
You can also type-hint the inputs and outputs of a function using a class, i.e.:
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from semantikon.typing import u
|
|
84
|
+
from semantikon.convert import semantikon_class
|
|
85
|
+
|
|
86
|
+
@semantikon_class
|
|
87
|
+
class MyRecord:
|
|
88
|
+
distance: u(int, units="meter")
|
|
89
|
+
time: u(int, units="second")
|
|
90
|
+
result: u(int, units="meter/second", label="speed")
|
|
91
|
+
|
|
92
|
+
def my_function(distance: MyRecord.distance, time: MyRecord.time) -> MyRecord.result:
|
|
93
|
+
return distance / time
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
This is equivalent to the previous example. Moreover, if you need to modify some parameters, you can use `u` again, e.g. `u(MyRecord.distance, units="kilometer")`.
|
|
97
|
+
|
|
98
|
+
### **Interpreters**
|
|
99
|
+
|
|
100
|
+
#### General interpreter
|
|
101
|
+
|
|
102
|
+
In order to extract argument information, you can use the functions `parse_input_args` and `parse_output_args`. `parse_input_args` parses the input variables and return a dictionary with the variable names as keys and the variable information as values. `parse_output_args` parses the output variables and return a dictionary with the variable information as values if there is one output variable, or a list of dictionaries if it is a tuple.
|
|
103
|
+
|
|
104
|
+
Example:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from semantikon.typing import u
|
|
108
|
+
from semantikon.converter import parse_input_args, parse_output_args
|
|
109
|
+
|
|
110
|
+
def my_function(
|
|
111
|
+
a: u(int, units="meter"),
|
|
112
|
+
b: u(int, units="second")
|
|
113
|
+
) -> u(int, units="meter/second", label="speed"):
|
|
114
|
+
return a / b
|
|
115
|
+
|
|
116
|
+
print(parse_input_args(my_function))
|
|
117
|
+
print(parse_output_args(my_function))
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Output:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
{'distance': {'units': 'meter', 'label': None, 'uri': None, 'shape': None, 'dtype': <class 'float'>}, 'time': {'units': 'second', 'label': None, 'uri': None, 'shape': None, 'dtype': <class 'float'>}}
|
|
124
|
+
{'units': 'meter/second', 'label': 'speed', 'uri': None, 'shape': None, 'dtype': <class 'float'>}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Here the output is the same whether `use_list` is set to `True` or `False`. When `use_list` is `False`, you can use additionally any tag that you want to store. When `use_list` is `True`, you can store only the data type, `units`, `label`, `uri`, `shape` and `dtype`.
|
|
128
|
+
|
|
129
|
+
Future announcement: There will be no distrinction between `use_list=True` and `use_list=False` when the official support of python 3.10 is dropped (i.e. around autumn 2026).
|
|
130
|
+
|
|
131
|
+
#### Unit conversion with `pint`
|
|
132
|
+
|
|
133
|
+
`semantikon` provides a way to interpret the types of inputs and outputs of a function via a decorator, in order to check consistency of the types and to convert them if necessary. Currently, `semantikon` provides an interpreter for `pint.UnitRegistry` objects. The interpreter is applied in the following way:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from semantikon.typing import u
|
|
137
|
+
from semantikon.converters import units
|
|
138
|
+
from pint import UnitRegistry
|
|
139
|
+
|
|
140
|
+
@units
|
|
141
|
+
def my_function(
|
|
142
|
+
a: u(int, units="meter"),
|
|
143
|
+
b: u(int, units="second")
|
|
144
|
+
) -> u(int, units="meter/second", label="speed"):
|
|
145
|
+
return a / b
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
ureg = UnitRegistry()
|
|
149
|
+
|
|
150
|
+
print(my_function(1 * ureg.meter, 1 * ureg.second))
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Output: `1.0 meter / second`
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
The interpreters check all types and, if necessary, convert them to the expected types **before** the function is executed, in order for all possible errors would be raised before the function execution. The interpreters convert the types in the way that the underlying function would receive the raw values.
|
|
157
|
+
|
|
158
|
+
In case there are multiple outputs, the type hints are to be passed as a tuple (e.g. `tuple[u(int, "meter"), u(int, "second"))`).
|
|
159
|
+
|
|
160
|
+
It is not totally garanteed as a functionality, but relative units as given [on this page](https://pint.readthedocs.io/en/0.10.1/wrapping.html#specifying-relations-between-arguments) can be also used.
|
|
161
|
+
|
|
162
|
+
Interpreters can distinguish between annotated arguments and non-anotated arguments. If the argument is annotated, the interpreter will try to convert the argument to the expected type. If the argument is not annotated, the interpreter will pass the argument as is.
|
|
163
|
+
|
|
164
|
+
Regardless of type hints are given or not, the interpreter acts only when the input values contain units and ontological types. If the input values do not contain units and ontological types, the interpreter will pass the input values to the function as is.
|
|
165
|
+
|
|
166
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.py
|
|
5
|
+
docs/README.md
|
|
6
|
+
semantikon/__init__.py
|
|
7
|
+
semantikon/_version.py
|
|
8
|
+
semantikon/converter.py
|
|
9
|
+
semantikon/typing.py
|
|
10
|
+
semantikon.egg-info/PKG-INFO
|
|
11
|
+
semantikon.egg-info/SOURCES.txt
|
|
12
|
+
semantikon.egg-info/dependency_links.txt
|
|
13
|
+
semantikon.egg-info/requires.txt
|
|
14
|
+
semantikon.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
semantikon
|