From 9583cac6337f9a5f2670fbe5e1f2e85aaad04522 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Thu, 21 Oct 2010 13:42:28 +0000 Subject: [PATCH] Issue #10089: Add support for arbitrary -X options on the command-line. They can be retrieved through a new attribute `sys._xoptions`. --- Doc/c-api/sys.rst | 15 ++++++++++ Doc/data/refcounts.dat | 5 ++++ Doc/library/sys.rst | 24 ++++++++++++++++ Doc/using/cmdline.rst | 16 +++++++---- Include/sysmodule.h | 3 ++ Lib/test/test_cmd_line.py | 9 ++++++ Misc/NEWS | 3 ++ Modules/main.c | 9 ++++-- Python/getopt.c | 6 ---- Python/sysmodule.c | 60 +++++++++++++++++++++++++++++++++++++++ 10 files changed, 136 insertions(+), 14 deletions(-) diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst index 232cec032e8..252bd1ad060 100644 --- a/Doc/c-api/sys.rst +++ b/Doc/c-api/sys.rst @@ -127,6 +127,21 @@ accessible to C code. They all work with the current interpreter thread's .. versionadded:: 3.2 +.. c:function:: void PySys_AddXOption(const wchar_t *s) + + Parse *s* as a set of :option:`-X` options and add them to the current + options mapping as returned by :c:func:`PySys_GetXOptions`. + + .. versionadded:: 3.2 + +.. c:function:: PyObject *PySys_GetXOptions() + + Return the current dictionary of :option:`-X` options, similarly to + :data:`sys._xoptions`. On error, *NULL* is returned and an exception is + set. + + .. versionadded:: 3.2 + .. _processcontrol: diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat index 2dc7084297a..f2a87670dbd 100644 --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -1305,6 +1305,9 @@ PyString_AsEncodedString:const char*:errors:: PySys_AddWarnOption:void::: PySys_AddWarnOption:char*:s:: +PySys_AddXOption:void::: +PySys_AddXOption:const wchar_t*:s:: + PySys_GetFile:FILE*::: PySys_GetFile:char*:name:: PySys_GetFile:FILE*:def:: @@ -1312,6 +1315,8 @@ PySys_GetFile:FILE*:def:: PySys_GetObject:PyObject*::0: PySys_GetObject:char*:name:: +PySys_GetXOptions:PyObject*::0: + PySys_SetArgv:int::: PySys_SetArgv:int:argc:: PySys_SetArgv:char**:argv:: diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 23fdb09d39c..bf8e0d01642 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -975,6 +975,30 @@ always available. module for informational purposes; modifying this value has no effect on the registry keys used by Python. Availability: Windows. + +.. data:: _xoptions + + A dictionary of the various implementation-specific flags passed through + the :option:`-X` command-line option. Option names are either mapped to + their values, if given explicitly, or to :const:`True`. Example:: + + $ ./python -Xa=b -Xc + Python 3.2a3+ (py3k, Oct 16 2010, 20:14:50) + [GCC 4.4.3] on linux2 + Type "help", "copyright", "credits" or "license" for more information. + >>> import sys + >>> sys._xoptions + {'a': 'b', 'c': True} + + .. impl-detail:: + + This is a CPython-specific way of accessing options passed through + :option:`-X`. Other implementations may export them through other + means, or not at all. + + .. versionadded:: 3.2 + + .. rubric:: Citations .. [C99] ISO/IEC 9899:1999. "Programming languages -- C." A public draft of this standard is available at http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf . diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 7da1954b25a..6f3cfbe2949 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -321,6 +321,17 @@ Miscellaneous options .. note:: The line numbers in error messages will be off by one. + +.. cmdoption:: -X + + Reserved for various implementation-specific options. CPython currently + defines none of them, but allows to pass arbitrary values and retrieve + them through the :data:`sys._xoptions` dictionary. + + .. versionchanged:: 3.2 + It is now allowed to pass :option:`-X` with CPython. + + Options you shouldn't use ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -330,11 +341,6 @@ Options you shouldn't use .. _Jython: http://jython.org -.. cmdoption:: -X - - Reserved for alternative implementations of Python to use for their own - purposes. - .. _using-on-envvars: Environment variables diff --git a/Include/sysmodule.h b/Include/sysmodule.h index e43f378f6e3..c00901b1798 100644 --- a/Include/sysmodule.h +++ b/Include/sysmodule.h @@ -27,6 +27,9 @@ PyAPI_FUNC(void) PySys_AddWarnOption(const wchar_t *); PyAPI_FUNC(void) PySys_AddWarnOptionUnicode(PyObject *); PyAPI_FUNC(int) PySys_HasWarnOptions(void); +PyAPI_FUNC(void) PySys_AddXOption(const wchar_t *); +PyAPI_FUNC(PyObject *) PySys_GetXOptions(void); + #ifdef __cplusplus } #endif diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index c864cdd4bb4..0ddc8131f68 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -67,6 +67,15 @@ class CmdLineTest(unittest.TestCase): rc, out, err = assert_python_ok('-vv') self.assertNotIn(b'stack overflow', err) + def test_xoptions(self): + rc, out, err = assert_python_ok('-c', 'import sys; print(sys._xoptions)') + opts = eval(out.splitlines()[0]) + self.assertEqual(opts, {}) + rc, out, err = assert_python_ok( + '-Xa', '-Xb=c,d=e', '-c', 'import sys; print(sys._xoptions)') + opts = eval(out.splitlines()[0]) + self.assertEqual(opts, {'a': True, 'b': 'c,d=e'}) + def test_run_module(self): # Test expected operation of the '-m' switch # Switch needs an argument diff --git a/Misc/NEWS b/Misc/NEWS index 265b88147e1..caf1b49a7d0 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 3.2 Beta 1? Core and Builtins ----------------- +- Issue #10089: Add support for arbitrary -X options on the command-line. + They can be retrieved through a new attribute ``sys._xoptions``. + - Issue #4388: On Mac OS X, decode command line arguments from UTF-8, instead of the locale encoding. If the LANG (and LC_ALL and LC_CTYPE) environment variable is not set, the locale encoding is ISO-8859-1, whereas most programs diff --git a/Modules/main.c b/Modules/main.c index 7df883c8bb7..008b6a4d10e 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -47,7 +47,7 @@ static wchar_t **orig_argv; static int orig_argc; /* command line options */ -#define BASE_OPTS L"bBc:dEhiJm:OsStuvVW:xX?" +#define BASE_OPTS L"bBc:dEhiJm:OsStuvVW:xX:?" #define PROGRAM_OPTS BASE_OPTS @@ -84,6 +84,7 @@ static char *usage_3 = "\ -W arg : warning control; arg is action:message:category:module:lineno\n\ also PYTHONWARNINGS=arg\n\ -x : skip first line of source, allowing use of non-Unix forms of #!cmd\n\ +-X opt : set implementation-specific option\n\ "; static char *usage_4 = "\ file : program read from script file\n\ @@ -407,8 +408,6 @@ Py_Main(int argc, wchar_t **argv) skipfirstline = 1; break; - /* case 'X': reserved for implementation-specific arguments */ - case 'h': case '?': help++; @@ -422,6 +421,10 @@ Py_Main(int argc, wchar_t **argv) PySys_AddWarnOption(_PyOS_optarg); break; + case 'X': + PySys_AddXOption(_PyOS_optarg); + break; + /* This space reserved for other options */ default: diff --git a/Python/getopt.c b/Python/getopt.c index 5147320af28..064a1874ea5 100644 --- a/Python/getopt.c +++ b/Python/getopt.c @@ -89,12 +89,6 @@ int _PyOS_GetOpt(int argc, wchar_t **argv, wchar_t *optstring) return '_'; } - if (option == 'X') { - fprintf(stderr, - "-X is reserved for implementation-specific arguments\n"); - return '_'; - } - if ((ptr = wcschr(optstring, option)) == NULL) { if (_PyOS_opterr) fprintf(stderr, "Unknown option: -%c\n", (char)option); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 033c9d5e564..2530cc07aac 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1086,6 +1086,61 @@ PySys_HasWarnOptions(void) return (warnoptions != NULL && (PyList_Size(warnoptions) > 0)) ? 1 : 0; } +static PyObject *xoptions = NULL; + +static PyObject * +get_xoptions(void) +{ + if (xoptions == NULL || !PyDict_Check(xoptions)) { + Py_XDECREF(xoptions); + xoptions = PyDict_New(); + } + return xoptions; +} + +void +PySys_AddXOption(const wchar_t *s) +{ + PyObject *opts; + PyObject *name = NULL, *value = NULL; + const wchar_t *name_end; + int r; + + opts = get_xoptions(); + if (opts == NULL) + goto error; + + name_end = wcschr(s, L'='); + if (!name_end) { + name = PyUnicode_FromWideChar(s, -1); + value = Py_True; + Py_INCREF(value); + } + else { + name = PyUnicode_FromWideChar(s, name_end - s); + value = PyUnicode_FromWideChar(name_end + 1, -1); + } + if (name == NULL || value == NULL) + goto error; + r = PyDict_SetItem(opts, name, value); + Py_DECREF(name); + Py_DECREF(value); + return; + +error: + Py_XDECREF(name); + Py_XDECREF(value); + /* No return value, therefore clear error state if possible */ + if (_Py_atomic_load_relaxed(&_PyThreadState_Current)) + PyErr_Clear(); +} + +PyObject * +PySys_GetXOptions(void) +{ + return get_xoptions(); +} + /* XXX This doc string is too long to be a single string literal in VC++ 5.0. Two literals concatenated works just fine. If you have a K&R compiler or other abomination that however *does* understand longer strings, @@ -1535,6 +1590,11 @@ _PySys_Init(void) PyDict_SetItemString(sysdict, "warnoptions", warnoptions); } + v = get_xoptions(); + if (v != NULL) { + PyDict_SetItemString(sysdict, "_xoptions", v); + } + /* version_info */ if (VersionInfoType.tp_name == 0) PyStructSequence_InitType(&VersionInfoType, &version_info_desc);