How to run a Python code inside a custom package? - python

I'm using Visual Studio Code.
Suppose my folder looks like:
├── main.py
└── package
├──__init__.py
├──utils.py
└──method.py
In my method.py, I import the utils.py, which is in the same directory, so I put the dot before the name:
from .utils import *
then I can run the script in main.py like:
from package import method
This will work. But the question is, how I can run the script in method.py at its directory instead of importing it in main.py? If I run the script method.py directly, an error will occur:
ModuleNotFoundError: No module named '__main__.modules'; '__main__' is not a package
What can I do to run the script in method.py without removing the dot as from utils import *?

To make your code work, change the import statement in method.py from
from .utils import *
to
import __main__, os
if os.path.dirname(__main__.__file__) == os.path.dirname(__file__):
# executed script in this folder
from utils import *
else:
# executed script from elsewhere
from .utils import *
When method.py runs, it checks the folder that the executed python script is in, and if it's the same folder as itself, it will import utils, rather than .utils.
You can achieve a similar thing using
if __name__=='__main__':
as your check. However, if method.py is imported by anther file inside the package folder, then method.py will try to import .utils, and won't be able to find it.

Related

Do PyCharm handles local packages differently?

I have a following package structure:
project\
app\
main.py
__init__.py
lib\
funcs.py
__init__.py
When I try to import my functions from funcs.py to main.py using from lib.funcs import func1, func2 it works perfectly fine in PyCharm, but not in VS Code. In VS Code I get:
ModuleNotFoundError: No module named 'lib'
However, if I chage the structure to:
project\
main.py
lib\
funcs.py
__init__.py
it works fine in VS Code as well.
Why is that? Is there are a way to run imported code from the app package like in the first example?
I tried to play around with __init__.py files, making and unmacking different folders a packages, using the from .lib.funcs import func1, func2 and using from project.lib.funcs import func1, func2. In the first case I get:
ImportError: attempted relative import with no known parent package'
While in the second:
ModuleNotFoundError: No module named 'project'
Open launch.json and add
"env":{
"PYTHONPATH":"${workspaceFolder}"
}
In main.py, import modules like from lib import func. This solution only works when you Run without Debugging:
The second way is adding the following code before importing modules, and you don't need to add args env in launch.json
import sys
sys.path.append("./")
Clicking the green button on the top right corner to Run Python File in Terminal and Run without debugging both works.

How to use Python imports between scripts in the same folder, imported as part of a package, and run as a stand-alone script within the folder

I have been reading through absolute vs relative imports for a long time and nothing has helped me.
Say I have a python module structured like so:
└── test_project
├── __init__.py
├── script1.py
├── script2.py
└── main.py
__init__.py is blank
script1.py has functions
script2.py accesses script1. This can be achieved through from . import script1,import .script1 (relative) or import script1 (absolute)
main.py is a script that runs a function from script1 on the command line, and therefore includes if '__name__'==__main__: followed by some version of import script1
I want to be able to import script2 into a python terminal both outside and inside the folder, and run the main.py script on the command line from both outside and inside the folder i.e. python test_project/main.py.
Despite a lot of trying, I cannot find any way of writing the import commands such that import script2 works in all these cases.
For example, if I use from . import script1 in main and script2 and run from test_project import script2 in python from outside the folder, it works fine. But if I run python test_project/main.py or try to import in python when within the folder, I get:
Traceback (most recent call last):
File "test_project/main.py", line 1, in <module>
from . import script1
ImportError: attempted relative import with no known parent package
I can try to modify the imports to be absolute to fix this. For example making main and script2 have import script1 rather than being relative. Now running main and importing from a python within the folder is ok, but importing from outside the folder with from test_project import script2 gives:
<ipython-input-1-c3cdbe7a7496> in <module>
----> 1 from test_project import script2
~/python/test_project/script2.py in <module>
----> 1 import script1
ModuleNotFoundError: No module named 'script1'
Is it, therefore, impossible to write import statements in such a way that these functionalities are possible?

Not able to import module from other directory in Python 3.7.1

I have a package structured as:
Classes in those packages are named exactly like the file names. Also, init.py has following code
from tableau_util import tableau_util
from sftp_util import sftp_util
from s3_util import s3_util
I have another file e.g. test.py which is outside this folder 'utils'. I want to import those classes into test.py so my code is
from utils.tableau_util import tableau_util
from utils.sftp_util import sftp_util
from utils.s3_util import s3_util
I am still getting the error:
ModuleNotFoundError: No module named 'tableau_util'
What can I try to resolve this?
Without knowing everything I would guess that you are trying to run your test.py as a normal python script. Given this folder structure
.
├── __init__.py
├── test
│   ├── __init__.py
│   └── test.py
└── utils
├── __init__.py
├── s3_util.py
└── tableau_util.py
with these files test.py
from utils.s3_util import s3_util
from utils.tableau_util import tableau_util
s3_util()
tableau_util()
import sys
print(sys.path)
s3_util.py
def s3_util():
print('Im a s3 util!')
tableau_util.py
def tableau_util():
print('Im a tableu util!')
if you just tried to run python test/test.py in the main folder it will give you the ModuleNotFoundError. That's because it sets the ./test folder as the python path and it won't be able to see the utils folder and therefore be able to import it. However if you run it as python -m test.test (note the lack of .py you don't need it when you run it as a module) that will tell python to load it as a module and then it will run correctly with this output:
Im a s3 util!
Im a tableau util!
If you don't want to put the test.py in another folder you can simply keep it in the parent folder of utils and be able to run it in the traditional python test.py and get the same results. Error while finding spec for 'fibo.py' (<class 'AttributeError'>: 'module' object has no attribute '__path__') has some more reading on the matter.
For the record all my __init__.py files are empty and don't import anything and this is normally how they are setup unless you want to specify certain functions that need to be imported when the module is imported automatically.
I used PyCharm's create package option to create folders and files again and it is working now. Here are my new (working) folder structure:
My main script has following lines of code to import those classes:
from utils_pkg import tableau_util
from utils_pkg import s3_util
from utils_pkg import sftp_util
First, inside __init__.py (or in any sub-module that tries to import one of its siblings from the same package) you should add a "relative import" dot to the beginning of the module name, so that it reads:
from .tableau_util import tableau_util
# ^right here
Second, make sure your current working directory is not utils. A good place to start, for testing, might be to cd to the parent directory of utils instead.

Relative import in Python 3.6

I want to use relative import in Python 3.
My project:
main_folder
- __init__.py
- run.py
- tools.py
I want to have in run.py (MyClass declared in __init__.py):
from . import MyClass
And in run.py:
from .tools import my_func
An ImportError is raise.
Alternatively, with absolute import, debugging in PyCharm does not work and the library takes from installed packages, not my directory.
I know one way, but it is terrible:
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
How to use this import in my project?
When you use PyCharm, it automatically makes the current module main, so relative statements like from . import <module> will not work. read more here.
to fix your problem, put the __init__.py and tools.py files in a sub-directory
main_directory/
run.py
sub_directory/
__init__.py
tools.py
in your run.py file, write the following as your import statements
from sub_directory import tools
from sub_directory.__init__ import MyClass
Edit: as #9000 mentioned, you can write from sub_directory import MyClass and achieve the same thing.

Cannot import modules of parent packages inside child packages

I have a parent package that has 2 child packages. It looks like this
backend
__init__.py
conf.py
db.py
connections.py
/api
__init__.py
register.py
api.py
/scheduled
__init__.py
helpers.py
All the __init__.py files are empty.
The code in backend/connections.py and backend/conf.py is being used by modules in both packages api and scheduled.
in register.py i have code like
from backend.conf import *
from backend.connections import *
Now when i do python register.py
i get this error
ImportError: No module named backend.conf
Also when i changed from backend.conf import * to from ..conf import * or from .. import conf i get this error
ValueError: Attempted relative import in non-package
What i understand by the above error is that python is not treating the above folders as packages. But i have __init__.py in all the folders. What is wrong?
When you run python register.py, your backend/register.py file is used as the __main__ module of the program, rather than as a module within the backend package. Further more, the Python import path will not automatically include the directory containing the backend directory, which is probably the cause of your problems.
One option that might work is to run your program as python -m backend.register from the top level directory of your project (or set PYTHONPATH so this module can be found). This will search for the script on the normal import path, and then run it as the main program.

Categories