-3

New to Python I'm trying to setup a simple OOP-structure of files, folders and classes. Here are the file paths:

  • C:\Users\Mc_Topaz\Programmering\Python\Terminal\Main.py
  • C:\Users\Mc_Topaz\Programmering\Python\Terminal\Connections\Connection.py
  • C:\Users\Mc_Topaz\Programmering\Python\Terminal\Connections\NoConnection.py

Notice Connection.py and NoConnection.py is loacted in sub folder Connections.

Connection.py

class Connection:
    def __init__(self):
        pass

    def ToString(self):
        pass

NoConnection.py

from Connection import Connection

class NoConnection(Connection):
    def __init__(self):
       pass

    def ToString(self):
        print("No connection")

In the Main.py file I would like to call the ToString() method from each class.

Main.py

from Connections.Connection import Connection
from Connections.NoConnection import NoConnection

connection = Connection()
print(connection.ToString())

noConnection = NoConnection()
print(noConnection.ToString())

When I run the Main.py file I get this error:

C:\Users\Mc_Topaz\Programmering\Python\Terminal>Main.py Traceback (most recent call last): File "C:\Users\Mc_Topaz\Programmering\Python\Terminal\Main.py", line 2, in from Connections.NoConnection import NoConnection

File "C:\Users\Mc_Topaz\Programmering\Python\Terminal\Connections\NoConnection.py", line 1, in from Connection import Connection

ImportError: No module named 'Connection'

It seems that the interpreter cannot import the NoConnection class in my Main.py file due to it cannot import the Connection class from the NoConnection.py file. I can run Connection.py and NoConnection.py separately with no problems.

I don't understand why the Main.py don't run. I assume is something super simple and I cannot see it due to I'm to green to Python.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Mc_Topaz
  • 567
  • 1
  • 6
  • 21
  • 1
    possible duplicate of [What is \_\_init\_\_.py for?](http://stackoverflow.com/questions/448271/what-is-init-py-for) – simonzack Nov 22 '14 at 20:35
  • Can't be lack of \_\_init\_\_.py because it finds Connection ok? – demented hedgehog Nov 22 '14 at 20:37
  • One source of general weirdness (unrelated to your problem) is you're printing something in your tostring methods and not returning anything. So it prints some Nones as well. – demented hedgehog Nov 22 '14 at 20:41
  • This may not be directly relevant, but I've always found it helpful to import your project in pycharm. It fixes a lot of your path problems. – simonzack Nov 22 '14 at 20:41
  • Ah I get the error in Python3 – demented hedgehog Nov 22 '14 at 20:46
  • @dementedhedgehog How can that make a difference? Theres no python 3 specific names in there. – simonzack Nov 22 '14 at 20:47
  • No idea.. it's working again. But I did see it. So possibly not python3 something a little weird. Relative paths handling? – demented hedgehog Nov 22 '14 at 20:55
  • You are right simonzack. My post is a probably a repost. But since I'm new to Python I didn't know about the __inti__.py file. Still I don't get it to work with the __init__.py file :( – Mc_Topaz Nov 22 '14 at 21:07
  • Stop this nonsense with the .py files. In python it's considered bad practice if you create separate files for each class. Also start using `__main__` check. Please start googling. – Kobor42 Dec 18 '14 at 10:13

4 Answers4

1

For python to recognize a directory is a module, or a collection of python files, that directory must contain a file named __init__.py. That file doesn't need to contain anything code whatsoever, though it can. If you add this file to your Connections directory, the interpreter should be able to import the contained files.

mobiusklein
  • 1,403
  • 9
  • 12
  • Can you update your directory layout to show me where you put the `__init__.py` file please? I realized my definition wasn't explicit about where it should be. It should be in the Connections/ directory. – mobiusklein Nov 22 '14 at 20:24
0

Just to add on to what mobiusklein mentioned: a common practice with __init__.py is to import the objects you use most frequently to avoid redundancy in your imports. In your example your Connections\__init__.py would likely contain:

import Connection
import NoConnection

Then your Main.py could use the following import statements successfully:

from Connections import Connection, NoConnection
griff
  • 19
  • 3
0

I think it's down to relative imports in Python 3.

Change the import line in NoConnection to be explicit...

 from Connections.Connection import Connection

and it works in Python3 (it works either way in Python2). Path to Terminal may have to be on you PYTHONPATH environment variable.

"Python 3 has disabled implicit relative imports altogether; imports are now always interpreted as absolute, meaning that in the above example import baz will always import the top-level module. You will have to use the explicit import syntax instead (from . import baz)." from here https://softwareengineering.stackexchange.com/questions/159503/whats-wrong-with-relative-imports-in-python

So when you import Connection from NoConnection it will be looking for it at the Terminal level, not at the Terminal/Connections level.

Community
  • 1
  • 1
demented hedgehog
  • 7,007
  • 4
  • 42
  • 49
  • Take a look at this.. http://python-notes.curiousefficiency.org/en/latest/python_concepts/import_traps.html – demented hedgehog Nov 22 '14 at 21:23
  • Thanks but that didn't work. If I change to Connections.Connection import Connection I cannot run NoConnection.py by itself. – Mc_Topaz Nov 22 '14 at 21:47
  • So Main.py still fails with the ImportError? If from Connections.Connection import Connection works in Main.py it should also work in NoConnection.py – demented hedgehog Nov 22 '14 at 21:50
  • Yes. I just made a new response to my own post. That one where the class name are changed. The problem is still there for me... – Mc_Topaz Nov 22 '14 at 22:13
0

UPDTAE: Read comments for this post as it contain the solution.

Still don't get this to work. But I have made some changes:

Changed names of classes

  • > Class Connection = Foo inside Connection.py
  • > NoConnection = Bar inside NoConnection.py

This is ensure that the interpreter don't get confused if Connection is a module or a class.

Dropped ini.py file

I have dropped the Connections\__init_.py file as this don't seem to be necessary in Python version 3.4.2.

Files still run separately

I can run Connection.py and NoConnection.py separately. So they work.

Main.py

from Connections.NoConnection import Bar

noConnection = Bar()
print(noConnection.ToString())

When running Main.py I get the same error at line 1: "Cannot find module 'Connection' in NoConnection.py at line 1".

The only logical reason I can see why this error happens is:

The interpreter looks for Connection.py inside my Terminal folder as Python was started from that folder. Even if it's importing the NoConnection.py file from the Connections folder where Connection.py is located.

Is this a bug?

Mc_Topaz
  • 567
  • 1
  • 6
  • 21
  • It's not a bug in Python. At the risk of sounding like a broken record.. can you paste in what NoConnection.py looks like? That's where your problem is. – demented hedgehog Nov 22 '14 at 22:18
  • from Connection import Foo class Bar(Foo): def __init__(self): print("ctor NC") def ToString(self): print("No connection") print("NoConnection.py") – Mc_Topaz Nov 22 '14 at 22:23
  • you need from Connections.Connection import Foo... Python3 doesn't like relative imports so it will be looking for Connection down in the Main.py parent dir – demented hedgehog Nov 22 '14 at 22:25
  • Yes that works. Thanks! BUT! If I run NoConnection.py separately it won't work. Is this something I should ignore? – Mc_Topaz Nov 22 '14 at 22:27
  • Cool. That's a good question. Python3 still allows you to use relative imports. You just have to be explicit about it, BUT it doesn't allow them from a non-module. So from .Connection import Connection (note the . same semantics as cwd .). So you don't need to the full path to Connection in NoConnection but if you try and run NoConnection.py it'll fail with a different error "ValueError: Attempted relative import in non-package". Alternatively, if you add C:\...\Python\Terminal to your PYTHONPATH evnironment variable then the full path import version of NoCOnnection will work. – demented hedgehog Nov 22 '14 at 22:36
  • Also three other things: i) relative imports are not good... you should avoid them they lead to problems. ii) If your library is going to be called Terminal then point your PYTHONPATH at C:\Users\Mc_Topaz\Programmering\Python and use from Terminal.Connections.Connection import Connection. and iii) take a look at PEP 8 if you want your python code to look a little more like idiomatic python. cheers mate.. I learnt some things from this. – demented hedgehog Nov 22 '14 at 22:39
  • Thanks a lot demented hedgehog! I will consider your suggestions. Can you mark this answer as the solution? I can only do that day after tomorrow... O_o – Mc_Topaz Nov 22 '14 at 22:48
  • I don't think I can.. I think it's something that only the asker can do. – demented hedgehog Nov 22 '14 at 22:51