diff --git a/Lib/_dummy_os.py b/Lib/_dummy_os.py index dae80cbc4..5bd5ec0a1 100644 --- a/Lib/_dummy_os.py +++ b/Lib/_dummy_os.py @@ -7,12 +7,13 @@ try: except ImportError: import abc - # this will throw an appropriate error if os isn't available and a module - # tries to use an os function. If os has become available, then this will - # just work. def __getattr__(name): - import os - return getattr(os, name) + raise OSError("no os specific module found") + + def _shim(): + import _dummy_os, sys + sys.modules['os'] = _dummy_os + sys.modules['os.path'] = _dummy_os.path import posixpath as path import sys diff --git a/Lib/linecache.py b/Lib/linecache.py index 47885bfd5..bb09280d6 100644 --- a/Lib/linecache.py +++ b/Lib/linecache.py @@ -7,7 +7,10 @@ that name. import functools import sys -import os +try: + import os +except ImportError: + import _dummy_os as os import tokenize __all__ = ["getline", "clearcache", "checkcache"] diff --git a/wasm/demo/snippets/import_pypi.py b/wasm/demo/snippets/import_pypi.py index 9acf3d513..cbe837cd0 100644 --- a/wasm/demo/snippets/import_pypi.py +++ b/wasm/demo/snippets/import_pypi.py @@ -1,19 +1,17 @@ import asyncweb -import pypimport +import whlimport -pypimport.setup() +whlimport.setup() -# shim path utilities into the "os" module -class os: - import posixpath as path -import sys -sys.modules['os'] = os -sys.modules['os.path'] = os.path -del sys, os +# make sys.modules['os'] a dumb version of the os module, which has posixpath +# available as os.path as well as a few other utilities, but will raise an +# OSError for anything that actually requires an OS +import _dummy_os +_dummy_os._shim() @asyncweb.main async def main(): - await pypimport.load_package("pygments") + await whlimport.load_package("pygments") import pygments import pygments.lexers import pygments.formatters.html diff --git a/wasm/demo/src/browser_module.rs b/wasm/demo/src/browser_module.rs new file mode 100644 index 000000000..e69de29bb diff --git a/wasm/lib/Lib/asyncweb.py b/wasm/lib/Lib/asyncweb.py index 034a39cc7..e1039efce 100644 --- a/wasm/lib/Lib/asyncweb.py +++ b/wasm/lib/Lib/asyncweb.py @@ -48,51 +48,16 @@ def main(async_func): async def _main_wrapper(coro): try: await coro - except BaseException as e: - for line in _format_exc(e, 1): - print(line) - - -# TODO: get traceback/linecache working in wasm - - -def _format_exc(exc, skip_tb=0): - exc_type, exc_value, exc_traceback = type(exc), exc, exc.__traceback__ - - _str = _some_str(exc_value) - - yield "Traceback (most recent call last):" - tb = exc_traceback - while tb: - if skip_tb: - skip_tb -= 1 - else: - co = tb.tb_frame.f_code - yield f' File "{co.co_filename}", line {tb.tb_lineno}, in {co.co_name}' - tb = tb.tb_next - - stype = exc_type.__qualname__ - smod = exc_type.__module__ - if smod not in ("__main__", "builtins"): - stype = smod + "." + stype - - yield _format_final_exc_line(stype, _str) - - -def _format_final_exc_line(etype, value): - valuestr = _some_str(value) - if value is None or not valuestr: - line = "%s" % etype - else: - line = "%s: %s" % (etype, valuestr) - return line - - -def _some_str(value): - try: - return str(value) except: - return "" % type(value).__name__ + try: + import traceback, sys + traceback.print_exc(file=sys.stdout) + except BaseException as e: + tb = e.__traceback__ + while tb: + print(tb.tb_lineno, tb.tb_frame.f_code.co_name, tb.tb_frame.f_code.co_filename) + tb = tb.tb_next + print(type(e), e) def _resolve(prom): diff --git a/wasm/lib/Lib/whlimport.py b/wasm/lib/Lib/whlimport.py index e58fb733d..033a885c7 100644 --- a/wasm/lib/Lib/whlimport.py +++ b/wasm/lib/Lib/whlimport.py @@ -73,14 +73,27 @@ class WheelFinder: return None @classmethod - def exec_module(cls, module): - origin = module.__spec__.origin + def get_source(cls, fullname): + spec = cls.find_spec(fullname) + if spec: + return cls._get_source(spec) + else: + raise ImportError('cannot find source for module', name=fullname) + + @classmethod + def _get_source(cls, spec): + origin = spec.origin if not origin or not origin.startswith("wheel:"): raise ImportError(f'{module.__spec__.name!r} is not a zip module') zipname, slash, path = origin[len('wheel:'):].partition('/') - source = cls._packages[zipname].read(path) - code = _bootstrap._call_with_frames_removed(compile, source, origin, 'exec', dont_inherit=True) + return cls._packages[zipname].read(path).decode() + + @classmethod + def exec_module(cls, module): + spec = module.__spec__ + source = cls._get_source(spec) + code = _bootstrap._call_with_frames_removed(compile, source, spec.origin, 'exec', dont_inherit=True) _bootstrap._call_with_frames_removed(exec, code, module.__dict__)