Commit b7d0f6b2 authored by Kirill Smelkov's avatar Kirill Smelkov

gpython: Implement -X for non-gpython options

We already handle -X gpython.* starting from a6b993c8 (gpython: Add way
to run it with threads runtime). However any other non-gpython -X option
was leading to failure - for example:

    (z-dev) kirr@deca:~/src/tools/go/pygolang$ gpython -X faulthandler
    unknown option: '-X'

(well the error message was also not good)

However on py3 there are useful -X options that might be handy to use,
for example `-X faulthandler` and `-X importtime`.

-> Add support to pymain to handle those via reexecuting underlying
   interpreter like we already do for -O and -E.

/reviewed-by @jerome
/reviewed-on nexedi/pygolang!30
parent 736143a5
...@@ -115,10 +115,21 @@ def pymain(argv, init=None): ...@@ -115,10 +115,21 @@ def pymain(argv, init=None):
if opt in ( if opt in (
'-E', # ignore $PYTHON* '-E', # ignore $PYTHON*
'-O', # optimize '-O', # optimize
'-X', # set implementation-specific option
): ):
reexec_with.append(opt)
if arg is not None: # but keep `-X gpython.*` in user part of argv in case of reexec
reexec_with.append(arg) # leaving it for main to handle. If it is only pymain to run, then
# we will be ignoring `-X gpython.*` which goes in line with builtin
# py3 behaviour to ignore any unknown -X option.
if opt == '-X' and arg is not None and arg.startswith('gpython.'):
reexec_argv.append(opt)
reexec_argv.append(arg)
else:
reexec_with.append(opt)
if arg is not None:
reexec_with.append(arg)
continue continue
reexec_argv.append(opt) reexec_argv.append(opt)
...@@ -382,33 +393,30 @@ def main(): ...@@ -382,33 +393,30 @@ def main():
# no harm wrt gevent monkey-patching even if we import os first. # no harm wrt gevent monkey-patching even if we import os first.
import os import os
# extract and process `-X gpython.*` # process `-X gpython.*`
# -X gpython.runtime=(gevent|threads) + $GPYTHON_RUNTIME # -X gpython.runtime=(gevent|threads) + $GPYTHON_RUNTIME
sys._xoptions = getattr(sys, '_xoptions', {}) sys._xoptions = getattr(sys, '_xoptions', {})
argv_ = []
gpy_runtime = os.getenv('GPYTHON_RUNTIME', 'gevent') gpy_runtime = os.getenv('GPYTHON_RUNTIME', 'gevent')
igetopt = _IGetOpt(sys.argv[1:], _pyopt, _pyopt_long) igetopt = _IGetOpt(sys.argv[1:], _pyopt, _pyopt_long)
for (opt, arg) in igetopt: for (opt, arg) in igetopt:
if opt == '-X': if opt == '-X':
if arg.startswith('gpython.'): # any non gpython -X option is handled by pymain; ignore them here
if arg.startswith('gpython.runtime='): if not arg.startswith('gpython.'):
gpy_runtime = arg[len('gpython.runtime='):] continue
sys._xoptions['gpython.runtime'] = gpy_runtime
else: if arg.startswith('gpython.runtime='):
raise RuntimeError('gpython: unknown -X option %s' % arg) gpy_runtime = arg[len('gpython.runtime='):]
sys._xoptions['gpython.runtime'] = gpy_runtime
continue else:
raise RuntimeError('gpython: unknown -X option %s' % arg)
argv_.append(opt) continue
if arg is not None:
argv_.append(arg)
# options after -c / -m are not for python itself # options after -c / -m are not for python itself
if opt in ('-c', '-m'): if opt in ('-c', '-m'):
break break
argv = [sys.argv[0]] + argv_ + igetopt.argv
# propagate those settings as defaults to subinterpreters, so that e.g. # propagate those settings as defaults to subinterpreters, so that e.g.
# sys.executable spawned from under `gpython -X gpython.runtime=threads` # sys.executable spawned from under `gpython -X gpython.runtime=threads`
...@@ -454,7 +462,7 @@ def main(): ...@@ -454,7 +462,7 @@ def main():
sys.version += (' [GPython %s] [%s]' % (golang.__version__, gpy_verextra)) sys.version += (' [GPython %s] [%s]' % (golang.__version__, gpy_verextra))
# tail to pymain # tail to pymain
pymain(argv, init) pymain(sys.argv, init)
# _is_buildout_script returns whether file @path is generated as python buildout script. # _is_buildout_script returns whether file @path is generated as python buildout script.
......
...@@ -338,6 +338,15 @@ def test_pymain_E(): ...@@ -338,6 +338,15 @@ def test_pymain_E():
assert sys_flags_optimize(1) not in gpyoutv assert sys_flags_optimize(1) not in gpyoutv
check_gpy_vs_py(['-E', 'testprog/print_opt.py'], _, envadj=envadj, cwd=here) check_gpy_vs_py(['-E', 'testprog/print_opt.py'], _, envadj=envadj, cwd=here)
# verify that pymain handles -X non-gpython-option in exactly the same way as underlying python does.
@pytest.mark.skipif(PY2, reason="-X does not work at all on plain cpython2")
@gpython_only
def test_pymain_X():
check_gpy_vs_py(['testprog/print_faulthandler.py'], cwd=here)
check_gpy_vs_py(['-X', 'faulthandler', 'testprog/print_faulthandler.py'], cwd=here)
# pymain -V/--version # pymain -V/--version
# gpython_only because output differs from !gpython. # gpython_only because output differs from !gpython.
@gpython_only @gpython_only
......
# -*- coding: utf-8 -*-
# Copyright (C) 2024 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
# the terms of any of the Free Software licenses or any of the Open Source
# Initiative approved licenses and Convey the resulting work. Corresponding
# source of such a combination shall include the source code for all other
# software used.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
"""Program print_faulthandler prints information about faulthandler settings."""
from __future__ import print_function, absolute_import
import sys
def main():
if 'faulthandler' not in sys.modules:
print('faulthandler is not imported')
return
fh = sys.modules['faulthandler']
print('faulthandler imported')
print('faulthandler %s' % ('enabled' if fh.is_enabled() else 'disabled'))
if __name__ == '__main__':
main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment