diff --git a/_quickjs.pyi b/_quickjs.pyi new file mode 100644 index 0000000..17b3cc9 --- /dev/null +++ b/_quickjs.pyi @@ -0,0 +1,32 @@ +from typing import Any, Callable, Literal + + +def test() -> Literal[1]: ... + +JSValue = None | bool | int | float | str | Object + +class Object(): + def json(self) -> str: ... + def __call__(self, *args: Any) -> Any: ... + +class Context: + def eval(self, code: str) -> JSValue: ... + def module(self, code: str) -> JSValue: ... + def execute_pending_job(self) -> bool: ... + def parse_json(self, data: str) -> JSValue: ... + def get(self, name: str) -> JSValue: ... + def set(self, name: str, item: JSValue) -> None: ... + def set_memory_limit(self, limit: int) -> None: ... + def set_time_limit(self, limit: int) -> None: ... + def set_max_stack_size(self, limit: int) -> None: ... + def memory(self) -> dict[str, int]: ... + def gc(self) -> None: ... + def add_callable(self, name: str, callable: Callable[..., Any]) -> None: ... + @property + def globalThis(self) -> Object: ... + +class JSException(Exception): + pass + +class StackOverflow(Exception): + pass diff --git a/module.c b/module.c index fba11c3..2a46433 100644 --- a/module.c +++ b/module.c @@ -642,7 +642,7 @@ static PyObject *runtime_set_max_stack_size(RuntimeData *self, PyObject *args) { // _quickjs.Context.memory // -// Sets the CPU time limit of the context. This will be used in an interrupt handler. +// Returns the memory usage as a dict. static PyObject *runtime_memory(RuntimeData *self) { PyObject *dict = PyDict_New(); if (dict == NULL) { diff --git a/pyproject.toml b/pyproject.toml index 61bed85..8791ba3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ description = "Python wrapper around https://bellard.org/quickjs/" authors = ["Petter Strandmark"] [tool.poetry.dependencies] -python = ">=3.6" +python = ">=3.7" [tool.poetry.dev-dependencies] yapf = "*" diff --git a/quickjs/__init__.py b/quickjs/__init__.py index 4285999..1106441 100644 --- a/quickjs/__init__.py +++ b/quickjs/__init__.py @@ -1,7 +1,7 @@ import concurrent.futures import json import threading -from typing import Tuple, Callable +from typing import Any, Tuple, Callable import _quickjs @@ -21,8 +21,8 @@ class Function: # same runtime, even if it is not at the same time. So we run everything on the same thread in # order to prevent this. _threadpool = concurrent.futures.ThreadPoolExecutor(max_workers=1) - - def __init__(self, name: str, code: str, *, own_executor=False) -> None: + + def __init__(self, name: str, code: str, *, own_executor: bool = False) -> None: """ Arguments: name: The name of the function in the provided code that will be executed. @@ -39,21 +39,21 @@ def __init__(self, name: str, code: str, *, own_executor=False) -> None: concurrent.futures.wait([future]) self._context, self._f = future.result() - def __call__(self, *args, run_gc=True): + def __call__(self, *args: Any, run_gc: bool = True) -> Any: with self._lock: future = self._threadpool.submit(self._call, *args, run_gc=run_gc) concurrent.futures.wait([future]) return future.result() - def set_memory_limit(self, limit): + def set_memory_limit(self, limit: int): with self._lock: return self._context.set_memory_limit(limit) - def set_time_limit(self, limit): + def set_time_limit(self, limit: int): with self._lock: return self._context.set_time_limit(limit) - def set_max_stack_size(self, limit): + def set_max_stack_size(self, limit: int): with self._lock: return self._context.set_max_stack_size(limit) @@ -61,7 +61,7 @@ def memory(self): with self._lock: return self._context.memory() - def add_callable(self, global_name: str, callable: Callable) -> None: + def add_callable(self, global_name: str, callable: Callable[..., Any]) -> None: with self._lock: self._context.add_callable(global_name, callable) @@ -86,10 +86,11 @@ def _compile(self, name: str, code: str) -> Tuple[Context, Object]: context = Context() context.eval(code) f = context.get(name) + assert isinstance(f, Object) return context, f - def _call(self, *args, run_gc=True): - def convert_arg(arg): + def _call(self, *args: Any, run_gc: bool = True): + def convert_arg(arg: Any): if isinstance(arg, (type(None), str, bool, float, int)): return arg else: @@ -99,7 +100,7 @@ def convert_arg(arg): try: result = self._f(*[convert_arg(a) for a in args]) if isinstance(result, Object): - result = json.loads(result.json()) + result = json.loads(result.json()) return result finally: if run_gc: diff --git a/quickjs/py.typed b/quickjs/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/setup.py b/setup.py index 4aedcbf..9c4941c 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,3 @@ -import glob import sys from typing import List @@ -16,13 +15,13 @@ # system PATH when compiling. # 3. The code below will moneky-patch distutils to work. import distutils.cygwinccompiler - distutils.cygwinccompiler.get_msvcr = lambda: [] + distutils.cygwinccompiler.get_msvcr = lambda: [] # type: ignore # Make sure that pthreads is linked statically, otherwise we run into problems # on computers where it is not installed. extra_link_args = ["-static"] -def get_c_sources(include_headers=False): +def get_c_sources(include_headers: bool = False): sources = [ "module.c", "upstream-quickjs/cutils.c", @@ -77,4 +76,9 @@ def get_c_sources(include_headers=False): description='Wrapping the quickjs C library.', long_description=long_description, packages=["quickjs"], - ext_modules=[_quickjs]) + ext_modules=[_quickjs], + package_data={ + "": ["_quickjs.pyi"], + "quickjs": ["py.typed"] + }, + include_package_data=True,)