Skip to content

Python API

pyjs_core

this module is the core of pyjs, it contains the C++ implementation of most of the functions and classes used by pyjs.

JsValue

A class holding a javascript object/value.

__await__()

Wait for the javascript object to resolve.

__call__(*args)

Call the javascript object as a function.

Parameters:

Name Type Description Default
*args Any

The arguments to pass to the function.

()

Returns:

Type Description
Any

The result of the function call.

__contains__(q)

Check if the javascript object contains a value.

__delattr__(__name)

Delete an attribute from the javascript object.

__delitem__(__name)

Delete an item from the javascript object.

__eq__(q)

Check if the javascript object is equal to a value.

__init__(value)

Create a new JsValue from a python value. Args: value: The value to convert to a JsValue. If the value is a primitive type (int, float, str, bool) it will be converted to the corresponding javascript type. For any other python object, it will be converted to the javascript class pyjs.pyobject which is a wrapper around the python object on the javascript side.

__iter__()

Get an iterator for the javascript object.

__len__()

Get the length of the javascript object.

__next__()

Get the next value from the iterator.

__repr__()

Convert the javascript object to a string.

__str__()

Convert the javascript object to a string.

new(*args)

Create a new instance of a JavaScript class.

pyjs

JsToPyConverterOptions

Bases: object

Source code in module/pyjs/convert.py
class JsToPyConverterOptions(object):
    def __init__(self, json=False, converters=None, default_converter=None):
        self.json = json

        if converters is None:
            converters = _basic_to_py_converters
        if default_converter is None:
            default_converter = _basic_to_py_converters["Object"]

        self.converters = converters
        self.default_converter = default_converter

WebLoop

Bases: AbstractEventLoop

A custom event loop for use in pyodide

Schedules tasks on the browser event loop. Does no lifecycle management and runs forever.

run_forever and run_until_complete cannot block like a normal event loop would because we only have one thread so blocking would stall the browser event loop and prevent anything from ever happening.

We defer all work to the browser event loop using the setTimeout function. To ensure that this event loop doesn't stall out UI and other browser handling, we want to make sure that each task is scheduled on the browser event loop as a task not as a microtask. setTimeout(callback, 0) enqueues the callback as a task so it works well for our purposes.

See Event Loop Methods <https://docs.python.org/3/library/asyncio-eventloop.html#asyncio-event-loop>_.

Source code in module/pyjs/webloop.py
class WebLoop(asyncio.AbstractEventLoop):
    """A custom event loop for use in pyodide

    Schedules tasks on the browser event loop. Does no lifecycle management and runs
    forever.

    ``run_forever`` and ``run_until_complete`` cannot block like a normal event loop would
    because we only have one thread so blocking would stall the browser event loop
    and prevent anything from ever happening.

    We defer all work to the browser event loop using the setTimeout function.
    To ensure that this event loop doesn't stall out UI and other browser handling,
    we want to make sure that each task is scheduled on the browser event loop as a
    task not as a microtask. ``setTimeout(callback, 0)`` enqueues the callback as a
    task so it works well for our purposes.

    See `Event Loop Methods
        <https://docs.python.org/3/library/asyncio-eventloop.html#asyncio-event-loop>`_.
    """

    def __init__(self):
        self._task_factory = None
        asyncio._set_running_loop(self)
        self._exception_handler = None
        self._current_handle = None
        self._set_timeout = js.setTimeout
        self._n_unfinished = 0

    def get_debug(self):
        return False

    #
    # Lifecycle methods: We ignore all lifecycle management
    #

    def is_running(self) -> bool:
        """Returns ``True`` if the event loop is running.

        Always returns ``True`` because WebLoop has no lifecycle management.
        """
        return True

    def is_closed(self) -> bool:
        """Returns ``True`` if the event loop was closed.

        Always returns ``False`` because WebLoop has no lifecycle management.
        """
        return False

    def _check_closed(self):
        """Used in create_task.

        Would raise an error if ``self.is_closed()``, but we are skipping all lifecycle stuff.
        """
        pass

    def run_forever(self):
        """Run the event loop forever. Does nothing in this implementation.

        We cannot block like a normal event loop would
        because we only have one thread so blocking would stall the browser event loop
        and prevent anything from ever happening.
        """
        pass

    def run_until_complete(self, future):
        """Run until future is done.

        If the argument is a coroutine, it is wrapped in a Task.

        The native event loop `run_until_complete` blocks until evaluation of the
        future is complete and then returns the result of the future.
        Since we cannot block, we just ensure that the future is scheduled and
        return the future. This makes this method a bit useless. Instead, use
        `future.add_done_callback(do_something_with_result)` or:
        ```python
        async def wrapper():
            result = await future
            do_something_with_result(result)
        ```
        """
        return asyncio.ensure_future(future)

    #
    # Scheduling methods: use browser.setTimeout to schedule tasks on the browser event loop.
    #

    def call_soon(self, callback: Callable, *args, context: contextvars.Context = None):
        """Arrange for a callback to be called as soon as possible.

        Any positional arguments after the callback will be passed to
        the callback when it is called.

        This schedules the callback on the browser event loop using ``setTimeout(callback, 0)``.
        """
        delay = 0
        return self.call_later(delay, callback, *args, context=context)

    def call_soon_threadsafe(
        self, callback: Callable, *args, context: contextvars.Context = None
    ):
        """Like ``call_soon()``, but thread-safe.

        We have no threads so everything is "thread safe", and we just use ``call_soon``.
        """
        return self.call_soon(callback, *args, context=context)

    def call_later(
        self,
        delay: float,
        callback: Callable,
        *args,
        context: contextvars.Context = None,
    ):
        """Arrange for a callback to be called at a given time.

        Return a Handle: an opaque object with a cancel() method that
        can be used to cancel the call.

        The delay can be an int or float, expressed in seconds.  It is
        always relative to the current time.

        Each callback will be called exactly once.  If two callbacks
        are scheduled for exactly the same time, it undefined which
        will be called first.

        Any positional arguments after the callback will be passed to
        the callback when it is called.

        This uses `setTimeout(callback, delay)`
        """
        if delay < 0:
            raise ValueError("Can't schedule in the past")

        self._n_unfinished += 1
        h = asyncio.Handle(callback, args, self, context=context)

        @contextlib.contextmanager
        def decrementor():
            yield
            self._n_unfinished -= 1

        def run_handle():
            with decrementor():
                if h.cancelled():
                    return
                h._run()

        # instead of using `pyjs.create_once_callable` we
        # use an internal optimized function, that does not allow for
        # any arguments, does not return anything, and does assume
        # that the function does not throw
        once_callable =  pyjs_core.internal.module_property("_create_once_callable_unsave_void_void")(
            pyjs_core.JsValue(run_handle)
        )
        self._set_timeout(once_callable, delay * 1000)
        return h

    def call_at(
        self,
        when: float,
        callback: Callable,
        *args,
        context: contextvars.Context = None,
    ):
        """Like ``call_later()``, but uses an absolute time.

        Absolute time corresponds to the event loop's ``time()`` method.

        This uses ``setTimeout(callback, when - cur_time)``
        """
        cur_time = self.time()
        delay = when - cur_time
        return self.call_later(delay, callback, *args, context=context)

    def run_in_executor(self, executor, func, *args):
        """Arrange for func to be called in the specified executor.

        This is normally supposed to run func(*args) in a separate process or
        thread and signal back to our event loop when it is done. It's possible
        to make the executor, but if we actually try to submit any functions to
        it, it will try to create a thread and throw an error. Best we can do is
        to run func(args) in this thread and stick the result into a future.
        """
        fut = self.create_future()
        try:
            fut.set_result(func(*args))
        except BaseException as e:
            fut.set_exception(e)
        return fut

    #
    # The remaining methods are copied directly from BaseEventLoop
    #

    def time(self):
        """Return the time according to the event loop's clock.

        This is a float expressed in seconds since an epoch, but the
        epoch, precision, accuracy and drift are unspecified and may
        differ per event loop.

        Copied from ``BaseEventLoop.time``
        """
        return time.monotonic()

    def create_future(self):
        """Create a Future object attached to the loop.

        Copied from ``BaseEventLoop.create_future``
        """
        return asyncio.futures.Future(loop=self)

    def create_task(self, coro, *, name=None):
        """Schedule a coroutine object.

        Return a task object.

        Copied from ``BaseEventLoop.create_task``
        """
        self._check_closed()
        if self._task_factory is None:
            task = asyncio.tasks.Task(coro, loop=self, name=name)
            if task._source_traceback:  # type: ignore[attr-defined]
                # Added comment:
                # this only happens if get_debug() returns True.
                # In that case, remove create_task from _source_traceback.
                del task._source_traceback[-1]  # type: ignore[attr-defined]
        else:
            task = self._task_factory(self, coro)
            asyncio.tasks._set_task_name(task, name)  # type: ignore[attr-defined]

        return task

    def set_task_factory(self, factory):
        """Set a task factory that will be used by loop.create_task().

        If factory is None the default task factory will be set.

        If factory is a callable, it should have a signature matching
        '(loop, coro)', where 'loop' will be a reference to the active
        event loop, 'coro' will be a coroutine object.  The callable
        must return a Future.

        Copied from ``BaseEventLoop.set_task_factory``
        """
        if factory is not None and not callable(factory):
            raise TypeError("task factory must be a callable or None")
        self._task_factory = factory

    def get_task_factory(self):
        """Return a task factory, or None if the default one is in use.

        Copied from ``BaseEventLoop.get_task_factory``
        """
        return self._task_factory

    def get_exception_handler(self):
        """Return an exception handler, or None if the default one is in use."""
        return self._exception_handler

    def set_exception_handler(self, handler):
        """Set handler as the new event loop exception handler.

        If handler is None, the default exception handler will be set.

        If handler is a callable object, it should have a signature matching
        '(loop, context)', where 'loop' will be a reference to the active event
        loop, 'context' will be a dict object (see `call_exception_handler()`
        documentation for details about context).
        """

        if handler is not None and not callable(handler):
            raise TypeError(
                f"A callable object or None is expected, " f"got {handler!r}"
            )
        self._exception_handler = handler

    def default_exception_handler(self, context):
        """Default exception handler.

        This is called when an exception occurs and no exception handler is set,
        and can be called by a custom exception handler that wants to defer to
        the default behavior. This default handler logs the error message and
        other context-dependent information.


        In debug mode, a truncated stack trace is also appended showing where
        the given object (e.g. a handle or future or task) was created, if any.
        The context parameter has the same meaning as in
        `call_exception_handler()`.
        """

        message = context.get("message")

        # internal.console_log("context", context)
        # internal.console_log("message", message)

        if not message:
            message = "Unhandled exception in event loop"

        if (
            "source_traceback" not in context
            and self._current_handle is not None
            and self._current_handle._source_traceback
        ):
            context["handle_traceback"] = self._current_handle._source_traceback

        log_lines = [message]
        for key in sorted(context):
            if key in {"message", "exception"}:
                continue
            value = context[key]
            if key == "source_traceback":
                tb = "".join(traceback.format_list(value))
                value = "Object created at (most recent call last):\n"
                value += tb.rstrip()
            elif key == "handle_traceback":
                tb = "".join(traceback.format_list(value))
                value = "Handle created at (most recent call last):\n"
                value += tb.rstrip()
            else:
                value = repr(value)
            log_lines.append(f"{key}: {value}")

        print("\n".join(log_lines), file=sys.stderr)

    def call_exception_handler(self, context):
        """Call the current event loop's exception handler.
        The context argument is a dict containing the following keys:

        * `message`: Error message;
        * `exception` (optional): Exception object;
        * `future` (optional): Future instance;
        * `task` (optional): Task instance;
        * `handle` (optional): Handle instance;
        * `protocol` (optional): Protocol instance;
        * `transport` (optional): Transport instance;
        * `socket` (optional): Socket instance;
        * `asyncgen` (optional): Asynchronous generator that caused
                                the exception.

        New keys maybe introduced in the future.
        Note: do not overload this method in an event loop subclass.
        For custom exception handling, use the
        `set_exception_handler()` method.
        """
        pyjs_core.js.console.log("call_exception_handler")
        # internal.console_log("context", context)
        pyjs_core.js.console.log("message", context['message'])
        if self._exception_handler is None:
            try:
                self.default_exception_handler(context)
            except (SystemExit, KeyboardInterrupt):
                raise
            except BaseException:
                # Second protection layer for unexpected errors
                # in the default implementation, as well as for subclassed
                # event loops with overloaded "default_exception_handler".
                print("Exception in default exception handler", file=sys.stderr)
                traceback.print_exc()
        else:
            try:
                self._exception_handler(self, context)
            except (SystemExit, KeyboardInterrupt):
                raise
            except BaseException as exc:
                # Exception in the user set custom exception handler.
                try:
                    # Let's try default handler.
                    self.default_exception_handler(
                        {
                            "message": "Unhandled error in exception handler",
                            "exception": exc,
                            "context": context,
                        }
                    )
                except (SystemExit, KeyboardInterrupt):
                    raise
                except BaseException:
                    # Guard 'default_exception_handler' in case it is
                    # overloaded.
                    print(
                        "Exception in default exception handler "
                        "while handling an unexpected error "
                        "in custom exception handler",
                        file=sys.stderr,
                    )
                    traceback.print_exc()

call_at(when, callback, *args, context=None)

Like call_later(), but uses an absolute time.

Absolute time corresponds to the event loop's time() method.

This uses setTimeout(callback, when - cur_time)

Source code in module/pyjs/webloop.py
def call_at(
    self,
    when: float,
    callback: Callable,
    *args,
    context: contextvars.Context = None,
):
    """Like ``call_later()``, but uses an absolute time.

    Absolute time corresponds to the event loop's ``time()`` method.

    This uses ``setTimeout(callback, when - cur_time)``
    """
    cur_time = self.time()
    delay = when - cur_time
    return self.call_later(delay, callback, *args, context=context)

call_exception_handler(context)

Call the current event loop's exception handler. The context argument is a dict containing the following keys:

  • message: Error message;
  • exception (optional): Exception object;
  • future (optional): Future instance;
  • task (optional): Task instance;
  • handle (optional): Handle instance;
  • protocol (optional): Protocol instance;
  • transport (optional): Transport instance;
  • socket (optional): Socket instance;
  • asyncgen (optional): Asynchronous generator that caused the exception.

New keys maybe introduced in the future. Note: do not overload this method in an event loop subclass. For custom exception handling, use the set_exception_handler() method.

Source code in module/pyjs/webloop.py
def call_exception_handler(self, context):
    """Call the current event loop's exception handler.
    The context argument is a dict containing the following keys:

    * `message`: Error message;
    * `exception` (optional): Exception object;
    * `future` (optional): Future instance;
    * `task` (optional): Task instance;
    * `handle` (optional): Handle instance;
    * `protocol` (optional): Protocol instance;
    * `transport` (optional): Transport instance;
    * `socket` (optional): Socket instance;
    * `asyncgen` (optional): Asynchronous generator that caused
                            the exception.

    New keys maybe introduced in the future.
    Note: do not overload this method in an event loop subclass.
    For custom exception handling, use the
    `set_exception_handler()` method.
    """
    pyjs_core.js.console.log("call_exception_handler")
    # internal.console_log("context", context)
    pyjs_core.js.console.log("message", context['message'])
    if self._exception_handler is None:
        try:
            self.default_exception_handler(context)
        except (SystemExit, KeyboardInterrupt):
            raise
        except BaseException:
            # Second protection layer for unexpected errors
            # in the default implementation, as well as for subclassed
            # event loops with overloaded "default_exception_handler".
            print("Exception in default exception handler", file=sys.stderr)
            traceback.print_exc()
    else:
        try:
            self._exception_handler(self, context)
        except (SystemExit, KeyboardInterrupt):
            raise
        except BaseException as exc:
            # Exception in the user set custom exception handler.
            try:
                # Let's try default handler.
                self.default_exception_handler(
                    {
                        "message": "Unhandled error in exception handler",
                        "exception": exc,
                        "context": context,
                    }
                )
            except (SystemExit, KeyboardInterrupt):
                raise
            except BaseException:
                # Guard 'default_exception_handler' in case it is
                # overloaded.
                print(
                    "Exception in default exception handler "
                    "while handling an unexpected error "
                    "in custom exception handler",
                    file=sys.stderr,
                )
                traceback.print_exc()

call_later(delay, callback, *args, context=None)

Arrange for a callback to be called at a given time.

Return a Handle: an opaque object with a cancel() method that can be used to cancel the call.

The delay can be an int or float, expressed in seconds. It is always relative to the current time.

Each callback will be called exactly once. If two callbacks are scheduled for exactly the same time, it undefined which will be called first.

Any positional arguments after the callback will be passed to the callback when it is called.

This uses setTimeout(callback, delay)

Source code in module/pyjs/webloop.py
def call_later(
    self,
    delay: float,
    callback: Callable,
    *args,
    context: contextvars.Context = None,
):
    """Arrange for a callback to be called at a given time.

    Return a Handle: an opaque object with a cancel() method that
    can be used to cancel the call.

    The delay can be an int or float, expressed in seconds.  It is
    always relative to the current time.

    Each callback will be called exactly once.  If two callbacks
    are scheduled for exactly the same time, it undefined which
    will be called first.

    Any positional arguments after the callback will be passed to
    the callback when it is called.

    This uses `setTimeout(callback, delay)`
    """
    if delay < 0:
        raise ValueError("Can't schedule in the past")

    self._n_unfinished += 1
    h = asyncio.Handle(callback, args, self, context=context)

    @contextlib.contextmanager
    def decrementor():
        yield
        self._n_unfinished -= 1

    def run_handle():
        with decrementor():
            if h.cancelled():
                return
            h._run()

    # instead of using `pyjs.create_once_callable` we
    # use an internal optimized function, that does not allow for
    # any arguments, does not return anything, and does assume
    # that the function does not throw
    once_callable =  pyjs_core.internal.module_property("_create_once_callable_unsave_void_void")(
        pyjs_core.JsValue(run_handle)
    )
    self._set_timeout(once_callable, delay * 1000)
    return h

call_soon(callback, *args, context=None)

Arrange for a callback to be called as soon as possible.

Any positional arguments after the callback will be passed to the callback when it is called.

This schedules the callback on the browser event loop using setTimeout(callback, 0).

Source code in module/pyjs/webloop.py
def call_soon(self, callback: Callable, *args, context: contextvars.Context = None):
    """Arrange for a callback to be called as soon as possible.

    Any positional arguments after the callback will be passed to
    the callback when it is called.

    This schedules the callback on the browser event loop using ``setTimeout(callback, 0)``.
    """
    delay = 0
    return self.call_later(delay, callback, *args, context=context)

call_soon_threadsafe(callback, *args, context=None)

Like call_soon(), but thread-safe.

We have no threads so everything is "thread safe", and we just use call_soon.

Source code in module/pyjs/webloop.py
def call_soon_threadsafe(
    self, callback: Callable, *args, context: contextvars.Context = None
):
    """Like ``call_soon()``, but thread-safe.

    We have no threads so everything is "thread safe", and we just use ``call_soon``.
    """
    return self.call_soon(callback, *args, context=context)

create_future()

Create a Future object attached to the loop.

Copied from BaseEventLoop.create_future

Source code in module/pyjs/webloop.py
def create_future(self):
    """Create a Future object attached to the loop.

    Copied from ``BaseEventLoop.create_future``
    """
    return asyncio.futures.Future(loop=self)

create_task(coro, *, name=None)

Schedule a coroutine object.

Return a task object.

Copied from BaseEventLoop.create_task

Source code in module/pyjs/webloop.py
def create_task(self, coro, *, name=None):
    """Schedule a coroutine object.

    Return a task object.

    Copied from ``BaseEventLoop.create_task``
    """
    self._check_closed()
    if self._task_factory is None:
        task = asyncio.tasks.Task(coro, loop=self, name=name)
        if task._source_traceback:  # type: ignore[attr-defined]
            # Added comment:
            # this only happens if get_debug() returns True.
            # In that case, remove create_task from _source_traceback.
            del task._source_traceback[-1]  # type: ignore[attr-defined]
    else:
        task = self._task_factory(self, coro)
        asyncio.tasks._set_task_name(task, name)  # type: ignore[attr-defined]

    return task

default_exception_handler(context)

Default exception handler.

This is called when an exception occurs and no exception handler is set, and can be called by a custom exception handler that wants to defer to the default behavior. This default handler logs the error message and other context-dependent information.

In debug mode, a truncated stack trace is also appended showing where the given object (e.g. a handle or future or task) was created, if any. The context parameter has the same meaning as in call_exception_handler().

Source code in module/pyjs/webloop.py
def default_exception_handler(self, context):
    """Default exception handler.

    This is called when an exception occurs and no exception handler is set,
    and can be called by a custom exception handler that wants to defer to
    the default behavior. This default handler logs the error message and
    other context-dependent information.


    In debug mode, a truncated stack trace is also appended showing where
    the given object (e.g. a handle or future or task) was created, if any.
    The context parameter has the same meaning as in
    `call_exception_handler()`.
    """

    message = context.get("message")

    # internal.console_log("context", context)
    # internal.console_log("message", message)

    if not message:
        message = "Unhandled exception in event loop"

    if (
        "source_traceback" not in context
        and self._current_handle is not None
        and self._current_handle._source_traceback
    ):
        context["handle_traceback"] = self._current_handle._source_traceback

    log_lines = [message]
    for key in sorted(context):
        if key in {"message", "exception"}:
            continue
        value = context[key]
        if key == "source_traceback":
            tb = "".join(traceback.format_list(value))
            value = "Object created at (most recent call last):\n"
            value += tb.rstrip()
        elif key == "handle_traceback":
            tb = "".join(traceback.format_list(value))
            value = "Handle created at (most recent call last):\n"
            value += tb.rstrip()
        else:
            value = repr(value)
        log_lines.append(f"{key}: {value}")

    print("\n".join(log_lines), file=sys.stderr)

get_exception_handler()

Return an exception handler, or None if the default one is in use.

Source code in module/pyjs/webloop.py
def get_exception_handler(self):
    """Return an exception handler, or None if the default one is in use."""
    return self._exception_handler

get_task_factory()

Return a task factory, or None if the default one is in use.

Copied from BaseEventLoop.get_task_factory

Source code in module/pyjs/webloop.py
def get_task_factory(self):
    """Return a task factory, or None if the default one is in use.

    Copied from ``BaseEventLoop.get_task_factory``
    """
    return self._task_factory

is_closed()

Returns True if the event loop was closed.

Always returns False because WebLoop has no lifecycle management.

Source code in module/pyjs/webloop.py
def is_closed(self) -> bool:
    """Returns ``True`` if the event loop was closed.

    Always returns ``False`` because WebLoop has no lifecycle management.
    """
    return False

is_running()

Returns True if the event loop is running.

Always returns True because WebLoop has no lifecycle management.

Source code in module/pyjs/webloop.py
def is_running(self) -> bool:
    """Returns ``True`` if the event loop is running.

    Always returns ``True`` because WebLoop has no lifecycle management.
    """
    return True

run_forever()

Run the event loop forever. Does nothing in this implementation.

We cannot block like a normal event loop would because we only have one thread so blocking would stall the browser event loop and prevent anything from ever happening.

Source code in module/pyjs/webloop.py
def run_forever(self):
    """Run the event loop forever. Does nothing in this implementation.

    We cannot block like a normal event loop would
    because we only have one thread so blocking would stall the browser event loop
    and prevent anything from ever happening.
    """
    pass

run_in_executor(executor, func, *args)

Arrange for func to be called in the specified executor.

This is normally supposed to run func(*args) in a separate process or thread and signal back to our event loop when it is done. It's possible to make the executor, but if we actually try to submit any functions to it, it will try to create a thread and throw an error. Best we can do is to run func(args) in this thread and stick the result into a future.

Source code in module/pyjs/webloop.py
def run_in_executor(self, executor, func, *args):
    """Arrange for func to be called in the specified executor.

    This is normally supposed to run func(*args) in a separate process or
    thread and signal back to our event loop when it is done. It's possible
    to make the executor, but if we actually try to submit any functions to
    it, it will try to create a thread and throw an error. Best we can do is
    to run func(args) in this thread and stick the result into a future.
    """
    fut = self.create_future()
    try:
        fut.set_result(func(*args))
    except BaseException as e:
        fut.set_exception(e)
    return fut

run_until_complete(future)

Run until future is done.

If the argument is a coroutine, it is wrapped in a Task.

The native event loop run_until_complete blocks until evaluation of the future is complete and then returns the result of the future. Since we cannot block, we just ensure that the future is scheduled and return the future. This makes this method a bit useless. Instead, use future.add_done_callback(do_something_with_result) or:

async def wrapper():
    result = await future
    do_something_with_result(result)

Source code in module/pyjs/webloop.py
def run_until_complete(self, future):
    """Run until future is done.

    If the argument is a coroutine, it is wrapped in a Task.

    The native event loop `run_until_complete` blocks until evaluation of the
    future is complete and then returns the result of the future.
    Since we cannot block, we just ensure that the future is scheduled and
    return the future. This makes this method a bit useless. Instead, use
    `future.add_done_callback(do_something_with_result)` or:
    ```python
    async def wrapper():
        result = await future
        do_something_with_result(result)
    ```
    """
    return asyncio.ensure_future(future)

set_exception_handler(handler)

Set handler as the new event loop exception handler.

If handler is None, the default exception handler will be set.

If handler is a callable object, it should have a signature matching '(loop, context)', where 'loop' will be a reference to the active event loop, 'context' will be a dict object (see call_exception_handler() documentation for details about context).

Source code in module/pyjs/webloop.py
def set_exception_handler(self, handler):
    """Set handler as the new event loop exception handler.

    If handler is None, the default exception handler will be set.

    If handler is a callable object, it should have a signature matching
    '(loop, context)', where 'loop' will be a reference to the active event
    loop, 'context' will be a dict object (see `call_exception_handler()`
    documentation for details about context).
    """

    if handler is not None and not callable(handler):
        raise TypeError(
            f"A callable object or None is expected, " f"got {handler!r}"
        )
    self._exception_handler = handler

set_task_factory(factory)

Set a task factory that will be used by loop.create_task().

If factory is None the default task factory will be set.

If factory is a callable, it should have a signature matching '(loop, coro)', where 'loop' will be a reference to the active event loop, 'coro' will be a coroutine object. The callable must return a Future.

Copied from BaseEventLoop.set_task_factory

Source code in module/pyjs/webloop.py
def set_task_factory(self, factory):
    """Set a task factory that will be used by loop.create_task().

    If factory is None the default task factory will be set.

    If factory is a callable, it should have a signature matching
    '(loop, coro)', where 'loop' will be a reference to the active
    event loop, 'coro' will be a coroutine object.  The callable
    must return a Future.

    Copied from ``BaseEventLoop.set_task_factory``
    """
    if factory is not None and not callable(factory):
        raise TypeError("task factory must be a callable or None")
    self._task_factory = factory

time()

Return the time according to the event loop's clock.

This is a float expressed in seconds since an epoch, but the epoch, precision, accuracy and drift are unspecified and may differ per event loop.

Copied from BaseEventLoop.time

Source code in module/pyjs/webloop.py
def time(self):
    """Return the time according to the event loop's clock.

    This is a float expressed in seconds since an epoch, but the
    epoch, precision, accuracy and drift are unspecified and may
    differ per event loop.

    Copied from ``BaseEventLoop.time``
    """
    return time.monotonic()

JsException

Bases: JsHolder, Exception

Source code in module/pyjs/error_handling.py
class JsException(JsHolder, Exception):
    def __init__(self, err, message=None):

        # default message
        if message is None:
            message = js.JSON.stringify(err, js.Object.getOwnPropertyNames(err))

        self.name = "UnknownError"
        try:
            self.name = err.name
        except  AttributeError:
            pass

        self.message = message

        # i
        Exception.__init__(self, self.message)
        JsHolder.__init__(self, js_proxy=err)

JsGenericError

Bases: JsException

Source code in module/pyjs/error_handling.py
class JsGenericError(JsException):
    def __init__(self, err):
        super().__init__(err=err)
        self.value = err

JsError

Bases: JsException

Source code in module/pyjs/error_handling.py
class JsError(JsException):
    def __init__(self, err):
        super().__init__(err=err)

JsInternalError

Bases: JsError

Source code in module/pyjs/error_handling.py
class JsInternalError(JsError):
    def __init__(self, err):
        super().__init__(err=err)

JsRangeError

Bases: JsError

Source code in module/pyjs/error_handling.py
class JsRangeError(JsError):
    def __init__(self, err):
        super().__init__(err=err)

JsReferenceError

Bases: JsError

Source code in module/pyjs/error_handling.py
class JsReferenceError(JsError):
    def __init__(self, err):
        super().__init__(err=err)

JsSyntaxError

Bases: JsError

Source code in module/pyjs/error_handling.py
class JsSyntaxError(JsError):
    def __init__(self, err):
        super().__init__(err=err)

JsTypeError

Bases: JsError

Source code in module/pyjs/error_handling.py
class JsTypeError(JsError):
    def __init__(self, err):
        super().__init__(err=err)

JsURIError

Bases: JsError

Source code in module/pyjs/error_handling.py
class JsURIError(JsError):
    def __init__(self, err):
        super().__init__(err=err)

to_js(value, cache=None, depth=0, max_depth=None)

Convert a Python object to a JavaScript object.

Parameters:

Name Type Description Default
value

The Python object to convert.

required
cache

A dictionary to use as a cache for already converted objects.

None
depth

The current depth of of nested object conversion.

0
max_depth

The maximum depth of nested object conversion.

None

Returns:

a JavaScript stored in a pyjs_core.JsValue
Source code in module/pyjs/convert_py_to_js.py
def to_js(value, cache=None, depth=0, max_depth=None):
    """
    Convert a Python object to a JavaScript object.

    Args:
        value: The Python object to convert.
        cache: A dictionary to use as a cache for already converted objects.
        depth: The current depth of of nested object conversion.
        max_depth: The maximum depth of nested object conversion.

    Returns:

        a JavaScript stored in a pyjs_core.JsValue
    """
    if cache is None:
        cache = dict()

    if max_depth is not None and depth >= max_depth:
        return value

    if isinstance(value, JsValue):
        return value
    elif isinstance(value, (list, tuple)):
        return _py_list_like_to_js(
            value=value, cache=cache, depth=depth, max_depth=max_depth
        )
    elif isinstance(value, dict):
        return _py_dict_like_to_js(
            value=value, cache=cache, depth=depth, max_depth=max_depth
        )
    elif isinstance(value, set):
        return _py_set_like_to_js(
            value=value, cache=cache, depth=depth, max_depth=max_depth
        )
    elif value is None:
        return js_undefined()
    elif isinstance(value, (int, float, str, bool)):
        return JsValue(value)

    # # bytestring
    elif isinstance(value, bytes):
        return internal.bytes_to_typed_array(value).buffer


    else:
        raise RuntimeError(f"no registerd converted for {value} of type {type(value)}")

to_py(js_val, depth=0, cache=None, converter_options=None)

Source code in module/pyjs/convert.py
def to_py(js_val, depth=0, cache=None, converter_options=None):
    if not isinstance(js_val, JsValue):
        return js_val
    if converter_options is None:
        converter_options = JsToPyConverterOptions()
    if cache is None:
        cache = _JsToPyConverterCache()
    converters = converter_options.converters
    default_converter = converter_options.default_converter
    ts = internal.get_type_string(js_val)
    return converters.get(ts, default_converter)(
        js_val, depth, cache, converter_options
    )

register_converter(cls_name, converter)

Register a custom JavaScript to Python converter.

Parameters:

Name Type Description Default
cls_name str

The name of the JavaScript class to convert.

required
converter callable

A function that takes a JavaScript object and returns a Python object.

required
Example

For this example we define the JavaScript class Rectangle on the fly and create an instance of it. We then register a custom converter for the Rectangle class and convert the instance to a Python object.

    # Define JavaScript Rectangle class
    # and create an instance of it
    rectangle = pyjs.js.Function("""
        class Rectangle {
        constructor(height, width) {
            this.height = height;
            this.width = width;
        }
        }
        return new Rectangle(10,20)
    """)()

    # A Python Rectangle class
    class Rectangle(object):
        def __init__(self, height, width):
            self.height = height
            self.width = width

    # the custom converter
    def rectangle_converter(js_val, depth, cache, converter_options):
        return Rectangle(js_val.height, js_val.width)

    # Register the custom converter
    pyjs.register_converter("Rectangle", rectangle_converter)

    # Convert the JavaScript Rectangle to a Python Rectangle
    r = pyjs.to_py(rectangle)
    assert isinstance(r, Rectangle)
    assert r.height == 10
    assert r.width == 20
Source code in module/pyjs/convert.py
def register_converter(cls_name : str, converter : callable):
    '''
    Register a custom JavaScript to Python converter.

    Args:
        cls_name: The name of the JavaScript class to convert.
        converter: A function that takes a JavaScript object and returns a Python object.

    Example:
        For this example we define the JavaScript class Rectangle on the fly
        and create an instance of it. We then register a custom converter for the
        Rectangle class and convert the instance to a Python object.

    ```python


        # Define JavaScript Rectangle class
        # and create an instance of it
        rectangle = pyjs.js.Function("""
            class Rectangle {
            constructor(height, width) {
                this.height = height;
                this.width = width;
            }
            }
            return new Rectangle(10,20)
        """)()

        # A Python Rectangle class
        class Rectangle(object):
            def __init__(self, height, width):
                self.height = height
                self.width = width

        # the custom converter
        def rectangle_converter(js_val, depth, cache, converter_options):
            return Rectangle(js_val.height, js_val.width)

        # Register the custom converter
        pyjs.register_converter("Rectangle", rectangle_converter)

        # Convert the JavaScript Rectangle to a Python Rectangle
        r = pyjs.to_py(rectangle)
        assert isinstance(r, Rectangle)
        assert r.height == 10
        assert r.width == 20

    ```

    '''


    _basic_to_py_converters[cls_name] = converter

new(cls_, *args)

Create a new instance of a JavaScript class.

This function is a wrapper around the new operator in JavaScript.

Parameters:

Name Type Description Default
cls_ JsValue

The JavaScript class to create an instance of

required
*args Any

The arguments to pass to the constructor of the JavaScript class

()
Source code in module/pyjs/core.py
def new(cls_, *args):
    """ Create a new instance of a JavaScript class.

    This function is a wrapper around the `new` operator in JavaScript.

    Args:
        cls_ (JsValue): The JavaScript class to create an instance of
        *args (Any): The arguments to pass to the constructor of the JavaScript class
    """
    return pyjs_core._module._new(cls_, *args)

create_callable(py_function)

Create a JavaScript callable from a Python function.

Parameters:

Name Type Description Default
py_function Callable

The Python function to create a JavaScript callable from.

required

Example:

def py_function(x, y):
    return x + y

js_callable, js_py_object = create_callable(py_function)

# this function can be passed to JavaScript.
# lets create some JavaScript code to test it
higher_order_function = pyjs.js.Function("f", "x", "y", "z", """
    return z * f(x, y);
""")

# call the higher order JavaScript function with py_function wrapped as a JavaScript callable
result = higher_order_function(js_callable, 1, 2, 3)
assert result == 9

js_py_object.delete()

Returns:

Name Type Description
callable

The JavaScript callable

js_py_object

this object needs to be deleted after the callable is no longer needed

Source code in module/pyjs/core.py
def create_callable(py_function):
    '''Create a JavaScript callable from a Python function.

    Args:
        py_function (Callable): The Python function to create a JavaScript callable from.

    Example:
    ```python
    def py_function(x, y):
        return x + y

    js_callable, js_py_object = create_callable(py_function)

    # this function can be passed to JavaScript.
    # lets create some JavaScript code to test it
    higher_order_function = pyjs.js.Function("f", "x", "y", "z", """
        return z * f(x, y);
    """)

    # call the higher order JavaScript function with py_function wrapped as a JavaScript callable
    result = higher_order_function(js_callable, 1, 2, 3)
    assert result == 9

    js_py_object.delete()
    ```

    Returns:
        callable: The JavaScript callable
        js_py_object: this object needs to be deleted after the callable is no longer needed
    '''    
    _js_py_object = js_py_object(py_function)
    return _js_py_object["py_call"].bind(_js_py_object), _js_py_object

callable_context(py_function)

Create a JavaScript callable from a Python function and delete it when the context is exited.

See create_callable for more information.

Parameters:

Name Type Description Default
py_function Callable

The Python function to create a JavaScript callable from.

required

Example:

def py_function(x, y):
    return x + y

with pyjs.callable_context(py_function) as js_function:
    # js_function is a JavaScript callable and could be passed and called from JavaScript
    # here we just call it from Python
    print(js_function(1,2))
Source code in module/pyjs/core.py
@contextlib.contextmanager
def callable_context(py_function):
    ''' Create a JavaScript callable from a Python function and delete it when the context is exited.

    See `create_callable` for more information.

    Args:
        py_function (Callable): The Python function to create a JavaScript callable from.

    Example:

    ```python
    def py_function(x, y):
        return x + y

    with pyjs.callable_context(py_function) as js_function:
        # js_function is a JavaScript callable and could be passed and called from JavaScript
        # here we just call it from Python
        print(js_function(1,2))
    ```
    '''


    cb, handle = create_callable(py_function)
    yield cb
    handle.delete()

create_once_callable(py_function)

Create a JavaScript callable from a Python function that can only be called once.

Since this function can only be called once, it will be deleted after the first call. Therefore no manual deletion is necessary. See create_callable for more information.

Parameters:

Name Type Description Default
py_function Callable

The Python function to create a JavaScript callable from.

required

Returns:

Name Type Description
callable

The JavaScript callable

Example:

def py_function(x, y):
    return x + y

js_function = pyjs.create_once_callable(py_function)
print(js_function(1,2)) # this will print 3

# the following will raise an error
try:
    print(js_function(1,2))
except Exception as e:
    print(e)

Source code in module/pyjs/core.py
def create_once_callable(py_function):
    """Create a JavaScript callable from a Python function that can only be called once.

    Since this function can only be called once, it will be deleted after the first call.
    Therefore no manual deletion is necessary.
    See `create_callable` for more information.

    Args:
        py_function (Callable): The Python function to create a JavaScript callable from.

    Returns:
        callable: The JavaScript callable

    Example:
    ```python

    def py_function(x, y):
        return x + y

    js_function = pyjs.create_once_callable(py_function)
    print(js_function(1,2)) # this will print 3

    # the following will raise an error
    try:
        print(js_function(1,2))
    except Exception as e:
        print(e)
    ```
    """

    js_py_function = JsValue(py_function)
    once_callable = pyjs_core._module._create_once_callable(js_py_function)
    return once_callable

promise(py_resolve_reject)

Create a new JavaScript promise with a python callback to resolve or reject the promise.

Parameters:

Name Type Description Default
py_resolve_reject Callable

A Python function that takes two arguments, resolve and reject, which are both functions.

required

Example:

import asyncio
import pyjs
def f(resolve, reject):
    async def task():
        try:
            print("start task")
            await asyncio.sleep(1)
            print("end task")
            # resolve when everything is done
            resolve()
        except:
            # reject the promise in case of an error
            reject()
    asyncio.create_task(task())

js_promise = pyjs.promise(f)
print("await the js promise from python")
await js_promise
print("the wait has an end")
print(js_promise)

Source code in module/pyjs/core.py
def promise(py_resolve_reject):
    """ Create a new JavaScript promise with a python callback to resolve or reject the promise.

    Args:
        py_resolve_reject (Callable): A Python function that takes two arguments, resolve and reject, which are both functions. 
        The resolve function should be called with the result of the promise and the reject function should be called with an error.

    Example:
    ```python
    import asyncio
    import pyjs
    def f(resolve, reject):
        async def task():
            try:
                print("start task")
                await asyncio.sleep(1)
                print("end task")
                # resolve when everything is done
                resolve()
            except:
                # reject the promise in case of an error
                reject()
        asyncio.create_task(task())

    js_promise = pyjs.promise(f)
    print("await the js promise from python")
    await js_promise
    print("the wait has an end")
    print(js_promise)
    ```
    """

    return pyjs_core.js.Promise.new(create_once_callable(py_resolve_reject))

apply(js_function, args)

Call a JavaScript function with the given arguments.

Parameters:

Name Type Description Default
js_function JsValue

The JavaScript function to call

required
args List

The arguments to pass to the JavaScript function

required

Returns:

Name Type Description
Any

The result of the JavaScript function

Example:

# create a JavaScript function on the fly
js_function = pyjs.js.Function("x", "y", """
    return x + y;
""")
result = pyjs.apply(js_function, [1, 2])
assert result == 3

Source code in module/pyjs/core.py
def apply(js_function, args):
    '''Call a JavaScript function with the given arguments.

    Args:
        js_function (JsValue): The JavaScript function to call
        args (List): The arguments to pass to the JavaScript function

    Returns:
        Any: The result of the JavaScript function

    Example:
    ```python

    # create a JavaScript function on the fly
    js_function = pyjs.js.Function("x", "y", """
        return x + y;
    """)
    result = pyjs.apply(js_function, [1, 2])
    assert result == 3
    ```
    '''
    js_array_args, is_generated_proxy = _make_js_args(args)
    ret, meta = pyjs_core.internal.apply_try_catch(js_function, js_array_args, is_generated_proxy)
    return ret

pyjs_core

this module is the core of pyjs, it contains the C++ implementation of most of the functions and classes used by pyjs.

JsValue

A class holding a javascript object/value.

__await__()

Wait for the javascript object to resolve.

__call__(*args)

Call the javascript object as a function.

Parameters:

Name Type Description Default
*args Any

The arguments to pass to the function.

()

Returns:

Type Description
Any

The result of the function call.

__contains__(q)

Check if the javascript object contains a value.

__delattr__(__name)

Delete an attribute from the javascript object.

__delitem__(__name)

Delete an item from the javascript object.

__eq__(q)

Check if the javascript object is equal to a value.

__init__(value)

Create a new JsValue from a python value. Args: value: The value to convert to a JsValue. If the value is a primitive type (int, float, str, bool) it will be converted to the corresponding javascript type. For any other python object, it will be converted to the javascript class pyjs.pyobject which is a wrapper around the python object on the javascript side.

__iter__()

Get an iterator for the javascript object.

__len__()

Get the length of the javascript object.

__next__()

Get the next value from the iterator.

__repr__()

Convert the javascript object to a string.

__str__()

Convert the javascript object to a string.

new(*args)

Create a new instance of a JavaScript class.