mirror of https://github.com/pyodide/pyodide.git
Ensure `Console` is locked and prevent `formatted_traceback` being unexpectedly truncated (#4905)
Co-authored-by: Gyeongjae Choi <def6488@gmail.com>
This commit is contained in:
parent
5fb36a458b
commit
9428c6f69e
|
@ -50,6 +50,13 @@ myst:
|
||||||
in `CodeRunner` and `Console`.
|
in `CodeRunner` and `Console`.
|
||||||
{pr}`4897`
|
{pr}`4897`
|
||||||
|
|
||||||
|
- {{ Fix }} Fixed a bug that caused `Console`'s `formatted_traceback` being truncated
|
||||||
|
unexpectedly when `filename` is specified.
|
||||||
|
{pr}`4905`
|
||||||
|
|
||||||
|
- {{ Fix }} Locked `PyodideConsole.runcode` to block `loadPackagesFromImports`.
|
||||||
|
{pr}`4905`
|
||||||
|
|
||||||
### Packages
|
### Packages
|
||||||
|
|
||||||
- Upgraded `scikit-learn` to 1.5 {pr}`4823`
|
- Upgraded `scikit-learn` to 1.5 {pr}`4823`
|
||||||
|
|
|
@ -405,18 +405,21 @@ class Console:
|
||||||
res.set_result(fut.result())
|
res.set_result(fut.result())
|
||||||
res = None
|
res = None
|
||||||
|
|
||||||
ensure_future(self.runcode(source, code)).add_done_callback(done_cb)
|
ensure_future(self._runcode_with_lock(source, code)).add_done_callback(done_cb)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
async def _runcode_with_lock(self, source: str, code: CodeRunner) -> Any:
|
||||||
|
async with self._lock:
|
||||||
|
return await self.runcode(source, code)
|
||||||
|
|
||||||
async def runcode(self, source: str, code: CodeRunner) -> Any:
|
async def runcode(self, source: str, code: CodeRunner) -> Any:
|
||||||
"""Execute a code object and return the result."""
|
"""Execute a code object and return the result."""
|
||||||
async with self._lock:
|
with self.redirect_streams():
|
||||||
with self.redirect_streams():
|
try:
|
||||||
try:
|
return await code.run_async(self.globals)
|
||||||
return await code.run_async(self.globals)
|
finally:
|
||||||
finally:
|
sys.stdout.flush()
|
||||||
sys.stdout.flush()
|
sys.stderr.flush()
|
||||||
sys.stderr.flush()
|
|
||||||
|
|
||||||
def formatsyntaxerror(self, e: Exception) -> str:
|
def formatsyntaxerror(self, e: Exception) -> str:
|
||||||
"""Format the syntax error that just occurred.
|
"""Format the syntax error that just occurred.
|
||||||
|
@ -435,7 +438,7 @@ class Console:
|
||||||
kept_frames = 0
|
kept_frames = 0
|
||||||
# Try to trim out stack frames inside our code
|
# Try to trim out stack frames inside our code
|
||||||
for frame, _ in traceback.walk_tb(tb):
|
for frame, _ in traceback.walk_tb(tb):
|
||||||
keep_frames = keep_frames or frame.f_code.co_filename == "<console>"
|
keep_frames = keep_frames or frame.f_code.co_filename == self.filename
|
||||||
keep_frames = keep_frames or frame.f_code.co_filename == "<exec>"
|
keep_frames = keep_frames or frame.f_code.co_filename == "<exec>"
|
||||||
if keep_frames:
|
if keep_frames:
|
||||||
kept_frames += 1
|
kept_frames += 1
|
||||||
|
|
|
@ -288,6 +288,7 @@ def test_nonpersistent_redirection(safe_sys_redirections):
|
||||||
asyncio.run(test())
|
asyncio.run(test())
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
async def test_compile_optimize():
|
async def test_compile_optimize():
|
||||||
from pyodide.console import Console
|
from pyodide.console import Console
|
||||||
|
|
||||||
|
@ -300,6 +301,29 @@ async def test_compile_optimize():
|
||||||
assert await console.push("f.__doc__") is None
|
assert await console.push("f.__doc__") is None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_console_filename():
|
||||||
|
from pyodide.console import Console
|
||||||
|
|
||||||
|
for filename in ("<console>", "<exec>", "other"):
|
||||||
|
future = Console(filename=filename).push("assert 0")
|
||||||
|
with pytest.raises(AssertionError):
|
||||||
|
await future
|
||||||
|
assert isinstance(future.formatted_error, str)
|
||||||
|
assert f'File "{filename}", line 1, in <module>' in future.formatted_error
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip_refcount_check
|
||||||
|
@run_in_pyodide
|
||||||
|
async def test_pyodide_console_runcode_locked(selenium):
|
||||||
|
from pyodide.console import PyodideConsole
|
||||||
|
|
||||||
|
console = PyodideConsole()
|
||||||
|
|
||||||
|
console.push("import micropip")
|
||||||
|
await console.push("micropip")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip_refcount_check
|
@pytest.mark.skip_refcount_check
|
||||||
@run_in_pyodide
|
@run_in_pyodide
|
||||||
async def test_console_imports(selenium):
|
async def test_console_imports(selenium):
|
||||||
|
|
Loading…
Reference in New Issue