0

I'm trying to make my first advanced python project but I'm struggling long time with imports.

Can someone describe me the usage of imports in python? Docs found about python imports in the official page is not so suffucient for me...

Here is an example:

I have the following source structure:

$ ls -ltrR
.:
total 1
drwx------+ 1 Administrators None  0 Nov 15 14:09 b
-rwx------+ 1 Administrators None 24 Nov 15 14:10 a.py

./b:
total 6
-rwx------+ 1 Administrators None  0 Nov 15 14:08 c.py
-rwx------+ 1 Administrators None 16 Nov 15 14:10 __init__.py
drwx------+ 1 Administrators None  0 Nov 15 14:10 __pycache__
-rwx------+ 1 Administrators None 61 Nov 15 14:10 b.py

and the content of the files:

$ cat a.py
import b

b.B().printC()

$ cat b/b.py
import c

class B:
  def printC(self):
    print(c.C().get())

$ cat b/c.py
class C():
  def get(self):
    return 'This is C'

$ cat __init__.py
from .b import *

When I start a.py it says: ImportError: No module named 'c'. When I start b.py only it says everything's fine.

Another solution when in b.py i'm modifying the import to "import b.c" -> in this case when I call a.py it will work, but when I call only b.py it is not going to work as b.py doesn't know b package.

Why do I need to start a.py and b.py also? a.py should be an executor for UTs, and b.py should be a UT. That's why it can happen that I would like to call all of the UTs and start a.py, and also it can happen that I'm just starting a specific UT (b.py).

vpas
  • 513
  • 1
  • 5
  • 18

1 Answers1

0

In your a.py, instead of just having import b, try from b import b because you want to import b.py from the b module. Alternatively, in your b/init.py, have from b import * But this is a question of preference (Look at this thread for more information on this topic)

This is a good tutorial to get started with modules and packages. (For Python 2)

If you are using Python 3, then it's a little bit different. Python 3 no longer supports implicit package name imports. This link explains this well. So you are required to explicitly mention where the package actually is from by using relative import - from . import c instead of import c (in your b.py) and in a.py: from b import b instead of import b.

We avoid using relative importing in a.py, because we want to run it as a script. In Python 3, simply running a module that uses relative import, as a script will throw the Error: SystemError: Parent module '' not loaded, cannot perform relative import. This link explains this issue and provides a solution. If you want to execute a module like a stand alone script you can use the -m flag: check the docs.

So, in your case:

a.py:

from b import b

b.B().printC()

b.py:

from . import c

class B:
    def printC(self):
        print(c.C().get())

c.py: no change Its good to explicitly cite only the modules/classes/functions you really need to import instead of importing a whole module, for lookup efficiency. But if you really wanted to just import the whole "b" package by using import b instead of just importing the b.py module from the b package using from b import b, you need to include all the modules that you mean to ship out in the all variable in your b/init.py like so:

__all__ = ['b', 'c']
from . import *

As explained very well in this post.

Hope this was useful.

Community
  • 1
  • 1
kartikg3
  • 2,590
  • 1
  • 16
  • 23
  • from b import b is not sufficient as b folder is a folder containing lot of UTs and I don't want to list UTs one by one.. btw I tried your suggestion but it is not ok, the error is the same. from b import * is still not OK. ...thanks for tuts i will check them – vpas Nov 15 '14 at 13:54
  • I ran your code on my end and it works fine. Which version of Python are you using? – kartikg3 Nov 15 '14 at 13:58
  • $ python --version Python 3.3.2 (maybe i did something wrong, could you please share your code?) – vpas Nov 15 '14 at 14:00
  • I am going to try the code using your version. I tried it using 2.7.3 – kartikg3 Nov 15 '14 at 14:05
  • It worked on my end because Python 2 supported implicit imports from with packages. Python 3 does not. I have edited the answer to reflect that. – kartikg3 Nov 15 '14 at 14:21
  • how should init.py look like? I have changed the import in a.py to `from . import b` but now i'm getting the error `from . import b SystemError: Parent module '' not loaded, cannot perform relative import` – vpas Nov 15 '14 at 14:32
  • We avoid using relative importing in a.py, because we want to run it as a script. In Python 3, simply running a module that uses relative import, as a script will throw the Error: `SystemError: Parent module '' not loaded, cannot perform relative import`. I have edited the answer to reflect the same. – kartikg3 Nov 15 '14 at 14:41
  • My problems with this: In a.py i will have to list all files from b if i want to use in it which is unaccaptable as in b module there can be a lot of files... another problem is that: b.py will be possible to be called via a.py because of that import... standalone execution can't be done... – vpas Nov 15 '14 at 14:48
  • Its good to explicitly cite only the modules/classes/functions you really need to import instead of importing a whole module, for lookup efficiency. But if you really want to import the whole package, you should do this in your case: in a.py: `import b` and then `b.b.B().printC()`, because b.py is a module inside of b package, you need to call `b.b.B()`.. Ofcourse, in which case, you ll need `from .b import *` in your b/__init__.py – kartikg3 Nov 15 '14 at 14:54
  • Sorry, thank you for your help, but I can't accept it as a solution, since it is not possible to start b.py standalone. – vpas Nov 15 '14 at 21:01
  • it would be really ugly to do that: `try: from . import c except: import c` – vpas Nov 15 '14 at 21:26
  • It is possible to start b.py as stand alone by using the -m flag. It is in one of the links. I have provided all the right links for you. Python 3 enforces this type of behaviour, and yes the try except is a very ugly bypass. – kartikg3 Nov 15 '14 at 21:41
  • If you want to execute a module like a stand alone script you can use the -m flag: check the docs: https://docs.python.org/3/using/cmdline.html#cmdoption-m Its been updated in the answer too. – kartikg3 Nov 15 '14 at 21:55