Access files relative to imported python module - python

Preliminary:
I have Anaconda 3 on Windows 10, and a folder, folder_default, that I have put on the Python path. I'm not actually sure whether that's the right terminology, so to be clear: regardless to where my Python script is, if I have a line of code that says import myFile, that line of code will succeed if myFile.py is in folder_default.
My issue:
In folder_default, I have:
A subfolder called useful_files which contains a text file called useful_file_1.txt.
A python script called my_misc.py.
my_misc.py has a line similar to: np.loadtxt('useful_files/useful_file_1.txt'). This line does not work if I use import my_script in a python file in a location other than folder_default, since useful_files/useful_file_1.txt is not the folder path relative to the python file that imports my_misc.py. I don't want to start using global file paths if I can avoid it.
How can I access files using file paths relative to the imported python module, rather than relative to the python script that imports that module?
Please let me know if the question is unclear - I tried to write a fake, minimal version of the setup that's actually on my computer in the hopes that that would simplify things, but I can change it if that actually makes things more confusing.
Thanks.

You can get the path to current module using the getfile method of inspect module as inspect.getfile(inspect.currentframe()).
For example:
# File : my_misc.py
import os, inspect
module_dir_path = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # get path to the directory of current module
useful_file_path = os.path.join(module_dir_path,'useful_files','useful_file_1.txt')
# path stored in useful_file_path. do whatever you want!
np.loadtxt(useful_file_path)

Related

Have a python script always reference the same directory regardless of where it's run in the system [duplicate]

This question already has answers here:
How do I get the path and name of the file that is currently executing?
(26 answers)
Closed 7 years ago.
I have a python script that accepts file names as arguments and performs operation on those files. Currently the script is in the same directory as the files it operates on. But I want to be able to run my python script from anywhere in the operating system. When I give the file name as argument to the script, it should know exactly which directory to look for regardless of where the python script is running in the system. How can I achieve this in python?
Here is the relevant portion of the script. Can I just hard code the path?
The type_mapping_file will be the filename passed into the script as an argument.
data = None
with open (type_mapping_file, "r") as myfile:
data=myfile.read()
if(data is not None):
request_params = {'type': type_name, 'index': index_name}
send_http_request("/index/type/create", request_params, base_url, post_body=data)
Thank you in advance.
how should it know that?
if it's a constant path you could hardcode it into the script and use os.path to build the full path:
import os
import sys
BASE_PATH = '/my/const/path'
fullpath = os.path.join(BASE_PATH,sys.argv[1])
although, as stated in comments, a more flexible solution would be to pass the path as a separate argument, or pass absolute path for each file
I assume you're looking for a way to find the path that's given via a relative path, perhaps calling the script itself from another location.
$ cat print_path.py
import os
import sys
print os.path.abspath(sys.argv[1])
If you call this script on a relative path, it prints the absolute path, so you can find it on the disk. The magic is from os.path.abspath().
$ python print_path.py ./planning.md
/Users/Gijs/Desktop/planning.md
$ cd ..
Also if you're calling from somewhere else.
$ python Desktop/print_path.py Desktop/planning.md
/Users/Gijs/Desktop/planning.md
Edit
No, wait, you're looking for the location of the python file that's executing. That's in __file__, see How do I get the path and name of the file that is currently executing?.
The full path to the current file is a magic variable called __file__. This is a suitable argument to functions like os.path.dirname():
print("This Python file is in " + os.path.dirname(__file__))
You can then os.path.join() this with the argument supplied on the command line to get files in the same directory as the script, wherever that may be.
Note that using __file__ in this fashion is not ideal for reusable packages. It is preferred to use pkgutil.get_data() or the equivalent Setuptools function. Basically, you pass it a module or package name (typically __name__, the name of the current module, or __package__, the name of the package you're in) and it retrieves the files for you. This is required if your module is going into an importable zip file or somewhere else where __file__ doesn't exist or have a useful value.

How to print the filename of the current execution file in python? [duplicate]

Is there a universal approach in Python, to find out the path to the file that is currently executing?
Failing approaches
path = os.path.abspath(os.path.dirname(sys.argv[0]))
This does not work if you are running from another Python script in another directory, for example by using execfile in 2.x.
path = os.path.abspath(os.path.dirname(__file__))
I found that this doesn't work in the following cases:
py2exe doesn't have a __file__ attribute, although there is a workaround
When the code is run from IDLE using execute(), in which case there is no __file__ attribute
On Mac OS X v10.6 (Snow Leopard), I get NameError: global name '__file__' is not defined
Test case
Directory tree
C:.
| a.py
\---subdir
b.py
Content of a.py
#! /usr/bin/env python
import os, sys
print "a.py: sys.argv[0]=", sys.argv[0]
print "a.py: __file__=", __file__
print "a.py: os.getcwd()=", os.getcwd()
print
execfile("subdir/b.py")
Content of subdir/b.py
#! /usr/bin/env python
import os, sys
print "b.py: sys.argv[0]=", sys.argv[0]
print "b.py: __file__=", __file__
print "b.py: os.getcwd()=", os.getcwd()
print
Output of python a.py (on Windows)
a.py: __file__= a.py
a.py: os.getcwd()= C:\zzz
b.py: sys.argv[0]= a.py
b.py: __file__= a.py
b.py: os.getcwd()= C:\zzz
Related (but these answers are incomplete)
Find path to currently running file
Path to current file depends on how I execute the program
How can I know the path of the running script in Python?
Change directory to the directory of a Python script
First, you need to import from inspect and os
from inspect import getsourcefile
from os.path import abspath
Next, wherever you want to find the source file from you just use
abspath(getsourcefile(lambda:0))
You can't directly determine the location of the main script being executed. After all, sometimes the script didn't come from a file at all. For example, it could come from the interactive interpreter or dynamically generated code stored only in memory.
However, you can reliably determine the location of a module, since modules are always loaded from a file. If you create a module with the following code and put it in the same directory as your main script, then the main script can import the module and use that to locate itself.
some_path/module_locator.py:
def we_are_frozen():
# All of the modules are built-in to the interpreter, e.g., by py2exe
return hasattr(sys, "frozen")
def module_path():
encoding = sys.getfilesystemencoding()
if we_are_frozen():
return os.path.dirname(unicode(sys.executable, encoding))
return os.path.dirname(unicode(__file__, encoding))
some_path/main.py:
import module_locator
my_path = module_locator.module_path()
If you have several main scripts in different directories, you may need more than one copy of module_locator.
Of course, if your main script is loaded by some other tool that doesn't let you import modules that are co-located with your script, then you're out of luck. In cases like that, the information you're after simply doesn't exist anywhere in your program. Your best bet would be to file a bug with the authors of the tool.
This solution is robust even in executables:
import inspect, os.path
filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))
I was running into a similar problem, and I think this might solve the problem:
def module_path(local_function):
''' returns the module path without the use of __file__. Requires a function defined
locally in the module.
from http://stackoverflow.com/questions/729583/getting-file-path-of-imported-module'''
return os.path.abspath(inspect.getsourcefile(local_function))
It works for regular scripts and in IDLE. All I can say is try it out for others!
My typical usage:
from toolbox import module_path
def main():
pass # Do stuff
global __modpath__
__modpath__ = module_path(main)
Now I use _modpath_ instead of _file_.
You have simply called:
path = os.path.abspath(os.path.dirname(sys.argv[0]))
instead of:
path = os.path.dirname(os.path.abspath(sys.argv[0]))
abspath() gives you the absolute path of sys.argv[0] (the filename your code is in) and dirname() returns the directory path without the filename.
The short answer is that there is no guaranteed way to get the information you want, however there are heuristics that work almost always in practice. You might look at How do I find the location of the executable in C?. It discusses the problem from a C point of view, but the proposed solutions are easily transcribed into Python.
See my answer to the question Importing modules from parent folder for related information, including why my answer doesn't use the unreliable __file__ variable. This simple solution should be cross-compatible with different operating systems as the modules os and inspect come as part of Python.
First, you need to import parts of the inspect and os modules.
from inspect import getsourcefile
from os.path import abspath
Next, use the following line anywhere else it's needed in your Python code:
abspath(getsourcefile(lambda:0))
How it works:
From the built-in module os (description below), the abspath tool is imported.
OS routines for Mac, NT, or Posix depending on what system we're on.
Then getsourcefile (description below) is imported from the built-in module inspect.
Get useful information from live Python objects.
abspath(path) returns the absolute/full version of a file path
getsourcefile(lambda:0) somehow gets the internal source file of the lambda function object, so returns '<pyshell#nn>' in the Python shell or returns the file path of the Python code currently being executed.
Using abspath on the result of getsourcefile(lambda:0) should make sure that the file path generated is the full file path of the Python file.
This explained solution was originally based on code from the answer at How do I get the path of the current executed file in Python?.
This should do the trick in a cross-platform way (so long as you're not using the interpreter or something):
import os, sys
non_symbolic=os.path.realpath(sys.argv[0])
program_filepath=os.path.join(sys.path[0], os.path.basename(non_symbolic))
sys.path[0] is the directory that your calling script is in (the first place it looks for modules to be used by that script). We can take the name of the file itself off the end of sys.argv[0] (which is what I did with os.path.basename). os.path.join just sticks them together in a cross-platform way. os.path.realpath just makes sure if we get any symbolic links with different names than the script itself that we still get the real name of the script.
I don't have a Mac; so, I haven't tested this on one. Please let me know if it works, as it seems it should. I tested this in Linux (Xubuntu) with Python 3.4. Note that many solutions for this problem don't work on Macs (since I've heard that __file__ is not present on Macs).
Note that if your script is a symbolic link, it will give you the path of the file it links to (and not the path of the symbolic link).
You can use Path from the pathlib module:
from pathlib import Path
# ...
Path(__file__)
You can use call to parent to go further in the path:
Path(__file__).parent
Simply add the following:
from sys import *
path_to_current_file = sys.argv[0]
print(path_to_current_file)
Or:
from sys import *
print(sys.argv[0])
If the code is coming from a file, you can get its full name
sys._getframe().f_code.co_filename
You can also retrieve the function name as f_code.co_name
The main idea is, somebody will run your python code, but you need to get the folder nearest the python file.
My solution is:
import os
print(os.path.dirname(os.path.abspath(__file__)))
With
os.path.dirname(os.path.abspath(__file__))
You can use it with to save photos, output files, ...etc
import os
current_file_path=os.path.dirname(os.path.realpath('__file__'))

Simplest way to Import a shared python script relative to the current script

I am trying to import one python script from another. I have a few common functions defined in one script and then lots of other scripts that want to import those functions. No classes, just functions.
The importing script needs to import from a relative path e.g. ../../SharedScripts/python/common.py
I then a have a few functions def f1(...) defined which I will call.
I found the imp module which seemed to be the right thing to use but I was unable to figure out the exact syntax that would work for my example.
Can someone suggest the correct code to use or the simplest approach if imp is not the right module?
SOLUTION from the answers below I was able to get this working...
projectKey = 'THOR'
# load the shared script relative to this script
sys.path.append(os.path.dirname(__file__) + '/../../SharedScripts/python')
import jira
jira.CheckJiraCommitMessage(sys.argv[1], sys.argv[2], projectKey)
Where I had an empty __init__.py and a jira.py in the SharedScripts/python directory with plain function definitions.
Why not adding ../../SharedScripts/python/ to the python path? Then you could use common.py like any other module:
import common
common.f1()
You can alternate the Python path through the system variable PYTHONPATH or by manipulating it directly from python: sys.path.append("../../SharedScripts/python/")
Please notice that it is probably wiser to work with absolute pathes... (The current directory of the app could change)
To get the absolute path could can call use the function os.path.abspath: os.path.abspath('../../SharedScripts/python/')
A possible way is to add the directory to the Python path before doing the import.
#!/usr/bin/env python
import sys
sys.path.append('../../SharedScripts/python')
import common

How to import Python code from a source file?

I was hesitant about asking this because I've seen similar questions with overly complicated answers. The question I actually want answered to was closed on account of being "vague" and "not a real question", so I will be as specific as possible.
I have an object called "line" in a file called "line.py". I want to create another object that inherits from "line" called "line_segment" and put it in a file called "line_segment.py" in the same directory.
path_finding_lib/
line.py
line_segment.py
a_star.py
The problem is I can't seem to find a way to use the code in "line.py" from inside "line_segment.py" without appending strings to the system PATH variable and stuff like that.
Isn't there a way to import code from a file path or something like that? If not, why not?
While you could append to the python path for a particular file using:
import sys
sys.path.append('pathtoModule')
If they are in the same folder, (not a module, as you lack an init.py), you can simply import from the line module by doing:
from line import Line
class LineSegment(line):
Naming convention supplies underscores and lowercases for modules, Capitalized for Classes:
http://www.python.org/dev/peps/pep-0008/
It is nonstandard and will likely lead to trouble if you dynamically append to the python path in your project, as it will cause errors in object comparison.
If you have an object declared as follows:
path_finding_lib/
line.py
line_segment.py
a_star.py
somemodule/
afile.py
If your line module imports and instantiates an object from afile using the path somemodule.afile.SomeObject
It is not the same class as instantiating an object from within afile:
afile.SomeObject.
If afile returns an instance of afile.SomeObject and the object is compared for equality to an instance of somemodule.afile.SomeObject, they will be found to be not equivalent.
i.e.
somemodule.afile.SomeObject == afile.SomeObject
==> False
The easiest way to use python code in other files is to use import statement.
Say when you do
import xyz
Python will attempt to find the file xyz.py. It looks into
The site-packages folder (which is the folder in your python installation directory which contains pre-installed modules like say django etc)
Locations mentioned in PYTHONPATH environment variable (or sys.path in python)
Your current directory
In your case, your program should have the following line
from line import line
Where first line is your line.py file and second line is your class
Wherever you want to use line object for inheritance just use
class newline(line):
The catch is how you run the program. If you run it from within path_finding_lib (i.e. when your working directory is path_finding_lib and you do
python line_segment.py
, it should work (You can optionally also make a blank file init.py in the same folder).
If you run it from say your home directory
~$ python /path_to/path_finding_lib line_segment.py
It will NOT work. This is because python will search site-packages, PYTHONPATH and your current directory and not find line.py. To be able to run it from everywhere, before you run it add location of line.py to the PYTHONPATH
$export PYTHONPATH=/path_to/path_finding_lib
Then you should be able to run it
NOTE: I have assumed you have a linux ystem. For Windows unfortunately I do not know the procedure of modifying PYTHONPATH
Since they're in the same directory, create an empty file named __init__.py. This lets Python treat the directory you're working from as a package, and you'll be able to pull objects and methods from these other files.

How do I use a relative path in a Python module when the CWD has changed?

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()

Categories

Resources