I'm learning Python using a book that uses Window's based examples and they use these as examples (the comments are the filenames):
# dir1\__init__.py
print('dir1 init')
x = 1
# dir1\dir2\__init__.py
print('dir1 init')
y = 2
# dir1\dir2\mod.py
print('in mod.py')
z = 3
Now using IDLE, it attempts to import the files using:
import dir1.dir2.mod
Which will display:
dir1 init
dir2 init
in mod.py
When I attempt to do this on IDLE on my Mac it comes up with an error saying there is no module named dir1.
The point of the exercise is to package imports but I don't if I'm formatting the files incorrectly or importing incorrectly.
I think the files are not in the same directory from where the IDLE is running or looking at.
Try to see where the IDLE is on your Mac, complete path. Once find that out may be try putting the files in the same place so that python can see those files.
As an experiment, I'd suggest, writing your scripts in an editor like VS Code. cd into the directory where you have saved the script. Run the script by python yourfilename.py and see what it says then. Personally, I have never used the IDLE but I have come across python not being able to find the file.
I'm not sure what exactly you are asking, but your file structure should look like this in Finder:
which is:
dir1
|-- __init__.py
|-- dir2
|-- __init__.py
|-- mod.py
And you need to make sure that your working directory in IDLE is the directory where dir1 is located. I don't think you can change that in IDLE, but you could do this to make it work:
>>> import sys
>>> sys.path.insert(0,'/path/to/directory/where/dir1/is/stored')
Related
I have project that I decided to divide into subfolders. My main module main.py imports other module mod1.py from a subfolder. The imported module mod1.py uses images that are located in another subfolder and refers to them relatively. I can't use absolute path from the drive, but I know the relative path from the beginning of the project structure.
The situation is illustrated below somehow
project
├── main.py
└───subfolder
├───mod1.py
└───pictures
└───pic1.png
So there's a line in mod1.py:
image = Image.open("./pictures/pic1.png")
and when I import mod1.py in main.py and run the program I get an error:
FileNotFoundError: [Errno 2] No such file or directory: './pictures/pic1.png'
How to access those pictures when I run main.py and import a module that relatively refers to them?
I have __init__.py file in the subfolder and all the imports are working.
try this
try:
image = Image.open("pictures/pic1.png")
except FileNotFoundError:
image = Image.open("subfolder/pictures/pic1.png")
so python will try the first path, if it fails, it will try the second, which looks for the main.py file
While Jorge's answer may work in some cases I suggest understanding why yours does not work and look how other people have solved this problem. Lets take a very simple example.
project
dir1
test.py
dir2
test2.py
Lets assume the full path to my project directory is located at /Users/sstacha/tmp/test_python/ and my 2 test files contain the following
test.py
import os
from pathlib import Path
from dir2.test2 import function2
def function1():
path = os.getcwd()
print(f"function1.os.cwd(): {path}")
DIR = Path(__file__).resolve()
print(f"function1.pathlib_path: {DIR}")
function1()
function2()
test2.py
import os
from pathlib import Path
def function2():
path = os.getcwd()
print(f"function2.os.cwd(): {path}")
DIR = Path(__file__).resolve()
print(f"function2.pathlib_path: {DIR}")
if i execute python dir1/test.py from the project directory I get the following output:
$ python dir1/test.py
function1.os.cwd(): /Users/sstacha/tmp/test_python
function1.pathlib_path: /Users/sstacha/tmp/test_python/dir1/test.py
function2.os.cwd(): /Users/sstacha/tmp/test_python
function2.pathlib_path: /Users/sstacha/tmp/test_python/dir1/dir2/test2.py
if I instead cd to dir1 and execute python test.py I get this output:
$ python test.py
function1.os.cwd(): /Users/sstacha/tmp/test_python/dir1
function1.pathlib_path: /Users/sstacha/tmp/test_python/dir1/test.py
function2.os.cwd(): /Users/sstacha/tmp/test_python/dir1
function2.pathlib_path: /Users/sstacha/tmp/test_python/dir1/dir2/test2.py
So your actual problem is that os.cwd() will always be set to whatever directory the os was set to when the python command was run. I also included a line from how the Django settings file handles this issue for python >= 3.4. As you can see, this approach will be relative to whatever file your function is defined in which should be a better / more portable solution regardless of what directory the python executable is called from.
Hopefully that helps you understand your issue better and a possible solution that might work for you.
I realized I never really fully answered the question here would be an example:
DIR = Path(__file__).resolve().parent
image = Image.open(DIR+"/pictures/pic1.png")
By the way if you are using a version earlier than 3.4 this is how the Django settings file approached it:
DIR = os.path.dirname(os.path.abspath(__file__))
image = Image.open(DIR+"/pictures/pic1.png")
I have looked up solutions online for this issue, but none of them seem to address my specific situation.
I have a pycharm project with multiple directories, subdirs and files. When I invoke the main entry point method from the command line, I get
ModuleNotFoundError on all the imports across ~20 files. The solutions I found online recommend modifying the PYTHONPATH. This is not a viable solution for my use case because
I would have to add the sys.path.append call in all my files. That's the only way that it seems to work.
I cannot use any third party libs.
I will be sharing the project as a zip file. Note: I cannot use github to share the project nor is my intention to create a distributable. So when someone else unzips the project on their PC, they should be able to run it from the command line with out any issues. They should not have to modify their env variables to run it.
What are my options?
EDIT:
Project structure:
Project-
|
|
mod-
|
|
data-
|
|
ClassA.py
ClassB.py
|
config-
|
|
ClassC.py
ClassD.py
...
main.py
Import statements look like this:
from mod.data.ClassA import ClassA
Error:
ModuleNotFoundError: No module named 'ClassA'
This error shows up for every import statement in my python files.
When I add sys.path.append it works, but I have to do it for every import statement and its a hard coded abs path that will need to be updated by anyone with the zip.
If your modules are contained in the same directory as your executable, as you seem to indicate, it's this simple:
File structure:
f1.py
m1
__init__.py
C1.py
C1.py
class C1:
def test(self):
print("Hi!")
f1.py
#!/usr/bin/env python
from m1.C1 import C1
C1().test()
Execution:
> python f1.py
Hi!
You do have __init__.py files in your module directories, right? If not, then that's probably why you're having trouble with this.
I'm trying to follow Learn Python the Hard Way to teach myself python. I want to use the directory structure described in Exercise 46, which for my question I'll simplify down to this:
bin/
app.py
data/
__init__.py
foobar.py
In exercise 50, he says to start the program from the project's top level directory like this:
$ python bin/app.py
Afterwards stating that you start it from the top level directory so the script can access other resources in the project.
But I can't seem to import modules that are in the data folder from app.py. Am I misunderstanding how to setup the directory structure?
Edit: Here's the bare-bones setup I have to try and figure this out
In app.py I have:
import data.foobar
I have __init__.py in the data directory and foobar.py just contains some nonsense like:
class Test:
x = 0
The directory structure matches that of above.
I'm not sure what the exercise asks to do, but your top-level directory needs to be in the PYTHONPATH. Try:
$ export PYTHONPATH=$PYTHONPATH:$PWD
$ python bin/app.py
I understand that this question has been asked several times but after reading them, and making the suggested fixes, I'm still stumped.
My project structure is as follows:
Project
|
src
|
root - has __init__.py
|
nested - has __init__.py
|
tests - has __init__.py
|
utilities - has __init__.py
|
services - has __init__.py
I've successfully run a unittest regression class from Eclipse without any issues.
As soon as I attempted to run the same class from the command-line (as other users who will be running the suite do not have access to Eclipse) I receive the error:
ImportError: No module named 'root'
As you can see from above, the module root has an __init__.py
All __init__.py modules are completely empty.
And assistance would be gratefully received.
Try adding a sys.path.append to the list of your imports.
import sys
sys.path.append("/Project/src/")
import root
import root.nested.tests
Just a note for anyone who arrives at this issue, using what Gus E showed in the accept answer and some further experience I've found the following to be very useful to ensure that I can run my programs from the command-line on my machine or on another colleague's should the need arise.
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), "..", ".."))
When I execute the 'main' method, which is located in the 'nested' directory, it ensures that the 'src' directory is added to the PYTHONPATH at the time of execution meaning all following imports will not throw an error.
Obviously, you need to adjust the number of ".." arguments to the os.path.join() method as determined by the location in your program of where your main method is executed from
Yet another way to solve this without the path goes like this: consider the following code where inside your folder name 'app' you have 3 files x.py, y.py and an empty init.py. So to run x.py you have an import from y such that:
x.py
from app.y import say_hi
print ("ok x is here")
say_hi()
And
y.py
print ("Im Y")
def say_hi():
print ("Y says hi")
so the folder structure would look like this:
testpy
app
__init__.py
x.py
y.py
Solution: in the folder BEFORE app do the following:
$ python -m app.x
Note: I did not use x.py (simply app.x)
Result:
Nespresso#adhg MINGW64 ~/Desktop/testpy
$ python -m app.x
Im Y
ok x is here
Y says hi
If anybody lands here:
I encountered this error as well. In my case, I used ~/my/path/ at the path.sys.append(...), and the fix was replacing ~ with the explicit path name (you can inquire it if you type pwd when you are on linux shell, or use os.path.expanduser(..) )
Another way to do this so python searches for modules in the current directory is to add it as an environment variable to your .bash_profile / .zshrc / etc. like so:
export PYTHONPATH="${PYTHONPATH}:."
I have a directory struture like that:
project
| __init__.py
| project.py
| src/
| __init__.py
| class_one.py
| class_two.py
| test/
| __init__.py
| test_class_one.py
Which project.py just instantiate ClassOne and run it.
My problem is in the tests, I don't know how to import src classes. I've tried importing these ways and I got nothing:
from project.src.class_one import ClassOne
and
from ..src.class_one import ClassOne
What am I doing wrong? Is there a better directory structure?
----- EDIT -----
I changed my dir structure, it's like this now:
Project/
| project.py
| project/
| __init__.py
| class_one.py
| class_two.py
| test/
| __init__.py
| test_class_one.py
And in the test_class_one.py file I'm trying to import this way:
from project.class_one import ClassOne
And it still doesn't work. I'm not using the executable project.py inside a bin dir exactly because I can't import a package from a higher level dir. :(
Thanks. =D
It all depends on your python path. The easiest way to achieve what you're wanting to do here is to set the PYTHONPATH environment variable to where the "project" directory resides. For example, if your source is living in:
/Users/crocidb/src/project/
I would:
export PYTHONPATH=/Users/crocidb/src
and then in the test_one.py I could:
import project.src.class_one
Actually I would probably do it this way:
export PYTHONPATH=/Users/crocidb/src/project
and then this in test_one.py:
import src.class_one
but that's just my preference and really depends on what the rest of your hierarchy is. Also note that if you already have something in PYTHONPATH you'll want to add to it:
export PYTHONPATH=/Users/crocidb/src/project:$PYTHONPATH
or in the other order if you want your project path to be searched last.
This all applies to windows, too, except you would need to use windows' syntax to set the environment variables.
From Jp Calderone's excellent blog post:
Do:
name the directory something related to your project. For example, if your
project is named "Twisted", name the
top-level directory for its source
files Twisted. When you do releases,
you should include a version number
suffix: Twisted-2.5.
create a directory Twisted/bin and put your executables there, if you
have any. Don't give them a .py
extension, even if they are Python
source files. Don't put any code in
them except an import of and call to a
main function defined somewhere else
in your projects. (Slight wrinkle:
since on Windows, the interpreter is
selected by the file extension, your
Windows users actually do want the .py
extension. So, when you package for
Windows, you may want to add it.
Unfortunately there's no easy
distutils trick that I know of to
automate this process. Considering
that on POSIX the .py extension is a
only a wart, whereas on Windows the
lack is an actual bug, if your
userbase includes Windows users, you
may want to opt to just have the .py
extension everywhere.)
If your project is expressable as a single Python source file, then put it
into the directory and name it
something related to your project. For
example, Twisted/twisted.py. If you
need multiple source files, create a
package instead (Twisted/twisted/,
with an empty
Twisted/twisted/__init__.py) and place
your source files in it. For example,
Twisted/twisted/internet.py.
put your unit tests in a sub-package of your package (note - this means
that the single Python source file
option above was a trick - you always
need at least one other file for your
unit tests). For example,
Twisted/twisted/test/. Of course, make
it a package with
Twisted/twisted/test/__init__.py.
Place tests in files like
Twisted/twisted/test/test_internet.py.
add Twisted/README and Twisted/setup.py to explain and
install your software, respectively,
if you're feeling nice.
Don't:
put your source in a directory called src or lib. This makes it hard
to run without installing.
put your tests outside of your Python package. This makes it hard to
run the tests against an installed
version.
create a package that only has a __init__.py and then put all your code into __init__.py. Just make a module
instead of a package, it's simpler.
try to come up with magical hacks to make Python able to import your module
or package without having the user add
the directory containing it to their
import path (either via PYTHONPATH or
some other mechanism). You will not
correctly handle all cases and users
will get angry at you when your
software doesn't work in their
environment.