1

I am trying to write a Python code to interact with another software that uses command line prompts. Once the command line prompt is executed, multiple output files are generated in the directory and the software uses those output files to do some calculations. Plus, the rest of my program utilizes those output files. Currently, I run my python code, then manually enter in the command line prompt, then call the rest of my code and that works fine, however when I attempted to put:

subprocess.call(['sfit4Layer0.py', '-bv5', '-fs'], shell=False)

into my file, it does not execute properly (the output files are not generated).

When I made the above code it's own individual python code and called it immediately after the first part of my code - it also worked.

According to my output, I am convinced that the problem is this: the call generated multiple files and then uses those files to make calculations, however, it is not generating the proper files so I get errors in my output. So in a way it seems like it is getting ahead of itself: not waiting for the output files to be produced before making calculations, but again, it works when I run this command separately outside of the program. Any ideas on why this would happen?

What am I doing wrong? Do I need to specify the directory (could the output files be put somewhere else in my computer)? Do I need to use subprocess.Popen ? I have searched the internet but I am new(ish) to Python and thoroughly stumped.

Any suggestions welcome. Thanks!

EDIT: for those who asked, here is the sfit4Layer0.py code:

#! /usr/bin/python
##! /usr/local/python-2.7/bin/python
##! /usr/bin/python
##! /usr/bin/python
# Change the above line to point to the location of your python executable
#----------------------------------------------------------------------------------------
# Name:
#        sfit4Layer0.py
#
# Purpose:
#       This file is the zeroth order running of sfit4. It accomplishes the following:
#           1) Calls pspec to convert binary spectra file (bnr) to ascii (t15asc)
#           2) Calls hbin to gather line parameters from hitran
#           3) Calls sfit4
#           4) Calls error analysis from Layer1mods.py
#           5) Clean outputs from sfit4 call
#
#
# External Subprocess Calls:
#           1) pspec executable file from pspec.f90
#           2) hbin  executable file from hbin.f90
#           3) sfit4 executable file from sfit4.f90
#                       4) errAnalysis from Layer1mods.py
#
#
#
# Notes:
#   1) Options include:
#            -i <dir>     : Optional. Data directory. Default is current working directory
#            -b     <dir/str> : Optional. Binary directory. Default is hard-code.
#            -f <str>     : Run flags, h = hbin, p = pspec, s = sfit4, e = error analysis, c = clean
#
#
# Usage:
#       ./sfit4Layer0.py [options]
#
#
# Examples:
#       1) This example runs hbin, pspec, sfit4, error analys, and cleans working directory prior to execution
#           ./sfit4Layer0.py -f hpsec
#
#       2) This example just runs sfit4
#           ./sfit4Layer0.py -f s
#
#       3) This example cleans the output file created by sfit4 in directory (/User/home/datafiles/) which is not the current directory
#          ./sfit4Layer0.py -i /User/home/datafiles/ -f c
#
# Version History:
#       Created, May, 2013  Eric Nussbaumer (ebaumer@ucar.edu)
#
#
# License:
#    Copyright (c) 2013-2014 NDACC/IRWG
#    This file is part of sfit4.
#
#    sfit4 is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    any later version.
#
#    sfit4 is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with sfit4.  If not, see <http://www.gnu.org/licenses/>
#
#----------------------------------------------------------------------------------------


#---------------
# Import modules
#---------------
import sys
import os
import getopt
import sfitClasses as sc
from Layer1Mods import errAnalysis
from Tkinter import Tk
from tkFileDialog import askopenfilename


#------------------------
# Define helper functions
#------------------------
def usage(binDirVer):
        print 'sfit4Layer0.py -f <str> [-i <dir> [-b <dir/str> ] \n'
        print '-i <dir>     Data directory. Optional: default is current working directory'
        print '-f <str>     Run Flags: Necessary: h = hbin, p = pspec, s = sfit4, e = error analysis, c = clean'
        print '-b <dir/str> Binary sfit directory. Optional: default is hard-coded in main(). Also accepts v1, v2, etc.'
        for ver in binDirVer:
                print '             {}: {}'.format(ver,binDirVer[ver])        

        sys.exit()


def main(argv):

        #----------------
        # Initializations
        #----------------
         #------------
         # Directories
         #------------
        wrkDir    = os.getcwd()                              # Set current directory as the data directory
        binDir    = '/data/bin'                              # Default binary directory. Used of nothing is specified on command line
        binDirVer = {
        'v1':   '/data/ebaumer/Code/sfit-core-code/src/',    # Version 1 for binary directory (Eric)
        'v2':   '/data/tools/400/sfit-core/src/',             # Version 2 for binary directory (Jim)
        'v3':   '/Users/jamesw/FDP/sfit/400/sfit-core/src/',             # Version 2 for binary directory (Jim)
        'v4':   '/home/ebaumer/Code/sfit4/src/',
        'v5':   '/Users/allisondavis/Documents/Summer2016/sfit4_0.9.4.3/src'
        }


         #----------
         # Run flags
         #----------
        hbinFlg  = False                                          # Flag to run hbin
        pspecFlg = False                                          # Flag to run pspec
        sfitFlg  = False                                          # Flag to run sfit4
        errFlg   = False                                          # Flag to run error analysis
        clnFlg   = False                                          # Flag to clean directory of output files listed in ctl file

        #--------------------------------
        # Retrieve command line arguments
        #--------------------------------
        try:
                opts, args = getopt.getopt(sys.argv[1:], 'i:b:f:?')

        except getopt.GetoptError as err:
                print str(err)
                usage(binDirVer)
                sys.exit()

        #-----------------------------
        # Parse command line arguments
        #-----------------------------
        for opt, arg in opts:
                # Data directory
                if opt == '-i':
                        wrkDir = arg
                        sc.ckDir(wrkDir,exitFlg=True)

                # Binary directory
                elif opt == '-b':
                        if not sc.ckDir(arg,exitFlg=False,quietFlg=True):
                                try:             binDir = binDirVer[arg.lower()]
                                except KeyError: print '{} not a recognized version for -b option'.format(arg); sys.exit()

                        else: binDir = arg

                        if not(binDir.endswith('/')): binDir = binDir + '/'

                # Run flags
                elif opt == '-f':
                        flgs = list(arg)
                        for f in flgs:
                                if   f.lower() == 'h': hbinFlg  = True
                                elif f.lower() == 'p': pspecFlg = True
                                elif f.lower() == 's': sfitFlg  = True
                                elif f.lower() == 'e': errFlg   = True
                                elif f.lower() == 'c': clnFile  = True
                                else: print '{} not an option for -f ... ignored'.format(f)
                elif opt == '-?':
                        usage(binDirVer)
                        sys.exit()                        

                else:
                        print 'Unhandled option: {}'.format(opt)
                        sys.exit()

        #--------------------------------------
        # If necessary change working directory
        # to directory with input data.
        #--------------------------------------
        if os.path.abspath(wrkDir) != os.getcwd(): os.chdir(wrkDir)
        if not(wrkDir.endswith('/')): wrkDir = wrkDir + '/'

        #--------------------------
        # Initialize sfit ctl class
        #--------------------------
        ctlFileName = wrkDir + 'sfit4.ctl'
        if sc.ckFile(wrkDir+'sfit4.ctl'): ctlFileName = wrkDir + 'sfit4.ctl'
        else:
                Tk().withdraw()
                ctlFileName = askopenfilename(initialdir=wrkDir,message='Please select sfit ctl file')

        ctlFile = sc.CtlInputFile(ctlFileName)
        ctlFile.getInputs()

        #------------------------
        # Initialize sb ctl class
        #------------------------
        if errFlg:
                if sc.ckFile(wrkDir+'sb.ctl'): sbCtlFileName = wrkDir + 'sb.ctl'
                else:
                        TK().withdraw()
                        sbCtlFileName = askopenfilename(initialdir=wrkDir,message='Please select sb ctl file')

                sbCtlFile = sc.CtlInputFile(sbCtlFileName)
                sbCtlFile.getInputs()

        #---------------------------
        # Clean up output from sfit4
        #---------------------------
        if clnFlg:
                for k in ctlFile.inputs['file.out']:
                        if 'file.out' in k:
                                try:            os.remove(wrkDir + ctlFile.inputs[k])
                                except OSError: pass

        #----------
        # Run pspec
        #----------
        if pspecFlg:
                print '*************'
                print 'Running pspec'
                print '*************'
                rtn = sc.subProcRun( [binDir + 'pspec'] )

        #----------
        # Run hbin
        #----------
        if hbinFlg:
                print '************'
                print 'Running hbin'
                print '************'
                rtn = sc.subProcRun( [binDir + 'hbin'] )

        #----------
        # Run sfit4
        #----------
        if sfitFlg:
                print '************'
                print 'Running sfit'
                print '************'
                rtn = sc.subProcRun( [binDir + 'sfit4'] )

        #-------------------
        # Run error analysis
        #-------------------
        if errFlg:
                print '**********************'
                print 'Running error analysis'
                print '**********************'
                rtn = errAnalysis(ctlFile,sbCtlFile,wrkDir)



if __name__ == "__main__":
        main(sys.argv[1:])
alli
  • 105
  • 3
  • 13
  • Have you check if a program do not attempt to open a file while it is still open in another one if they are running at the same time ? – lu1her Jul 26 '16 at 15:57
  • how do I check this? or allow it to do this? that's what I think may be the problem – alli Jul 26 '16 at 16:05
  • It depend of the behavior of your programs, if they just use the files one time make sure to `file.close()` before open it in a different program, but if you have to check simultaniously the same file in different programs I advise you to use shared memory technique – lu1her Jul 26 '16 at 16:10
  • @lu1her I really appreciate your help - do you happen to have a link to some information on this? – alli Jul 26 '16 at 16:19
  • Does the program change the current working directory? You could `print('os.getcwd())` just before you run the command. – tdelaney Jul 26 '16 at 17:25
  • If you control the called program, you can add trace messages to see where its writing the files. – tdelaney Jul 26 '16 at 17:26
  • That call is correct so the problem is elsewhere in your code... and we can only guess about that. You could delete old versions of the output files and see if new versions show up after execution. Is this stuff run from the command line? Is there any error text from the called program? – tdelaney Jul 26 '16 at 17:37
  • I had it print the directory before and after each call and it remained the same so that's not the problem. The error message I am getting states that there are no valid values for 3 variables which are supposed to be read from one of the output files. And I can see that the output files are not being produced (I always delete them after generating them to test my code). Is subprocess supposed to work just like the command line? Bc like I said - it works if I manually write it in after 1st part of my code or make it it's own Python program and execute right after 1st part of code... – alli Jul 26 '16 at 17:49
  • I do not know good tutorials in python about this but here is the documentation with some examples https://docs.python.org/2/library/multiprocessing.html – lu1her Jul 27 '16 at 07:16

3 Answers3

0

give this a try: subprocess.call('sfit4Layer0.py -bv5 -fs', shell=True)

Q-man
  • 2,069
  • 1
  • 17
  • 16
0

If you are trying to call another python script from your python script the subprocess.call() method is suited for your operation.

I would suggest you to turn

subprocess.call(['sfit4Layer0.py', '-bv5', '-fs'], shell=True)

Hope this solution works.

Popen is generally used when you want to pipe the STDIN/STDOUT or STDERR from one process to another.

Also when ever you write files make sure you create file or directory paths as absolute paths, this will help you in placing the file always on your desired location.

Happy Coding.

Varad
  • 920
  • 10
  • 25
0
subprocess.call(['sfit4Layer0.py', '-bv5', '-fs'], shell=False)
  1. assumes that sfit4Layer0.py is executable, which it may not be
  2. assumes that sfit4Layer0.py includes the #!/usr/bin/python shebang, which it may not.

if the script does contain a shebang and is not executable Try:

subprocess.call(['python','/path/to/script/sfit4Layer0.py','-bv5','-fs'], shell=False)

if the script is executable and contains the shebang Try:

subprocess.call(['/path/to/script/sfit4Layer0.py -bv5 -fs'], shell=True)
Rolf of Saxony
  • 21,661
  • 5
  • 39
  • 60
  • neither of these worked :/ according to my output, I am convinced that the problem is this: the call generated multiple files and then uses those files to make calculations, however, it is not generating the proper files so I get errors in my output. So in a way it seems like it is getting ahead of itself: not waiting for the output files to be produced before making calculations, but again, it works when I run this command separately outside of the program. Any ideas on why this would happen? – alli Jul 26 '16 at 17:26
  • In that case use Popen().wait without seeing the code in your called script it's difficult to say. See:http://stackoverflow.com/questions/15107714/wait-process-untill-all-subprocess-finish – Rolf of Saxony Jul 26 '16 at 17:46
  • Have you tried printing debugging codes to watch the progress of what is going on in the called script. Print is one hell of a debugging tool. – Rolf of Saxony Jul 26 '16 at 17:54
  • interestingly enough when I do p = subprocess.call(['sfit4Layer0.py', '-bv5', '-fs'], shell=False) # I think this writes the summary file p.wait() I get the error "AttributeError: 'int' object has no attribute 'wait'" ... is subprocess.call supposed to be an int value? – alli Jul 26 '16 at 18:07
  • You didn't read that link I gave you! subprocess.Popen(....).wait is not subprocess.call(). Post the code of sfit4Layer0.py. Without it we're pissing in the wind. – Rolf of Saxony Jul 27 '16 at 06:52