mathjson-solver 1.11.0__tar.gz → 1.12.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.
- mathjson_solver-1.12.0/PKG-INFO +83 -0
- mathjson_solver-1.12.0/README.md +59 -0
- {mathjson_solver-1.11.0 → mathjson_solver-1.12.0}/setup.cfg +1 -1
- {mathjson_solver-1.11.0 → mathjson_solver-1.12.0}/setup.py +1 -1
- {mathjson_solver-1.11.0 → mathjson_solver-1.12.0}/src/mathjson_solver/__main__.py +82 -52
- mathjson_solver-1.12.0/src/mathjson_solver.egg-info/PKG-INFO +83 -0
- {mathjson_solver-1.11.0 → mathjson_solver-1.12.0}/tests/test_with_pytest.py +40 -0
- mathjson_solver-1.11.0/PKG-INFO +0 -274
- mathjson_solver-1.11.0/README.md +0 -250
- mathjson_solver-1.11.0/src/mathjson_solver.egg-info/PKG-INFO +0 -274
- {mathjson_solver-1.11.0 → mathjson_solver-1.12.0}/LICENSE +0 -0
- {mathjson_solver-1.11.0 → mathjson_solver-1.12.0}/pyproject.toml +0 -0
- {mathjson_solver-1.11.0 → mathjson_solver-1.12.0}/src/mathjson_solver/__init__.py +0 -0
- {mathjson_solver-1.11.0 → mathjson_solver-1.12.0}/src/mathjson_solver.egg-info/SOURCES.txt +0 -0
- {mathjson_solver-1.11.0 → mathjson_solver-1.12.0}/src/mathjson_solver.egg-info/dependency_links.txt +0 -0
- {mathjson_solver-1.11.0 → mathjson_solver-1.12.0}/src/mathjson_solver.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: mathjson-solver
|
|
3
|
+
Version: 1.12.0
|
|
4
|
+
Summary: Utilities for MathJSON evaluation
|
|
5
|
+
Home-page: https://github.com/LongenesisLtd/mathjson-solver
|
|
6
|
+
Author: Martins Mednis
|
|
7
|
+
Author-email: mrt@mednis.info
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/LongenesisLtd/mathjson-solver/issues
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.6
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Dynamic: author
|
|
16
|
+
Dynamic: author-email
|
|
17
|
+
Dynamic: classifier
|
|
18
|
+
Dynamic: description
|
|
19
|
+
Dynamic: description-content-type
|
|
20
|
+
Dynamic: home-page
|
|
21
|
+
Dynamic: project-url
|
|
22
|
+
Dynamic: requires-python
|
|
23
|
+
Dynamic: summary
|
|
24
|
+
|
|
25
|
+
# MathJSON Solver
|
|
26
|
+
|
|
27
|
+
[](https://pypi.org/project/mathjson-solver/)
|
|
28
|
+
[](https://pepy.tech/projects/mathjson-solver)
|
|
29
|
+

|
|
30
|
+
|
|
31
|
+
_MathJSON Solver_ is a Python module to numerically evaluate MathJSON expressions, like `["Add", 1, 2]`. It is developed by [Longenesis](https://longenesis.com/team) to enable numerical evaluation of user provided mathematical expressions in Longenesis digital health products. Its development was inspired by [CortexJS](https://cortexjs.io/compute-engine/) Compute Engine.
|
|
32
|
+
|
|
33
|
+
Please ask questions and share feedback in our Gitter chat [https://gitter.im/mathjson-solver/community](https://gitter.im/mathjson-solver/community).
|
|
34
|
+
[](https://gitter.im/mathjson-solver/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
|
35
|
+
|
|
36
|
+
## How to use
|
|
37
|
+
```python
|
|
38
|
+
from mathjson_solver import create_solver
|
|
39
|
+
|
|
40
|
+
parameters = {"x": 2, "y": 3}
|
|
41
|
+
expression = ["Add", "x", "y", 4]
|
|
42
|
+
|
|
43
|
+
solver = create_solver(parameters)
|
|
44
|
+
answer = solver(expression)
|
|
45
|
+
|
|
46
|
+
print(answer)
|
|
47
|
+
# 9, because 2+3+4=9
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Currently supported constructs
|
|
51
|
+
Find the full list of supported constructs in the [docs/README.md](https://github.com/LongenesisLtd/mathjson-solver/blob/main/docs/README.md).
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
## Exception handling
|
|
55
|
+
|
|
56
|
+
A `MathJSONException` is raised when expression cannot be evaluated. Import `MathJSONException` to handle it:
|
|
57
|
+
```python
|
|
58
|
+
from mathjson_solver import create_solver, MathJSONException
|
|
59
|
+
|
|
60
|
+
solver = create_solver({})
|
|
61
|
+
try:
|
|
62
|
+
solver(["Divide", 1, 0])
|
|
63
|
+
except MathJSONException:
|
|
64
|
+
pass
|
|
65
|
+
# invoke your own exception logger here
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Left unhandled, the exception will look like `MathJSONException("Problem in Divide. ['Divide', 1, 0]. division by zero")`.
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
## How to run tests
|
|
72
|
+
Make sure you have `pytest` installed. Then `cd` into project directory and run:
|
|
73
|
+
```bash
|
|
74
|
+
pytest
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Contributing Code
|
|
78
|
+
|
|
79
|
+
We welcome your contributions in the form of pull requests.
|
|
80
|
+
|
|
81
|
+
1. Fork the repo;
|
|
82
|
+
2. Make improvements;
|
|
83
|
+
3. Make a pull request to share your improvements with the community and to include it into official release.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# MathJSON Solver
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/mathjson-solver/)
|
|
4
|
+
[](https://pepy.tech/projects/mathjson-solver)
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
_MathJSON Solver_ is a Python module to numerically evaluate MathJSON expressions, like `["Add", 1, 2]`. It is developed by [Longenesis](https://longenesis.com/team) to enable numerical evaluation of user provided mathematical expressions in Longenesis digital health products. Its development was inspired by [CortexJS](https://cortexjs.io/compute-engine/) Compute Engine.
|
|
8
|
+
|
|
9
|
+
Please ask questions and share feedback in our Gitter chat [https://gitter.im/mathjson-solver/community](https://gitter.im/mathjson-solver/community).
|
|
10
|
+
[](https://gitter.im/mathjson-solver/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
|
11
|
+
|
|
12
|
+
## How to use
|
|
13
|
+
```python
|
|
14
|
+
from mathjson_solver import create_solver
|
|
15
|
+
|
|
16
|
+
parameters = {"x": 2, "y": 3}
|
|
17
|
+
expression = ["Add", "x", "y", 4]
|
|
18
|
+
|
|
19
|
+
solver = create_solver(parameters)
|
|
20
|
+
answer = solver(expression)
|
|
21
|
+
|
|
22
|
+
print(answer)
|
|
23
|
+
# 9, because 2+3+4=9
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Currently supported constructs
|
|
27
|
+
Find the full list of supported constructs in the [docs/README.md](https://github.com/LongenesisLtd/mathjson-solver/blob/main/docs/README.md).
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## Exception handling
|
|
31
|
+
|
|
32
|
+
A `MathJSONException` is raised when expression cannot be evaluated. Import `MathJSONException` to handle it:
|
|
33
|
+
```python
|
|
34
|
+
from mathjson_solver import create_solver, MathJSONException
|
|
35
|
+
|
|
36
|
+
solver = create_solver({})
|
|
37
|
+
try:
|
|
38
|
+
solver(["Divide", 1, 0])
|
|
39
|
+
except MathJSONException:
|
|
40
|
+
pass
|
|
41
|
+
# invoke your own exception logger here
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Left unhandled, the exception will look like `MathJSONException("Problem in Divide. ['Divide', 1, 0]. division by zero")`.
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
## How to run tests
|
|
48
|
+
Make sure you have `pytest` installed. Then `cd` into project directory and run:
|
|
49
|
+
```bash
|
|
50
|
+
pytest
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Contributing Code
|
|
54
|
+
|
|
55
|
+
We welcome your contributions in the form of pull requests.
|
|
56
|
+
|
|
57
|
+
1. Fork the repo;
|
|
58
|
+
2. Make improvements;
|
|
59
|
+
3. Make a pull request to share your improvements with the community and to include it into official release.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import numbers
|
|
2
|
+
from types import NoneType
|
|
2
3
|
from typing import Union
|
|
3
4
|
from functools import reduce
|
|
4
5
|
import math
|
|
@@ -26,17 +27,17 @@ class MathJSONException(Exception):
|
|
|
26
27
|
return f"Problem in {self.construct}. {self.expr}. {m}"
|
|
27
28
|
|
|
28
29
|
|
|
29
|
-
def requires_array(func):
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
# def requires_array(func):
|
|
31
|
+
# def inner1(*args, **kwargs):
|
|
32
|
+
# try:
|
|
33
|
+
# if args[0][1][0] == "Array" and len(args[0][1]) > 0:
|
|
34
|
+
# return func(*args, **kwargs)
|
|
35
|
+
# else:
|
|
36
|
+
# raise ValueError(f"'{func.__name__}' should receive a list")
|
|
37
|
+
# except TypeError:
|
|
38
|
+
# raise ValueError(f"'{func.__name__}' really should receive a list")
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
# return inner1
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
def is_numeric(x):
|
|
@@ -92,40 +93,51 @@ def has_matching_sublist(
|
|
|
92
93
|
return count >= required_match_count
|
|
93
94
|
|
|
94
95
|
|
|
95
|
-
def has_sublist2(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
) -> bool:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
96
|
+
# def has_sublist2(
|
|
97
|
+
# *,
|
|
98
|
+
# my_list: list,
|
|
99
|
+
# required_match_count: int,
|
|
100
|
+
# position: int,
|
|
101
|
+
# contiguous: bool,
|
|
102
|
+
# condition: callable,
|
|
103
|
+
# ) -> bool:
|
|
104
|
+
# if contiguous:
|
|
105
|
+
# # Check for contiguous matches based on position
|
|
106
|
+
# if position == 0:
|
|
107
|
+
# # Check if the beginning of the list matches
|
|
108
|
+
# count = sum(1 for x in my_list[:required_match_count] if condition(x))
|
|
109
|
+
# return count == required_match_count
|
|
110
|
+
# elif position > 0:
|
|
111
|
+
# # Skip the first `position` elements
|
|
112
|
+
# count = sum(
|
|
113
|
+
# 1
|
|
114
|
+
# for x in my_list[position : position + required_match_count]
|
|
115
|
+
# if condition(x)
|
|
116
|
+
# )
|
|
117
|
+
# return count == required_match_count
|
|
118
|
+
# elif position == -1:
|
|
119
|
+
# # Check if the end of the list matches
|
|
120
|
+
# count = sum(1 for x in my_list[-required_match_count:] if condition(x))
|
|
121
|
+
# return count == required_match_count
|
|
122
|
+
# elif position < -1:
|
|
123
|
+
# # Skip the last `abs(position)` elements
|
|
124
|
+
# count = sum(1 for x in my_list[:position] if condition(x))
|
|
125
|
+
# return count == required_match_count
|
|
126
|
+
# else:
|
|
127
|
+
# # Check for non-contiguous matches
|
|
128
|
+
# count = sum(1 for x in my_list if condition(x))
|
|
129
|
+
# return count >= required_match_count
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def comparison_safe_converter(x):
|
|
133
|
+
if type(x) in [int, float, str]:
|
|
134
|
+
return f"{x}"
|
|
135
|
+
elif type(x) in [bool, NoneType]:
|
|
136
|
+
if x:
|
|
137
|
+
return True
|
|
138
|
+
else:
|
|
139
|
+
return False
|
|
140
|
+
return x
|
|
129
141
|
|
|
130
142
|
|
|
131
143
|
def create_mathjson_solver(solver_parameters):
|
|
@@ -177,14 +189,12 @@ def create_mathjson_solver(solver_parameters):
|
|
|
177
189
|
l_res.append(res)
|
|
178
190
|
return sum(l_res)
|
|
179
191
|
|
|
180
|
-
# @requires_array
|
|
181
192
|
def Max(s):
|
|
182
193
|
if isinstance(s[1], str):
|
|
183
194
|
return max([f(x, c) for x in f(s[1], c) if is_numeric(f(x, c))])
|
|
184
195
|
else:
|
|
185
196
|
return max([f(x, c) for x in s[1][1:] if is_numeric(f(x, c))])
|
|
186
197
|
|
|
187
|
-
# @requires_array
|
|
188
198
|
def Min(s):
|
|
189
199
|
if isinstance(s[1], str):
|
|
190
200
|
return min([f(x, c) for x in f(s[1], c) if is_numeric(f(x, c))])
|
|
@@ -203,14 +213,12 @@ def create_mathjson_solver(solver_parameters):
|
|
|
203
213
|
except ZeroDivisionError:
|
|
204
214
|
return None
|
|
205
215
|
|
|
206
|
-
# @requires_array
|
|
207
216
|
def Median(s):
|
|
208
217
|
if isinstance(s[1], str):
|
|
209
218
|
return median([f(x, c) for x in f(s[1], c) if is_numeric(f(x, c))])
|
|
210
219
|
else:
|
|
211
220
|
return median([f(x, c) for x in s[1][1:] if is_numeric(f(x, c))])
|
|
212
221
|
|
|
213
|
-
# @requires_array
|
|
214
222
|
def Length(s):
|
|
215
223
|
if isinstance(s[1], str):
|
|
216
224
|
|
|
@@ -218,11 +226,9 @@ def create_mathjson_solver(solver_parameters):
|
|
|
218
226
|
else:
|
|
219
227
|
return len([x for x in s[1][1:]])
|
|
220
228
|
|
|
221
|
-
# @requires_array
|
|
222
229
|
def Any(s):
|
|
223
230
|
return any([f(x, c) for x in s[1][1:]])
|
|
224
231
|
|
|
225
|
-
# @requires_array
|
|
226
232
|
def All(s):
|
|
227
233
|
return all([f(x, c) for x in s[1][1:]])
|
|
228
234
|
|
|
@@ -397,6 +403,26 @@ def create_mathjson_solver(solver_parameters):
|
|
|
397
403
|
def TimeDeltaWeeks(s):
|
|
398
404
|
return datetime.timedelta(weeks=f(s[1], c))
|
|
399
405
|
|
|
406
|
+
# def Equal(s):
|
|
407
|
+
# a = comparison_safe_converter(f(s[1], c))
|
|
408
|
+
# b = comparison_safe_converter(f(s[2], c))
|
|
409
|
+
# return a == b
|
|
410
|
+
# if type(a) in [int, float, str]:
|
|
411
|
+
# a = f"{a}"
|
|
412
|
+
# elif type(a) in [bool, NoneType]:
|
|
413
|
+
# if a:
|
|
414
|
+
# a = True
|
|
415
|
+
# else:
|
|
416
|
+
# a = None
|
|
417
|
+
|
|
418
|
+
# if is_numeric(a):
|
|
419
|
+
|
|
420
|
+
# lambda s: f"{f(s[1], c)}" == f"{f(s[2], c)}",
|
|
421
|
+
|
|
422
|
+
def IsDefined(s):
|
|
423
|
+
# Todo: This does not work
|
|
424
|
+
return s[1] in c.keys()
|
|
425
|
+
|
|
400
426
|
constructs = {
|
|
401
427
|
"Sum": Sum,
|
|
402
428
|
"Add": Add,
|
|
@@ -419,7 +445,10 @@ def create_mathjson_solver(solver_parameters):
|
|
|
419
445
|
"Log": lambda s: math.log(f(s[1], c)),
|
|
420
446
|
"Log2": lambda s: math.log2(f(s[1], c)),
|
|
421
447
|
"Log10": lambda s: math.log10(f(s[1], c)),
|
|
422
|
-
"Equal": lambda s: f(s[1], c) == f(s[2], c),
|
|
448
|
+
# "Equal": lambda s: f"{f(s[1], c)}" == f"{f(s[2], c)}",
|
|
449
|
+
"Equal": lambda s: comparison_safe_converter(f(s[1], c))
|
|
450
|
+
== comparison_safe_converter(f(s[2], c)),
|
|
451
|
+
"StrictEqual": lambda s: f(s[1], c) == f(s[2], c),
|
|
423
452
|
"Greater": lambda s: f(s[1], c) > f(s[2], c),
|
|
424
453
|
"GreaterEqual": lambda s: f(s[1], c) >= f(s[2], c),
|
|
425
454
|
"Less": lambda s: f(s[1], c) < f(s[2], c),
|
|
@@ -452,7 +481,8 @@ def create_mathjson_solver(solver_parameters):
|
|
|
452
481
|
"Float": Float,
|
|
453
482
|
"Str": Str,
|
|
454
483
|
"Not": Not,
|
|
455
|
-
"IsDefined": lambda s: s[1] in c,
|
|
484
|
+
# "IsDefined": lambda s: s[1] in c,
|
|
485
|
+
"IsDefined": IsDefined,
|
|
456
486
|
"Map": Map,
|
|
457
487
|
"HasMatchingSublist": HasMatchingSublist,
|
|
458
488
|
"Strptime": Strptime,
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: mathjson-solver
|
|
3
|
+
Version: 1.12.0
|
|
4
|
+
Summary: Utilities for MathJSON evaluation
|
|
5
|
+
Home-page: https://github.com/LongenesisLtd/mathjson-solver
|
|
6
|
+
Author: Martins Mednis
|
|
7
|
+
Author-email: mrt@mednis.info
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/LongenesisLtd/mathjson-solver/issues
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.6
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Dynamic: author
|
|
16
|
+
Dynamic: author-email
|
|
17
|
+
Dynamic: classifier
|
|
18
|
+
Dynamic: description
|
|
19
|
+
Dynamic: description-content-type
|
|
20
|
+
Dynamic: home-page
|
|
21
|
+
Dynamic: project-url
|
|
22
|
+
Dynamic: requires-python
|
|
23
|
+
Dynamic: summary
|
|
24
|
+
|
|
25
|
+
# MathJSON Solver
|
|
26
|
+
|
|
27
|
+
[](https://pypi.org/project/mathjson-solver/)
|
|
28
|
+
[](https://pepy.tech/projects/mathjson-solver)
|
|
29
|
+

|
|
30
|
+
|
|
31
|
+
_MathJSON Solver_ is a Python module to numerically evaluate MathJSON expressions, like `["Add", 1, 2]`. It is developed by [Longenesis](https://longenesis.com/team) to enable numerical evaluation of user provided mathematical expressions in Longenesis digital health products. Its development was inspired by [CortexJS](https://cortexjs.io/compute-engine/) Compute Engine.
|
|
32
|
+
|
|
33
|
+
Please ask questions and share feedback in our Gitter chat [https://gitter.im/mathjson-solver/community](https://gitter.im/mathjson-solver/community).
|
|
34
|
+
[](https://gitter.im/mathjson-solver/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
|
35
|
+
|
|
36
|
+
## How to use
|
|
37
|
+
```python
|
|
38
|
+
from mathjson_solver import create_solver
|
|
39
|
+
|
|
40
|
+
parameters = {"x": 2, "y": 3}
|
|
41
|
+
expression = ["Add", "x", "y", 4]
|
|
42
|
+
|
|
43
|
+
solver = create_solver(parameters)
|
|
44
|
+
answer = solver(expression)
|
|
45
|
+
|
|
46
|
+
print(answer)
|
|
47
|
+
# 9, because 2+3+4=9
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Currently supported constructs
|
|
51
|
+
Find the full list of supported constructs in the [docs/README.md](https://github.com/LongenesisLtd/mathjson-solver/blob/main/docs/README.md).
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
## Exception handling
|
|
55
|
+
|
|
56
|
+
A `MathJSONException` is raised when expression cannot be evaluated. Import `MathJSONException` to handle it:
|
|
57
|
+
```python
|
|
58
|
+
from mathjson_solver import create_solver, MathJSONException
|
|
59
|
+
|
|
60
|
+
solver = create_solver({})
|
|
61
|
+
try:
|
|
62
|
+
solver(["Divide", 1, 0])
|
|
63
|
+
except MathJSONException:
|
|
64
|
+
pass
|
|
65
|
+
# invoke your own exception logger here
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Left unhandled, the exception will look like `MathJSONException("Problem in Divide. ['Divide', 1, 0]. division by zero")`.
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
## How to run tests
|
|
72
|
+
Make sure you have `pytest` installed. Then `cd` into project directory and run:
|
|
73
|
+
```bash
|
|
74
|
+
pytest
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Contributing Code
|
|
78
|
+
|
|
79
|
+
We welcome your contributions in the form of pull requests.
|
|
80
|
+
|
|
81
|
+
1. Fork the repo;
|
|
82
|
+
2. Make improvements;
|
|
83
|
+
3. Make a pull request to share your improvements with the community and to include it into official release.
|
|
@@ -16,6 +16,7 @@ from mathjson_solver import create_solver, MathJSONException, extract_variables
|
|
|
16
16
|
({}, ["Sum", ["Array", 1, 1], 4, 3], 9),
|
|
17
17
|
({}, ["Sum", ["Array", 2, 4, 3]], 9),
|
|
18
18
|
({"a": 2}, ["Sum", "a", 4, 3], 9),
|
|
19
|
+
({"a": ["Array", 1, 1]}, ["Sum", "a"], 2),
|
|
19
20
|
({"a": ["Array", 1, 1]}, ["Sum", "a", 4, 3], 9),
|
|
20
21
|
({}, ["Subtract", 10, 5, 2], 3),
|
|
21
22
|
({}, ["Add", 5, 4, ["Negate", 3]], 6),
|
|
@@ -36,6 +37,38 @@ from mathjson_solver import create_solver, MathJSONException, extract_variables
|
|
|
36
37
|
({}, ["Equal", 10, 12], False),
|
|
37
38
|
({}, ["Equal", "aaa", "aaa"], True),
|
|
38
39
|
({}, ["Equal", "aaa", "baa"], False),
|
|
40
|
+
({}, ["Equal", "aaa", 11], False),
|
|
41
|
+
({}, ["Equal", None, "1"], False),
|
|
42
|
+
({}, ["Equal", 1, "1"], True),
|
|
43
|
+
({}, ["Equal", None, False], True),
|
|
44
|
+
|
|
45
|
+
({}, ["StrictEqual", 1, "1"], False),
|
|
46
|
+
({}, ["StrictEqual", 10, 10], True),
|
|
47
|
+
({}, ["StrictEqual", 10, 12], False),
|
|
48
|
+
({}, ["StrictEqual", "aaa", "aaa"], True),
|
|
49
|
+
({}, ["StrictEqual", "aaa", "baa"], False),
|
|
50
|
+
({}, ["StrictEqual", "aaa", 11], False),
|
|
51
|
+
({}, ["StrictEqual", None, "1"], False),
|
|
52
|
+
({}, ["Equal", None, False], True),
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
({}, ["Greater", 1, 2], False),
|
|
56
|
+
({}, ["Greater", 2, -2], True),
|
|
57
|
+
({}, ["GreaterEqual", 1, 1], True),
|
|
58
|
+
({}, ["GreaterEqual", 2, 1], True),
|
|
59
|
+
({}, ["GreaterEqual", 0, 0], True),
|
|
60
|
+
({}, ["GreaterEqual", 1, 2], False),
|
|
61
|
+
({}, ["Less", 1, 1], False),
|
|
62
|
+
({}, ["Less", 1, 2], True),
|
|
63
|
+
({}, ["LessEqual", 1, 1], True),
|
|
64
|
+
({}, ["LessEqual", 1, 2], True),
|
|
65
|
+
# NotEqual
|
|
66
|
+
({}, ["NotEqual", 1, 1], False),
|
|
67
|
+
({}, ["NotEqual", 1, 2], True),
|
|
68
|
+
({}, ["NotEqual", "aaa", "bbb"], True),
|
|
69
|
+
({}, ["NotEqual", "aaa", 0], True),
|
|
70
|
+
# ({"a": 12}, ["IsDefined", "a"], True),
|
|
71
|
+
({"a": 12}, ["IsDefined", "b"], False),
|
|
39
72
|
({}, ["Abs", -3.5], 3.5),
|
|
40
73
|
({}, ["Round", -5.123456, 2], -5.12),
|
|
41
74
|
({}, ["Round", -5.123456, 0], -5),
|
|
@@ -103,6 +136,12 @@ from mathjson_solver import create_solver, MathJSONException, extract_variables
|
|
|
103
136
|
({"color": "green"}, ["Switch", "color", 0, ["blue", 10], ["red", 30]], 0),
|
|
104
137
|
({"color": "green"}, ["Switch", "undefined", 0, ["blue", 10], ["red", 30]], 0),
|
|
105
138
|
({}, ["If", [["Equal", 1, 0], 10], [["Equal", 2, 2], 20], 9000], 20),
|
|
139
|
+
# # The following tests that If don't fail on incompatible data types
|
|
140
|
+
# ({}, ["If", [["Equal", 1, "1"], 10], [["Equal", "1", "1"], 20], -1], 20),
|
|
141
|
+
|
|
142
|
+
# ({"a": 1}, ["If", [["Equal", "a", "1"], 10], [["Equal", "a", 1], 20], -1], 20),
|
|
143
|
+
# ({"a": 1}, ["If", [["Equal", "a", 1], 10], [["Equal", "a", "1"], 20], -1], 10),
|
|
144
|
+
|
|
106
145
|
({"a": 10, "b": 10}, ["If", [["Equal", "a", "b"], 10], 9000], 10),
|
|
107
146
|
({"a": 10, "b": 20}, ["If", [["Equal", "a", "b"], 10], 9000], 9000),
|
|
108
147
|
({"a": 10}, ["If", [["Equal", "a", "b"], 10], 9000], 9000),
|
|
@@ -116,6 +155,7 @@ from mathjson_solver import create_solver, MathJSONException, extract_variables
|
|
|
116
155
|
({"a": ["Array", 2, 1, 3, 5, 2]}, ["Min", "a"], 1),
|
|
117
156
|
({}, ["Median", ["Array", 1, 2, 3, 5, 2]], 2),
|
|
118
157
|
({"a": ["Array", 1, 2, 3, 5, 2]}, ["Median", "a"], 2),
|
|
158
|
+
({}, ["Average", ["Array", 2, "three", 4, "6"]], 4),
|
|
119
159
|
({}, ["Average", ["Array", 1, 2, 3, 5, 2]], 2.6),
|
|
120
160
|
(
|
|
121
161
|
{},
|
mathjson_solver-1.11.0/PKG-INFO
DELETED
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.2
|
|
2
|
-
Name: mathjson-solver
|
|
3
|
-
Version: 1.11.0
|
|
4
|
-
Summary: Utilities for MathJSON evaluation
|
|
5
|
-
Home-page: https://github.com/LongenesisLtd/mathjson-solver
|
|
6
|
-
Author: Martins Mednis
|
|
7
|
-
Author-email: mrt@mednis.info
|
|
8
|
-
Project-URL: Bug Tracker, https://github.com/LongenesisLtd/mathjson-solver/issues
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.6
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Dynamic: author
|
|
16
|
-
Dynamic: author-email
|
|
17
|
-
Dynamic: classifier
|
|
18
|
-
Dynamic: description
|
|
19
|
-
Dynamic: description-content-type
|
|
20
|
-
Dynamic: home-page
|
|
21
|
-
Dynamic: project-url
|
|
22
|
-
Dynamic: requires-python
|
|
23
|
-
Dynamic: summary
|
|
24
|
-
|
|
25
|
-
# MathJSON Solver
|
|
26
|
-
|
|
27
|
-
[](https://gitter.im/mathjson-solver/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
|
28
|
-
|
|
29
|
-
_MathJSON Solver_ is a Python module to numerically evaluate MathJSON expressions. It was created by [Longenesis](https://longenesis.com/team) to add numerical evaluation capability of user generated mathematical expressions in Longenesis digital health products and later released as open source project. Its development was inspired by [CortexJS](https://cortexjs.io/compute-engine/) Compute Engine.
|
|
30
|
-
|
|
31
|
-
Please ask questions and share feedback in our Gitter chat [https://gitter.im/mathjson-solver/community](https://gitter.im/mathjson-solver/community).
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
## How to use
|
|
35
|
-
```python
|
|
36
|
-
from mathjson_solver import create_solver
|
|
37
|
-
|
|
38
|
-
parameters = {"x": 2, "y": 3}
|
|
39
|
-
expression = ["Add", "x", "y", 4]
|
|
40
|
-
|
|
41
|
-
solver = create_solver(parameters)
|
|
42
|
-
answer = solver(expression)
|
|
43
|
-
|
|
44
|
-
print(answer)
|
|
45
|
-
# 9, because 2+3+4=9
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Currently supported constructs
|
|
49
|
-
* `Add` - Iteratively adds up the given values. Compatible with time delta.
|
|
50
|
-
* `Sum` - Internally uses python's `sum`. Not compatible with time delta.
|
|
51
|
-
* `Subtract` -
|
|
52
|
-
* `Constants` -
|
|
53
|
-
* `Switch` -
|
|
54
|
-
* `If` -
|
|
55
|
-
* `Multiply` -
|
|
56
|
-
* `Divide` -
|
|
57
|
-
* `Negate` -
|
|
58
|
-
* `Power` -
|
|
59
|
-
* `Root` -
|
|
60
|
-
* `Sqrt` -
|
|
61
|
-
* `Square` -
|
|
62
|
-
* `Exp` -
|
|
63
|
-
* `Log` -
|
|
64
|
-
* `Log2` -
|
|
65
|
-
* `Log10` -
|
|
66
|
-
* `Equal` -
|
|
67
|
-
* `Greater` -
|
|
68
|
-
* `GreaterEqual` -
|
|
69
|
-
* `Less` -
|
|
70
|
-
* `LessEqual` -
|
|
71
|
-
* `NotEqual` -
|
|
72
|
-
* `Abs` -
|
|
73
|
-
* `Round` -
|
|
74
|
-
* `Max` -
|
|
75
|
-
* `Min` -
|
|
76
|
-
* `Average` - Internally tries to convert strings to numbers, making calculation of average from `[2, 4 ,"6"]` actually possible. Also, it ignores un-convertible elements so arrays like `[2, "three", 4 ,"6"]` don't crash the solver.
|
|
77
|
-
* `Median` -
|
|
78
|
-
* `Length` -
|
|
79
|
-
* `Any` -
|
|
80
|
-
* `All` -
|
|
81
|
-
* `Array` -
|
|
82
|
-
* `In` -
|
|
83
|
-
* `Not_in` -
|
|
84
|
-
* `Contains_any_of` -
|
|
85
|
-
* `Contains_all_of` -
|
|
86
|
-
* `Contains_none_of` -
|
|
87
|
-
* `NotIn` -
|
|
88
|
-
* `ContainsAnyOf` -
|
|
89
|
-
* `ContainsAllOf` -
|
|
90
|
-
* `ContainsNoneOf` -
|
|
91
|
-
* `Int` -
|
|
92
|
-
* `Float` -
|
|
93
|
-
* `Str` -
|
|
94
|
-
* `Not` -
|
|
95
|
-
* `IsDefined` - Checks if a value is in parameters.
|
|
96
|
-
* `Map` -
|
|
97
|
-
* `HasMatchingSublist` -
|
|
98
|
-
* `Strptime` -
|
|
99
|
-
* `Strftime` -
|
|
100
|
-
* `Today` -
|
|
101
|
-
* `Now` -
|
|
102
|
-
* `TimeDeltaWeeks` -
|
|
103
|
-
* `TimeDeltaHours` -
|
|
104
|
-
* `TimeDeltaMinutes` -
|
|
105
|
-
* `TimeDeltaDays` -
|
|
106
|
-
|
|
107
|
-
## Examples
|
|
108
|
-
```python
|
|
109
|
-
["Add", 2, 4, 3] # 2+4+3=9
|
|
110
|
-
["Subtract", 10, 5, 2] # 10-5-2=3
|
|
111
|
-
["Add", 5, 4, ["Negate", 3]] # 5+4+(-3)=6
|
|
112
|
-
["Multiply", 2, 3, 4] # 2*3*4=24
|
|
113
|
-
["Divide", 10, 5] # 10/5=2.0
|
|
114
|
-
["Divide", 10, 4] # 10/4=2.5
|
|
115
|
-
["Power", 2, 3] # 2^3=8
|
|
116
|
-
["Root", 9, 2] # √9=3.0
|
|
117
|
-
["Root", 8, 3] # ∛8=2.0
|
|
118
|
-
["Sqrt", 9] # √9=3.0
|
|
119
|
-
["Square", 4] # 4^2=16
|
|
120
|
-
["Exp", 2] # e^2≅7.389
|
|
121
|
-
["Divide", 10, ["Add", 2+3]] # 10/(2+3)=10/5=2
|
|
122
|
-
["Log", 2.7183] # ln(2.7183)≅1.0000
|
|
123
|
-
["Log2", 8] # log2(8)=3.0
|
|
124
|
-
["Log10", 1000] # log10(1000)=3.0
|
|
125
|
-
["Equal", 10, 10] # 10==10 = True
|
|
126
|
-
["Equal", 10, 12] # 10==12 = False
|
|
127
|
-
["Abs", -3.5] # |-3.5| = 3.5
|
|
128
|
-
["Round", -5.123456, 2] # -5.12
|
|
129
|
-
["Round", -5.123456, 0] # -5.0
|
|
130
|
-
["Round", -5.123456] # -5
|
|
131
|
-
["Array", 1, 2] # ["Array", 1, 2]
|
|
132
|
-
|
|
133
|
-
["Max", ["Array", 1, 2, 3, 5, 2]] # 5
|
|
134
|
-
["Max", ["Array", 1, 2, ["Sum", 2, 4, 3], 5, 2]] # 9
|
|
135
|
-
["Median", ["Array", 1, 2, 3, 5, 2]] # 2
|
|
136
|
-
["Average", ["Array", 1, 2, 3, 5, 2]] # 2.6
|
|
137
|
-
["Average", ["Array"]] # None
|
|
138
|
-
|
|
139
|
-
["Length", ["Array", 1, 2, 3, 5, 2, 9]] # 6
|
|
140
|
-
["Length", ["Array"]] # 0
|
|
141
|
-
["Any", ["Array", 0, 0, False, 0, 0]] # False
|
|
142
|
-
["Any", ["Array", 0, 1, False, 0, 0]] # True
|
|
143
|
-
["All", ["Array", 0, 1, False, 0, 0]] # False
|
|
144
|
-
["All", ["Array", 0, 1, False, "", 0]] # False
|
|
145
|
-
["All", ["Array", 2, 1, True, "zz", 2]] # True
|
|
146
|
-
["Int", "12"] # 12
|
|
147
|
-
["Int", "12.2"] # 12
|
|
148
|
-
["Float", "12.2"] # 12.2
|
|
149
|
-
["Str", 12] # "12"
|
|
150
|
-
["Str", "12"] # "12"
|
|
151
|
-
["Str", "aabb"] # "aabb"
|
|
152
|
-
["Not", True] # False
|
|
153
|
-
["Not", 0] # True
|
|
154
|
-
|
|
155
|
-
["In", 2, ["Array", 1, 2, 3]] # True
|
|
156
|
-
["In", 4, ["Array", 1, 2, 3]] # False
|
|
157
|
-
["ContainsAnyOf", ["Array", 1, 2, 3], ["Array", 3, 4, 5, 6]] # True
|
|
158
|
-
["ContainsAnyOf", ["Array", 1, 2, 3], ["Array", 4, 5, 6]] # False
|
|
159
|
-
["ContainsAllOf", ["Array", 1, 2, 3], ["Array", 1, 2, 3]] # True
|
|
160
|
-
["ContainsAllOf", ["Array", 1, 2], ["Array", 1, 2, 3]] # False
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### Constants
|
|
164
|
-
```
|
|
165
|
-
[
|
|
166
|
-
"Constants",
|
|
167
|
-
["constant_name1", <expression>],
|
|
168
|
-
["constant_name2", <expression>],
|
|
169
|
-
["constant_name3", <expression>],
|
|
170
|
-
...,
|
|
171
|
-
<expression>
|
|
172
|
-
]
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
`Constants` construct consists of keyword "Constants" followed by arbitrary number of name&value pairs. The last element in `Constants` construct is the expression to calculate using the defined constants.
|
|
176
|
-
|
|
177
|
-
The following example has two constants defined - `x=10` and `y=20`. Then the sum of these two constants is calculated and returned.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
```python
|
|
181
|
-
[
|
|
182
|
-
"Constants",
|
|
183
|
-
["x", 10],
|
|
184
|
-
["y", 20],
|
|
185
|
-
["Add","x", "y"]
|
|
186
|
-
]
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
### If statement
|
|
191
|
-
```
|
|
192
|
-
[
|
|
193
|
-
"If",
|
|
194
|
-
[
|
|
195
|
-
<true-or-false-expression>,
|
|
196
|
-
<expression-to-calculate>
|
|
197
|
-
],
|
|
198
|
-
[
|
|
199
|
-
<elseif-true-or-false-expression>,
|
|
200
|
-
<expression-to-calculate>
|
|
201
|
-
],
|
|
202
|
-
...,
|
|
203
|
-
<else-expression-to-calculate>
|
|
204
|
-
]
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
Example
|
|
208
|
-
```python
|
|
209
|
-
[
|
|
210
|
-
"If",
|
|
211
|
-
[
|
|
212
|
-
["Equal", 1, 0],
|
|
213
|
-
10
|
|
214
|
-
],
|
|
215
|
-
[
|
|
216
|
-
["Equal", 2, 2],
|
|
217
|
-
20
|
|
218
|
-
],
|
|
219
|
-
9000
|
|
220
|
-
]
|
|
221
|
-
```
|
|
222
|
-
This construct translates to:
|
|
223
|
-
```
|
|
224
|
-
if 1 == 0 then 10
|
|
225
|
-
elif 2 == 2 then 20
|
|
226
|
-
else 9000
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
`If` expressions do not need to be strictly _boolean_. Any value that is not _false_ are considered _true_.
|
|
230
|
-
|
|
231
|
-
### Switch-Case statement
|
|
232
|
-
```
|
|
233
|
-
["Switch", <on-expression>, <default-result-expression>, [<case1-expression>, <result-expression>], ...],
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
`Switch` construct consists of keyword "Switch" followed by expression whose value will be compared to _Cases'_ values. Then comes the default value. Then follows arbitrary number of _Cases_.
|
|
237
|
-
|
|
238
|
-
Example
|
|
239
|
-
```python
|
|
240
|
-
["Switch", "color", 100, ["red", 10], ["blue", 20], ["green", 30]],
|
|
241
|
-
```
|
|
242
|
-
The expression in this example will make solver to look for a constant (or a parameter) with the name "color". If "color" is "red", expression evaluates to 10, if "blue" - to 20, if "green" - to 30. Otherwise to 100. Please note that "color" here is a valid expression that evaluates to the actual value of "color" whether it is a parameter or constant.
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
## Exception handling
|
|
246
|
-
|
|
247
|
-
A `MathJSONException` is raised when expression cannot be evaluated. Import `MathJSONException` to handle it:
|
|
248
|
-
```python
|
|
249
|
-
from mathjson_solver import create_solver, MathJSONException
|
|
250
|
-
|
|
251
|
-
solver = create_solver({})
|
|
252
|
-
try:
|
|
253
|
-
solver(["Divide", 1, 0])
|
|
254
|
-
except MathJSONException:
|
|
255
|
-
pass
|
|
256
|
-
# invoke your own exception logger here
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
Left unhandled, the exception will look like `MathJSONException("Problem in Divide. ['Divide', 1, 0]. division by zero")`.
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
## How to run tests
|
|
263
|
-
Make sure you have `pytest` installed. Then `cd` into project directory and run:
|
|
264
|
-
```bash
|
|
265
|
-
pytest
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
## Contributing Code
|
|
269
|
-
|
|
270
|
-
We welcome your contributions in the form of pull requests.
|
|
271
|
-
|
|
272
|
-
1. Fork the repo;
|
|
273
|
-
2. Make improvements;
|
|
274
|
-
3. Make a pull request to share your improvements with the community and to include it into official release.
|
mathjson_solver-1.11.0/README.md
DELETED
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
# MathJSON Solver
|
|
2
|
-
|
|
3
|
-
[](https://gitter.im/mathjson-solver/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
|
4
|
-
|
|
5
|
-
_MathJSON Solver_ is a Python module to numerically evaluate MathJSON expressions. It was created by [Longenesis](https://longenesis.com/team) to add numerical evaluation capability of user generated mathematical expressions in Longenesis digital health products and later released as open source project. Its development was inspired by [CortexJS](https://cortexjs.io/compute-engine/) Compute Engine.
|
|
6
|
-
|
|
7
|
-
Please ask questions and share feedback in our Gitter chat [https://gitter.im/mathjson-solver/community](https://gitter.im/mathjson-solver/community).
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
## How to use
|
|
11
|
-
```python
|
|
12
|
-
from mathjson_solver import create_solver
|
|
13
|
-
|
|
14
|
-
parameters = {"x": 2, "y": 3}
|
|
15
|
-
expression = ["Add", "x", "y", 4]
|
|
16
|
-
|
|
17
|
-
solver = create_solver(parameters)
|
|
18
|
-
answer = solver(expression)
|
|
19
|
-
|
|
20
|
-
print(answer)
|
|
21
|
-
# 9, because 2+3+4=9
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Currently supported constructs
|
|
25
|
-
* `Add` - Iteratively adds up the given values. Compatible with time delta.
|
|
26
|
-
* `Sum` - Internally uses python's `sum`. Not compatible with time delta.
|
|
27
|
-
* `Subtract` -
|
|
28
|
-
* `Constants` -
|
|
29
|
-
* `Switch` -
|
|
30
|
-
* `If` -
|
|
31
|
-
* `Multiply` -
|
|
32
|
-
* `Divide` -
|
|
33
|
-
* `Negate` -
|
|
34
|
-
* `Power` -
|
|
35
|
-
* `Root` -
|
|
36
|
-
* `Sqrt` -
|
|
37
|
-
* `Square` -
|
|
38
|
-
* `Exp` -
|
|
39
|
-
* `Log` -
|
|
40
|
-
* `Log2` -
|
|
41
|
-
* `Log10` -
|
|
42
|
-
* `Equal` -
|
|
43
|
-
* `Greater` -
|
|
44
|
-
* `GreaterEqual` -
|
|
45
|
-
* `Less` -
|
|
46
|
-
* `LessEqual` -
|
|
47
|
-
* `NotEqual` -
|
|
48
|
-
* `Abs` -
|
|
49
|
-
* `Round` -
|
|
50
|
-
* `Max` -
|
|
51
|
-
* `Min` -
|
|
52
|
-
* `Average` - Internally tries to convert strings to numbers, making calculation of average from `[2, 4 ,"6"]` actually possible. Also, it ignores un-convertible elements so arrays like `[2, "three", 4 ,"6"]` don't crash the solver.
|
|
53
|
-
* `Median` -
|
|
54
|
-
* `Length` -
|
|
55
|
-
* `Any` -
|
|
56
|
-
* `All` -
|
|
57
|
-
* `Array` -
|
|
58
|
-
* `In` -
|
|
59
|
-
* `Not_in` -
|
|
60
|
-
* `Contains_any_of` -
|
|
61
|
-
* `Contains_all_of` -
|
|
62
|
-
* `Contains_none_of` -
|
|
63
|
-
* `NotIn` -
|
|
64
|
-
* `ContainsAnyOf` -
|
|
65
|
-
* `ContainsAllOf` -
|
|
66
|
-
* `ContainsNoneOf` -
|
|
67
|
-
* `Int` -
|
|
68
|
-
* `Float` -
|
|
69
|
-
* `Str` -
|
|
70
|
-
* `Not` -
|
|
71
|
-
* `IsDefined` - Checks if a value is in parameters.
|
|
72
|
-
* `Map` -
|
|
73
|
-
* `HasMatchingSublist` -
|
|
74
|
-
* `Strptime` -
|
|
75
|
-
* `Strftime` -
|
|
76
|
-
* `Today` -
|
|
77
|
-
* `Now` -
|
|
78
|
-
* `TimeDeltaWeeks` -
|
|
79
|
-
* `TimeDeltaHours` -
|
|
80
|
-
* `TimeDeltaMinutes` -
|
|
81
|
-
* `TimeDeltaDays` -
|
|
82
|
-
|
|
83
|
-
## Examples
|
|
84
|
-
```python
|
|
85
|
-
["Add", 2, 4, 3] # 2+4+3=9
|
|
86
|
-
["Subtract", 10, 5, 2] # 10-5-2=3
|
|
87
|
-
["Add", 5, 4, ["Negate", 3]] # 5+4+(-3)=6
|
|
88
|
-
["Multiply", 2, 3, 4] # 2*3*4=24
|
|
89
|
-
["Divide", 10, 5] # 10/5=2.0
|
|
90
|
-
["Divide", 10, 4] # 10/4=2.5
|
|
91
|
-
["Power", 2, 3] # 2^3=8
|
|
92
|
-
["Root", 9, 2] # √9=3.0
|
|
93
|
-
["Root", 8, 3] # ∛8=2.0
|
|
94
|
-
["Sqrt", 9] # √9=3.0
|
|
95
|
-
["Square", 4] # 4^2=16
|
|
96
|
-
["Exp", 2] # e^2≅7.389
|
|
97
|
-
["Divide", 10, ["Add", 2+3]] # 10/(2+3)=10/5=2
|
|
98
|
-
["Log", 2.7183] # ln(2.7183)≅1.0000
|
|
99
|
-
["Log2", 8] # log2(8)=3.0
|
|
100
|
-
["Log10", 1000] # log10(1000)=3.0
|
|
101
|
-
["Equal", 10, 10] # 10==10 = True
|
|
102
|
-
["Equal", 10, 12] # 10==12 = False
|
|
103
|
-
["Abs", -3.5] # |-3.5| = 3.5
|
|
104
|
-
["Round", -5.123456, 2] # -5.12
|
|
105
|
-
["Round", -5.123456, 0] # -5.0
|
|
106
|
-
["Round", -5.123456] # -5
|
|
107
|
-
["Array", 1, 2] # ["Array", 1, 2]
|
|
108
|
-
|
|
109
|
-
["Max", ["Array", 1, 2, 3, 5, 2]] # 5
|
|
110
|
-
["Max", ["Array", 1, 2, ["Sum", 2, 4, 3], 5, 2]] # 9
|
|
111
|
-
["Median", ["Array", 1, 2, 3, 5, 2]] # 2
|
|
112
|
-
["Average", ["Array", 1, 2, 3, 5, 2]] # 2.6
|
|
113
|
-
["Average", ["Array"]] # None
|
|
114
|
-
|
|
115
|
-
["Length", ["Array", 1, 2, 3, 5, 2, 9]] # 6
|
|
116
|
-
["Length", ["Array"]] # 0
|
|
117
|
-
["Any", ["Array", 0, 0, False, 0, 0]] # False
|
|
118
|
-
["Any", ["Array", 0, 1, False, 0, 0]] # True
|
|
119
|
-
["All", ["Array", 0, 1, False, 0, 0]] # False
|
|
120
|
-
["All", ["Array", 0, 1, False, "", 0]] # False
|
|
121
|
-
["All", ["Array", 2, 1, True, "zz", 2]] # True
|
|
122
|
-
["Int", "12"] # 12
|
|
123
|
-
["Int", "12.2"] # 12
|
|
124
|
-
["Float", "12.2"] # 12.2
|
|
125
|
-
["Str", 12] # "12"
|
|
126
|
-
["Str", "12"] # "12"
|
|
127
|
-
["Str", "aabb"] # "aabb"
|
|
128
|
-
["Not", True] # False
|
|
129
|
-
["Not", 0] # True
|
|
130
|
-
|
|
131
|
-
["In", 2, ["Array", 1, 2, 3]] # True
|
|
132
|
-
["In", 4, ["Array", 1, 2, 3]] # False
|
|
133
|
-
["ContainsAnyOf", ["Array", 1, 2, 3], ["Array", 3, 4, 5, 6]] # True
|
|
134
|
-
["ContainsAnyOf", ["Array", 1, 2, 3], ["Array", 4, 5, 6]] # False
|
|
135
|
-
["ContainsAllOf", ["Array", 1, 2, 3], ["Array", 1, 2, 3]] # True
|
|
136
|
-
["ContainsAllOf", ["Array", 1, 2], ["Array", 1, 2, 3]] # False
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### Constants
|
|
140
|
-
```
|
|
141
|
-
[
|
|
142
|
-
"Constants",
|
|
143
|
-
["constant_name1", <expression>],
|
|
144
|
-
["constant_name2", <expression>],
|
|
145
|
-
["constant_name3", <expression>],
|
|
146
|
-
...,
|
|
147
|
-
<expression>
|
|
148
|
-
]
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
`Constants` construct consists of keyword "Constants" followed by arbitrary number of name&value pairs. The last element in `Constants` construct is the expression to calculate using the defined constants.
|
|
152
|
-
|
|
153
|
-
The following example has two constants defined - `x=10` and `y=20`. Then the sum of these two constants is calculated and returned.
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
```python
|
|
157
|
-
[
|
|
158
|
-
"Constants",
|
|
159
|
-
["x", 10],
|
|
160
|
-
["y", 20],
|
|
161
|
-
["Add","x", "y"]
|
|
162
|
-
]
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
### If statement
|
|
167
|
-
```
|
|
168
|
-
[
|
|
169
|
-
"If",
|
|
170
|
-
[
|
|
171
|
-
<true-or-false-expression>,
|
|
172
|
-
<expression-to-calculate>
|
|
173
|
-
],
|
|
174
|
-
[
|
|
175
|
-
<elseif-true-or-false-expression>,
|
|
176
|
-
<expression-to-calculate>
|
|
177
|
-
],
|
|
178
|
-
...,
|
|
179
|
-
<else-expression-to-calculate>
|
|
180
|
-
]
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
Example
|
|
184
|
-
```python
|
|
185
|
-
[
|
|
186
|
-
"If",
|
|
187
|
-
[
|
|
188
|
-
["Equal", 1, 0],
|
|
189
|
-
10
|
|
190
|
-
],
|
|
191
|
-
[
|
|
192
|
-
["Equal", 2, 2],
|
|
193
|
-
20
|
|
194
|
-
],
|
|
195
|
-
9000
|
|
196
|
-
]
|
|
197
|
-
```
|
|
198
|
-
This construct translates to:
|
|
199
|
-
```
|
|
200
|
-
if 1 == 0 then 10
|
|
201
|
-
elif 2 == 2 then 20
|
|
202
|
-
else 9000
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
`If` expressions do not need to be strictly _boolean_. Any value that is not _false_ are considered _true_.
|
|
206
|
-
|
|
207
|
-
### Switch-Case statement
|
|
208
|
-
```
|
|
209
|
-
["Switch", <on-expression>, <default-result-expression>, [<case1-expression>, <result-expression>], ...],
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
`Switch` construct consists of keyword "Switch" followed by expression whose value will be compared to _Cases'_ values. Then comes the default value. Then follows arbitrary number of _Cases_.
|
|
213
|
-
|
|
214
|
-
Example
|
|
215
|
-
```python
|
|
216
|
-
["Switch", "color", 100, ["red", 10], ["blue", 20], ["green", 30]],
|
|
217
|
-
```
|
|
218
|
-
The expression in this example will make solver to look for a constant (or a parameter) with the name "color". If "color" is "red", expression evaluates to 10, if "blue" - to 20, if "green" - to 30. Otherwise to 100. Please note that "color" here is a valid expression that evaluates to the actual value of "color" whether it is a parameter or constant.
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
## Exception handling
|
|
222
|
-
|
|
223
|
-
A `MathJSONException` is raised when expression cannot be evaluated. Import `MathJSONException` to handle it:
|
|
224
|
-
```python
|
|
225
|
-
from mathjson_solver import create_solver, MathJSONException
|
|
226
|
-
|
|
227
|
-
solver = create_solver({})
|
|
228
|
-
try:
|
|
229
|
-
solver(["Divide", 1, 0])
|
|
230
|
-
except MathJSONException:
|
|
231
|
-
pass
|
|
232
|
-
# invoke your own exception logger here
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
Left unhandled, the exception will look like `MathJSONException("Problem in Divide. ['Divide', 1, 0]. division by zero")`.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
## How to run tests
|
|
239
|
-
Make sure you have `pytest` installed. Then `cd` into project directory and run:
|
|
240
|
-
```bash
|
|
241
|
-
pytest
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
## Contributing Code
|
|
245
|
-
|
|
246
|
-
We welcome your contributions in the form of pull requests.
|
|
247
|
-
|
|
248
|
-
1. Fork the repo;
|
|
249
|
-
2. Make improvements;
|
|
250
|
-
3. Make a pull request to share your improvements with the community and to include it into official release.
|
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.2
|
|
2
|
-
Name: mathjson-solver
|
|
3
|
-
Version: 1.11.0
|
|
4
|
-
Summary: Utilities for MathJSON evaluation
|
|
5
|
-
Home-page: https://github.com/LongenesisLtd/mathjson-solver
|
|
6
|
-
Author: Martins Mednis
|
|
7
|
-
Author-email: mrt@mednis.info
|
|
8
|
-
Project-URL: Bug Tracker, https://github.com/LongenesisLtd/mathjson-solver/issues
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.6
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Dynamic: author
|
|
16
|
-
Dynamic: author-email
|
|
17
|
-
Dynamic: classifier
|
|
18
|
-
Dynamic: description
|
|
19
|
-
Dynamic: description-content-type
|
|
20
|
-
Dynamic: home-page
|
|
21
|
-
Dynamic: project-url
|
|
22
|
-
Dynamic: requires-python
|
|
23
|
-
Dynamic: summary
|
|
24
|
-
|
|
25
|
-
# MathJSON Solver
|
|
26
|
-
|
|
27
|
-
[](https://gitter.im/mathjson-solver/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
|
28
|
-
|
|
29
|
-
_MathJSON Solver_ is a Python module to numerically evaluate MathJSON expressions. It was created by [Longenesis](https://longenesis.com/team) to add numerical evaluation capability of user generated mathematical expressions in Longenesis digital health products and later released as open source project. Its development was inspired by [CortexJS](https://cortexjs.io/compute-engine/) Compute Engine.
|
|
30
|
-
|
|
31
|
-
Please ask questions and share feedback in our Gitter chat [https://gitter.im/mathjson-solver/community](https://gitter.im/mathjson-solver/community).
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
## How to use
|
|
35
|
-
```python
|
|
36
|
-
from mathjson_solver import create_solver
|
|
37
|
-
|
|
38
|
-
parameters = {"x": 2, "y": 3}
|
|
39
|
-
expression = ["Add", "x", "y", 4]
|
|
40
|
-
|
|
41
|
-
solver = create_solver(parameters)
|
|
42
|
-
answer = solver(expression)
|
|
43
|
-
|
|
44
|
-
print(answer)
|
|
45
|
-
# 9, because 2+3+4=9
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Currently supported constructs
|
|
49
|
-
* `Add` - Iteratively adds up the given values. Compatible with time delta.
|
|
50
|
-
* `Sum` - Internally uses python's `sum`. Not compatible with time delta.
|
|
51
|
-
* `Subtract` -
|
|
52
|
-
* `Constants` -
|
|
53
|
-
* `Switch` -
|
|
54
|
-
* `If` -
|
|
55
|
-
* `Multiply` -
|
|
56
|
-
* `Divide` -
|
|
57
|
-
* `Negate` -
|
|
58
|
-
* `Power` -
|
|
59
|
-
* `Root` -
|
|
60
|
-
* `Sqrt` -
|
|
61
|
-
* `Square` -
|
|
62
|
-
* `Exp` -
|
|
63
|
-
* `Log` -
|
|
64
|
-
* `Log2` -
|
|
65
|
-
* `Log10` -
|
|
66
|
-
* `Equal` -
|
|
67
|
-
* `Greater` -
|
|
68
|
-
* `GreaterEqual` -
|
|
69
|
-
* `Less` -
|
|
70
|
-
* `LessEqual` -
|
|
71
|
-
* `NotEqual` -
|
|
72
|
-
* `Abs` -
|
|
73
|
-
* `Round` -
|
|
74
|
-
* `Max` -
|
|
75
|
-
* `Min` -
|
|
76
|
-
* `Average` - Internally tries to convert strings to numbers, making calculation of average from `[2, 4 ,"6"]` actually possible. Also, it ignores un-convertible elements so arrays like `[2, "three", 4 ,"6"]` don't crash the solver.
|
|
77
|
-
* `Median` -
|
|
78
|
-
* `Length` -
|
|
79
|
-
* `Any` -
|
|
80
|
-
* `All` -
|
|
81
|
-
* `Array` -
|
|
82
|
-
* `In` -
|
|
83
|
-
* `Not_in` -
|
|
84
|
-
* `Contains_any_of` -
|
|
85
|
-
* `Contains_all_of` -
|
|
86
|
-
* `Contains_none_of` -
|
|
87
|
-
* `NotIn` -
|
|
88
|
-
* `ContainsAnyOf` -
|
|
89
|
-
* `ContainsAllOf` -
|
|
90
|
-
* `ContainsNoneOf` -
|
|
91
|
-
* `Int` -
|
|
92
|
-
* `Float` -
|
|
93
|
-
* `Str` -
|
|
94
|
-
* `Not` -
|
|
95
|
-
* `IsDefined` - Checks if a value is in parameters.
|
|
96
|
-
* `Map` -
|
|
97
|
-
* `HasMatchingSublist` -
|
|
98
|
-
* `Strptime` -
|
|
99
|
-
* `Strftime` -
|
|
100
|
-
* `Today` -
|
|
101
|
-
* `Now` -
|
|
102
|
-
* `TimeDeltaWeeks` -
|
|
103
|
-
* `TimeDeltaHours` -
|
|
104
|
-
* `TimeDeltaMinutes` -
|
|
105
|
-
* `TimeDeltaDays` -
|
|
106
|
-
|
|
107
|
-
## Examples
|
|
108
|
-
```python
|
|
109
|
-
["Add", 2, 4, 3] # 2+4+3=9
|
|
110
|
-
["Subtract", 10, 5, 2] # 10-5-2=3
|
|
111
|
-
["Add", 5, 4, ["Negate", 3]] # 5+4+(-3)=6
|
|
112
|
-
["Multiply", 2, 3, 4] # 2*3*4=24
|
|
113
|
-
["Divide", 10, 5] # 10/5=2.0
|
|
114
|
-
["Divide", 10, 4] # 10/4=2.5
|
|
115
|
-
["Power", 2, 3] # 2^3=8
|
|
116
|
-
["Root", 9, 2] # √9=3.0
|
|
117
|
-
["Root", 8, 3] # ∛8=2.0
|
|
118
|
-
["Sqrt", 9] # √9=3.0
|
|
119
|
-
["Square", 4] # 4^2=16
|
|
120
|
-
["Exp", 2] # e^2≅7.389
|
|
121
|
-
["Divide", 10, ["Add", 2+3]] # 10/(2+3)=10/5=2
|
|
122
|
-
["Log", 2.7183] # ln(2.7183)≅1.0000
|
|
123
|
-
["Log2", 8] # log2(8)=3.0
|
|
124
|
-
["Log10", 1000] # log10(1000)=3.0
|
|
125
|
-
["Equal", 10, 10] # 10==10 = True
|
|
126
|
-
["Equal", 10, 12] # 10==12 = False
|
|
127
|
-
["Abs", -3.5] # |-3.5| = 3.5
|
|
128
|
-
["Round", -5.123456, 2] # -5.12
|
|
129
|
-
["Round", -5.123456, 0] # -5.0
|
|
130
|
-
["Round", -5.123456] # -5
|
|
131
|
-
["Array", 1, 2] # ["Array", 1, 2]
|
|
132
|
-
|
|
133
|
-
["Max", ["Array", 1, 2, 3, 5, 2]] # 5
|
|
134
|
-
["Max", ["Array", 1, 2, ["Sum", 2, 4, 3], 5, 2]] # 9
|
|
135
|
-
["Median", ["Array", 1, 2, 3, 5, 2]] # 2
|
|
136
|
-
["Average", ["Array", 1, 2, 3, 5, 2]] # 2.6
|
|
137
|
-
["Average", ["Array"]] # None
|
|
138
|
-
|
|
139
|
-
["Length", ["Array", 1, 2, 3, 5, 2, 9]] # 6
|
|
140
|
-
["Length", ["Array"]] # 0
|
|
141
|
-
["Any", ["Array", 0, 0, False, 0, 0]] # False
|
|
142
|
-
["Any", ["Array", 0, 1, False, 0, 0]] # True
|
|
143
|
-
["All", ["Array", 0, 1, False, 0, 0]] # False
|
|
144
|
-
["All", ["Array", 0, 1, False, "", 0]] # False
|
|
145
|
-
["All", ["Array", 2, 1, True, "zz", 2]] # True
|
|
146
|
-
["Int", "12"] # 12
|
|
147
|
-
["Int", "12.2"] # 12
|
|
148
|
-
["Float", "12.2"] # 12.2
|
|
149
|
-
["Str", 12] # "12"
|
|
150
|
-
["Str", "12"] # "12"
|
|
151
|
-
["Str", "aabb"] # "aabb"
|
|
152
|
-
["Not", True] # False
|
|
153
|
-
["Not", 0] # True
|
|
154
|
-
|
|
155
|
-
["In", 2, ["Array", 1, 2, 3]] # True
|
|
156
|
-
["In", 4, ["Array", 1, 2, 3]] # False
|
|
157
|
-
["ContainsAnyOf", ["Array", 1, 2, 3], ["Array", 3, 4, 5, 6]] # True
|
|
158
|
-
["ContainsAnyOf", ["Array", 1, 2, 3], ["Array", 4, 5, 6]] # False
|
|
159
|
-
["ContainsAllOf", ["Array", 1, 2, 3], ["Array", 1, 2, 3]] # True
|
|
160
|
-
["ContainsAllOf", ["Array", 1, 2], ["Array", 1, 2, 3]] # False
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### Constants
|
|
164
|
-
```
|
|
165
|
-
[
|
|
166
|
-
"Constants",
|
|
167
|
-
["constant_name1", <expression>],
|
|
168
|
-
["constant_name2", <expression>],
|
|
169
|
-
["constant_name3", <expression>],
|
|
170
|
-
...,
|
|
171
|
-
<expression>
|
|
172
|
-
]
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
`Constants` construct consists of keyword "Constants" followed by arbitrary number of name&value pairs. The last element in `Constants` construct is the expression to calculate using the defined constants.
|
|
176
|
-
|
|
177
|
-
The following example has two constants defined - `x=10` and `y=20`. Then the sum of these two constants is calculated and returned.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
```python
|
|
181
|
-
[
|
|
182
|
-
"Constants",
|
|
183
|
-
["x", 10],
|
|
184
|
-
["y", 20],
|
|
185
|
-
["Add","x", "y"]
|
|
186
|
-
]
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
### If statement
|
|
191
|
-
```
|
|
192
|
-
[
|
|
193
|
-
"If",
|
|
194
|
-
[
|
|
195
|
-
<true-or-false-expression>,
|
|
196
|
-
<expression-to-calculate>
|
|
197
|
-
],
|
|
198
|
-
[
|
|
199
|
-
<elseif-true-or-false-expression>,
|
|
200
|
-
<expression-to-calculate>
|
|
201
|
-
],
|
|
202
|
-
...,
|
|
203
|
-
<else-expression-to-calculate>
|
|
204
|
-
]
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
Example
|
|
208
|
-
```python
|
|
209
|
-
[
|
|
210
|
-
"If",
|
|
211
|
-
[
|
|
212
|
-
["Equal", 1, 0],
|
|
213
|
-
10
|
|
214
|
-
],
|
|
215
|
-
[
|
|
216
|
-
["Equal", 2, 2],
|
|
217
|
-
20
|
|
218
|
-
],
|
|
219
|
-
9000
|
|
220
|
-
]
|
|
221
|
-
```
|
|
222
|
-
This construct translates to:
|
|
223
|
-
```
|
|
224
|
-
if 1 == 0 then 10
|
|
225
|
-
elif 2 == 2 then 20
|
|
226
|
-
else 9000
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
`If` expressions do not need to be strictly _boolean_. Any value that is not _false_ are considered _true_.
|
|
230
|
-
|
|
231
|
-
### Switch-Case statement
|
|
232
|
-
```
|
|
233
|
-
["Switch", <on-expression>, <default-result-expression>, [<case1-expression>, <result-expression>], ...],
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
`Switch` construct consists of keyword "Switch" followed by expression whose value will be compared to _Cases'_ values. Then comes the default value. Then follows arbitrary number of _Cases_.
|
|
237
|
-
|
|
238
|
-
Example
|
|
239
|
-
```python
|
|
240
|
-
["Switch", "color", 100, ["red", 10], ["blue", 20], ["green", 30]],
|
|
241
|
-
```
|
|
242
|
-
The expression in this example will make solver to look for a constant (or a parameter) with the name "color". If "color" is "red", expression evaluates to 10, if "blue" - to 20, if "green" - to 30. Otherwise to 100. Please note that "color" here is a valid expression that evaluates to the actual value of "color" whether it is a parameter or constant.
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
## Exception handling
|
|
246
|
-
|
|
247
|
-
A `MathJSONException` is raised when expression cannot be evaluated. Import `MathJSONException` to handle it:
|
|
248
|
-
```python
|
|
249
|
-
from mathjson_solver import create_solver, MathJSONException
|
|
250
|
-
|
|
251
|
-
solver = create_solver({})
|
|
252
|
-
try:
|
|
253
|
-
solver(["Divide", 1, 0])
|
|
254
|
-
except MathJSONException:
|
|
255
|
-
pass
|
|
256
|
-
# invoke your own exception logger here
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
Left unhandled, the exception will look like `MathJSONException("Problem in Divide. ['Divide', 1, 0]. division by zero")`.
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
## How to run tests
|
|
263
|
-
Make sure you have `pytest` installed. Then `cd` into project directory and run:
|
|
264
|
-
```bash
|
|
265
|
-
pytest
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
## Contributing Code
|
|
269
|
-
|
|
270
|
-
We welcome your contributions in the form of pull requests.
|
|
271
|
-
|
|
272
|
-
1. Fork the repo;
|
|
273
|
-
2. Make improvements;
|
|
274
|
-
3. Make a pull request to share your improvements with the community and to include it into official release.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mathjson_solver-1.11.0 → mathjson_solver-1.12.0}/src/mathjson_solver.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{mathjson_solver-1.11.0 → mathjson_solver-1.12.0}/src/mathjson_solver.egg-info/top_level.txt
RENAMED
|
File without changes
|