From 78b9dda002efc7cade0f9fddf2c537412a81ba65 Mon Sep 17 00:00:00 2001 From: VishnuSanal Date: Wed, 19 Jun 2024 19:11:18 +0530 Subject: [PATCH 1/7] fixes #654 --- robyn/__init__.py | 36 +++++++++++++++++++----------------- robyn/argument_parser.py | 3 +++ robyn/cli.py | 2 +- robyn/reloader.py | 26 ++++++++++++++++++-------- 4 files changed, 41 insertions(+), 26 deletions(-) diff --git a/robyn/__init__.py b/robyn/__init__.py index 656f1a91f..23f8c68e6 100644 --- a/robyn/__init__.py +++ b/robyn/__init__.py @@ -10,6 +10,7 @@ from robyn import status_codes from robyn.argument_parser import Config from robyn.authentication import AuthenticationHandler +from robyn.cli import start_dev_server from robyn.dependency_injection import DependencyMap from robyn.env_populator import load_vars from robyn.events import Events @@ -56,8 +57,6 @@ def __init__( "SERVER IS RUNNING IN VERBOSE/DEBUG MODE. Set --log-level to WARN to run in production mode.", color=Colors.BLUE, ) - if self.config.dev: - exit("Dev mode is not supported in the python wrapper. Please use the CLI. e.g. python3 -m robyn app.py --dev ") self.router = Router() self.middleware_router = MiddlewareRouter() @@ -225,21 +224,24 @@ def start(self, host: str = "127.0.0.1", port: int = 8080, _check_port: bool = T mp.allow_connection_pickling() - run_processes( - host, - port, - self.directories, - self.request_headers, - self.router.get_routes(), - self.middleware_router.get_global_middlewares(), - self.middleware_router.get_route_middlewares(), - self.web_socket_router.get_routes(), - self.event_handlers, - self.config.workers, - self.config.processes, - self.response_headers, - open_browser, - ) + if self.config.dev: + start_dev_server(self.config, self.config.file_path) + else: + run_processes( + host, + port, + self.directories, + self.request_headers, + self.router.get_routes(), + self.middleware_router.get_global_middlewares(), + self.middleware_router.get_route_middlewares(), + self.web_socket_router.get_routes(), + self.event_handlers, + self.config.workers, + self.config.processes, + self.response_headers, + open_browser, + ) def exception(self, exception_handler: Callable): self.exception_handler = exception_handler diff --git a/robyn/argument_parser.py b/robyn/argument_parser.py index a1b532f9a..ae9a21e30 100644 --- a/robyn/argument_parser.py +++ b/robyn/argument_parser.py @@ -1,4 +1,5 @@ import argparse +import sys class Config: @@ -87,6 +88,8 @@ def __init__(self) -> None: if arg.endswith(".py"): self.file_path = arg break + else: + self.file_path = sys.argv[0] if self.dev and (self.processes != 1 or self.workers != 1): raise Exception("--processes and --workers shouldn't be used with --dev") diff --git a/robyn/cli.py b/robyn/cli.py index 385348890..abc716019 100644 --- a/robyn/cli.py +++ b/robyn/cli.py @@ -84,7 +84,7 @@ def start_dev_server(config: Config, file_path: Optional[str] = None): directory_path = absolute_file_path.parent if config.dev and not os.environ.get("IS_RELOADER_RUNNING", False): - setup_reloader(str(directory_path), str(absolute_file_path)) + setup_reloader(config, str(directory_path), str(absolute_file_path)) return diff --git a/robyn/reloader.py b/robyn/reloader.py index a4e8dfe86..41c3a74c5 100644 --- a/robyn/reloader.py +++ b/robyn/reloader.py @@ -9,6 +9,7 @@ from watchdog.events import FileSystemEventHandler from watchdog.observers import Observer +from robyn import Config from robyn.logger import Colors, logger dir_path = None @@ -58,8 +59,8 @@ def clean_rust_binaries(rust_binaries: List[str]): os.remove(file) -def setup_reloader(directory_path: str, file_path: str): - event_handler = EventHandler(file_path, directory_path) +def setup_reloader(config: Config, directory_path: str, file_path: str): + event_handler = EventHandler(config, file_path, directory_path) event_handler.reload() @@ -91,7 +92,8 @@ def terminating_signal_handler(_sig, _frame): class EventHandler(FileSystemEventHandler): - def __init__(self, file_path: str, directory_path: str) -> None: + def __init__(self, config: Config, file_path: str, directory_path: str) -> None: + self.config = config self.file_path = file_path self.directory_path = directory_path self.process = None # Keep track of the subprocess @@ -115,11 +117,19 @@ def reload(self): clean_rust_binaries(self.built_rust_binaries) self.built_rust_binaries = compile_rust_files(self.directory_path) - self.process = subprocess.Popen( - [sys.executable, *arguments], - env=new_env, - start_new_session=False, - ) + if self.config.dev and self.config.file_path is not None: + subprocess.call(f'cd {"/".join(self.config.file_path.split("/")[-2:-1])}', shell=True) + self.process = subprocess.Popen( + [sys.executable, "-m", self.config.file_path.split("/")[-2], *arguments], + env=new_env, + start_new_session=False, + ) + else: + self.process = subprocess.Popen( + [sys.executable, *arguments], + env=new_env, + start_new_session=False, + ) self.last_reload = time.time() From 6cab870f0c970f24584f1aa00d86b8ed464f9f49 Mon Sep 17 00:00:00 2001 From: VishnuSanal Date: Thu, 20 Jun 2024 14:41:01 +0530 Subject: [PATCH 2/7] [#654] review: refactor `EventHandler#reload` --- robyn/reloader.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/robyn/reloader.py b/robyn/reloader.py index 41c3a74c5..8a37c844f 100644 --- a/robyn/reloader.py +++ b/robyn/reloader.py @@ -118,9 +118,14 @@ def reload(self): self.built_rust_binaries = compile_rust_files(self.directory_path) if self.config.dev and self.config.file_path is not None: - subprocess.call(f'cd {"/".join(self.config.file_path.split("/")[-2:-1])}', shell=True) + split = self.config.file_path.split("/") + + working_directory = "/".join(split[-2:-1]) + + subprocess.call(f"cd {working_directory}", shell=True) + self.process = subprocess.Popen( - [sys.executable, "-m", self.config.file_path.split("/")[-2], *arguments], + [sys.executable, "-m", split[-2], *arguments], env=new_env, start_new_session=False, ) From 7f477885bca36e5287c08ccd80c098591928e72d Mon Sep 17 00:00:00 2001 From: VishnuSanal Date: Fri, 21 Jun 2024 19:28:07 +0530 Subject: [PATCH 3/7] [#654] review: address review comments --- robyn/__init__.py | 5 ++--- robyn/cli.py | 19 ++++--------------- robyn/dev_server.py | 18 ++++++++++++++++++ robyn/reloader.py | 10 +++------- 4 files changed, 27 insertions(+), 25 deletions(-) create mode 100644 robyn/dev_server.py diff --git a/robyn/__init__.py b/robyn/__init__.py index 23f8c68e6..b950d36a7 100644 --- a/robyn/__init__.py +++ b/robyn/__init__.py @@ -7,10 +7,9 @@ import multiprocess as mp from nestd import get_all_nested -from robyn import status_codes +from robyn import status_codes, dev_server from robyn.argument_parser import Config from robyn.authentication import AuthenticationHandler -from robyn.cli import start_dev_server from robyn.dependency_injection import DependencyMap from robyn.env_populator import load_vars from robyn.events import Events @@ -225,7 +224,7 @@ def start(self, host: str = "127.0.0.1", port: int = 8080, _check_port: bool = T mp.allow_connection_pickling() if self.config.dev: - start_dev_server(self.config, self.config.file_path) + dev_server.start_dev_server(self.config, self.config.file_path) else: run_processes( host, diff --git a/robyn/cli.py b/robyn/cli.py index abc716019..ec684cad4 100644 --- a/robyn/cli.py +++ b/robyn/cli.py @@ -1,11 +1,12 @@ import os import sys -from typing import Optional import webbrowser from InquirerPy.resolver import prompt from InquirerPy.base.control import Choice + +from . import dev_server from .argument_parser import Config -from .reloader import create_rust_file, setup_reloader +from .reloader import create_rust_file from robyn.robyn import get_version from pathlib import Path import shutil @@ -76,18 +77,6 @@ def docs(): webbrowser.open("https://robyn.tech") -def start_dev_server(config: Config, file_path: Optional[str] = None): - if file_path is None: - return - - absolute_file_path = (Path.cwd() / file_path).resolve() - directory_path = absolute_file_path.parent - - if config.dev and not os.environ.get("IS_RELOADER_RUNNING", False): - setup_reloader(config, str(directory_path), str(absolute_file_path)) - return - - def start_app_normally(config: Config): # Parsing the known and unknown arguments known_arguments, unknown_args = config.parser.parse_known_args() @@ -118,6 +107,6 @@ def run(): elif config.dev: print("Starting dev server...") - start_dev_server(config, config.file_path) + dev_server.start_dev_server(config, config.file_path) else: start_app_normally(config) diff --git a/robyn/dev_server.py b/robyn/dev_server.py new file mode 100644 index 000000000..e077e2741 --- /dev/null +++ b/robyn/dev_server.py @@ -0,0 +1,18 @@ +import os +from pathlib import Path +from typing import Optional + +from robyn import reloader +from robyn.argument_parser import Config + + +def start_dev_server(config: Config, file_path: Optional[str] = None): + if file_path is None: + return + + absolute_file_path = (Path.cwd() / file_path).resolve() + directory_path = absolute_file_path.parent + + if config.dev and not os.environ.get("IS_RELOADER_RUNNING", False): + reloader.setup_reloader(config, str(directory_path), str(absolute_file_path)) + return diff --git a/robyn/reloader.py b/robyn/reloader.py index 8a37c844f..f2610a302 100644 --- a/robyn/reloader.py +++ b/robyn/reloader.py @@ -9,7 +9,7 @@ from watchdog.events import FileSystemEventHandler from watchdog.observers import Observer -from robyn import Config +from robyn.argument_parser import Config from robyn.logger import Colors, logger dir_path = None @@ -118,14 +118,10 @@ def reload(self): self.built_rust_binaries = compile_rust_files(self.directory_path) if self.config.dev and self.config.file_path is not None: - split = self.config.file_path.split("/") - - working_directory = "/".join(split[-2:-1]) - - subprocess.call(f"cd {working_directory}", shell=True) + module_name = self.config.file_path.split("/")[-2] self.process = subprocess.Popen( - [sys.executable, "-m", split[-2], *arguments], + [sys.executable, "-m", module_name, *arguments], env=new_env, start_new_session=False, ) From 8b06cdd2667cf15fee29c356aed876efa419aac1 Mon Sep 17 00:00:00 2001 From: VishnuSanal Date: Fri, 21 Jun 2024 22:33:51 +0530 Subject: [PATCH 4/7] [#654] review: update imports & docstring --- robyn/__init__.py | 5 +++-- robyn/cli.py | 4 ++-- robyn/dev_server.py | 6 ++++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/robyn/__init__.py b/robyn/__init__.py index b950d36a7..046e20c78 100644 --- a/robyn/__init__.py +++ b/robyn/__init__.py @@ -7,10 +7,11 @@ import multiprocess as mp from nestd import get_all_nested -from robyn import status_codes, dev_server +from robyn import status_codes from robyn.argument_parser import Config from robyn.authentication import AuthenticationHandler from robyn.dependency_injection import DependencyMap +from robyn.dev_server import start_dev_server from robyn.env_populator import load_vars from robyn.events import Events from robyn.jsonify import jsonify @@ -224,7 +225,7 @@ def start(self, host: str = "127.0.0.1", port: int = 8080, _check_port: bool = T mp.allow_connection_pickling() if self.config.dev: - dev_server.start_dev_server(self.config, self.config.file_path) + start_dev_server(self.config, self.config.file_path) else: run_processes( host, diff --git a/robyn/cli.py b/robyn/cli.py index ec684cad4..0496c66c0 100644 --- a/robyn/cli.py +++ b/robyn/cli.py @@ -4,7 +4,7 @@ from InquirerPy.resolver import prompt from InquirerPy.base.control import Choice -from . import dev_server +from robyn.dev_server import start_dev_server from .argument_parser import Config from .reloader import create_rust_file from robyn.robyn import get_version @@ -107,6 +107,6 @@ def run(): elif config.dev: print("Starting dev server...") - dev_server.start_dev_server(config, config.file_path) + start_dev_server(config, config.file_path) else: start_app_normally(config) diff --git a/robyn/dev_server.py b/robyn/dev_server.py index e077e2741..8e55930b0 100644 --- a/robyn/dev_server.py +++ b/robyn/dev_server.py @@ -7,6 +7,12 @@ def start_dev_server(config: Config, file_path: Optional[str] = None): + """ + Start the dev server. Initialize the reloader to monitor file changes + + @param config: the config object + @param file_path: the path to the file + """ if file_path is None: return From 63970c1ceaec87d326969569651b2ed43c58d5e9 Mon Sep 17 00:00:00 2001 From: VishnuSanal Date: Wed, 26 Jun 2024 12:31:00 +0530 Subject: [PATCH 5/7] [#854] review: fix imports --- robyn/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/robyn/cli.py b/robyn/cli.py index 0496c66c0..51f0dab7d 100644 --- a/robyn/cli.py +++ b/robyn/cli.py @@ -5,8 +5,8 @@ from InquirerPy.base.control import Choice from robyn.dev_server import start_dev_server -from .argument_parser import Config -from .reloader import create_rust_file +from robyn.argument_parser import Config +from robyn.reloader import create_rust_file from robyn.robyn import get_version from pathlib import Path import shutil From c72e01a8952de9120fc930909575423c9d109d5c Mon Sep 17 00:00:00 2001 From: VishnuSanal Date: Wed, 26 Jun 2024 13:02:48 +0530 Subject: [PATCH 6/7] [#854] fix: errors when running `robyn app.py --dev` --- robyn/argument_parser.py | 2 ++ robyn/reloader.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/robyn/argument_parser.py b/robyn/argument_parser.py index ae9a21e30..5130af82e 100644 --- a/robyn/argument_parser.py +++ b/robyn/argument_parser.py @@ -82,6 +82,7 @@ def __init__(self) -> None: self.version = args.version self.compile_rust_path = args.compile_rust_path self.create_rust_file = args.create_rust_file + self.running_as_module = False # find something that ends with .py in unknown_args for arg in unknown_args: @@ -90,6 +91,7 @@ def __init__(self) -> None: break else: self.file_path = sys.argv[0] + self.running_as_module = True if self.dev and (self.processes != 1 or self.workers != 1): raise Exception("--processes and --workers shouldn't be used with --dev") diff --git a/robyn/reloader.py b/robyn/reloader.py index f2610a302..325f240e7 100644 --- a/robyn/reloader.py +++ b/robyn/reloader.py @@ -117,7 +117,7 @@ def reload(self): clean_rust_binaries(self.built_rust_binaries) self.built_rust_binaries = compile_rust_files(self.directory_path) - if self.config.dev and self.config.file_path is not None: + if self.config.dev and self.config.running_as_module: module_name = self.config.file_path.split("/")[-2] self.process = subprocess.Popen( From a7272e5941ca7341f19bb1c3f7a7fcac8383c64e Mon Sep 17 00:00:00 2001 From: VishnuSanal Date: Wed, 3 Jul 2024 23:03:49 +0530 Subject: [PATCH 7/7] fix merge conflicts --- robyn/reloader.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/robyn/reloader.py b/robyn/reloader.py index 4b7fc3c1a..7d24cc564 100644 --- a/robyn/reloader.py +++ b/robyn/reloader.py @@ -1,5 +1,5 @@ -import os import glob +import os import signal import subprocess import sys @@ -118,6 +118,10 @@ def reload(self): clean_rust_binaries(self.built_rust_binaries) self.built_rust_binaries = compile_rust_files(self.directory_path) + prev_process = self.process + if prev_process: + prev_process.kill() + if self.config.dev and self.config.running_as_module: module_name = self.config.file_path.split("/")[-2] @@ -132,14 +136,6 @@ def reload(self): env=new_env, start_new_session=False, ) - prev_process = self.process - if prev_process: - prev_process.kill() - - self.process = subprocess.Popen( - [sys.executable, *arguments], - env=new_env, - ) self.last_reload = time.time()