javascript


Namejavascript JSON
Version 1!1.2.0 PyPI version JSON
download
home_pagehttps://github.com/extremeheat/JSPyBridge
SummaryCall and interop Node.js APIs with Python
upload_time2024-05-11 05:48:19
maintainerNone
docs_urlNone
authorextremeheat
requires_python<4,>=3.7
licenseNone
keywords node javascript bridge development
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # JSPyBridge
[![NPM version](https://img.shields.io/npm/v/pythonia.svg)](http://npmjs.com/package/pythonia)
[![PyPI](https://img.shields.io/pypi/v/javascript)](https://pypi.org/project/javascript/)
[![Build Status](https://github.com/extremeheat/JSPyBridge/actions/workflows/node.yml/badge.svg)](https://github.com/extremeheat/JSPyBridge/actions/workflows/)
[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/extremeheat/jspybridge)


Interoperate Node.js and Python. You can run Python from Node.js, *or* run Node.js from Python. **Work in progress.** 

Requires Node.js 18 and Python 3.8 or newer.

## Key Features

* Ability to call async and sync functions and get object properties with a native feel
* Built-in garbage collection
* Bidirectional callbacks with arbitrary arguments
* Iteration and exception handling support
* Object inspection allows you to easily `console.log` or `print()` any foreign objects
* (Bridge to call Python from JS) Python class extension and inheritance. [See pytorch and tensorflow examples](https://github.com/extremeheat/JSPyBridge/blob/master/examples/javascript/pytorch-train.js).
* (Bridge to call JS from Python) Native decorator-based event emitter support
* (Bridge to call JS from Python) **First-class Jupyter Notebook/Google Colab support.** See some Google Colab uses below.


## Basic usage example

See some examples [here](https://github.com/extremeheat/JSPyBridge/tree/master/examples). See [documentation](https://github.com/extremeheat/JSPyBridge#documentation) below and in [here](https://github.com/extremeheat/JSPyBridge/tree/master/docs).

### Access JavaScript from Python


```sh
pip3 install javascript
```


```py
from javascript import require, globalThis

chalk, fs = require("chalk"), require("fs")

print("Hello", chalk.red("world!"), "it's", globalThis.Date().toLocaleString())
fs.writeFileSync("HelloWorld.txt", "hi!")
```

### Access Python from JavaScript

Make sure to have the dependencies installed before hand!

```sh
npm i pythonia
```

```js
import { python } from 'pythonia'
// Import tkinter
const tk = await python('tkinter')
// All Python API access must be prefixed with await
const root = await tk.Tk()
// A function call with a $ suffix will treat the last argument as a kwarg dict
const a = await tk.Label$(root, { text: 'Hello World' })
await a.pack()
await root.mainloop()
python.exit() // Make sure to exit Python in the end to allow node to exit. You can also use process.exit.
```

### Examples
[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/extremeheat/jspybridge)

Check out some cool examples below! Try them on Gitpod! Click the Open in Gitpod link above, and then open the examples folder.


[![PyTorch](https://www.vectorlogo.zone/logos/pytorch/pytorch-ar21.svg)](https://github.com/extremeheat/JSPyBridge/blob/master/examples/javascript/pytorch-train.js)
[![numpy](https://www.vectorlogo.zone/logos/numpy/numpy-ar21.svg)](https://github.com/extremeheat/JSPyBridge/blob/master/examples/javascript/matplotlib.js)
[![tensorflow](https://www.vectorlogo.zone/logos/tensorflow/tensorflow-ar21.svg)](https://github.com/extremeheat/JSPyBridge/blob/master/examples/javascript/tensorflow.js)
[![mineflayer](https://www.vectorlogo.zone/logos/minecraft/minecraft-ar21.svg)](https://github.com/extremeheat/JSPyBridge/blob/master/examples/python/mineflayer.py)
<!-- <img src="https://matplotlib.org/stable/_static/logo2_compressed.svg" alt="matplotlib" width="120" height="70">
 -->


### Bridge feature comparison

Unlike other bridges, you may notice you're not just writing Python code in JavaScript, or vice-versa. You can operate on objects
on the other side of the bridge as if the objects existed on your side. This is achieved through real interop support: you can call
callbacks, and do loss-less function calls with any arguments you like (with the exception of floating points percision of course).

|  | python(ia) bridge | javascript bridge | [npm:python-bridge](https://www.npmjs.com/package/python-bridge) |
|---|---|---|---|
| Garbage collection | ✔ | ✔ | ❌ |
| Class extension support | ✔ | Not built-in (rare use case), can be manually done with custom proxy | ❌ |
| Passthrough stdin | ❌ (Standard input is not piped to bridge processes. Instead, listen to standard input then expose an API on the other side of the bridge recieve the data.) | ❌ | ✔ |
| Passthrough stdout, stderr | ✔ | ✔ | ✔ |
| Long-running sync calls | ✔ | ✔ | ✔ |
| Long-running async calls | ❌ (need to manually create new thread) | ✔ (AsyncTask) | ❌ (need to manually create new thread) |
| Callbacks | ✔ | ✔ | ❌ |
| Call classes | ✔ | ✔ |  |
| Iterators | ✔ | ✔ | ❌ |
| Inline eval | ✔ | ✔ |  |
| Dependency Management | ❌ | ✔ | ❌ |
| Local File Imports | ✔ | ✔ | ❌ |
| Error Management | ✔ | ✔ | ✔ |
| Object inspection | ✔ | ✔ | ❌ |

## Who's using it
* [PrismarineJS/mineflayer](https://github.com/PrismarineJS/mineflayer) -- [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/PrismarineJS/mineflayer/blob/master/docs/mineflayer.ipynb)

# Documentation

## From Python

You can import the bridge module with 
```py
from javascript import require
```

This will import the require function which you can use just like in Node.js. This is a slightly
modified require function which does dependency management for you. The first paramater is the name
or location of the file to import. Internally, this calls the ES6 dynamic `import()` function. Which
supports both CommonJS and ES6 modules.

If you are passing a module name (does not start with / or include a .) such as 'chalk', it will search 
for the dependency in the internal node_module folder and if not found, install it automatically. 
This install will only happen once, it won't impact startup afterwards.

The second paramater to the built-in require function is the version of the package you want, for
example `require('chalk', '^3')` to get a version greater than major version 3. Just like you would
if you were using `npm install`. It's reccomended to only use the major version as the name and version
will be internally treated as a unique package, for example 'chalk--^3'. If you leave this empty, 
we will install `latest` version instead, or use the version that may already be installed globally.

### Usage

* All function calls to JavaScript are thread synchronous
* ES6 classes can be constructed without new
* ES5 classes can be constructed with the .new psuedo method
* Use `@On` decorator when binding event listeners. Use `off()` to disable it.
* All callbacks run on a dedicated callback thread. DO NOT BLOCK in a callback or all other events will be blocked. Instead:
* Use the @AsyncTask decorator when you need to spawn a new thread for an async JS task.

For more, see [docs/python.md](https://github.com/extremeheat/JSPyBridge/blob/master/docs/python.md).

### Usage

<details>
  <summary>👉 Click here to see some code usage examples 👈</summary>

### Basic import

Let's say we have a file in JS like this called `time.js` ...
```js
function whatTimeIsIt() {
    return (new Date()).toLocaleString()
}
module.exports = { whatTimeIsIt }
```

Then we can call it from Python !
```py
from javascript import require
time = require('./time.js')
print(time.whatTimeIsIt())
```

### Event emitter

*You must use the provided On, Once, decorator and off function over the normal dot methods.*

emitter.js
```js
const { EventEmitter } = require('events')
class MyEmitter extends EventEmitter {
    counter = 0
    inc() {
        this.emit('increment', ++this.counter)
    }
}
module.exports = { MyEmitter }
```

listener.py
```py
from javascript import require, On, off
MyEmitter = require('./emitter.js')
# New class instance
myEmitter = MyEmitter()
# Decorator usage
@On(myEmitter, 'increment')
def handleIncrement(this, counter):
    print("Incremented", counter)
    # Stop listening. `this` is the this variable in JS.
    off(myEmitter, 'increment', handleIncrement)
# Trigger the event handler
myEmitter.inc()
```

### ES5 class

es5.js
```js
function MyClass(num) {
    this.getNum = () => num
}
module.exports = { MyClass }
```


es5.py
```py
MyEmitter = require('./es5.js')
myClass = MyClass.new(3)
print(myClass.getNum())
```

### Iteration
items.js
```js
module.exports = { items: [5, 6, 7, 8] }
```

items.py
```py
items = require('./items.js')
for item in items:
    print(item)
```

### Callback

callback.js
```js
export function method(cb, salt) {
    cb(42 + salt)
}
```
callback.py
```py
method = require('./callback').method
# Example with a lambda, but you can also pass a function ref
method(lambda v: print(v), 2) # Prints 44
```

</details>

## From JavaScript

* All the Python APIs are async. You must await them all. 
* Use `python.exit()` or `process.exit()` at the end to quit the Python process.
* This library doesn't manage the packaging. 
  * Right now you need to install all the deps from pip globally, but later on we may allow loading from pip-envs.
* When you do a normal Python function call, you can supply "positional" arguments, which must 
  be in the correct order to what the Python function expects.
* Some Python objects accept arbitrary keyword arguments. You can call these functions by using
  the special `$` function syntax. 
  * When you do a function call with a `$` before the parenthesis, such as `await some.pythonCall$()`, 
    the final argument is evaluated as a kwarg dictionary. You can supply named arguments this way.
* Property access with a $ at the end acts as a error suppression operator. 
  * Any errors will be ignored and instead undefined will be returned
* See [docs/javascript.md](docs/javascript.md) for more docs, and the examples for more info

### Usage

<details>
  <summary>👉 Click here to see some code usage examples 👈</summary>

### Basic import

Let's say we have a file in Python like this called `time.py` ...
```py
import datetime
def what_time_is_it():
  return str(datetime.datetime.now())
```

Then we can call it from JavaScript !
```js
import { python } from 'pythonia'
const time = await python('./time.py')
console.log("It's", await time.what_time_is_it())
python.exit()
```

### Iterating

* When iterating a Python object, you *must* use a `for await` loop instead of a normal `for-of` loop.

iter.py
```py
import os
def get_files():
  for f in os.listdir():
    yield f
```

iter.js
```js
const iter = await python('./iter.py')
const files = await iter.get_files()
for await (const file of files) {
  console.log(file)
}
```
</details>

## Details

* When doing a function call, any returned foreign objects will be sent to you as a reference. For example, if you're in JavaScript and do a function call to Python that returns an array, you won't get a JS array back, but you will get a reference to the Python array. You can still access the array normally with the [] notation, as long as you use await.

* This behavior makes it very fast to pass objects directly between same-language functions, avoiding costly cross-language data transfers.

* However, this does not apply with callbacks or non-native function input parameters. The bridge will try to serialize what it can, and will give you a foreign reference if it's unable to serialize something. So if you pass a JS object, you'll get a Python dict, but if the dict contains something like a class, you'll get a reference in its place.

* If you would like the bridge to turn a foreign reference to something native, you can use `.valueOf()` to transfer an object via JSON serialization, or `.blobValueOf()` to write an object into the communication pipe directly.
  - `.valueOf()` can be used on any JSON-serializable object, but may be very slow for big data.
  - `.blobValueOf()` can be used on any pipe-writeable object implementing the `length` property (e.g. `Buffer`). It can be massively faster by circumventing the JSON+UTF8 encode/decode layer, which is inept for large byte arrays.

* You can use custom Node.js/Python binary paths by setting the `NODE_BIN` or `PYTHON_BIN` enviornment variables before importing the library. Otherwise, the `node` and `python3` or `python` binaries will be called relative to your PATH enviornment variable. 

* The inter-process communication can be inspected by setting the `DEBUG` env var to `jspybridge`.

#### Limitations

* The `ffid` keyword is reserved. You cannot use it in variable names, object keys or values as this is used to internlly track objects.

* On the bridge to call JavaScript from Python, due to the limiatations of Python and cross-platform IPC, we currently communicate over standard error which means that specific output in JS standard error can interfere with the bridge (as of this writing, the prefices `{"r"` and `blob!` are reserved). A similar issue exists on Windows with Python. You are however very unlikely to have issues with this.

* Function calls will timeout after 100000 ms and throw a `BridgeException` error. That default value can be overridden by defining the new value of `REQ_TIMEOUT` in an environment variable.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/extremeheat/JSPyBridge",
    "name": "javascript",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4,>=3.7",
    "maintainer_email": null,
    "keywords": "node, javascript, bridge, development",
    "author": "extremeheat",
    "author_email": "extreme@protonmail.ch",
    "download_url": "https://files.pythonhosted.org/packages/75/2f/2d9c438f6812812fef0241389a821d8da72c55469b7276f79890ba1b1f4f/javascript-1!1.2.0.tar.gz",
    "platform": null,
    "description": "# JSPyBridge\n[![NPM version](https://img.shields.io/npm/v/pythonia.svg)](http://npmjs.com/package/pythonia)\n[![PyPI](https://img.shields.io/pypi/v/javascript)](https://pypi.org/project/javascript/)\n[![Build Status](https://github.com/extremeheat/JSPyBridge/actions/workflows/node.yml/badge.svg)](https://github.com/extremeheat/JSPyBridge/actions/workflows/)\n[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/extremeheat/jspybridge)\n\n\nInteroperate Node.js and Python. You can run Python from Node.js, *or* run Node.js from Python. **Work in progress.** \n\nRequires Node.js 18 and Python 3.8 or newer.\n\n## Key Features\n\n* Ability to call async and sync functions and get object properties with a native feel\n* Built-in garbage collection\n* Bidirectional callbacks with arbitrary arguments\n* Iteration and exception handling support\n* Object inspection allows you to easily `console.log` or `print()` any foreign objects\n* (Bridge to call Python from JS) Python class extension and inheritance. [See pytorch and tensorflow examples](https://github.com/extremeheat/JSPyBridge/blob/master/examples/javascript/pytorch-train.js).\n* (Bridge to call JS from Python) Native decorator-based event emitter support\n* (Bridge to call JS from Python) **First-class Jupyter Notebook/Google Colab support.** See some Google Colab uses below.\n\n\n## Basic usage example\n\nSee some examples [here](https://github.com/extremeheat/JSPyBridge/tree/master/examples). See [documentation](https://github.com/extremeheat/JSPyBridge#documentation) below and in [here](https://github.com/extremeheat/JSPyBridge/tree/master/docs).\n\n### Access JavaScript from Python\n\n\n```sh\npip3 install javascript\n```\n\n\n```py\nfrom javascript import require, globalThis\n\nchalk, fs = require(\"chalk\"), require(\"fs\")\n\nprint(\"Hello\", chalk.red(\"world!\"), \"it's\", globalThis.Date().toLocaleString())\nfs.writeFileSync(\"HelloWorld.txt\", \"hi!\")\n```\n\n### Access Python from JavaScript\n\nMake sure to have the dependencies installed before hand!\n\n```sh\nnpm i pythonia\n```\n\n```js\nimport { python } from 'pythonia'\n// Import tkinter\nconst tk = await python('tkinter')\n// All Python API access must be prefixed with await\nconst root = await tk.Tk()\n// A function call with a $ suffix will treat the last argument as a kwarg dict\nconst a = await tk.Label$(root, { text: 'Hello World' })\nawait a.pack()\nawait root.mainloop()\npython.exit() // Make sure to exit Python in the end to allow node to exit. You can also use process.exit.\n```\n\n### Examples\n[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/extremeheat/jspybridge)\n\nCheck out some cool examples below! Try them on Gitpod! Click the Open in Gitpod link above, and then open the examples folder.\n\n\n[![PyTorch](https://www.vectorlogo.zone/logos/pytorch/pytorch-ar21.svg)](https://github.com/extremeheat/JSPyBridge/blob/master/examples/javascript/pytorch-train.js)\n[![numpy](https://www.vectorlogo.zone/logos/numpy/numpy-ar21.svg)](https://github.com/extremeheat/JSPyBridge/blob/master/examples/javascript/matplotlib.js)\n[![tensorflow](https://www.vectorlogo.zone/logos/tensorflow/tensorflow-ar21.svg)](https://github.com/extremeheat/JSPyBridge/blob/master/examples/javascript/tensorflow.js)\n[![mineflayer](https://www.vectorlogo.zone/logos/minecraft/minecraft-ar21.svg)](https://github.com/extremeheat/JSPyBridge/blob/master/examples/python/mineflayer.py)\n<!-- <img src=\"https://matplotlib.org/stable/_static/logo2_compressed.svg\" alt=\"matplotlib\" width=\"120\" height=\"70\">\n -->\n\n\n### Bridge feature comparison\n\nUnlike other bridges, you may notice you're not just writing Python code in JavaScript, or vice-versa. You can operate on objects\non the other side of the bridge as if the objects existed on your side. This is achieved through real interop support: you can call\ncallbacks, and do loss-less function calls with any arguments you like (with the exception of floating points percision of course).\n\n|  | python(ia) bridge | javascript bridge | [npm:python-bridge](https://www.npmjs.com/package/python-bridge) |\n|---|---|---|---|\n| Garbage collection | \u2714 | \u2714 | \u274c |\n| Class extension support | \u2714 | Not built-in (rare use case), can be manually done with custom proxy | \u274c |\n| Passthrough stdin | \u274c (Standard input is not piped to bridge processes. Instead, listen to standard input then expose an API on the other side of the bridge recieve the data.) | \u274c | \u2714 |\n| Passthrough stdout, stderr | \u2714 | \u2714 | \u2714 |\n| Long-running sync calls | \u2714 | \u2714 | \u2714 |\n| Long-running async calls | \u274c (need to manually create new thread) | \u2714 (AsyncTask) | \u274c (need to manually create new thread) |\n| Callbacks | \u2714 | \u2714 | \u274c |\n| Call classes | \u2714 | \u2714 |  |\n| Iterators | \u2714 | \u2714 | \u274c |\n| Inline eval | \u2714 | \u2714 |  |\n| Dependency Management | \u274c | \u2714 | \u274c |\n| Local File Imports | \u2714 | \u2714 | \u274c |\n| Error Management | \u2714 | \u2714 | \u2714 |\n| Object inspection | \u2714 | \u2714 | \u274c |\n\n## Who's using it\n* [PrismarineJS/mineflayer](https://github.com/PrismarineJS/mineflayer) -- [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/PrismarineJS/mineflayer/blob/master/docs/mineflayer.ipynb)\n\n# Documentation\n\n## From Python\n\nYou can import the bridge module with \n```py\nfrom javascript import require\n```\n\nThis will import the require function which you can use just like in Node.js. This is a slightly\nmodified require function which does dependency management for you. The first paramater is the name\nor location of the file to import. Internally, this calls the ES6 dynamic `import()` function. Which\nsupports both CommonJS and ES6 modules.\n\nIf you are passing a module name (does not start with / or include a .) such as 'chalk', it will search \nfor the dependency in the internal node_module folder and if not found, install it automatically. \nThis install will only happen once, it won't impact startup afterwards.\n\nThe second paramater to the built-in require function is the version of the package you want, for\nexample `require('chalk', '^3')` to get a version greater than major version 3. Just like you would\nif you were using `npm install`. It's reccomended to only use the major version as the name and version\nwill be internally treated as a unique package, for example 'chalk--^3'. If you leave this empty, \nwe will install `latest` version instead, or use the version that may already be installed globally.\n\n### Usage\n\n* All function calls to JavaScript are thread synchronous\n* ES6 classes can be constructed without new\n* ES5 classes can be constructed with the .new psuedo method\n* Use `@On` decorator when binding event listeners. Use `off()` to disable it.\n* All callbacks run on a dedicated callback thread. DO NOT BLOCK in a callback or all other events will be blocked. Instead:\n* Use the @AsyncTask decorator when you need to spawn a new thread for an async JS task.\n\nFor more, see [docs/python.md](https://github.com/extremeheat/JSPyBridge/blob/master/docs/python.md).\n\n### Usage\n\n<details>\n  <summary>\ud83d\udc49 Click here to see some code usage examples \ud83d\udc48</summary>\n\n### Basic import\n\nLet's say we have a file in JS like this called `time.js` ...\n```js\nfunction whatTimeIsIt() {\n    return (new Date()).toLocaleString()\n}\nmodule.exports = { whatTimeIsIt }\n```\n\nThen we can call it from Python !\n```py\nfrom javascript import require\ntime = require('./time.js')\nprint(time.whatTimeIsIt())\n```\n\n### Event emitter\n\n*You must use the provided On, Once, decorator and off function over the normal dot methods.*\n\nemitter.js\n```js\nconst { EventEmitter } = require('events')\nclass MyEmitter extends EventEmitter {\n    counter = 0\n    inc() {\n        this.emit('increment', ++this.counter)\n    }\n}\nmodule.exports = { MyEmitter }\n```\n\nlistener.py\n```py\nfrom javascript import require, On, off\nMyEmitter = require('./emitter.js')\n# New class instance\nmyEmitter = MyEmitter()\n# Decorator usage\n@On(myEmitter, 'increment')\ndef handleIncrement(this, counter):\n    print(\"Incremented\", counter)\n    # Stop listening. `this` is the this variable in JS.\n    off(myEmitter, 'increment', handleIncrement)\n# Trigger the event handler\nmyEmitter.inc()\n```\n\n### ES5 class\n\nes5.js\n```js\nfunction MyClass(num) {\n    this.getNum = () => num\n}\nmodule.exports = { MyClass }\n```\n\n\nes5.py\n```py\nMyEmitter = require('./es5.js')\nmyClass = MyClass.new(3)\nprint(myClass.getNum())\n```\n\n### Iteration\nitems.js\n```js\nmodule.exports = { items: [5, 6, 7, 8] }\n```\n\nitems.py\n```py\nitems = require('./items.js')\nfor item in items:\n    print(item)\n```\n\n### Callback\n\ncallback.js\n```js\nexport function method(cb, salt) {\n    cb(42 + salt)\n}\n```\ncallback.py\n```py\nmethod = require('./callback').method\n# Example with a lambda, but you can also pass a function ref\nmethod(lambda v: print(v), 2) # Prints 44\n```\n\n</details>\n\n## From JavaScript\n\n* All the Python APIs are async. You must await them all. \n* Use `python.exit()` or `process.exit()` at the end to quit the Python process.\n* This library doesn't manage the packaging. \n  * Right now you need to install all the deps from pip globally, but later on we may allow loading from pip-envs.\n* When you do a normal Python function call, you can supply \"positional\" arguments, which must \n  be in the correct order to what the Python function expects.\n* Some Python objects accept arbitrary keyword arguments. You can call these functions by using\n  the special `$` function syntax. \n  * When you do a function call with a `$` before the parenthesis, such as `await some.pythonCall$()`, \n    the final argument is evaluated as a kwarg dictionary. You can supply named arguments this way.\n* Property access with a $ at the end acts as a error suppression operator. \n  * Any errors will be ignored and instead undefined will be returned\n* See [docs/javascript.md](docs/javascript.md) for more docs, and the examples for more info\n\n### Usage\n\n<details>\n  <summary>\ud83d\udc49 Click here to see some code usage examples \ud83d\udc48</summary>\n\n### Basic import\n\nLet's say we have a file in Python like this called `time.py` ...\n```py\nimport datetime\ndef what_time_is_it():\n  return str(datetime.datetime.now())\n```\n\nThen we can call it from JavaScript !\n```js\nimport { python } from 'pythonia'\nconst time = await python('./time.py')\nconsole.log(\"It's\", await time.what_time_is_it())\npython.exit()\n```\n\n### Iterating\n\n* When iterating a Python object, you *must* use a `for await` loop instead of a normal `for-of` loop.\n\niter.py\n```py\nimport os\ndef get_files():\n  for f in os.listdir():\n    yield f\n```\n\niter.js\n```js\nconst iter = await python('./iter.py')\nconst files = await iter.get_files()\nfor await (const file of files) {\n  console.log(file)\n}\n```\n</details>\n\n## Details\n\n* When doing a function call, any returned foreign objects will be sent to you as a reference. For example, if you're in JavaScript and do a function call to Python that returns an array, you won't get a JS array back, but you will get a reference to the Python array. You can still access the array normally with the [] notation, as long as you use await.\n\n* This behavior makes it very fast to pass objects directly between same-language functions, avoiding costly cross-language data transfers.\n\n* However, this does not apply with callbacks or non-native function input parameters. The bridge will try to serialize what it can, and will give you a foreign reference if it's unable to serialize something. So if you pass a JS object, you'll get a Python dict, but if the dict contains something like a class, you'll get a reference in its place.\n\n* If you would like the bridge to turn a foreign reference to something native, you can use `.valueOf()` to transfer an object via JSON serialization, or `.blobValueOf()` to write an object into the communication pipe directly.\n  - `.valueOf()` can be used on any JSON-serializable object, but may be very slow for big data.\n  - `.blobValueOf()` can be used on any pipe-writeable object implementing the `length` property (e.g. `Buffer`). It can be massively faster by circumventing the JSON+UTF8 encode/decode layer, which is inept for large byte arrays.\n\n* You can use custom Node.js/Python binary paths by setting the `NODE_BIN` or `PYTHON_BIN` enviornment variables before importing the library. Otherwise, the `node` and `python3` or `python` binaries will be called relative to your PATH enviornment variable. \n\n* The inter-process communication can be inspected by setting the `DEBUG` env var to `jspybridge`.\n\n#### Limitations\n\n* The `ffid` keyword is reserved. You cannot use it in variable names, object keys or values as this is used to internlly track objects.\n\n* On the bridge to call JavaScript from Python, due to the limiatations of Python and cross-platform IPC, we currently communicate over standard error which means that specific output in JS standard error can interfere with the bridge (as of this writing, the prefices `{\"r\"` and `blob!` are reserved). A similar issue exists on Windows with Python. You are however very unlikely to have issues with this.\n\n* Function calls will timeout after 100000 ms and throw a `BridgeException` error. That default value can be overridden by defining the new value of `REQ_TIMEOUT` in an environment variable.\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Call and interop Node.js APIs with Python",
    "version": "1!1.2.0",
    "project_urls": {
        "Bug Reports": "https://github.com/extremeheat/JSPyBridge/issues",
        "Homepage": "https://github.com/extremeheat/JSPyBridge",
        "Say Thanks!": "https://github.com/extremeheat/JSPyBridge",
        "Source": "https://github.com/extremeheat/JSPyBridge/"
    },
    "split_keywords": [
        "node",
        " javascript",
        " bridge",
        " development"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "094c7e1d0e14aa12647e19c870f6f2dc1626eed0368b87865a64378a6be19a8d",
                "md5": "43aab16d06a263252fcb083cbb56f680",
                "sha256": "9d1578ab68ab1901d110619fcad9acb20af3da22e692e78ab72abef74781c526"
            },
            "downloads": -1,
            "filename": "javascript-1!1.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "43aab16d06a263252fcb083cbb56f680",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4,>=3.7",
            "size": 34268,
            "upload_time": "2024-05-11T05:48:17",
            "upload_time_iso_8601": "2024-05-11T05:48:17.584303Z",
            "url": "https://files.pythonhosted.org/packages/09/4c/7e1d0e14aa12647e19c870f6f2dc1626eed0368b87865a64378a6be19a8d/javascript-1!1.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "752f2d9c438f6812812fef0241389a821d8da72c55469b7276f79890ba1b1f4f",
                "md5": "e07501a6688c6d205d51d76f5851c22d",
                "sha256": "a07650bba1d5b557a63010ea5bf9116cd08b40af414d786b6a34889dffcd1d59"
            },
            "downloads": -1,
            "filename": "javascript-1!1.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "e07501a6688c6d205d51d76f5851c22d",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4,>=3.7",
            "size": 38054,
            "upload_time": "2024-05-11T05:48:19",
            "upload_time_iso_8601": "2024-05-11T05:48:19.108954Z",
            "url": "https://files.pythonhosted.org/packages/75/2f/2d9c438f6812812fef0241389a821d8da72c55469b7276f79890ba1b1f4f/javascript-1!1.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-05-11 05:48:19",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "extremeheat",
    "github_project": "JSPyBridge",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "javascript"
}
        
Elapsed time: 0.27888s