Source code for reactpy.backend.utils

from __future__ import annotations

import asyncio
import logging
import socket
import sys
from collections.abc import Iterator
from contextlib import closing
from importlib import import_module
from typing import Any

from reactpy.backend.types import BackendType
from reactpy.types import RootComponentConstructor

logger = logging.getLogger(__name__)

SUPPORTED_BACKENDS = (
    "fastapi",
    "sanic",
    "tornado",
    "flask",
    "starlette",
)


[docs]def run( component: RootComponentConstructor, host: str = "127.0.0.1", port: int | None = None, implementation: BackendType[Any] | None = None, ) -> None: """Run a component with a development server""" logger.warning(_DEVELOPMENT_RUN_FUNC_WARNING) implementation = implementation or import_module("reactpy.backend.default") app = implementation.create_development_app() implementation.configure(app, component) port = port or find_available_port(host) app_cls = type(app) logger.info( "ReactPy is running with '%s.%s' at http://%s:%s", app_cls.__module__, app_cls.__name__, host, port, ) asyncio.run(implementation.serve_development_app(app, host, port))
[docs]def find_available_port(host: str, port_min: int = 8000, port_max: int = 9000) -> int: """Get a port that's available for the given host and port range""" for port in range(port_min, port_max): with closing(socket.socket()) as sock: try: if sys.platform in ("linux", "darwin"): # Fixes bug on Unix-like systems where every time you restart the # server you'll get a different port on Linux. This cannot be set # on Windows otherwise address will always be reused. # Ref: https://stackoverflow.com/a/19247688/3159288 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind((host, port)) except OSError: pass else: return port msg = f"Host {host!r} has no available port in range {port_max}-{port_max}" raise RuntimeError(msg)
[docs]def all_implementations() -> Iterator[BackendType[Any]]: """Yield all available server implementations""" for name in SUPPORTED_BACKENDS: try: import_module(name) except ImportError: # nocov logger.debug("Failed to import %s", name, exc_info=True) continue reactpy_backend_name = f"{__name__.rsplit('.', 1)[0]}.{name}" yield import_module(reactpy_backend_name)
_DEVELOPMENT_RUN_FUNC_WARNING = """\ The `run()` function is only intended for testing during development! To run \ in production, refer to the docs on how to use reactpy.backend.*.configure.\ """