From 09f90e523f628bee039f1c6afa1e344cf380762c Mon Sep 17 00:00:00 2001 From: Nikhil Rao Date: Wed, 15 Nov 2023 17:53:29 -0800 Subject: [PATCH 1/2] Speed up reflex CLI imports --- reflex/reflex.py | 59 ++++++++++++++++++++++++++++----------- reflex/utils/exec.py | 15 ++++++++-- reflex/utils/telemetry.py | 28 ++++++------------- tests/test_telemetry.py | 28 ++++++------------- 4 files changed, 73 insertions(+), 57 deletions(-) diff --git a/reflex/reflex.py b/reflex/reflex.py index a69300f980..3364e506f1 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -16,21 +16,11 @@ import typer import typer.core -from alembic.util.exc import CommandError from tabulate import tabulate -from reflex import constants, model +from reflex import constants from reflex.config import get_config -from reflex.utils import ( - build, - console, - dependency, - exec, - hosting, - prerequisites, - processes, - telemetry, -) +from reflex.utils import console, dependency, telemetry # Disable typer+rich integration for help panels typer.core.rich = False # type: ignore @@ -81,6 +71,8 @@ def _init( loglevel: constants.LogLevel = config.loglevel, ): """Initialize a new Reflex app in the given directory.""" + from reflex.utils import exec, prerequisites + # Set the log level. console.set_log_level(loglevel) @@ -138,12 +130,14 @@ def _run( env: constants.Env = constants.Env.DEV, frontend: bool = True, backend: bool = True, - frontend_port: str = str(get_config().frontend_port), - backend_port: str = str(get_config().backend_port), + frontend_port: str = str(config.frontend_port), + backend_port: str = str(config.backend_port), backend_host: str = config.backend_host, loglevel: constants.LogLevel = config.loglevel, ): """Run the app in the given directory.""" + from reflex.utils import build, exec, prerequisites, processes + # Set the log level. console.set_log_level(loglevel) @@ -279,10 +273,12 @@ def export( hidden=True, ), loglevel: constants.LogLevel = typer.Option( - console._LOG_LEVEL, help="The log level to use." + config.loglevel, help="The log level to use." ), ): """Export the app to a zip file.""" + from reflex.utils import build, exec, prerequisites + # Set the log level. console.set_log_level(loglevel) @@ -320,10 +316,12 @@ def export( @cli.command() def login( loglevel: constants.LogLevel = typer.Option( - config.loglevel, help="The log level to use." + constants.LogLevel.DEBUG, help="The log level to use." ), ): """Authenticate with Reflex hosting service.""" + from reflex.utils import hosting + # Set the log level. console.set_log_level(loglevel) @@ -345,10 +343,12 @@ def login( @cli.command() def logout( loglevel: constants.LogLevel = typer.Option( - config.loglevel, help="The log level to use." + constants.LogLevel.DEBUG, help="The log level to use." ), ): """Log out of access to Reflex hosting service.""" + from reflex.utils import hosting + console.set_log_level(loglevel) hosting.log_out_on_browser() @@ -367,6 +367,9 @@ def _skip_compile(): @db_cli.command(name="init") def db_init(): """Create database schema and migration configuration.""" + from reflex import model + from reflex.utils import prerequisites + # Check the database url. if config.db_url is None: console.error("db_url is not configured, cannot initialize.") @@ -392,6 +395,9 @@ def db_init(): @db_cli.command() def migrate(): """Create or update database schema from migration scripts.""" + from reflex import model + from reflex.utils import prerequisites + _skip_compile() prerequisites.get_app() if not prerequisites.check_db_initialized(): @@ -407,6 +413,11 @@ def makemigrations( ), ): """Create autogenerated alembic migration scripts.""" + from alembic.util.exc import CommandError + + from reflex import model + from reflex.utils import prerequisites + _skip_compile() prerequisites.get_app() if not prerequisites.check_db_initialized(): @@ -493,6 +504,8 @@ def deploy( ), ): """Deploy the app to the Reflex hosting service.""" + from reflex.utils import hosting, prerequisites + # Set the log level. console.set_log_level(loglevel) @@ -732,6 +745,8 @@ def list_deployments( ), ): """List all the hosted deployments of the authenticated user.""" + from reflex.utils import hosting + console.set_log_level(loglevel) try: deployments = hosting.list_deployments() @@ -759,6 +774,8 @@ def delete_deployment( ), ): """Delete a hosted instance.""" + from reflex.utils import hosting + console.set_log_level(loglevel) try: hosting.delete_deployment(key) @@ -776,6 +793,8 @@ def get_deployment_status( ), ): """Check the status of a deployment.""" + from reflex.utils import hosting + console.set_log_level(loglevel) try: @@ -812,6 +831,8 @@ def get_deployment_logs( ), ): """Get the logs for a deployment.""" + from reflex.utils import hosting + console.set_log_level(loglevel) console.print("Note: there is a few seconds delay for logs to be available.") try: @@ -829,6 +850,8 @@ def get_deployment_build_logs( ), ): """Get the logs for a deployment.""" + from reflex.utils import hosting + console.set_log_level(loglevel) console.print("Note: there is a few seconds delay for logs to be available.") @@ -852,6 +875,8 @@ def get_deployment_regions( ), ): """List all the regions of the hosting service.""" + from reflex.utils import hosting + console.set_log_level(loglevel) list_regions_info = hosting.get_regions() if as_json: diff --git a/reflex/utils/exec.py b/reflex/utils/exec.py index e63f1e718c..04b225a18d 100644 --- a/reflex/utils/exec.py +++ b/reflex/utils/exec.py @@ -12,11 +12,10 @@ from urllib.parse import urljoin import psutil -import uvicorn from reflex import constants from reflex.config import get_config -from reflex.utils import console, path_ops, prerequisites, processes +from reflex.utils import console, path_ops from reflex.utils.watch import AssetFolderWatch @@ -73,6 +72,8 @@ def run_process_and_launch_url(run_command: list[str]): Args: run_command: The command to run. """ + from reflex.utils import processes + json_file_path = os.path.join(constants.Dirs.WEB, "package.json") last_hash = detect_package_change(json_file_path) process = None @@ -113,6 +114,8 @@ def run_frontend(root: Path, port: str): root: The root path of the project. port: The port to run the frontend on. """ + from reflex.utils import prerequisites + # Start watching asset folder. start_watching_assets_folder(root) # validate dependencies before run @@ -131,6 +134,8 @@ def run_frontend_prod(root: Path, port: str): root: The root path of the project (to keep same API as run_frontend). port: The port to run the frontend on. """ + from reflex.utils import prerequisites + # Set the port. os.environ["PORT"] = str(get_config().frontend_port if port is None else port) # validate dependencies before run @@ -152,6 +157,8 @@ def run_backend( port: The app port loglevel: The log level. """ + import uvicorn + config = get_config() app_module = f"{config.app_name}.{config.app_name}:{constants.CompileVars.APP}" @@ -183,6 +190,8 @@ def run_backend_prod( port: The app port loglevel: The log level. """ + from reflex.utils import processes + num_workers = processes.get_num_workers() config = get_config() RUN_BACKEND_PROD = f"gunicorn --worker-class {config.gunicorn_worker_class} --preload --timeout {config.timeout} --log-level critical".split() @@ -227,6 +236,8 @@ def output_system_info(): if console._LOG_LEVEL > constants.LogLevel.DEBUG: return + from reflex.utils import prerequisites + config = get_config() try: config_file = sys.modules[config.__module__].__file__ diff --git a/reflex/utils/telemetry.py b/reflex/utils/telemetry.py index 5eaf2fc13b..d6dd61d54d 100644 --- a/reflex/utils/telemetry.py +++ b/reflex/utils/telemetry.py @@ -7,12 +7,9 @@ import platform from datetime import datetime -import httpx import psutil from reflex import constants -from reflex.base import Base -from reflex.config import get_config def get_os() -> str: @@ -60,16 +57,6 @@ def get_memory() -> int: return psutil.virtual_memory().total >> 20 -class Telemetry(Base): - """Anonymous telemetry for Reflex.""" - - user_os: str = get_os() - cpu_count: int = get_cpu_count() - memory: int = get_memory() - reflex_version: str = get_reflex_version() - python_version: str = get_python_version() - - def send(event: str, telemetry_enabled: bool | None = None) -> bool: """Send anonymous telemetry for Reflex. @@ -80,6 +67,10 @@ def send(event: str, telemetry_enabled: bool | None = None) -> bool: Returns: Whether the telemetry was sent successfully. """ + import httpx + + from reflex.config import get_config + # Get the telemetry_enabled from the config if it is not specified. if telemetry_enabled is None: telemetry_enabled = get_config().telemetry_enabled @@ -89,7 +80,6 @@ def send(event: str, telemetry_enabled: bool | None = None) -> bool: return False try: - telemetry = Telemetry() with open(constants.Dirs.REFLEX_JSON) as f: reflex_json = json.load(f) distinct_id = reflex_json["project_hash"] @@ -98,11 +88,11 @@ def send(event: str, telemetry_enabled: bool | None = None) -> bool: "event": event, "properties": { "distinct_id": distinct_id, - "user_os": telemetry.user_os, - "reflex_version": telemetry.reflex_version, - "python_version": telemetry.python_version, - "cpu_count": telemetry.cpu_count, - "memory": telemetry.memory, + "user_os": get_os(), + "reflex_version": get_reflex_version(), + "python_version": get_python_version(), + "cpu_count": get_cpu_count(), + "memory": get_memory(), }, "timestamp": datetime.utcnow().isoformat(), } diff --git a/tests/test_telemetry.py b/tests/test_telemetry.py index f4d35ec4c5..98e5d558ad 100644 --- a/tests/test_telemetry.py +++ b/tests/test_telemetry.py @@ -1,5 +1,3 @@ -import json - from reflex.utils import telemetry @@ -9,32 +7,24 @@ def versiontuple(v): def test_telemetry(): """Test that telemetry is sent correctly.""" - tel = telemetry.Telemetry() - # Check that the user OS is one of the supported operating systems. - assert tel.user_os is not None - assert tel.user_os in ["Linux", "Darwin", "Java", "Windows"] + user_os = telemetry.get_os() + assert user_os is not None + assert user_os in ["Linux", "Darwin", "Java", "Windows"] # Check that the CPU count and memory are greater than 0. - assert tel.cpu_count > 0 + assert telemetry.get_cpu_count() > 0 # Check that the available memory is greater than 0 - assert tel.memory > 0 + assert telemetry.get_memory() > 0 # Check that the Reflex version is not None. - assert tel.reflex_version is not None + assert telemetry.get_reflex_version() is not None # Check that the Python version is greater than 3.7. - assert tel.python_version is not None - assert versiontuple(tel.python_version) >= versiontuple("3.7") - - # Check the json method. - tel_json = json.loads(tel.json()) - assert tel_json["user_os"] == tel.user_os - assert tel_json["cpu_count"] == tel.cpu_count - assert tel_json["memory"] == tel.memory - assert tel_json["reflex_version"] == tel.reflex_version - assert tel_json["python_version"] == tel.python_version + python_version = telemetry.get_python_version() + assert python_version is not None + assert versiontuple(python_version) >= versiontuple("3.7") def test_disable(): From 117804704b2596800ab5251dd31368db0f810f7c Mon Sep 17 00:00:00 2001 From: Nikhil Rao Date: Wed, 15 Nov 2023 18:20:01 -0800 Subject: [PATCH 2/2] Fix default log levels --- reflex/reflex.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reflex/reflex.py b/reflex/reflex.py index 3364e506f1..91bcec60cd 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -316,7 +316,7 @@ def export( @cli.command() def login( loglevel: constants.LogLevel = typer.Option( - constants.LogLevel.DEBUG, help="The log level to use." + config.loglevel, help="The log level to use." ), ): """Authenticate with Reflex hosting service.""" @@ -343,7 +343,7 @@ def login( @cli.command() def logout( loglevel: constants.LogLevel = typer.Option( - constants.LogLevel.DEBUG, help="The log level to use." + config.loglevel, help="The log level to use." ), ): """Log out of access to Reflex hosting service."""