mathjson-solver 1.9.1__tar.gz → 1.11.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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: mathjson-solver
3
- Version: 1.9.1
3
+ Version: 1.11.0
4
4
  Summary: Utilities for MathJSON evaluation
5
5
  Home-page: https://github.com/LongenesisLtd/mathjson-solver
6
6
  Author: Martins Mednis
@@ -12,6 +12,15 @@ Classifier: Operating System :: OS Independent
12
12
  Requires-Python: >=3.6
13
13
  Description-Content-Type: text/markdown
14
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
15
24
 
16
25
  # MathJSON Solver
17
26
 
@@ -21,14 +30,6 @@ _MathJSON Solver_ is a Python module to numerically evaluate MathJSON expression
21
30
 
22
31
  Please ask questions and share feedback in our Gitter chat [https://gitter.im/mathjson-solver/community](https://gitter.im/mathjson-solver/community).
23
32
 
24
- ## What's new
25
-
26
- ### 1.4.2
27
- Added `Str` construct. It tries to convert value to string.
28
-
29
- ### 1.4.0
30
- We changed the behavior of `Average` to be more forgiving. In version 1.4.0 `Average` accepts arrays like `[2, 4 ,"6"]` and internally converts numeric strings to floats.
31
- Also, it skips values that cannot be converted to numeric. Internally `Average` will convert array `[2, "three", 4 ,"6"]` to `[2.0, 4.0 ,6.0]`. When given an empty array, `Average` now returns `None` instead of throwing an error.
32
33
 
33
34
  ## How to use
34
35
  ```python
@@ -44,75 +45,64 @@ print(answer)
44
45
  # 9, because 2+3+4=9
45
46
  ```
46
47
 
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.
60
-
61
-
62
48
  ## Currently supported constructs
63
- ### Math
64
- * `Sum` (alias `Add`)
65
- * `Subtract`
66
- * `Multiply`
67
- * `Divide`
68
- * `Negate`
69
- * `Power`
70
- * `Root`
71
- * `Sqrt`
72
- * `Square`
73
- * `Exp`
74
- * `Log`
75
- * `Log2`
76
- * `Log10`
77
-
78
-
79
- ### Aggregation
80
- * `Array`
81
- * `Max`
82
- * `Min`
83
- * `Average`
84
- * `Median`
85
- * `Len`
86
- * `All`
87
- * `Any`
88
-
89
-
90
- ### Conditions
91
- * `If`
92
- * `Switch`
93
- * `Equal`
94
- * `Greater`
95
- * `GreaterEqual`
96
- * `Less`
97
- * `LessEqual`
98
- * `NotEqual`
99
-
100
- ### Membership operators
101
- * `In`
102
- * `NotIn`
103
- * `ContainsAnyOf`
104
- * `ContainsAllOf`
105
- * `ContainsNoneOf`
106
-
107
- ### Typecasting
108
- * `Str`
109
- * `Int`
110
- * `Float`
111
- * `Not`
112
-
113
- ### Additional constructs
114
- * `Constants`
115
-
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` -
116
106
 
117
107
  ## Examples
118
108
  ```python
@@ -133,7 +123,7 @@ We welcome your contributions in the form of pull requests.
133
123
  ["Log2", 8] # log2(8)=3.0
134
124
  ["Log10", 1000] # log10(1000)=3.0
135
125
  ["Equal", 10, 10] # 10==10 = True
136
- ["Equal", 10, 12] # 10==10 = False
126
+ ["Equal", 10, 12] # 10==12 = False
137
127
  ["Abs", -3.5] # |-3.5| = 3.5
138
128
  ["Round", -5.123456, 2] # -5.12
139
129
  ["Round", -5.123456, 0] # -5.0
@@ -236,7 +226,7 @@ elif 2 == 2 then 20
236
226
  else 9000
237
227
  ```
238
228
 
239
- `If` expression do not need to be strictly _boolean_. Any value that is not _false_ are considered _true_.
229
+ `If` expressions do not need to be strictly _boolean_. Any value that is not _false_ are considered _true_.
240
230
 
241
231
  ### Switch-Case statement
242
232
  ```
@@ -267,3 +257,18 @@ except MathJSONException:
267
257
  ```
268
258
 
269
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.
@@ -6,14 +6,6 @@ _MathJSON Solver_ is a Python module to numerically evaluate MathJSON expression
6
6
 
7
7
  Please ask questions and share feedback in our Gitter chat [https://gitter.im/mathjson-solver/community](https://gitter.im/mathjson-solver/community).
8
8
 
9
- ## What's new
10
-
11
- ### 1.4.2
12
- Added `Str` construct. It tries to convert value to string.
13
-
14
- ### 1.4.0
15
- We changed the behavior of `Average` to be more forgiving. In version 1.4.0 `Average` accepts arrays like `[2, 4 ,"6"]` and internally converts numeric strings to floats.
16
- Also, it skips values that cannot be converted to numeric. Internally `Average` will convert array `[2, "three", 4 ,"6"]` to `[2.0, 4.0 ,6.0]`. When given an empty array, `Average` now returns `None` instead of throwing an error.
17
9
 
18
10
  ## How to use
19
11
  ```python
@@ -29,75 +21,64 @@ print(answer)
29
21
  # 9, because 2+3+4=9
30
22
  ```
31
23
 
32
- ## How to run tests
33
- Make sure you have `pytest` installed. Then `cd` into project directory and run:
34
- ```bash
35
- pytest
36
- ```
37
-
38
- ## Contributing Code
39
-
40
- We welcome your contributions in the form of pull requests.
41
-
42
- 1. Fork the repo;
43
- 2. Make improvements;
44
- 3. Make a pull request to share your improvements with the community and to include it into official release.
45
-
46
-
47
24
  ## Currently supported constructs
48
- ### Math
49
- * `Sum` (alias `Add`)
50
- * `Subtract`
51
- * `Multiply`
52
- * `Divide`
53
- * `Negate`
54
- * `Power`
55
- * `Root`
56
- * `Sqrt`
57
- * `Square`
58
- * `Exp`
59
- * `Log`
60
- * `Log2`
61
- * `Log10`
62
-
63
-
64
- ### Aggregation
65
- * `Array`
66
- * `Max`
67
- * `Min`
68
- * `Average`
69
- * `Median`
70
- * `Len`
71
- * `All`
72
- * `Any`
73
-
74
-
75
- ### Conditions
76
- * `If`
77
- * `Switch`
78
- * `Equal`
79
- * `Greater`
80
- * `GreaterEqual`
81
- * `Less`
82
- * `LessEqual`
83
- * `NotEqual`
84
-
85
- ### Membership operators
86
- * `In`
87
- * `NotIn`
88
- * `ContainsAnyOf`
89
- * `ContainsAllOf`
90
- * `ContainsNoneOf`
91
-
92
- ### Typecasting
93
- * `Str`
94
- * `Int`
95
- * `Float`
96
- * `Not`
97
-
98
- ### Additional constructs
99
- * `Constants`
100
-
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` -
101
82
 
102
83
  ## Examples
103
84
  ```python
@@ -118,7 +99,7 @@ We welcome your contributions in the form of pull requests.
118
99
  ["Log2", 8] # log2(8)=3.0
119
100
  ["Log10", 1000] # log10(1000)=3.0
120
101
  ["Equal", 10, 10] # 10==10 = True
121
- ["Equal", 10, 12] # 10==10 = False
102
+ ["Equal", 10, 12] # 10==12 = False
122
103
  ["Abs", -3.5] # |-3.5| = 3.5
123
104
  ["Round", -5.123456, 2] # -5.12
124
105
  ["Round", -5.123456, 0] # -5.0
@@ -221,7 +202,7 @@ elif 2 == 2 then 20
221
202
  else 9000
222
203
  ```
223
204
 
224
- `If` expression do not need to be strictly _boolean_. Any value that is not _false_ are considered _true_.
205
+ `If` expressions do not need to be strictly _boolean_. Any value that is not _false_ are considered _true_.
225
206
 
226
207
  ### Switch-Case statement
227
208
  ```
@@ -252,3 +233,18 @@ except MathJSONException:
252
233
  ```
253
234
 
254
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,6 +1,6 @@
1
1
  [metadata]
2
2
  name = mathjson-solver
3
- version = 1.9.1
3
+ version = 1.11.0
4
4
  author = Martins Mednis
5
5
  author_email = mrt@mednis.info
6
6
  description = Utilities for MathJSON evaluation
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name="mathjson-solver",
8
- version="1.9.1",
8
+ version="1.11.0",
9
9
  author="Martins Mednis",
10
10
  author_email="mrt@mednis.info",
11
11
  description="Utilities for MathJSON evaluation",
@@ -6,6 +6,7 @@ from copy import deepcopy
6
6
  from statistics import median
7
7
  import logging
8
8
  import traceback
9
+ import datetime
9
10
 
10
11
 
11
12
  class MathJSONException(Exception):
@@ -141,6 +142,31 @@ def create_mathjson_solver(solver_parameters):
141
142
  def Arr(s):
142
143
  return s
143
144
 
145
+ def Add(s):
146
+ l_res = []
147
+ tmp = 0
148
+ for i, x in enumerate(s[1:]):
149
+ res = f(x, c)
150
+ if i == 0:
151
+ tmp = res
152
+ else:
153
+ tmp = tmp + res
154
+
155
+ # if isinstance(res, list):
156
+ # l_res.append(sum([xx for xx in res[1:]]))
157
+ # else:
158
+ # l_res.append(res)
159
+
160
+ return tmp
161
+
162
+ # tmp = 0
163
+ # for i, x in enumerate(l):
164
+ # if i == 0:
165
+ # tmp = x
166
+ # else:
167
+ # tmp = tmp + x
168
+ # return tmp
169
+
144
170
  def Sum(s):
145
171
  l_res = []
146
172
  for x in s[1:]:
@@ -343,9 +369,37 @@ def create_mathjson_solver(solver_parameters):
343
369
  conditions=conditions,
344
370
  )
345
371
 
372
+ def Strptime(s):
373
+ datetime_str = f(s[1], c)
374
+ parameters = f(s[2], c)
375
+ return datetime.datetime.strptime(datetime_str, parameters)
376
+
377
+ def Strftime(s):
378
+ dt = f(s[1], c)
379
+ parameters = f(s[2], c)
380
+ return dt.strftime(parameters)
381
+
382
+ def Now(s):
383
+ return datetime.datetime.now()
384
+
385
+ def Today(s):
386
+ return datetime.date.today()
387
+
388
+ def TimeDeltaDays(s):
389
+ return datetime.timedelta(days=f(s[1], c))
390
+
391
+ def TimeDeltaMinutes(s):
392
+ return datetime.timedelta(minutes=f(s[1], c))
393
+
394
+ def TimeDeltaHours(s):
395
+ return datetime.timedelta(hours=f(s[1], c))
396
+
397
+ def TimeDeltaWeeks(s):
398
+ return datetime.timedelta(weeks=f(s[1], c))
399
+
346
400
  constructs = {
347
401
  "Sum": Sum,
348
- "Add": Sum,
402
+ "Add": Add,
349
403
  "Subtract": lambda s: reduce(
350
404
  lambda a, b: a - b, [f(x, c) for x in s[1:]]
351
405
  ),
@@ -401,11 +455,29 @@ def create_mathjson_solver(solver_parameters):
401
455
  "IsDefined": lambda s: s[1] in c,
402
456
  "Map": Map,
403
457
  "HasMatchingSublist": HasMatchingSublist,
458
+ "Strptime": Strptime,
459
+ "Strftime": Strftime,
460
+ "Today": Today,
461
+ "Now": Now,
462
+ "TimeDeltaWeeks": TimeDeltaWeeks,
463
+ "TimeDeltaHours": TimeDeltaHours,
464
+ "TimeDeltaMinutes": TimeDeltaMinutes,
465
+ "TimeDeltaDays": TimeDeltaDays,
404
466
  }
405
467
  if s[0] in constructs:
406
468
  try:
407
469
  return constructs[s[0]](s)
408
- except Exception as e:
470
+
471
+ # except RecursionError:
472
+ # return s[0]
473
+ # except Exception as e:
474
+ except TypeError as e:
475
+ raise MathJSONException(e, s, mathjson_construct=s[0])
476
+ except ValueError as e:
477
+ raise MathJSONException(e, s, mathjson_construct=s[0])
478
+ except IndexError as e:
479
+ raise MathJSONException(e, s, mathjson_construct=s[0])
480
+ except ZeroDivisionError as e:
409
481
  raise MathJSONException(e, s, mathjson_construct=s[0])
410
482
  else:
411
483
  # raise MathJSONException(
@@ -413,7 +485,10 @@ def create_mathjson_solver(solver_parameters):
413
485
  # )
414
486
  return s
415
487
  elif s in solver_parameters:
416
- return f(solver_parameters[s], c)
488
+ try:
489
+ return f(solver_parameters[s], c)
490
+ except RecursionError:
491
+ return solver_parameters[s]
417
492
  elif s in c:
418
493
  return f(c[s], c)
419
494
  else:
@@ -474,6 +549,14 @@ def extract_variables(s: Union[list, int, float, str], li: set, ignore_list: set
474
549
  "IsDefined",
475
550
  "Map",
476
551
  "HasMatchingSublist",
552
+ "Strptime",
553
+ "Strftime",
554
+ "Today",
555
+ "Now",
556
+ "TimeDeltaWeeks",
557
+ "TimeDeltaHours",
558
+ "TimeDeltaMinutes",
559
+ "TimeDeltaDays",
477
560
  ]
478
561
  if isinstance(s, str):
479
562
  if s in ignore_list:
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: mathjson-solver
3
- Version: 1.9.1
3
+ Version: 1.11.0
4
4
  Summary: Utilities for MathJSON evaluation
5
5
  Home-page: https://github.com/LongenesisLtd/mathjson-solver
6
6
  Author: Martins Mednis
@@ -12,6 +12,15 @@ Classifier: Operating System :: OS Independent
12
12
  Requires-Python: >=3.6
13
13
  Description-Content-Type: text/markdown
14
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
15
24
 
16
25
  # MathJSON Solver
17
26
 
@@ -21,14 +30,6 @@ _MathJSON Solver_ is a Python module to numerically evaluate MathJSON expression
21
30
 
22
31
  Please ask questions and share feedback in our Gitter chat [https://gitter.im/mathjson-solver/community](https://gitter.im/mathjson-solver/community).
23
32
 
24
- ## What's new
25
-
26
- ### 1.4.2
27
- Added `Str` construct. It tries to convert value to string.
28
-
29
- ### 1.4.0
30
- We changed the behavior of `Average` to be more forgiving. In version 1.4.0 `Average` accepts arrays like `[2, 4 ,"6"]` and internally converts numeric strings to floats.
31
- Also, it skips values that cannot be converted to numeric. Internally `Average` will convert array `[2, "three", 4 ,"6"]` to `[2.0, 4.0 ,6.0]`. When given an empty array, `Average` now returns `None` instead of throwing an error.
32
33
 
33
34
  ## How to use
34
35
  ```python
@@ -44,75 +45,64 @@ print(answer)
44
45
  # 9, because 2+3+4=9
45
46
  ```
46
47
 
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.
60
-
61
-
62
48
  ## Currently supported constructs
63
- ### Math
64
- * `Sum` (alias `Add`)
65
- * `Subtract`
66
- * `Multiply`
67
- * `Divide`
68
- * `Negate`
69
- * `Power`
70
- * `Root`
71
- * `Sqrt`
72
- * `Square`
73
- * `Exp`
74
- * `Log`
75
- * `Log2`
76
- * `Log10`
77
-
78
-
79
- ### Aggregation
80
- * `Array`
81
- * `Max`
82
- * `Min`
83
- * `Average`
84
- * `Median`
85
- * `Len`
86
- * `All`
87
- * `Any`
88
-
89
-
90
- ### Conditions
91
- * `If`
92
- * `Switch`
93
- * `Equal`
94
- * `Greater`
95
- * `GreaterEqual`
96
- * `Less`
97
- * `LessEqual`
98
- * `NotEqual`
99
-
100
- ### Membership operators
101
- * `In`
102
- * `NotIn`
103
- * `ContainsAnyOf`
104
- * `ContainsAllOf`
105
- * `ContainsNoneOf`
106
-
107
- ### Typecasting
108
- * `Str`
109
- * `Int`
110
- * `Float`
111
- * `Not`
112
-
113
- ### Additional constructs
114
- * `Constants`
115
-
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` -
116
106
 
117
107
  ## Examples
118
108
  ```python
@@ -133,7 +123,7 @@ We welcome your contributions in the form of pull requests.
133
123
  ["Log2", 8] # log2(8)=3.0
134
124
  ["Log10", 1000] # log10(1000)=3.0
135
125
  ["Equal", 10, 10] # 10==10 = True
136
- ["Equal", 10, 12] # 10==10 = False
126
+ ["Equal", 10, 12] # 10==12 = False
137
127
  ["Abs", -3.5] # |-3.5| = 3.5
138
128
  ["Round", -5.123456, 2] # -5.12
139
129
  ["Round", -5.123456, 0] # -5.0
@@ -236,7 +226,7 @@ elif 2 == 2 then 20
236
226
  else 9000
237
227
  ```
238
228
 
239
- `If` expression do not need to be strictly _boolean_. Any value that is not _false_ are considered _true_.
229
+ `If` expressions do not need to be strictly _boolean_. Any value that is not _false_ are considered _true_.
240
230
 
241
231
  ### Switch-Case statement
242
232
  ```
@@ -267,3 +257,18 @@ except MathJSONException:
267
257
  ```
268
258
 
269
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.
@@ -45,6 +45,60 @@ from mathjson_solver import create_solver, MathJSONException, extract_variables
45
45
  ({}, ["Constants", ["a", 1], ["b", 2], ["c", 100], ["Sum", "a", "b"]], 3),
46
46
  ({}, ["Constants", ["a", 1], ["b", ["Add", 2, "a"]], "b"], 3),
47
47
  ({"x": 1}, ["Add", 2, "x"], 3),
48
+ ({"value": 1}, ["Switch", "value", 0, [1, 11], [2, 22]], 11),
49
+ ({"value": 3}, ["Switch", "value", 0, [1, 11], [2, 22]], 0),
50
+ (
51
+ {"[uzwuoy][-1][14]": 1},
52
+ ["Switch", "[uzwuoy][-1][14]", 0, [1, 11], [2, 22]],
53
+ 11,
54
+ ),
55
+ ({"14": 1}, ["Switch", "14", 0, [1, 11], [2, 22]], 11),
56
+ ({"14": "1"}, ["Switch", "14", 0, ["0", 0], ["1", 1], ["2", 2]], 1),
57
+ ({"29": "1"}, ["Switch", "29", 0, ["0", 0], ["1", 1], ["2", 2]], 1),
58
+ ({"29": "2"}, ["Switch", "29", 0, ["0", 0], ["1", 1], ["2", 2]], 2),
59
+ ({"a": "a"}, ["Switch", "a", 0, ["0", 0], ["1", 1], ["2", 2]], 0),
60
+ (
61
+ {"14": "1", "29": "1"},
62
+ [
63
+ "Add",
64
+ ["Switch", "14", 0, ["0", 0], ["1", 1], ["2", 2]],
65
+ ["Switch", "29", 0, ["0", 0], ["1", 1], ["2", 2]],
66
+ ],
67
+ 2,
68
+ ),
69
+ ({}, ["Switch", "14", 6, ["0", 0], ["1", 1], ["2", 2]], 6),
70
+ ({}, ["Switch", "1", 6, ["0", 0], ["1", 1], ["2", 2]], 1), # BKUS
71
+ (
72
+ {"1": "2"},
73
+ ["Switch", "1", 6, ["0", 0], ["1", 1], ["2", 2]],
74
+ 1,
75
+ ), # Because all "1"s become "2"
76
+ (
77
+ {"1": "3"},
78
+ ["Switch", "1", 6, ["0", 0], ["1", 1], ["2", 2]],
79
+ 1,
80
+ ), # Because string "1" is equal string "1"
81
+ # The following test works.
82
+ # It is commented out because otherwise black auto-formatter would expand it to 100+ lines
83
+ # (
84
+ # {"14": "1", "29": "1", "30": "1", "31": "1", "32": "1", "33": "1", "35": "1", "45": "1", "50": "1", "52": "1", "71": "1", "91": "1", "112": "1"},
85
+ # ["Add",
86
+ # ["Switch","14",0,["0",0],["1",1],["2",2]],
87
+ # ["Switch","29",0,["0",0],["1",1],["2",2]],
88
+ # ["Switch","30",0,["0",0],["1",1],["2",2]],
89
+ # ["Switch","31",0,["0",0],["1",1],["2",2]],
90
+ # ["Switch","32",0,["0",0],["1",1],["2",2]],
91
+ # ["Switch","33",0,["0",0],["1",1],["2",2]],
92
+ # ["Switch","35",0,["0",0],["1",1],["2",2]],
93
+ # ["Switch","45",0,["0",0],["1",1],["2",2]],
94
+ # ["Switch","50",0,["0",0],["1",1],["2",2]],
95
+ # ["Switch","52",0,["0",0],["1",1],["2",2]],
96
+ # ["Switch","71",0,["0",0],["1",1],["2",2]],
97
+ # ["Switch","91",0,["0",0],["1",1],["2",2]],
98
+ # ["Switch","112",0,["0",0],["1",1],["2",2]]
99
+ # ],
100
+ # 13
101
+ # ),
48
102
  ({"color": "red"}, ["Switch", "color", 0, ["blue", 10], ["red", 30]], 30),
49
103
  ({"color": "green"}, ["Switch", "color", 0, ["blue", 10], ["red", 30]], 0),
50
104
  ({"color": "green"}, ["Switch", "undefined", 0, ["blue", 10], ["red", 30]], 0),
@@ -52,6 +106,7 @@ from mathjson_solver import create_solver, MathJSONException, extract_variables
52
106
  ({"a": 10, "b": 10}, ["If", [["Equal", "a", "b"], 10], 9000], 10),
53
107
  ({"a": 10, "b": 20}, ["If", [["Equal", "a", "b"], 10], 9000], 9000),
54
108
  ({"a": 10}, ["If", [["Equal", "a", "b"], 10], 9000], 9000),
109
+ # The following test checks if Sum failure (1+"b") is handled correctly in If.
55
110
  ({"a": 10}, ["If", [["Equal", "a", ["Sum", 1, "b"]], 10], 9000], 9000),
56
111
  ({}, ["Array", 1, 2, 3, 5, 2], ["Array", 1, 2, 3, 5, 2]),
57
112
  ({}, ["Max", ["Array", 1, 2, 3, 5, 2]], 5),
@@ -93,6 +148,9 @@ from mathjson_solver import create_solver, MathJSONException, extract_variables
93
148
  ({}, ["Length", ["Array", 1, 2, 3, 5, 2, 9]], 6),
94
149
  ({"a": ["Array", 1, 2, 3, 5, 2, 9]}, ["Length", "a"], 6),
95
150
  ({}, ["Length", ["Array"]], 0),
151
+ # Next test illustrates an invalid formula, where 'Length' receives an invalid array.
152
+ ({}, ["Length", ["Greater", ["Array", 3, 5, 6, 4, 8, 1, 0, 1], 5]], 2),
153
+ ({}, ["Sum", ["Array", True, False, True, False, False]], 2),
96
154
  ({}, ["Int", "12"], 12),
97
155
  ({}, ["Int", "12.2"], 12),
98
156
  ({}, ["Float", "12.2"], 12.2),
@@ -180,6 +238,12 @@ from mathjson_solver import create_solver, MathJSONException, extract_variables
180
238
  ["Map", ["Array", 1, 2, 3], ["GreaterEqual"], 2],
181
239
  ["Array", False, True, True],
182
240
  ),
241
+ (
242
+ {},
243
+ ["Sum", ["Map", ["Array", 1, 2, 3, 4, 1, 1, 0, 1], ["GreaterEqual"], 2]],
244
+ 3,
245
+ ),
246
+ ({}, ["Sum", ["Array", True, False, True, False, False]], 2),
183
247
  # ["HasMatchingSublist", list, required_match_count, position, contiguous, function, more parameters]
184
248
  (
185
249
  {},
@@ -259,6 +323,78 @@ from mathjson_solver import create_solver, MathJSONException, extract_variables
259
323
  ],
260
324
  False,
261
325
  ),
326
+ (
327
+ {},
328
+ ["Strftime", ["Strptime", "2025-01-10T10:05", "%Y-%m-%dT%H:%M"], "%Y"],
329
+ "2025",
330
+ ),
331
+ ({}, ["Strftime", ["Today"], "%Y"], "2025"),
332
+ ({}, ["Strftime", ["Now"], "%Y"], "2025"),
333
+ (
334
+ {},
335
+ [
336
+ "Strftime",
337
+ [
338
+ "Add",
339
+ ["Strptime", "2025-01-10T10:05", "%Y-%m-%dT%H:%M"],
340
+ ["TimeDeltaDays", 3],
341
+ ],
342
+ "%d",
343
+ ],
344
+ "13",
345
+ ),
346
+ (
347
+ {},
348
+ [
349
+ "Strftime",
350
+ [
351
+ "Subtract",
352
+ ["Strptime", "2025-01-10T10:05", "%Y-%m-%dT%H:%M"],
353
+ ["TimeDeltaDays", 3],
354
+ ],
355
+ "%d",
356
+ ],
357
+ "07",
358
+ ),
359
+ (
360
+ {},
361
+ [
362
+ "Strftime",
363
+ [
364
+ "Add",
365
+ ["Strptime", "2025-01-10T10:05", "%Y-%m-%dT%H:%M"],
366
+ ["TimeDeltaMinutes", 5],
367
+ ],
368
+ "%M",
369
+ ],
370
+ "10",
371
+ ),
372
+ (
373
+ {},
374
+ [
375
+ "Strftime",
376
+ [
377
+ "Add",
378
+ ["Strptime", "2025-01-10T10:05", "%Y-%m-%dT%H:%M"],
379
+ ["TimeDeltaHours", 2],
380
+ ],
381
+ "%H",
382
+ ],
383
+ "12",
384
+ ),
385
+ (
386
+ {},
387
+ [
388
+ "Strftime",
389
+ [
390
+ "Add",
391
+ ["Strptime", "2025-01-10T10:05", "%Y-%m-%dT%H:%M"],
392
+ ["TimeDeltaWeeks", 1],
393
+ ],
394
+ "%d",
395
+ ],
396
+ "17",
397
+ ),
262
398
  ],
263
399
  )
264
400
  def test_solver_simple(parameters, expression, expected_result):