py.js
is a parser and evaluator of Python expressions, written in
pure javascript.
py.js
is not intended to implement a full Python interpreter, its
specification document is the Python 2.7 Expressions spec (along with the
lexical analysis part) as well as the Python builtins.
Usage
To evaluate a Python expression, simply call
py.eval()
. py.eval()
takes a mandatory Python expression
parameter, as a string, and an optional evaluation context (namespace
for the expression’s free variables), and returns a javascript value:
> py.eval("t in ('a', 'b', 'c') and foo", {t: 'c', foo: true});
true
If the expression needs to be repeatedly evaluated, or the result of
the expression is needed in its “python” form without being converted
back to javascript, you can use the underlying triplet of functions
py.tokenize()
, py.parse()
and py.evaluate()
directly.
API
Core functions
py.eval(expr[, context])
“Do everything” function, to use for one-shot evaluation of Python expressions. Chains tokenizing, parsing and evaluating the expression then converts the result back to javascript
- expr (
String
) – Python expression to evaluate - context (
Object
) – evaluation context for the expression’s free variables
py.tokenize(expr)
Expression tokenizer
String
) – Python expression to tokenizepy.parse(tokens)
Parses a token stream and returns the corresponding parse tree.
The parse tree is stateless and can be memoized and reused for frequently evaluated expressions.
py.tokenize()
py.evaluate(tree[, context])
Evaluates the expression represented by the provided parse tree, using the provided context for the exprssion’s free variables.
- tree – parse tree returned by
py.parse()
- context – evaluation context
Conversions from Javascript to Python
py.js
will automatically attempt to convert non-py.object
values into their py.js
equivalent in the following situations:
- Values passed through the context of
py.eval()
orpy.evaluate()
- Attributes accessed directly on objects
- Values of mappings passed to
py.dict
Notably, py.js
will not attempt an automatic conversion of
values returned by functions or methods, these must be
py.object
instances.
The automatic conversions performed by py.js
are the following:
null
is converted topy.None
true
is converted topy.True
false
is converted topy.False
- numbers are converted to
py.float
- strings are converted to
py.str
- functions are wrapped into
py.PY_dev
Array
instances are converted topy.list
The rest generates an error, except for undefined
which
specifically generates a NameError
.
Conversions from Python to Javascript
py.js types (extensions of py.object()
) can be converted
back to javascript by calling their py.object.toJSON()
method.
The default implementation raises an error, as arbitrary objects can not be converted back to javascript.
Most built-in objects provide a py.object.toJSON()
implementation out of the box.
Javascript-level exceptions
Javascript allows throwing arbitrary things, but runtimes don’t seem
to provide any useful information (when they ever do) if what is
thrown isn’t a direct instance of Error
. As a result, while
py.js
tries to match the exception-throwing semantics of Python it
only ever throws bare Error
at the javascript-level. Instead, it
prefixes the error message with the name of the Python expression, a
colon, a space, and the actual message.
For instance, where Python would throw KeyError("'foo'")
when
accessing an invalid key on a dict
, py.js
will throw
Error("KeyError: 'foo'")
.