diff --git a/hy/cmdline.py b/hy/cmdline.py index f78008e..08f6c0b 100644 --- a/hy/cmdline.py +++ b/hy/cmdline.py @@ -229,13 +229,21 @@ def run_repl(hr=None, **kwargs): def run_icommand(source, **kwargs): - hr = HyREPL(**kwargs) if os.path.exists(source): + # Emulate Python cmdline behavior by setting `sys.path` relative + # to the executed file's location. + if sys.path[0] == '': + sys.path[0] = os.path.realpath(os.path.split(source)[0]) + else: + sys.path.insert(0, os.path.split(source)[0]) + with io.open(source, "r", encoding='utf-8') as f: source = f.read() filename = source else: filename = '' + + hr = HyREPL(**kwargs) hr.runsource(source, filename=filename, symbol='single') return run_repl(hr) @@ -333,9 +341,18 @@ def cmdline_handler(scriptname, argv): else: # User did "hy " + filename = options.args[0] + + # Emulate Python cmdline behavior by setting `sys.path` relative + # to the executed file's location. + if sys.path[0] == '': + sys.path[0] = os.path.realpath(os.path.split(filename)[0]) + else: + sys.path.insert(0, os.path.split(filename)[0]) + try: sys.argv = options.args - runpy.run_path(options.args[0], run_name='__main__') + runpy.run_path(filename, run_name='__main__') return 0 except FileNotFoundError as e: print("hy: Can't open file '{0}': [Errno {1}] {2}".format( diff --git a/tests/resources/relative_import.hy b/tests/resources/relative_import.hy new file mode 100644 index 0000000..65acc66 --- /dev/null +++ b/tests/resources/relative_import.hy @@ -0,0 +1,3 @@ +(import bin.printenv) +(import sys) +(print sys.path) diff --git a/tests/test_bin.py b/tests/test_bin.py index 8827fd6..e642f53 100644 --- a/tests/test_bin.py +++ b/tests/test_bin.py @@ -214,6 +214,10 @@ def test_bin_hy_icmd_file(): output, _ = run_cmd("hy -i resources/icmd_test_file.hy", "(ideas)") assert "Hy!" in output + file_relative_path = os.path.realpath(os.path.split('tests/resources/relative_import.hy')[0]) + + output, _ = run_cmd("hy -i tests/resources/relative_import.hy None") + assert file_relative_path in output def test_bin_hy_icmd_and_spy(): output, _ = run_cmd("hy -i \"(+ [] [])\" --spy", "(+ 1 1)") @@ -346,6 +350,20 @@ def test_bin_hy_file_main_file(): assert "This is a __main__.hy" in output +def test_bin_hy_file_sys_path(): + """The test resource `relative_import.hy` will perform an absolute import + of a module in its directory: a directory that is not on the `sys.path` of + the script executing the module (i.e. `hy`). We want to make sure that Hy + adopts the file's location in `sys.path`, instead of the runner's current + dir (e.g. '' in `sys.path`). + """ + file_path, _ = os.path.split('tests/resources/relative_import.hy') + file_relative_path = os.path.realpath(file_path) + + output, _ = run_cmd("hy tests/resources/relative_import.hy") + assert file_relative_path in output + + def test_bin_hy_module_main_args(): output, _ = run_cmd("hy -m tests.resources.bin.main test 123") assert "test" in output