'ModuleNotFoundError' when trying to import script from imported script - python

My folder structure:
ttsTacotron.py
Tacotron-2
|..
|tacotron|
|train.py
|synthetizer.py
|...
|synthesize.py # imports hparams.py
|hparams.py
...
When I call synthesize.py directly it works fine, all of its imports get processed successfully. When I import synthesize in the ttsTacotron.py and call it, it fails on importing synthesize's modules. Specifically, it fails on importing hparams.
ttsTacotron.py:
import fire
import sys
import os
import importlib
foobar = importlib.import_module("Tacotron-2.synthesize")
Tacotron folder in question is this repository but the issue is unlikely to be specific to it.
Remarks: I use importlib to handle having - in the subfolder. Can't really rename it for various reasons.
My goal: Be able to call synthetize's methods & be able to import tacotron modules from a script that is in the root folder.

This is because, when running ttsTacotron.py, Python looks up all non-relative imported modules in the directory containing ttsTacotron.py (and in the system module directories, which isn't relevant here), yet hparams.py is in the Tacotron-2 directory. The simplest fix is probably to add Tacotron-2 to the list of directories in which modules are looked up; this also eliminates the need to use importlib.
import sys
sys.path.insert(1, 'Tacotron-2')
import synthesize as foobar

Related

Why does error occurs when importing from same *sub*directory?

Consider this folder structure:
main.py
module_a/
aa.py
bb.py
__init__.py
In main.py, I import aa as:
from module_a import aa
aa.yyy()
Then in aa.py, I import bb and include its functions as:
import bb
bb.xxx()
However, when I run main.py, python says "No module named 'bb'".
May I know why this happens. What is the correct way to import bb.
Thanks!!!
I have tried to write aa.py as:
import .bb
bb.xxx()
But it still does not work.
why this happens
Because the aa folder is not a place that Python is searching for modules.
Python's imports are absolute by default. They only look in specific places determined by sys.path. In main.py, import module_a.aa works because the root folder of the project happens to be on the sys.path; that folder contains a module_a folder; and that folder contains aa.py.
What is the correct way to import bb.
Please use relative imports between files in your package. In this case, the necessary import in aa.py looks like:
from . import bb
Absolute imports are error-prone; a project that uses two packages whose contents have overlapping names will run into namespace collisions. (Sadly, the standard library uses absolute imports in most places, such that projects need to ban certain module names for safety.) Relative imports will also require much less maintenance, should you later rename a sub-package.
The only thing relative imports require is that the package gets loaded, which typically will happen automatically with the first (yes, absolute) import of any of the package contents. When the package is loaded, it automatically sets a __package__ attribute on the modules in that package, which Python can use to resolve the relative imports. It's important to note that relative imports are relative to the package hierarchy, not the directory structure, which is why this is necessary; imports like from .. import example do not work by figuring out the current file location and then going up a level in the directory hierarchy. Instead, they check the __package__ to figure out what the containing package is, then check the file/folder location for that, and work from there.
If the "driver" script is within the package, run it as a module, using the -m switch for Python. For example, from the root folder, if module_a/aa.py is the driver, use python -m module_a.aa. This instructs Python that module_a is the containing package for aa.py, and ensures it gets loaded even though no import in the code has loaded it.
Contrary to what many people will wrongly tell you, it is almost never required to manipulate sys.path; there are popular Python projects on GitHub, running hundreds of thousands of lines of code, which either do not use it at all or use it only once in an ancillary role (perhaps because of a special requirement for a documentation tool). Just don't do it.
Also contrary to what many people will wrongly tell you, __init__.py files are not required to create packages in Python. They are simply a place where additional code can be placed for package initialization - for example, to create aliases for sub-package contents, or to limit what will be imported with a *-import (by setting __all__).
import .bb
This is just invalid. Relative imports only use the from syntax. See above for the correct syntax.
Suppose the same file structure as stated in OP, and:
main.py:
import module_a.aa
module_a.aa.thisFile()
module_a.aa.module_a.bb.thisFile()
aa.py:
import module_a.bb
def thisFile():
print("aa")
bb.py:
def thisFile():
print("bb")
Then, this will print
aa
bb
like you would expect. The main difference here, is that bb.py is imported in aa.py via module_a.bb. Running main.py gives no problem, however, running aa.py does not work in this way. That is why you might want to add folders to your path, such that you can call a function from a different file without this trouble. This is done via:
import os, inspect, sys
current_folder = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parent_folder = os.path.dirname(current_folder)
sys.path.insert(0,parent_folder)
Then you can import your files such as import file. If you consider this option, I would suggest to do some reading about how this works. Tip: make sure you avoid cyclic import problems.

ImportError: attempted relative import with no known parent package STILL NO SOLUTION

I have looked at I think 5 different answers to this problem, yet none of them have worked for me yet. For reference, I've looked through all of these posts:
Relative imports for the billionth time
Attempted relative import with no known parent package
"Attempted relative import with no known parent package"
From what I've gathered, there are two solutions to this problem:
Move the .py file you're trying to import functions from into the same directory as the script you're trying to run (this works, but it is not a good solution, I should be able to import from a parent directory without this error)
Create a __init__.py file in the directory of the .py file you're trying to import from, and use import package_name to it. (I have tried this, but same issue)
Here is my project's structure:
I'm trying to run the test.py script, which (attempts) to import the function add_technical_indicators from the add_technical_indicators.py file. My import statement looks like this:
from ..utils.add_technical_indicators import add_technical_indicators
Looking at the folder structure again, I have to go UP one directory, then into the utils folder to bring in the add_technical_indicators .py file, and finally the function add_technical_indicators.
Here's what I have tried so far:
from ..utils.add_technical_indicators import add_technical_indicators
from .utils.add_technical_indicators import add_technical_indicators
from utils.add_technical_indicators import add_technical_indicators (this doesn't work of course because add_technical_indicators is not in the same folder as the script being run)
Created an __init__.py file in the utils folder that reads import add_technical_indicators
Created an __init__.py file in the misc folder that reads import test
None of it works. I need a concise and actionable answer as to why this is still not working. I'm running Python 3.7.9, Windows 10, and VS code in case that matters.
I have looked through previous, repeat answers but none of them have worked for me, so although this IS a duplicate question, please do not close it until I have a solution because linking to the already "answered" questions didn't help me.
short solution
In test.py import as from utils.add_technical_indicators import add_technical_indicators
and run as python -m misc.test (not test.py) in parent directory(in STOCK_PEAKS_ADN_THROUGHS_2)
explained
python cannot import files from upper directory of your working directory unless you add them to PATH, so from ..utils.add_technical_indicators import add_technical_indicators won't work.
python finds files starting from your working directory, so from utils.add_technical_indicators import add_technical_indicators in test.py can find utils/add_technical_indicators.py if you run script at parent directory.
python -m misc.test will run misc/test.py in parent directory. Note that python misc/test.py will run script in misc directory and will give you same error.
You did the right thing here: from ..utils.add_technical_indicators import add_technical_indicators
The main issue must be in the imports of utils/add_technical_indicators.py file
Did you try importing stuffs inside add_technical_indicators.py relative to itself (if so, those imports only work when add_technical_indicators.py is run instead of test.py)
In contrast to what minolee has said Python actually can import files from upper directories. Python has a built-in SourceFileLoader that can load Python code from any file in the file system, also from any upper directory of your working directory.
It requires some boilerplate code, so I have decided to wrap this approach into an experimental import library: ultraimport
ultraimport can do file system based imports. In your test.py you could then write:
import ultraimport
add_technical_indicators = ultraimport('__dir__/../utils/add_technical_indicators.py')
This will always work, no matter what is your current working directory and no matter what is your current sys.path. You don't need to create __init__.py files and it also works if you run the code as a script or as a module.
One caveat when importing files like this is if the imported code contains further relative imports. ultraimport has a built-in preprocessor to automatically rewrite subsequent relative imports so they continue to work.

In Google Colab Python Notebook, what's the cleanest way to import other .py files?

I am trying to avoid using sys.path.append...or any hacks and want to organise the folders. Given I have a notebook .ipynb file, how can I import .py files if I place them in a directory ?
If you place them in the same directory, you can import your module (.py) files easily with:
from my_module import * # This will import all functions
from my_module import foo # This will import only my_module.foo
foo()
or simply import the module
import my_module
my_module.foo()
Refer to this python documentation for more explanation about module.
Update on updated question
As per this answer, you can use the above approach if you upload your module. Just ensure your pwd is correct.
Better yet in the sample, you can define __init__.py inside your module folder (refer to section 6.4. Packages in the doc above) to do something like:
from folder.my_module import foo
foo()

Python - fails importing package

I have trouble importing package.
My file structure is like this:
filelib/
__init__.py
converters/
__init__.py
cmp2locus.py
modelmaker/
__init__.py
command_file.py
In module command_file.py I have a class named CommandFile which i want to call in the cmp2locus.py module.
I have tried the following in cmp2locus.py module:
import filelib.modelmaker.command_file
import modelmaker.command_file
from filelib.modelmaker.command_file import CommandFile
All these options return ImportError: No modules named ...
Appreciate any hint on solving this. I do not understand why this import does not work.
To perform these imports you have 3 options, I'll list them in the order I'd prefer. (For all of these options I will be assuming python 3)
Relative imports
Your file structure looks like a proper package file structure so this should work however anyone else trying this option should note that it requires you to be in a package; this won't work for some random script.
You'll also need to run the script doing the importing from outside the package, for example by importing it and running it from there rather than just running the cmp2locus.py script directly
Then you'll need to change your imports to be relative by using ..
So:
import filelib.modelmaker.command_file
becomes
from ..modelmaker import command_file
The .. refers to the parent folder (like the hidden file in file systems).
Also note you have to use the from import syntax because names starting with .. aren't valid identifiers in python. However you can of course import it as whatever you'd like using from import as.
See also the PEP
Absolute imports
If you place your package in site-packages (the directories returned by site.getsitepackages()) you will be able to use the format of imports that you were trying to use in the question. Note that this requires any users of your package to install it there too so this isn't ideal (although they probably would, relying on it is bad).
Modifying the python path
As Meera answered you can also directly modify the python path by using sys.
I dislike this option personally as it feels very 'hacky' but I've been told it can be useful as it gives you precise control of what you can import.
To import from another folder, you have to append that path of the folder to sys.path:
import sys
sys.path.append('path/filelib/modelmaker')
import command_file

Python: Importing a file from a parent folder

...Now I know this question has been asked many times & I have looked at these other threads. Nothing so far has worked, from using sys.path.append('.') to just import foo.
I have a python file that wishes to import a file (that is in its parent directory). Can you help me figure out how my child file can successfully import its a file in its parent directory. I am using python 2.7.
The structure is like so (each directory also has the __init__.py file in it):
StockTracker/
└─ Comp/
├─ a.py
└─ SubComp/
└─ b.py
Inside b.py, I would like to import a.py: So I have tried each of the following but I still get an error inside b.py saying "There is no such module a".
import a
import .a
import Comp.a
import StockTracker.Comp.a
import os
import sys
sys.path.append('.')
import a
sys.path.remove('.')
from .. import a
Should do it. This will only work on recent versions of Python--from 2.6, I believe [Edit: since 2.5].
Each level (Comp and Subcomp) must also be have an __init__.py file for this to work. You've said that they do.
When packages are structured into
subpackages (as with the sound package
in the example), you can use absolute
imports to refer to submodules of
siblings packages. For example, if the
module sound.filters.vocoder needs to
use the echo module in the
sound.effects package, it can use from
sound.effects import echo.
Starting with Python 2.5, in addition
to the implicit relative imports
described above, you can write
explicit relative imports with the
from module import name form of import
statement. These explicit relative
imports use leading dots to indicate
the current and parent packages
involved in the relative import. From
the surround module for example, you
might use:
from . import echo
from .. import formats
from ..filters import equalizer
Quote from here http://docs.python.org/tutorial/modules.html#intra-package-references
If the Comp directory is in your PYTHONPATH environment variable, plain old
import a
will work.
If you're using Linux or OS X, and launching your program from the bash shell, you can accomplish that by
export PYTHONPATH=$PYTHONPATH:/path/to/Comp
For Windows, take a look at these links:
http://docs.python.org/using/windows.html
http://www.itechtalk.com/thread3595.html
EDIT:
To modify the path programmatically, you were on the right track in your original question. You just need to add the parent directory instead of the current directory.
sys.path.append("..")
import a

Categories

Resources