Importing modules from a neighbouring folder in Python - python

I have put the question in the figure below:
EDIT
The question put next to the figure is:
How do I make script_A1 import a function from script_B2?
Similar questions have been asked before. But most answers suggest to add the module/script/package(whatever) to the PATH variable. For example:
sys.path.append('...')
But adding the module to the PATH variable just feels so wrong. I do not want to alter my system in any way. When my application closes, I want my Python environment to be clean and 'untouched'. I'm afraid that adding uncontrolled modules to the PATH variables on my system will cause headaches later on.
Thank you for helping me out :-)

You can use a trick of adding the top folder to path:
import sys
sys.path.append('..')
import folderB.something
You can also use imp.load_source if you prefer.

I think I solved the issue.
In the following way, you can append the parent directory to the PATH. Put this at the top of script_A1:
import sys
import os
myDir = os.path.dirname(os.path.abspath(__file__))
parentDir = os.path.split(myDir)[0]
if(sys.path.__contains__(parentDir)):
print('parent already in path')
pass
else:
print('parent directory added')
sys.path.append(parentDir)
# Now comes the rest of your script
You can verify that the parent directory myProject is indeed added to the PATH by printing out:
print(sys.path)
Since the parent directory myProject is now part of the PATH, you can import scripts/modules/whatever from any of its subdirectories. This is how you import script_B2 from folder_B:
import folder_B.script_B2 as script_B2
After closing your application, you can verify if your Python environment is restored to its initial state. just print the PATH again and check if the directory you had appended is gone.

Put this at the top of script_A1;
from folderB.script_B2 import YourClass as your_class

Related

Python Can't Import Class From Parent Directory?

I am new to Python, so I might not be seeing the obvious solution to this. I have searched online for a solution and everyone seems to have the same answer. I am trying to import a file from a parent directory in Python. I am coming from JavaScript where you simply type import Function from '../ParenetDirectory/FileThatIncludesFunction' and you can import that module. Every website I have visited says you have to include the parent directory in your freakin' path to import it. Are we serious here? I assume I am missing something because it seems to me that Python would have a more elegant way to do this than editing your freaking path to import a class from a parent directory. Please tell me it does, or explain to me why it doesn't.
You can do this by using the sys module and adding the desired directory to its path.
"../ParenetDirectory/FileThatIncludesFunction.py" :
def Function():
return 'Hello, World!'
main.py :
import sys
sys.path.append('../ParenetDirectory')
from FileThatIncludesFunction import Function
print(Function())
Note that if you want to run this via cmd, make sure that the folder in cmd is exactly where the main.py file is located.

Correct syntax for import statement

Newbie here
I want to import a class from a file in another directory, in this case:
C:\Users\jose_\Desktop\my_ref\stack_class.py, using the from - import statement. I have an init.py file in said directory but cannot find the right sintax anywhere.
How do you put C:\Users\jose_\Desktop\my_ref\stack_class.py in the import part?
I have tried using these other two ways:
exec(open("file path on windows").read())
and the import sys and sys.path.insert
they both work, trying to do it with the import statement.
from C:\Users\jose_\Desktop\my_ref\stack_class.py import Stack #Error here
foo = Stack()
print(type(foo))
Error
File "C:/Users/jose_/OneDrive/Mis_Documentos/Educacion/Linkedin/Ex_Files_Python_Data_Structures_Queues/Exercise_Files/Ch02/02_02/End/main2.py", line 4
from C:\Users\jose_\Desktop\my_ref\stack_class.py import Stack
^
SyntaxError: invalid syntax
As far as I know, you cannot import from a file path in Python.
You can only import by passing a module name:
import module.submodule
# then
module.submodule.sth()
or
from module.submodule import sth
# then
sth()
And Python will search module/submodule.py and module/submodule/__init_.py in all the directories in sys.path.
So if you want to import from a file in another directory created by yourself (not included in the sys.path list) you have to append that directory to the list to tell Python where to find that module. Try to run:
import sys
sys.path.append('C:\\Users\\jose_\\Desktop\\my_ref')
from stack_class import Stack
# then
foo = Stack()
print(type(foo))
Edit
If you don't want to append to sys.path, you need to move your module to one of the diretories in sys.path, for example, the current directory . is also in sys.path, or Python won't know where the module is (C:\ is not in sys.path).
Python never imports from directories that are not included in sys.path (via import statements, I mean)!
Did you make sure to switch your forward slashes "\" with back slashes "/" ?
try using:
sys.path.extend('file path here')
to add the folder path to your python path, that way python knows where to look for the stack_class module - either that or navigate to the folder before importing
also make sure in the folder your init file is called __init__.py
you should then be able to do
from stack_class import Stack

Flask and Google Calendar API Authentication Issues [duplicate]

I have a Python module which uses some resources in a subdirectory of the module directory. After searching around on stack overflow and finding related answers, I managed to direct the module to the resources by using something like
import os
os.path.join(os.path.dirname(__file__), 'fonts/myfont.ttf')
This works fine when I call the module from elsewhere, but it breaks when I call the module after changing the current working directory. The problem is that the contents of __file__ are a relative path, which doesn't take into account the fact that I changed the directory:
>>> mymodule.__file__
'mymodule/__init__.pyc'
>>> os.chdir('..')
>>> mymodule.__file__
'mymodule/__init__.pyc'
How can I encode the absolute path in __file__, or barring that, how can I access my resources in the module no matter what the current working directory is? Thanks!
Store the absolute path to the module directory at the very beginning of the module:
package_directory = os.path.dirname(os.path.abspath(__file__))
Afterwards, load your resources based on this package_directory:
font_file = os.path.join(package_directory, 'fonts', 'myfont.ttf')
And after all, do not modify of process-wide resources like the current working directory. There is never a real need to change the working directory in a well-written program, consequently avoid os.chdir().
Building on lunaryorn's answer, I keep a function at the top of my modules in which I have to build multiple paths. This saves me repeated typing of joins.
def package_path(*paths, package_directory=os.path.dirname(os.path.abspath(__file__))):
return os.path.join(package_directory, *paths)
To build the path, call it like this:
font_file = package_path('fonts', 'myfont.ttf')
Or if you just need the package directory:
package_directory = package_path()

Importing python modules from multiple directories

I have a python 2.6 Django app which has a folder structure like this:
/foo/bar/__init__.py
I have another couple directories on the filesystem full of python modules like this:
/modules/__init__.py
/modules/module1/__init__.py
/other_modules/module2/__init__.py
/other_modules/module2/file.py
Each module __init__ has a class. For example module1Class() and module2Class() respectively. In module2, file.py contains a class called myFileClass().
What I would like to do is put some code in /foo/bar/__init__.py so I can import in my Django project like this:
from foo.bar.module1 import module1Class
from foo.bar.module2 import module2Class
from foo.bar.module2.file import myFileClass
The list of directories which have modules is contained in a tuple in a Django config which looks like this:
module_list = ("/modules", "/other_modules",)
I've tried using __import__ and vars() to dynamically generate variables like this:
import os
import sys
for m in module_list:
sys.path.insert(0, m)
for d in os.listdir(m):
if os.path.isdir(d):
vars()[d] = getattr(__import__(m.split("/")[-1], fromlist=[d], d)
But that doesn't seem to work. Is there any way to do this?
Thanks!
I can see at least one problem with your code. The line...
if os.path.isdir(d):
...won't work, because os.listdir() returns relative pathnames, so you'll need to convert them to absolute pathnames, otherwise the os.path.isdir() will return False because the path doesn't exist (relative to the current working directory), rather than raising an exception (which would make more sense, IMO).
The following code works for me...
import sys
import os
# Directories to search for packages
root_path_list = ("/modules", "/other_modules",)
# Make a backup of sys.path
old_sys_path = sys.path[:]
# Add all paths to sys.path first, in case one package imports from another
for root_path in root_path_list:
sys.path.insert(0, root_path)
# Add new packages to current scope
for root_path in root_path_list:
filenames = os.listdir(root_path)
for filename in filenames:
full_path = os.path.join(root_path, filename)
if os.path.isdir(full_path):
locals()[filename] = __import__(filename)
# Restore sys.path
sys.path[:] = old_sys_path
# Clean up locals
del sys, os, root_path_list, old_sys_path, root_path, filenames, filename, full_path
Update
Thinking about it, it might be safer to check for the presence of __init__.py, rather than using os.path.isdir() in case you have subdirectories which don't contain such a file, otherwise the __import__() will fail.
So you could change the lines...
full_path = os.path.join(root_path, filename)
if os.path.isdir(full_path):
locals()[filename] = __import__(filename)
...to...
full_path = os.path.join(root_path, filename, '__init__.py')
if os.path.exists(full_path):
locals()[filename] = __import__(filename)
...but it might be unnecessary.
We wound up biting the bullet and changing how we do things. Now the list of directories to find modules is passed in the Django config and each one is added to sys.path (similar to a comment Aya mentioned and something I did before but wasn't too happy with). Then for each module inside of it, we check for an __init__.py and if it exists, attempt to treat it as a module to use inside of the app without using the foo.bar piece.
This required some adjustment on how we interact with the modules and how developers code their modules (they now need to use relative imports within their module instead of the full path imports they used before) but I think this will be an easier design for developers to use long-term.
We didn't add these to INSTALLED_APPS because we do some exception handling where if we cannot import a module due to dependency issues or bad code our software will continue running just without that module. If they were in INSTALLED_APPS we wouldn't be able to leverage that flexibility on when/how to deal with those exceptions.
Thanks for all of the help!

python import from sub-directory in a git safe way

Here is my current directory structure:
proj/
proj/__init__.py
proj/submodFolder/
proj/submodFolder/submod/
proj/submodFolder/submod/__init__.py
I'm writing a project and I would like to have import submod or even import submodFolder.submod in proj/__init__.py. However without __init__.py in submodFolder this won't work.
Assume submodFolder is a git repository that i have sub-repoed (a third party library if you will); adding the requisite __init__.py will break the git subrepo and complicate updating libraries from their master repos.
Assuming submodFolder is an immutable git sub-repo what is the best way to push python down the dirtree to the module? Modifying the python path seemed the nearest solution to me - but none of the questions already asked assumed an immutable submodFolder.
Examples welcome, note relative paths.
If you prefer not to modify the PYTHONPATH environment variable, you can modify sys.path inside of proj/__init__.py, the following should work:
import sys
import os
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'submodFolder'))
import submod
Step-by-step code with comments, so it makes a little more sense:
# get absolute path to proj/__init__.py
script_path = os.path.realpath(__file__)
# strip off the file name to get the absolute path to proj
proj_path = os.path.dirname(script_path)
# join on os.sep to get absolute path to proj/submodFolder
submod_path = os.path.join(proj_path, 'submodFolder')
# add the complete path to proj/submodFolder to sys.path
sys.path.append(submod_path)

Categories