diff --git a/lib/dependencies/index.ts b/lib/dependencies/index.ts index 63d4b86..5ccb570 100644 --- a/lib/dependencies/index.ts +++ b/lib/dependencies/index.ts @@ -27,7 +27,6 @@ export async function getDependencies( options = {}; } let command = options.command || 'python'; - const pythonCmd = command; const includeDevDeps = !!(options.dev || false); // handle poetry projects by parsing manifest & lockfile and return a dep-graph @@ -52,7 +51,6 @@ export async function getDependencies( getMetaData(command, baseargs, root, targetFile), inspectInstalledDeps( command, - pythonCmd, baseargs, root, targetFile, diff --git a/lib/dependencies/inspect-implementation.ts b/lib/dependencies/inspect-implementation.ts index e476261..7a8212f 100644 --- a/lib/dependencies/inspect-implementation.ts +++ b/lib/dependencies/inspect-implementation.ts @@ -8,9 +8,6 @@ import { buildDepGraph, PartialDepTree } from './build-dep-graph'; import { FILENAMES } from '../types'; import { EmptyManifestError, RequiredPackagesMissingError } from '../errors'; -const PYTHON_3_12_REGEX = new RegExp('^Python 3.12.*'); -const UPDATED_SETUPTOOLS_VERSION = '68.0.0'; - const returnedTargetFile = (originalTargetFile) => { const basename = path.basename(originalTargetFile); @@ -209,38 +206,8 @@ function dumpAllFilesInTempDir(tempDirName: string) { }); } -async function updateSetuptools( - setuptoolsVersion: string, - dir: string, - pythonEnv, - command: string -) { - // For python 3.12, setuptools needs to be updated - // due to removal of some deprecated packages - // see: https://github.com/pypa/pip/pull/11997 - - const pythonVersion = await subProcess.execute(command, ['--version'], { - cwd: dir, - env: pythonEnv, - }); - - if (!PYTHON_3_12_REGEX.test(pythonVersion)) { - return; - } - - await subProcess.execute( - `${command} -m pip install setuptools==${setuptoolsVersion}`, - [], - { - cwd: dir, - env: pythonEnv, - } - ); -} - export async function inspectInstalledDeps( command: string, - pythonCmd: string, baseargs: string[], root: string, targetFile: string, @@ -258,13 +225,6 @@ export async function inspectInstalledDeps( try { const pythonEnv = getPythonEnv(targetFile); - await updateSetuptools( - UPDATED_SETUPTOOLS_VERSION, - root, - pythonEnv, - pythonCmd - ); - // See ../../pysrc/README.md const output = await subProcess.execute( command, diff --git a/pysrc/pip_resolve.py b/pysrc/pip_resolve.py index be124a6..45b2c6b 100644 --- a/pysrc/pip_resolve.py +++ b/pysrc/pip_resolve.py @@ -7,7 +7,6 @@ import utils import requirements import pipfile -import setup_file import codecs from operator import le, lt, gt, ge, eq, ne from constants import DepsManager @@ -135,6 +134,7 @@ def create_children_recursive( def create_dir_as_root(): name, version = None, None if os.path.basename(req_file_path) == 'setup.py': + import setup_file with open(req_file_path, "r") as setup_py_file: name, version = setup_file.parse_name_and_version(setup_py_file.read()) @@ -231,7 +231,7 @@ def matches_python_version(requirement): # Gloss over the 'and' case and return true on the first matching python version - for sub_exp in re.split("\s*(?:and|or)\s*", cond_text): + for sub_exp in re.split(r"\s*(?:and|or)\s*", cond_text): match = PYTHON_MARKER_REGEX.search(sub_exp) if match: @@ -329,6 +329,7 @@ def get_requirements_for_setuptools(requirements_file_path): list[Requirement]: if requirements were found. empty list: if no requirements were found in the requirements file. """ + import setup_file with open(requirements_file_path, 'r') as f: setup_py_file_content = f.read() requirements_data = setup_file.parse_requirements(setup_py_file_content) diff --git a/test/system/inspect.spec.ts b/test/system/inspect.spec.ts index 7adccfa..b571714 100644 --- a/test/system/inspect.spec.ts +++ b/test/system/inspect.spec.ts @@ -305,6 +305,221 @@ describe('inspect', () => { compareTransitiveLines(result.dependencyGraph, expected); } ); + it.each([ + { + workspace: 'pip-app', + uninstallPackages: [], + pluginOpts: {}, + expected: [ + { + pkg: { + name: 'jaraco.collections', + version: '5.0.1', + }, + directDeps: ['irc'], + }, + { + pkg: { + name: 'django-appconf', + version: '1.0.6', + }, + directDeps: ['django-select2'], + }, + ], + }, + { + workspace: 'pip-app-bom', + uninstallPackages: [], + pluginOpts: {}, + expected: [ + { + pkg: { + name: 'markupsafe', + version: '2.1.5', + }, + directDeps: ['jinja2'], + }, + ], + }, + { + workspace: 'pip-app-deps-with-urls', + uninstallPackages: [], + pluginOpts: {}, + expected: [ + { + pkg: { + name: 'markupsafe', + version: '2.1.5', + }, + directDeps: ['jinja2'], + }, + ], + }, + { + workspace: 'pip-app-without-markupsafe', + uninstallPackages: ['MarkupSafe'], + pluginOpts: { allowMissing: true }, + expected: [ + { + pkg: { + name: 'markupsafe', + version: '?', + }, + directDeps: ['jinja2'], + }, + ], + }, + { + workspace: 'pip-app-deps-not-installed', + uninstallPackages: [], + pluginOpts: { allowMissing: true }, + expected: [ + { + pkg: { + name: 's3transfer', + version: '0.10.2', + }, + directDeps: ['awss'], + }, + ], + }, + { + workspace: 'pip-app-trusted-host', + uninstallPackages: [], + pluginOpts: {}, + expected: [ + { + pkg: { + name: 'markupsafe', + version: '2.1.5', + }, + directDeps: ['jinja2'], + }, + ], + }, + { + workspace: 'pip-app-deps-with-dashes', + uninstallPackages: [], + pluginOpts: {}, + expected: [ + { + pkg: { + name: 'dj-database-url', + version: '0.4.2', + }, + directDeps: ['dj-database-url'], + }, + ], + }, + { + workspace: 'pip-app-with-openapi_spec_validator', + uninstallPackages: [], + pluginOpts: {}, + expected: [ + { + pkg: { + name: 'jsonschema', + version: '4.23.0', + }, + directDeps: ['openapi-spec-validator'], + }, + ], + }, + { + workspace: 'pip-app-deps-conditional', + uninstallPackages: [], + pluginOpts: {}, + expected: [ + { + pkg: { + name: 'posix-ipc', + version: '1.0.0', + }, + directDeps: ['posix-ipc'], + }, + ], + }, + { + workspace: 'pip-app-deps-editable', + uninstallPackages: [], + pluginOpts: {}, + expected: [ + { + pkg: { + name: 'posix-ipc', + version: '1.0.0', + }, + directDeps: ['posix-ipc'], + }, + ], + }, + { + workspace: 'pip-app-deps-canonicalization', + uninstallPackages: [], + pluginOpts: {}, + expected: [ + { + pkg: { + name: 'zope.interface', + version: '5.4.0', + }, + directDeps: ['zope.interface'], + }, + { + pkg: { + name: 'twisted', + version: '23.10.0', + }, + directDeps: ['twisted'], + }, + ], + }, + { + workspace: 'pip-app-optional-dependencies', + uninstallPackages: [], + pluginOpts: {}, + expected: [ + { + pkg: { + name: 'opentelemetry-distro', + version: '0.35b0', + }, + directDeps: ['opentelemetry-distro'], + }, + ], + }, + { + workspace: 'pip-app-dev-alpha-beta-python-version', + uninstallPackages: [], + pluginOpts: {}, + expected: [ + { + pkg: { + name: 'requests', + version: '2.31.0', + }, + directDeps: ['requests'], + }, + ], + }, + ])( + 'should get a valid dependency graph for workspace = $workspace without setuptools previously installed', + async ({ workspace, uninstallPackages, pluginOpts, expected }) => { + testUtils.chdirWorkspaces(workspace); + testUtils.ensureVirtualenv(workspace); + tearDown = testUtils.activateVirtualenv(workspace); + testUtils.pipUninstall('setuptools'); + testUtils.pipInstall(); + if (uninstallPackages) { + uninstallPackages.forEach((pkg) => { + testUtils.pipUninstall(pkg); + }); + } + + const result = await inspect('.', FILENAMES.pip.manifest, pluginOpts); + compareTransitiveLines(result.dependencyGraph, expected); + } + ); it('should fail on missing transitive dependencies', async () => { const workspace = 'pip-app'; @@ -439,7 +654,6 @@ describe('inspect', () => { status: 0, } as SpawnSyncReturns); mockedExecute.mockResolvedValueOnce('Python 3.9.5'); - mockedExecute.mockResolvedValueOnce('Python 3.9.5'); mockedExecute.mockResolvedValueOnce( '{"name": "pipenv-app", "version": "0.0.0", "dependencies": {"jinja2": {"name": "jinja2", "version": "3.0.1", "dependencies": {"MarkupSafe": {"name": "markupsafe", "version": "2.0.1"}}}}, "packageFormatVersion": "pip:0.0.1"}' ); @@ -563,7 +777,6 @@ describe('inspect', () => { }); it('should return correct target file for setuptools project when relative path to setup lock file is passed', async () => { - mockedExecute.mockResolvedValueOnce('Python 3.9.5'); mockedExecute.mockResolvedValueOnce('Python 3.9.5'); mockedExecute.mockResolvedValueOnce( '{"name": "pipenv-app", "version": "0.0.0", "dependencies": {"jinja2": {"name": "jinja2", "version": "3.0.1", "dependencies": {"MarkupSafe": {"name": "markupsafe", "version": "2.0.1"}}}}, "packageFormatVersion": "pip:0.0.1"}' @@ -589,7 +802,6 @@ describe('inspect', () => { status: 0, } as SpawnSyncReturns); mockedExecute.mockResolvedValueOnce('Python 3.9.5'); - mockedExecute.mockResolvedValueOnce('Python 3.9.5'); mockedExecute.mockResolvedValueOnce( fs.readFileSync( 'test/fixtures/dence-dep-graph/pip_resolve_output.json', @@ -640,7 +852,6 @@ describe('inspect', () => { describe('manifest file is empty', () => { it('should throw EmptyManifestError', async () => { - mockedExecute.mockResolvedValueOnce('Python 3.9.5'); mockedExecute.mockResolvedValueOnce('Python 3.9.5'); mockedExecute.mockRejectedValueOnce( 'No dependencies detected in manifest.' @@ -655,7 +866,6 @@ describe('inspect', () => { describe('required packages were not installed', () => { it('should throw RequiredPackagesMissingError', async () => { - mockedExecute.mockResolvedValueOnce('Python 3.9.5'); mockedExecute.mockResolvedValueOnce('Python 3.9.5'); mockedExecute.mockRejectedValueOnce('Required packages missing'); const manifestFilePath = 'path/to/requirements.txt';