Skip to content

Commit

Permalink
feat: support dev dependencies in pipenv projects
Browse files Browse the repository at this point in the history
  • Loading branch information
taleinat authored and adrukh committed Aug 1, 2018
1 parent 6bec298 commit 0b1b013
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 17 deletions.
45 changes: 37 additions & 8 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ module.exports.__tests = {
function inspect(root, targetFile, options) {
if (!options) { options = {}; }
var command = options.command || 'python';
var includeDevDeps = !!(options.dev || false);
var baseargs = [];

if (path.basename(targetFile) === 'Pipfile') {
// Check that pipenv is available by running it.
var pipenvCheckProc = subProcess.executeSync('pipenv', ['--version']);
if (pipenvCheckProc.status !== 0) {
throw new Error('Failed to run `pipenv`; please make sure it is installed.');
throw new Error(
'Failed to run `pipenv`; please make sure it is installed.');
}
command = 'pipenv';
baseargs = ['run', 'python'];
Expand All @@ -29,7 +31,14 @@ function inspect(root, targetFile, options) {
return Promise.all([
getMetaData(command, baseargs, root),
getDependencies(
command, baseargs, root, targetFile, options.allowMissing, options.args),
command,
baseargs,
root,
targetFile,
options.allowMissing,
includeDevDeps,
options.args
),
])
.then(function (result) {
return {
Expand Down Expand Up @@ -123,8 +132,15 @@ function dumpAllFilesInTempDir(tempDirName) {
});
}

function getDependencies(command, baseargs, root, targetFile,
allowMissing, args) {
function getDependencies(
command,
baseargs,
root,
targetFile,
allowMissing,
includeDevDeps,
args
) {
var tempDirObj = tmp.dirSync({
unsafeCleanup: true
});
Expand All @@ -134,7 +150,14 @@ function getDependencies(command, baseargs, root, targetFile,
return subProcess.execute(
command,
[].concat(baseargs,
buildArgs(targetFile, allowMissing, tempDirObj.name, args)),
buildArgs(
targetFile,
allowMissing,
tempDirObj.name,
includeDevDeps,
args
)
),
{ cwd: root }
)
.then(function (output) {
Expand All @@ -157,12 +180,18 @@ function getDependencies(command, baseargs, root, targetFile,
});
}

function buildArgs(targetFile, allowMissing, tempDirPath, extraArgs) {

function buildArgs(
targetFile,
allowMissing,
tempDirPath,
includeDevDeps,
extraArgs
) {
var pathToRun = path.join(tempDirPath, 'pip_resolve.py');
var args = [pathToRun];
if (targetFile) { args.push(targetFile); }
if (allowMissing) { args.push('--allow-missing'); }
if (includeDevDeps) { args.push('--dev-deps'); }
if (extraArgs) { args = args.concat(extraArgs); }
return args;
}
}
21 changes: 16 additions & 5 deletions plug/pip_resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,15 @@ def matches_environment(requirement):
def is_testable(requirement):
return requirement.editable == False and requirement.vcs is None

def get_requirements_list(requirements_file_path):
def get_requirements_list(requirements_file_path, dev_deps=False):
# TODO: refactor recognizing the dependency manager to a single place
if os.path.basename(requirements_file_path) == 'Pipfile':
with io.open(requirements_file_path, 'r', encoding='utf-8') as f:
requirements_data = f.read()
req_list = list(pipfile.parse(requirements_data).get('packages', []))
parsed_reqs = pipfile.parse(requirements_data)
req_list = list(parsed_reqs.get('packages', []))
if dev_deps:
req_list.extend(parsed_reqs.get('dev-packages', []))
else:
# assume this is a requirements.txt formatted file
# Note: requirements.txt files are unicode and can be in any encoding.
Expand All @@ -135,7 +138,9 @@ def get_requirements_list(requirements_file_path):
required = [req.name.replace('_', '-') for req in req_list]
return required

def create_dependencies_tree_by_req_file_path(requirements_file_path, allow_missing=False):
def create_dependencies_tree_by_req_file_path(requirements_file_path,
allow_missing=False,
dev_deps=False):
# get all installed packages
pkgs = get_installed_distributions(local_only=False, skip=[])

Expand All @@ -146,7 +151,7 @@ def create_dependencies_tree_by_req_file_path(requirements_file_path, allow_miss
dist_tree = utils.construct_tree(dist_index)

# create a list of dependencies from the dependencies file
required = get_requirements_list(requirements_file_path)
required = get_requirements_list(requirements_file_path, dev_deps=dev_deps)
installed = [p for p in dist_index]
packages = []
for r in required:
Expand All @@ -172,10 +177,16 @@ def main():
action="store_true",
help="don't fail if some packages listed in the dependencies file " +
"are not installed")
parser.add_argument("--dev-deps",
action="store_true",
help="resolve dev dependencies")
args = parser.parse_args()

create_dependencies_tree_by_req_file_path(
args.requirements, args.allow_missing)
args.requirements,
allow_missing=args.allow_missing,
dev_deps=args.dev_deps,
)

if __name__ == '__main__':
sys.exit(main())
33 changes: 33 additions & 0 deletions test/inspect.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,39 @@ test('inspect pipenv app with auto-created virtualenv', function (t) {
});
});

test('inspect pipenv app dev dependencies', function (t) {
return Promise.resolve().then(function () {
chdirWorkspaces('pipenv-app');

var venvCreated = testUtils.ensureVirtualenv('pipenv-app');
t.teardown(testUtils.activateVirtualenv('pipenv-app'));
if (venvCreated) {
return testUtils.pipenvInstall();
}
})
.then(function () {
return plugin.inspect('.', 'Pipfile', {dev: true})
})
.then(function (result) {
var pkg = result.package;

t.test('package dependencies', function (t) {
Object.keys(pipenvAppExpectedDependencies).forEach(function (depName) {
t.match(
pkg.dependencies[depName],
pipenvAppExpectedDependencies[depName].data,
pipenvAppExpectedDependencies[depName].msg
);
});

t.match(pkg.dependencies.virtualenv, {name: 'virtualenv'});

t.end();
});

t.end();
});
});

function chdirWorkspaces(dir) {
process.chdir(path.resolve(__dirname, 'workspaces', dir));
Expand Down
39 changes: 35 additions & 4 deletions test/python-plugin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ var test = require('tap').test;
var plugin = require('../lib').__tests;

test('check build args with array', function (t) {
var result = plugin.buildArgs('requirements.txt', false, "../plug", [
var result = plugin.buildArgs('requirements.txt', false, "../plug", false, [
'-argOne',
'-argTwo',
]);
Expand All @@ -16,7 +16,7 @@ test('check build args with array', function (t) {
});

test('check build args with array & allowMissing', function (t) {
var result = plugin.buildArgs('requirements.txt', true, "../plug", [
var result = plugin.buildArgs('requirements.txt', true, "../plug", false, [
'-argOne',
'-argTwo',
]);
Expand All @@ -30,8 +30,39 @@ test('check build args with array & allowMissing', function (t) {
t.end();
});

test('check build args with array & devDeps', function (t) {
var result = plugin.buildArgs('requirements.txt', false, "../plug", true, [
'-argOne',
'-argTwo',
]);
t.match(result[0], /.*\/plug\/pip_resolve\.py/);
t.deepEqual(result.slice(1), [
'requirements.txt',
'--dev-deps',
'-argOne',
'-argTwo',
]);
t.end();
});

test('check build args with array & allowMissing & devDeps', function (t) {
var result = plugin.buildArgs('requirements.txt', true, "../plug", true, [
'-argOne',
'-argTwo',
]);
t.match(result[0], /.*\/plug\/pip_resolve\.py/);
t.deepEqual(result.slice(1), [
'requirements.txt',
'--allow-missing',
'--dev-deps',
'-argOne',
'-argTwo',
]);
t.end();
});

test('check build args with string', function (t) {
var result = plugin.buildArgs('requirements.txt', false, "../plug", '-argOne -argTwo');
var result = plugin.buildArgs('requirements.txt', false, "../plug", false, '-argOne -argTwo');
t.match(result[0], /.*\/plug\/pip_resolve\.py/);
t.deepEqual(result.slice(1), [
'requirements.txt',
Expand All @@ -41,7 +72,7 @@ test('check build args with string', function (t) {
});

test('check build args with string & allowMissing', function (t) {
var result = plugin.buildArgs('requirements.txt', true, "../plug", '-argOne -argTwo');
var result = plugin.buildArgs('requirements.txt', true, "../plug", false, '-argOne -argTwo');
t.match(result[0], /.*\/plug\/pip_resolve\.py/);
t.deepEqual(result.slice(1), [
'requirements.txt',
Expand Down

0 comments on commit 0b1b013

Please sign in to comment.