py.js / doc / index.rst

Full commit

py.js, a Python expressions parser and evaluator

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.


To evaluate a Python expression, simply call :func:`py.eval`. :func:`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});

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 :func:`py.tokenize`, :func:`py.parse` and :func:`py.evaluate` directly.


Core functions

Utility functions

These are functions provided to implement py objects which can be used within a py.js evaluation, they're essentially py.js's version of the Python C API. They live in a py sub-namespace (and are thus accessible via[function])

Implementation details

Conversions from Javascript to Python

Conversions from Python to Javascript

Calling convention

Because Python supports keyword arguments and javascript does not, moving arguments from the python domain to the javascript domain is not completely straightforward.

py.js implements two different conventions for that case (…)

  • Dunder methods (pre- and post-fixed with __) of the Python Data Model — fully and knowingly called in javascript — receive their arguments unwrapped and positionally, as normal arguments to a javascript functions. These arguments will still generally be :class:`py.object`.
  • Arbitrary user-defined methods receive two parameters args and kwargs, holding respectively the positional and keyword arguments passed to the callable from the expression.

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'").

[1]Python 2, which py.js currently implements, does not support Python-level keyword-only parameters (it can be done through the C-API), but it seemed neat and easy enough so there.