Call Python packages in JavaScript.

Overview

boa

Introduction to Boa

Boa is the Python Bridge Layer in Pipcook, it lets you call Python functions seamlessly in Node.js, it delivers any Python module for Node.js developer in lower-cost to learn or use.

Quick Start

Install Boa from npm:

$ npm install @pipcook/boa

Let's have a glance on how to call to Python's function:

const boa = require('@pipcook/boa');
const os = boa.import('os');
console.log(os.getpid()); // prints the pid from python.

// using keyword arguments namely `kwargs`
os.makedirs('..', boa.kwargs({
  mode: 0x777,
  exist_ok: false,
}));

// using bult-in functions
const { range, len } = boa.builtins();
const list = range(0, 10); // create a range array
console.log(len(list)); // 10
console.log(list[2]); // 2

Install Python Package

By default, Boa will install a conda virtual environment under the path of the Boa package. To make it easier to install python libraries, you can run:

$ ./node_modules/.bin/bip install <package-name>

bip is an alias of pip that points to the correct Python environment.

API References

A Connection between 2 languages(ecosystems) has huge works to be done, even though this package is working only on the unilateral from Python to JavaScript. The most difficult part is that for developers, they need to understand the correspondence between the two languages and ecosystems. Therefore, a good design principle will make developers reduce learning costs.

boa

require('@pipcook/boa') returns the root object, which will be your entry point to all Python functions, and it provides these methods:

.builtins()

Gets the Python's built-in functions, for example:

const { len, range } = boa.builtins();
len([1, 2, 3]); // 3
len(range(0, 10)); // 10

.import(mod)

Imports a Python module in your current environment, the module includes:

  • system modules like os, string and re.
  • third-party modules like numpy and request via pip.

To call the function, you should pass a mod argument for the module that you want to import.

const os = boa.import('os');
const str = boa.import('string');
const numpy = boa.import('numpy');

This returns an instance of PythonObjectWrapper or a JavaScript primitive value for some special cases.

.kwargs(map)

Creates a Python's keyword arguments, Python provides a way to map arguments with names:

fs.open('./a-file-to-open', mode=0e777)

Correspondingly, this function is used to represent a keyword arguments, and the specific usage is very easy to understand:

const fs = boa.import('fs');
fs.open('./a-file-to-open', boa.kwargs({ mode: 0e777 }));

.with(ctx, fn)

It's equivalent to the with-statement in Python, this would be called with an object ctx that supports the context management protocol (that is, has __enter__() and __exit__() methods). And 2nd fn is corresponding to the execution block, A simple example is as follows:

boa.with(localcontext(), (ctx) => {
  // execution
  // the ctx is localcontext().__enter().
});

.eval(str)

Execute Python expression in the context specified, here is a simple call:

boa.eval('len([10, 20])');
// 2

Alternatively, developers can use tagged template literal to pass variables that have been defined in JavaScript:

const elem = np.array([[1, 2, 3], [4, 5, 6]], np.int32);
boa.eval`${elem} + 100`;  // do matrix + operation
boa.eval`len(${elem})`;   // equivalent to `len(elem)`

For multi-line code, Python 3 does not provide a mechanism to return a value, so the eval function can only handle single-line Python expressions.

.bytes(str)

A shortcut to create a Python's bytes literal from JavaScript string, it's equivalent to b'foobar' in Python.

const { bytes } = boa;
bytes('foobar'); // "b'foobar'"

The bytes(str) function simply creates a plain object that is used to pass a string to a Python function as a bytes literal, but does not correspond to any Python object itself. Alternatively, you could use Python's builtin class bytes for creating a real object:

const { bytes } = boa.builtins();
const foobar = Buffer.from('foobar');
bytes.fromhex(foobar.toString('hex'));
// "b'foobar'"

Class PythonObjectWrapper

This class represents a wrapper for the corresponding object in Python runtime, it must be returned only from boa methods like boa.builtins and boa.import.

creation of instance

In order for developers to use Python objects seamlessly, creating a PythonObjectWrapper requires some necessary steps.

First, check the type of the Python object under instance. If it is one of the following types, it will be converted to the corresponding primitive type.

python type primitive
int,float number
int64 bigint
float64 bigdecimal
bool boolean
str string
NoneType null

If the type of the object that needs to be wrapped is not in the above primitive, a temporary object will be created, and methods and properties will be defined through Object.defineProperties.

On an instance of PythonObjectWrapper, developers can directly obtain values through the property way, just like using those in Python. This is because we use ES6 Proxy, so the last step, we created a Proxy Object, configured with 3 trap handlers, get, set, apply, and finally returns this proxy object.

property accessor

At Python language, an object has attr and item accessors, and they use different expressions:

  • x.y is for attr accessor
  • m[n] is for item accessor

Unfortunately, ES6 Proxy does not distinguish the above things. Therefore, it's needed to define an algorithm to confirm their priority in a time of operation.

  • given a name variable which is passed by ES6 Proxy's get handler.
  • check the name property is owned by the JavaScript object via .hasOwnProperty().
    • return the property if it's truthy.
  • check the name property is owned by the object's class via .constructor.prototype.hasOwnProperty().
    • return the property if it's truthy.
  • check if name is a numeric representation.
    • if it's truthy, call the internal method .__getitem__(i) for item accessor.
    • otherwise
      • try to access the attr via the internal method .__getattr__().
      • try to access the item via the internal method .__getitem__().
      • otherwise, return undefined.

To better understand the algorithm above, let's look at some examples:

const boa = require('@pipcook/boa');
const { abs, tuple } = boa.builtins();

{
  console.log(abs(-100));  // 100
  console.log(abs(100));   // 100
}
{
  const re = boa.import('re');
  const m = re.search('(?<=abc)def', 'abcdef');
  console.log(m.group(0)); // 'def'
}
{
  // make sure the `numpy` is in your current python env.
  const np = boa.import('numpy');
  const x0 = np.array([[1, 2, 3], [4, 5, 6]], np.int32);
  const x1 = np.arange(15).reshape(3, 5);
  const x2 = np.zeros(tuple([3, 4]));
}

As mentioned above, in addition to dynamically obtaining objects from the Python runtime, the class PythonObjectWrapper also defines the following public methods built into JavaScript.

.prototype.toString()

Returns a string for representing the object, internally it calls the CPython's PyObject_Str.

console.log(boa.import('os').toString());
// "<module 'os' from '/usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/lib/python3.7/os.py'>"

.prototype.slice(start, stop, step)

Returns a new wrapped slice object, it's equivalent to s[start:stop:step]. For example:

const { range } = boa.builtins();
const mlist = range(0, 10); // [0...10]
const s = mlist.slice(2, 10, 1); // [2...10]

Note: a new tc39 proposal slice notation attempts to add this kind of syntax, it'll be merged when it's land on v8 engine. Or try with eval in Python's syntax:

boa.eval`${mlist}[0...10]`
boa.eval`${mlist}[1:10:2]`

.prototype.__hash__()

Returns the hash value of this object, internally it calls the CPython's PyObject_Hash.

Magic methods there are some others like __getitem__, __setitem__, __getattr__, __setattr__ which are used internally in this library, it's not recommended to actively use them at user-land.

.prototype[Symbol.toPrimitive](hint)

Returns a corresponding primitive value for this object, see Symbol.toPrimitive on MDN for more details.

Working with ECMAScript Modules

Requires Node.js >= v12.11.1

Use Node.js custom loader for better import-statement.

// app.mjs
import { range, len } from 'py:builtins';
import os from 'py:os';
import {
  array as NumpyArray,
  int32 as NumpyInt32,
} from 'py:numpy';

console.log(os.getpid()); // prints the pid from python.

const list = range(0, 10); // create a range array
console.log(len(list)); // 10
console.log(list[2]); // 2

const arr = NumpyArray([1, 2, 3], NumpyInt32); // Create an array of int32 using ndarry constructor
console.log(arr[0]); // 1

In Node.js v14.x you can specify only --experimental-loader to launch your application:

$ node --experimental-loader @pipcook/boa/esm/loader.mjs app.mjs

In Node.js version < v14.x, you also need to add the --experimental-modules option:

$ node --experimental-modules --experimental-loader @pipcook/boa/esm/loader.mjs app.mjs

Generators

The package is able to handle the Python generator in JavaScript directly:

# Write a Python Generator in count_down.py
def count_down(count):
  while count >= 0:
    yield count
    count -= 1

The above code will take a number and keep yielding and decreasing the value until 0.

const boa = require('@pipcook/boa')
const countDown = boa.import('count_down')
const generator = countDown(3); // Generator

// You can use typical next syntax
let curr = generator.next();

while (curr.done) {
  console.log(curr.value); // 3 2 1 0
  curr = generator.next()
}

Or use the syntactic suger:

const boa = require('@pipcook/boa')
const countDown = boa.import('count_down')
const generator = countDown(3); // Generator

// Or access data via the following syntax
for (const element of generator) {
  console.log(element) // 3 2 1 0
}

Python functions in worker_threads

The @pipcook/boa package calls Python function in blocking way, which is because of the Python(CPython)'s object model is not thread-safe, thus Python limits to run Python functions in different threads.

However the @pipcook/boa package allows running Python function in another thread with Node.js worker_threads, an non-blocking example is:

const { Worker, isMainThread, workerData, parentPort } = require('worker_threads');
const boa = require('@pipcook/boa');
const pybasic = boa.import('tests.base.basic'); // a Python example
const { SharedPythonObject, symbols } = boa;

class Foobar extends pybasic.Foobar {
  hellomsg(x) {
    return `hello <${x}> on ${this.test}(${this.count})`;
  }
}

if (isMainThread) {
  const foo = new Foobar();
  const worker = new Worker(__filename, {
    workerData: {
      foo: new SharedPythonObject(foo),
    },
  });
  let alive = setInterval(() => {
    const ownership = foo[symbols.GetOwnershipSymbol]();
    console.log(`ownership should be ${expectedOwnership}.`);
  }, 1000);

  worker.on('message', state => {
    if (state === 'done') {
      console.log('task is completed');
      setTimeout(() => {
        clearInterval(alive);
        console.log(foo.ping('x'));
      }, 1000);
    }
  });
} else {
  const { foo } = workerData;
  console.log(`worker: get an object${foo} and sleep 5s in Python`);
  foo.sleep(); // this is a blocking function which is implemented at Python to sleep 1s
  
  console.log('python sleep is done, and sleep in nodejs(thread)');
  setTimeout(() => parentPort.postMessage('done'), 1000);
}

In the new sub-thread created by worker_threads, the @pipcook/boa won't create the new interrupter, it means all the threads by Node.js shares the same Python interpreter to avoid the Python GIL.

To make sure the thread-safty works, we introduce a SharedPythonObject class to share the Python objects between threads via the following:

// main thread
const foo = new Foobar(); // Python object
const worker = new Worker(__filename, {
  workerData: {
    foo: new SharedPythonObject(foo),
  },
});

// worker thread
const { workerData } = require('worker_threads');
const boa = require('@pipcook/boa');
console.log(workerData.foo);

The SharedPythonObject accepts a Python object created by @pipcook/boa, once created, the original object won't be used util the worker thread exits, this is to make sure the thread-safty of the shared objects, it means an object could only be used by worker or main thread at the same time.

Build from source

# clone this project firstly.
$ npm install
$ npm run build

Verify if the generated library is linked to correct Python version

When buidling finished, use objdump -macho -dylibs-used ./build/Release/boa.node to check if your linked libs are correct as:

/build/Release/boa.node:
  /usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/Python (compatibility version 3.7.0, current version 3.7.0)
  /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
  /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)

See ./tests for more testing details.

Build Tests

To run the full tests:

$ npm test

Virtual Environment for Python

If you are using virtualenv or conda, you can just set up your system environment PYTHONPATH to point to your site-packages folder. For instance:

$ export PYTHONPATH = /Users/venv/lib/python3.7/site-packages

License

Apache 2.0

Comments
  • Fix tests for memory leak patch

    Fix tests for memory leak patch

    @rickycao-qy I have been looking into #10 and saw that you had a fix for it prepared in #12.

    I've spent some time getting the tests to pass locally. Would you be able to take a look for me?

    Thanks, Matt

    opened by mattseddon 6
  • 远程部署发生错误。

    远程部署发生错误。

    通过pm2 deploy方式在服务器上部署服务,执行npm install的时候提示这个错误。 之前也尝试过在heroku上部署这一服务,也是在执行到npm install的时候发生了这一错误。

    npm ERR! code 1 npm ERR! path /www/wwwroot/yazi/source/node_modules/@pipcook/boa npm ERR! command failed npm ERR! command sh -c node-gyp rebuild npm ERR! gyp info it worked if it ends with ok npm ERR! gyp info using [email protected] npm ERR! gyp info using [email protected] | linux | x64 npm ERR! gyp info find Python using Python version 3.8.10 found at "/usr/bin/python3" npm ERR! gyp info spawn /usr/bin/python3 npm ERR! gyp info spawn args [ npm ERR! gyp info spawn args '/www/server/nvm/versions/node/v14.17.6/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py', npm ERR! gyp info spawn args 'binding.gyp', npm ERR! gyp info spawn args '-f', npm ERR! gyp info spawn args 'make', npm ERR! gyp info spawn args '-I', npm ERR! gyp info spawn args '/www/wwwroot/yazi/source/node_modules/@pipcook/boa/build/config.gypi', npm ERR! gyp info spawn args '-I', npm ERR! gyp info spawn args '/www/server/nvm/versions/node/v14.17.6/lib/node_modules/npm/node_modules/node-gyp/addon.gypi', npm ERR! gyp info spawn args '-I', npm ERR! gyp info spawn args '/root/.cache/node-gyp/14.17.6/include/node/common.gypi', npm ERR! gyp info spawn args '-Dlibrary=shared_library', npm ERR! gyp info spawn args '-Dvisibility=default', npm ERR! gyp info spawn args '-Dnode_root_dir=/root/.cache/node-gyp/14.17.6', npm ERR! gyp info spawn args '-Dnode_gyp_dir=/www/server/nvm/versions/node/v14.17.6/lib/node_modules/npm/node_modules/node-gyp', npm ERR! gyp info spawn args '-Dnode_lib_file=/root/.cache/node-gyp/14.17.6/<(target_arch)/node.lib', npm ERR! gyp info spawn args '-Dmodule_root_dir=/www/wwwroot/yazi/source/node_modules/@pipcook/boa', npm ERR! gyp info spawn args '-Dnode_engine=v8', npm ERR! gyp info spawn args '--depth=.', npm ERR! gyp info spawn args '--no-parallel', npm ERR! gyp info spawn args '--generator-output', npm ERR! gyp info spawn args 'build', npm ERR! gyp info spawn args '-Goutput_dir=.' npm ERR! gyp info spawn args ] npm ERR! internal/fs/utils.js:314 npm ERR! throw err; npm ERR! ^ npm ERR! npm ERR! Error: ENOENT: no such file or directory, open '/www/wwwroot/yazi/source/node_modules/@pipcook/boa/.CONDA_INSTALL_DIR' npm ERR! at Object.openSync (fs.js:498:3) npm ERR! at Object.readFileSync (fs.js:394:35) npm ERR! at Object.getCondaPath (/www/wwwroot/yazi/source/node_modules/@pipcook/boa/tools/utils.js:31:23) npm ERR! at Object.getPythonHeaderPath (/www/wwwroot/yazi/source/node_modules/@pipcook/boa/tools/utils.js:43:18) npm ERR! at [eval]:1:26 npm ERR! at Script.runInThisContext (vm.js:134:12) npm ERR! at Object.runInThisContext (vm.js:310:38) npm ERR! at internal/process/execution.js:81:19 npm ERR! at [eval]-wrapper:6:22 npm ERR! at evalScript (internal/process/execution.js:80:60) { npm ERR! errno: -2, npm ERR! syscall: 'open', npm ERR! code: 'ENOENT', npm ERR! path: '/www/wwwroot/yazi/source/node_modules/@pipcook/boa/.CONDA_INSTALL_DIR' npm ERR! } npm ERR! gyp: Call to 'node -p "require('./tools/utils').getPythonHeaderPath()"' returned exit status 1 while in binding.gyp. while trying to load binding.gyp npm ERR! gyp ERR! configure error npm ERR! gyp ERR! stack Error: gyp failed with exit code: 1 npm ERR! gyp ERR! stack at ChildProcess.onCpExit (/www/server/nvm/versions/node/v14.17.6/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:351:16) npm ERR! gyp ERR! stack at ChildProcess.emit (events.js:400:28) npm ERR! gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:277:12) npm ERR! gyp ERR! System Linux 5.11.0-1017-gcp npm ERR! gyp ERR! command "/www/server/nvm/versions/node/v14.17.6/bin/node" "/www/server/nvm/versions/node/v14.17.6/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild" npm ERR! gyp ERR! cwd /www/wwwroot/yazi/source/node_modules/@pipcook/boa npm ERR! gyp ERR! node -v v14.17.6 npm ERR! gyp ERR! node-gyp -v v7.1.2 npm ERR! gyp ERR! not ok

    npm ERR! A complete log of this run can be found in: npm ERR! /root/.npm/_logs/2021-09-04T06_01_55_284Z-debug.log

    post-deploy hook failed

    Deploy failed Deploy failed with exit code: 1

    opened by zooPanda 1
  • WARNING: pip is being invoked by an old script wrapper

    WARNING: pip is being invoked by an old script wrapper

    When I run bip install I get the following warning:

    WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
    Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
    To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
    

    This happens with pip==21.0.1

    opened by AbdealiLoKo 1
  • bip install mysqlclient - Python.h: No such file or directory

    bip install mysqlclient - Python.h: No such file or directory

    Hi, was trying to use boa to call some of my python scripts. My python script connects to MySQL in some cases.

    Got the following error when I try to install mysqlclient with bip:

    $ ./node_modules/.bin/bip install mysqlclient
    sh "/home/abdealijk/node_modules/@pipcook/boa/binding/v6/bin/python /home/abdealijk/node_modules/@pipcook/boa/binding/v6/bin/pip install mysqlclient"
    Collecting mysqlclient
      Using cached https://files.pythonhosted.org/packages/3c/df/59cd2fa5e48d0804d213bdcb1acb4d08c403b61c7ff7ed4dd4a6a2deb3f7/mysqlclient-2.0.3.tar.gz
    Building wheels for collected packages: mysqlclient
      Building wheel for mysqlclient (setup.py) ... error
      ERROR: Command errored out with exit status 1:
    ....
        Running setup.py install for mysqlclient ... error
        ERROR: Command errored out with exit status 1:
         command: /home/abdealijk/node_modules/@pipcook/boa/binding/v6/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-zhzlp_0p/mysqlclient/setup.py'"'"'; __file__='"'"'/tmp/pip-install-zhzlp_0p/mysqlclient/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-_xhxik_q/install-record.txt --single-version-externally-managed --compile
             cwd: /tmp/pip-install-zhzlp_0p/mysqlclient/
        Complete output (44 lines):
        mysql_config --version
        ['5.7.30']
        mysql_config --libs
        ['-L/usr/lib/x86_64-linux-gnu', '-lmysqlclient', '-lpthread', '-lz', '-lm', '-lrt', '-latomic', '-lssl', '-lcrypto', '-ldl']
        mysql_config --cflags
        ['-I/usr/include/mysql']
        ext_options:
          library_dirs: ['/usr/lib/x86_64-linux-gnu']
          libraries: ['mysqlclient', 'pthread', 'm', 'rt', 'atomic', 'dl']
          extra_compile_args: ['-std=c99']
          extra_link_args: []
          include_dirs: ['/usr/include/mysql']
          extra_objects: []
          define_macros: [('version_info', "(2,0,3,'final',0)"), ('__version__', '2.0.3')]
        running install
        running build
        running build_py
        creating build
        creating build/lib.linux-x86_64-3.7
        creating build/lib.linux-x86_64-3.7/MySQLdb
        copying MySQLdb/__init__.py -> build/lib.linux-x86_64-3.7/MySQLdb
        copying MySQLdb/_exceptions.py -> build/lib.linux-x86_64-3.7/MySQLdb
        copying MySQLdb/connections.py -> build/lib.linux-x86_64-3.7/MySQLdb
        copying MySQLdb/converters.py -> build/lib.linux-x86_64-3.7/MySQLdb
        copying MySQLdb/cursors.py -> build/lib.linux-x86_64-3.7/MySQLdb
        copying MySQLdb/release.py -> build/lib.linux-x86_64-3.7/MySQLdb
        copying MySQLdb/times.py -> build/lib.linux-x86_64-3.7/MySQLdb
        creating build/lib.linux-x86_64-3.7/MySQLdb/constants
        copying MySQLdb/constants/__init__.py -> build/lib.linux-x86_64-3.7/MySQLdb/constants
        copying MySQLdb/constants/CLIENT.py -> build/lib.linux-x86_64-3.7/MySQLdb/constants
        copying MySQLdb/constants/CR.py -> build/lib.linux-x86_64-3.7/MySQLdb/constants
        copying MySQLdb/constants/ER.py -> build/lib.linux-x86_64-3.7/MySQLdb/constants
        copying MySQLdb/constants/FIELD_TYPE.py -> build/lib.linux-x86_64-3.7/MySQLdb/constants
        copying MySQLdb/constants/FLAG.py -> build/lib.linux-x86_64-3.7/MySQLdb/constants
        running build_ext
        building 'MySQLdb._mysql' extension
        creating build/temp.linux-x86_64-3.7
        creating build/temp.linux-x86_64-3.7/MySQLdb
        gcc -pthread -B /boa/.miniconda/compiler_compat -Wl,--sysroot=/ -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -Dversion_info=(2,0,3,'final',0) -D__version__=2.0.3 -I/usr/include/mysql -I/home/abdealijk/node_modules/@pipcook/boa/binding/v6/include/python3.7m -c MySQLdb/_mysql.c -o build/temp.linux-x86_64-3.7/MySQLdb/_mysql.o -std=c99
        MySQLdb/_mysql.c:46:10: fatal error: Python.h: No such file or directory
         #include "Python.h"
                  ^~~~~~~~~~
        compilation terminated.
        error: command 'gcc' failed with exit status 1
        ----------------------------------------
    ERROR: Command errored out with exit status 1: /home/abdealijk/frontend/node_modules/@pipcook/boa/binding/v6/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-zhzlp_0p/mysqlclient/setup.py'"'"'; __file__='"'"'/tmp/pip-install-zhzlp_0p/mysqlclient/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-_xhxik_q/install-record.txt --single-version-externally-managed --compile Check the logs for full command output.
    

    Works fine if I use pip directly:

    $ pip install mysqlclient
    Collecting mysqlclient
    Installing collected packages: mysqlclient
    Successfully installed mysqlclient-2.0.3
    
    opened by AbdealiLoKo 1
  • NumPy built-in scalar types conversion exceptions

    NumPy built-in scalar types conversion exceptions

    | Environment | Info | |---|---| | OS | Ubuntu 20.04 LTS | | Node.js | 14.19.2 | | npm | 8.9.0 | | NumPy | 1.21.6 |

    The numpy.float type will be converted to the primitive number type, but the numpy.int type will be converted to the primitive string type.

    const boa = require("@pipcook/boa");
    const np = boa.import("numpy");
    console.log(typeof np.float_(0)); // number
    console.log(typeof np.float64(0)); // number
    console.log(typeof np.int_(0)); // string
    console.log(typeof np.int64(0)); // string
    
    opened by peidongxie 0
  • boa.builtins().bytes memory leak

    boa.builtins().bytes memory leak

        while (true) {
            const foobar = Buffer.from('foobar');
            boa.builtins().bytes.fromhex(foobar.toString('hex'));
        }
    

    above code causes memory leak

    opened by bonboru93 0
  • critical memory leak

    critical memory leak

    const boa = require('@pipcook/boa');
    const { bytes } = boa.builtins();
    async function sleep(ms){
            const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
            await delay(ms);
    }
    async function test(){
            while(1){
                    let buf = Buffer.from('f'.repeat(10000000));
                    aa = bytes.fromhex(buf.toString('hex'));
                    await sleep(1000);
                    console.log(aa.slice(0,10));
            }
    }
    test();
    

    run it in docker, and run "docker stats" to watch the memory.

    bug 
    opened by yiwiz-sai 9
Owner
imgcook
imgcook is an ingenious chef who specializes in cooking with various images (Sketch / PSD / static images).
imgcook
[UNMAINTAINED] Simple feed-forward neural network in JavaScript

This project has reached the end of its development as a simple neural network library. Feel free to browse the code, but please use other JavaScript

Heather 8k Dec 26, 2022
A neural network library built in JavaScript

A flexible neural network library for Node.js and the browser. Check out a live demo of a movie recommendation engine built with Mind. Features Vector

Steven Miller 1.5k Dec 31, 2022
Pure Javascript OCR for more than 100 Languages 📖🎉🖥

Version 2 is now available and under development in the master branch, read a story about v2: Why I refactor tesseract.js v2? Check the support/1.x br

Project Naptha 29.2k Dec 31, 2022
WebGL-accelerated ML // linear algebra // automatic differentiation for JavaScript.

This repository has been archived in favor of tensorflow/tfjs. This repo will remain around for some time to keep history but all future PRs should be

null 8.5k Dec 31, 2022
A JavaScript deep learning and reinforcement learning library.

neurojs is a JavaScript framework for deep learning in the browser. It mainly focuses on reinforcement learning, but can be used for any neural networ

Jan 4.4k Jan 4, 2023
Differential Programming in JavaScript.

April 19, 2018 TensorFlow.js was recently released. It is well engineered, provides an autograd-style interface to backprop, and has committed to supp

Propel 2.7k Dec 29, 2022
Machine learning tools in JavaScript

ml.js - Machine learning tools in JavaScript Introduction This library is a compilation of the tools developed in the mljs organization. It is mainly

ml.js 2.3k Jan 1, 2023
Deep Neural Network Sandbox for JavaScript.

Deep Neural Network Sandbox for Javascript Train a neural network with your data & save it's trained state! Demo • Installation • Getting started • Do

Matias Vazquez-Levi 420 Jan 4, 2023
A WebGL accelerated JavaScript library for training and deploying ML models.

TensorFlow.js TensorFlow.js is an open-source hardware-accelerated JavaScript library for training and deploying machine learning models. ⚠️ We recent

null 16.9k Jan 4, 2023
JavaScript API for face detection and face recognition in the browser and nodejs with tensorflow.js

face-api.js JavaScript face recognition API for the browser and nodejs implemented on top of tensorflow.js core (tensorflow/tfjs-core) Click me for Li

Vincent Mühler 14.6k Jan 2, 2023
Linear Regression library in pure Javascript

Lyric Linear Regression library in pure Javascript Lyric can help you analyze any set of x,y series data by building a model that can be used to: Crea

Flurry, Inc. 43 Dec 22, 2020
JavaScript Machine Learning Toolkit

The JavaScript Machine Learning Toolkit, or JSMLT, is an open source JavaScript library for education in machine learning.

JSMLT 25 Nov 23, 2022
K-nearest neighbors algorithm for supervised learning implemented in javascript

kNear Install npm install knear --save About kNear is a javascript implementation of the k-nearest neighbors algorithm. It is a supervised machine lea

Nathan Epstein 45 Mar 7, 2022
Latent Dirichlet allocation (LDA) topic modeling in javascript for node.js.

LDA Latent Dirichlet allocation (LDA) topic modeling in javascript for node.js. LDA is a machine learning algorithm that extracts topics and their rel

Kory Becker 279 Nov 4, 2022
Simple Javascript implementation of the k-means algorithm, for node.js and the browser

#kMeans.js Simple Javascript implementation of the k-means algorithm, for node.js and the browser ##Installation npm install kmeans-js ##Example (JS)

Emil Bay 44 Aug 19, 2022
DN2A - Digital Neural Networks Architecture in JavaScript

DN2A (JavaScript) Digital Neural Networks Architecture About DN2A is a set of highly decoupled JavaScript modules for Neural Networks and Artificial I

Antonio De Luca 464 Jan 1, 2023
Clustering algorithms implemented in Javascript for Node.js and the browser

Clustering.js ####Clustering algorithms implemented in Javascript for Node.js and the browser Examples License Copyright (c) 2013 Emil Bay github@tixz

Emil Bay 29 Aug 19, 2022
:robot: Natural language processing with JavaScript

classifier.js ?? An library for natural language processing with JavaScript Table of Contents Instalation Example of use Auto detection of numeric str

Nathan Firmo 90 Dec 12, 2022
This is a project that is used to execute python codes in the web page. You can install and use it in django projects, You can do any operations that can be performed in python shell with this package.

Django execute code This is a project that is used to execute python codes in the web page. You can install and use it in django projects, You can do

Shinu 5 Nov 12, 2022
In this project I'll use Asynchronous Javascript to call an API and set the leaderboard of the best players.

Leaderboard Project In this project I'll use Asynchronous Javascript to call an API and set the leaderboard of the best players. The main goals of thi

Oscar Fernández Muñoz 4 Oct 17, 2022