Skip to content

Commit

Permalink
lib: drop Python 2 support in find-python.js (#2333)
Browse files Browse the repository at this point in the history
Co-authored-by: Christian Clauss <cclauss@me.com>

PR-URL: #2333
Reviewed-By: Christian Clauss <cclauss@me.com>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
  • Loading branch information
DeeDeeG committed Mar 26, 2021
1 parent e81602e commit 1bd18f3
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 27 deletions.
41 changes: 27 additions & 14 deletions lib/find-python.js
@@ -1,13 +1,29 @@
'use strict'

const path = require('path')
const log = require('npmlog')
const semver = require('semver')
const cp = require('child_process')
const extend = require('util')._extend // eslint-disable-line
const win = process.platform === 'win32'
const logWithPrefix = require('./util').logWithPrefix

const systemDrive = process.env.SystemDrive || 'C:'
const username = process.env.USERNAME || process.env.USER || require('os').userInfo().username
const localAppData = process.env.LOCALAPPDATA || `${systemDrive}\\${username}\\AppData\\Local`
const programFiles = process.env.ProgramW6432 || process.env.ProgramFiles || `${systemDrive}\\Program Files`
const programFilesX86 = process.env['ProgramFiles(x86)'] || `${programFiles} (x86)`

const winDefaultLocationsArray = []
for (const majorMinor of ['39', '38', '37', '36']) {
winDefaultLocationsArray.push(
`${localAppData}\\Programs\\Python\\Python${majorMinor}\\python.exe`,
`${programFiles}\\Python${majorMinor}\\python.exe`,
`${localAppData}\\Programs\\Python\\Python${majorMinor}-32\\python.exe`,
`${programFiles}\\Python${majorMinor}-32\\python.exe`,
`${programFilesX86}\\Python${majorMinor}-32\\python.exe`
)
}

function PythonFinder (configPython, callback) {
this.callback = callback
this.configPython = configPython
Expand All @@ -18,17 +34,14 @@ PythonFinder.prototype = {
log: logWithPrefix(log, 'find Python'),
argsExecutable: ['-c', 'import sys; print(sys.executable);'],
argsVersion: ['-c', 'import sys; print("%s.%s.%s" % sys.version_info[:3]);'],
semverRange: '2.7.x || >=3.5.0',
semverRange: '>=3.6.0',

// These can be overridden for testing:
execFile: cp.execFile,
env: process.env,
win: win,
pyLauncher: 'py.exe',
winDefaultLocations: [
path.join(process.env.SystemDrive || 'C:', 'Python37', 'python.exe'),
path.join(process.env.SystemDrive || 'C:', 'Python27', 'python.exe')
],
winDefaultLocations: winDefaultLocationsArray,

// Logs a message at verbose level, but also saves it to be displayed later
// at error level if an error occurs. This should help diagnose the problem.
Expand Down Expand Up @@ -96,11 +109,6 @@ PythonFinder.prototype = {
before: () => { this.addLog('checking if "python" can be used') },
check: this.checkCommand,
arg: 'python'
},
{
before: () => { this.addLog('checking if "python2" can be used') },
check: this.checkCommand,
arg: 'python2'
}
]

Expand All @@ -119,7 +127,7 @@ PythonFinder.prototype = {
checks.push({
before: () => {
this.addLog(
'checking if the py launcher can be used to find Python')
'checking if the py launcher can be used to find Python 3')
},
check: this.checkPyLauncher
})
Expand Down Expand Up @@ -188,10 +196,15 @@ PythonFinder.prototype = {
// Distributions of Python on Windows by default install with the "py.exe"
// Python launcher which is more likely to exist than the Python executable
// being in the $PATH.
// Because the Python launcher supports Python 2 and Python 3, we should
// explicitly request a Python 3 version. This is done by supplying "-3" as
// the first command line argument. Since "py.exe -3" would be an invalid
// executable for "execFile", we have to use the launcher to figure out
// where the actual "python.exe" executable is located.
checkPyLauncher: function checkPyLauncher (errorCallback) {
this.log.verbose(
`- executing "${this.pyLauncher}" to get Python executable path`)
this.run(this.pyLauncher, this.argsExecutable, false,
`- executing "${this.pyLauncher}" to get Python 3 executable path`)
this.run(this.pyLauncher, ['-3', ...this.argsExecutable], false,
function (err, execPath) {
// Possible outcomes: same as checkCommand
if (err) {
Expand Down
22 changes: 9 additions & 13 deletions test/test-find-python.js
Expand Up @@ -16,13 +16,8 @@ test('find python', function (t) {
t.strictEqual(err, null)
var proc = execFile(found, ['-V'], function (err, stdout, stderr) {
t.strictEqual(err, null)
if (/Python 2/.test(stderr)) {
t.strictEqual(stdout, '')
t.ok(/Python 2/.test(stderr))
} else {
t.ok(/Python 3/.test(stdout))
t.strictEqual(stderr, '')
}
t.ok(/Python 3/.test(stdout))
t.strictEqual(stderr, '')
})
proc.stdout.setEncoding('utf-8')
proc.stderr.setEncoding('utf-8')
Expand Down Expand Up @@ -66,7 +61,7 @@ test('find python - python', function (t) {
poison(f, 'execFile')
t.strictEqual(program, '/path/python')
t.ok(/sys\.version_info/.test(args[1]))
cb(null, '2.7.15')
cb(null, '3.9.1')
}
t.strictEqual(program,
process.platform === 'win32' ? '"python"' : 'python')
Expand Down Expand Up @@ -146,13 +141,14 @@ test('find python - no python2, no python, unix', function (t) {
})

test('find python - no python, use python launcher', function (t) {
t.plan(3)
t.plan(4)

var f = new TestPythonFinder(null, done)
f.win = true

f.execFile = function (program, args, opts, cb) {
if (program === 'py.exe') {
t.notEqual(args.indexOf('-3'), -1)
t.notEqual(args.indexOf('-c'), -1)
return cb(null, 'Z:\\snake.exe')
}
Expand All @@ -162,7 +158,7 @@ test('find python - no python, use python launcher', function (t) {
cb(new Error('not found'))
} else if (/sys\.version_info/.test(args[args.length - 1])) {
if (program === 'Z:\\snake.exe') {
cb(null, '2.7.14')
cb(null, '3.9.0')
} else {
t.fail()
}
Expand All @@ -181,17 +177,17 @@ test('find python - no python, use python launcher', function (t) {
test('find python - no python, no python launcher, good guess', function (t) {
t.plan(2)

var re = /C:[\\/]Python37[\\/]python[.]exe/
var f = new TestPythonFinder(null, done)
f.win = true
const expectedProgram = f.winDefaultLocations[0]

f.execFile = function (program, args, opts, cb) {
if (program === 'py.exe') {
return cb(new Error('not found'))
}
if (/sys\.executable/.test(args[args.length - 1])) {
cb(new Error('not found'))
} else if (re.test(program) &&
} else if (program === expectedProgram &&
/sys\.version_info/.test(args[args.length - 1])) {
cb(null, '3.7.3')
} else {
Expand All @@ -202,7 +198,7 @@ test('find python - no python, no python launcher, good guess', function (t) {

function done (err, python) {
t.strictEqual(err, null)
t.ok(re.test(python))
t.ok(python === expectedProgram)
}
})

Expand Down

0 comments on commit 1bd18f3

Please sign in to comment.