Skip to content

Commit 9583cac

Browse files
committed
Issue #10089: Add support for arbitrary -X options on the command-line.
They can be retrieved through a new attribute `sys._xoptions`.
1 parent 6d61cb4 commit 9583cac

File tree

10 files changed

+136
-14
lines changed

10 files changed

+136
-14
lines changed

Doc/c-api/sys.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,21 @@ accessible to C code. They all work with the current interpreter thread's
127127
128128
.. versionadded:: 3.2
129129
130+
.. c:function:: void PySys_AddXOption(const wchar_t *s)
131+
132+
Parse *s* as a set of :option:`-X` options and add them to the current
133+
options mapping as returned by :c:func:`PySys_GetXOptions`.
134+
135+
.. versionadded:: 3.2
136+
137+
.. c:function:: PyObject *PySys_GetXOptions()
138+
139+
Return the current dictionary of :option:`-X` options, similarly to
140+
:data:`sys._xoptions`. On error, *NULL* is returned and an exception is
141+
set.
142+
143+
.. versionadded:: 3.2
144+
130145
131146
.. _processcontrol:
132147

Doc/data/refcounts.dat

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,13 +1305,18 @@ PyString_AsEncodedString:const char*:errors::
13051305
PySys_AddWarnOption:void:::
13061306
PySys_AddWarnOption:char*:s::
13071307

1308+
PySys_AddXOption:void:::
1309+
PySys_AddXOption:const wchar_t*:s::
1310+
13081311
PySys_GetFile:FILE*:::
13091312
PySys_GetFile:char*:name::
13101313
PySys_GetFile:FILE*:def::
13111314

13121315
PySys_GetObject:PyObject*::0:
13131316
PySys_GetObject:char*:name::
13141317

1318+
PySys_GetXOptions:PyObject*::0:
1319+
13151320
PySys_SetArgv:int:::
13161321
PySys_SetArgv:int:argc::
13171322
PySys_SetArgv:char**:argv::

Doc/library/sys.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,30 @@ always available.
975975
module for informational purposes; modifying this value has no effect on the
976976
registry keys used by Python. Availability: Windows.
977977

978+
979+
.. data:: _xoptions
980+
981+
A dictionary of the various implementation-specific flags passed through
982+
the :option:`-X` command-line option. Option names are either mapped to
983+
their values, if given explicitly, or to :const:`True`. Example::
984+
985+
$ ./python -Xa=b -Xc
986+
Python 3.2a3+ (py3k, Oct 16 2010, 20:14:50)
987+
[GCC 4.4.3] on linux2
988+
Type "help", "copyright", "credits" or "license" for more information.
989+
>>> import sys
990+
>>> sys._xoptions
991+
{'a': 'b', 'c': True}
992+
993+
.. impl-detail::
994+
995+
This is a CPython-specific way of accessing options passed through
996+
:option:`-X`. Other implementations may export them through other
997+
means, or not at all.
998+
999+
.. versionadded:: 3.2
1000+
1001+
9781002
.. rubric:: Citations
9791003

9801004
.. [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 .

Doc/using/cmdline.rst

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,17 @@ Miscellaneous options
321321

322322
.. note:: The line numbers in error messages will be off by one.
323323

324+
325+
.. cmdoption:: -X
326+
327+
Reserved for various implementation-specific options. CPython currently
328+
defines none of them, but allows to pass arbitrary values and retrieve
329+
them through the :data:`sys._xoptions` dictionary.
330+
331+
.. versionchanged:: 3.2
332+
It is now allowed to pass :option:`-X` with CPython.
333+
334+
324335
Options you shouldn't use
325336
~~~~~~~~~~~~~~~~~~~~~~~~~
326337

@@ -330,11 +341,6 @@ Options you shouldn't use
330341

331342
.. _Jython: http://jython.org
332343

333-
.. cmdoption:: -X
334-
335-
Reserved for alternative implementations of Python to use for their own
336-
purposes.
337-
338344
.. _using-on-envvars:
339345

340346
Environment variables

Include/sysmodule.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ PyAPI_FUNC(void) PySys_AddWarnOption(const wchar_t *);
2727
PyAPI_FUNC(void) PySys_AddWarnOptionUnicode(PyObject *);
2828
PyAPI_FUNC(int) PySys_HasWarnOptions(void);
2929

30+
PyAPI_FUNC(void) PySys_AddXOption(const wchar_t *);
31+
PyAPI_FUNC(PyObject *) PySys_GetXOptions(void);
32+
3033
#ifdef __cplusplus
3134
}
3235
#endif

Lib/test/test_cmd_line.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ def test_verbose(self):
6767
rc, out, err = assert_python_ok('-vv')
6868
self.assertNotIn(b'stack overflow', err)
6969

70+
def test_xoptions(self):
71+
rc, out, err = assert_python_ok('-c', 'import sys; print(sys._xoptions)')
72+
opts = eval(out.splitlines()[0])
73+
self.assertEqual(opts, {})
74+
rc, out, err = assert_python_ok(
75+
'-Xa', '-Xb=c,d=e', '-c', 'import sys; print(sys._xoptions)')
76+
opts = eval(out.splitlines()[0])
77+
self.assertEqual(opts, {'a': True, 'b': 'c,d=e'})
78+
7079
def test_run_module(self):
7180
# Test expected operation of the '-m' switch
7281
# Switch needs an argument

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 3.2 Beta 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #10089: Add support for arbitrary -X options on the command-line.
14+
They can be retrieved through a new attribute ``sys._xoptions``.
15+
1316
- Issue #4388: On Mac OS X, decode command line arguments from UTF-8, instead
1417
of the locale encoding. If the LANG (and LC_ALL and LC_CTYPE) environment
1518
variable is not set, the locale encoding is ISO-8859-1, whereas most programs

Modules/main.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ static wchar_t **orig_argv;
4747
static int orig_argc;
4848

4949
/* command line options */
50-
#define BASE_OPTS L"bBc:dEhiJm:OsStuvVW:xX?"
50+
#define BASE_OPTS L"bBc:dEhiJm:OsStuvVW:xX:?"
5151

5252
#define PROGRAM_OPTS BASE_OPTS
5353

@@ -84,6 +84,7 @@ static char *usage_3 = "\
8484
-W arg : warning control; arg is action:message:category:module:lineno\n\
8585
also PYTHONWARNINGS=arg\n\
8686
-x : skip first line of source, allowing use of non-Unix forms of #!cmd\n\
87+
-X opt : set implementation-specific option\n\
8788
";
8889
static char *usage_4 = "\
8990
file : program read from script file\n\
@@ -407,8 +408,6 @@ Py_Main(int argc, wchar_t **argv)
407408
skipfirstline = 1;
408409
break;
409410

410-
/* case 'X': reserved for implementation-specific arguments */
411-
412411
case 'h':
413412
case '?':
414413
help++;
@@ -422,6 +421,10 @@ Py_Main(int argc, wchar_t **argv)
422421
PySys_AddWarnOption(_PyOS_optarg);
423422
break;
424423

424+
case 'X':
425+
PySys_AddXOption(_PyOS_optarg);
426+
break;
427+
425428
/* This space reserved for other options */
426429

427430
default:

Python/getopt.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,6 @@ int _PyOS_GetOpt(int argc, wchar_t **argv, wchar_t *optstring)
8989
return '_';
9090
}
9191

92-
if (option == 'X') {
93-
fprintf(stderr,
94-
"-X is reserved for implementation-specific arguments\n");
95-
return '_';
96-
}
97-
9892
if ((ptr = wcschr(optstring, option)) == NULL) {
9993
if (_PyOS_opterr)
10094
fprintf(stderr, "Unknown option: -%c\n", (char)option);

Python/sysmodule.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,61 @@ PySys_HasWarnOptions(void)
10861086
return (warnoptions != NULL && (PyList_Size(warnoptions) > 0)) ? 1 : 0;
10871087
}
10881088

1089+
static PyObject *xoptions = NULL;
1090+
1091+
static PyObject *
1092+
get_xoptions(void)
1093+
{
1094+
if (xoptions == NULL || !PyDict_Check(xoptions)) {
1095+
Py_XDECREF(xoptions);
1096+
xoptions = PyDict_New();
1097+
}
1098+
return xoptions;
1099+
}
1100+
1101+
void
1102+
PySys_AddXOption(const wchar_t *s)
1103+
{
1104+
PyObject *opts;
1105+
PyObject *name = NULL, *value = NULL;
1106+
const wchar_t *name_end;
1107+
int r;
1108+
1109+
opts = get_xoptions();
1110+
if (opts == NULL)
1111+
goto error;
1112+
1113+
name_end = wcschr(s, L'=');
1114+
if (!name_end) {
1115+
name = PyUnicode_FromWideChar(s, -1);
1116+
value = Py_True;
1117+
Py_INCREF(value);
1118+
}
1119+
else {
1120+
name = PyUnicode_FromWideChar(s, name_end - s);
1121+
value = PyUnicode_FromWideChar(name_end + 1, -1);
1122+
}
1123+
if (name == NULL || value == NULL)
1124+
goto error;
1125+
r = PyDict_SetItem(opts, name, value);
1126+
Py_DECREF(name);
1127+
Py_DECREF(value);
1128+
return;
1129+
1130+
error:
1131+
Py_XDECREF(name);
1132+
Py_XDECREF(value);
1133+
/* No return value, therefore clear error state if possible */
1134+
if (_Py_atomic_load_relaxed(&_PyThreadState_Current))
1135+
PyErr_Clear();
1136+
}
1137+
1138+
PyObject *
1139+
PySys_GetXOptions(void)
1140+
{
1141+
return get_xoptions();
1142+
}
1143+
10891144
/* XXX This doc string is too long to be a single string literal in VC++ 5.0.
10901145
Two literals concatenated works just fine. If you have a K&R compiler
10911146
or other abomination that however *does* understand longer strings,
@@ -1535,6 +1590,11 @@ _PySys_Init(void)
15351590
PyDict_SetItemString(sysdict, "warnoptions", warnoptions);
15361591
}
15371592

1593+
v = get_xoptions();
1594+
if (v != NULL) {
1595+
PyDict_SetItemString(sysdict, "_xoptions", v);
1596+
}
1597+
15381598
/* version_info */
15391599
if (VersionInfoType.tp_name == 0)
15401600
PyStructSequence_InitType(&VersionInfoType, &version_info_desc);

0 commit comments

Comments
 (0)