summaryrefslogtreecommitdiff
path: root/python-environs.spec
diff options
context:
space:
mode:
Diffstat (limited to 'python-environs.spec')
-rw-r--r--python-environs.spec1432
1 files changed, 1432 insertions, 0 deletions
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
+
+[![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 3 compatible](https://badgen.net/badge/marshmallow/3)](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)
+- [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
+
+[![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 3 compatible](https://badgen.net/badge/marshmallow/3)](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)
+- [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
+
+[![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 3 compatible](https://badgen.net/badge/marshmallow/3)](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)
+- [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