- 
          
 - 
                Notifications
    
You must be signed in to change notification settings  - Fork 657
 
Consistent PEP8-compliant imports layout #901
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
Conversation
| 
           @sisp thanks for the PR. I have no strong opinion about using isort or reorder-python-imports. Seems like we have a problem in   | 
    
          
 No, I'm not sure why there is this large difference in rating.  
 Off the top of my head: But the author looks very solid to me. 
 Yes, there is an issue with circular imports which didn't show up before as imports were sorted in a way that didn't reveal the problem. A fix is coming in a second.  | 
    
| 
           @sisp so to better understand the problem with  Anyway, we can go with   | 
    
| 
           The way I understand it, in order for  - id: isort
  name: isort
  entry: isort -rc .
  language: system
  require_serial: true
  types: [python]But for some reason I have yet to understand  While this is getting slightly beyond the scope of this PR, in my opinion   | 
    
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thanks @sisp !
| 
           @sisp sorry for reiterating on that, after private discussions with the team, we prefer to keep multiline imports instead of single line (even taking into account the argument on git conflicts). Could you please configure the tool for that ? Thank you  | 
    
| 
           
  | 
    
| 
           @sisp thanks a lot for working on that ! Yes, seems like   | 
    
| 
           Just to clarify: Would you like a different multi-line output mode (e.g. "0 - Grid") or is all you'd like the setting   | 
    
| 
           Well, idea is to keep the imports as "0 - Grid" and "Intelligently Balanced Multi-line Imports" seems to be the best fit...  | 
    
| 
           I just noticed this setting   | 
    
| 
           @sisp can we do something with that in order to keep "0 - Grid" ?  | 
    
| 
           I don't think so because   | 
    
          
 OK, I see what you mean. Seems like two tools can not play well without multiplying the number of imports...  | 
    
| 
           Could you elaborate a bit on what you dislike about the way  Before this PR, the imports layout was not consistent, e.g.: -from ignite.contrib.handlers import ProgressBar
-from ignite.contrib.handlers import VisdomLogger
-from ignite.contrib.handlers import TensorboardLogger, global_step_from_engine
-from ignite.contrib.handlers import MLflowLogger
-from ignite.contrib.handlers import PolyaxonLogger
+from ignite.contrib.handlers import (
+    MLflowLogger,
+    PolyaxonLogger,
+    ProgressBar,
+    TensorboardLogger,
+    VisdomLogger,
+    global_step_from_engine,
+)I don't see a limitation in  If you feel there are too many imports in a module, perhaps the module needs to be refactored or modules rather than specific classes/functions should be imported. In fact, there are inconsistencies of that sort right now, e.g.: from ignite.contrib.handlers import MLflowLogger
import ignite.contrib.handlers.mlflow_logger as mlflow_logger_module | 
    
| 
           @sisp well, IMO, my perfect reformatting would do the following: -from ignite.contrib.handlers import ProgressBar
-from ignite.contrib.handlers import VisdomLogger
-from ignite.contrib.handlers import TensorboardLogger, global_step_from_engine
-from ignite.contrib.handlers import MLflowLogger
-from ignite.contrib.handlers import PolyaxonLogger
+from ignite.contrib.handlers import MLflowLogger, PolyaxonLogger, ProgressBar
+from ignite.contrib.handlers import TensorboardLogger, VisdomLogger, global_step_from_engineYes, I agree that in some cases we can rework the code. But what can we do in this case for example in tests, when we need to import all classes: from ignite.contrib.handlers.param_scheduler import (
    ConcatScheduler,
    CosineAnnealingScheduler,
    LinearCyclicalScheduler,
    LRScheduler,
    ParamGroupScheduler,
    PiecewiseLinear,
    create_lr_scheduler_with_warmup,
)Maybe   | 
    
| 
           Interesting, I've never seen this layout. I actually prefer one import per line which means multiple lines for importing multiple classes/functions from the same module. It is consistent and also works for quite long import statements. But I guess it's a matter of taste.  | 
    
| 
           While looking at the code at bit more, I find it odd to pass a module to a function: ignite/ignite/contrib/engines/common.py Line 209 in 32275a8 
 Sure, this can be done in Python, but it means a logger module must implement a particular interface. Also, a class constructor like   | 
    
          
 
 
 I agree that  
 I see what you mean. Let me think about it...  | 
    
| 
           True, I just don't think of constructors as part of a public interface, i.e. I can't enforce the signature of a constructor.  | 
    
| 
           By the way, I'm not sure why tests are failing. GitHub just says "This check failed". Do you know what's wrong?  | 
    
          
 Maybe github service is out... I do not know. I restarted them  | 
    
| 
           @sisp could you please update this PR as we updated   | 
    
- removed redundant tests from frequency
| 
           @sisp thanks for the PR !  | 
    
This PR adds a pre-commit hook and CI jobs/steps to fix and check the Python imports layout so that it is consistent and PEP8-compliant. Different from my initial suggestion in #896 to use
isort, I now usereorder-python-importsfor reasons I'll discuss below. At this stage I consider this PR a basis for discussion about how to proceed.isortis great for auto-formatting imports, but it only works well when it is installed run in the same virtual environment in which the dependencies of a project are installed.While runtime dependencies are centrally managed in
setup.pyandconda.recipe/meta.yaml, development dependencies are installed where needed on the fly and in different ways. For instance,pre-commitpullsblackvia its own mechanism while Travis installsblackviapipwhile (before this PR) GitHub Actions use a community action forblack. In all of these cases, Ignite and its dependencies are not installed along with its development dependencies, soisortwouldn't be able to properly determine third party dependencies.One possible solution is to let
seed-isort-configdetermine third party dependencies forisortbeforeisortis run, but (at least to me) this feels like a small hack. An alternative solution - and the one I ended up using in this PR - is to usereorder-python-importswhich appears to be doing a better job at determining third party dependencies.Before this PR, Ignite mostly used several imports from the same package in one line, although there were cases where only one import per line was used.
reorder-python-importsaims at reducing merge conflicts which is why it produces only one import per line. Is this a format you agree with?At least for now
reorder-python-importsonly applies to Python files inignite/**andtests/**. Formatting imports inexamples/**leads to incorrect results because, e.g.,import utilsinexamples/fast_neural_style/neural_style.pyis classified as a third party dependency although it is a local module. There are many other cases like this. I suspect the misclassification is due to the non-standard project layout inexamples/**.There is a small downside to using
reorder-python-importsthough, in my opinion. At least VS Code's official Python extension does not seem to support it, so "format on save" won't work. And choosingisortin VS Code will lead to a different imports layout unless configured explicitly to match the layout produced byreorder-python-imports.