GitLab is used only for code review, issue tracking and project management. Canonical locations for source code are still https://gitweb.torproject.org/ https://git.torproject.org/ and git-rw.torproject.org.

Commit 95b15ac3 authored by Hiro's avatar Hiro 🏄
Browse files

Merge contribution from giant-rabbit for the donate portal

parents c55b8645 600dcb3e
...@@ -2,3 +2,5 @@ ...@@ -2,3 +2,5 @@
__pycache__ __pycache__
*.pyc *.pyc
.egg* .egg*
/packages/txt-to-html/lektor_txt_to_html.egg-info/
/packages/xml-to-html/lektor_xml_to_html.egg-info/
# Changelog
## 8.0.0 (2020-05-27)
Bug fixes:
- Fix behavior of recurse=True when custom filepath is passed to `env.read_env`
([#100](https://github.com/sloria/environs/issues/100)). Thanks [ribeaud](https://github.com/ribeaud) and [timoklimmer](https://github.com/sloria/environs/pull/157) for the help.
Other changes:
- _Backwards-incompatible_: As a result of the above fix, passing a directory to `env.read_env` is no longer allowed and will raise a `ValueError`.
Only file paths or file names should be passed.
## 7.4.0 (2020-04-18)
- Add `subcast_key` argument to `env.dict` ([#151](https://github.com/sloria/environs/issues/151)).
Thanks [AugPro](https://github.com/AugPro) for the suggestion and PR.
## 7.3.1 (2020-03-22)
- Fix error when parsing empty list with subcast
[#137](https://github.com/sloria/environs/issues/137).
Thanks [sabdouni] for the catch and patch.
## 7.3.0 (2020-03-01)
- `log_level` accepts lower-cased log level names and rejects invalid
names ([#138](https://github.com/sloria/environs/pull/138)).
Thanks [gnarvaja](https://github.com/gnarvaja) for the PR.
## 7.2.0 (2020-02-09)
- Add `dj_cache_url` for caching Django cache URLs (requires installing with `[django]`)
([#126](https://github.com/sloria/environs/issues/126)).
Thanks [epicserve](https://github.com/epicserve) for the suggestion and PR.
## 7.1.0 (2019-12-07)
- Improve typings and run mypy with dependencies type annotations ([#115](https://github.com/sloria/environs/pull/115)).
- Distribute types per PEP 561 ([#116](https://github.com/sloria/environs/pull/116)).
Thanks [hukkinj1](https://github.com/hukkinj1) for the PRs.
## 7.0.0 (2019-12-02)
- _Backwards-incompatible_: Remove `stream` argument from `read_env`,
since it had no effect ([#114](https://github.com/sloria/environs/pull/114)).
- _Backwards-incompatible_: `Env.read_env` consistently returns `None`
([#111](https://github.com/sloria/environs/pull/111)).
- Remove unnecessary `__str__` definition ([#112](https://github.com/sloria/environs/pull/112)).
Thanks [hukkinj1](https://github.com/hukkinj1) for the PRs.
## 6.1.0 (2019-11-03)
Features:
- Add deferred validation via the `eager` parameter and `env.seal()` ([#56](https://github.com/sloria/environs/issues/56)).
Thanks [robertlagrant](https://github.com/robertlagrant) for the suggestion.
Other changes:
- Test against Python 3.8 ([#108](https://github.com/sloria/environs/pull/108)).
## 6.0.0 (2019-09-22)
Features:
- Default parser methods are now defined as bound methods.
This enables static analysis features, e.g. autocomplete ([#103](https://github.com/sloria/environs/issues/103)).
Thanks [rugleb](https://github.com/rugleb) for the suggestion.
_Backwards-incompatible_: As a result of this change, adding a parser name that is the same as an existing method
will result in an error being raised.
```python
import environs
env = environs.Env()
# Below conflicts with built-in `url` method.
# In <6.0.0, this would override the built-in method.
# In >=6.0.0, this raises an error:
# environs.ParserConflictError: Env already has a method with name 'url'. Use a different name.
@env.parser_for("url")
def https_url(value):
return "https://" + value
```
Bug fixes:
- Fix error message for prefixed variables ([#102](https://github.com/sloria/environs/issues/102)).
Thanks [AGeekInside](https://github.com/AGeekInside) for reporting.
Other changes:
- _Backwards-incompatible_: Rename `Env.__parser_map__` to `Env.__custom_parsers__`.
## 5.2.1 (2019-08-08)
Bug fixes:
- Fix behavior when recursively searching for a specified file
([#96](https://github.com/sloria/environs/issues/96)).
Thanks [ribeaud](https://github.com/ribeaud) for the catch and patch.
## 5.2.0 (2019-07-19)
Changes:
- Improve typings.
## 5.1.0 (2019-07-13)
Features:
- Add `env.log_level` ([#7](https://github.com/sloria/environs/issues/7)).
- Use `raise from` to improve tracebacks.
Other changes:
- Improve typings.
## 5.0.0 (2019-07-06)
Features:
- Add `env.path` ([#81](https://github.com/sloria/environs/issues/81)).
Thanks [umrashrf](https://github.com/umrashrf) for the suggestion.
- Add type annotations.
Other changes:
- _Backwards-incompatible_: Drop support for Python 2. If you use Python 2,
you will need to use version 4.2.0 or older.
## 4.2.0 (2019-06-01)
- Minor optimization.
Bug fixes:
- Reset prefix when an exception is raised within an `env.prefixed()`
context ([#78](https://github.com/sloria/environs/issues/78)).
Thanks [rcuza](https://github.com/rcuza) for the catch and patch.
## 4.1.3 (2019-05-15)
Bug fixes:
- Fix behavior when passing a `dict` value as the default
to `env.dict` ([#76](https://github.com/sloria/environs/pull/76)).
Thanks [c-w](https://github.com/c-w) for the PR.
Support:
- Document how to read a specific file with `env.read_env`
([#66](https://github.com/sloria/environs/issues/66)).
Thanks [nvtkaszpir](https://github.com/nvtkaszpir) and
[c-w](https://github.com/c-w).
## 4.1.2 (2019-05-05)
Bug fixes:
- Fix compatibility with marshmallow 3.0.0>=rc6.
## 4.1.1 (2019-05-04)
Bug fixes:
- Fix accessing proxied envvars when using `env.prefixed`
([#72](https://github.com/sloria/environs/issues/72)).
Thanks [Kamforka](https://github.com/Kamforka) for the catch and patch.
- Fix behavior when an envvar is explicitly set to an empty string
([#71](https://github.com/sloria/environs/issues/71)).
Thanks [twosigmajab](https://github.com/twosigmajab) for reporting
and thanks [hvtuananh](https://github.com/hvtuananh) for the PR.
## 4.1.0 (2018-12-10)
- `EnvError` subclasses `ValueError` ([#50](https://github.com/sloria/environs/pull/50)).
Thanks [alexpirine](https://github.com/alexpirine).
- Test against Python 3.7.
## 4.0.0 (2018-08-06)
- Use python-dotenv for parsing .env files. `Env.read_env` behaves
mostly the same except that a warning isn't raised by default if a
.env file isn\'t found. Pass `verbose=True` to raise a warning.
## 3.0.0 (2018-08-05)
Features:
- _Backwards-incompatible_: `Env.read_env` raises a warning instead of
an error when `.env` isn\'t found
([#10](https://github.com/sloria/environs/issues/10)). Thanks
[lachlancooper](https://github.com/lachlancooper) for the
suggestion.
- Add optional Django support. Install using
`pip install environs[django]`, which enables `env.dj_db_url` and
`env.dj_email_url`.
## 2.1.1 (2018-05-21)
Features:
- Fix compatibility with marshmallow 3 beta.
## 2.1.0 (2018-01-25)
Features:
- Add recurse parameter to Env.read_env
([#9](https://github.com/sloria/environs/pull/9)). Thanks
[gthank](https://github.com/gthank) for the PR.
## 2.0.0 (2018-01-02)
Features:
- Add support for nested prefixes
([#8](https://github.com/sloria/environs/pull/8)). Thanks
[gvialetto](https://github.com/gvialetto) for the PR.
Other changes:
- _Backwards-incompatible_: Drop support for Python 3.3 and 3.4.
## 1.2.0 (2017-01-12)
Features:
- Add `url` parser that returns a `urllib.parse.ParseResult`
([#6](https://github.com/sloria/environs/issues/6)). Thanks
[IlyaSemenov](https://github.com/IlyaSemenov) for the suggestion.
Bug fixes:
- Every instance of `Env` gets its own parser map, so calling
`env.parser_for` for one instance doesn\'t affect other instances.
## 1.1.0 (2016-05-01)
- Add `Env.read_env` method for reading `.env` files.
## 1.0.0 (2016-04-30)
- Support for proxied variables
([#2](https://github.com/sloria/environs/issues/2)).
- _Backwards-incompatible_: Remove `env.get` method. Use `env()`
instead.
- Document how to read `.env` files
([#1](https://github.com/sloria/environs/issues/1)).
## 0.1.0 (2016-04-25)
- First PyPI release.
# Contributing
## Setting up for development
- Create and activate a new Python 3 virtual environment
- `pip install -e '.[dev]'`
- (Optional but recommended) Install the pre-commit hooks, which will
format and lint your git staged files:
```
# The pre-commit CLI was installed above
pre-commit install
```
- To run tests:
```
pytest
```
- To run syntax checks:
```
tox -e lint
```
- (Optional) To run tests on Python 3.5, 3.6, and 3.7 virtual environments (must have each interpreter installed):
```
tox
```
Copyright 2020 Steven Loria
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
include LICENSE
include *.rst *.md
Metadata-Version: 2.1
Name: environs
Version: 8.0.0
Summary: simplified environment variable parsing
Home-page: https://github.com/sloria/environs
Author: Steven Loria
Author-email: sloria1@gmail.com
License: MIT
Project-URL: Issues, https://github.com/sloria/environs/issues
Project-URL: Changelog, https://github.com/sloria/environs/blob/master/CHANGELOG.md
Description: # environs: simplified environment variable parsing
[![Latest version](https://badgen.net/pypi/v/environs)](https://pypi.org/project/environs/)
[![Build Status](https://dev.azure.com/sloria/sloria/_apis/build/status/sloria.environs?branchName=master)](https://dev.azure.com/sloria/sloria/_build/latest?definitionId=12&branchName=master)
[![marshmallow 2/3 compatible](https://badgen.net/badge/marshmallow/2,3?list=1)](https://marshmallow.readthedocs.io/en/latest/upgrading.html)
[![Black code style](https://badgen.net/badge/code%20style/black/000)](https://github.com/ambv/black)
**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](https://12factor.net/config) methodology.
## Contents
- [Features](#features)
- [Install](#install)
- [Basic usage](#basic-usage)
- [Supported types](#supported-types)
- [Reading .env files](#reading-env-files)
- [Reading a specific file](#reading-a-specific-file)
- [Handling prefixes](#handling-prefixes)
- [Proxied variables](#proxied-variables)
- [Validation](#validation)
- [Deferred validation](#deferred-validation)
- [Serialization](#serialization)
- [Defining custom parser behavior](#defining-custom-parser-behavior)
- [Usage with Flask](#usage-with-flask)
- [Usage with Django](#usage-with-django)
- [Why...?](#why)
- [Why envvars?](#why-envvars)
- [Why not os.environ?](#why-not-osenviron)
- [Why another library?](#why-another-library)
- [License](#license)
## 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](#usage-with-flask) and [Django](#usage-with-django)
## Install
pip install environs
## Basic usage
With some environment variables set...
```bash
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 COORDINATES=23.3,50.0
export LOG_LEVEL=DEBUG
```
Parse them with environs...
```python
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]
```
## 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` keyword argument)
- `env.dict` (accepts optional `subcast` keyword argument)
- `env.json`
- `env.datetime`
- `env.date`
- `env.timedelta` (assumes value is an integer in seconds)
- `env.url`
- `env.uuid`
- `env.log_level`
- `env.path` (casts to a [`pathlib.Path`](https://docs.python.org/3/library/pathlib.html))
## Reading `.env` files
```bash
# .env
DEBUG=true
PORT=4567
```
Call `Env.read_env` before parsing variables.
```python
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:
```python
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
```python
# 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)
```
## Proxied variables
```python
# export MAILGUN_LOGIN=sloria
# export SMTP_LOGIN={{MAILGUN_LOGIN}}
smtp_login = env("SMTP_LOGIN") # =>'sloria'
```
## Validation
```python
# 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.
```python
# 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
```python
# 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
```python
# 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("enum")
def enum_parser(value, choices):
if value not in choices:
raise environs.EnvError("Invalid!")
return value
color = env.enum("COLOR", choices=["black"]) # => raises EnvError
```
## Usage with Flask
```python
# 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.
```python
# myapp/app.py
from flask import Flask
app = Flask(__name__)
app.config.from_object("myapp.settings")