Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to import from a sibling directory in python3?

I have the following file structure:

bot
├── LICENSE.md
├── README.md
├── bot.py # <-- file that is executed from command line
├── plugins
│   ├── __init__.py
│   ├── debug.py
│   └── parsemessages.py
├── helpers
│   ├── __init__.py
│   ├── parse.py
│   └── greetings.py
└── commands
    ├── __init__.py
    └── search.py

bot.py, when executed from the command line, will load in everything in the plugins directory.

I want plugins/parsemessages.py to import parse from the helpers directory, so I do that:

# parsemessages.py
from ..helpers import parse
parse.execute("string to be parsed")

I run python3 bot.py from the command line.

I get the following error:

File "/home/bot/plugins/parsemessages.py", line 2, in <module>
  from ..helpers import parse
ValueError: attempted relative import beyond top-level package

So I change two dots to one:

# parsemessages.py
from .helpers import parse
parse.execute("string to be parsed")

...but I get another error:

File "/home/bot/plugins/parsemessages.py", line 2, in <module>
  from .helpers import parse
ImportError: No module named 'plugins.helpers'

How can I get this import to work?

It's worth noting that I'm not attempting to make a package here, this is just a normal script. That being said, I'm not willing to mess around with sys.path - I want this to be clean to use.

Additionally, I want parse to be imported as parse - so for the example above, I should be typing parse.execute() and not execute().

I found this post and this post, but they start with a file that's quite deep in the file structure (mine is right at the top). I also found this post, but it seems to be talking about a package rather than just a regular .py.

What's the solution here?

like image 481
snazzybouche Avatar asked Mar 06 '19 01:03

snazzybouche


People also ask

How do I import a file from one directory to another in Python?

We can use sys. path to add the path of the new different folder (the folder from where we want to import the modules) to the system path so that Python can also look for the module in that directory if it doesn't find the module in its current directory.

Can import Python file from same directory?

Make an empty file called __init__.py in the same directory as the files. That will signify to Python that it's "ok to import from this directory". The same holds true if the files are in a subdirectory - put an __init__.py in the subdirectory as well, and then use regular import statements, with dot notation.

How do you use relative import in Python?

Here is the solution which works for me: I do the relative imports as from .. sub2 import mod2 and then, if I want to run mod1.py then I go to the parent directory of app and run the module using the python -m switch as python -m app. sub1.

How do I import all files from another file in Python?

If you have your own python files you want to import, you can use the import statement as follows: >>> import my_file # assuming you have the file, my_file.py in the current directory. # For files in other directories, provide path to that file, absolute or relative.


1 Answers

You could remove the dots, and it should work:

# parsemessages.py
from helpers import parse
parse.execute("string to be parsed")

That's probably your best solution if you really don't want to make it a package. You could also nest the entire project one directory deeper, and call it like python3 foo/bot.py.

Explanation:

When you're not working with an actual installed package and just importing stuff relative to your current working directory, everything in that directory is considered a top-level package. In your case, bot, plugins, helpers, and commands are all top-level packages/modules. Your current working directory itself is not a package.

So when you do ...

from ..helpers import parse

... helpers is considered a top-level package, because it's in your current working directory, and you're trying to import from one level higher than that (from your current working directory itself, which is not a package).

When you do ...

from .helpers import parse

... you're importing relative to plugins. So .helpers resolves to plugins.helpers.

When you do ...

from helpers import parse

... it finds helpers as a top-level package because it's in your current working directory.

like image 135
jnrbsn Avatar answered Oct 30 '22 10:10

jnrbsn