How to get directory path of an unknown importing module - python-3.x

My goal is to define a function that gets a relative path and returns an absolute path.
The issue is that I want this function to be located in a specific module and that other modules will be able to use it.
If the function would be located in each module (and not being imported) it would have looked something like this:
import os
def get_absolute(relative):
dir_path = os.path.dirname(os.path.realpath(__file__))
return os.path.abspath(os.path.join(dir_path, relative_path))
absolute = get_absolute('../file.txt')
but if I want to define this function once (in one module) and be able to import it by other modules I will need to add another argument to the function for the directory path of the module that imported the function like so:
helper.py
import os
def get_absolute(relative, dir_path):
return os.path.abspath(os.path.join(dir_path, relative_path))
importer.py
import os
from helper import get_absolute
DIR_PATH = os.path.dirname(os.path.realpath(__file__))
absolute = get_absolute('../file.txt', DIR_PATH)
I saw Get path of importing module but in my case the module is unknown (multiple modules can import this function).
Is there a way for the helper module to know the directory path of the importing module without passing it as an argument?

Related

Finding the absolute path to an upstream directory using python pathlib

I have a pathlib.Path object and want to find the absolute path to a parent folder, called "BASE". However, I do not know how much further up the device tree the "BASE" folder is. I just know the pathlib.Path will contain a folder called "BASE".
Example:
import pathlib
# the script is located at:
my_file_dir = pathlib.Path(__file__).parent
# some pathlib function to find the absolute path to BASE
# input_1: /some/path/BASE/some/more/layers/script.py
# output_1: /some/path/BASE
# input_2: /usr/BASE/script.py
# output_2: /usr/BASE
In earlier python versions I would use os.path, os.path.split() and search for the string to get the directory. Now, it seems, pathlib should be used for these things. But how?
EDIT:
Here is how I solved it using pathlib.
def get_base_dir(current_dir: Path, base: str) -> Path:
base_parts = current_dir.parts[:current_dir.parts.index(base)+1]
return Path(*base_parts)
Honestly, #victor__von__doom's solution is better.
I think you could do this more simply using some basic string processing on the command line args:
import sys
script_path, my_file_dir = sys.argv[0], ''
try:
my_file_dir = script_path[:script_path.index('BASE')]
except ValueError:
print("No path found back to BASE"); exit()
sys seems like a much easier option than pathlib here.

Python import files from 3 layers

I have the following file structure
home/user/app.py
home/user/content/resource.py
home/user/content/call1.py
home/user/content/call2.py
I have imported resources.py in app.py as below:
import content.resource
Also, I have imported call1 and call2 in resource.py
import call1
import call2
The requirement is to run two tests individually.
run app.py
run resource.py
When I run app.py, it says cannot find call1 and call2.
When run resource.py, the file is running without any issues. How to run app.py python file to call import functions in resource.py and also call1.py and call2.py files?
All the 4 files having __init__ main function.
In your __init__ files, just create a list like this for each init, so for your user __init__: __all__ = ["app", "content"]
And for your content __init__: __all__ = ["resource", "call1", "call2"]
First try: export PYTHONPATH=/home/user<-- Make sure this is the correct absolute path.
If that doesn't solve the issue, try adding content to the path as well.
try: export PYTHONPATH=/home/user/:/home/user/content/
This should definitely work.
You will then import like so:
import user.app
import user.content.resource
NOTE
Whatever you want to use, you must import in every file. Don't bother importing in __init__. Just mention whatever modules that __init__ includes by doing __all__ = []
You have to import call1 and call2 in app.py if you want to call them there.

Importing all variables from a flexibly defined module

I have a main config.py file and then specific client config files, e.g. client1_config.py.
What I'd like to do is import all variables within my client1_config.py file into my config.py file. The catch is I want to do this flexibly at runtime according to an environment variable. It would look something like this:
import os
import importlib
client = os.environ['CLIENT']
client_config = importlib.import_module(
'{client}_config'.format(
client=client))
from client_config import *
This code snippet returns the following error: ModuleNotFoundError: No module named 'client_config'
Is it possible (and how) to achieve what I'm trying to do or Python does not support this kind of importing at all?
The call to import_module already imports the client configuration. from client_config import * assumes that client_config is the name of the module you are trying to import, just as import os will import the module os even if you create a variable os beforehand:
os = "sys"
import os # still imports the os module, not the sys module
In the following, assume that we have a client1_config.py which just contains one variable:
dummy = True
To add its elements to the main namespace of config.py so that you can access them directly, you can do the following:
import importlib
client = "client1"
# Import the client's configuration
client_config = importlib.import_module(f"{client}_config")
print(client_config.dummy) # True
# Add all elements from client_config
# to the main namespace:
globals().update({v: getattr(client_config, v)
for v in client_config.__dict__
if not v.startswith("_")})
print(dummy) # True
However, I would suggest to access the client's configuration as config.client for clarity and to avoid the client's configuration file overwriting values in the main configuration file.

Python 3.6 Importing a class from a parallel folder

I have a file structure as shown below,
MainFolder
__init__.py
FirstFolder
__init__.py
firstFile.py
SecondFolder
__init__.py
secondFile.py
Inside firstFile.py, I have a class named Math and I want to import this class in secondFile.py.
Code for firstFile.py
class Math(object):
def __init__(self, first_value, second_value):
self.first_value = first_value
self.second_value = second_value
def addition(self):
self.total_add_value = self.first_value + self.second_value
print(self.total_add_value)
def subtraction(self):
self.total_sub_value = self.first_value - self.second_value
print(self.total_sub_value)
Code for secondFile.py
from FirstFolder.firstFile import Math
Math(10, 2).addition()
Math(10, 2).subtraction()
When I tried running secondFile.py I get this error: ModuleNotFoundError: No module named 'First'
I am using Windows and the MainFolder is located in my C drive, under C:\Users\Name\Documents\Python\MainFolder
Possible solutions that I have tried are, creating the empty __init__.py for all main and sub folders, adding the dir of MainFolder into path under System Properties environment variable and using import sys & sys.path.append('\Users\Name\Documents\Python\MainFolder').
Unfortunately, all these solutions that I have found are not working. If anyone can highlight my mistakes to me or suggest other solutions, that would be great. Any help will be greatly appreciated!
There are potentially two issues. The first is with your import statement. The import statement should be
from FirstFolder.firstFile import Math
The second is likely that your PYTHONPATH environment variable doesn't include your MainFolder.
On linux and unix based systems you can do this temporarily on the commandline with
export PYTHONPATH=$PYTHONPATH:/path/to/MainFolder
On windows
set PYTHONPATH="%path%;C:\path\to\MainFolder"
If you want to set it permanently, use setx instead of set

Loading python modules in Python 3

How do I load a python module, that is not built in. I'm trying to create a plugin system for a small project im working on. How do I load those "plugins" into python? And, instaed of calling "import module", use a string to reference the module.
Have a look at importlib
Option 1: Import an arbitrary file in an arbiatrary path
Assume there's a module at /path/to/my/custom/module.py containing the following contents:
# /path/to/my/custom/module.py
test_var = 'hello'
def test_func():
print(test_var)
We can import this module using the following code:
import importlib.machinery
myfile = '/path/to/my/custom/module.py'
sfl = importlib.machinery.SourceFileLoader('mymod', myfile)
mymod = sfl.load_module()
The module is imported and assigned to the variable mymod. We can then access the module's contents as:
mymod.test_var
# prints 'hello' to the console
mymod.test_func()
# also prints 'hello' to the console
Option 2: Import a module from a package
Use importlib.import_module
For example, if you want to import settings from a settings.py file in your application root folder, you could use
_settings = importlib.import_module('settings')
The popular task queue package Celery uses this a lot, rather than giving you code examples here, please check out their git repository

Resources