123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- """The Pynecone config."""
- from __future__ import annotations
- import importlib
- import os
- import sys
- import urllib.parse
- from typing import Any, Dict, 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
- # Tailwind config.
- tailwind: Optional[Dict[str, Any]] = None
- # Timeout when launching the gunicorn server.
- timeout: int = constants.TIMEOUT
- 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
|