-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pylint takes the isort configuration into account only if it's directly available in its launch directory #4437
Comments
Thank you for analyzing this problem ! |
take |
After some investigation it seems like they are all returning third party? could you share file contents of fruit.apple.data / fruit.banana.data? |
I'm having the same issue as @fphammerle and am also able to reproduce it using your example above. Given the following # pylint: disable=missing-docstring,unused-import
import functional.w.wrong_import_order # third party
import numpy # third party
import functional.u.unbalanced_tuple_unpacking # first party I'm getting the following pylint output:
The directory structure for this example looks like this:
@yushao2 I uploaded the above example to this repository, can you try if you can reproduce the issue there? |
Thank you so much for the example! I'm just struggling to figure out how to make functional test cases to reproduce this issue on the repo at the moment :/ If there are any one else interested to work on resolving this bug please go ahead with it! |
I assume that I have missed something as I cannot repro the OP? For me, If I read PEP-402 (Simplified Package Layout and Partitioning), PEP-420 (Implicit Namespace Packages) and PEP-561 (Distributing and Packaging Type Information) this is the behaviour we would expect. If we treat a namespace as a collection of modules e.g. The OP report said that SetupIf I have a directory structure as follows:
And file contents as follows: # fruit[1, 2 or 3]/apple's __init__.py or apple.py:
import math # std lib
import fruit[1, 2 or 3].banana.data # update the fruit number for each test candidate
import numpy
import fruit[1, 2 or 3].apple.data # fruit[1, 2 or 3]/apple/data.py
data = "some apple data" # fruit[1, 2 or 3]/banana's __init__.py or banana.py:
# empty file # fruit[1, 2 or 3]/banana/data.py
data = "some banana data" Results (isort)When I run @@ -2,7 +2,7 @@
import math
-import fruit3.banana.data
import numpy
import fruit3.apple.data
+import fruit3.banana.data Results (pylint)Running
Environment/configthe sort version is:
the pylint version is:
The rc diff applied on top of 2.11.1 generate-rc command is: diff --git a/.pylint.rc b/.pylint.rc
index 6dfc542..547412c 100644
--- a/.pylint.rc
+++ b/.pylint.rc
@@ -85,6 +85,9 @@ disable=raw-checker-failed,
suppressed-message,
useless-suppression,
deprecated-pragma,
+ unused-import,
+ missing-module-docstring,
+ invalid-name,
use-symbolic-message-instead
# Enable the message, report, category or checker with the given id(s). You can |
As an aside I came across this whilst looking for a pylint checker that checks for
-- PEP-402, on issues like this one, |
Thanks @doublethefish, you've clearly demonstrated this is not currently an issue. I imagine this was fixed in |
Based on the investigation above from @doublethefish I did some more digging since for me the issue is still not resolved. There is still an inconsistency between Test setupI used the I have taken the
And file contents as follows (same as above): # fruit[1 or 2]/apple's __init__.py:
import math # std lib
import fruit[1 or 2].banana.data # update the fruit number for each test candidate
import numpy
import fruit[1 or 2].apple.data # fruit[1 or 2]/apple/data.py
data = "some apple data" # fruit[1 or 2]/banana's __init__.py:
# empty file # fruit[1, 2 or 3]/banana/data.py
data = "some banana data" pylint inconsistencyNow given the directory structure above, pylint behaves differently for me depending on where it is invoked: > # in the root directory
> pylint --rcfile .pylintrc apple/fruit2/apple/__init__.py
************* Module apple
apple/fruit2/apple/__init__.py:6:0: C0412: Imports from package fruit2 are not grouped (ungrouped-imports)
------------------------------------------------------------------
Your code has been rated at 7.50/10 (previous run: 7.50/10, +0.00)
cd apple
> pylint --rcfile ../.pylintrc fruit2/apple/__init__.py
************* Module apple
fruit2/apple/__init__.py:4:0: C0411: third party import "import numpy" should be placed before "import fruit2.banana.data" (wrong-import-order)
fruit2/apple/__init__.py:6:0: C0412: Imports from package fruit2 are not grouped (ungrouped-imports)
------------------------------------------------------------------
Your code has been rated at 5.00/10 (previous run: 7.50/10, -2.50) isort inconsistencyInvoking isort from the cd apple
isort fruit2/apple/__init__.py
# no output, no changes
cd .. # back to repo root
isort apple/fruit2/apple/__init__.py
> Fixing pylint-issue-demo/apple/fruit2/apple/__init__.py with this diff --git a/apple/fruit2/apple/__init__.py b/apple/fruit2/apple/__init__.py
index fd23b38..1970b58 100644
--- a/apple/fruit2/apple/__init__.py
+++ b/apple/fruit2/apple/__init__.py
@@ -1,6 +1,5 @@
import math
+import fruit2.apple.data
import fruit2.banana.data
import numpy
-
-import fruit2.apple.data Note: For the diff --git a/fruit1/apple/__init__.py b/fruit1/apple/__init__.py
index fa74f83..642d85b 100644
--- a/fruit1/apple/__init__.py
+++ b/fruit1/apple/__init__.py
@@ -1,6 +1,6 @@
import math
-import fruit1.banana.data
import numpy
import fruit1.apple.data
+import fruit1.banana.data |
Thanks for the additional details @lukasbindreiter! Have you tested against |
|
@lukasbindreiter having had a better look at your examples, what you have crafted in your example is a Nested Namespace Package, which will exhibit different behaviours depending on where you run Therer are two key differences:
Additionally, in your first Then, in the second I guess one way to think about it is, "can we run the example code from Another way to think about it is run-context, or To summarise, depending on where we run |
I have changed my mind and OP is correct (now that I understand it). Imports inside a Nested Namespace Package should be treated consistently in all cases.
I was wrong that it "cannot be otherwise" because I had the wrong logical basis, but it is hard for tools to detect local vs third-party imports in both types of Namespace Packages (those packages without There are two logical options here that shape the design:
As OP implies, option 2 is probably a better, more intuitive option. Taking option 2 as correct then each sub-package in a Nested Namespace Package, should always differentiate between first-order imports (local-sibling submdoules) vs third-party imports (non-local sibling submodules), as follows (should be testable @yushao2): # Namespace Package (currently ok), here for reference:
# NOTE: no __init__.py files although a regular package behaves the same.
src/
parent/
child_a/
a.py # should treat parent.child_a.a_sibling and parent.child_b.b_sibling as first-party (because both are inside parent)
a_sibling.py
child_b/
b.py # should similarly treat a_sibing & b_sibling as first-party because of the shared root
b_sibling.py
# Nested Namespace Package:
container/
project1/
src/
parent/
child/
a.py # should treat parent.child.a_sibling as first-party, but parent.child.b_sibling as third-party (because of the project1 vs project2 root dirs)
a_sibling.py
project2/
src/
parent/
child/
b.py # should similarly treat parent.child.b_sibling as first-party, but parent.child.a_sibling as third-party
b_sibling.py To get to this conclusion, I wrote an issue (unsubmitted) for isort and reviewed one of my own NNPs. Doing so I realised that my NNP imports were actually incorrect vs what I hoped for at the time - I remember being frustrated at the time but found a way to adhere to what the tooling does, and accepted that. All of that is why I submitted #7085 to pylint, because it helps work around related issues. I also looked at Tim's line in So, yeah, OP is right after all :D |
Also see this issue in |
@doublethefish do we agree it's an isort issue and pylint is not using isort incorrectly ? |
I don't know. isort certainly has an issue, and I would assume that any upstream fix in isort would then have to be reflected in the corresponding pylint checker. |
Relevant code : We use |
Just tested it with the latest astroid commit, but the behaviour is exactly the same as described in my last comment, so no changes there. |
@doublethefish Thanks for the detailed response. I was unaware of the term From your response I agree that option 2 would be the most logical, intuitive approach, but I understand that it may very well be complicated for tools to achieve 😄 The issue with different behaviour from different working directories is not really that much of a problem, I just wanted to raise that as a concern as well, but the working directory itself can be easily enough configured in a CI pipeline. The main problem (and also the reason for this issue in the first place) is this: When invoked from the correct working dir, import math
import fruit2.banana.data
import numpy
import fruit2.apple.data However, when
I'm assuming this is because For import math
import numpy
import fruit2.apple.data
import fruit2.banana.data which is accepted by Any ideas for a workaround here are very welcome 😄 |
Thank you for analysis the issue in depth. We need to fix that part then. I think it needs some investigation, but in general pylint do not handle not being called from the root directory very well. Maybe we have to permit to define the path to the isort config in our own configuration. |
Steps to reproduce
Create two python packages
apple
andbanana
that share a common namespacefruit
.banana
is a dependency ofapple
.Create a module in
apple
with the following code:Sort the mentioned module with
isort
(no change)Run
pylint
Current behavior
Expected behavior
No warning / error
Explanation
In contrast to
isort
(the command-line tool),pylint
incorrectly classifiesimport fruit.banana.data
as a first party import.This bug results from
pylint
callingisort_driver.place_module("fruit")
(returning "first party") instead ofisort_driver.place_module("fruit.banana.data")
(would return "third party"):https://github.com/PyCQA/pylint/blob/v2.8.2/pylint/checkers/imports.py#L723
The text was updated successfully, but these errors were encountered: