Plusminus

Latest version: v0.8.1

Safety actively analyzes 714919 Python packages for vulnerabilities to keep your Python projects secure.

Scan your dependencies

Page 2 of 2

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

Not secure
- 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

Not secure
- 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

Not secure
- Core API classes and methods
- ArithmeticParser
- BasicArithmeticParser

- examples
- example_parsers.py
- DiceRollerArithmeticParser
- CombinatoricsArithmeticParser
- BusinessArithmeticParser
- DatetimeArithmeticParser
- bottle_repl.py
- console_repl.py

Page 2 of 2

© 2025 Safety CLI Cybersecurity Inc. All Rights Reserved.