diff options
author | CoprDistGit <infra@openeuler.org> | 2023-04-10 12:25:03 +0000 |
---|---|---|
committer | CoprDistGit <infra@openeuler.org> | 2023-04-10 12:25:03 +0000 |
commit | ead48eb634827dc2ecfaff4b4a3ee4c2fabf2453 (patch) | |
tree | e7b6f4c97ad903196c299e9f55ea8288efef6e95 | |
parent | 792db65924d97ae26ea593d337982823964f99b5 (diff) |
automatic import of python-environs
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | python-environs.spec | 1432 | ||||
-rw-r--r-- | sources | 1 |
3 files changed, 1434 insertions, 0 deletions
@@ -0,0 +1 @@ +/environs-9.5.0.tar.gz diff --git a/python-environs.spec b/python-environs.spec new file mode 100644 index 0000000..4e815fc --- /dev/null +++ b/python-environs.spec @@ -0,0 +1,1432 @@ +%global _empty_manifest_terminate_build 0 +Name: python-environs +Version: 9.5.0 +Release: 1 +Summary: simplified environment variable parsing +License: MIT +URL: https://github.com/sloria/environs +Source0: https://mirrors.nju.edu.cn/pypi/web/packages/d4/e3/c3c6c76f3dbe3e019e9a451b35bf9f44690026a5bb1232f7b77097b72ff5/environs-9.5.0.tar.gz +BuildArch: noarch + +Requires: python3-marshmallow +Requires: python3-dotenv +Requires: python3-pytest +Requires: python3-dj-database-url +Requires: python3-dj-email-url +Requires: python3-django-cache-url +Requires: python3-flake8 +Requires: python3-flake8-bugbear +Requires: python3-mypy +Requires: python3-pre-commit +Requires: python3-tox +Requires: python3-dj-database-url +Requires: python3-dj-email-url +Requires: python3-django-cache-url +Requires: python3-flake8 +Requires: python3-flake8-bugbear +Requires: python3-mypy +Requires: python3-pre-commit +Requires: python3-pytest +Requires: python3-dj-database-url +Requires: python3-dj-email-url +Requires: python3-django-cache-url + +%description +# environs: simplified environment variable parsing + +[](https://pypi.org/project/environs/) +[](https://dev.azure.com/sloria/sloria/_build/latest?definitionId=12&branchName=master) +[](https://marshmallow.readthedocs.io/en/latest/upgrading.html) +[](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) +- [Variable expansion](#variable-expansion) +- [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 GITHUB_REPO_PRIORITY="webargs=2,konch=3" +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] + +# 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`](https://docs.python.org/3/library/pathlib.html)) +- `env.enum` (casts to any given enum type specified in `type` keyword argument, accepts optional `ignore_case` keyword argument) + +## 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) +``` + +## Variable expansion + +```python +# 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 + +```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("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 + +```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") +``` + +For local development, use a `.env` file to override the default +configuration. + +```bash +# .env +DEBUG=true +SECRET_KEY="not so secret" +``` + +Note: Because environs depends on [python-dotenv](https://github.com/theskumar/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. + +- [dj-database-url](https://github.com/jacobian/dj-database-url) +- [django-cache-url](https://github.com/epicserve/django-cache-url) +- [dj-email-url](https://github.com/migonzalvar/dj-email-url) + +Basic example: + +```python +# 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. + +```bash +# .env +DEBUG=true +SECRET_KEY="not so secret" +``` + +For a more complete example, see +[django_example.py](https://github.com/sloria/environs/blob/master/examples/django_example.py) +in the `examples/` directory. + +## Why\...? + +### Why envvars? + +See [The 12-factor App](http://12factor.net/config) section on +[configuration](http://12factor.net/config). + +### 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](https://github.com/rconradharris/envparse) and +[django-environ](https://github.com/joke2k/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](https://github.com/rconradharris/envparse/issues/12#issue-151036722) +which details specific differences with envparse. + +## License + +MIT licensed. See the +[LICENSE](https://github.com/sloria/environs/blob/master/LICENSE) file +for more details. + + + + +%package -n python3-environs +Summary: simplified environment variable parsing +Provides: python-environs +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +%description -n python3-environs +# environs: simplified environment variable parsing + +[](https://pypi.org/project/environs/) +[](https://dev.azure.com/sloria/sloria/_build/latest?definitionId=12&branchName=master) +[](https://marshmallow.readthedocs.io/en/latest/upgrading.html) +[](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) +- [Variable expansion](#variable-expansion) +- [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 GITHUB_REPO_PRIORITY="webargs=2,konch=3" +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] + +# 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`](https://docs.python.org/3/library/pathlib.html)) +- `env.enum` (casts to any given enum type specified in `type` keyword argument, accepts optional `ignore_case` keyword argument) + +## 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) +``` + +## Variable expansion + +```python +# 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 + +```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("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 + +```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") +``` + +For local development, use a `.env` file to override the default +configuration. + +```bash +# .env +DEBUG=true +SECRET_KEY="not so secret" +``` + +Note: Because environs depends on [python-dotenv](https://github.com/theskumar/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. + +- [dj-database-url](https://github.com/jacobian/dj-database-url) +- [django-cache-url](https://github.com/epicserve/django-cache-url) +- [dj-email-url](https://github.com/migonzalvar/dj-email-url) + +Basic example: + +```python +# 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. + +```bash +# .env +DEBUG=true +SECRET_KEY="not so secret" +``` + +For a more complete example, see +[django_example.py](https://github.com/sloria/environs/blob/master/examples/django_example.py) +in the `examples/` directory. + +## Why\...? + +### Why envvars? + +See [The 12-factor App](http://12factor.net/config) section on +[configuration](http://12factor.net/config). + +### 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](https://github.com/rconradharris/envparse) and +[django-environ](https://github.com/joke2k/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](https://github.com/rconradharris/envparse/issues/12#issue-151036722) +which details specific differences with envparse. + +## License + +MIT licensed. See the +[LICENSE](https://github.com/sloria/environs/blob/master/LICENSE) file +for more details. + + + + +%package help +Summary: Development documents and examples for environs +Provides: python3-environs-doc +%description help +# environs: simplified environment variable parsing + +[](https://pypi.org/project/environs/) +[](https://dev.azure.com/sloria/sloria/_build/latest?definitionId=12&branchName=master) +[](https://marshmallow.readthedocs.io/en/latest/upgrading.html) +[](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) +- [Variable expansion](#variable-expansion) +- [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 GITHUB_REPO_PRIORITY="webargs=2,konch=3" +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] + +# 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`](https://docs.python.org/3/library/pathlib.html)) +- `env.enum` (casts to any given enum type specified in `type` keyword argument, accepts optional `ignore_case` keyword argument) + +## 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) +``` + +## Variable expansion + +```python +# 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 + +```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("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 + +```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") +``` + +For local development, use a `.env` file to override the default +configuration. + +```bash +# .env +DEBUG=true +SECRET_KEY="not so secret" +``` + +Note: Because environs depends on [python-dotenv](https://github.com/theskumar/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. + +- [dj-database-url](https://github.com/jacobian/dj-database-url) +- [django-cache-url](https://github.com/epicserve/django-cache-url) +- [dj-email-url](https://github.com/migonzalvar/dj-email-url) + +Basic example: + +```python +# 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. + +```bash +# .env +DEBUG=true +SECRET_KEY="not so secret" +``` + +For a more complete example, see +[django_example.py](https://github.com/sloria/environs/blob/master/examples/django_example.py) +in the `examples/` directory. + +## Why\...? + +### Why envvars? + +See [The 12-factor App](http://12factor.net/config) section on +[configuration](http://12factor.net/config). + +### 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](https://github.com/rconradharris/envparse) and +[django-environ](https://github.com/joke2k/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](https://github.com/rconradharris/envparse/issues/12#issue-151036722) +which details specific differences with envparse. + +## License + +MIT licensed. See the +[LICENSE](https://github.com/sloria/environs/blob/master/LICENSE) file +for more details. + + + + +%prep +%autosetup -n environs-9.5.0 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-environs -f filelist.lst +%dir %{python3_sitelib}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Mon Apr 10 2023 Python_Bot <Python_Bot@openeuler.org> - 9.5.0-1 +- Package Spec generated @@ -0,0 +1 @@ +7df5cb194ff30a004e1f03d9b4fdbee6 environs-9.5.0.tar.gz |