From f729d897970ef4ade010750e63768e17736f9678 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Tue, 22 Apr 2025 22:30:29 -0700 Subject: [PATCH 1/3] reattempt at granian as default --- pyproject.toml | 4 ++-- reflex/utils/exec.py | 26 +++++++++++--------------- uv.lock | 18 ++---------------- 3 files changed, 15 insertions(+), 33 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9fe53e2f830..b6d566f177d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,6 @@ dependencies = [ "alembic >=1.15.2,<2.0", "fastapi >=0.115.0", "granian[reload] >=2.2.5", - "gunicorn >=23.0.0,<24.0.0", "httpx >=0.28.0,<1.0", "jinja2 >=3.1.2,<4.0", "packaging >=24.2,<26", @@ -38,7 +37,6 @@ dependencies = [ "sqlmodel >=0.0.24,<0.1", "typer >=0.15.2,<1.0", "typing_extensions >=4.13.0", - "uvicorn >=0.34.0", "wrapt >=1.17.0,<2.0", ] classifiers = [ @@ -166,4 +164,6 @@ dev = [ "ruff >=0.11", "selenium >=4.31", "starlette-admin >=0.14", + "uvicorn >=0.34.0", + ] diff --git a/reflex/utils/exec.py b/reflex/utils/exec.py index 2022a45e250..09f7500a8ca 100644 --- a/reflex/utils/exec.py +++ b/reflex/utils/exec.py @@ -189,11 +189,9 @@ def run_frontend_prod(root: Path, port: str, backend_present: bool = True): @once def _warn_user_about_uvicorn(): - # When we eventually switch to Granian by default, we should enable this warning. - if False: - console.warn( - "Using Uvicorn for backend as it is installed. This behavior will change in 0.8.0 to use Granian by default." - ) + console.warn( + "Using Uvicorn for backend as it is installed. This behavior will change in 0.8.0 to use Granian by default." + ) def should_use_granian(): @@ -202,8 +200,8 @@ def should_use_granian(): Returns: True if Granian should be used. """ - if environment.REFLEX_USE_GRANIAN.get(): - return True + if environment.REFLEX_USE_GRANIAN.is_set(): + return environment.REFLEX_USE_GRANIAN.get() if ( importlib.util.find_spec("uvicorn") is None or importlib.util.find_spec("gunicorn") is None @@ -367,14 +365,12 @@ def _deprecate_asgi_config( config_name: str, reason: str = "", ): - # When we eventually switch to Granian by default, we should enable this deprecation. - if False: - console.deprecate( - f"config.{config_name}", - reason=reason, - deprecation_version="0.7.5", - removal_version="0.8.0", - ) + console.deprecate( + f"config.{config_name}", + reason=reason, + deprecation_version="0.7.9", + removal_version="0.8.0", + ) @once diff --git a/uv.lock b/uv.lock index 54ab717fbb9..f216e30e0fb 100644 --- a/uv.lock +++ b/uv.lock @@ -492,18 +492,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/80/7b/773a30602234597fc2882091f8e1d1a38ea0b4419d99ca7ed82c827e2c3a/greenlet-3.2.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:397b6bbda06f8fe895893d96218cd6f6d855a6701dc45012ebe12262423cec8b", size = 269908 }, ] -[[package]] -name = "gunicorn" -version = "23.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/34/72/9614c465dc206155d93eff0ca20d42e1e35afc533971379482de953521a4/gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec", size = 375031 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029 }, -] - [[package]] name = "h11" version = "0.14.0" @@ -1528,7 +1516,6 @@ dependencies = [ { name = "alembic" }, { name = "fastapi" }, { name = "granian", extra = ["reload"] }, - { name = "gunicorn" }, { name = "httpx" }, { name = "jinja2" }, { name = "packaging" }, @@ -1543,7 +1530,6 @@ dependencies = [ { name = "sqlmodel" }, { name = "typer" }, { name = "typing-extensions" }, - { name = "uvicorn" }, { name = "wrapt" }, ] @@ -1575,6 +1561,7 @@ dev = [ { name = "ruff" }, { name = "selenium" }, { name = "starlette-admin" }, + { name = "uvicorn" }, ] [package.metadata] @@ -1582,7 +1569,6 @@ requires-dist = [ { name = "alembic", specifier = ">=1.15.2,<2.0" }, { name = "fastapi", specifier = ">=0.115.0" }, { name = "granian", extras = ["reload"], specifier = ">=2.2.5" }, - { name = "gunicorn", specifier = ">=23.0.0,<24.0.0" }, { name = "httpx", specifier = ">=0.28.0,<1.0" }, { name = "jinja2", specifier = ">=3.1.2,<4.0" }, { name = "packaging", specifier = ">=24.2,<26" }, @@ -1597,7 +1583,6 @@ requires-dist = [ { name = "sqlmodel", specifier = ">=0.0.24,<0.1" }, { name = "typer", specifier = ">=0.15.2,<1.0" }, { name = "typing-extensions", specifier = ">=4.13.0" }, - { name = "uvicorn", specifier = ">=0.34.0" }, { name = "wrapt", specifier = ">=1.17.0,<2.0" }, ] @@ -1629,6 +1614,7 @@ dev = [ { name = "ruff", specifier = ">=0.11" }, { name = "selenium", specifier = ">=4.31" }, { name = "starlette-admin", specifier = ">=0.14" }, + { name = "uvicorn", specifier = ">=0.34.0" }, ] [[package]] From 146bd67d23b3c70583f639f0c57a13ff4282f298 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 23 Apr 2025 00:19:19 -0700 Subject: [PATCH 2/3] use filename instead of module --- reflex/utils/exec.py | 50 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/reflex/utils/exec.py b/reflex/utils/exec.py index 09f7500a8ca..7ed8e54a01b 100644 --- a/reflex/utils/exec.py +++ b/reflex/utils/exec.py @@ -217,9 +217,47 @@ def get_app_module(): Returns: The app module for the backend. """ - config = get_config() + return get_config().module + + +def get_app_instance(): + """Get the app module for the backend. + + Returns: + The app module for the backend. + """ + return f"{get_app_module()}:{constants.CompileVars.APP}" + + +def get_app_file() -> Path: + """Get the app file for the backend. + + Returns: + The app file for the backend. + + Raises: + ImportError: If the app module is not found. + """ + module_spec = importlib.util.find_spec(get_app_module()) + if module_spec is None: + raise ImportError( + f"Module {get_app_module()} not found. Make sure the module is installed." + ) + file_name = module_spec.origin + if file_name is None: + raise ImportError( + f"Module {get_app_module()} not found. Make sure the module is installed." + ) + return Path(file_name).resolve() + - return f"{config.module}:{constants.CompileVars.APP}" +def get_app_instance_from_file() -> str: + """Get the app module for the backend. + + Returns: + The app module for the backend. + """ + return f"{get_app_file()}:{constants.CompileVars.APP}" def run_backend( @@ -321,7 +359,7 @@ def run_uvicorn_backend(host: str, port: int, loglevel: LogLevel): import uvicorn uvicorn.run( - app=f"{get_app_module()}", + app=f"{get_app_instance()}", factory=True, host=host, port=port, @@ -347,7 +385,7 @@ def run_granian_backend(host: str, port: int, loglevel: LogLevel): from granian.server import MPServer as Granian Granian( - target=get_app_module(), + target=get_app_instance_from_file(), factory=True, address=host, port=port, @@ -464,7 +502,7 @@ def run_uvicorn_backend_prod(host: str, port: int, loglevel: LogLevel): config = get_config() - app_module = get_app_module() + app_module = get_app_instance() command = ( [ @@ -564,7 +602,7 @@ def run_granian_backend_prod(host: str, port: int, loglevel: LogLevel): *("--host", host), *("--port", str(port)), *("--interface", str(Interfaces.ASGI)), - *("--factory", get_app_module()), + *("--factory", get_app_instance_from_file()), ] processes.new_process( command, From 14d841c45fd1dfb815e640c0fa28db1c3becfc3d Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 23 Apr 2025 10:59:55 -0700 Subject: [PATCH 3/3] current_work_directory --- reflex/utils/exec.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/reflex/utils/exec.py b/reflex/utils/exec.py index 7ed8e54a01b..618ae73aa3d 100644 --- a/reflex/utils/exec.py +++ b/reflex/utils/exec.py @@ -238,6 +238,10 @@ def get_app_file() -> Path: Raises: ImportError: If the app module is not found. """ + current_working_dir = str(Path.cwd()) + if current_working_dir not in sys.path: + # Add the current working directory to sys.path + sys.path.insert(0, current_working_dir) module_spec = importlib.util.find_spec(get_app_module()) if module_spec is None: raise ImportError(