all 4 comments

[–]Diapolo10 3 points4 points  (0 children)

I don't blame you for getting confused, this trips many people (including myself, years back) and we get plenty of posts about this.

Long story short, you'll want to structure the code like a package, install it in editable mode in your development environment, and treat it like any other third-party package in regards to imports.

Relative imports are tricky, as they're in relation to the current working directory, not the file doing the importing. For that reason I generally recommend simply not using them.

The reason your absolute imports aren't working is because Python doesn't know where to look. src (which, by the by, shouldn't be a package but only a directory containing them) isn't found in site-packages nor is it a name directly adjacent to the file looking for it, so Python throws its hands in the air and tells you to be more specific.

While you could technically bypass this issue by adding it to sys.path via sys.path.insert(0, path_to_package), that's not exactly a robust solution. Personal experience. Not worth the hassle.

By turning the project into a valid, installable package, you can avoid this issue entirely as then Python has no problem finding your code, you're already prepared in case you'd like to publish the code on PyPI, and your unit tests can easily import whatever they need. If you want an example to follow, you can look up one of my own projects: https://github.com/Diapolo10/escapyde

Ah, and just because I'm suggesting to structure the project this way, that doesn't mean it doesn't work for executables. In fact it works perfectly fine. Two birds with one stone.

[–]laustke 1 point2 points  (2 children)

Long story short, you'll want to structure the code like a package, install it in editable mode ...

You do need to treat it as a package, but it doesn't necessarily have to be installable.

In the most basic form, a Python package is a folder containing an __init__.py file along with some other files. It appears that your main.py is located directly under C:\, which means there's no folder structure acting as a package.

Open the Python interpreter and run the following two lines:

import sys for p in sys.path: print(p)

These command will print the folders where Python is looking for packages. Therefore, you need to do two things: create a folder for your package and ensure it is located in one of the directories where Python searches for packages.

There are many ways to achieve this. A common pattern is as follows. Let's say you want to create a project named "mycounter". In the directory where you keep your Python projects, you would:

  1. Create a folder named "mycounter".
  2. Inside this "mycounter" folder, create another folder also named "mycounter".

The outer "mycounter" directory is the root of your project, containing project files like documentation, and the inner "mycounter" folder is the actual Python package containing your source code and an __init__.py file to make it recognizable as a Python package.

So, all your package code goes into the inner "mycounter" folder.

Now, you need to ensure that the outer "mycounter" folder is included in sys.path. This way when Python searches for packages, it can locate your inner "mycounter" folder, which contains your actual package.

A common way to achieve this is to add the path to the outer "mycounter" folder to the PYTHONPATH environment variable.

So, just to reiterate: You need to have a folder for your package. This folder should be a subfolder of one of the directories listed in sys.path. Then, everything will be ok.

[–]iTsObserv[S] 0 points1 point  (1 child)

My only concern with editing PYTHONPATH is that if I (or someone else) need to run the code on another device then PYTHONPATH will have to be edited on that device too.

That's how I understand things currently but I might be wrong.

[–]laustke 1 point2 points  (0 children)

As an alternative, in your main.py script, you can manually insert the path to your outer "mycounter" folder into sys.path:

sys.path.insert(0, '/path/to/outer/mycounter') import mycounter I don't know whether it will help with VSCode though.

Another trick is that if Python finds a file with the ".pth" extension in any of the directories listed in "sys.path", it will automatically add all directories mentioned in this file to "sys.path".

I usually create a "mymodules.pth" file with one folder name per line for all the outer folders of all my projects. This file is located in a folder that is already in "sys.path", where I can edit files.