environs is a Python library for parsing environment variables.

Overview

environs: simplified environment variable parsing

Latest version Build Status marshmallow 3 compatible Black code style

environs is a Python library for parsing environment variables. It allows you to store configuration separate from your code, as per The Twelve-Factor App methodology.

Contents

Features

  • Type-casting
  • Read .env files into os.environ (useful for local development)
  • Validation
  • Define custom parser behavior
  • Framework-agnostic, but integrates well with Flask and Django

Install

pip install environs

Basic usage

With some environment variables set...

export GITHUB_USER=sloria
export MAX_CONNECTIONS=100
export SHIP_DATE='1984-06-25'
export TTL=42
export ENABLE_LOGIN=true
export GITHUB_REPOS=webargs,konch,ped
export GITHUB_REPO_PRIORITY="webargs=2,konch=3"
export COORDINATES=23.3,50.0
export LOG_LEVEL=DEBUG

Parse them with environs...

'sloria' secret = env("SECRET") # => raises error if not set # casting max_connections = env.int("MAX_CONNECTIONS") # => 100 ship_date = env.date("SHIP_DATE") # => datetime.date(1984, 6, 25) ttl = env.timedelta("TTL") # => datetime.timedelta(0, 42) log_level = env.log_level("LOG_LEVEL") # => logging.DEBUG # providing a default value enable_login = env.bool("ENABLE_LOGIN", False) # => True enable_feature_x = env.bool("ENABLE_FEATURE_X", False) # => False # parsing lists gh_repos = env.list("GITHUB_REPOS") # => ['webargs', 'konch', 'ped'] coords = env.list("COORDINATES", subcast=float) # => [23.3, 50.0] # parsing dicts gh_repos_priorities = env.dict( "GITHUB_REPO_PRIORITY", subcast_values=int ) # => {'webargs': 2, 'konch': 3}">
from environs import Env

env = Env()
env.read_env()  # read .env file, if it exists
# required variables
gh_user = env("GITHUB_USER")  # => 'sloria'
secret = env("SECRET")  # => raises error if not set

# casting
max_connections = env.int("MAX_CONNECTIONS")  # => 100
ship_date = env.date("SHIP_DATE")  # => datetime.date(1984, 6, 25)
ttl = env.timedelta("TTL")  # => datetime.timedelta(0, 42)
log_level = env.log_level("LOG_LEVEL")  # => logging.DEBUG

# providing a default value
enable_login = env.bool("ENABLE_LOGIN", False)  # => True
enable_feature_x = env.bool("ENABLE_FEATURE_X", False)  # => False

# parsing lists
gh_repos = env.list("GITHUB_REPOS")  # => ['webargs', 'konch', 'ped']
coords = env.list("COORDINATES", subcast=float)  # => [23.3, 50.0]

# parsing dicts
gh_repos_priorities = env.dict(
    "GITHUB_REPO_PRIORITY", subcast_values=int
)  # => {'webargs': 2, 'konch': 3}

Supported types

The following are all type-casting methods of Env:

  • env.str
  • env.bool
  • env.int
  • env.float
  • env.decimal
  • env.list (accepts optional subcast and delimiter keyword arguments)
  • env.dict (accepts optional subcast_keys and subcast_values keyword arguments)
  • env.json
  • env.datetime
  • env.date
  • env.time
  • env.timedelta (assumes value is an integer in seconds)
  • env.url
  • env.uuid
  • env.log_level
  • env.path (casts to a pathlib.Path)
  • env.enum (casts to any given enum type specified in type keyword argument, accepts optional ignore_case keyword argument)

Reading .env files

# .env
DEBUG=true
PORT=4567

Call Env.read_env before parsing variables.

True env.int("PORT") # => 4567">
from environs import Env

env = Env()
# Read .env into os.environ
env.read_env()

env.bool("DEBUG")  # => True
env.int("PORT")  # => 4567

Reading a specific file

By default, Env.read_env will look for a .env file in current directory and (if no .env exists in the CWD) recurse upwards until a .env file is found.

You can also read a specific file:

from environs import Env

with open(".env.test", "w") as fobj:
    fobj.write("A=foo\n")
    fobj.write("B=123\n")

env = Env()
env.read_env(".env.test", recurse=False)

assert env("A") == "foo"
assert env.int("B") == 123

Handling prefixes

'lolcathost' port = env.int("PORT", 5000) # => 3000 # nested prefixes are also supported: # export MYAPP_DB_HOST=lolcathost # export MYAPP_DB_PORT=10101 with env.prefixed("MYAPP_"): with env.prefixed("DB_"): db_host = env("HOST", "lolcathost") db_port = env.int("PORT", 10101)">
# export MYAPP_HOST=lolcathost
# export MYAPP_PORT=3000

with env.prefixed("MYAPP_"):
    host = env("HOST", "localhost")  # => 'lolcathost'
    port = env.int("PORT", 5000)  # => 3000

# nested prefixes are also supported:

# export MYAPP_DB_HOST=lolcathost
# export MYAPP_DB_PORT=10101

with env.prefixed("MYAPP_"):
    with env.prefixed("DB_"):
        db_host = env("HOST", "lolcathost")
        db_port = env.int("PORT", 10101)

Variable expansion

'https://sloria:secret@localhost' year = env.int("YEAR") # =>2020">
# export CONNECTION_URL=https://${USER:-sloria}:${PASSWORD}@${HOST:-localhost}/
# export PASSWORD=secret
# export YEAR=${CURRENT_YEAR:-2020}

from environs import Env

env = Env(expand_vars=True)

connection_url = env("CONNECTION_URL")  # =>'https://sloria:secret@localhost'
year = env.int("YEAR")  # =>2020

Validation

0) # => Environment variable "TTL" invalid: ['Invalid value.'] # using marshmallow validators env.str( "NODE_ENV", validate=OneOf( ["production", "development"], error="NODE_ENV must be one of: {choices}" ), ) # => Environment variable "NODE_ENV" invalid: ['NODE_ENV must be one of: production, development'] # multiple validators env.str("EMAIL", validate=[Length(min=4), Email()]) # => Environment variable "EMAIL" invalid: ['Shorter than minimum length 4.', 'Not a valid email address.']">
# export TTL=-2
# export NODE_ENV='invalid'
# export EMAIL='^_^'

from environs import Env
from marshmallow.validate import OneOf, Length, Email

env = Env()

# simple validator
env.int("TTL", validate=lambda n: n > 0)
# => Environment variable "TTL" invalid: ['Invalid value.']


# using marshmallow validators
env.str(
    "NODE_ENV",
    validate=OneOf(
        ["production", "development"], error="NODE_ENV must be one of: {choices}"
    ),
)
# => Environment variable "NODE_ENV" invalid: ['NODE_ENV must be one of: production, development']

# multiple validators
env.str("EMAIL", validate=[Length(min=4), Email()])
# => Environment variable "EMAIL" invalid: ['Shorter than minimum length 4.', 'Not a valid email address.']

Deferred validation

By default, a validation error is raised immediately upon calling a parser method for an invalid environment variable. To defer validation and raise an exception with the combined error messages for all invalid variables, pass eager=False to Env. Call env.seal() after all variables have been parsed.

# export TTL=-2
# export NODE_ENV='invalid'
# export EMAIL='^_^'

from environs import Env
from marshmallow.validate import OneOf, Email, Length, Range

env = Env(eager=False)

TTL = env.int("TTL", validate=Range(min=0, max=100))
NODE_ENV = env.str(
    "NODE_ENV",
    validate=OneOf(
        ["production", "development"], error="NODE_ENV must be one of: {choices}"
    ),
)
EMAIL = env.str("EMAIL", validate=[Length(min=4), Email()])

env.seal()
# environs.EnvValidationError: Environment variables invalid: {'TTL': ['Must be greater than or equal to 0 and less than or equal to 100.'], 'NODE_ENV': ['NODE_ENV must be one of: production, development'], 'EMAIL': ['Shorter than minimum length 4.', 'Not a valid email address.']}

env.seal() validates all parsed variables and prevents further parsing (calling a parser method will raise an error).

Serialization

# serialize to a dictionary of simple types (numbers and strings)
env.dump()
# {'COORDINATES': [23.3, 50.0],
# 'ENABLE_FEATURE_X': False,
# 'ENABLE_LOGIN': True,
# 'GITHUB_REPOS': ['webargs', 'konch', 'ped'],
# 'GITHUB_USER': 'sloria',
# 'MAX_CONNECTIONS': 100,
# 'MYAPP_HOST': 'lolcathost',
# 'MYAPP_PORT': 3000,
# 'SHIP_DATE': '1984-06-25',
# 'TTL': 42}

Defining custom parser behavior

furl('https://myapp.com') # Custom parsers can take extra keyword arguments @env.parser_for("choice") def choice_parser(value, choices): if value not in choices: raise environs.EnvError("Invalid!") return value color = env.choice("COLOR", choices=["black"]) # => raises EnvError">
# export DOMAIN='http://myapp.com'
# export COLOR=invalid

from furl import furl

# Register a new parser method for paths
@env.parser_for("furl")
def furl_parser(value):
    return furl(value)


domain = env.furl("DOMAIN")  # => furl('https://myapp.com')


# Custom parsers can take extra keyword arguments
@env.parser_for("choice")
def choice_parser(value, choices):
    if value not in choices:
        raise environs.EnvError("Invalid!")
    return value


color = env.choice("COLOR", choices=["black"])  # => raises EnvError

Usage with Flask

# myapp/settings.py

from environs import Env

env = Env()
env.read_env()

# Override in .env for local development
DEBUG = env.bool("FLASK_DEBUG", default=False)
# SECRET_KEY is required
SECRET_KEY = env.str("SECRET_KEY")

Load the configuration after you initialize your app.

# myapp/app.py

from flask import Flask

app = Flask(__name__)
app.config.from_object("myapp.settings")

For local development, use a .env file to override the default configuration.

# .env
DEBUG=true
SECRET_KEY="not so secret"

Note: Because environs depends on python-dotenv, the flask CLI will automatically read .env and .flaskenv files.

Usage with Django

environs includes a number of helpers for parsing connection URLs. To install environs with django support:

pip install environs[django]

Use env.dj_db_url, env.dj_cache_url and env.dj_email_url to parse the DATABASE_URL, CACHE_URL and EMAIL_URL environment variables, respectively.

For more details on URL patterns, see the following projects that environs is using for converting URLs.

Basic example:

# myproject/settings.py
from environs import Env

env = Env()
env.read_env()

# Override in .env for local development
DEBUG = env.bool("DEBUG", default=False)
# SECRET_KEY is required
SECRET_KEY = env.str("SECRET_KEY")

# Parse database URLs, e.g.  "postgres://localhost:5432/mydb"
DATABASES = {"default": env.dj_db_url("DATABASE_URL")}

# Parse email URLs, e.g. "smtp://"
email = env.dj_email_url("EMAIL_URL", default="smtp://")
EMAIL_HOST = email["EMAIL_HOST"]
EMAIL_PORT = email["EMAIL_PORT"]
EMAIL_HOST_PASSWORD = email["EMAIL_HOST_PASSWORD"]
EMAIL_HOST_USER = email["EMAIL_HOST_USER"]
EMAIL_USE_TLS = email["EMAIL_USE_TLS"]

# Parse cache URLS, e.g "redis://localhost:6379/0"
CACHES = {"default": env.dj_cache_url("CACHE_URL")}

For local development, use a .env file to override the default configuration.

# .env
DEBUG=true
SECRET_KEY="not so secret"

For a more complete example, see django_example.py in the examples/ directory.

Why...?

Why envvars?

See The 12-factor App section on configuration.

Why not os.environ?

While os.environ is enough for simple use cases, a typical application will need a way to manipulate and validate raw environment variables. environs abstracts common tasks for handling environment variables.

environs will help you

  • cast envvars to the correct type
  • specify required envvars
  • define default values
  • validate envvars
  • parse list and dict values
  • parse dates, datetimes, and timedeltas
  • parse expanded variables
  • serialize your configuration to JSON, YAML, etc.

Why another library?

There are many great Python libraries for parsing environment variables. In fact, most of the credit for environs' public API goes to the authors of envparse and django-environ.

environs aims to meet three additional goals:

  1. Make it easy to extend parsing behavior and develop plugins.
  2. Leverage the deserialization and validation functionality provided by a separate library (marshmallow).
  3. Clean up redundant API.

See this GitHub issue which details specific differences with envparse.

License

MIT licensed. See the LICENSE file for more details.

Comments
  • Add support for a cache_url for Django

    Add support for a cache_url for Django

    I just switched to this library from https://github.com/joke2k/django-environ. One thing that it had was a way to set a cache_url for configuring Django's cache framework. It would be nice if you could just update the setup.py to install https://github.com/ghickman/django-cache-url, however it looks like it's deprecated.

    enhancement help wanted 
    opened by epicserve 14
  • Add env.secret

    Add env.secret

    For casting strings that shouldn't be revealed in tracebacks, etc.

    See https://github.com/encode/starlette/blob/1e1f3bab464d497a9250590a72b025f6095b20a7/starlette/datastructures.py#L179

    feedback welcome 
    opened by sloria 9
  • Dict Error -> ValueError: not enough values to unpack (expected 2, got 1)

    Dict Error -> ValueError: not enough values to unpack (expected 2, got 1)

    Hi Sloria, i found this error while running a script i made:

    test = env.dict("id_services") File "/home/john4s/Desktop/pyMail/.env/lib/python3.8/site-packages/environs/init.py", line 89, in method value = preprocess(value, subcast=subcast, **kwargs) File "/home/john4s/Desktop/pyMail/.env/lib/python3.8/site-packages/environs/init.py", line 174, in _preprocess_dict return { File "/home/john4s/Desktop/pyMail/.env/lib/python3.8/site-packages/environs/init.py", line 178, in for key, val in (item.split("=", 1) for item in value.split(",") if value) ValueError: not enough values to unpack (expected 2, got 1)

    This error appears only if i want to get a dict from an env file, i tried to pass 2 args in the function but the error appear again.

    Regards, john4s

    opened by gdjohn4s 8
  • Support for env var substitutions in env.str and env.dict and other composite types

    Support for env var substitutions in env.str and env.dict and other composite types

    I found some use cases where doing env var substitution inside the VALUE of another envvar it's very helpful.

    For example:

    DB_URI=postgres://${PGUSER:-gnarvaja}:${PGPASS}@myserver/mydb
    PGPASS=awesome
    

    And being able to read the variable like this would be awesome:

    >>> env.str("DB_URI", substitute_envs=True)
    postgres://gnarvaja:awesome@myserver/mydb
    

    The main use case is when you have the user/pass as individuals secrets (perhaps handled by an operator like https://github.com/zalando/postgres-operator) but you need a URI with parts that don't need to be secret.

    Another use case is a workaround when composite variables like dict become too complex. For example:

    INIT_KARGS="name=foo,script_params=--http-header Referer=https://radiocut.fm"
    

    If you do env.dict("INIT_KARGS") you get ValueError: too many values to unpack because of the "=" in the second value. So in this case you can do:

    INIT_KARGS="name=foo,script_params=--http-header ${HTTP_HEADER}"
    HTTP_HEADER="Referer=https://radiocut.fm"
    
    >>> env.dict("INIT_KARGS", substitute_envs=True)
    {"name": "foo", "script_params": "--http-header Referer=https://radiocut.fm"}
    

    We can use a syntax like this for the references to the environments variables: ${VARIABLE[:-default][:ttype]}. For example ${YEAR:-2020:tint}. (the :- is how you specify defaults in bash, the third :t parameter is for specifying the type is not str).

    Here is the code I'm using in my project (a bit ugly):

    envvar_matcher = re.compile(r'\$\{([A-Za-z0-9_]+)(:-[^\}:]*)?(:t[^\}]*)?\}')
    
    
    def _replace_envs(value):
        ret = ""
        prev_start = 0
        for m in envvar_matcher.finditer(value):
            env_name = m.group(1)
            env_default = m.group(2)
            env_type = m.group(3)
            if env_type is None:
                method = env.str
            else:
                method_name = env_type[2:]
                method = getattr(env, method_name)
            if env_default is None:
                env_value = method(env_name)
            else:
                env_default = env_default[2:]
                env_value = method(env_name, default=env_default)
    
            if m.start() == 0 and m.end() == len(value):
                return env_value
            ret += value[prev_start:m.start()] + env_value
            prev_start = m.end()
        ret += value[prev_start:]
        return ret
    
    

    If you agree with this new feature, I can try to do a PR. The new feature will be activated only if explicitly using substitute_envs=True as parameter.

    opened by gnarvaja 5
  • dump() is lazy?

    dump() is lazy?

    > from environs import Env
    > env = Env()
    > env.read_env()
    > loaded_env = env.dump()
    > 
    > loaded_env
    > {}
    > 
    > mytest = env('MYVAR')
    > loaded_env = env.dump()
    > loaded_env
    > {'MYVAR': my value}
    > 
    

    So loaded_env remains empty, even if there are valid entries in .env After a variable is accessed via env('MYVAR), it appears in the dump() result...

    Why not in the first case?

    opened by jacopsd 5
  •  Support for env var substitutions

    Support for env var substitutions

    Optional parameter for Env object to allow recursive variable substitutions.

    Example:

    # export PG_URL=postgres://${PGUSER:-sloria}:${PGPASS}@${PGHOST:-localhost}
    # export PGUSER=gnarvaja
    # export PGPASS=secret
    
    env = Env(expand_vars=True)
    assert env.str("PG_URL") == "postgres://gnarvaja:secret@localhost"
    
    opened by gnarvaja 4
  • Add argument `raise_error_if_not_found` for read_env

    Add argument `raise_error_if_not_found` for read_env

    • raise IOError when env file not found, this is an essential feature for serious deployment that should not run when the file is missing
    • print if env file is found or not when verbose=True
    opened by reorx 4
  • Error when parsing empty list with subcast

    Error when parsing empty list with subcast

    Hello,

    The env.list can't handle an empty list when using subcast It raises an exception environs.EnvValidationError: Environment variable "LIST" invalid: {0: ['Not a valid integer.']} This can be reproduced by e.g

        os.environ["LIST"] = ""
        env = Env()
        LIST = env.list("LIST", [], subcast=int)
    

    If you don't use subcast it works just fine by e.g

        os.environ["LIST"] = ""
        env = Env()
        LIST = env.list("LIST", [])
    

    Maybe one solution is if the env variable is falsy (empty or doesn't exist) env.list should return the default value if defined

    Happy to submit a PR if that would be of interest. Thanks!

    bug help wanted 
    opened by sabdouni 4
  • Add support for django-cache-url

    Add support for django-cache-url

    Added support for django-cache-url.

    Todo [x] Update the readme [x] Fix one test that is failing locally

    @sloria,

    I have one test that is failing locally. Let me know if you have any ideas.

    ============================== FAILURES ==============================
    ___ TestEnvFileReading.test_read_env_not_found_with_verbose_warns ____
    
    self = <test_environs.TestEnvFileReading object at 0x10e694070>
    env = <Env {}>
    
        def test_read_env_not_found_with_verbose_warns(self, env):
            with pytest.warns(UserWarning) as record:
    >           env.read_env("notfound", recurse=False, verbose=True)
    E           Failed: DID NOT WARN. No warnings of type (<class 'UserWarning'>,) was emitted. The list of emitted warnings is: [].
    
    tests/test_environs.py:233: Failed
    ------------------------- Captured log call --------------------------
    WARNING  dotenv.main:main.py:67 File doesn't exist notfound
    ==================== 1 failed, 67 passed in 0.17s ====================
    
    opened by epicserve 4
  • API is a bit strange

    API is a bit strange

    I know the title is a bit weird as well but bear with me, I'll explain where I'm coming from.

    Instances of classes usually hold and manage state related to their name. The main class in this library is called Env. That suggests to me that an instance of Env holds and manages the state of the environment. Now, let's look at some code:

    >>> from environs import Env
    >>> import os
    >>> env = Env()
    >>> env('FOO')
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
      File "/home/user/project/env/lib64/python3.7/site-packages/environs/__init__.py", line 74, in method
        raise EnvValidationError('Environment variable "{}" not set'.format(source_key), [message])
    environs.EnvValidationError: Environment variable "FOO" not set
    >>> os.environ['FOO'] = 'bar'
    >>> env('FOO')
    'bar'
    

    To me that is quite unexpected. It looks like manipulating os.environ changes the state of env, that's not really nice behavior.

    I do know that this is actually not how the library works. Env does not actually hold and manage any state related to the environment. The only state it holds is the parsing state, as in the variables it has parsed so far. Let's look at some more code (continuing where I left off):

    >>> env.dump()
    {'FOO': 'bar'}
    >>> os.environ['FOO'] = 'lorem'
    >>> env.dump()
    {'FOO': 'bar'}
    >>> env('FOO')
    'lorem'
    >>> env.dump()
    {'FOO': 'lorem'}
    

    dump seems to return all variables that have been parsed so far, including their values. But after changing the environment it still has the old value, quite unexpected again, it does keep some state. Only after parsing again, the new value shows up in the dump.

    Another confusing behavior is that of read_env which does not suggest any side effects but it does change the current environment. Granted, it does not override anything but it's still not ideal behavior.

    Some of the confusion can probably be fixed with better documentation.

    However, the reason I started writing this is another one. I was hoping that this library could help me parse the environment of another system, specifically a Docker container. But while it has all the wonderful tools I can't do that without polluting my own environment, and read_env only accepts file system paths while the underlying library would happily accept file-like objects as well.

    opened by dAnjou 4
  • Adding suffixed func to Env class

    Adding suffixed func to Env class

    Hi, everyone.

    Overview

    I would like to suggest adding the suffixed method to Env class. In some cases, suffix is fixed instead of prefix. For example,

    export HOGE_PATH=aaaa
    export FUGA_PATH=aaaa
    

    In this case, the below is clearer

    env = Env()
    env.read_env()
    with env.suffixed('_PATH'):
        hoge_path = env.str('HOGE')
        fuga_path = env.str('FUGA')
    

    Details

    I did three things

    • adding suffixed to environs/init.py
    • adding test codes corresponded to suffixed
    • editing _get_key method

    Alternative Options

    • Merging suffixed method into prefixed.

    Remains

    • document modification
    opened by hayata-yamamoto 4
  • Bump flake8-bugbear from 21.9.2 to 22.12.6

    Bump flake8-bugbear from 21.9.2 to 22.12.6

    Bumps flake8-bugbear from 21.9.2 to 22.12.6.

    Release notes

    Sourced from flake8-bugbear's releases.

    22.12.6

    • Add B905: zip() without an explicit strict= parameter. (#314)
    • B027: ignore @​overload when typing is imported with other names (#309)

    22.10.27

    • B027: Ignore @​overload decorator (#306)
    • B023: Also fix map (#305)
    • B023: Avoid false alarms with filter, reduce, key= and return. Added tests for functools (#303)

    22.10.25

    • Make B015 and B018 messages slightly more polite (#298)
    • Add B027: Empty method in abstract base class with no abstract decorator
    • Multiple B024 false positive fixes
    • Move CI to use tox (#294)
    • Move to using PEP621 / pyproject.toml package (#291)
    • Tested in 3.11

    22.9.23

    • add B026: find argument unpacking after keyword argument (#287)
    • Move to setup.cfg like flake8 (#288)

    22.9.11

    • Add B025: Find duplicate except clauses (#284)

    22.8.23

    • Add B024 error code to message for B024 (#276)

    22.8.22

    • Add B024: abstract base class with no abstract methods (#273)

    22.7.1

    22.6.22

    • Don't crash when select / extend_select are None (#261)
    • Ignore lambda arguments for B020 (#259)
    • Fix missing space typos in B021, B022 error messages (#257)

    22.4.25

    • Ignore black formatting for b013 test case (#251)
    • B010 Fix lambda false positive (#246)
    • B008 Fix edge case with lambda functions (#243)

    22.3.23

    • B006 and B008: Detect function calls at any level of the default expression (#239)
    • B020: Fix comprehension false postives (#238)
    • Tweak B019 desc (#237)

    ... (truncated)

    Commits
    • 7141009 Correct version buddy !
    • 9e9ff04 Update README + version for 22.12.6 release
    • 0826e81 Merge pull request #314 from jakkdl/zip_require_strict
    • a54a4a3 Update README.rst
    • e4de78e add b905: require strict= argument to zip()
    • 356f0dc B027 now ignores @[anything].overload to reduce false positives. (#309)
    • 9652dbd fix typo in unused comparison (B015) message (#307)
    • e81c636 Update README + version for 22.10.27 release
    • 7b2af62 Merge pull request #306 from jakkdl/b027_ignore_overload
    • 7a0b1e4 Merge pull request #305 from jakkdl/B023-false-alarms
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Bump flake8 from 4.0.1 to 6.0.0

    Bump flake8 from 4.0.1 to 6.0.0

    Bumps flake8 from 4.0.1 to 6.0.0.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Bump mypy from 0.910 to 0.991

    Bump mypy from 0.910 to 0.991

    Bumps mypy from 0.910 to 0.991.

    Commits
    • b7788fc Update version to remove "+dev" for releasing 0.991
    • 6077d19 manually CP typeshed #9130
    • ab0ea1e Fix crash with function redefinition (#14064)
    • 592a9ce Fix another crash with report generation on namespace packages (#14063)
    • 1650ae0 Update --no-warn-no-return docs for empty body changes (#14065)
    • b9daa31 Don't ignore errors in files passed on the command line (#14060)
    • 02fd8a5 Filter out wasm32 wheel in upload-pypi.py (#14035)
    • 131c8d7 Fix crash on inference with recursive alias to recursive instance (#14038)
    • 1368338 Change version to 0.991+dev in preparation for the point release
    • b71dc3d Remove +dev from version
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Is TOML support wanted?

    Is TOML support wanted?

    Python 3.11 is now introducing native toml support.

    Is this something that is wanted to support on this library? Or does it interfere with current use case, and it should be a completely different library? If the second, you can immediately close this issue.

    opened by bvanelli 0
  • Default values and subcast

    Default values and subcast

    As far as I can tell the default value can either be of the cast type or a string. So env.bool('FOO', True), env.bool('FOO', 'true'), env.bool('FOO', '1') and env.bool('FOO', 'YES') all are basically the same.

    >>> os.environ.get('FOO')
    >>> env.bool('FOO', True)
    True
    >>> env.bool('FOO', 'true')
    True
    >>> env.bool('FOO', '1')
    True
    >>> env.bool('FOO', 'YES')
    True
    

    The same goes for lists with a subcast to a basic type. env.list('FOO', '1, 2, 42', subcast=float) and env.list('FOO', [1.0, 2.0, 42.0], subcast=float) both do work.

    >>> env.list('FOO', '1, 2, 42', subcast=float)
    [1.0, 2.0, 42.0]
    >>> env.list('FOO', [1.0, 2.0, 42.0], subcast=float)
    [1.0, 2.0, 42.0]
    

    But, using the target type as default only works as long as the subcast type/callable can be called with the cast type itself. It breaks when the callable expects a string and returns something else. For example:

    >>> env.list('FOO', 'a:b, b:c', subcast=lambda s: tuple(s.split(':')))
    [('a', 'b'), (' b', 'c')]
    >>> env.list('FOO', ['a:b', 'b:c'], subcast=lambda s: tuple(s.split(':')))
    [('a', 'b'), ('b', 'c')]
    >>> env.list('FOO', [('a', 'b'), ('b', 'c')], subcast=lambda s: tuple(s.split(':')))
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
      File "[…]\lib\site-packages\environs\__init__.py", line 123, in method
        value = field.deserialize(value)
      File "[…]\lib\site-packages\marshmallow\fields.py", line 368, in deserialize
        output = self._deserialize(value, attr, data, **kwargs)
      File "[…]\lib\site-packages\marshmallow\fields.py", line 784, in _deserialize
        result.append(self.inner.deserialize(each, **kwargs))
      File "[…]\lib\site-packages\marshmallow\fields.py", line 368, in deserialize
        output = self._deserialize(value, attr, data, **kwargs)
      File "[…]\lib\site-packages\environs\__init__.py", line 188, in _deserialize
        return func(value)
      File "<console>", line 1, in <lambda>
    AttributeError: 'tuple' object has no attribute 'split'
    

    If this is expected behaviour, I’d be happy to provide a pull request with a supplement to the documentation (well, README.md).

    opened by tobiasmboelz 0
Owner
Steven Loria
Always a student, forever a junior developer
Steven Loria
Load Django Settings from Environmental Variables with One Magical Line of Code

DjEnv: Django + Environment Load Django Settings Directly from Environmental Variables features modify django configuration without modifying source c

Daniel J. Dufour 28 Oct 1, 2022
Inject your config variables into methods, so they are as close to usage as possible

Inject your config variables into methods, so they are as close to usage as possible

GDWR 7 Dec 14, 2022
A modern simfile parsing & editing library for Python 3

A modern simfile parsing & editing library for Python 3

ash garcia 38 Nov 1, 2022
Python YAML Environment (ymlenv) by Problem Fighter Library

In the name of God, the Most Gracious, the Most Merciful. PF-PY-YMLEnv Documentation Install and update using pip: pip install -U PF-PY-YMLEnv Please

Problem Fighter 2 Jan 20, 2022
Python 3+ compatible port of the configobj library

configobj Python 3+ compatible port of the configobj library. Documentation You can find a full manual on how to use ConfigObj at readthedocs. If you

Differently Sized Kittens 288 Dec 14, 2022
A Python library to parse PARI/GP configuration and header files

pari-utils A Python library to parse PARI/GP configuration and header files. This is mainly used in the code generation of https://github.com/sagemath

Sage Mathematical Software System 3 Sep 18, 2022
A compact library for Python 3.10x that allows users to configure their SimPads real-time

SimpadLib v1.0.6 What is this? This is a python library programmed by Ashe Muller that allows users to interface directly with their SimPad devices, a

Ashe Muller 2 Jan 8, 2022
Configuration Management for Python ⚙

dynaconf - Configuration Management for Python. Features Inspired by the 12-factor application guide Settings management (default values, validation,

Bruno Rocha 2.8k Jan 6, 2023
Flexible Python configuration system. The last one you will ever need.

OmegaConf Description Project Code quality Docs and support OmegaConf is a hierarchical configuration system, with support for merging configurations

Omry Yadan 1.4k Jan 2, 2023
🤫 Easily manage configs and secrets in your Python projects (with CLI support)

Installation pip install confidential How does it work? Confidential manages secrets for your project, using AWS Secrets Manager. First, store a secr

Candid™️ 63 Oct 30, 2022
Python Marlin Configurator to make valid configuration files to be used to compile Marlin with.

marlin-configurator Concept originally imagined by The-EG using PowerShell Build Script for Marlin Configurations The purpose of this project is to pa

DevPeeps 2 Oct 9, 2021
Read configuration settings from python configuration files.

Maison Read configuration settings from python configuration files. Motivation When developing a python application, e.g a command-line tool, it can b

null 9 Jan 4, 2023
Simple dataclasses configuration management for Python with hocon/json/yaml/properties/env-vars/dict support.

Simple dataclasses configuration management for Python with hocon/json/yaml/properties/env-vars/dict support, based on awesome and lightweight pyhocon parsing library.

Teo Stocco 62 Dec 23, 2022
Scooch Configures Object Oriented Class Hierarchies for python

Scooch Scooch Configures Object Oriented Class Hierarchies for python. A good place to start with Scooch is at the documentation found here. Scooch is

Pandora Media, Inc. 6 Dec 20, 2022
A set of Python scripts and notebooks to help administer and configure Workforce projects.

Workforce Scripts A set of Python scripts and notebooks to help administer and configure Workforce projects. Notebooks Several example Jupyter noteboo

Esri 75 Sep 9, 2022
Apt2sbom python package generates SPDX or YAML files

Welcome to apt2sbom This package contains a library and a CLI tool to convert a Ubuntu software package inventory to a software bill of materials. You

Eliot Lear 15 Nov 13, 2022
A small example project for efficiently configuring a Python application with YAMLs and the CLI

Hydra Example Project for Python A small example project for efficiently configuring a Python application with YAMLs and the CLI. Why should I care? A

Florian Wilhelm 4 Dec 31, 2022
This script allows you to retrieve all functions / variables names of a Python code, and the variables values.

Memory Extractor This script allows you to retrieve all functions / variables names of a Python code, and the variables values. How to use it ? The si

Venax 2 Dec 26, 2021
Generates all variables from your .tf files into a variables.tf file.

tfvg Generates all variables from your .tf files into a variables.tf file. It searches for every var.variable_name in your .tf files and generates a v

null 1 Dec 1, 2022
Django-environ allows you to utilize 12factor inspired environment variables to configure your Django application.

Django-environ django-environ allows you to use Twelve-factor methodology to configure your Django application with environment variables. import envi

Daniele Faraglia 2.7k Jan 7, 2023