2022-01-18 23:46:10 +08:00
""" 本模块定义了 NoneBot 本身运行所需的配置项。
2020-08-20 16:34:07 +08:00
2023-06-24 14:47:35 +08:00
NoneBot 使用 [ ` pydantic ` ] ( https : / / pydantic - docs . helpmanual . io / ) 以及
[ ` python - dotenv ` ] ( https : / / saurabh - kumar . com / python - dotenv / ) 来读取配置 。
2020-08-20 16:34:07 +08:00
2023-06-24 14:47:35 +08:00
配置项需符合特殊格式或 json 序列化格式
详情见 [ ` pydantic Field Type ` ] ( https : / / pydantic - docs . helpmanual . io / usage / types / ) 文档 。
2022-01-16 11:30:09 +08:00
FrontMatter :
2024-10-22 10:33:48 +08:00
mdx :
format : md
2022-01-16 11:30:09 +08:00
sidebar_position : 1
description : nonebot . config 模块
2020-08-20 16:34:07 +08:00
"""
2023-06-24 14:47:35 +08:00
2024-01-15 13:24:55 +08:00
import abc
2024-12-01 12:31:11 +08:00
from collections . abc import Mapping
2020-08-06 17:54:55 +08:00
from datetime import timedelta
2020-07-04 22:51:10 +08:00
from ipaddress import IPv4Address
2024-12-01 12:31:11 +08:00
import json
import os
from pathlib import Path
from typing import TYPE_CHECKING , Any , Optional , Union
2024-01-26 11:12:57 +08:00
from typing_extensions import TypeAlias , get_args , get_origin
2020-07-04 22:51:10 +08:00
2024-01-15 13:24:55 +08:00
from dotenv import dotenv_values
2024-12-01 12:31:11 +08:00
from pydantic import BaseModel , Field
2024-01-26 11:12:57 +08:00
from pydantic . networks import IPvAnyAddress
2020-08-07 11:18:02 +08:00
2024-01-26 11:12:57 +08:00
from nonebot . compat import (
PYDANTIC_V2 ,
ConfigDict ,
ModelField ,
PydanticUndefined ,
PydanticUndefinedType ,
model_config ,
model_fields ,
)
2024-12-01 12:31:11 +08:00
from nonebot . log import logger
from nonebot . typing import origin_is_union
from nonebot . utils import deep_update , lenient_issubclass , type_is_complex
2021-12-27 02:26:02 +08:00
2024-01-15 13:24:55 +08:00
DOTENV_TYPE : TypeAlias = Union [
2024-04-16 00:33:48 +08:00
Path , str , list [ Union [ Path , str ] ] , tuple [ Union [ Path , str ] , . . . ]
2024-01-15 13:24:55 +08:00
]
ENV_FILE_SENTINEL = Path ( " " )
2024-02-06 12:48:23 +08:00
class SettingsError ( ValueError ) : . . .
2024-01-15 13:24:55 +08:00
class BaseSettingsSource ( abc . ABC ) :
2024-04-16 00:33:48 +08:00
def __init__ ( self , settings_cls : type [ " BaseSettings " ] ) - > None :
2024-01-15 13:24:55 +08:00
self . settings_cls = settings_cls
@property
2024-01-26 11:12:57 +08:00
def config ( self ) - > " SettingsConfig " :
return model_config ( self . settings_cls )
2024-01-15 13:24:55 +08:00
@abc.abstractmethod
2024-04-16 00:33:48 +08:00
def __call__ ( self ) - > dict [ str , Any ] :
2024-01-15 13:24:55 +08:00
raise NotImplementedError
class InitSettingsSource ( BaseSettingsSource ) :
__slots__ = ( " init_kwargs " , )
def __init__ (
2024-04-16 00:33:48 +08:00
self , settings_cls : type [ " BaseSettings " ] , init_kwargs : dict [ str , Any ]
2024-01-15 13:24:55 +08:00
) - > None :
self . init_kwargs = init_kwargs
super ( ) . __init__ ( settings_cls )
2024-04-16 00:33:48 +08:00
def __call__ ( self ) - > dict [ str , Any ] :
2024-01-15 13:24:55 +08:00
return self . init_kwargs
def __repr__ ( self ) - > str :
return f " InitSettingsSource(init_kwargs= { self . init_kwargs !r} ) "
class DotEnvSettingsSource ( BaseSettingsSource ) :
def __init__ (
self ,
2024-04-16 00:33:48 +08:00
settings_cls : type [ " BaseSettings " ] ,
2024-01-15 13:24:55 +08:00
env_file : Optional [ DOTENV_TYPE ] = ENV_FILE_SENTINEL ,
env_file_encoding : Optional [ str ] = None ,
case_sensitive : Optional [ bool ] = None ,
env_nested_delimiter : Optional [ str ] = None ,
) - > None :
super ( ) . __init__ ( settings_cls )
self . env_file = (
2024-01-26 11:12:57 +08:00
env_file
if env_file is not ENV_FILE_SENTINEL
else self . config . get ( " env_file " , ( " .env " , ) )
2024-01-15 13:24:55 +08:00
)
self . env_file_encoding = (
env_file_encoding
if env_file_encoding is not None
2024-01-26 11:12:57 +08:00
else self . config . get ( " env_file_encoding " , " utf-8 " )
2024-01-15 13:24:55 +08:00
)
self . case_sensitive = (
2024-01-26 11:12:57 +08:00
case_sensitive
if case_sensitive is not None
else self . config . get ( " case_sensitive " , False )
2024-01-15 13:24:55 +08:00
)
self . env_nested_delimiter = (
env_nested_delimiter
if env_nested_delimiter is not None
2024-01-26 11:12:57 +08:00
else self . config . get ( " env_nested_delimiter " , None )
2024-01-15 13:24:55 +08:00
)
def _apply_case_sensitive ( self , var_name : str ) - > str :
return var_name if self . case_sensitive else var_name . lower ( )
2024-04-16 00:33:48 +08:00
def _field_is_complex ( self , field : ModelField ) - > tuple [ bool , bool ] :
2024-01-26 11:12:57 +08:00
if type_is_complex ( field . annotation ) :
2024-01-15 13:24:55 +08:00
return True , False
2024-01-26 11:12:57 +08:00
elif origin_is_union ( get_origin ( field . annotation ) ) and any (
type_is_complex ( arg ) for arg in get_args ( field . annotation )
2024-01-15 13:24:55 +08:00
) :
return True , True
return False , False
def _parse_env_vars (
self , env_vars : Mapping [ str , Optional [ str ] ]
2024-04-16 00:33:48 +08:00
) - > dict [ str , Optional [ str ] ] :
2024-01-15 13:24:55 +08:00
return {
self . _apply_case_sensitive ( key ) : value for key , value in env_vars . items ( )
}
2024-04-16 00:33:48 +08:00
def _read_env_file ( self , file_path : Path ) - > dict [ str , Optional [ str ] ] :
2024-01-15 13:24:55 +08:00
file_vars = dotenv_values ( file_path , encoding = self . env_file_encoding )
return self . _parse_env_vars ( file_vars )
2024-04-16 00:33:48 +08:00
def _read_env_files ( self ) - > dict [ str , Optional [ str ] ] :
2024-01-15 13:24:55 +08:00
env_files = self . env_file
if env_files is None :
return { }
if isinstance ( env_files , ( str , os . PathLike ) ) :
env_files = [ env_files ]
2024-04-16 00:33:48 +08:00
dotenv_vars : dict [ str , Optional [ str ] ] = { }
2024-01-15 13:24:55 +08:00
for env_file in env_files :
env_path = Path ( env_file ) . expanduser ( )
if env_path . is_file ( ) :
dotenv_vars . update ( self . _read_env_file ( env_path ) )
return dotenv_vars
def _next_field (
self , field : Optional [ ModelField ] , key : str
) - > Optional [ ModelField ] :
2024-01-26 11:12:57 +08:00
if not field or origin_is_union ( get_origin ( field . annotation ) ) :
2024-01-15 13:24:55 +08:00
return None
2024-01-26 11:12:57 +08:00
elif field . annotation and lenient_issubclass ( field . annotation , BaseModel ) :
for field in model_fields ( field . annotation ) :
if field . name == key :
return field
2024-01-15 13:24:55 +08:00
return None
def _explode_env_vars (
self ,
field : ModelField ,
2024-04-16 00:33:48 +08:00
env_vars : dict [ str , Optional [ str ] ] ,
env_file_vars : dict [ str , Optional [ str ] ] ,
) - > dict [ str , Any ] :
2024-01-15 13:24:55 +08:00
if self . env_nested_delimiter is None :
return { }
prefix = f " { field . name } { self . env_nested_delimiter } "
2024-04-16 00:33:48 +08:00
result : dict [ str , Any ] = { }
2024-01-15 13:24:55 +08:00
for env_name , env_val in env_vars . items ( ) :
if not env_name . startswith ( prefix ) :
continue
# delete from file vars when used
if env_name in env_file_vars :
del env_file_vars [ env_name ]
_ , * keys , last_key = env_name . split ( self . env_nested_delimiter )
env_var = result
target_field : Optional [ ModelField ] = field
for key in keys :
target_field = self . _next_field ( target_field , key )
env_var = env_var . setdefault ( key , { } )
target_field = self . _next_field ( target_field , last_key )
if target_field and env_val :
is_complex , allow_parse_failure = self . _field_is_complex ( target_field )
if is_complex :
try :
2024-01-26 11:12:57 +08:00
env_val = json . loads ( env_val )
2024-01-15 13:24:55 +08:00
except ValueError as e :
if not allow_parse_failure :
raise SettingsError (
f ' error parsing env var " { env_name } " '
) from e
env_var [ last_key ] = env_val
2020-08-07 11:18:02 +08:00
2024-01-15 13:24:55 +08:00
return result
2024-04-16 00:33:48 +08:00
def __call__ ( self ) - > dict [ str , Any ] :
2023-06-24 14:47:35 +08:00
""" 从环境变量和 dotenv 配置文件中读取配置项。 """
2024-04-16 00:33:48 +08:00
d : dict [ str , Any ] = { }
2020-08-07 11:18:02 +08:00
2024-01-15 13:24:55 +08:00
env_vars = self . _parse_env_vars ( os . environ )
env_file_vars = self . _read_env_files ( )
2022-10-14 09:58:44 +08:00
env_vars = { * * env_file_vars , * * env_vars }
2020-08-07 11:18:02 +08:00
2024-01-26 11:12:57 +08:00
for field in model_fields ( self . settings_cls ) :
field_name = field . name
env_name = self . _apply_case_sensitive ( field_name )
2024-01-15 13:24:55 +08:00
# try get values from env vars
2024-01-26 11:12:57 +08:00
env_val = env_vars . get ( env_name , PydanticUndefined )
2024-01-15 13:24:55 +08:00
# delete from file vars when used
if env_name in env_file_vars :
del env_file_vars [ env_name ]
2020-08-07 11:18:02 +08:00
2024-01-15 13:24:55 +08:00
is_complex , allow_parse_failure = self . _field_is_complex ( field )
2022-10-14 09:58:44 +08:00
if is_complex :
2024-01-26 11:12:57 +08:00
if isinstance ( env_val , PydanticUndefinedType ) :
2023-07-04 10:45:55 +08:00
# field is complex but no value found so far, try explode_env_vars
2024-01-15 13:24:55 +08:00
if env_val_built := self . _explode_env_vars (
field , env_vars , env_file_vars
) :
2024-01-26 11:12:57 +08:00
d [ field_name ] = env_val_built
2023-07-04 10:45:55 +08:00
elif env_val is None :
2024-01-26 11:12:57 +08:00
d [ field_name ] = env_val
2022-10-14 09:58:44 +08:00
else :
2023-06-24 14:47:35 +08:00
# field is complex and there's a value
# decode that as JSON, then add explode_env_vars
2022-09-09 11:52:57 +08:00
try :
2024-01-26 11:12:57 +08:00
env_val = json . loads ( env_val )
2022-09-09 11:52:57 +08:00
except ValueError as e :
2022-10-14 09:58:44 +08:00
if not allow_parse_failure :
raise SettingsError (
2024-01-15 13:24:55 +08:00
f ' error parsing env var " { env_name } " '
2022-10-14 09:58:44 +08:00
) from e
if isinstance ( env_val , dict ) :
2024-01-15 13:24:55 +08:00
# field value is a dict
# try explode_env_vars to find more sub-values
2024-01-26 11:12:57 +08:00
d [ field_name ] = deep_update (
2024-01-15 13:24:55 +08:00
env_val ,
self . _explode_env_vars ( field , env_vars , env_file_vars ) ,
2022-09-09 11:52:57 +08:00
)
2022-10-14 09:58:44 +08:00
else :
2024-01-26 11:12:57 +08:00
d [ field_name ] = env_val
elif env_val is not PydanticUndefined :
2023-06-24 14:47:35 +08:00
# simplest case, field is not complex
# we only need to add the value if it was found
2024-01-26 11:12:57 +08:00
d [ field_name ] = env_val
2022-10-14 09:58:44 +08:00
# remain user custom config
for env_name in env_file_vars :
env_val = env_vars [ env_name ]
if env_val and ( val_striped := env_val . strip ( ) ) :
# there's a value, decode that as JSON
try :
2024-01-26 11:12:57 +08:00
env_val = json . loads ( val_striped )
2023-06-24 14:47:35 +08:00
except ValueError :
2022-10-14 09:58:44 +08:00
logger . trace (
" Error while parsing JSON for "
f " { env_name !r} = { val_striped !r} . "
" Assumed as string. "
)
# explode value when it's a nested dict
env_name , * nested_keys = env_name . split ( self . env_nested_delimiter )
if nested_keys and ( env_name not in d or isinstance ( d [ env_name ] , dict ) ) :
result = { }
* keys , last_key = nested_keys
_tmp = result
for key in keys :
_tmp = _tmp . setdefault ( key , { } )
_tmp [ last_key ] = env_val
d [ env_name ] = deep_update ( d . get ( env_name , { } ) , result )
elif not nested_keys :
2020-08-07 11:18:02 +08:00
d [ env_name ] = env_val
return d
2020-07-04 22:51:10 +08:00
2021-02-28 00:35:40 +08:00
2024-01-26 11:12:57 +08:00
if PYDANTIC_V2 : # pragma: pydantic-v2
class SettingsConfig ( ConfigDict , total = False ) :
env_file : Optional [ DOTENV_TYPE ]
env_file_encoding : str
case_sensitive : bool
env_nested_delimiter : Optional [ str ]
else : # pragma: pydantic-v1
class SettingsConfig ( ConfigDict ) :
env_file : Optional [ DOTENV_TYPE ]
env_file_encoding : str
case_sensitive : bool
env_nested_delimiter : Optional [ str ]
2024-01-15 13:24:55 +08:00
class BaseSettings ( BaseModel ) :
2022-01-27 11:15:44 +08:00
if TYPE_CHECKING :
# dummy getattr for pylance checking, actually not used
def __getattr__ ( self , name : str ) - > Any : # pragma: no cover
return self . __dict__ . get ( name )
2020-08-20 15:07:05 +08:00
2024-01-26 11:12:57 +08:00
if PYDANTIC_V2 : # pragma: pydantic-v2
2024-04-16 00:33:48 +08:00
model_config = SettingsConfig (
2024-01-26 11:12:57 +08:00
extra = " allow " ,
env_file = " .env " ,
env_file_encoding = " utf-8 " ,
case_sensitive = False ,
env_nested_delimiter = " __ " ,
)
else : # pragma: pydantic-v1
class Config ( SettingsConfig ) :
extra = " allow " # type: ignore
env_file = " .env "
env_file_encoding = " utf-8 "
case_sensitive = False
env_nested_delimiter = " __ "
2024-01-15 13:24:55 +08:00
def __init__ (
__settings_self__ , # pyright: ignore[reportSelfClsParameterName]
_env_file : Optional [ DOTENV_TYPE ] = ENV_FILE_SENTINEL ,
_env_file_encoding : Optional [ str ] = None ,
_env_nested_delimiter : Optional [ str ] = None ,
* * values : Any ,
) - > None :
super ( ) . __init__ (
* * __settings_self__ . _settings_build_values (
values ,
env_file = _env_file ,
env_file_encoding = _env_file_encoding ,
env_nested_delimiter = _env_nested_delimiter ,
2021-11-22 23:21:26 +08:00
)
2024-01-15 13:24:55 +08:00
)
def _settings_build_values (
self ,
2024-04-16 00:33:48 +08:00
init_kwargs : dict [ str , Any ] ,
2024-01-15 13:24:55 +08:00
env_file : Optional [ DOTENV_TYPE ] = None ,
env_file_encoding : Optional [ str ] = None ,
env_nested_delimiter : Optional [ str ] = None ,
2024-04-16 00:33:48 +08:00
) - > dict [ str , Any ] :
2024-01-15 13:24:55 +08:00
init_settings = InitSettingsSource ( self . __class__ , init_kwargs = init_kwargs )
env_settings = DotEnvSettingsSource (
self . __class__ ,
env_file = env_file ,
env_file_encoding = env_file_encoding ,
env_nested_delimiter = env_nested_delimiter ,
)
return deep_update ( env_settings ( ) , init_settings ( ) )
class Env ( BaseSettings ) :
2022-01-18 12:31:08 +08:00
""" 运行环境配置。大小写不敏感。
2020-08-20 15:07:05 +08:00
2023-06-24 14:47:35 +08:00
将会从 * * 环境变量 * * > * * dotenv 配置文件 * * 的优先级读取环境信息 。
2020-08-20 15:07:05 +08:00
"""
2020-07-04 22:51:10 +08:00
environment : str = " prod "
2022-01-18 12:31:08 +08:00
""" 当前环境名。
NoneBot 将从 ` . env . { environment } ` 文件中加载配置 。
2020-08-20 15:07:05 +08:00
"""
2020-07-04 22:51:10 +08:00
2024-01-15 13:24:55 +08:00
class Config ( BaseSettings ) :
2022-01-18 12:31:08 +08:00
""" NoneBot 主要配置。大小写不敏感。
2020-08-07 11:18:02 +08:00
2022-01-12 18:19:21 +08:00
除了 NoneBot 的配置项外 , 还可以自行添加配置项到 ` . env . { environment } ` 文件中 。
这些配置将会在 json 反序列化后一起带入 ` Config ` 类中 。
2022-01-18 12:31:08 +08:00
2023-06-01 14:18:16 +08:00
配置方法参考 : [ 配置 ] ( https : / / nonebot . dev / docs / appendices / config )
2020-08-07 11:18:02 +08:00
"""
2021-11-22 23:21:26 +08:00
2024-01-26 11:12:57 +08:00
if TYPE_CHECKING :
_env_file : Optional [ DOTENV_TYPE ] = " .env " , " .env.prod "
2022-01-04 14:36:32 +08:00
2020-08-01 22:03:40 +08:00
# nonebot configs
2021-12-25 14:57:29 +08:00
driver : str = " ~fastapi "
2022-01-18 12:31:08 +08:00
""" NoneBot 运行所使用的 `Driver` 。继承自 {ref} `nonebot.drivers.Driver` 。
2021-06-20 23:38:42 +08:00
2022-01-12 19:41:42 +08:00
配置格式为 ` < module > [ : < Driver > ] [ + < module > [ : < Mixin > ] ] * ` 。
2021-12-25 14:57:29 +08:00
2022-01-12 19:41:42 +08:00
` ~ ` 为 ` nonebot . drivers . ` 的缩写 。
2023-06-24 14:47:35 +08:00
配置方法参考 : [ 配置驱动器 ] ( https : / / nonebot . dev / docs / advanced / driver #%E9%85%8D%E7%BD%AE%E9%A9%B1%E5%8A%A8%E5%99%A8)
2020-08-20 15:07:05 +08:00
"""
2020-08-18 17:24:49 +08:00
host : IPvAnyAddress = IPv4Address ( " 127.0.0.1 " ) # type: ignore
2022-01-18 12:31:08 +08:00
""" NoneBot {ref} `nonebot.drivers.ReverseDriver` 服务端监听的 IP/主机名。 """
2023-01-25 12:31:26 +08:00
port : int = Field ( default = 8080 , ge = 1 , le = 65535 )
2022-01-18 12:31:08 +08:00
""" NoneBot {ref} `nonebot.drivers.ReverseDriver` 服务端监听的端口。 """
2021-12-28 15:19:53 +08:00
log_level : Union [ int , str ] = " INFO "
2023-06-24 14:47:35 +08:00
""" NoneBot 日志输出等级,可以为 `int` 类型等级或等级名称。
2022-01-18 12:31:08 +08:00
2023-06-24 14:47:35 +08:00
参考 [ 记录日志 ] ( https : / / nonebot . dev / docs / appendices / log ) , [ loguru 日志等级 ] ( https : / / loguru . readthedocs . io / en / stable / api / logger . html #levels)。
2022-01-18 12:31:08 +08:00
: : : tip 提示
日志等级名称应为大写 , 如 ` INFO ` 。
: : :
2021-04-19 21:15:10 +08:00
2022-01-12 18:53:30 +08:00
用法 :
` ` ` conf
2021-04-19 21:15:10 +08:00
LOG_LEVEL = 25
LOG_LEVEL = INFO
2022-01-12 18:53:30 +08:00
` ` `
2021-04-19 21:15:10 +08:00
"""
2020-07-04 22:51:10 +08:00
2020-08-01 22:03:40 +08:00
# bot connection configs
2021-11-22 23:21:26 +08:00
api_timeout : Optional [ float ] = 30.0
2022-01-18 12:31:08 +08:00
""" API 请求超时时间,单位: 秒。 """
2020-08-01 22:03:40 +08:00
# bot runtime configs
2024-04-16 00:33:48 +08:00
superusers : set [ str ] = set ( )
2022-01-18 12:31:08 +08:00
""" 机器人超级用户。
2020-11-30 11:08:00 +08:00
2022-01-12 18:53:30 +08:00
用法 :
` ` ` conf
2021-01-05 23:06:36 +08:00
SUPERUSERS = [ " 12345789 " ]
2022-01-12 18:53:30 +08:00
` ` `
2020-08-20 16:34:07 +08:00
"""
2024-04-16 00:33:48 +08:00
nickname : set [ str ] = set ( )
2022-01-18 12:31:08 +08:00
""" 机器人昵称。 """
2024-04-16 00:33:48 +08:00
command_start : set [ str ] = { " / " }
2022-01-18 12:31:08 +08:00
""" 命令的起始标记,用于判断一条消息是不是命令。
2023-06-24 14:47:35 +08:00
参考 [ 命令响应规则 ] ( https : / / nonebot . dev / docs / advanced / matcher #command)。
2022-01-18 12:31:08 +08:00
用法 :
` ` ` conf
COMMAND_START = [ " / " , " " ]
` ` `
2020-08-20 16:34:07 +08:00
"""
2024-04-16 00:33:48 +08:00
command_sep : set [ str ] = { " . " }
2022-01-18 12:31:08 +08:00
""" 命令的分隔标记,用于将文本形式的命令切分为元组(实际的命令名)。
2023-06-24 14:47:35 +08:00
参考 [ 命令响应规则 ] ( https : / / nonebot . dev / docs / advanced / matcher #command)。
2022-01-18 12:31:08 +08:00
用法 :
` ` ` conf
COMMAND_SEP = [ " . " ]
` ` `
2020-08-20 16:34:07 +08:00
"""
2020-08-06 17:54:55 +08:00
session_expire_timeout : timedelta = timedelta ( minutes = 2 )
2022-01-18 12:31:08 +08:00
""" 等待用户回复的超时时间。
2020-11-30 11:08:00 +08:00
2022-01-12 18:53:30 +08:00
用法 :
` ` ` conf
2024-02-22 13:59:57 +08:00
SESSION_EXPIRE_TIMEOUT = [ - ] [ DD ] D [ , ] [ HH : MM : ] SS [ . ffffff ]
SESSION_EXPIRE_TIMEOUT = [ ± ] P [ DD ] DT [ HH ] H [ MM ] M [ SS ] S # ISO 8601
2022-01-12 18:53:30 +08:00
` ` `
2020-08-20 16:34:07 +08:00
"""
2020-07-04 22:51:10 +08:00
2021-01-12 17:55:27 +08:00
# adapter configs
# adapter configs are defined in adapter/config.py
2020-08-01 22:03:40 +08:00
# custom configs
2020-08-07 11:18:02 +08:00
# custom configs can be assigned during nonebot.init
# or from env file using json loads
2020-07-04 22:51:10 +08:00
2024-01-26 11:12:57 +08:00
if PYDANTIC_V2 : # pragma: pydantic-v2
model_config = SettingsConfig ( env_file = ( " .env " , " .env.prod " ) )
else : # pragma: pydantic-v1
2024-04-16 00:33:48 +08:00
class Config ( # pyright: ignore[reportIncompatibleVariableOverride]
SettingsConfig
) :
2024-01-26 11:12:57 +08:00
env_file = " .env " , " .env.prod "
2022-01-18 12:31:08 +08:00
__autodoc__ = {
2024-01-15 13:24:55 +08:00
" SettingsError " : False ,
" BaseSettingsSource " : False ,
" InitSettingsSource " : False ,
" DotEnvSettingsSource " : False ,
" SettingsConfig " : False ,
" BaseSettings " : False ,
2022-01-18 12:31:08 +08:00
}