Dowsing Rod
Dowse for Python 2.7 installations on your system and make them available to node-gyp
subprocesses.
Why?
node-gyp
only works with Python 2, and this is unlikely to change in the near future.
Furthermore, while node-gyp
allows you to override the Python executable it discovers itself by specifying a PYTHON
environment variable or setting the python
npm config option, certain node-gyp
builds will only work correctly if the python 2 executable is on the ${PATH}
with the exact name "python", because the Makefiles they generate execute generated files with a shebang line of #!/usr/bin/env python
.
Fixing this upstream would be tricky and require changes to trickle through a number of dependent projects. Hence @atom/dowsing-rod, which exists to:
- Locate a compatible Python 2 executable (a) from an existing
$PYTHON
variable (b) as anypython
,python2
, orpython2.7
executable on your$PATH
or (c) specified directly as a.python2-bin
file. - Set the
$PYTHON
environment variable to the discovered binary's path. Prepend a directory containing a wrapper script to your$PATH
so that shebang scripts will execute your chosen Python binary properly.
Install
$ npm install @atom/dowsing-rod
You'll also likely want to add .python2-bin
to your .gitignore
:
$ echo '.python2-bin' >> .gitignore
Use
From your package.json
To fix your node-gyp rebuild
command, add the following to your package.json
:
{
"scripts": {
"install": "with-python2-env node-gyp rebuild"
}
}
From code
If you're launching node-gyp as a subprocess yourself (like we do within the build scripts, for example), you can modify your process' environment directly:
const path = require('path')
const dowsingRod = require('@atom/dowsing-rod')
const options = {
// npm binary used to read config settings
npmBin: 'npm',
// file to store located Python binary
pythonBinFile: path.join(process.cwd(), '.python2-bin')
}
// Options are optional with the defaults shown.
const promise = dowsingRod.setPythonEnv(options, process.env)
// Any exec or spawn calls after the returned promise resolves will have the correct Python environments.
// Or, if you wish to do something with the path yourself:
dowsingRod.getPythonBin(options)
.then(pythonBin => console.log(`Python binary: ${pythonBin}`))
// Synchronous variants are also exported:
dowsingRod.setPythonEnvSync(options, process.env)
const pythonBin = dowsingRod.getPythonBinSync(options)