8

Desiring to improve my Python style, I ran a PEP-8 style checker on one of my script and it complained about something I don't know how to fix. The prologue of the script is something like:

#! /bin/env python3

import sys
import os

exe_name = os.path.basename(os.path.realpath(__file__))
bin_dir = os.path.dirname(os.path.realpath(__file__))
inst_dir = os.path.dirname(bin_dir)
sys.path.insert(0, inst_dir+'/path/to/packages')

import mypackage.mymodule

and the style checker complain on the import mymodule line, stating that it should be a top of file. But I obviously can't move it before setting the path where it will be found. Is there a good way to achieve this (mandating an environment variable or a shell wrapper are not what I find better than my current code) while respecting PEP-8 recommendations at the same time?

AProgrammer
  • 51,233
  • 8
  • 91
  • 143
  • 6
    PEP-8 recommendations are just that: recommendations. I'd just tell the linter to ignore that one line. – Martijn Pieters Apr 03 '17 at 15:43
  • @MartijnPieters, that's was my first inclination (rules are either simple and exceptions are needed, or complex and not followed as nobody remember them) but I wondered if there was a common idiom that I was unaware of. – AProgrammer Apr 03 '17 at 15:49
  • Nah, this looks like a good exception. – Martijn Pieters Apr 03 '17 at 15:49
  • Just append the line with `# noqa`, so that lint would ignore it, like so `import mypackage.mymodule # noqa`. –  Jul 23 '18 at 10:42

3 Answers3

2

If you want to avoid path manipulation, you may be able to do so by using the under-known .pth feature.

sys.path should begin with the directory containing the main program either by name or by reference as ''. I assume that the file importing mymodule is not part of mypackage, so that the '' entry is not useful for importing mymodule.

sys.path should end with the site-packages directory for the executing binary. That is the normal place for added packages. If you do not want to move mypackage into site-packages, you can extend the latter 'vitually' by putting a mystuff.pth file in it. It should contain one line: the path to the directory containing mypackage. Call it myprojects. Then mypackage and any other package in myprojects can be imported as if they were in site-packages.

One advantage of .pth files is that you can put identical copies in multiple site-packages directories. For instance, I have multiple projects in F:/python. I have multiple versions of Python installed. So I have put python.pth containing that one line in the site-packages for each.

Terry Jan Reedy
  • 18,414
  • 3
  • 40
  • 52
0

The best strategy would be to put the sys.path related code in separate file and import it in working code file.

So, I will split above code in two files. One named my_module.py and other named working_module.py

Now my_module will contain below lines

import sys
import os

exe_name = os.path.basename(os.path.realpath(__file__))
bin_dir = os.path.dirname(os.path.realpath(__file__))
inst_dir = os.path.dirname(bin_dir)
sys.path.insert(0, inst_dir+'/path/to/packages')

and working_module will contain

import my_module
import mypackage.mymodule

because we are importing my_module before mypackage, it will execute the path related code before and your package will be available in path.

Rahul
  • 2,056
  • 1
  • 21
  • 37
  • 3
    Imports shouldn't alter functionality like that. It's super-duper bad form, and it doesn't make it clear *why* your code is failing when you take out the seemingly unneeded import. – Arya McCarthy Apr 03 '17 at 16:04
  • @aryamccarthy it is not changing/altering any functionality. You can write imports in another file if it too long. – Rahul Apr 03 '17 at 19:03
  • 3
    Adding another file just to respect a style guidance does not seem such a good idea to me. – AProgrammer Apr 03 '17 at 19:49
  • @AProgrammer it doesn't seems right then it would be better to ask Pep8 to silent/ignore these lines. – Rahul Apr 08 '17 at 17:59
-2

You can use importlib module (python 3.5) or imp for python 2.7 to load mypackage.mymodule programatically. Both have the same purpose:

mechanisms used to implement the import statement

This question might help you more: How to import a module given the full path?

https://docs.python.org/3/library/importlib.html#examples

https://docs.python.org/2/library/imp.html

Community
  • 1
  • 1
  • 7
    To what end? Only to not have an import statement after the `sys.path` manipulation? Just mark the line as ignored, never write more complicated code just to satisfy a style-guide recommendation. – Martijn Pieters Apr 03 '17 at 17:09