class Config(object): @environ.config class Twitter(object): consumer_key=environ.var() consumer_secret=environ.var() access_token=environ.var() access_token_secret=environ.var() twitter = environ.group(Twitter) @environ.config class LDA(object): num_topics=environ.var(10, converter=int) num_top_words=environ.var(20, converter=int) lda = environ.group(LDA) @environ.config class S3(object): access_key=environ.var() secret_key=environ.var() bucket=environ.var() s3 = environ.group(S3) sample_size = environ.var(5000, converter=int)
class PyNuts: input_cls = environ.var("serialiec62056", converter=convInputPlugin) input_name = environ.var("power") input_tz = environ.var("Europe/Amsterdam", converter=pytz.timezone) output_cls = environ.var("influxdb", converter=convOutputPlugin) output_name = environ.var("influxdb") loglevel = environ.var("INFO", converter=convLoglevel) influxdb_bucket = environ.var('pynuts', name='INFLUXDB_V2_BUCKET') # bit awkward, but if we put it under sub-config-class we cannot get this nice envvar @environ.config class Serial: port = environ.var('') baudrate = environ.var(115200, converter=int) bytesize = environ.var(7, converter=int) parity = environ.var('N') stopbits = environ.var(1, converter=int) timeout = environ.var(2, converter=float) vid = environ.var('') pid = environ.var('') serial = environ.var('') serial = environ.group(Serial) @environ.config class Counter: filename = environ.var('/sys/class/gpio/gpio71/value') # On Pine A64 this is PC7 / pin 11 on Pi2 header increase = environ.var(0.5, converter=float) key = environ.var('volume') interval = environ.var(0.1) counter = environ.group(Counter)
class BotAppConfig: """Bot app config. Construct it as follows:: >>> from octomachinery.app.config import BotAppConfig >>> config = BotAppConfig.from_dotenv() # for dev env >>> config = BotAppConfig.from_env() # for pure env >>> """ github = environ.group(GitHubAppIntegrationConfig) action = environ.group(GitHubActionConfig) server = environ.group(WebServerConfig) runtime = environ.group(RuntimeConfig) @classmethod @lru_cache(maxsize=1) def from_dotenv( cls, *, app_name: Optional[str] = None, app_version: Optional[str] = None, app_url: Optional[str] = None, ): """Return an initialized dev config instance. Read .env into env vars before that. """ envparse.Env.read_envfile( '.env', # Making it relative to CWD, relative to caller if None ) return cls.from_env( app_name=app_name, app_version=app_version, app_url=app_url, ) @classmethod @lru_cache(maxsize=1) def from_env( cls, *, app_name: Optional[str] = None, app_version: Optional[str] = None, app_url: Optional[str] = None, ): """Return an initialized config instance.""" env_vars = dict(os.environ) if app_name is not None: env_vars['OCTOMACHINERY_APP_NAME'] = app_name if app_version is not None: env_vars['OCTOMACHINERY_APP_VERSION'] = app_version if app_url is not None: env_vars['OCTOMACHINERY_APP_URL'] = app_url return environ.to_config(cls, environ=env_vars)
class Config: @environ.config class S3Config: endpoint_url = environ.var('http://localhost:9000') aws_access_key_id = environ.var('minio_access_key') aws_secret_access_key = environ.var('minio_secret_key') bucket = environ.var('boringart') s3 = environ.group(S3Config) @environ.config class MongoConfig: uri = environ.var('mongodb://localhost:27017') database = environ.var('boringart') mongo = environ.group(MongoConfig) @environ.config class Keycloak: server_url = environ.var('http://localhost:8080') realm_name = environ.var('boringart') client_id = environ.var('api') client_secret = environ.var() keycloak = environ.group(Keycloak) @environ.config class APIConfig: scheme = environ.var('http') host = environ.var('0.0.0.0') port = environ.var('8000') @property def absolute_url(self): absolute_url = URL.build(scheme=self.scheme, host=self.host, port=self.port) if absolute_url.is_default_port(): absolute_url = absolute_url.with_port(None) return absolute_url api = environ.group(APIConfig) @environ.config class SiteConfig: index = environ.var('http://localhost:3000') site = environ.group(SiteConfig)
class WithOptionalChild(object): @environ.config(prefix="CHILD") class Child(object): grandchild_a = environ.var() grandchild_b = environ.var("FOO") child = environ.group(Child, optional=True)
class Email: host = environ.var( default='mxf9a9.netcup.net', converter=str, help="The SMTP Hostname to use to send emails through." ) port = environ.var( default=587, converter=int, help="The SMTP Port to use to send emails through." ) tls = environ.bool_var( default=True, help="SMTP use TLS or not.") timeout = environ.var( default=60, converter=int, help="The Default Timeout for SMTP Connection establishment." ) backend = environ.var( default='django.core.mail.backends.smtp.EmailBackend', converter=str, help="The EMAIL Backend to use for django." ) user = environ.group(User)
class MedallionConfig(object): backend = environ.group(backends.BackendConfig) taxii = environ.group(TAXIIConfig) @classmethod def __strip(cls, dict_): for k, v in tuple(dict_.items()): if isinstance(v, dict): cls.__strip(v) if v is None or v == {}: del dict_[k] def as_dict(self): dictified = attr.asdict(self) self.__strip(dictified) return dictified
class AppConfig: @environ.config class ElasticConfig: url = environ.var(name='ELASTIC_URL') elastic = environ.group(ElasticConfig)
class Nested(object): """A nested configuration example.""" @environ.config class Sub(object): y = environ.var() x = environ.var() sub = environ.group(Sub)
class Cfg(object): @environ.config class Sub(object): y = environ.var() x = environ.var() y = environ.var() sub = environ.group(Sub)
class AppConfig: env = environ.var(default="dev") @environ.config(frozen=True) class Ghibli: films_url = environ.var(default="https://ghibliapi.herokuapp.com/films") people_url = environ.var(default="https://ghibliapi.herokuapp.com/people") film_data_cache_key = "film_data" ghibli = environ.group(Ghibli)
class Cfg(object): @environ.config(frozen=True) class Sub(object): z = environ.var() x = environ.var() y = environ.var() sub = environ.group(Sub)
class BackendConfig(object): for name, clsobj in base.BackendRegistry.iter_(): # We have to use a magic attribute name here since `config`s don't have # a specific mixin or type we can check for try: locals()[name] = environ.group(clsobj.Config, optional=True) except AttributeError: pass module_class = environ.var(None)
class AppConfig: db_uri = environ.var() listen_uri = environ.var("tcp://*:5001") @environ.config class Unprivileged: ratelimit = environ.group(Ratelimit) unprivileged = environ.group(Unprivileged)
class WithOptionalGrandChild(object): @environ.config(prefix="CHILD") class Child(object): @environ.config(prefix="GRANDCHILD") class GrandChild(object): foo = environ.var() grandchild = environ.group(GrandChild, optional=True) child = environ.group(Child)
class WichtelitConfig: secret_key = environ.var( default='---cjz#uz(&br66^fis#p+(x1!wpqt&%nr#ny_!@-09#*jwk+m', converter=str, help="The Secret Key of the Django Application. (Default is development Key," + " https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/" ) debug = environ.bool_var( default=True, help="This enables the development mode." ) fqdn = environ.var( default="wichtelit", converter=str, help="Adding the Allowed host from outside." ) captcha = environ.group(Captcha) database = environ.group(Database) email = environ.group(Email) contact = environ.group(Contact)
class Database: host = environ.var(default='postgres', converter=str, help="The RDBMS Hostname to use to connect to.") port = environ.var(default=5432, converter=int, help="The RDBMS Port to use to connect to.") name = environ.var( default='sipam', converter=str, help="The Name of the RDBMS Database to use to connect to.") user = environ.group(User)
class _Config: secret_key = environ.var() @environ.config class DB: name: str = environ.var() host: str = environ.var() port: str = environ.var() user: str = environ.var() password = environ.var() database: DB = environ.group(DB)
class Config: @environ.config class Paths: root_directory = environ.var(".sigla") templates_folder = environ.var("templates") snapshots_folder = environ.var("snapshots") definitions_folder = environ.var("definitions") scripts_folder = environ.var("scripts") filters_filename = environ.var("filters.py") @property def templates(self): return f"{self.root_directory}/{self.templates_folder}" @property def scripts(self): return f"{self.root_directory}/{self.scripts_folder}" @property def snapshots(self): return f"{self.root_directory}/{self.snapshots_folder}" @property def definitions(self): return f"{self.root_directory}/{self.definitions_folder}" @property def filters(self): return f"{self.root_directory}/{self.filters_filename}" @environ.config class Cls: node_list = environ.var("sigla.core.node_lists.NodeList") node = environ.var("sigla.core.nodes.Node") path: Paths = environ.group(Paths) cls: Cls = environ.group(Cls)
class Config: @environ.config() class Bind: host = environ.var(default="localhost") port = environ.var(default="80", converter=int) bind = environ.group(Bind) database_uri = environ.var() encryption_key = environ.var() schedule_interval = environ.var( name="SCHEDULE_INTERVAL_SECONDS", converter=lambda value: timedelta(seconds=int(value)), default=50)
class Configuration: # pylint: disable=R0903 """Root configuration.""" @environ.config class FlaskConfig: # pylint: disable=R0903 """Flask specific configuration.""" SECRET_KEY = environ.var(_gen_secret_key()) DEBUG = environ.bool_var(False) TESTING = environ.bool_var(False) SQLALCHEMY_DATABASE_URI = environ.var("sqlite://") SQLALCHEMY_TRACK_MODIFICATIONS = environ.bool_var(False) flask = environ.group(FlaskConfig) skip_db_setup = environ.bool_var(False) verbosity = environ.var( "WARNING", validator=in_(["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"]))
def get_merged_conf_object(): """ Get the merged configuration object. Note this returns the value environ.config expects as an argument (eg, its attrs will be the return value of environ.var, not the configured values). """ # Bootstrap a config we can read the modules for the subconfigs from bootstrap_config = environ.to_config( environ.config(Configuration, prefix="LEDGE")) # Frankenstein our real config together for kls in chain(bootstrap_config.handlers, bootstrap_config.responders): if kls.provides_subconfig(): subconfig_name, subconfig = kls.provide_subconfig() setattr(Configuration, subconfig_name, environ.group(subconfig)) return environ.config(Configuration, prefix="LEDGE", frozen=True)
class Config: """Custom Config class.""" allowed_hosts = environ.var("*", converter=csv_converter) db_url = environ.var( "sqlite:///db.sqlite3") # default allows for running manage.py locally debug = environ.bool_var(False) django_env = environ.var("local") secret_key = environ.var("default-secret-key") @environ.config class RestFramework: parser_classes = environ.var("rest_framework.parsers.JSONParser", converter=csv_converter) renderer_classes = environ.var( "rest_framework.renderers.JSONRenderer", converter=csv_converter, ) drf: RestFramework = environ.group(RestFramework)
class Database: engine = environ.var( default='django.db.backends.postgresql', converter=str, help="The Database Engine to use." ) host = environ.var( default='127.0.0.1', converter=str, help="The RDBMS Hostname to use to connect to." ) port = environ.var( default='5432', converter=int, help="The RDBMS Port to use to connect to." ) name = environ.var( default='wichtelit', converter=str, help="The Name of the RDBMS Database to use to connect to." ) user = environ.group(User)
class Parent(object): not_a_var = attr.ib() # For testing that only environ.var's are processed. var1 = environ.var(help="var1, no default") var2 = environ.var("bar", help="var2, has default") var3 = environ.bool_var(help="var3, bool_var, no default") var4 = environ.bool_var(True, help="var4, bool_var, has default") var5 = environ.var("canine", name="DOG", help="var5, named, has default") var6 = environ.var(name="CAT", help="var6, named, no default") @environ.config class Child(object): var7 = environ.var(help="var7, no default") var8 = environ.var("bar", help="var8, has default") var9 = environ.bool_var(help="var9, bool_var, no default") var10 = environ.bool_var(True, help="var10, bool_var, has default") var11 = environ.var("canine", name="DOG2", help="var11, named, has default") var12 = environ.var(name="CAT2", help="var12, named, no default") var13 = environ.var("default") # var with default, no help var14 = environ.var() # var without default, no help child = environ.group(Child)
class WithRequiredChild(object): @environ.config(prefix="CHILD") class Child(object): grandchild = environ.var("FOO") child = environ.group(Child)
class Cfg(object): @environ.config class DB(object): password = ini.secret() db = environ.group(DB)
class Config: bot = environ.group(BotGroup) log = environ.group(LogGroup) mongo = environ.group(MongoGroup)
class NoeConfig: debug = environ.bool_var( default=False, name="DJANGO_DEBUG", help="SECURITY WARNING: Don't run with debug turned on in production!" ) secret_key = environ.var(help="SECURITY WARNING: keep the secret key used in production secret!") frontend_url = environ.var(help="Where the React frontend SPA is hosted") backend_url = environ.var(help="Where the Django backend is hosted") allowed_hosts = environ.var(default="*", converter=split_by_comma) allowed_cors_hosts = environ.var(default=None, converter=lambda val: split_by_comma(val) if val else None) behind_tls_proxy = environ.bool_var( default=False, help='Whether or not to set the "X-Forwarded-Proto" header to "https". Should be set to True behind a proxy.', ) language_code = environ.var(default="hu-hu") time_zone = environ.var(default="Europe/Budapest") log_level = environ.var(default="INFO", help="Python logger log level") sentry_dsn_url = environ.var( default=None, name="SENTRY_DSN_URL", help="If you want to track exceptions with https://sentry.io", ) @environ.config class Database: _DB_SQLITE_ENGINE = "django.db.backends.sqlite3" _PARAM_HELP = "Not required for SQLite" def _convert_database_engine(value): if value == "postgresql": return "django.db.backends.postgresql" elif value in ("mysql", "mariadb"): return "django.db.backends.mysql" elif value in ("sqlite", "sqlite3"): return NoeConfig.Database._DB_SQLITE_ENGINE raise ValueError( f'Invalid database engine: {value!r}\npossible values: "postgresql", "mysql", "mariadb", "sqlite"' ) def _validate_param(obj, attribute, value): if not value and obj.engine != NoeConfig.Database._DB_SQLITE_ENGINE: raise ValueError( f"The DJANGO_DATABASE_{attribute.name.upper()} environment variable is required\n{attribute!r}" ) engine = environ.var(converter=_convert_database_engine) name = environ.var() user = environ.var(default=None, validator=_validate_param, help=_PARAM_HELP) password = environ.var(default=None, validator=_validate_param, help=_PARAM_HELP) host = environ.var(default=None, validator=_validate_param, help=_PARAM_HELP) port = environ.var(default=None, validator=_validate_param, help=_PARAM_HELP) database = environ.group(Database) @environ.config class Email: class Backend(enum.Enum): CONSOLE = "console" SMTP = "smtp" _PARAM_HELP = "Required for SMTP only" def _convert_backend(value): backend = NoeConfig.Email.Backend(value) return f"django.core.mail.backends.{backend.value}.EmailBackend" def _validate_param(obj, attribute, value): if not value and obj.backend == "smtp": raise ValueError( f"The DJANGO_DATABASE_{attribute.name.upper()} environment variable is required\n{attribute!r}" ) def _convert_verification_key(value): if value is None: raise ValueError("You need to generate an EMAIL_VERIFICATION_KEY.") value_bytes = value.encode() try: Fernet(value_bytes) except Exception as exc: raise ValueError(f"EMAIL_VERIFICATION_KEY: {value}") else: return value_bytes backend = environ.var(converter=_convert_backend, help='"console" or "smtp"') host = environ.var(default=None, help=_PARAM_HELP) port = environ.var(default=None, help=_PARAM_HELP) user = environ.var(default=None, help=_PARAM_HELP) password = environ.var(default=None, help=_PARAM_HELP) use_tls = environ.bool_var(default=True) default_from = environ.bool_var(help="Sender email address for automatic emails") verification_key = environ.var( default=None, converter=_convert_verification_key, help="SECRET_KEY for encrpyting the email verification token", ) email = environ.group(Email) @environ.config class Static: url = environ.var( default="/static/", help=( "URL path generated for static files. " "If you change this, backend won't serve static files with WhiteNoise anymore." ), ) root = environ.var( default="/project_noe/static_root", help=( "Where manage.py collectstatic put all static files. " "The default value is where the static files are in the Docker container" ), ) static = environ.group(Static) default_time_slot_capacity = environ.var(default=30, converter=int) @environ.config class Szamlazzhu: agent_key = environ.var() invoice_prefix = environ.var() szamlazzhu = environ.group(Szamlazzhu) @environ.config class SimplePay: class Environment(enum.Enum): SANDBOX = "sandbox" LIVE = "live" merchant = environ.var() secret_key = environ.var() ipn_url = environ.var() use_live = environ.var(default=False) environment = environ.var(name="SIMPLEPAY_ENVIRONMENT", converter=Environment) def __attrs_post_init__(self): self.use_live = self.environment is NoeConfig.SimplePay.Environment.LIVE simplepay = environ.group(SimplePay) def __attrs_post_init__(self): if not self.allowed_cors_hosts and "*" not in self.allowed_hosts: self.allowed_cors_hosts = self.allowed_hosts
class Unprivileged: ratelimit = environ.group(Ratelimit)