diff --git a/lib/index.js b/lib/index.js index 96956863..40bb0107 100644 --- a/lib/index.js +++ b/lib/index.js @@ -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']; @@ -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 { @@ -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 }); @@ -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) { @@ -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; -} \ No newline at end of file +} diff --git a/plug/pip_resolve.py b/plug/pip_resolve.py index 0ff1b1fb..e36a6189 100644 --- a/plug/pip_resolve.py +++ b/plug/pip_resolve.py @@ -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. @@ -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=[]) @@ -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: @@ -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()) diff --git a/test/inspect.test.js b/test/inspect.test.js index edbb3d8c..fd5ba2db 100644 --- a/test/inspect.test.js +++ b/test/inspect.test.js @@ -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)); diff --git a/test/python-plugin.test.js b/test/python-plugin.test.js index d9195af7..8bc5d0f4 100644 --- a/test/python-plugin.test.js +++ b/test/python-plugin.test.js @@ -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', ]); @@ -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', ]); @@ -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', @@ -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',