Having experience in JavaScript and Python, I wanted to find how to use both and get the benefit from their rich development environment. So I searched many candidates and found python-bridge useful.
In this post, we will learn how to use it with JavaScript async await. You will find that it is easy if you already wrote codes for both languages.
Prerequisite
I will suppose that you already know how to handle packages in Python and JavaScript.
You should read python-bridge repository and follow the examples before you read on this post.
The post about JavaScirpt async programming will help you to understand how to use it greatly.
If you just want to see the entire code first, you can find the end result of this post at pyscript Repository.
Table of Contents
- How python-bridge works
- How to improve the example with async await
- How to use Python packages in JavaScript
- Compare the equivalent JavaScript package with Python package
- Conclusion
1. How python-bridge works
I hope you already invested your time to read the documentation for python-bridge.
The main example for that is
'use strict';
let assert = require('assert');
let pythonBridge = require('python-bridge');
let python = pythonBridge();
python.ex`import math`;
python`math.sqrt(9)`.then(x => assert.equal(x, 3));
let list = [3, 4, 2, 1];
python`sorted(${list})`.then(x => assert.deepEqual(x, list.sort()));
python.end();
If you haven't yet please install the python-bridge package first with these and make a file with the code snippet below.
$yarn add python-bridge
$touch py.js
If you play with it for a while with node py.js
, You will find that the main API of it are python.ex
and python
.
python.ex`import math`;
python`math.sqrt(9)`.then(x => assert.equal(x, 3));
like they were used above.
You can see that it uses JavaScript Promise to consume return value from Python(x in example).
If you have both Node and Python installed in your machine and tested it, you will find it work without problem.
It is also important to notice that we should use ${variable}
syntax to pass variable from JavaScript to Python.
It is reasonable because we are using Python in JavaScript and call data from Python Virtual Machine to Node.
This is already great. You can use Python and its modules inside JavaScript with Promise API.
You can test it with your favorite python modules such as Numpy, Pandas, pyautogui etc at this point or other built in modules if you want.
To do that you have to use $pip -m venv <yourproject>
and $source activate
to activate that virtual env and install the dependencies you want to test first and should be at the same folder where your package.json is located.
2. How to improve the example with async await
You may have found it useful already. But, it is not easy to use only Promise to save and use various datas calculated from Python code and modules such as Numpy and Pandas.
It will be better for us to find how to easily save data from Python as variables and use them inside JavaScript whenever we want.
It is time to use JavaScript async await
syntax like the example below.
// index.js
'use strict';
const assert = require('assert');
const python = require('python-bridge');
const py = python(); // return value
const {
ex, // no return value
end,
} = py;
const list = [3, 4, 2, 1];
ex`import math`
async function pyscript() {
try {
let math = await py`math.sqrt(9)`;
let sort = await py`sorted(${list})`;
assert.eqaul(math, 3);
assert.deepEqual(sort, list.sort());
} catch (e) {
console.log(e)
}
end();
}
(async () => {
pyscript();
console.log("Python works in JavaScript");
})().catch(error => {
console.log("error");
console.error(error);
});
You can see that the example from the previous code became more readable with async await.
We could also separate each value from Python and save it as separate variables.
You can test it with $node py.js and hope it would work well.
I think that you don't need explanation for how async await works here. I hope you already read one that explains it best.
With the above example, you just need await keyword whenever you want to save data from Python as variables. Use them whenever you want later.
With async before function name and await for value from Python Virtual Machine We can pass datas easily between Python and JavaScirpt and use both in the same .js file with python-bridge.
Recently, I had to find the hex value for BigNumber to test ERC20 token and compare it inside test file with JavaScript and it wasn't easy to find that.
So, I thought it will be useful to use what used for this post. If you have somewhat can be done easier in Python than JavaScript it will be better to adapt code used here.
// py.js
const python = require('python-bridge');
const py = python(); // return value
const { end } = py;
async function bigNumberToHex(bigNumber) {
try {
const hexFromBigNumber = await py`hex(${bigNumber})`;
return hexFromBigNumber;
} catch (error) {
console.log("error");
console.error(error);
} finally {
end();
}
}
(async () => {
const hex = await bigNumberToHex(10 ** 10);
console.log(hex);
})().catch(error => {
console.log("error");
console.error(error);
});
You can compare to use node py.js
or test it at your Python console manually similar to the code below or use a website if you can find it.
By having the code used for this post, you will have one more option when you use JavaScript and are familiar with Python already. Then, you will be able to save your time if you can find the right opportunities to use it.
$python3
>>> hex(1000000000000000000000000)
'0xd3c21bcecceda1000000'
>>> hex(1000000000000000000000000000000)
'0xc9f2c9cd04674edea40000000'
>>> hex(1000000000000000000000000000000000)
'0x314dc6448d9338c15b0a00000000'
>>> hex(1000000000000000000000000)
'0xd3c21bcecceda1000000'
>>> 10 ** 26
100000000000000000000000000
>>> hex(_)
'0x52b7d2dcc80cd2e4000000'
3. How to use Python packages in JavaScript
In the previous part, we learnt how to use async await to make the example from the site more usable. But, you can use them also with some well known packages and make the example useful.
So we will include some well-known Python packages in this part.
Numpy, Pandas and pyautogui are used as examples for I think Python is strong in data manipulation and automation and they are main Python package for that.
Let me show you the code first. To use them, you have to install them first and should be at the right location to use test this while venv is activated correctly for the Python packages.
Update your py.js and $node py.js
to test it work.
'use strict';
const python = require('python-bridge');
const py = python(); // It returns value!
const {
ex, // It does not return value!
end,
} = py;
const list = [3, 4, 2, 1];
// <python modules>
ex`import math`;
ex`import pyautogui`;
ex`import numpy as np`;
ex`import pandas`;
// </>
// 1.
function fromPython(pycode = {}) {
return JSON.stringify(pycode);
}
function toJavaScript(pystr = "") {
return JSON.parse(pystr)
}
function fromPy(pycode = {}) {
}
return toJavaScript(fromPython(pycode));
async function pyscript() {
try {
let math = await py`math.sqrt(9)`;
let sort = await py`sorted(${list})`;
// 2.
ex`
value = np.random.randint(0, 7, size = 10)
returnit = pandas.Series(value).tolist()
`;
let returnExample = await py`returnit`; // return value with await and python
console.log(returnExample);
// 3.
const test = (math + sort.reduce((a, c) => a + c, 0))
// 4.
let position = await py`pyautogui.position()`
console.log(position); // object
// 5.
ex`pyautogui.screenshot("test.png")`;
ex`print(str(${test}))`;
ex`pyautogui.typewrite(str(${test}))`;
py`pyautogui.typewrite("show it to me")`;
py`pyautogui.moveTo(${test}, ${math})`;
} catch (e) {
console.log(e)
}
end();
}
(async () => {
await pyscript();
})().catch(error => {
console.log("error");
console.error(error);
});
While playing with this package, I found that everything wouldn't work well magically with the help from the package author.
We should invest our time to find how to use them for our own project.
1. We define some functions to wrap return value from Python inside "" with JSON API or convert it to string type value before they enter JavaScript development environment. What you mainly need will be just fromPy
.(You can either use toString() in JavaScript or str() or other type conversion methods given by Python whenever you meet the type relevant problem.)
2. We test Numpy and Pandas would really work or not. You can see that they work and find that you need to use py
only when you need to return value from Python to JavaScript. Otherwise, you will use ex
mainly.
3. You can see that you can use value from Python and use them freely inside JavaScript.
4. We use pyautogui to get the current position of your mouse cursor. I couldn't find its equivalent in JavaScript packages. You can find that you can use Python packages instead when there is no JavaScript module also.
- We test various API of pyautogui here. I want you to test it in your own machine. You will see that your mouse, keyboard and screenshot all work well. You can use
py
also in some cases when you can useex
also.
The packages and name used here is not important and its your turn to find get the best out of them.
4. Compare the equivalent JavaScript package with Python package
The code used here is just for a prototype. You will be able to find a better way to compare the speed if you are ready to invest your time for.
So you may have found it more useful than me with the example before if you use Python a lot.
But you may wonder that it is worth using Python inside JavaScript when you consider performance and there are similar JavaScript Module.
So we will briefly compare Numpy and Numjs because they serve for the same purpose and have very similar API.
You can save the code snippet below and test it with node py.js
.
'use strict'; // numpy_and_numjs_compare.js
const python = require('python-bridge'); // https://www.npmjs.com/package/python-bridge
const nj = require('numjs'); // www.npmjs.com/package/numjs
const py = python(); // return value
let {
ex, // no return value
end,
} = py;
// <Python Modules>
ex`import numpy as np`;
ex`import pandas`;
// </>
function fromPython(pycode = {}) {
return JSON.stringify(pycode);
}
function toJavaScript(pystr = "") {
return JSON.parse(pystr)
}
function fromPy(pycode = {}) {
return toJavaScript(fromPython(pycode));
}
async function pyscript() {
try {
// If you want, use POSIX command line with $time after you read manual for that $man time
// and tweak the example here
// Test here is to compare time taken to assign return values to variables
// console.log(new Date());
// let testnumpy = fromPy(await py`np.arange(1000).reshape(50, 20).tolist()`);
// console.log(new Date()); // 1.8 ~ 2 seconds
console.log(new Date());
let testnumjs = nj.arange(1000).reshape(50, 20).tolist();
console.log(new Date()); // About 0.05 seconds
} catch (e) { console.log(e) }
end();
}
(async () => {
await pyscript();
})().catch(error => {
console.log("error");
console.error(error);
});
With this simple implementation to compare speed, You will find that it could be better to use JavaScript packages instead of Python packages when there are alternatives for them already.
This doesn't mean that the JavaScript package will be faster than Python and vice versa because with this approach to use Python package, you should wait for the Python return value asynchronously to your Node code also.
For the main purpose of the post is not test and compare speed, I won't find test examples that works with details. If you want, you can make it better.
5. Conclusion
I hope this post to be helpful for someone who wanted to use and write code for Python and JavaScript in the same file.
It was also a trial for me to be more familiar with Python code.
If you liked the post, please share it with others. More posts are coming Follow me here. I am plan to share more blockchain and other stuffs. I am interested in ETH and POLKADOT.
Thanks.
Top comments (1)
Have you heard of Brython? It is a Python 3 implementation for client-side web programming
brython.info/