Without worrying about current working directory (Python).
What if you have some script or application that uses relative path and you want to invoke it from another directory. To get things more complicated. maybe your “external” code also use relative path, but relative to another directory. Here, I will describe the recipe how you can make all of these to work.
Suppose, that you wrote some script or application that is packaged and installed as YourApp (that is, it is installed into site-packages or venv). Something like this:
Note: Here I’m using init_app_conf module. You can read about it here.
Typically, at the end of the script/application’s
main() function there are following lines:
They are designed to forward the call to the
main()function when the file is called as script, typically from the the directory where
app.py is laid down (
cd YourApp) something like this is called:
Now, what if you want to call
app.py (or it’s
main() function) from another directory?
If you have code such as in line 17, it will just fail. The essential problem their that my code use relative path, so it assumes that my working directory is the same as
An alternative approach may be to supply some
runner.py file, something like this:
Note, that this file also don’t have:
at the end.
It basically, calls
main() function decorated by
FixRelCwd context-manager. I will get back to
Now, in some unrelated directory, you should have something like this:
This is “real”
main method. If you want to put some extra code before or after the
main() function. You can put it in lines 15 and 17.
Here you can read my story that describes my way to configure logging.
To put simple, besides lines 2 and 16 this is typical
main() function. I want among many other thing to call
app.py script/application that is installed in
YourApp package. To make in concrete, the following code was executed:
python -m pip uninstall --yes YourApp
python setup.py sdist bdist_wheel
python -m pip install --find-links=./dist YourApp
So, because we installed
YourApp package we can import (the wrapper of, why it is important that it is wrapper will be clear below)
main() function at line 2 and make regular call to it whenever it is appropriate (we can add some code before and/or after it, if we will).
Let’s quickly some-app, what we have. We have
YourApp script application. It is installed into site-packages or venv. It has
app.py file with
main() function that does some computation. We have some “wrapper”
main() function decorated by
FixRelCwd context-manager. And we have some “real” file with “real”
main() function as above.
So, the real power is in
FixRelCwd is context-manager. It takes relPackage and, optionally, logger.
It temporary changes current working directory to the one where relPackage is installed. If logger is not specified, than some default one will be used.
If this function is called in REPL or IPython notebook it does nothing.
This function wasn’t tested from frozen python script (frozen using py2exe), but it should work (by doing nothing).
Basically, first it stores
os.chdir for the later use, than it looks for
__file__ attribute in the relPackage module, takes directory from there and set cwd to it (by calling to
On the exit, it restores
os.chdir, so your “external” code can operate as usual.
- Integrating Python’s logging and warnings packages.
mainsmodule or Making relative path to file to work.
mainsmodule or Make path to file on Windows works on Linux.
mainsmodule or Making more to relative path to file to work
mainsmodule or Exception Propagation from another Process
filesmodule or Join Files.