Welcome, guest | Sign In | My Account | Store | Cart

This module allows one to create a command to call a Python function from the command line, and to call that function with arguments from the command line without using getopt or optparse

Python, 82 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
"""
PythonCall.py

PythonCall is a shortcut that allows a CLI command with arguments to call 
any function within a Python module with only two lines of plumbing code.

Usage
=====
* Add code below to bottom of Python module.
    if __name__ == "__main__":
        import sys, PythonCall
        PythonCall.PythonCall(sys.argv).execute()
        
* From command line or desktop shortcut, build a command of form:
    <pythonpath> <module> <function> <arg1 arg2 ...>
    Example: C:\Python25\python.exe C:\Dev\PyUtils\src\TextUtils.py xclip wrap 64
            
Notes
=====
* Called functions must expect args to be strings and do their own conversions.
* No argument checking or error-checking.
* In case of exception, PythonCall sends message to stderr.
* I often use this with text I pass in via the clipboard, which requires
  code to read and write the clipboard (not included here).

Tested with Windows; should work on other platforms.

Jack Trainor 2008
"""
import os, os.path
import sys
import types

class PythonCall(object):
    def __init__(self, sysArgs):
        try:
            self.function = None
            self.args = []
            self.modulePath = sysArgs[0]
            self.moduleDir, tail = os.path.split(self.modulePath)
            self.moduleName, ext = os.path.splitext(tail)
            __import__(self.moduleName)
            self.module = sys.modules[self.moduleName]
            if len(sysArgs) > 1:
                self.functionName = sysArgs[1]
                self.function = self.module.__dict__[self.functionName]
                self.args = sysArgs[2:] 
        except Exception, e:
            sys.stderr.write("%s %s\n" % ("PythonCall#__init__", e))

    def execute(self):
        try:
            if self.function:
                self.function(*self.args)
        except Exception, e:
            sys.stderr.write("%s %s\n" % ("PythonCall#execute", e))
            
            
#####################################################
# Test Examples - REMOVE
#
# Normally the function calls are in a module other than PythonCall. 
# These are only examples.
#
# Example 1: C:\Python25\python.exe C:\Dev\PyUtils\src\PythonCall.py double 14
# Example 2: C:\Python25\python.exe C:\Dev\PyUtils\src\PythonCall.py capitalize "Four score and seven years ago..."
#####################################################

def double(x):
    x = int(x)
    print 2 * x

def capitalize(s):
    print s.upper()

if __name__ == "__main__":
    import sys, PythonCall
    PythonCall.PythonCall(sys.argv).execute()

#####################################################
# End - REMOVE
#####################################################

I wanted a quick, flexible way to create commands or Windows shortcuts that would call my Python functions without having to add getopt or optparse parsing sections to the bottom of my Python source.

I mostly use this code with to process text in and out of the clipboard (such as wrap to a number of columns) by double-clicking on a desktop shortcut.

(This is a big improvement to an earlier version of this recipe which included an extra function and was harder to follow.)

1 comment

Jack Trainor (author) 16 years, 7 months ago  # | flag

Fixed a bug, added some testing. Coerced args in getCommand to strings. Added the testing section at bottom of module to show how Passer and PythonCall work.