Python import acting strange (only uppercase working, not with relatives)

503 views Asked by At

I'm using PyCharm and Python 3 and I have the next python folder layout:

src/
    __init__.py
    command/
        __init__.py
        simpleremote/
            __init__.py
            Command.py
            GarageDoor.py
            GarageDoorOpenCommand.py
            Light.py
            LightOffCommand.py
            LightOnCommand.py
            RemoteControlTest.py
            SimpleRemoteControl.py

I created packages, as you can see. The file with the main method is RemoteControlTest.py which worked perfectly with these imports:

from pythonDesignPatterns.src.command.simpleremote.GarageDoor import GarageDoor
from pythonDesignPatterns.src.command.simpleremote.GarageDoorOpenCommand import GarageDoorOpenCommand
from pythonDesignPatterns.src.command.simpleremote.Light import Light
from pythonDesignPatterns.src.command.simpleremote.command import LightOnCommand
from pythonDesignPatterns.src.command.simpleremote.SimpleRemoteControl import SimpleRemoteControl

Previous to create the init.py files for the packages, I tried to use relative imports instead of the former ones, for example

from .command import LightOnCommand

but it gave me an error (going to call this Case A):

SystemError: Parent module '' not loaded, cannot perform relative import. 

so fiddling around I found out that this worked for the same line:

from command.simpleremote.Command import LightOnCommand

and the program was executed succesfully again, but if I use the "Refactor" option from the IDE (PyCharm) and rename "Command" to "command" , writing this line:

from command.simpleremote.command import LightOnCommand

it suddenly shows the error (Case B):

ImportError: No module named 'command.simpleremote'; 'command' is not a package

Which is the problem in each case (A and B)? I can't understand why it would work in between each cases when importing from command.simpleremote. Why not one level further or closer? Why is it working with capital 'C' and not 'c'? Is this case-sensitive?

I've looked at official Python docs, (and webs for PEP302, PEP328 and PEP420) but it's too complex for me in a single night. Can anyone make understand this in a simpler way (or tell me a resource I can read about this explained simpler)?

Thanks in advance

1

There are 1 answers

6
Michael Butscher On BEST ANSWER

I guess that you run RemoteControlTest.py directly.

Case A

Python's importer can't go to parent if the module was run directly as script instead of acquiring it going through the package structure.

The Python designers presumably didn't want to let submodules be called directly as scripts so there are no really good solutions for that. Mainly you can

  1. run the script with python -m command.simpleremote.RemoteControlTest when src is either current directory or in PYTHONPATH or
  2. use a testing framework which does the calling for you.

A more detailed discussion of possible solutions can be found at Relative imports in Python 3.

Case B

A consequence of the direct start is that "src/command/simpleremote" is in the module search path. "src" seems also to be added to the path but after "src/command/simpleremote".

Before case B on from command... the import mechanism didn't find matching "command" in "src/command/simpleremote" and continued looking in "src" where the command package was found -> success.

In case B it findscommand.py in "src/command/simpleremote" which isn't a package -> error.