running a .py file from another Python script using os - python

Can someone give me a tip on how I can use os to run a different .py file from my python script? This code below works, but only because I specify the complete file path.
How can I modify the code to incorporate running plots.py from the same directory as my main script app.py? Im using Windows at the moment but hoping it can work on any operating system. Thanks
import os
os.system('py C:/Users/benb/Desktop/flaskEconServer/plots.py')

You can execute an arbitrary Python script as a separate process using the subprocess.run() function something like this:
import os
import subprocess
import sys
#py_filepath = 'C:/Users/benb/Desktop/flaskEconServer/plots.py'
py_filepath = 'plots_test.py'
args = '"%s" "%s" "%s"' % (sys.executable, # command
py_filepath, # argv[0]
os.path.basename(py_filepath)) # argv[1]
proc = subprocess.run(args)
print('returncode:', proc.returncode)
If you would like to communicate with the process while it's running, that can also be done, plus there are other subprocess functions, including the lower-level but very general subprocess.Popen class that support doing those kind of things.

Python has built-in support for executing other scripts, without the need for the os module.
Try:
from . import plots
If you want to execute it in an independent python process, look into the multiprocessing or subprocess modules.

You can get the directory of the app.py file by using the following call in app.py
dir_path = os.path.dirname(os.path.realpath(__file__))
then join the file name you want
file_path = os.path.join(dir_path,'plot.py')
Finally your system call
os.system(f'py {file_path}') # if you're on 3.6 and above.
os.system('py %s' % file_path) # 3.5 and below
As others have said sub-processes and multi-threading may be better, but for your specific question this is what you want.

Related

Using "Subprocess Call" to call a program at an unkown directory [duplicate]

This question already has answers here:
How to reliably open a file in the same directory as the currently running script
(9 answers)
Closed 1 year ago.
I'm looking for a way to open another python file in the same folder, but it could be anywhere on a PC. (i.e when I send it to someone the program should be able to find it's way to the file (blahblahblah\IDLE\Login,py).
Here is the code I currently have after some googling, but I really have no idea what I'm doing.
from subprocess import call
import subprocess
import os
def main():
subprocess.call(['bash' , os.path.expanduser('~') + "\IDLE\Login.py" ] )
if __name__ == '__main__':
main()
I know that one of the subprocess imports are redundant but it's just a remnant of older code while I try to find this new way.
The end goal of the project is to use the main file and turn it into an executable to run all the other files in the directory which are called by each other.
Many thanks!
This will give you a full path to the script's location
print('sys.argv[0] =', sys.argv[0])
pathname = os.path.dirname(sys.argv[0])
print('path =', pathname)
print('full path =', os.path.abspath(pathname))
Here's how to run bash to execute a script named "Login.py" that is in the same directory as the currently running Python file:
import subprocess
import os
def main():
here = os.path.dirname(os.path.abspath(__file__))
subprocess.call(['bash', os.path.join(here, "Login.py")])
if __name__ == '__main__':
main()
__file__ is always the path of the file containing the Python code being executed.
I don't know why you want to run bash on a .py file, but the mechanics would be the same if you wanted to run python instead or wanted to run bash on a file named Login.sh.

How to run another python script

I would like to run another python script from within a python script, and terminate the originating script. I have tried the following:
import os
import os.path
print os.getcwd()
>>>home/pi/Gen
print os.path.exists('/home/pi/Gen/Binary2.py')
>>> True
os.execl('python', '/home/pi/Gen/Binary2.py')
>>> OSError: [Errno 2] No such file or directory
What am i doing wrong ?
You need to supply the full path to the executable. You also need to provide, as the first argument, the executable itself:
import os
os.execl('/usr/bin/python', '/usr/bin/python', '/home/pi/Gen/Binary2.py')
You could also use the p variant to use the current process' path to find the executable:
os.execlp('python', 'python', '/home/pi/Gen/Binary2.py')
Couple of methods:
you can try to add this to your code
execfile("Script-To-Execute.py")
Another method:
import subprocess
subprocess.call("Script-To-Execute.py", shell=True)

Calling a python script with input within a python script using subprocess

I have a script a.py and while executing it will ask certain queries to user and frame the output in json format. Using python subprocess, I am able to call this script from another script named b.py. Everything is working as expected except that I am not able to get the output in a variable? I am doing this in Python 3.
To call a Python script from another one using subprocess module and to pass it some input and to get its output:
#!/usr/bin/env python3
import os
import sys
from subprocess import check_output
script_path = os.path.join(get_script_dir(), 'a.py')
output = check_output([sys.executable, script_path],
input='\n'.join(['query 1', 'query 2']),
universal_newlines=True)
where get_script_dir() function is defined here.
A more flexible alternative is to import module a and to call a function, to get the result (make sure a.py uses if __name__=="__main__" guard, to avoid running undesirable code on import):
#!/usr/bin/env python
import a # the dir with a.py should be in sys.path
result = [a.search(query) for query in ['query 1', 'query 2']]
You could use mutliprocessing to run each query in a separate process (if performing a query is CPU-intensive then it might improve time performance):
#!/usr/bin/env python
from multiprocessing import freeze_support, Pool
import a
if __name__ == "__main__":
freeze_support()
pool = Pool() # use all available CPUs
result = pool.map(a.search, ['query 1', 'query 2'])
Another way than mentioned, is by using the built-in funtion exec
This function gets a string of python code and executes it
To use it on a script file, you can simply read it as a text file, as such:
#dir is the directory of a.py
#a.py, for example, contains the variable 'x=1'
exec(open(dir+'\\a.py').read())
print(x) #outputs 1

How to print the filename of the current execution file in python? [duplicate]

Is there a universal approach in Python, to find out the path to the file that is currently executing?
Failing approaches
path = os.path.abspath(os.path.dirname(sys.argv[0]))
This does not work if you are running from another Python script in another directory, for example by using execfile in 2.x.
path = os.path.abspath(os.path.dirname(__file__))
I found that this doesn't work in the following cases:
py2exe doesn't have a __file__ attribute, although there is a workaround
When the code is run from IDLE using execute(), in which case there is no __file__ attribute
On Mac OS X v10.6 (Snow Leopard), I get NameError: global name '__file__' is not defined
Test case
Directory tree
C:.
| a.py
\---subdir
b.py
Content of a.py
#! /usr/bin/env python
import os, sys
print "a.py: sys.argv[0]=", sys.argv[0]
print "a.py: __file__=", __file__
print "a.py: os.getcwd()=", os.getcwd()
print
execfile("subdir/b.py")
Content of subdir/b.py
#! /usr/bin/env python
import os, sys
print "b.py: sys.argv[0]=", sys.argv[0]
print "b.py: __file__=", __file__
print "b.py: os.getcwd()=", os.getcwd()
print
Output of python a.py (on Windows)
a.py: __file__= a.py
a.py: os.getcwd()= C:\zzz
b.py: sys.argv[0]= a.py
b.py: __file__= a.py
b.py: os.getcwd()= C:\zzz
Related (but these answers are incomplete)
Find path to currently running file
Path to current file depends on how I execute the program
How can I know the path of the running script in Python?
Change directory to the directory of a Python script
First, you need to import from inspect and os
from inspect import getsourcefile
from os.path import abspath
Next, wherever you want to find the source file from you just use
abspath(getsourcefile(lambda:0))
You can't directly determine the location of the main script being executed. After all, sometimes the script didn't come from a file at all. For example, it could come from the interactive interpreter or dynamically generated code stored only in memory.
However, you can reliably determine the location of a module, since modules are always loaded from a file. If you create a module with the following code and put it in the same directory as your main script, then the main script can import the module and use that to locate itself.
some_path/module_locator.py:
def we_are_frozen():
# All of the modules are built-in to the interpreter, e.g., by py2exe
return hasattr(sys, "frozen")
def module_path():
encoding = sys.getfilesystemencoding()
if we_are_frozen():
return os.path.dirname(unicode(sys.executable, encoding))
return os.path.dirname(unicode(__file__, encoding))
some_path/main.py:
import module_locator
my_path = module_locator.module_path()
If you have several main scripts in different directories, you may need more than one copy of module_locator.
Of course, if your main script is loaded by some other tool that doesn't let you import modules that are co-located with your script, then you're out of luck. In cases like that, the information you're after simply doesn't exist anywhere in your program. Your best bet would be to file a bug with the authors of the tool.
This solution is robust even in executables:
import inspect, os.path
filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))
I was running into a similar problem, and I think this might solve the problem:
def module_path(local_function):
''' returns the module path without the use of __file__. Requires a function defined
locally in the module.
from http://stackoverflow.com/questions/729583/getting-file-path-of-imported-module'''
return os.path.abspath(inspect.getsourcefile(local_function))
It works for regular scripts and in IDLE. All I can say is try it out for others!
My typical usage:
from toolbox import module_path
def main():
pass # Do stuff
global __modpath__
__modpath__ = module_path(main)
Now I use _modpath_ instead of _file_.
You have simply called:
path = os.path.abspath(os.path.dirname(sys.argv[0]))
instead of:
path = os.path.dirname(os.path.abspath(sys.argv[0]))
abspath() gives you the absolute path of sys.argv[0] (the filename your code is in) and dirname() returns the directory path without the filename.
The short answer is that there is no guaranteed way to get the information you want, however there are heuristics that work almost always in practice. You might look at How do I find the location of the executable in C?. It discusses the problem from a C point of view, but the proposed solutions are easily transcribed into Python.
See my answer to the question Importing modules from parent folder for related information, including why my answer doesn't use the unreliable __file__ variable. This simple solution should be cross-compatible with different operating systems as the modules os and inspect come as part of Python.
First, you need to import parts of the inspect and os modules.
from inspect import getsourcefile
from os.path import abspath
Next, use the following line anywhere else it's needed in your Python code:
abspath(getsourcefile(lambda:0))
How it works:
From the built-in module os (description below), the abspath tool is imported.
OS routines for Mac, NT, or Posix depending on what system we're on.
Then getsourcefile (description below) is imported from the built-in module inspect.
Get useful information from live Python objects.
abspath(path) returns the absolute/full version of a file path
getsourcefile(lambda:0) somehow gets the internal source file of the lambda function object, so returns '<pyshell#nn>' in the Python shell or returns the file path of the Python code currently being executed.
Using abspath on the result of getsourcefile(lambda:0) should make sure that the file path generated is the full file path of the Python file.
This explained solution was originally based on code from the answer at How do I get the path of the current executed file in Python?.
This should do the trick in a cross-platform way (so long as you're not using the interpreter or something):
import os, sys
non_symbolic=os.path.realpath(sys.argv[0])
program_filepath=os.path.join(sys.path[0], os.path.basename(non_symbolic))
sys.path[0] is the directory that your calling script is in (the first place it looks for modules to be used by that script). We can take the name of the file itself off the end of sys.argv[0] (which is what I did with os.path.basename). os.path.join just sticks them together in a cross-platform way. os.path.realpath just makes sure if we get any symbolic links with different names than the script itself that we still get the real name of the script.
I don't have a Mac; so, I haven't tested this on one. Please let me know if it works, as it seems it should. I tested this in Linux (Xubuntu) with Python 3.4. Note that many solutions for this problem don't work on Macs (since I've heard that __file__ is not present on Macs).
Note that if your script is a symbolic link, it will give you the path of the file it links to (and not the path of the symbolic link).
You can use Path from the pathlib module:
from pathlib import Path
# ...
Path(__file__)
You can use call to parent to go further in the path:
Path(__file__).parent
Simply add the following:
from sys import *
path_to_current_file = sys.argv[0]
print(path_to_current_file)
Or:
from sys import *
print(sys.argv[0])
If the code is coming from a file, you can get its full name
sys._getframe().f_code.co_filename
You can also retrieve the function name as f_code.co_name
The main idea is, somebody will run your python code, but you need to get the folder nearest the python file.
My solution is:
import os
print(os.path.dirname(os.path.abspath(__file__)))
With
os.path.dirname(os.path.abspath(__file__))
You can use it with to save photos, output files, ...etc
import os
current_file_path=os.path.dirname(os.path.realpath('__file__'))

Python: Using multiprocessing when the function called is dependent on a file

I have a very old fortran file, which is too complex for me to convert into python. So I have to compile the file and run it via python.
For the fortran file to work it requires 3 input values on 3 lines from the mobcal.run file. They are as follows:
line 1 - Name of file to run
line 2 - Name of output file
line 3 - random seed number
I change the input values per worker in the run() function.
When I run my script (see below), only 2 output file were created, but all 32 processers were running which i found out via the top command
I'm guessing the issue is here, is that there was not enough time to change the mobcal.run file for each worker.
The only solution I have come up with so far is to put a time.sleep(random.randint(1,100)) at the beginning of the run() function. But I dont find this solution very elegant and may not always work as two workers may have the same random.randint, is there a more pythonic way to solve this?
def run(mfj_file):
import shutil
import random
import subprocess
#shutil.copy('./mfj_files/%s' % mfj_file, './')
print 'Calculating cross sections for: %s' % mfj_file[:-4]
with open('mobcal.run', 'w') as outf:
outf.write(mfj_file+'\n'+mfj_file[:-4]+'.out\n'+str(random.randint(5000000,6000000)))
ccs = subprocess.Popen(['./a.out'])
ccs.wait()
shutil.move('./'+mfj_file[:-4]+'.out', './results/%s.out' % mfj_file[:-4])
def mobcal_multi_cpu():
from multiprocessing import Pool
import os
import shutil
mfj_list = os.listdir('./mfj_files/')
for f in mfj_list:
shutil.copy('./mfj_files/'+f, './')
if __name__ == '__main__':
pool = Pool(processes=32)
pool.map(run,mfj_list)
mobcal_multi_cpu()
I assume your a.out looks in the current working directory for its mobcal.run. If you run each instance in it's own directory then each process can have it's own mobcal.run without clobbering the others. This isn't necessarily the most pythonic way but it's the most unixy.
import tempfile
import os
def run(mjf_file):
dir = tempfile.mkdtemp(dir=".")
os.chdir(dir)
# rest of function here
# create mobcal.run in current directory
# while changing references to other files from "./" to "../"
Create several directories, with one mobcal.run each, and run your fortran program into them instead.
If you need a sleep() in multiprocessing you are doing it wrong.

Categories

Resources