-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathCHANGES
318 lines (216 loc) · 11.2 KB
/
CHANGES
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
plusminus Change Log
0.8.2 -
- Added omitted operator ∆ to _base_operators, which adds it to
the operators list in the help
0.8.1 -
- Fixed bug in evaluating boolean expressions with more than
two terms, reported by ccaapton - fixed Issue #23.
0.8.0 -
- Added tox for automated testing on multiple Python versions.
- Added support for Python 3.12 and 3.13.
- Added support for serializing plusminus parsers and results over
cloudpickle (used in Apache Spark applications). Fixes Issue #22,
reported and assisted by ccaapton, thanks!
- Added a "use_decimal" keyword argument to the `BaseArithmeticParser`
class. If passed as `True`, the parser will evaluate float values using
Python's `decimal.Decimal` class. Addresses Issue #20, submitted by
ezekielnewren, nice idea!
0.7.0 -
- Added type annotations on public methods, to aid in type checking and
autocomplete.
- Added sin², sin³, sin⁻¹, etc. methods for common mathematical notation
such as sin²(x) for sin(x)**2, and sin⁻¹(x) for asin(x).
- Dropped BasicArithmeticParser synonym for ArithmeticParser
(too easily confused with BaseArithmeticParser).
- Added symmetric difference set operations, supported by '∆' and '^'
operators.
- Added radical expressions for roots > 2, up to 9, to the ArithmeticParser
class:
³√2 -> 2**(1/3) (1.259921049894873)
⁹√2 -> 2**(1/9) (1.080059738892306)
- Added Unicode variable assignment operator '←'.
- Added option to allow/disallow user-defined variables in expressions.
- Added better docstring to enumerate all supported parser options.
- Added scan_string method, to replace deprecated scanString method.
(Many features added by TheOneMusic, thanks!)
0.6.0 -
- Auto-promote operators that are alphabetic to pyparsing Keywords,
to help differentiate operators that are similar.
- Added "less" and "off" operators to BusinessArithmeticParser for parsing
discounting expressions like "20% off of 30" or "30 less 20%".
0.5.0 -
- Python 3.5 is no longer supported, plusminus now only works with
Python 3.6 and later.
- Refactored classes and parser interface to support better
definition of precedence of operations for custom operators, and to better
align the BaseArithmeticParser class to standard Python `eval()`, with
some enhancements/distinctions:
- `|x|` absolute value notation included
- Unicode operators included (`≠ ≤ ≥ ∈ ∉ ∩ ∪ ∧ ∨` for
`!= <= >= in not-in intersection union and or`)
- C-style `condition ? true_value : false_value` ternary operator included
- support for set union, intersection, and element
- dict and list containers not supported
The new ArithmeticParser class (renamed from BasicArithmeticParser) adds:
- trig, algebra, and random functions
- algebra constants `π τ e φ ϕ`
- `√` square root operator (unary and binary)
- exponent operators `⁻¹ ⁰ ¹ ² ³`
- `!` factorial operator
- `°` degrees-to-radians conversion operator
The former `BasicArithmeticParser` is deprecated, as too easily confused with the
`BaseArithmeticParser`. A compatibility synonym is defined for now, but this
will be removed in a future release (probably 1.0).
- Dropped support for "in" range notation, with ranges specified
using (), (], [) or [] notation ("in" with sets is still
supported).
- Deleted the example_parsers.py module in the examples directory, and split
the parsers out into separate modules in that directory.
- Added __version_info__ structure, following pattern of sys.version_info
field names.
- Added `user_defined_formulas_supported` attribute for parsers,
to enable/disable support for `@=` formula assignment operator
(default=`True`)
- Added documentation to functions in the ArithmeticParser class
for better understanding and readability.
- Unary "+" operator can now be used. For example:
parser = ArithmeticParser()
parser.evaluate("+5")
- "&" and "|" added as set operations, respectively intersection and
union (same as "∩" and "∪" characters).
0.4.0 -
- Update default `sys.setrecursionlimit` to 3000 if it has not
already been modified, to allow for deep call stacks generated
from infixNotation parsers.
- Custom functions can now take different numbers of arguments,
using a tuple of integers for the arity. For example, here is the
log function, that can take only one or two arguments:
self.add_function("log", (1, 2), math.log)
- Updated operators and functions in ArithmeticParser:
- "−" can now be used as a unary minus operator, like "-".
- "//" operator for floor division added.
- round function now accepts one or two arguments, instead of two only.
- Updated operators, functions and variables in BasicArithmeticParser:
- Added the log function above in the BasicArithmeticParser. If called
with one argument, base e is used. If called with two, the second
argument is used as the base.
- Removed the nhypot function. The hypot function now takes any number
of arguments.
- gamma function now takes one parameter, instead of two.
- Added variable "tau" (same as "τ"), which is equal to 2×π.
- Added variables "ϕ" and "phi" (same as "φ", the golden number).
- Updated documentation and examples in the BasicArithmeticParser class.
Thanks to TheOneMusic for his awesome contributions to this release!
- PLANNED FOR 0.5.0
- Refactoring the parser classes to provide a
parser for standard Python expressions using standard Python
operators and builtins, and functions from the math module
(may limit types to int and float). Will make this parser more
of a safe drop-in replacement for "eval" without extra bells and
whistles.
- Better definition of custom operators, to permit support for
proper definition of precedence of operations.
- Update web demo to support selection of different parsers.
0.3.0 -
- Added syntax to clear a defined variable:
a, b = 1, 2
c = a + b -> 3
a = -> clears variable a
c = a + b -> NameError
- Added support for nested sets, and better set display format.
{{1, 2}, 99, 100}
{99, 'z', 'a'} ∪ {'a', 't', 100} -> {99, 100, 'a', 't', 'z'}
- Set literals can be used as function arguments, if supported
by the function.
max({1, 2, 4}) -> 4
min({1, 2, 4}) -> 1
sin({1, 2, 4}) -> TypeError
- Added dict-like access API to set and get variables defined within
a parser:
for x in range(10):
parser['x'] = x
parser.evaluate("y = x * x")
print(parser['y'])
del parser['y']
- plusminus has been hardened against some possible attacks, using
deep expression nesting or formula references:
- To guard against expressions that are too deeply nested, a
customizable maximum_expression_depth attribute has been added
to parsers. Parsers customized with additional operators may need
to limit the allowed depth. The default maximum depth is 6
(reduced from 10 in 0.2.0).
((((((0)))))) -> 0
(((((((0))))))) -> OverflowError: too deeply nested
There is also a maximum_set_depth attribute for nested sets,
also defaults to 6.
- A similar performance issue can be raised if a formula chains
to another formula to another formula, etc. too deeply.
a @= b + b
b @= c + c
c @= d + d
...
m @= n + n -> OverflowError: function variables nested too deeply
A customizable parser attribute maximum_formula_depth will limit the number
of formula indirections. The default value is 12.
- An attack may try to define too many variables and crash an application
by consuming excessive memory. A value to limit the number of variables and
their respective memory usage was previously hard-coded. These are now
part of the public API for parsers: max_number_of_vars (default = 1000)
and max_var_memory (default = 10MB).
0.2.0 -
- Added set notation and arithmetic:
{1, 2, 3} is the set of the integers 1, 2, and 3
{} is the empty set
a ∩ b the intersection of sets a and b
a ∪ b the union of sets a and b
a ∈ b a is an element of b (can also be written 'a in b')
a ∉ b a is not an element of b (can also be written 'a not in b')
- Replaced "between", "within", and "in range from-to" operators
to single "in" operator, taking an argument of the form:
[1, 10] between 1 and 10 (including the values 1 and 10)
[1, 10) between 1 and 10 (excluding the value 10)
(1, 10] between 1 and 10 (excluding the value 1)
(1, 10) between 1 and 10 (excluding the values 1 and 10)
- Custom functions can now take variable numbers of arguments,
using ... for the arity. For example, here is a variant of
hypot computing an n-dimensional distance:
self.add_function("nhypot", ..., lambda *seq: sum(safe_pow(i, 2) for i in seq)**0.5)
- Updated the values returned from evaluating an assignment
expression. If a single value is assigned, then a single
value is returned. If multiple values are assigned, a tuple
of the values is returned. (Previously, the underlying
list of values was returned.)
- Guard against overly-nested ()'s (10 levels is the max).
- Changed signature of safe_pow, now takes multiple operands
instead of a tuple of operands.
- New unit tests, thanks toonarmycaptain!
0.1.1 -
- Added useful customization methods to public API
- safe_pow
- safe_str_mult
- constrained_factorial
- ArithmeticParseException
- Modified example parsers to use these safe methods
- Moved many functions out of the base ArithmeticParser class and into
BasicArithmeticParser, so that applications can choose to extend
from the base class if trigonometric, etc. functions are not
relevant to their particular domain.
- Moved example parsers into plusminus import tree, so that they can be
imported and used:
from plusminus.examples.example_parsers import DiceRollParser
parser = DiceRollParser()
print(parser.evaluate("3d20")
- Moved body of usage() out of bottle_repl and into the parser class
itself so that repls can get basic usage text directly from the parser.
0.1 - initial release
- Core API classes and methods
- ArithmeticParser
- BasicArithmeticParser
- examples
- example_parsers.py
- DiceRollerArithmeticParser
- CombinatoricsArithmeticParser
- BusinessArithmeticParser
- DatetimeArithmeticParser
- bottle_repl.py
- console_repl.py