0

I have a number of scripts that reference a Python program via the:

python -c "execfile('myfile.py'); readFunc(param='myParam', input='blahblah')"

interface. What I'd like to do is conceptually simple: Develop a more modular system with a "main" and a normal Python CLI interface that then calls these functions, but also MAINTAINS the existing interface, so the scripts built to use it still work.

Is this possible?

Ideally, if I was to call

python myFile readFunc myParam blabblah

It'd be something like:

main(sys.argv):
     readFunc(sys.argv[2], sys.arg[3])

I've tried something like that, but it hasn't quite worked. Is it possible to keep both interfaces/methods of invocation?

Thanks!

user770901
  • 414
  • 1
  • 4
  • 15

2 Answers2

0

The first idea that comes to mind stems from the optional arguments to the execfile() function. You might be able to do something like this:

#!python
def main(args):
    results = do_stuff()
    return results

if __name__ == '__main__':
    import sys
    main(sys.argv[1:])

if __name__ == 'execfile':
    main(args)

... and then when you want to call it via execfile() you supply a dictionary for its optional globals argument:

#!sh
python -c 'execfile(myfile, {"__name__":"execfile", "args":(1,2,3)}); ...'

This does require a little extra work when you're calling your functionality via -c as you have to remember to pass that dictionary and over-ride '__name__' ... through I suppose you could actually use any valid Python identifier. It's just that __name__ is closest to what you're actually doing.

The next idea feels a little dirty but relies on the apparent handling of the __file__ global identifier. That seems to be unset when calling python -c and set if the file is being imported or executed. So this works (at least for CPython 2.7.9):

#!/usr/bin/env python
foo='foo'
if __name__ == '__main__' and '__file__' not in globals():
    print "Under -c:", foo

elif __name__ == '__main__':
    print "Executed standalone:", foo

... and if you use that please don't give me credit. It looks ...

... ... ummm ....

... just ...

.... WRONG

Jim Dennis
  • 17,054
  • 13
  • 68
  • 116
  • I should note that the string "execfile" for `__name__` here is completely arbitrary and you might even be better using a string that can never collide with the name of any module into which your code might ever be imported. Perhaps just '*' ... the literal asterisk string. – Jim Dennis Mar 10 '15 at 06:21
  • Yeah, the point is that the executing execfile interface needs to be persevered EXACTLY. If we're going to change it, we might as well abandon it completely and bring things to the 21st century anyway. I'll push for this, but there are a LOT of scripts build on that interface, so it would be best to do this in parallel right now. – user770901 Mar 10 '15 at 06:38
  • You might do something with `__name__` == `'__main__'` and `'__file__'` not in globals(). I'm adding a sample to my posting. – Jim Dennis Mar 10 '15 at 06:55
  • I've accepted this answer, although I doubt it does exactly what I want it to do. I appreciate the effort! The good news is that I've been told we can abandon the old interface, so thankfully this isn't an issue anymore! – user770901 Mar 12 '15 at 04:20
0

If I understand this one

python myFile readFunc myParam blabblah

correctly, you want to parse argv[1] as a command name to be executed.

So just do

if __name__ == '__main__':
    import sys
    if len(sys.argv) < 2 or sys.argv[1].lower() == 'nop' or sys.argv[0] == '-c': # old, legacy interface
        pass
    elif sys.argv[1].lower() == 'readfunc': # new one
        readFunc(sys.argv[2:])

where the 2nd part gets executed on a direct execution of the file (either via python file.py readFunc myParam blabblah or via python -m file readFunc myParam blabblah)

The "nop" / empty argv branch comes to play when using the "legacy" interface: in this case, you most probably have given no cmdline arguments and thus can assume that you don't want to execute anything.

This makes the situation as before: the readFunc identifier is exported and can be used from within the -c script as before.

glglgl
  • 89,107
  • 13
  • 149
  • 217