I gotta be honest, after coding in Python for 3 years, your videos are always something I keep coming back to for little things here or there. It'll be like "I remember Anthony had a video on this... what did he say to do again?"
I just spent like 5 hours trying to get my imports working without modifying the sys path directly. This video is exactly what I was looking for. Thank ya!
Thanks Anthony, this is always useful! I just keep coming back to a video I have seen of yours whenever I run into these situations in "real life examples"
Would you still make all paths relative in your code? Like using pathlib to get the current path, and then going up directories from there? Or would you simply make all the paths relative to the main entrypoint as defined in setup.py?
if they're user-specified paths (like input files / etc.) I'd take them as arguments and deal with them that way if they're resource files I'd use `importlib.resources` to access them and not think about the pathing or layout (it might not even be on the filesystem!)
@@anthonywritescode I'm having difficulty understanding how importlib.resources works. If I have some dir structure like . ├── example-files │ ├── inputs │ │ ├── file1 │ │ └── file2 ├── requirements.txt ├── src │ ├── main.py ├── nested │ ├── dir │ │ ├── foo.py └── test ├── test1 If I want to load the example-files.inputs.file1 or example-files.inputs.file2 from src/main.py, how would I do it? What if I want to load it from nested/dir/foo.py? I tried simply doing from importlib.resources import files f = files('example-files.inputs') But I get "ModuleNotFoundError: No module named 'example-files'" If however I run the code above from the root DIR, it works fine. Are the modules somehow relative to the "executing directory" as well?
don't run, I agree. In all seriousness, I've not really run into this problem, but maybe that's because I just monoscript for console script like stuff, or use __file__ vs. os.cwd when trying to deal with paths of things, but it's been a while since I've had to do any of that kind of stuff.
I don't think the cwd should be on the import path; as the author of an import statement I want to know that the code I intend to import hasn't been overridden by the presence of a random module in somebody's current directory. The very idea that it would do this is slightly terrifying!
Anthony, thank you so much for making these videos. I have been doing PYTHONPATH for my whole life and never suspected there might be something wrong there. If I can be helpful for any of your project, just let me know. Your videos are wonderful, keep the good job
Great explanation, one thing is however missed: how to import from another file inside a folder in (like a/helpers.py) in a/main.py. Example: # a/helpers.py def answer2life(): return 42 # a/main.py from a.helpers import answer2life print(answer2life()) it looks ugly IMO when your directory is named src (instead of 'a' here). Any other way to do it?
I go over both ways in the video -- absolute imports I strongly prefer but there's also explicit relative imports but also your top-level module shouldn't be named `src` -- you're probably doing src-layout incorrectly: th-cam.com/video/sW1qUZ_nSXk/w-d-xo.html
@@anthonywritescode Thanks for your reply but I couldn't find my answer in that video. The layout I meant is something like this: myproject/ requirements.txt src/ __init__.py helpers.py main.py data/ ... tests/ How would you import functions from helpers.py in the main.py. The way that works for me (while using python -m src.main) is # main.py from src.helpers import funcA, funcB I would be grateful if you can elaborate what is the correct way of both doing both layout and import in this case.
@@mofiro6758 IMO it is. I usually name the module the same way as project/git repo (only replacing dashes to underscores), e.g. my-project/ requirements.txt my_project/ __init__.py __main__.py main.py helpers.py data/ ... tests/ I added __main__.py as it allows creating a nice entry point to the whole with: python -m my_project Also, you might consider using requirements.txt & requirements-minimal.txt if we're talking about a project that is meant to be deployable (in contrary to libraries or tools like flake8). In the latter req file you list only top level imports as loosely specified as possible, and you use this file to easily update requirements.txt which should have all dependencies with frozen versions. This guarantees you repeatable builds
What really annoys me more than the behavior of Python when running a script is that the ratio of actual best practices to garbage non-solutions on the web is tiiiiiny! So, thank you for this video! May it blow up and be referenced from Stackoverflow or something! I only wish you had talked about how setup.py is outdated and that a modern package would look differently.
setup.py is not outdated. What is outdated is invoking setup.py directly - you should use external commands like `pip install` that will know to use your setup.py. Alternatives like poetry have a lot of benefits, and are definetly better for people starting with Python while knowing other languages and their package managers (especially npm). But using plain old setup.py+pip+venv not only is just as capable of getting job done - it has some useful quirks that you can really use if you spend time understanting them.
@@GrzesiuG44 my understanding is that one should at least go for a setup.cfg, if not outright a pyproject.toml. Independent of using any particular packaging solution.
@Penny Lane They are definetly the future, but I expect it will take a few more years before it can be considered the way. My understanding is that currently setuptools is only on its way in fully migrating from setup.py and setup.cfg into pyproject.toml - and even once this happens the setup.py support and probably even usage for new projects will stay for a long time. If I understand correctly you can't do things like `pip install -e .` with pyproject.toml currently. This also is the endless battle of configuration inside code vs code inside configuration. The latter is probably cleaner (esp for 3rdparty parsers) and current trend; but makefiles and more recently cmakes show that just having a dirty mess that gets the job done might be more practical. Because sometimes you just want to have a package that collects files with even number of vowels in their filename, and puts it into package name acquired by HTTP request.
nope: see th-cam.com/video/MGTX5qI2Jts/w-d-xo.html - poetry: too complicated, doesn't really add anything for me, wrong about versions - pipenv: slow for no reason, I avoid code by the original author - pdm: running code blindly from working directory is a security issue -- see also th-cam.com/video/_fpXyS_i1xE/w-d-xo.html and th-cam.com/video/J7NMyb-LNX4/w-d-xo.html for similar issues
it ~forces `~=` versioning on everything making compatibility difficult. it does this as well for `python_requires` and forces you to match the minimums of your dependencies (even if a version could resolve) -- this is why so many with poetry have `python_requires>=3.6.1` (just because a popular package of mine sets the same!). all three of these behaviours are harmful for integration between libraries
I gotta be honest, after coding in Python for 3 years, your videos are always something I keep coming back to for little things here or there. It'll be like "I remember Anthony had a video on this... what did he say to do again?"
I just spent like 5 hours trying to get my imports working without modifying the sys path directly. This video is exactly what I was looking for. Thank ya!
Thanks Anthony, this is always useful! I just keep coming back to a video I have seen of yours whenever I run into these situations in "real life examples"
I can't believe this channel was not recommended by youtube to me for so long.
Loving these videos. Super informative.
Thank you so much.
Can you explain the raise SystemExit(main())?
Would you still make all paths relative in your code?
Like using pathlib to get the current path, and then going up directories from there?
Or would you simply make all the paths relative to the main entrypoint as defined in setup.py?
if they're user-specified paths (like input files / etc.) I'd take them as arguments and deal with them that way
if they're resource files I'd use `importlib.resources` to access them and not think about the pathing or layout (it might not even be on the filesystem!)
@@anthonywritescode I'm having difficulty understanding how importlib.resources works.
If I have some dir structure like
.
├── example-files
│ ├── inputs
│ │ ├── file1
│ │ └── file2
├── requirements.txt
├── src
│ ├── main.py
├── nested
│ ├── dir
│ │ ├── foo.py
└── test
├── test1
If I want to load the example-files.inputs.file1 or example-files.inputs.file2 from src/main.py, how would I do it? What if I want to load it from nested/dir/foo.py?
I tried simply doing
from importlib.resources import files
f = files('example-files.inputs')
But I get "ModuleNotFoundError: No module named 'example-files'"
If however I run the code above from the root DIR, it works fine. Are the modules somehow relative to the "executing directory" as well?
Great video, honestly something I've been wondering for over three years and never really got to the bottom of.
don't run, I agree. In all seriousness, I've not really run into this problem, but maybe that's because I just monoscript for console script like stuff, or use __file__ vs. os.cwd when trying to deal with paths of things, but it's been a while since I've had to do any of that kind of stuff.
i searched about this error so many times and tried to learn and none of the other answers helped me. Great video. Thanks a lot
I don't think the cwd should be on the import path; as the author of an import statement I want to know that the code I intend to import hasn't been overridden by the presence of a random module in somebody's current directory. The very idea that it would do this is slightly terrifying!
currently my program is working. But ill try to do this and see if something changes
Is it why python3 -m pip install package recommended?
I've got a video about that! th-cam.com/video/gnYdk_U6UQ0/w-d-xo.html
Anthony, thank you so much for making these videos.
I have been doing PYTHONPATH for my whole life and never suspected there might be something wrong there.
If I can be helpful for any of your project, just let me know.
Your videos are wonderful, keep the good job
Great explanation, one thing is however missed: how to import from another file inside a folder in (like a/helpers.py) in a/main.py.
Example:
# a/helpers.py
def answer2life():
return 42
# a/main.py
from a.helpers import answer2life
print(answer2life())
it looks ugly IMO when your directory is named src (instead of 'a' here). Any other way to do it?
I go over both ways in the video -- absolute imports I strongly prefer but there's also explicit relative imports
but also your top-level module shouldn't be named `src` -- you're probably doing src-layout incorrectly: th-cam.com/video/sW1qUZ_nSXk/w-d-xo.html
@@anthonywritescode Thanks for your reply but I couldn't find my answer in that video. The layout I meant is something like this:
myproject/
requirements.txt
src/
__init__.py
helpers.py
main.py
data/
...
tests/
How would you import functions from helpers.py in the main.py. The way that works for me (while using python -m src.main) is
# main.py
from src.helpers import funcA, funcB
I would be grateful if you can elaborate what is the correct way of both doing both layout and import in this case.
src is a very bad top level name it should be the name of your project or a descriptive module name
@@anthonywritescode Thanks man, but apart from naming, is the structure correct for a simple project?
@@mofiro6758 IMO it is. I usually name the module the same way as project/git repo (only replacing dashes to underscores), e.g.
my-project/
requirements.txt
my_project/
__init__.py
__main__.py
main.py
helpers.py
data/
...
tests/
I added __main__.py as it allows creating a nice entry point to the whole with:
python -m my_project
Also, you might consider using requirements.txt & requirements-minimal.txt if we're talking about a project that is meant to be deployable (in contrary to libraries or tools like flake8). In the latter req file you list only top level imports as loosely specified as possible, and you use this file to easily update requirements.txt which should have all dependencies with frozen versions. This guarantees you repeatable builds
WHY AREN'T MY IMPORTS WORKING
what is the best way professionals deal with this? I want to learn the proper way so I can Implement it on my project. Thanks Anthony!
I show the alternatives! (either -m or make an installable tool)
What really annoys me more than the behavior of Python when running a script is that the ratio of actual best practices to garbage non-solutions on the web is tiiiiiny! So, thank you for this video! May it blow up and be referenced from Stackoverflow or something!
I only wish you had talked about how setup.py is outdated and that a modern package would look differently.
setup.py is not outdated. What is outdated is invoking setup.py directly - you should use external commands like `pip install` that will know to use your setup.py.
Alternatives like poetry have a lot of benefits, and are definetly better for people starting with Python while knowing other languages and their package managers (especially npm). But using plain old setup.py+pip+venv not only is just as capable of getting job done - it has some useful quirks that you can really use if you spend time understanting them.
@@GrzesiuG44 my understanding is that one should at least go for a setup.cfg, if not outright a pyproject.toml. Independent of using any particular packaging solution.
@Penny Lane They are definetly the future, but I expect it will take a few more years before it can be considered the way. My understanding is that currently setuptools is only on its way in fully migrating from setup.py and setup.cfg into pyproject.toml - and even once this happens the setup.py support and probably even usage for new projects will stay for a long time. If I understand correctly you can't do things like `pip install -e .` with pyproject.toml currently.
This also is the endless battle of configuration inside code vs code inside configuration. The latter is probably cleaner (esp for 3rdparty parsers) and current trend; but makefiles and more recently cmakes show that just having a dirty mess that gets the job done might be more practical. Because sometimes you just want to have a package that collects files with even number of vowels in their filename, and puts it into package name acquired by HTTP request.
Very helpful! I spent several hours to solve this problem, and I finally solve it with your method!
Is venv your virtualenv generator of choice? What are your thoughts on poetry/pipenv/pdm?
nope: see th-cam.com/video/MGTX5qI2Jts/w-d-xo.html
- poetry: too complicated, doesn't really add anything for me, wrong about versions
- pipenv: slow for no reason, I avoid code by the original author
- pdm: running code blindly from working directory is a security issue -- see also th-cam.com/video/_fpXyS_i1xE/w-d-xo.html and th-cam.com/video/J7NMyb-LNX4/w-d-xo.html for similar issues
@@anthonywritescode you don't use requests? why and what should be used instead?
urllib.request works fine for me, if I need async I'll use httpx
@@anthonywritescode why poetry is wrong about versions?
it ~forces `~=` versioning on everything making compatibility difficult. it does this as well for `python_requires` and forces you to match the minimums of your dependencies (even if a version could resolve) -- this is why so many with poetry have `python_requires>=3.6.1` (just because a popular package of mine sets the same!). all three of these behaviours are harmful for integration between libraries
I'm still going to do it. my python projects are all one big script anyway
"$PYTHONPATH is almost always wrong" should be a tattoo
literally me crying why .. and . imports dont work
Thanks for the detailed explanation!!! I already subscribe to your channel!!!
Thank you for another great video ! Very informative.
Amazing work friend
great video as always, thank you
Took me also a while to figure this out.
Anthony ur the mann
Grate video with very useful info
we learn everyday
Would replying to a JIRA ticket with a YT video be passive aggressive? Asking for a friend.
lol I use these in code reviews all the time
Im sure at somepoint, ill understand what he explained. lol
that fancy keyboard is just begging you to use vim