Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speed up reflex CLI imports #2185

Merged
merged 2 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
55 changes: 40 additions & 15 deletions reflex/reflex.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -324,6 +320,8 @@ def login(
),
):
"""Authenticate with Reflex hosting service."""
from reflex.utils import hosting

# Set the log level.
console.set_log_level(loglevel)

Expand All @@ -349,6 +347,8 @@ def logout(
),
):
"""Log out of access to Reflex hosting service."""
from reflex.utils import hosting

console.set_log_level(loglevel)

hosting.log_out_on_browser()
Expand All @@ -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.")
Expand All @@ -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():
Expand All @@ -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():
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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)
Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -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.")
Expand All @@ -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:
Expand Down
15 changes: 13 additions & 2 deletions reflex/utils/exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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}"

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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__
Expand Down
28 changes: 9 additions & 19 deletions reflex/utils/telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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.

Expand All @@ -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
Expand All @@ -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"]
Expand All @@ -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(),
}
Expand Down
28 changes: 9 additions & 19 deletions tests/test_telemetry.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import json

from reflex.utils import telemetry


Expand All @@ -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():
Expand Down