diff options
author | Raymond Hettinger <python@rcn.com> | 2004-10-07 06:46:25 (GMT) |
---|---|---|
committer | Raymond Hettinger <python@rcn.com> | 2004-10-07 06:46:25 (GMT) |
commit | db29e0fe8cab58c68d1263487ba5bac7b99c7612 (patch) | |
tree | 8ca6ad43fa5c3b9878ccf022f7161be0b6ba8b5e | |
parent | fb09f0e85cd75ec46700562687a9da3063ff0b7c (diff) | |
download | cpython-db29e0fe8cab58c68d1263487ba5bac7b99c7612.zip cpython-db29e0fe8cab58c68d1263487ba5bac7b99c7612.tar.gz cpython-db29e0fe8cab58c68d1263487ba5bac7b99c7612.tar.bz2 |
SF patch #1035498: -m option to run a module as a script
(Contributed by Nick Coghlan.)
-rw-r--r-- | Doc/tut/tut.tex | 13 | ||||
-rw-r--r-- | Include/import.h | 4 | ||||
-rw-r--r-- | Misc/NEWS | 7 | ||||
-rw-r--r-- | Modules/main.c | 80 | ||||
-rw-r--r-- | Python/import.c | 16 |
5 files changed, 109 insertions, 11 deletions
diff --git a/Doc/tut/tut.tex b/Doc/tut/tut.tex index 9cb665a..ba0e3fd 100644 --- a/Doc/tut/tut.tex +++ b/Doc/tut/tut.tex @@ -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}} diff --git a/Include/import.h b/Include/import.h index c2c869e..9f1c2be 100644 --- a/Include/import.h +++ b/Include/import.h @@ -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 *); @@ -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 ------- diff --git a/Modules/main.c b/Modules/main.c index bc543a4..1005b94 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -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; diff --git a/Python/import.c b/Python/import.c index 8f81d6e..75c6d3e 100644 --- a/Python/import.c +++ b/Python/import.c @@ -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 |