Locating a resource file in the same directory - python

I am building an application that needs access to a resource in the same folder (It needs the xsd file to validate the input file).
How can I reach this xsd file reliably?
To elaborate:
I need to be able to call the executable:
cd not/the/directory/of/the/program
path/to/program -c config.xml
What is the path to use here?
subprocess.Popen("xmllint --noout --schema ?/?/config.xsd " + configfilename)

Take a look at the zeroth command-line argument your program gets. It's usually the name of the program, and might also include a path to the program. Combine that with the current directory. Then use realpath or some equivalent of it to get rid of symbolic links. However, I think there are still some corner cases where this approach might fail.
You didn't specify /the programming language/ or operating system you are using. If you're writing a bash script, see here:
https://stackoverflow.com/a/246128/11451509
For Python, see How do I get the path of the current executed file in Python?
If the operating system is Linux, you could also go through the /proc pseudo filesystem, as explained here:
https://stackoverflow.com/a/738024/11451509

Related

Execute an .exe in Python in Ubuntu/WSL

How can I execute an .exe file with Python3 on Ubuntu in WSL? From my searches I found os.system, but despite being placed in the correct folder, I cannot find the .exe file. I also tried with os.open with no results.
import os
current = os.chdir('../../../Programmi/OWASP/Zed Attack Proxy/')
os.system("ZAP.exe")
To expound on #MichaelMatsaev's answer a bit, what you are attempting to do with the Python example in your question is essentially the same as this Bash construct:
cd ../../../Programmi/OWASP/Zed Attack Proxy/
ZAP.exe
You'll get a command not found from Bash. Pretty much every Linux app will work the same way, since they all ultimately use some form of syscall in the exec family.
When executing any binary in Linux (not just Windows .exe's in WSL), the binary must be either:
On the search $PATH
Specified with a fully-qualified (relative or absolute) path to the binary.
So in addition to #MichaelMatsaev's (correct) suggestion to use:
os.system("../../../Programmi/OWASP/Zed Attack Proxy/ZAP.exe")
The following would work as well:
os.chdir('../../../Programmi/OWASP/Zed Attack Proxy/')
os.system("./ZAP.exe")
And, while it would be a bit pathologic (i.e. I can't imagine you'd want to do it) for this case, you could even modify the search path inside the code and then call the binary without a fully-qualified path:
os.environ['PATH'] += os.pathsep + '../../../Programmi/OWASP/Zed Attack Proxy/'
os.system("ZAP.exe")
Side-note: AFAIK, there's no reason to attempt to store the os.chdir into the current variable, as os.chdir doesn't return a value.
Try using a fully-qualified path:
os.system("../../../Programmi/OWASP/Zed Attack Proxy/ZAP.exe")

Is it possible to access the launching shortcut directory from a Python executalbe?

I currently have a Python scrip that runs through all Excel files in the current directory and generates a PDF report.
It works fine now but I don't want the users to be anywhere near frozen Python scripts. I created an MSI with cxFreeze which puts the EXE and scripts in the Program Files directory.
What I would like to be able to do is create a shortcut to this executable and pass the directory the shortcut was run from to the Python program so that can be set as the working directory. This would allow the user to move the shortcut to any folder of Excel files and generate a report there.
Does Windows send the location of a opened shortcut to the executable and is there a way to access it from Python?
When you launch a shortcut, Windows changes the working directory to the directory specified in the shortcut, in the Start in field. At this point, Windows has no memory of where the shortcut was stored.
You could change the Start in field to point to the directory that the shortcut is in. But you'd have to do that for every single shortcut, and never make a mistake.
The better approach is to use a script, rather than a shortcut. Place your actual Python script (which we'll call doit.py for sake of example) somewhere in your PYTHONPATH. Then create a single-line Python script that imports it:
import doit
Save it (but don't name it doit.py) and copy it to each directory from which you want to be able to invoke the main script. In doit.py you can use os.getcwd() to find out what directory you're being invoked from.
You could also do it with a batch file. This is a little more flexible in that you can specify the exact name of the script and which Python interpreter should be used, and don't need to store the script in a directory in PYTHONPATH. Also, you don't need to worry about the file's name clashing with the name of a Python module. Simply put this line in a file:
C:\path\to\your\python.exe C:\path\to\your\script.py
Save it as (e.g.) doit.bat and copy it into the directories from which you want to invoke it. As before, your Python script can call os.getcwd() to get the directory. Or you can write it so your Python script accepts it as the first argument, and write your batch file like:
C:\path\to\your\python.exe C:\path\to\your\script.py %cd%
Another thing you can do with the batch file approach is add a pause command to the end so that the user is asked to press a key after the script runs, giving them the opportunity to read any output generated by the script. You could even make this conditional so that it only happens if an error occurs (which requires returning a proper exit code from the script). I'll leave that as an exercise. :-)
Is there a problem with modifying the script to take the directory to process as a command line argument?
You could then configure the different shortcuts to pass in the appropriate directory.
Type the following into a batch file (i.e. script.bat):
python \absolute\path\to\your\script.py %~dp0
pause
Then add these imports at the top of your python file script.py (if not already included):
import os
import sys
And add this to the bottom of the python file (or combine it with a similar statement):
if __name__ == "__main__":
# set current working directory:
if len(sys.argv) > 1:
os.chdir(sys.argv[1])
main()
replace main() with whatever function you want to call or code you want to run.
The following is how I came to my answer:
I tried using kindall's answer and had the following issues:
The first suggestion of storing the script somewhere in PYTHONPATH could not be applied to my situation because my script will be used on a server and needs to be independent of the client computer's python environment (besides having the required pip installations).
I tried calling my python script from a Windows Batch File which could be moved to a different location. Instead of the batch file's location being used as the current working directory, it was C:\Windows.
I tried passing %cd% as an argument to my python script, then setting that to be my CWD. This still resulted in a CWD of C:\Windows.
After reviewing the comments, I tried Eryk Sun's suggestion of instead passing %~dp0 as an argument to the python script. This resulted in the CWD being correctly set to the batch file's location.
I hope this helps others facing similar difficulties.

Python utility fails to successfully run a non-Python script that uses relative paths

My Python3 utility has a function that doesn't work (unless it's placed within selected directories, where it can then run the non-python pdflatex scripts successfully). I want to run the utility from a set location on any of the template.tex files I have, stored in various other locations.
The Python utility prompts the user to select a pdflatex template file from an absolute path using a tkinter.filedialog GUI, then runs the user's selected pdflatexscript using, for example: os.system("pdflatex /afullpath/a/b/c/mytemplate.tex")
Python's os.system runs pdflatex, which then runs its mytemplate.tex script. mytemplate.tex has numerous inputs written with relative paths like ./d/another.tex.
So, the Python utility works fine as long as it's in the exact same path as /afullpath/a/b/c/mytemplate.tex that the user selects. Otherwise pdflatex can't finds its own input files. pdflatex delivers an error message like: ! LaTeX Error: File ./d/another.tex not found because the execution path is relative to the Python script and not the pdflatex script.
[pdflatex needs to use relative paths because the folders with its .tex files get moved around, as needed.]
I found the following similar case on Stack Overflow, but I don't think the answers are geared towards this situation: Relative Paths In Python -- Stack Overflow
By referring to other files with relative paths like ./d/another.tex, your mytemplate.tex file is assuming (and requiring) that pdflatex is only run on it from the same directory that mytemplate.tex is located in. You thus need to satisfy this requirement by changing to the directory containing mytemplate.tex before calling os.system:
input_file = '/afullpath/a/b/c/mytemplate.tex'
olddir = os.getcwd()
os.chdir(os.path.dirname(input_file))
os.system('pdflatex ' + input_file)
os.chdir(olddir)
Even better is to use subprocess.call, as it handles the change of directory for you and isn't vulnerable to shell quoting issues:
subprocess.call(['pdflatex', input_file], cwd=os.path.dirname(input_file))
Use subprocess.run instead of os.system and pass in the cwd parameter as the directory of the latex script.
See the subprocess.run docs here, and look at the cwd parameter for subprocess.Popen.
Example:
subprocess.run(["pdflatex", "/afullpath/a/b/c/mytemplate.tex"], cwd="/afullpath/a/b/c/")

One-word-command from .py (without aliases)

Some programs can be executed from anywhere with a single one-word command. An example of this is youtube-dl, which is a python program that can be executed with the simple command youtube-dl [input]. As far as I have understood, this is simply because there exists a file called /usr/bin/youtube-dl, and /usr/bin is in PATH. However, I do not understand what I have to do to make something like this myself. Right now, I have a python project called testproject that includes a python program like this:
~/testproject/files/myownprogram.py
What do I have to do to make this a binary executable such as youtube-dl?
I know I can make an alias mop="python ~/testproject/files/myownprogram.py", and this is also what I have done, and it works fine. That is, I can write $ mop, and successfully run my program.
But for curiosity's, and learning's, sake, I want to know how to make a file such as the /usr/bin/youtube-dl file, removing the need for aliases.
I find this hard to find information about in search engines...
Any help is greatly appreciated! :-)
Edit:
My question differs from the one marked as duplicate, in that I'm not looking to execute it as a .sh-script. I simply want to execute it as a suffix-less one-word command, similar to all the other executables that are in /usr/bin. :-)
Ex.: $ myown should run my program, without the need for aliases or writing ".sh" or ".py" at the prompt. That is, I want to have a file /usr/bin/myown that somehow runs my testproject at the simple command myownfrom anywhere.
The applications are being executed "from anywhere" because the system has a specific hierarchy of places it looks for these files (the current directory, then the system path). So, it knows to look in /usr/bin because that's in your system path.
As to ensuring it to use python when it's executed, you should add the following to the top of the file (check out some python application source code and you'll see this):
#!/usr/bin/env python
This tells the system to execute the script using the systems "python" command.

Reference file in Ruby subshell in Rails app

I am having trouble referencing a file in another directory in my rails app. I have a controller located in my_app/app/controllers/concerns/my_controller with the following line of code:
#value = %x(python ../../lib/assets/python/test.py #{Shellwords.escape(params[:first_name])} 2>&1)
That is running test.py located in my_app/lib/assets/python/test.py with the %x() subshell.
When I reference the file from my desktop, it runs the test.py code correctly. But when I place the script in my lib/assets/python folder I get a cannot find file or directory error.
How should I correctly reference my test.py file so that the %x() command can find it?
If the PATH isn't set so the user running your code is able to find python then you'll get that error.
Instead of referencing it as python which forces the system to try to locate Python by walking the PATH, use the full path to the interpreter. You can usually find that by typing
which python
at the command prompt, and then putting that into the code replacing the single word python.
Ruby's File class has several very useful methods for finding the path from a directory to another, or to a specific file. Look at:
absolute_path
realpath
expand_path
I generally use realpath since it checks to see that the target actually exists before returning a path to it.
You could use it something like:
File.realpath('../../path/to/file', File.dirname(__FILE__))
which should return a path relative to the script that is currently being executed.
You can reference from the running script using:
File.realpath('../../path/to/file', File.dirname($0))
You'll need to figure out whether you want to base your path from __FILE__ or $0 and what the differences are.

Categories

Resources