From 2e3cf8ae524e6bfdd77c89fede88ff6ac79e706a Mon Sep 17 00:00:00 2001 From: Philip Georgi <110174000+philg314@users.noreply.github.com> Date: Tue, 23 Aug 2022 16:42:42 +0200 Subject: [PATCH 1/2] Add types --- _quickjs.pyi | 60 +++++++++++++++++++++++++++++++++++++++++++++ module.c | 2 +- pyproject.toml | 2 +- quickjs/__init__.py | 23 ++++++++--------- quickjs/py.typed | 0 setup.py | 12 ++++++--- 6 files changed, 82 insertions(+), 17 deletions(-) create mode 100644 _quickjs.pyi create mode 100644 quickjs/py.typed diff --git a/_quickjs.pyi b/_quickjs.pyi new file mode 100644 index 0000000..2755189 --- /dev/null +++ b/_quickjs.pyi @@ -0,0 +1,60 @@ +from typing import Any, Callable, Literal, TypedDict + + +def test() -> Literal[1]: ... + +JSValue = None | bool | int | float | str | Object + +class Object(): + def json(self) -> str: ... + def __call__(self, *args: Any) -> Any: ... + +class MemoryDict(TypedDict): + malloc_size: int + malloc_limit: int + memory_used_size: int + malloc_count: int + memory_used_count: int + atom_count: int + atom_size: int + str_count: int + str_size: int + obj_count: int + obj_size: int + prop_count: int + prop_size: int + shape_count: int + shape_size: int + js_func_count: int + js_func_size: int + js_func_code_size: int + js_func_pc2line_count: int + js_func_pc2line_size: int + c_func_count: int + array_count: int + fast_array_count: int + fast_array_elements: int + binary_object_count: int + binary_object_size: int + +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) -> MemoryDict: ... + 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,) From 50ffc9c50ea2964751df63a37dcc2ded8613a024 Mon Sep 17 00:00:00 2001 From: Philip Georgi <110174000+philg314@users.noreply.github.com> Date: Thu, 25 Aug 2022 23:53:51 +0200 Subject: [PATCH 2/2] Remove typed memory dict --- _quickjs.pyi | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/_quickjs.pyi b/_quickjs.pyi index 2755189..17b3cc9 100644 --- a/_quickjs.pyi +++ b/_quickjs.pyi @@ -1,4 +1,4 @@ -from typing import Any, Callable, Literal, TypedDict +from typing import Any, Callable, Literal def test() -> Literal[1]: ... @@ -9,34 +9,6 @@ class Object(): def json(self) -> str: ... def __call__(self, *args: Any) -> Any: ... -class MemoryDict(TypedDict): - malloc_size: int - malloc_limit: int - memory_used_size: int - malloc_count: int - memory_used_count: int - atom_count: int - atom_size: int - str_count: int - str_size: int - obj_count: int - obj_size: int - prop_count: int - prop_size: int - shape_count: int - shape_size: int - js_func_count: int - js_func_size: int - js_func_code_size: int - js_func_pc2line_count: int - js_func_pc2line_size: int - c_func_count: int - array_count: int - fast_array_count: int - fast_array_elements: int - binary_object_count: int - binary_object_size: int - class Context: def eval(self, code: str) -> JSValue: ... def module(self, code: str) -> JSValue: ... @@ -47,7 +19,7 @@ class Context: 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) -> MemoryDict: ... + def memory(self) -> dict[str, int]: ... def gc(self) -> None: ... def add_callable(self, name: str, callable: Callable[..., Any]) -> None: ... @property