feat: improve CLI parameter handling and cleanup unused code (#4002)

* chore: remove envvar parameter from CLI option

* chore: add show_default=False flag to CLI option

* chore: update argument type to accept None

* feat: add missing Settings to CLI options

* feat: add default path value for components

* chore: rename CLI parameters to match Settings

* feat: update function to enforce parameter hierarchy

CLI > specific env_file > default env_file

* fix: adjust CLI parameter code to pass unit tests

* fix: mypy error arg-type

* fix: little ajustments
This commit is contained in:
Ítalo Johnny 2024-10-03 13:10:04 -03:00 • committed by GitHub
commit ed7ec6a332
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 90 additions and 61 deletions

View file

@ -243,7 +243,7 @@ start:
ifeq ($(open_browser),false) ifeq ($(open_browser),false)
@make install_backend && uv run langflow run \ @make install_backend && uv run langflow run \
--path $(path) \ --frontend-path $(path) \
--log-level $(log_level) \ --log-level $(log_level) \
--host $(host) \ --host $(host) \
--port $(port) \ --port $(port) \
@ -251,7 +251,7 @@ ifeq ($(open_browser),false)
--no-open-browser --no-open-browser
else else
@make install_backend && uv run langflow run \ @make install_backend && uv run langflow run \
--path $(path) \ --frontend-path $(path) \
--log-level $(log_level) \ --log-level $(log_level) \
--host $(host) \ --host $(host) \
--port $(port) \ --port $(port) \
@ -262,7 +262,7 @@ setup_devcontainer: ## set up the development container
make install_backend make install_backend
make install_frontend make install_frontend
make build_frontend make build_frontend
uv run langflow --path src/frontend/build uv run langflow --frontend-path src/frontend/build
setup_env: ## set up the environment setup_env: ## set up the environment
@sh ./scripts/setup/setup_env.sh @sh ./scripts/setup/setup_env.sh

View file

@ -1,3 +1,4 @@
import inspect
import platform import platform
import socket import socket
import sys import sys
@ -28,7 +29,6 @@ from langflow.services.database.utils import session_getter
from langflow.services.deps import get_db_service, get_settings_service, session_scope from langflow.services.deps import get_db_service, get_settings_service, session_scope
from langflow.services.settings.constants import DEFAULT_SUPERUSER from langflow.services.settings.constants import DEFAULT_SUPERUSER
from langflow.services.utils import initialize_services from langflow.services.utils import initialize_services
from langflow.utils.util import update_settings
from langflow.utils.version import fetch_latest_version, get_version_info from langflow.utils.version import fetch_latest_version, get_version_info
from langflow.utils.version import is_pre_release as langflow_is_pre_release from langflow.utils.version import is_pre_release as langflow_is_pre_release
@ -79,69 +79,73 @@ def set_var_for_macos_issue():
@app.command() @app.command()
def run( def run(
host: str = typer.Option("127.0.0.1", help="Host to bind the server to.", envvar="LANGFLOW_HOST"), host: str | None = typer.Option(None, help="Host to bind the server to.", show_default=False),
workers: int = typer.Option(1, help="Number of worker processes.", envvar="LANGFLOW_WORKERS"), workers: int | None = typer.Option(None, help="Number of worker processes.", show_default=False),
timeout: int = typer.Option(300, help="Worker timeout in seconds.", envvar="LANGFLOW_WORKER_TIMEOUT"), worker_timeout: int | None = typer.Option(None, help="Worker timeout in seconds.", show_default=False),
port: int = typer.Option(7860, help="Port to listen on.", envvar="LANGFLOW_PORT"), port: int | None = typer.Option(None, help="Port to listen on.", show_default=False),
components_path: Path | None = typer.Option( components_path: Path | None = typer.Option(
Path(__file__).parent / "components", Path(__file__).parent / "components",
help="Path to the directory containing custom components.", help="Path to the directory containing custom components.",
envvar="LANGFLOW_COMPONENTS_PATH", show_default=False,
), ),
# .env file param # .env file param
env_file: Path = typer.Option(None, help="Path to the .env file containing environment variables."), env_file: Path | None = typer.Option(
log_level: str = typer.Option("critical", help="Logging level.", envvar="LANGFLOW_LOG_LEVEL"), None,
log_file: Path = typer.Option("logs/langflow.log", help="Path to the log file.", envvar="LANGFLOW_LOG_FILE"), help="Path to the .env file containing environment variables.",
cache: str | None = typer.Option( show_default=False,
envvar="LANGFLOW_LANGCHAIN_CACHE",
help="Type of cache to use. (InMemoryCache, SQLiteCache)",
default=None,
), ),
dev: bool = typer.Option(False, help="Run in development mode (may contain bugs)"), log_level: str | None = typer.Option(None, help="Logging level.", show_default=False),
path: str = typer.Option( log_file: Path | None = typer.Option(None, help="Path to the log file.", show_default=False),
cache: str | None = typer.Option(
None,
help="Type of cache to use. (InMemoryCache, SQLiteCache)",
show_default=False,
),
dev: bool | None = typer.Option(None, help="Run in development mode (may contain bugs)", show_default=False),
frontend_path: str | None = typer.Option(
None, None,
help="Path to the frontend directory containing build files. This is for development purposes only.", help="Path to the frontend directory containing build files. This is for development purposes only.",
envvar="LANGFLOW_FRONTEND_PATH", show_default=False,
), ),
open_browser: bool = typer.Option( open_browser: bool | None = typer.Option(
True, None,
help="Open the browser after starting the server.", help="Open the browser after starting the server.",
envvar="LANGFLOW_OPEN_BROWSER", show_default=False,
), ),
remove_api_keys: bool = typer.Option( remove_api_keys: bool | None = typer.Option(
False, None,
help="Remove API keys from the projects saved in the database.", help="Remove API keys from the projects saved in the database.",
envvar="LANGFLOW_REMOVE_API_KEYS", show_default=False,
), ),
backend_only: bool = typer.Option( backend_only: bool | None = typer.Option(
False, None,
help="Run only the backend server without the frontend.", help="Run only the backend server without the frontend.",
envvar="LANGFLOW_BACKEND_ONLY", show_default=False,
), ),
store: bool = typer.Option( store: bool | None = typer.Option(
True, None,
help="Enables the store features.", help="Enables the store features.",
envvar="LANGFLOW_STORE", show_default=False,
), ),
auto_saving: bool = typer.Option( auto_saving: bool | None = typer.Option(
True, None,
help="Defines if the auto save is enabled.", help="Defines if the auto save is enabled.",
envvar="LANGFLOW_AUTO_SAVING", show_default=False,
), ),
auto_saving_interval: int = typer.Option( auto_saving_interval: int | None = typer.Option(
1000, None,
help="Defines the debounce time for the auto save.", help="Defines the debounce time for the auto save.",
envvar="LANGFLOW_AUTO_SAVING_INTERVAL", show_default=False,
), ),
health_check_max_retries: bool = typer.Option( health_check_max_retries: bool | None = typer.Option(
True, None,
help="Defines the number of retries for the health check.", help="Defines the number of retries for the health check.",
envvar="LANGFLOW_HEALTH_CHECK_MAX_RETRIES", show_default=False,
), ),
max_file_size_upload: int = typer.Option( max_file_size_upload: int | None = typer.Option(
100, None,
help="Defines the maximum file size for the upload in MB.", help="Defines the maximum file size for the upload in MB.",
envvar="LANGFLOW_MAX_FILE_SIZE_UPLOAD", show_default=False,
), ),
): ):
""" """
@ -153,33 +157,44 @@ def run(
if env_file: if env_file:
load_dotenv(env_file, override=True) load_dotenv(env_file, override=True)
logger.debug(f"Loading config from file: '{env_file}'")
update_settings(
dev=dev,
remove_api_keys=remove_api_keys,
cache=cache,
components_path=components_path,
store=store,
auto_saving=auto_saving,
auto_saving_interval=auto_saving_interval,
health_check_max_retries=health_check_max_retries,
max_file_size_upload=max_file_size_upload,
)
# create path object if path is provided
static_files_dir: Path | None = Path(path) if path else None
settings_service = get_settings_service() settings_service = get_settings_service()
settings_service.set("backend_only", backend_only)
frame = inspect.currentframe()
valid_args: list = []
values: dict = {}
if frame is not None:
arguments, _, _, values = inspect.getargvalues(frame)
valid_args = [arg for arg in arguments if values[arg] is not None]
for arg in valid_args:
if arg == "components_path":
settings_service.settings.update_settings(components_path=components_path)
elif hasattr(settings_service.settings, arg):
settings_service.set(arg, values[arg])
logger.debug(f"Loading config from cli parameter '{arg}': '{values[arg]}'")
host = settings_service.settings.host
port = settings_service.settings.port
workers = settings_service.settings.workers
worker_timeout = settings_service.settings.worker_timeout
log_level = settings_service.settings.log_level
frontend_path = settings_service.settings.frontend_path
backend_only = settings_service.settings.backend_only
# create path object if frontend_path is provided
static_files_dir: Path | None = Path(frontend_path) if frontend_path else None
app = setup_app(static_files_dir=static_files_dir, backend_only=backend_only) app = setup_app(static_files_dir=static_files_dir, backend_only=backend_only)
# check if port is being used # check if port is being used
if is_port_in_use(port, host): if is_port_in_use(port, host):
port = get_free_port(port) port = get_free_port(port)
settings_service.set("worker_timeout", timeout)
options = { options = {
"bind": f"{host}:{port}", "bind": f"{host}:{port}",
"workers": get_number_of_workers(workers), "workers": get_number_of_workers(workers),
"timeout": timeout, "timeout": worker_timeout,
} }
# Define an env variable to know if we are just testing the server # Define an env variable to know if we are just testing the server
@ -472,7 +487,7 @@ def migration(
@app.command() @app.command()
def api_key( def api_key(
log_level: str = typer.Option("error", help="Logging level.", envvar="LANGFLOW_LOG_LEVEL"), log_level: str = typer.Option("error", help="Logging level."),
): ):
""" """
Creates an API key for the default superuser if AUTO_LOGIN is enabled. Creates an API key for the default superuser if AUTO_LOGIN is enabled.

View file

@ -146,6 +146,20 @@ class Settings(BaseSettings):
"""If set to True, Langflow will keep track of each vertex builds (outputs) in the UI for any flow.""" """If set to True, Langflow will keep track of each vertex builds (outputs) in the UI for any flow."""
# Config # Config
host: str = "127.0.0.1"
"""The host on which Langflow will run."""
port: int = 7860
"""The port on which Langflow will run."""
workers: int = 1
"""The number of workers to run."""
log_level: str = "critical"
"""The log level for Langflow."""
log_file: str | None = "logs/langflow.log"
"""The path to log file for Langflow."""
frontend_path: str | None = None
"""The path to the frontend directory containing build files. This is for development purposes only.."""
open_browser: bool = False
"""If set to True, Langflow will open the browser on startup."""
auto_saving: bool = True auto_saving: bool = True
"""If set to True, Langflow will auto save flows.""" """If set to True, Langflow will auto save flows."""
auto_saving_interval: int = 1000 auto_saving_interval: int = 1000