260 lines
6.8 KiB
Python
260 lines
6.8 KiB
Python
"""The Pynecone config."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import os
|
|
import sys
|
|
import urllib.parse
|
|
from typing import List, Optional
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
from pynecone import constants
|
|
from pynecone.admin import AdminDash
|
|
from pynecone.base import Base
|
|
|
|
|
|
class DBConfig(Base):
|
|
"""Database config."""
|
|
|
|
engine: str
|
|
username: Optional[str] = ""
|
|
password: Optional[str] = ""
|
|
host: Optional[str] = ""
|
|
port: Optional[int] = None
|
|
database: str
|
|
|
|
@classmethod
|
|
def postgresql(
|
|
cls,
|
|
database: str,
|
|
username: str,
|
|
password: Optional[str] = None,
|
|
host: Optional[str] = None,
|
|
port: Optional[int] = 5432,
|
|
) -> DBConfig:
|
|
"""Create an instance with postgresql engine.
|
|
|
|
Args:
|
|
database: Database name.
|
|
username: Database username.
|
|
password: Database password.
|
|
host: Database host.
|
|
port: Database port.
|
|
|
|
Returns:
|
|
DBConfig instance.
|
|
"""
|
|
return cls(
|
|
engine="postgresql",
|
|
username=username,
|
|
password=password,
|
|
host=host,
|
|
port=port,
|
|
database=database,
|
|
)
|
|
|
|
@classmethod
|
|
def postgresql_psycopg2(
|
|
cls,
|
|
database: str,
|
|
username: str,
|
|
password: Optional[str] = None,
|
|
host: Optional[str] = None,
|
|
port: Optional[int] = 5432,
|
|
) -> DBConfig:
|
|
"""Create an instance with postgresql+psycopg2 engine.
|
|
|
|
Args:
|
|
database: Database name.
|
|
username: Database username.
|
|
password: Database password.
|
|
host: Database host.
|
|
port: Database port.
|
|
|
|
Returns:
|
|
DBConfig instance.
|
|
"""
|
|
return cls(
|
|
engine="postgresql+psycopg2",
|
|
username=username,
|
|
password=password,
|
|
host=host,
|
|
port=port,
|
|
database=database,
|
|
)
|
|
|
|
@classmethod
|
|
def sqlite(
|
|
cls,
|
|
database: str,
|
|
) -> DBConfig:
|
|
"""Create an instance with sqlite engine.
|
|
|
|
Args:
|
|
database: Database name.
|
|
|
|
Returns:
|
|
DBConfig instance.
|
|
"""
|
|
return cls(
|
|
engine="sqlite",
|
|
database=database,
|
|
)
|
|
|
|
def get_url(self) -> str:
|
|
"""Get database URL.
|
|
|
|
Returns:
|
|
The database URL.
|
|
"""
|
|
host = (
|
|
f"{self.host}:{self.port}" if self.host and self.port else self.host or ""
|
|
)
|
|
username = urllib.parse.quote_plus(self.username) if self.username else ""
|
|
password = urllib.parse.quote_plus(self.password) if self.password else ""
|
|
|
|
if username:
|
|
path = f"{username}:{password}@{host}" if password else f"{username}@{host}"
|
|
else:
|
|
path = f"{host}"
|
|
|
|
return f"{self.engine}://{path}/{self.database}"
|
|
|
|
|
|
class Config(Base):
|
|
"""A Pynecone config."""
|
|
|
|
# The name of the app.
|
|
app_name: str
|
|
|
|
# The username.
|
|
username: Optional[str] = None
|
|
|
|
# The frontend port.
|
|
frontend_port: str = constants.FRONTEND_PORT
|
|
|
|
# The backend port.
|
|
backend_port: str = constants.BACKEND_PORT
|
|
|
|
# The backend host.
|
|
backend_host: str = constants.BACKEND_HOST
|
|
|
|
# The backend API url.
|
|
api_url: str = constants.API_URL
|
|
|
|
# The deploy url.
|
|
deploy_url: Optional[str] = constants.DEPLOY_URL
|
|
|
|
# The database url.
|
|
db_url: Optional[str] = constants.DB_URL
|
|
|
|
# The database config.
|
|
db_config: Optional[DBConfig] = None
|
|
|
|
# The redis url.
|
|
redis_url: Optional[str] = constants.REDIS_URL
|
|
|
|
# Telemetry opt-in.
|
|
telemetry_enabled: bool = True
|
|
|
|
# The pcdeploy url.
|
|
pcdeploy_url: Optional[str] = None
|
|
|
|
# The environment mode.
|
|
env: constants.Env = constants.Env.DEV
|
|
|
|
# The path to the bun executable.
|
|
bun_path: str = constants.BUN_PATH
|
|
|
|
# Disable bun.
|
|
disable_bun: bool = False
|
|
|
|
# Additional frontend packages to install.
|
|
frontend_packages: List[str] = []
|
|
|
|
# The Admin Dash
|
|
admin_dash: Optional[AdminDash] = None
|
|
|
|
# Backend transport methods.
|
|
backend_transports: Optional[
|
|
constants.Transports
|
|
] = constants.Transports.WEBSOCKET_POLLING
|
|
|
|
# List of origins that are allowed to connect to the backend API.
|
|
cors_allowed_origins: Optional[list] = constants.CORS_ALLOWED_ORIGINS
|
|
|
|
# Whether credentials (cookies, authentication) are allowed in requests to the backend API.
|
|
cors_credentials: Optional[bool] = True
|
|
|
|
# The maximum size of a message when using the polling backend transport.
|
|
polling_max_http_buffer_size: Optional[int] = constants.POLLING_MAX_HTTP_BUFFER_SIZE
|
|
|
|
# Dotenv file path
|
|
env_path: Optional[str] = constants.DOT_ENV_FILE
|
|
|
|
# Whether to override OS environment variables
|
|
override_os_envs: Optional[bool] = True
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
"""Initialize the config values.
|
|
|
|
If db_url is not provided gets it from db_config.
|
|
|
|
Args:
|
|
*args: The args to pass to the Pydantic init method.
|
|
**kwargs: The kwargs to pass to the Pydantic init method.
|
|
"""
|
|
if "db_url" not in kwargs and "db_config" in kwargs:
|
|
kwargs["db_url"] = kwargs["db_config"].get_url()
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
# set overriden class attribute values as os env variables to avoid losing them
|
|
for key, value in dict(self).items():
|
|
key = key.upper()
|
|
if (
|
|
key.startswith("_")
|
|
or key in os.environ
|
|
or (value is None and key != "DB_URL")
|
|
):
|
|
continue
|
|
os.environ[key] = str(value)
|
|
|
|
# Avoid overriding if env_path is not provided or does not exist
|
|
if self.env_path is not None and os.path.isfile(self.env_path):
|
|
load_dotenv(self.env_path, override=self.override_os_envs) # type: ignore
|
|
# Recompute constants after loading env variables
|
|
importlib.reload(constants)
|
|
# Recompute instance attributes
|
|
self.recompute_field_values()
|
|
|
|
def recompute_field_values(self):
|
|
"""Recompute instance field values to reflect new values after reloading
|
|
constant values.
|
|
"""
|
|
for field in self.get_fields():
|
|
try:
|
|
if field.startswith("_"):
|
|
continue
|
|
setattr(self, field, getattr(constants, f"{field.upper()}"))
|
|
except AttributeError:
|
|
pass
|
|
|
|
|
|
def get_config() -> Config:
|
|
"""Get the app config.
|
|
|
|
Returns:
|
|
The app config.
|
|
"""
|
|
from pynecone.config import Config
|
|
|
|
sys.path.append(os.getcwd())
|
|
try:
|
|
return __import__(constants.CONFIG_MODULE).config
|
|
|
|
except ImportError:
|
|
return Config(app_name="") # type: ignore
|