Commit 9eb579f4 authored by Kirill Smelkov's avatar Kirill Smelkov

gpython/pymain: -O, sys.executable, ...

- Teach gpython and pymain about `-`;
- Teach gpython and pymain about -O;
- Teach pymain to always set sys.executable, so that subprocess and multiprocessing work correctly out of the box;
- Fix ./bin/gpython crash;
- Rewrite options parsing via incremental getopt-like thing.

This changes are motivated by nexedi/slapos!862 (comment 121470) and nexedi/slapos!862 (comment 121600).

/reviewed-by @jerome
/reviewed-on nexedi/pygolang!10
parents 167912d3 840a5eae
This diff is collapsed.
...@@ -163,6 +163,10 @@ def test_pymain(): ...@@ -163,6 +163,10 @@ def test_pymain():
# interactive # interactive
_ = pyout([], stdin=b'import hello\n', cwd=testdata) _ = pyout([], stdin=b'import hello\n', cwd=testdata)
assert _ == b"hello\nworld\n['']\n" assert _ == b"hello\nworld\n['']\n"
_ = pyout(['-'], stdin=b'import hello\n', cwd=testdata)
assert _ == b"hello\nworld\n['-']\n"
_ = pyout(['-', 'zzz'], stdin=b'import hello\n', cwd=testdata)
assert _ == b"hello\nworld\n['-', 'zzz']\n"
# -c <command> # -c <command>
_ = pyout(['-c', 'import hello', 'abc', 'def'], cwd=testdata) _ = pyout(['-c', 'import hello', 'abc', 'def'], cwd=testdata)
...@@ -230,15 +234,12 @@ def test_pymain_syspath(): ...@@ -230,15 +234,12 @@ def test_pymain_syspath():
# check verifies that print_syspath output for gpython and underlying python is the same. # check verifies that print_syspath output for gpython and underlying python is the same.
# if path0cwd2realpath=Y, expect realpath('') instead of '' in sys.path[0] # if path0cwd2realpath=Y, expect realpath('') instead of '' in sys.path[0]
def check(argv, path0cwd2realpath=False, **kw): def check(argv, path0cwd2realpath=False, **kw):
gpyout = u(pyout(argv, **kw)) def _(gpyoutv, stdpyoutv):
stdpyout = u(pyout(argv, pyexe=sys._gpy_underlying_executable, **kw))
gpyoutv = gpyout.splitlines()
stdpyoutv = stdpyout.splitlines()
if path0cwd2realpath: if path0cwd2realpath:
assert stdpyoutv[0] == '' assert stdpyoutv[0] == ''
stdpyoutv[0] = realpath(kw.get('cwd', '')) stdpyoutv[0] = realpath(kw.get('cwd', ''))
assert gpyoutv == stdpyoutv check_gpy_vs_py(argv, postprocessf=_, **kw)
check([], stdin=b'import print_syspath', cwd=testprog) # interactive check([], stdin=b'import print_syspath', cwd=testprog) # interactive
check(['-c', 'import print_syspath'], cwd=testprog) # -c check(['-c', 'import print_syspath'], cwd=testprog) # -c
...@@ -246,6 +247,23 @@ def test_pymain_syspath(): ...@@ -246,6 +247,23 @@ def test_pymain_syspath():
path0cwd2realpath=(PY2 or is_pypy)) path0cwd2realpath=(PY2 or is_pypy))
check(['testprog/print_syspath.py'], cwd=here) # file check(['testprog/print_syspath.py'], cwd=here) # file
# verify that pymain handles -O in exactly the same was as underlying python does.
@gpython_only
def test_pymain_opt():
def check(argv):
argv += ["print_opt.py"]
kw = {'cwd': testprog}
check_gpy_vs_py(argv, **kw)
check([])
check(["-O"])
check(["-OO"])
check(["-OOO"])
check(["-O", "-O"])
check(["-O", "-O", "-O"])
# pymain -V/--version # pymain -V/--version
# gpython_only because output differs from !gpython. # gpython_only because output differs from !gpython.
@gpython_only @gpython_only
...@@ -274,6 +292,13 @@ def test_pymain_ver(runtime): ...@@ -274,6 +292,13 @@ def test_pymain_ver(runtime):
ret, out, err = _pyrun(['--version'], stdout=PIPE, stderr=PIPE, env=gpyenv(runtime)) ret, out, err = _pyrun(['--version'], stdout=PIPE, stderr=PIPE, env=gpyenv(runtime))
assert (ret, out, b(err)) == (0, b'', b(vok)) assert (ret, out, b(err)) == (0, b'', b(vok))
# verify that ./bin/gpython runs ok.
@gpython_only
def test_pymain_run_via_relpath():
argv = ['-c', 'import sys; print(sys.version)']
out1 = pyout( argv, pyexe=sys.executable)
out2 = pyout(['./__init__.py'] + argv, pyexe=sys._gpy_underlying_executable, cwd=here)
assert out1 == out2
# verify -X gpython.runtime=... # verify -X gpython.runtime=...
@gpython_only @gpython_only
...@@ -311,3 +336,15 @@ def grepv(pattern, text): # -> text ...@@ -311,3 +336,15 @@ def grepv(pattern, text): # -> text
if not m: if not m:
v.append(l) v.append(l)
return t.join(v) return t.join(v)
# check_gpy_vs_py verifies that gpython output matches underlying python output.
def check_gpy_vs_py(argv, postprocessf=None, **kw):
gpyout = u(pyout(argv, **kw))
stdpyout = u(pyout(argv, pyexe=sys._gpy_underlying_executable, **kw))
gpyoutv = gpyout.splitlines()
stdpyoutv = stdpyout.splitlines()
if postprocessf is not None:
postprocessf(gpyoutv, stdpyoutv)
assert gpyoutv == stdpyoutv
# -*- coding: utf-8 -*-
# Copyright (C) 2020 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_opt prints information about optimizations."""
from __future__ import print_function, absolute_import
import sys, os, os.path, tempfile, shutil
def main():
print('sys.flags.debug: %s' % sys.flags.debug)
print('sys.flags.optimize: %s' % sys.flags.optimize)
print('__debug__: %s' % __debug__)
print('assert: %s' % is_assert_enabled())
print('docstrings: %s' % is_docstrings_enabled())
print('import mod.py: %s' % modpy_imports_from())
# is_assert_enabled returns whether assert statements are enabled.
def is_assert_enabled():
try:
assert False # must raise AssertionError
except AssertionError:
return True
else:
return False
# is_docstrings_enabled returns whether docstrings are enabled.
def is_docstrings_enabled():
def _():
"""hello world"""
if _.__doc__ is None:
return False
if _.__doc__ == "hello world":
return True
raise AssertionError(_.__doc__)
# modpy returns name for compiled version of python module mod.py
def modpy_imports_from():
try:
import mod
except ImportError:
# ok - should not be there
pass
else:
raise AssertionError("module 'mod' is already there")
tmpd = tempfile.mkdtemp('', 'modpy_imports_from')
try:
pymod = "%s/mod.py" % tmpd
with open(pymod, "w") as f:
f.write("# hello up there\n")
sys.path.insert(0, tmpd)
import mod
files = set()
for dirpath, dirnames, filenames in os.walk(tmpd):
for _ in filenames:
f = '%s/%s' % (dirpath, _)
if f.startswith(tmpd+'/'):
f = f[len(tmpd+'/'):]
files.add(f)
files.remove("mod.py") # must be there | raises if not
if len(files) == 0:
from_ = "mod.py" # source-only import
else:
if len(files) != 1:
raise AssertionError("mod.py -> multiple compiled files (%s)" % (files,))
from_ = files.pop()
return from_
finally:
shutil.rmtree(tmpd)
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