]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
SF patch #1035498: -m option to run a module as a script
authorRaymond Hettinger <python@rcn.com>
Thu, 7 Oct 2004 06:46:25 +0000 (06:46 +0000)
committerRaymond Hettinger <python@rcn.com>
Thu, 7 Oct 2004 06:46:25 +0000 (06:46 +0000)
(Contributed by Nick Coghlan.)

Doc/tut/tut.tex
Include/import.h
Misc/NEWS
Modules/main.c
Python/import.c

index 9cb665abc1fcc23251adea4933bcd6d7b54632dd..ba0e3fd59bfc37b8b88bfba60ec4854d3f21da02 100644 (file)
@@ -205,6 +205,11 @@ executes the statement(s) in \var{command}, analogous to the shell's
 or other characters that are special to the shell, it is best to quote 
 \var{command} in its entirety with double quotes.
 
+Some Python modules are also useful as scripts.  These can be invoked using
+\samp{\program{python} \programopt{-m} \var{module} [arg] ...}, which
+executes the source file for \var{module} as if you had spelled out its
+full name on the command line.
+
 Note that there is a difference between \samp{python file} and
 \samp{python <file}.  In the latter case, input requests from the
 program, such as calls to \function{input()} and \function{raw_input()}, are
@@ -229,9 +234,11 @@ one; when no script and no arguments are given, \code{sys.argv[0]} is
 an empty string.  When the script name is given as \code{'-'} (meaning 
 standard input), \code{sys.argv[0]} is set to \code{'-'}.  When
 \programopt{-c} \var{command} is used, \code{sys.argv[0]} is set to
-\code{'-c'}.  Options found after \programopt{-c} \var{command} are
-not consumed by the Python interpreter's option processing but left in
-\code{sys.argv} for the command to handle.
+\code{'-c'}.  When \programopt{-m} \var{module} is used, \code{sys.argv[0]} 
+is set to the full name of the located module.  Options found after 
+\programopt{-c} \var{command} or \programopt{-m} \var{module} are not consumed 
+by the Python interpreter's option processing but left in \code{sys.argv} for 
+the command or module to handle.
 
 \subsection{Interactive Mode \label{interactive}}
 
index c2c869e496e57ab7791d9b9087e47782c4aef124..9f1c2be24a662694f1d893858d3ffdb0ab797176 100644 (file)
@@ -21,6 +21,10 @@ PyAPI_FUNC(PyObject *) PyImport_ReloadModule(PyObject *m);
 PyAPI_FUNC(void) PyImport_Cleanup(void);
 PyAPI_FUNC(int) PyImport_ImportFrozenModule(char *);
 
+PyAPI_FUNC(struct filedescr *) _PyImport_FindModule(
+       const char *, PyObject *, char *, size_t, FILE **, PyObject **);
+PyAPI_FUNC(int) _PyImport_IsScript(struct filedescr *);
+
 PyAPI_FUNC(PyObject *)_PyImport_FindExtension(char *, char *);
 PyAPI_FUNC(PyObject *)_PyImport_FixupExtension(char *, char *);
 
index 81db100b53b12df79060b1e05ea9fc3af905be20..9e5477eb75c35c7f9882a3b0561558921f2ec528 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 2.4 beta 1?
 Core and builtins
 -----------------
 
+- Added a command line option, -m module, which searches sys.path for the
+  module and then runs it.  (Contributed by Nick Coghlan.)
+
 - The bytecode optimizer now folds tuples of constants into a single
   constant.
 
@@ -29,7 +32,9 @@ Extension modules
 
 - ``collections.deque`` objects didn't play quite right with garbage
   collection, which could lead to a segfault in a release build, or
-  an assert failure in a debug build.
+  an assert failure in a debug build.  Also, added overflow checks,
+  better detection of mutation during iteration, and shielded deque
+  comparisons from unusual subclass overrides of the __iter__() method.
 
 Library
 -------
index bc543a4cac83734663dd1ce31936853baff99792..1005b94e224935641a3e789bb1766144fecf8725 100644 (file)
@@ -3,6 +3,7 @@
 #include "Python.h"
 #include "osdefs.h"
 #include "compile.h" /* For CO_FUTURE_DIVISION */
+#include "import.h"
 
 #ifdef __VMS
 #include <unixlib.h>
@@ -33,7 +34,7 @@ static char **orig_argv;
 static int  orig_argc;
 
 /* command line options */
-#define BASE_OPTS "c:dEhiOQ:StuUvVW:xX"
+#define BASE_OPTS "c:dEhim:OQ:StuUvVW:xX"
 
 #ifndef RISCOS
 #define PROGRAM_OPTS BASE_OPTS
@@ -47,7 +48,7 @@ extern int Py_RISCOSWimpFlag;
 
 /* Short usage message (with %s for argv0) */
 static char *usage_line =
-"usage: %s [option] ... [-c cmd | file | -] [arg] ...\n";
+"usage: %s [option] ... [-c cmd | -m mod | file | -] [arg] ...\n";
 
 /* Long usage message, split into parts < 512 bytes */
 static char *usage_1 = "\
@@ -60,15 +61,16 @@ Options and arguments (and corresponding environment variables):\n\
          and force prompts, even if stdin does not appear to be a terminal\n\
 ";
 static char *usage_2 = "\
+-m mod : run library module as a script (terminates option list)\n\
 -O     : optimize generated bytecode (a tad; also PYTHONOPTIMIZE=x)\n\
 -OO    : remove doc-strings in addition to the -O optimizations\n\
 -Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew\n\
 -S     : don't imply 'import site' on initialization\n\
 -t     : issue warnings about inconsistent tab usage (-tt: issue errors)\n\
 -u     : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x)\n\
-         see man page for details on internal buffering relating to '-u'\n\
 ";
 static char *usage_3 = "\
+         see man page for details on internal buffering relating to '-u'\n\
 -v     : verbose (trace import statements) (also PYTHONVERBOSE=x)\n\
 -V     : print the Python version number and exit\n\
 -W arg : warning control (arg is action:message:category:module:lineno)\n\
@@ -130,6 +132,28 @@ static void RunStartupFile(PyCompilerFlags *cf)
        }
 }
 
+/* Get the path to a top-level module */
+static struct filedescr * FindModule(const char *module,
+                                    FILE **fp, char **filename)
+{
+       struct filedescr *fdescr = NULL;
+       *fp = NULL;
+       *filename = malloc(MAXPATHLEN);
+
+       if (*filename == NULL)
+               return NULL;
+
+       /* Find the actual module source code */
+       fdescr = _PyImport_FindModule(module, NULL,
+                                       *filename, MAXPATHLEN, fp, NULL);
+
+       if (fdescr == NULL) {
+               free(*filename);
+               *filename = NULL;
+       }
+
+       return fdescr;
+}
 
 /* Main program */
 
@@ -140,6 +164,7 @@ Py_Main(int argc, char **argv)
        int sts;
        char *command = NULL;
        char *filename = NULL;
+       char *module = NULL;
        FILE *fp = stdin;
        char *p;
        int inspect = 0;
@@ -177,6 +202,18 @@ Py_Main(int argc, char **argv)
                        break;
                }
 
+               if (c == 'm') {
+                       /* -m is the last option; following arguments
+                          that look like options are left for the
+                          module to interpret. */
+                       module = malloc(strlen(_PyOS_optarg) + 2);
+                       if (module == NULL)
+                               Py_FatalError(
+                                  "not enough memory to copy -m argument");
+                       strcpy(module, _PyOS_optarg);
+                       break;
+               }
+
                switch (c) {
 
                case 'd':
@@ -289,7 +326,7 @@ Py_Main(int argc, char **argv)
            (p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0')
                unbuffered = 1;
 
-       if (command == NULL && _PyOS_optind < argc &&
+       if (command == NULL && module == NULL && _PyOS_optind < argc &&
            strcmp(argv[_PyOS_optind], "-") != 0)
        {
 #ifdef __VMS
@@ -381,7 +418,7 @@ Py_Main(int argc, char **argv)
        Py_Initialize();
 
        if (Py_VerboseFlag ||
-           (command == NULL && filename == NULL && stdin_is_interactive)) {
+           (command == NULL && filename == NULL && module == NULL && stdin_is_interactive)) {
                fprintf(stderr, "Python %s on %s\n",
                        Py_GetVersion(), Py_GetPlatform());
                if (!Py_NoSiteFlag)
@@ -394,9 +431,34 @@ Py_Main(int argc, char **argv)
                argv[_PyOS_optind] = "-c";
        }
 
+       if (module != NULL) {
+               /* Backup _PyOS_optind and find the real file */
+                struct filedescr *fdescr = NULL;
+               _PyOS_optind--;
+               if ((fdescr = FindModule(module, &fp, &filename))) {
+                       argv[_PyOS_optind] = filename;
+               } else {
+                       fprintf(stderr, "%s: module %s not found\n",
+                               argv[0], module);
+                       return 2;
+               }
+               if (!fp) {
+                       fprintf(stderr,
+                               "%s: module %s has no associated file\n",
+                               argv[0], module);
+                       return 2;
+               }
+               if (!_PyImport_IsScript(fdescr)) {
+                       fprintf(stderr,
+                               "%s: module %s not usable as script\n  (%s)\n",
+                               argv[0], module, filename);
+                       return 2;
+               }
+       }
+
        PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind);
 
-       if ((inspect || (command == NULL && filename == NULL)) &&
+       if ((inspect || (command == NULL && filename == NULL && module == NULL)) &&
            isatty(fileno(stdin))) {
                PyObject *v;
                v = PyImport_ImportModule("readline");
@@ -409,6 +471,10 @@ Py_Main(int argc, char **argv)
        if (command) {
                sts = PyRun_SimpleStringFlags(command, &cf) != 0;
                free(command);
+       } else if (module) {
+               sts = PyRun_AnyFileExFlags(fp, filename, 1, &cf) != 0;
+               free(module);
+               free(filename);
        }
        else {
                if (filename == NULL && stdin_is_interactive) {
@@ -431,7 +497,7 @@ Py_Main(int argc, char **argv)
        }
 
        if (inspect && stdin_is_interactive &&
-           (filename != NULL || command != NULL))
+           (filename != NULL || command != NULL || module != NULL))
                /* XXX */
                sts = PyRun_AnyFileFlags(stdin, "<stdin>", &cf) != 0;
 
index 8f81d6ef8e1bc751579075cddf3382701507e668..75c6d3e93ba56ea5c0770379c83574af42e2edc1 100644 (file)
@@ -1334,6 +1334,22 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf,
        return fdp;
 }
 
+/* Helpers for main.c
+ *  Find the source file corresponding to a named module
+ */
+struct filedescr *
+_PyImport_FindModule(const char *name, PyObject *path, char *buf,
+           size_t buflen, FILE **p_fp, PyObject **p_loader)
+{
+       return find_module((char *) name, (char *) name, path,
+                          buf, buflen, p_fp, p_loader);
+}
+
+PyAPI_FUNC(int) _PyImport_IsScript(struct filedescr * fd)
+{
+       return fd->type == PY_SOURCE || fd->type == PY_COMPILED;
+}
+
 /* case_ok(char* buf, int len, int namelen, char* name)
  * The arguments here are tricky, best shown by example:
  *    /a/b/c/d/e/f/g/h/i/j/k/some_long_module_name.py\0