12

I have an executable python script that exists in a "scripts" directory, and there's a symbolic link to that script (used to launch the file) in a root directory. Something like:

.
├── scripts
│   ├── const.py
│   ├── fops.py
│   ├── i_build.py
│   └── i_Props.ini
└── build_i -> scripts/i_build.py

I would like to be able to launch/run my scripts via:

python build_i

From the root directory. The i_build.py script will attempt to open i_Props.ini and do some magic based on what's in there.

The issue is that when the i_build.py script is launched via the symlink in the root directory, the i_build.py script will look in the root directory for the other files (not the /scripts directory where i_build.py is stored).

The i_build.py file has the props file location as:

PROP_FILE = "i_Props.ini"

and attempts to open that, and then fails. I do not want to hardcode a path for obvious reasons.

A quick test adding os.getcwd() in the main file confirms my suspicions that it thinks the CWD is the root directory, and a check of __file__ says it is the symbolic link ("build_i").

Is there anything I can do to have python use the destination of the symbolic like for the __file__ name and CWD?

Mike
  • 40,613
  • 26
  • 100
  • 171
  • You could probably monitor the filesystem using kqueue/whatever they have on the other operating systems. The thing that will ultimately set the two locations apart might be the inode that initiates the execution. None of that is exposed very clearly without some digging though.. The only other thing I can think would be a hard link rather than a soft link, but I'm thinking that might have the opposite effect entirely. There's a couple shell tricks you could do, I believe Z shell has a 'before you run the program' hook that could feed your real cwd to the script as an arg?.. – synthesizerpatel Oct 28 '13 at 19:27
  • This isn't worthy of an answer so I'm commenting. You could read the symlink using `os.readlink()`, and run the script from the result with `subprocess.Popen()`. A bit clunky but does the job as nothing's hardcoded and it doesn't add dependencies. – ThinkChaos Oct 28 '13 at 19:36
  • related: [How do I get the path of the current executed file in python?](http://stackoverflow.com/q/2632199/4279) – jfs Nov 05 '13 at 23:33

2 Answers2

18

You can use __file__, but you have to take some precautions to get the real path:

import os
base_dir = os.path.dirname(os.path.realpath(__file__))

Then load your other files / resources relative to base_dir:

some_subdir = 'my_subdir'
some_file = 'my.ini'

ini_path = os.path.join(base_dir, some_subdir, some_file)
Ronald Portier
  • 201
  • 1
  • 2
  • 1
    [`__file__` can be undefined](http://stackoverflow.com/q/2632199/4279) you could [fallback on `sys.argv[0]` in this case](https://bitbucket.org/pypy/pypy/src/a299cd0a893f/pypy/tool/autopath.py?at=default#cl-29) – jfs Nov 05 '13 at 23:57
2

Just a few possibilities spring to mind:

  1. In the root directory have a shell file that calls your python script by explicit path.
  2. Add the directory that it lives in to your path.
  3. Specifically add the directory to sys.path
Steve Barnes
  • 24,968
  • 6
  • 54
  • 63
  • Option 1 might be my work around... 2 and 3 are essentially hardcoding still. I need to avoid anything that involves extra steps as this is distributed to a number of people, the less env vars that are messed with the better. – Mike Oct 28 '13 at 19:28
  • On linux if you add the bash script to /etc or /bin or /usr/etc then it will be executable without giving a path. – Steve Barnes Oct 28 '13 at 19:33