|
1 | 1 | import os
|
2 | 2 | import subprocess
|
3 | 3 | import sys
|
| 4 | +import tempfile |
4 | 5 | import unittest
|
| 6 | +from pathlib import Path |
5 | 7 | from typing import Iterable
|
6 | 8 |
|
7 | 9 | from python import runfiles
|
|
13 | 15 | EXPECT_TEST_MODULE_IMPORTABLE = os.environ["EXPECT_TEST_MODULE_IMPORTABLE"] == "1"
|
14 | 16 |
|
15 | 17 |
|
| 18 | +# An arbitrary piece of code that sets some kind of variable. The variable needs to persist into the |
| 19 | +# actual shell. |
| 20 | +PYTHONSTARTUP_SETS_VAR = """\ |
| 21 | +foo = 1234 |
| 22 | +""" |
| 23 | + |
| 24 | + |
16 | 25 | class ReplTest(unittest.TestCase):
|
17 | 26 | def setUp(self):
|
18 | 27 | self.repl = rfiles.Rlocation("rules_python/python/bin/repl")
|
19 | 28 | assert self.repl
|
20 | 29 |
|
21 |
| - def run_code_in_repl(self, lines: Iterable[str]) -> str: |
| 30 | + def run_code_in_repl(self, lines: Iterable[str], *, env=None) -> str: |
22 | 31 | """Runs the lines of code in the REPL and returns the text output."""
|
23 | 32 | return subprocess.check_output(
|
24 | 33 | [self.repl],
|
25 | 34 | text=True,
|
26 | 35 | stderr=subprocess.STDOUT,
|
27 | 36 | input="\n".join(lines),
|
| 37 | + env=env, |
28 | 38 | ).strip()
|
29 | 39 |
|
30 | 40 | def test_repl_version(self):
|
@@ -69,6 +79,44 @@ def test_import_test_module_failure(self):
|
69 | 79 | )
|
70 | 80 | self.assertIn("ModuleNotFoundError: No module named 'test_module'", result)
|
71 | 81 |
|
| 82 | + def test_pythonstartup_gets_executed(self): |
| 83 | + """Validates that we can use the variables from PYTHONSTARTUP in the console itself.""" |
| 84 | + with tempfile.TemporaryDirectory() as tempdir: |
| 85 | + pythonstartup = Path(tempdir) / "pythonstartup.py" |
| 86 | + pythonstartup.write_text(PYTHONSTARTUP_SETS_VAR) |
| 87 | + |
| 88 | + env = os.environ.copy() |
| 89 | + env["PYTHONSTARTUP"] = str(pythonstartup) |
| 90 | + |
| 91 | + result = self.run_code_in_repl( |
| 92 | + [ |
| 93 | + "print(f'The value of foo is {foo}')", |
| 94 | + ], |
| 95 | + env=env, |
| 96 | + ) |
| 97 | + |
| 98 | + self.assertIn("The value of foo is 1234", result) |
| 99 | + |
| 100 | + def test_pythonstartup_doesnt_leak(self): |
| 101 | + """Validates that we don't accidentally leak code into the console. |
| 102 | +
|
| 103 | + This test validates that a few of the variables we use in the template and stub are not |
| 104 | + accessible in the REPL itself. |
| 105 | + """ |
| 106 | + with tempfile.TemporaryDirectory() as tempdir: |
| 107 | + pythonstartup = Path(tempdir) / "pythonstartup.py" |
| 108 | + pythonstartup.write_text(PYTHONSTARTUP_SETS_VAR) |
| 109 | + |
| 110 | + env = os.environ.copy() |
| 111 | + env["PYTHONSTARTUP"] = str(pythonstartup) |
| 112 | + |
| 113 | + for var_name in ("exitmsg", "sys", "code", "bazel_runfiles", "STUB_PATH"): |
| 114 | + with self.subTest(var_name=var_name): |
| 115 | + result = self.run_code_in_repl([f"print({var_name})"], env=env) |
| 116 | + self.assertIn( |
| 117 | + f"NameError: name '{var_name}' is not defined", result |
| 118 | + ) |
| 119 | + |
72 | 120 |
|
73 | 121 | if __name__ == "__main__":
|
74 | 122 | unittest.main()
|
0 commit comments