From dcd9826a4cd0dd2209516affe9c66378c479a7c0 Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Wed, 11 Oct 2017 16:21:39 +0300 Subject: [PATCH] Honor packages installed inside module (PY-20489) --- .../PyPackageRequirementsInspection.java | 42 +++++++++++-------- .../PackageInstalledIntoModule/a.py | 1 + .../apispec-0.25.4.dist-info/top_level.txt | 1 + .../requirements.txt | 1 + .../PyPackageRequirementsInspectionTest.java | 5 +++ 5 files changed, 32 insertions(+), 18 deletions(-) create mode 100644 python/testData/inspections/PyPackageRequirementsInspection/PackageInstalledIntoModule/a.py create mode 100644 python/testData/inspections/PyPackageRequirementsInspection/PackageInstalledIntoModule/apispec-0.25.4.dist-info/top_level.txt create mode 100644 python/testData/inspections/PyPackageRequirementsInspection/PackageInstalledIntoModule/requirements.txt diff --git a/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java b/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java index 71410214f9b3..aa8955377539 100644 --- a/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.jetbrains.python.inspections; import com.google.common.collect.ImmutableSet; @@ -28,10 +14,13 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.JDOMExternalizableStringList; +import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.profile.codeInspection.ProjectInspectionProfileManager; import com.intellij.psi.*; +import com.intellij.util.ArrayUtil; +import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyBundle; import com.jetbrains.python.codeInsight.imports.AddImportHelper; @@ -156,7 +145,6 @@ public class PyPackageRequirementsInspection extends PyInspection { } final PyExpression packageReferenceExpression = PyPsiUtils.getFirstQualifier(importedExpression); - if (packageReferenceExpression == null) return; final String packageName = packageReferenceExpression.getName(); if (packageName != null && !myIgnoredPackages.contains(packageName)) { @@ -266,15 +254,16 @@ public class PyPackageRequirementsInspection extends PyInspection { private static List findUnsatisfiedRequirements(@NotNull Module module, @NotNull Sdk sdk, @NotNull Set ignoredPackages) { final PyPackageManager manager = PyPackageManager.getInstance(sdk); - List requirements = manager.getRequirements(module); + final List requirements = manager.getRequirements(module); if (requirements != null) { final List packages = manager.getPackages(); if (packages == null) { return null; } + final List packagesInModule = collectPackagesInModule(module); final List unsatisfied = new ArrayList<>(); for (PyRequirement req : requirements) { - if (!ignoredPackages.contains(req.getName()) && req.match(packages) == null) { + if (!ignoredPackages.contains(req.getName()) && req.match(packages) == null && req.match(packagesInModule) == null) { unsatisfied.add(req); } } @@ -283,6 +272,23 @@ public class PyPackageRequirementsInspection extends PyInspection { return null; } + @NotNull + private static List collectPackagesInModule(@NotNull Module module) { + final String[] metadataExtensions = {"egg-info", "dist-info"}; + final List result = new SmartList<>(); + + for (VirtualFile srcRoot : PyUtil.getSourceRoots(module)) { + for (VirtualFile metadata : VfsUtil.getChildren(srcRoot, file -> ArrayUtil.contains(file.getExtension(), metadataExtensions))) { + final String[] nameAndVersionAndRest = metadata.getNameWithoutExtension().split("-", 3); + if (nameAndVersionAndRest.length >= 2) { + result.add(new PyPackage(nameAndVersionAndRest[0], nameAndVersionAndRest[1], null, Collections.emptyList())); + } + } + } + + return result; + } + private static void setRunningPackagingTasks(@NotNull Module module, boolean value) { module.putUserData(PyPackageManager.RUNNING_PACKAGING_TASKS, value); } diff --git a/python/testData/inspections/PyPackageRequirementsInspection/PackageInstalledIntoModule/a.py b/python/testData/inspections/PyPackageRequirementsInspection/PackageInstalledIntoModule/a.py new file mode 100644 index 000000000000..ba2da4212716 --- /dev/null +++ b/python/testData/inspections/PyPackageRequirementsInspection/PackageInstalledIntoModule/a.py @@ -0,0 +1 @@ +from apispec import APISpec \ No newline at end of file diff --git a/python/testData/inspections/PyPackageRequirementsInspection/PackageInstalledIntoModule/apispec-0.25.4.dist-info/top_level.txt b/python/testData/inspections/PyPackageRequirementsInspection/PackageInstalledIntoModule/apispec-0.25.4.dist-info/top_level.txt new file mode 100644 index 000000000000..0643e290572b --- /dev/null +++ b/python/testData/inspections/PyPackageRequirementsInspection/PackageInstalledIntoModule/apispec-0.25.4.dist-info/top_level.txt @@ -0,0 +1 @@ +apispec diff --git a/python/testData/inspections/PyPackageRequirementsInspection/PackageInstalledIntoModule/requirements.txt b/python/testData/inspections/PyPackageRequirementsInspection/PackageInstalledIntoModule/requirements.txt new file mode 100644 index 000000000000..dcd7646ebb8b --- /dev/null +++ b/python/testData/inspections/PyPackageRequirementsInspection/PackageInstalledIntoModule/requirements.txt @@ -0,0 +1 @@ +apispec \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyPackageRequirementsInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyPackageRequirementsInspectionTest.java index c2427d7dfc9e..d15ceafa8bea 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyPackageRequirementsInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyPackageRequirementsInspectionTest.java @@ -65,4 +65,9 @@ public class PyPackageRequirementsInspectionTest extends PyInspectionTestCase { public void testOnePackageManyPossibleRequirements() { doMultiFileTest("test1.py"); } + + // PY-20489 + public void testPackageInstalledIntoModule() { + doMultiFileTest(); + } }