npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

pyfi

v1.0.8

Published

Call Python functions and classes from Node or a client 📼

Downloads

5

Readme

This is in alpha! Try it out & tell us how it goes! Okay!

PyFi CircleCI License: MIT npm

Call Python functions from Node with an asynchronous architecture ✨

PyFi is designed for prototyping Node apps with data-driven Python backends. It runs Python as a subprocess of Node, which will get you up and running quickly for prototyping, but is not recommended for a production environment.

This package can be used along with pyfi-client to quickly make Python functionality available to a javascript client.

Why?

Python is the language of choice for data science and machine learning (as well as other applications), and a node stack is great for prototyping highly-interactive apps. PyFi makes it straightforward to take advantage of both of these strengths simultaneously.

Compatibility

Requires Node 6+ and Python 3.4+

Installation

PyFi no longer has any Python dependancies, so to install you can just:

npm install pyfi

Basic Usage

PyFi mimics how you'd use Python normally.

Say we have this Python module: fancycomputation.py

def my_very_fancy_function(first, second, commentary='nice job!'):
  # ... something fancy you need python for ...
  return str(first + second) + ' ' + commentary

In another Python module, after setting a PYTHONPATH to that module, we could call it:

from fancycomputation import my_very_fancy_function

result = my_very_fancy_function(1,2, commentary='hooray!')

print(result)
# 3 hooray!

Using PyFi, we can do essentially the same thing in node:

const PyFi = require('pyfi');

const py = PyFi({
  path: './python-stuff', // equivalent to setting PYTHONPATH
  imports: [{
    from: 'fancycomputation',
    import: 'my_very_fancy_function',
  }],
});

// callback for when pythonic is ready
py._.onReady(() => {
  // we wrap args in an array and kwargs in an object
  py.my_very_fancy_function([1, 2], {commentary: 'way to go!'})
  .then((result) => {
    console.log(result)
    // 3 way to go!
  })
});

Reference

PyFi({options})

Returns a PyFi instance, starts a Python kernel and attaches callables in node as described in options.

Options

path Array|String

The path or paths to append to the PYTHONPATH

imports Array as {import, [from]}

Describes which Python modules to import. Supports these patterns from Python:

| Python | Pyfi | | ------------------------------------- | ------------------------------------------------- | | from MODULE import OBJECT1, OBJECT2 | {from: 'MODULE' import: ['OBJECT1', 'OBJECT2']} | | from PACKAGE import MODULE | {from: 'PACKAGE', import: 'MODULE'} | | import MODULE | {import: 'MODULE'} | | from MODULE import * | {from: 'MODULE', import: '*'} |

Importing and Calling Python Functions

All imports are attached to the PyFi instance as they would be to the global namespace in Python. Only callables are made available to Node (not constants).

All calls to Python functions return a promise that resolves to the result.

For example:

const py = PyFi({
  imports:[
    {from: 'my_mod', import: ['my_func', 'my_other_func']}
  ]
 });

will make my_func and my_other_func available:

py.my_func().then(result => {
  console.log(result)
});
py.my_other_func().then(result => {
  console.log(result)
});

Similarly if my_other_mod contains do_this() and do_that(), we can run:

const py = PyFi({
  imports:[
    {import: 'my_other_mod'}
  ]
});

and now we'll be able to do this:

py.my_other_mod.do_this().then(result => {
  console.log(result)
});
py.my_other_mod.do_that().then(result => {
  console.log(result)
});

Handing arguments to Python

Since JavaScript doesn't have a notion of keyword arguments, instead you can make calls to Python that contain arguments using an array of positional arguments and an object of keyword arguments:

py.my_function([args], {kwargs})

You may omit either [args] or {kwargs} if the function you're calling doesn't require them, but to keep the notation explicit you must always wrap positional arguments in an array.

Sending messages through PyFi while a function is running

PyFi includes handling for sending back from Python while a function is running. That allows for, for example, streaming status back to a client while a long-running function is in progress. To accomplish that, a function pyfi_message is injected into the run context, which is received by an onMessage handler attached to the corresponding promise.

That looks like this: Python:

def my_function():
  # ... do something ...
  pyfi_message('my message')
  # ... do something else ...
  return 'done!'

Node:

// assuming you've imported this function already
py.my_function()
  .onMessage(data => {
    console.log(data)
    // 'my message'
  })
  .then(res => {
    console.log(res);
    // 'done'
  })

Instantiating Python classes

Say you've imported a Python class:

const py = PyFi({
  imports:[
    {from: 'my_mod', import: 'MyClass'}
  ]
});

PyFi allows you to create and use an instance of that class:

py._.initClass({
    class: 'MyClass',
    as: 'mc',
    args: [/*init args*/],
    kwargs: {/*init kwargs*/}
})
// the initClass method returns a promise
.then(()=>{
  // once the class is init'ed we can call it:
  py.mc.instace_method(['good stuff']).then(result => {
    console.log(result)
  })
});

The instance will continue to be available as py.mc with all of it's callable methods attached.

Usage with Pyfi-Client

PyFi-Client allows for frontend clients to attach to a node instance of PyFi using socket.io. The _.attachClientSocketIO method is used to make this functionality available using an existing socket.io instance. You can see a full example in the PyFi-Client repo.

Methods

_.onReady(callback)

Attach a callback for when the instance of PyFi is ready.

_.onPrint(callback)

Attach a callback for when python prints. By default it will be console.loged and denote as PYTHON:.

py._.onPrint((message) => {
  console.log(`Here's what python said: ${message}`)
})

_.initClass({options})

Instantiate a python class and attach it to the instance of PyFi. Returns a Promise. See Instantiating Python Classes above.

_.importModules([modules])

Import modules after the initial init. Follows the same pattern as the init options (see Importing and Calling Python Functions for examples).

_.attachClientSocketIO(socketIOInstance)

Make this instance of PyFi available to PyFi-Client by attaching an instance of socket.io. See Usage with PyFi-Client.

What's with the _?

Since the py. namespaces is reserved for the python modules imported by the user, instance methods on the PyFi object are proxied to py._..

Contributing

We welcome issues and pull requests.

If you spot a bug, please provide as much context as possible – including your OS, which versions of Node and Python you're running on, how you're managing your Python environment, and anything else that could be relevant.

License

MIT License (c) 2018 - Present IDEO CoLab