Launching a python script via a symbolic link
Asked Answered
C

3

14

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?

Cavalryman answered 28/10, 2013 at 19:15 Comment(3)
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?..Nic
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.Radiotelephone
related: How do I get the path of the current executed file in python?Immortal
E
20

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)
Exostosis answered 5/11, 2013 at 22:45 Comment(1)
__file__ can be undefined you could fallback on sys.argv[0] in this caseImmortal
M
3

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
Maturation answered 28/10, 2013 at 19:23 Comment(2)
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.Cavalryman
On linux if you add the bash script to /etc or /bin or /usr/etc then it will be executable without giving a path.Maturation
V
0

The simplest way to be able to launch a Python script from a symlink and have the script use the link destination's path is:

os.chdir("<path to link destination>")

For example, I like to put my script and its associated files in /usr/local/lib/myapp

Then for convenience I create a symlink to /usr/local/lib/myapp/myapp.py in /usr/local/bin/:

cd /usr/local/bin
ln -s ../lib/myapp/myapp.py myapp

In myapp.py I would have this:

os.chdir("/usr/local/lib/myapp")
# put any import statements for myapp files here
Vickeyvicki answered 29/1, 2023 at 0:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.