Commit 6b4990f6 authored by Kirill Smelkov's avatar Kirill Smelkov

gpython: Fix pymain to properly setup sys.path[0]

Pymain was not adding e.g. directory of executed file to sys.path, and
as the result if there were e.g. 2 files

	dir/hello.py	# imports world
	dir/world.py

running `gpython dir/hello.py` would fail to import world.

The case for interactive console was also failing to setup sys.argv as
empty, so it was containing ['/path/to/gpython']. It was also, contrary
to standard python, unconditionally showing '>>>' prompt even when stdin
was not a tty.

Fix all that and add a test to cover pymain functionality.
parent 411bdd7d
include COPYING README.rst CHANGELOG.rst tox.ini include COPYING README.rst CHANGELOG.rst tox.ini
recursive-include golang/testdata *.py recursive-include golang/testdata *.py
recursive-include gpython/testdata *.py
...@@ -43,15 +43,37 @@ from __future__ import print_function ...@@ -43,15 +43,37 @@ from __future__ import print_function
# argv is what comes via `...` without first [0] for python. # argv is what comes via `...` without first [0] for python.
def pymain(argv): def pymain(argv):
import sys, code, runpy, six import sys, code, runpy, six
from os.path import dirname
from six.moves import input as raw_input
# interactive console # interactive console
if not argv: if not argv:
code.interact() sys.argv = ['']
sys.path.insert(0, '') # cwd
# like code.interact() but with overridden console.raw_input _and_
# readline imported (code.interact mutually excludes those two).
try:
import readline # enable interactive editing
except ImportError:
pass
console = code.InteractiveConsole()
def _(prompt):
# python behaviour: don't print '>>>' if stdin is not a tty
# (builtin raw_input always prints prompt)
if not sys.stdin.isatty():
prompt=''
return raw_input(prompt)
console.raw_input = _
console.interact()
return return
# -c command # -c command
if argv[0] == '-c': if argv[0] == '-c':
sys.argv = argv[0:1] + argv[2:] # python leaves '-c' as argv[0] sys.argv = argv[0:1] + argv[2:] # python leaves '-c' as argv[0]
sys.path.insert(0, '') # cwd
# exec with the same globals `python -c ...` does # exec with the same globals `python -c ...` does
g = {'__name__': '__main__', g = {'__name__': '__main__',
...@@ -63,7 +85,9 @@ def pymain(argv): ...@@ -63,7 +85,9 @@ def pymain(argv):
elif argv[0] == '-m': elif argv[0] == '-m':
# search sys.path for module and run corresponding .py file as script # search sys.path for module and run corresponding .py file as script
sys.argv = argv[1:] sys.argv = argv[1:]
runpy.run_module(sys.argv[0], init_globals={'__doc__': None}, run_name='__main__') sys.path.insert(0, '') # cwd
runpy.run_module(sys.argv[0], init_globals={'__doc__': None},
run_name='__main__', alter_sys=True)
elif argv[0].startswith('-'): elif argv[0].startswith('-'):
print("unknown option: '%s'" % argv[0], file=sys.stderr) print("unknown option: '%s'" % argv[0], file=sys.stderr)
...@@ -73,6 +97,7 @@ def pymain(argv): ...@@ -73,6 +97,7 @@ def pymain(argv):
else: else:
sys.argv = argv sys.argv = argv
filepath = argv[0] filepath = argv[0]
sys.path.insert(0, dirname(filepath))
# exec with same globals `python file.py` does # exec with same globals `python file.py` does
# XXX use runpy.run_path() instead? # XXX use runpy.run_path() instead?
......
...@@ -81,11 +81,53 @@ def test_gevent_activated(): ...@@ -81,11 +81,53 @@ def test_gevent_activated():
if sys.hexversion >= 0x03070000: # >= 3.7.0 if sys.hexversion >= 0x03070000: # >= 3.7.0
assert patched('queue') assert patched('queue')
# pyrun runs `sys.executable argv... <stdin` and returns its output.
def pyrun(argv, stdin=None, **kw):
from subprocess import Popen, PIPE
argv = [sys.executable] + argv
p = Popen(argv, stdin=(PIPE if stdin else None), stdout=PIPE, stderr=PIPE, **kw)
stdout, stderr = p.communicate(stdin)
if p.returncode:
raise RuntimeError(' '.join(argv) + '\n' + (stderr and str(stderr) or '(failed)'))
return stdout
@gpython_only @gpython_only
def test_executable(): def test_executable():
# sys.executable must point to gpython and we must be able to execute it. # sys.executable must point to gpython and we must be able to execute it.
assert 'gpython' in sys.executable assert 'gpython' in sys.executable
out = subprocess.check_output([sys.executable, '-c', 'import sys; print(sys.version)']) out = pyrun(['-c', 'import sys; print(sys.version)'])
assert ('[GPython %s]' % golang.__version__) in str(out) assert ('[GPython %s]' % golang.__version__) in str(out)
# TODO test_pymain (it is not gpython_only) # b converts s to UTF-8 encoded bytes.
def b(s):
from golang.strconv import _bstr
s, _ = _bstr(s)
return s
# verify pymain.
#
# !gpython_only to make sure we get the same output when run via pymain (under
# gpython) and plain python (!gpython).
def test_pymain():
from os.path import join, dirname, realpath
here = dirname(__file__)
testdata = join(dirname(__file__), 'testdata')
# interactive
_ = pyrun([], stdin=b'import hello\n', cwd=testdata)
assert _ == b"hello\nworld\n['']\n"
# -c
_ = pyrun(['-c', 'import hello', 'abc', 'def'], cwd=testdata)
assert _ == b"hello\nworld\n['-c', 'abc', 'def']\n"
# -m
_ = pyrun(['-m', 'hello', 'abc', 'def'], cwd=testdata)
# realpath rewrites e.g. `local/lib -> lib` if local/lib is symlink
hellopy = realpath(join(testdata, 'hello.py'))
assert _ == b"hello\nworld\n['%s', 'abc', 'def']\n" % b(hellopy)
# file
_ = pyrun(['testdata/hello.py', 'abc', 'def'], cwd=here)
assert _ == b"hello\nworld\n['testdata/hello.py', 'abc', 'def']\n"
print('hello')
# imports should be resolved relative to main py file
import world
# sys.argv
import sys
print(sys.argv)
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