JavaScript to Python Translator & JavaScript interpreter written in 100% pure Python🚀

Overview

Build Status Downloads

Pure Python JavaScript Translator/Interpreter

Everything is done in 100% pure Python so it's extremely easy to install and use. Supports Python 2 & 3. Full support for ECMAScript 5.1, ECMA 6 support is still experimental.


Simple Example:

>> add = js2py.eval_js('function add(a, b) {return a + b}') >>> add(1, 2) + 3 6 >>> add.constructor function Function() { [python code] } >>> js2py.require('underscore') 'function _(obj) { [python code] }'">
    >>> import js2py
    >>> js2py.eval_js('console.log( "Hello World!" )')
    'Hello World!'
    >>> add = js2py.eval_js('function add(a, b) {return a + b}')
    >>> add(1, 2) + 3
    6
    >>> add.constructor
    function Function() { [python code] }
    >>> js2py.require('underscore')
    'function _(obj) { [python code] }'

You can also import a big number of node modules as if they were written in Python! For example, here we import a pure JS library crypto-js:

    >>> CryptoJS = js2py.require('crypto-js')
    >>> data = [{'id': 1}, {'id': 2}]
    >>> JSON = js2py.eval_js('JSON')
    >>> ciphertext = CryptoJS.AES.encrypt(JSON.stringify(data), 'secret key 123')
    >>> bytes  = CryptoJS.AES.decrypt(ciphertext.toString(), 'secret key 123')
    >>> decryptedData = JSON.parse(bytes.toString(CryptoJS.enc.Utf8)).to_list()
    >>> decryptedData
    [{u'id': 1}, {u'id': 2}]

Now also supports JavaScript 6 (still experimental):

    >>> js2py.eval_js6('let a = () => 11; a()')
    11

JavaScript 6 support was achieved by using Js2Py to translate javascript library called Babel. Babel translates JS 6 to JS 5 and afterwards Js2Py translates JS 5 to Python. The only downside is that translated babel.js has about 4 MB and importing such a long Python file takes about 15 seconds!


Translating a JavaScript file:

    # this will translate example.js to example.py
    >>> js2py.translate_file('example.js', 'example.py')
    # example.py can be now imported and used!
    >>> from example import example
    >>> example.someFunction()
    ...

Every feature of ECMA 5.1 is implemented (except of 'with' statement):

>>> js2py.eval_js("Object.prototype.toString.call(Function('s', 'return s+arguments[1]')(new Date(), 7).__proto__)")
[object String]

Unfortunately even though Js2Py can be generally used to translate huge Js files (over 50k lines long), in rare cases you may encounter some unexpected problems (like javascript calling a function with 300 arguments - python allows only 255). These problems are very hard to fix with current translation approach. I will try to implement an interpreter in near future which will hopefully fix all the edge cases.

Installation

pip install js2py

More advanced usage example

It is possible to access all the variables from JS scope using EvalJs. Moreover, you can use Python objects from your JavaScript code if you add them to the scope. In this example we will be using Python built-in sum function to sum elements in JS array. It will stand under python_sum.

# Adding Python built-in sum to the JS context:
>>> context = js2py.EvalJs({'python_sum': sum})  
>>> js_code = '''
var a = 10
function f(x) {return x*x}
'''
>>> context.execute(js_code)
# Get value of variable a:
>>> context.a
10
# context.f behaves just like js function so you can supply more than 1 argument. '9'*'9' in javascript is 81.
>>> context.f('9', 0)  
81    
# context.f has all attributes of normal JavaScript object
>>> context.f.toString()
u'function f(x) { [python code] }'
>>> context.f.bind
function bind(thisArg) { [python code] }
# You can also add variables to the context:
>>> context.foo = [1,2,3]  # context.foo is now Js Array object and behaves just like javascript array!
>>> context.foo.push(4)  
4
>>> context.foo.to_list() # convert to python list
[1, 2, 3, 4]
# You can use Python objects that you put inside the context!
>>> context.eval('python_sum(new Array(1, 2, 3))')
6

You can also enable require support in JavaScript like this:

>>> context = js2py.EvalJs(enable_require=True)
>>> context.eval("require('esprima').parse('var a = 1')")

JavaScript 'VirtualMachine' in Python

As a fun experimental project I have also implemented a VM-based JavaScript (yes - there are 2 separate JS implementations in this repo). It is feature complete and faster than the translation based version. Below you can see a demo with a nice debug view (bytecode + execution sequence):

>>> from js2py.internals import seval
>>> seval.eval_js_vm("try {throw 3+3} catch (e) {console.log(e)}", debug=True)
[LOAD_UNDEFINED(),
 JUMP(4,),
 LABEL(1,),
 LOAD_UNDEFINED(),
 POP(),
 LOAD_NUMBER(3.0,),
 LOAD_NUMBER(3.0,),
 BINARY_OP('+',),
 THROW(),
 NOP(),
 LABEL(2,),
 LOAD_UNDEFINED(),
 POP(),
 LOAD('console',),
 LOAD('e',),
 LOAD_N_TUPLE(1,),
 CALL_METHOD_DOT('log',),
 NOP(),
 LABEL(3,),
 LOAD_UNDEFINED(),
 NOP(),
 LABEL(4,),
 TRY_CATCH_FINALLY(1, 2, 'e', 3, False, 4)]

0 LOAD_UNDEFINED()
1 JUMP(4,)
18 TRY_CATCH_FINALLY(1, 2, 'e', 3, False, 4)
  ctx entry (from:2, to:9)
  2 LOAD_UNDEFINED()
  3 POP()
  4 LOAD_NUMBER(3.0,)
  5 LOAD_NUMBER(3.0,)
  6 BINARY_OP('+',)
  7 THROW()
  ctx exit (js errors)
  ctx entry (from:9, to:16)
  9 LOAD_UNDEFINED()
  10 POP()
  11 LOAD('console',)
  12 LOAD('e',)
  13 LOAD_N_TUPLE(1,)
  14 CALL_METHOD_DOT('log',)
6
  15 NOP()
  ctx exit (normal)

This is just a curiosity and I do not recommend using VM in practice (requires more polishing).


Limitations

There are 3 main limitations:

  • "strict mode" is ignored
  • with statement is not supported
  • Indirect call to eval is treated as direct call to eval (hence always evals in local scope)

They are generally not a big issue in practice. In practice more problematic are minor edge cases that unfortunately sometimes do happen. Please report a bug if you find one.

Js2Py was able to successfully translate and run huge JS libraries like Babel (100k+ loc), esprima, crypto-js and more. You can try it yourself by importing any supported npm package via js2py.require('your_package').


Other Examples

In Js2Py all JavaScript objects are a subclass of PyJs object. For example JS Number is represented by PyJsNumber class. js2py.eval_js and js2py.EvalJs automatically tries to convert PyJs type to builtin python type. So for example if you execute:

>>> js2py.eval_js('var a = "hello"; a')

eval_js will return unicode type (u"hello"). However for complex types such conversion is impossible and JsObjectWrapper is returned. See the conversion table JsType -> PyType:

Boolean -> bool
String -> unicode (str in Python 3)
Number -> float (or int/long if whole number)
undefined -> None
null -> None
OTHER -> JsObjectWrapper

JsObjectWrapper supports: getitem, getattr, setitem, setattr, repr and call. Moreover it has to_list and to_dict methods if you want to convert it to builtin python type.

>>> js = js2py.eval_js('d = {a:1, b:2}')
>>> js
{a: 1, b: 2}  
>>> type(js)
<class 'js2py.base.JsObjectWrapper'>
>>> js.a
1
>>> js['a']
1
>>> js.b = 20
>>> js
{a: 1, b: 20}  
>>> js['c'] = 30
>>> js.to_dict()
{u'a': 1, 'c': 30, u'b': 20}

Also, of course you can use Js2Py to parse (tree is the same as in esprima.js) and translate JavaScript

Parsing:

>>> js2py.parse_js('var $ = 5')   
{
    "body": [
        {
            "declarations": [
                {
                    "id": {
                        "name": "$",
                        "type": "Identifier"
                    },
                    "init": {
                        "raw": "5",
                        "type": "Literal",
                        "value": 5
                    },
                    "type": "VariableDeclarator"
                }
            ],
            "kind": "var",
            "type": "VariableDeclaration"
        }
    ],
    "type": "Program"
}

Translating:

>>> print(js2py.translate_js('var $ = 5'))
from js2py.pyjs import *
# setting scope
var = Scope( JS_BUILTINS )
set_global_object(var)

# Code follows:
var.registers(['$'])
var.put('$', Js(5.0))

pyimport statement

Finally, Js2Py also supports importing any Python code from JavaScript using 'pyimport' statement:

>> js2py.eval_js(x) 18211 undefined">
>>> x = """pyimport urllib;
           var result = urllib.urlopen('https://www.google.com/').read();
           console.log(result.length)
        """
>>> js2py.eval_js(x)
18211
undefined
UUID version 7, which are time-sortable (following the Peabody RFC4122 draft)

uuid7 - time-sortable UUIDs This module implements the version 7 UUIDs, proposed by Peabody and Davis in https://www.ietf.org/id/draft-peabody-dispatc

Steve Simmons 22 Dec 20, 2022
A sys-botbase client for remote control automation of Nintendo Switch consoles. Based on SysBot.NET, written in python.

SysBot.py A sys-botbase client for remote control automation of Nintendo Switch consoles. Based on SysBot.NET, written in python. Setup: Download the

7 Dec 16, 2022
jfc is an utility to make reviewing ArXiv papers for your Journal Club easier.

jfc is an utility to make reviewing ArXiv papers for your Journal Club easier.

Miguel M. 3 Dec 20, 2021
Search, generate & deliver Msfvenom payloads in an quick and easy way

Goal Search, generate & deliver payloads in an quick and easy way Be as simple as possible BUT with all msfvenom payloads. Ever lost time searching th

2 Mar 03, 2022
Simple tool for creating changelogs

Description Simple utility for quickly generating changelogs, assuming your commits are ordered as they should be. This tool will simply log all lates

2 Jan 05, 2022
✨ Un code pour voir les disponibilités des vaccins contre le covid totalement fait en Python par moi, et en français.

Vaccine Notifier ❗ Un chois aléatoire d'un article sur Wikipedia totalement fait en Python par moi, et en français. 🔮 Grâce a une requète API, on peu

MrGabin 3 Jun 06, 2021
Dependency injection lib for Python 3.8+

PyDI Dependency injection lib for python How to use To define the classes that should be injected and stored as bean use decorator @component @compone

Nikita Antropov 2 Nov 09, 2021
Go through a random file in your favourite open source projects!

Random Source Codes Never be bored again! Staring at your screen and just scrolling the great world wide web? Would you rather read through some code

Mridul Seth 1 Nov 03, 2022
Python utilities for writing cross-version compatible libraries

Python utilities for writing cross-version compatible libraries

Tyler M. Kontra 85 Jun 29, 2022
Convert any-bit number to decimal number and vise versa.

2deci Convert any-bit number to decimal number and vise versa. --bit n to set bit to n --exp xxx to set expression to xxx --r to run reversely (from d

3 Sep 15, 2021
Runes - Simple Cookies You Can Extend (similar to Macaroons)

Runes - Simple Cookies You Can Extend (similar to Macaroons) is a paper called "Macaroons: Cookies with Context

Rusty Russell 22 Dec 11, 2022
Writing Alfred copy/paste scripts in Python

Writing Alfred copy/paste scripts in Python This repository shows how to create Alfred scripts in Python. It assumes that you using pyenv for Python v

Will Fitzgerald 2 Oct 26, 2021
A (very dirty) experiment to remove layers from a Docker image.

Surgically remove layers from a Docker image (with a chainsaw)

Jérôme Petazzoni 9 Jun 08, 2022
Script to decrypt / import chromium (edge/chrome) cookies

Cloonie Script to decrypt / import chromium (edge/chrome) cookies. Requirements Install the python dependencies via pip: pip install -r requirements.t

Lorenzo Bernardi 5 Sep 13, 2022
✨ Un juste prix totalement fait en Python par moi, et en français.

Juste Prix ❗ Un juste prix totalement fait en Python par moi, et en français. 🔮 Avec l'utilisation du module "random", j'ai pu faire un choix aléatoi

MrGabin 3 Jun 06, 2021
Aggregating gridded data (xarray) to polygons

A package to aggregate gridded data in xarray to polygons in geopandas using area-weighting from the relative area overlaps between pixels and polygons.

Kevin Schwarzwald 42 Nov 09, 2022
Export watched content from Tautulli to the Letterboxd CSV Import Format

Export watched content from Tautulli to the Letterboxd CSV Import Format

Evan J 5 Aug 31, 2022
Exports the local variables into a global dictionary for later debugging.

PyExfiltrator Julia’s @exfiltrate for Python; Exports the local variables into a global dictionary for later debugging. Installation pip install pyexf

6 Nov 07, 2022
convert a dict-list object from / to a typed object(class instance with type annotation)

objtyping 带类型定义的对象转换器 由来 Python不是强类型语言,开发人员没有给数据定义类型的习惯。这样虽然灵活,但处理复杂业务逻辑的时候却不够方便——缺乏类型检查可能导致很难发现错误,在IDE里编码时也没

Song Hui 15 Dec 22, 2022
This tool lets you perform some quick tasks for CTFs and Pentesting.

This tool lets you convert strings and numbers between number bases (2, 8, 10 and 16) as well as ASCII text. You can use the IP address analyzer to find out details on IPv4 and perform abbreviation a

Ayomide Ayodele-Soyebo 1 Jul 16, 2022