How to get current directory with subprocess? - python

How can i get the current directory to which I am in? like the use of
os.getcwd()

First, I presume you're not asking about a particular subprocess that exists simply to tell you the current working directory and do nothing else (Apducer's answer). If that were the case you could simply as os.getcwd() and forget the subprocess. You clearly already know that. So you must be dealing with some other (arbitrary?) subprocess.
Second, I presume you understand, via dr1fter's answer, that you have control over the working directory in which the subprocess starts. I suspect that's not enough for you.
Rather, I suspect you're thinking that the subprocess might, according to its own internal logic, have changed its working directory sometime since its launch, that you can't predict where it has ended up, and you want to be able to send some sort of signal to the subprocess at an arbitrary time, to interrogate it about where it's currently working. In general, this is only possible if the process has been specifically programmed with the logic that receives such a signal (through whatever route) and issues such a response. I think that's what SuperStew meant by the comment, "isn't that going to depend on the subprocess?"
I say "in general" because there are platform-specific approaches. For example, see:
windows batch command to determine working directory of a process
How do I print the current working directory of another user in linux?

by default, subprocesses you spawn inherit your PWD. you can however, specify the cwd argument to the subprocess.Popen c'tor to set a different initial PWD.

Unix (Linux, MacOS):
import subprocess
arguments = ['pwd']
directory = subprocess.check_output(arguments)
Windows:
import subprocess
arguments = ['cd']
directory = subprocess.check_output(arguments)
If you want to run in both types of OS, you'll have to check the machine OS:
import os
import subprocess
if os.name == 'nt': # Windows
arguments = ['cd']
else: # other (unix)
arguments = ['pwd']
directory = subprocess.check_output(arguments)

Related

How to run Open Pose binary (.exe) from within a Python script?

I am making a body tracking application where I want to run Open Pose if the user chooses to track their body movements. The OpenPose binary file can be run like so:
bin\OpenPoseDemo.exe --write_json 'path\to\dump\output'
So, in my Python script, I want to have a line of code that would run Open Pose, instead of having to ask the user to manually run OpenPose by opening a separate command line window. For that, I have tried:
import os
os.popen(r"C:\path\to\bin\OpenPoseDemo.exe --write_json 'C:\path\to\dump\output'")
But this gives the following error:
Error:
Could not create directory: 'C:\Users\Admin\Documents\Openpose\. Status error = -1. Does the parent folder exist and/or do you have writing access to that path?
Which I guess means that OpenPose can be opened only by going inside the openpose directory where the bin subdirectory resides. So, I wrote a shell script containing this line:
bin\OpenPoseDemo.exe --write_json 'C:\path\to\dump\output'
and saved it as run_openpose_binary.sh in the openpose directory (i.e., the same directory where bin is located).
I then tried to run this shell script from within my Python script like so:
import subprocess
subprocess.call(['sh', r'C:\path\to\openpose\run_openpose_binary.sh'])
and this gives the following error:
FileNotFoundError: [WinError 2] The system cannot find the file specified
I also tried the following:
os.popen(r"C:\path\to\openpose\run_openpose_binary.sh")
and
os.system(r"C:\path\to\openpose\run_openpose_binary.sh")
These do not produce any error, but instead just pop up a blank window and closes.
So, my question is, how do I run the OpenPoseDemo.exe from within my Python script?
For your last method, you're missing the return value from os.popen, which is a pipe. So, what you need is something like:
# untested as I don't have access to a Windows system
import os
with os.popen(r"/full/path/to/sh C:/path/to/openpose/run_openpose_binary.sh") as p:
# pipes work like files
output_of_command = p.read().strip() # this is a string
or, if you want to future-proof yourself, the alternative is:
# untested as I don't have access to a Windows system
popen = subprocess.Popen([r'/full/path/to/sh.exe', r'/full/path/to/run_openpose_binary.sh')], stdin=subprocess.PIPE, stdout=subprocess.PIPE,encoding='utf-8')
stdout, stderr = popen.communicate(input='')
Leave a comment if you have further difficulty.
I've had to fight this battle several times and I've found a solution. It's likely not the most elegant solution but it does work, and I'll explain it using an example of how to run OpenPose on a video.
You've got your path to the openpose download and your path to the video, and from there it's a 3-line solution. First, change the current working directory to that openpose folder, and then create your command, then call subprocess.run (I tried using subprocess.call and that did not work. I did not try shell=False but I have heard it's a safer way to do so. I'll leave that up to you.)
import os
import subprocess
openpose_path = "C:\\Users\\me\\Desktop\\openpose-1.7.0-binaries-win64-gpu-python3.7-flir-3d_recommended\\openpose\\"
video_path = "C:\\Users\\me\\Desktop\\myvideo.mp4"
os.chdir(openpose_path)
command = "".join(["bin\\OpenPoseDemo.exe", " -video ", video_path])
subprocess.run(command, shell=True)

Run subprocess to call another python script without waiting

I have read way to many threads now and really lost.
Just trying to do something basic before I make it complicated.
so i have a script test.py
I want to call the script from within runme.py but without waiting so it will process the other chunk of code, but then when it gets to the end wait for test.py code to finish before continuing on.
I cant seem to figure out the correct syntax for the p = subprocess.Popen (I have tried so many)
and do I need the that to the test.py if its in the same directory?
here is what i have but cant get to work.
import subprocess
p = subprocess.Popen(['python test.py'])
#do some code
p.wait()
I cant seem to figure out the correct syntax for the p = subprocess.Popen (I have tried so many)
You want to pass it a list of arguments. The first argument is the program to run, python (although actually, you probably want sys.executable here); the second is the script that you want python to run. So:
p = subprocess.Popen(['python', 'test.py'])
and do I need the that to the test.py if its in the same directory?
This will work the same way as if you ran python test.py at the shell: it will just pass test.py as-is to python, and python will treat that as a path relative to the current working directory (CWD).
So, if test.py is in the CWD, this will just work.
If test.py is somewhere else, then you need to provide either an absolute path, or one relative to the CWD.
One common thing you want is that test.py is in not necessarily in the CWD, but instead it's in the same directory as the script/module that wants to launch it:
scriptpath = os.path.join(os.path.dirname(__file__), 'test.py')
… or in the same directory as the main script used to start your program:1
scriptpath = os.path.join(os.path.dirname(sys.argv[0]), 'test.py')
Either way, you just pass that as the argument:
p = subprocess.Popen(['python', scriptpath])
1. On some platforms, this may actually be a relative path. If you might have done an os.chdir since startup, it will now be wrong. If you need to handle that, you want to stash os.path.abspath(os.path.dirname(sys.argv[0])) in the main script at startup, then pass it down to other functions for them to use instead of calling dirname(argv[0]) themselves.

Python 3: subprocess, changing directory

I have a main project in C:/myproject/harry.py
harry.py is launching threads.
harry.py is saving and loading text documents every few seconds using an already established path self.relativePath = os.path.dirname(sys.argv[0])
Inside each thread, a subprocess is being called to activate a command line .exe file found in C:/myproject/betty/here.exe
I have tried all sorts of things to achieve this such as:
my_env = os.environ
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
doit = subprocess.Popen('cd betty/', 'here.exe -command', env=my_env)
doit.wait()
or
my_env = os.environ
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
doit = subprocess.Popen('here.exe -command', cwd='C:/myproject/betty/')
doit.wait()
Response:
FileNotFoundError: [WinError 2] The system cannot find the file specified
Is it possible to run the subprocess inside the subfolder with the custom path ... that will not interfere with the already established path self.relativePath
Thanks,
You were fairly close:
> doit = subprocess.Popen('here.exe -command', cwd='C:/myproject/betty/')
This would actually work if your command were called here.exe -command but of course, no such file exists. You want ['here.exe', '-command'] (or somewhat more unsafely and less efficiently add shell=True; but really, don't).
It seems you forgot to pass in env=my_env in this attempt, too; though does here.exe really require you to modify the PATH? And if it does, repeatedly creating a new copy for each new subprocess seems slightly wasteful.
You'll also want to switch to subprocess.run() or one of the legacy wrappers; you should really only use the low-level Popen() function directly from library functions.
On the other hand, does here.exe really need to run in a particular directory, and does that directory exist on your PATH? Windows is slightly weird and Windows programmers are often unaware of basic command-line usability design principles; but if here.exe is at all correctly written, perhaps you are actually looking for
s = subprocess.run(['c:/myproject/betty/here.exe', '-command'], env=my_env)
I have discovered the answer with some help from various stackoverflow posts on the topic as well as stumbling through possible solutions. It was not easy!
self.relativePath = os.path.dirname(sys.argv[0])
self.relativePath1 = self.relativePath + '\\your_subdirectoryHERE\\'
Be sure to include double slashes, to match os.path.dirname(sys.argv[0])
self.process = subprocess.Popen(self.relativePath1 + 'flare.exe -command', cwd=self.relativePath1)

subprocess.Popen and relative directories

I am writing a script to open notepad.exe using subprocess.Popen()
import subprocess
command = '%windir%\system32\\notepad.exe'
process = subprocess.Popen(command)
output = process.communicate()
print(output[0])
This throws a FileNotFoundError
Is it possible to change/add to the above code to make it work with relative paths?
I did try to run the script from C:\Windows> after moving it there, which again failed. Also set the shell=True, but failed as well.
Writing a similar script using os.popen() works ok with relative paths, regardless which directory the script is run from, but as far as I understand popen is not the way forward..
Early steps in the world of programming/Python. Any input much appreciated.
Use os.path.expandvars to expand %windir%:
command = os.path.expandvars('%windir%\\system32\\notepad.exe')
The result is a path that then can be passed to subprocess.Popen.
subprocess.Popen does not expand environment variables such as %windir%. The shell might but you really should not depend on shell=True to do that.
Pro tip: whenever you get an error asking the system to execute a command, print the command (and, if applicable, the current working directory). The results will often surprise you.
In your case, I suspect you're just missing a backslash. Use this instead:
command = '%windir%\\system32\\notepad.exe'
Before you make that change, try printing the value of command immediately after assignment. I think you'll find the leading "s" in "system" is missing, and that the mistake is obvious.
HTH.
You could use raw strings to avoid having to double-up your backslashes.
command = r'%windir%\system32\notepad.exe'

pythonrc in interactive code

I have a .pythonrc in my path, which gets loaded when I run python:
python
Loading pythonrc
>>>
The problem is that my .pythonrc is not loaded when I execute files:
python -i script.py
>>>
It would be very handy to have tab completion (and a few other things) when I load things interactively.
From the Python documentation for -i:
When a script is passed as first argument or the -c option is used, enter interactive mode after executing the script or the command, even when sys.stdin does not appear to be a terminal. The PYTHONSTARTUP file is not read.
I believe this is done so that scripts run predictably for all users, and do not depend on anything in a user's particular PYTHONSTARTUP file.
As Greg has noted, there is a very good reason why -i behaves the way it does. However, I do find it pretty useful to be able to have my PYTHONSTARTUP loaded when I want an interactive session. So, here's the code I use when I want to be able to have PYTHONSTARTUP active in a script run with -i.
if __name__ == '__main__':
#do normal stuff
#and at the end of the file:
import sys
if sys.flags.interactive==1:
import os
myPythonPath = os.environ['PYTHONSTARTUP'].split(os.sep)
sys.path.append(os.sep.join(myPythonPath[:-1]))
pythonrcName = ''.join(myPythonPath[-1].split('.')[:-1]) #the filename minus the trailing extension, if the extension exists
pythonrc = __import__(pythonrcName)
for attr in dir(pythonrc):
__builtins__.__dict__[attr] = getattr(pythonrc, attr)
sys.path.remove(os.sep.join(myPythonPath[:-1]))
del sys, os, pythonrc
Note that this is fairly hacky and I never do this without ensuring that my pythonrc isn't accidentally clobbering variables and builtins.
Apparently the user module provides this, but has been removed in Python 3.0. It is a bit of a security hole, depending what's in your pythonrc...
In addition to Chinmay Kanchi and Greg Hewgill's answers, I'd like to add that IPython and BPython work fine in this case. Perhaps it's time for you to switch? :)

Categories

Resources