nodejs-pypi icon indicating copy to clipboard operation
nodejs-pypi copied to clipboard

Planned Python API, request for feedback.

Open samwillis opened this issue 2 years ago • 2 comments

The current planned Python API for nodejs-bin would be very limited.

Because nodejs-bin versions are tied to Node.js versions exactly we have to fix this api for the forceable future and will be unable to iterate on it once nodejs-bin goes stable.

For node itself and other included comments such as npm, npx etc there would be a run() and start() function:

from nodejs import node, npm, npx

# Run Node.js and return the exit code.
node.run(['script.js', 'arg1', ...], **kwargs)

# Run npm and return the exit code.
npm.run(['command', 'arg1', ...], **kwargs)

# Run npx and return the exit code.
npx.run(['command', 'arg1', ...], **kwargs)

The run(args, **kwargs) functions wrap subprocess.call(), passes though all kwargs and returns the exit code of the process.

Additionally, to start a Node.js process and return a subprocess.Popen object, you can use the start(args, **kwargs) functions:

from nodejs import node, npm, npx

# Start Node.js and return the Popen object.
node_process = node.start(['script.js', 'arg1', ...], **kwargs)

# Start npm and return the Popen object.
npm_process = npm.start(['command', 'arg1', ...], **kwargs)

# Start npx and return the Popen object.
npx_process = npx.start(['command', 'arg1', ...], **kwargs)

The start(args, **kwargs) functions wrap subprocess.Popen(), passes though all kwargs and returns a Popen object.

It would also be possible to do just:

import nodejs

nodejs.run(['script.js', 'arg1', ...], **kwargs)
node_process = nodejs.start(['script.js', 'arg1', ...], **kwargs)

Finally, there will be:

import nodejs

nodejs.__version__
# The version of the nodejs-bin package, it will always start with the version of node itself 
# However for an alpha release it would have an 'aN' suffix 
# or a 'build' for post release, such as '-1' (useful if find a problem with the packaging of a release)

nodejs.node_version
# The version of node itself

nodejs.path
# The path (str) to the node binary that has been installed

See PEP 440 for details of the version string: https://peps.python.org/pep-0440/

samwillis avatar Jun 19 '22 19:06 samwillis

My two cents:

Change the API to be of the form:

node.run("script.js", "argument 1", **kwargs)

There's less scope for getting the wrong data type in the arguments, enforces explicitness for all the keyword arguments (something you seem to want already) and requires less typing on the user's end. This is similar to what nox's Session object does, which is where I'm pulling this suggestion from. :)

Unlike Popen, you likely don't want to take a string with already-escaped arguments that you'd pass with shell=True -- so args don't need to be a dedicated argument and can instead be a *args

pradyunsg avatar Jun 20 '22 17:06 pradyunsg

Thanks Pradyun,

That was my original plan, however as it's such a thin wrapper around subprocess.call() (and subprocess.Popen()), really just setting the first args, I'm cautious of deveating too far from the signature of the original functions.

I now realise run() should probably wrap the newer subprocess.run() and also have a call() wrapping subprocess.call(), and while I'm at it change start() to Popen() so it indicates it wraps subprocess.Popen().

Also just to note; while for node these are just setting the first arg to the path to the installed node binary. For npm and npx they actually differ between Windows and Mac/Posix. On Windows there are npm.cmd and npx.cmd binaries, whereas on the others they call node /path/to/np[n,x]/script.js.

My thinking/hope is that someone will create an elegant api that wraps node in a much more Pythonic way, however I think it's best to keep node-bin super simple.

Update:

New version "a2" released doing this.

samwillis avatar Jun 20 '22 19:06 samwillis