[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [lego/master] Move donate lektor packages to be local
commit 4903d4baa8b01b870b0af8be217012c19d57e644
Author: Peter Haight <peterh@xxxxxxxxxxxxxxx>
Date: Tue Oct 13 11:06:16 2020 -0700
Move donate lektor packages to be local
Adding the packages the new donate stuff is using to the repository so
that they do not need to be downloaded to run lektor. I had to make some
modifications to the setup.py files for these modules in order to get
them to work. Otherwise I was getting errors about invalid syntax in the
requires.txt files and also one of the modules was requiring lektor
which was pulling in a bunch of stuff that's not needed because we are
running inside lektor. I put all these changes in patch files in a new
patches subdirectory.
---
packages/environs/CHANGELOG.md | 259 ++++++++++++
packages/environs/CONTRIBUTING.md | 31 ++
packages/environs/LICENSE | 19 +
packages/environs/MANIFEST.in | 2 +
packages/environs/PKG-INFO | 458 +++++++++++++++++++++
packages/environs/README.md | 430 +++++++++++++++++++
packages/environs/environs.egg-info/PKG-INFO | 454 ++++++++++++++++++++
packages/environs/environs.egg-info/SOURCES.txt | 16 +
.../environs.egg-info/dependency_links.txt | 1 +
packages/environs/environs.egg-info/not-zip-safe | 1 +
packages/environs/environs.egg-info/requires.txt | 2 +
packages/environs/environs.egg-info/top_level.txt | 1 +
packages/environs/environs/__init__.py | 393 ++++++++++++++++++
packages/environs/environs/py.typed | 1 +
packages/environs/pyproject.toml | 3 +
packages/environs/setup.cfg | 19 +
packages/environs/setup.py | 66 +++
packages/envvars/LICENSE | 22 +
packages/envvars/MANIFEST.in | 2 +
packages/envvars/PKG-INFO | 106 +++++
packages/envvars/README.rst | 92 +++++
packages/envvars/lektor_envvars.egg-info/PKG-INFO | 106 +++++
.../envvars/lektor_envvars.egg-info/SOURCES.txt | 11 +
.../lektor_envvars.egg-info/dependency_links.txt | 1 +
.../lektor_envvars.egg-info/entry_points.txt | 3 +
.../envvars/lektor_envvars.egg-info/top_level.txt | 1 +
packages/envvars/lektor_envvars.py | 34 ++
packages/envvars/setup.cfg | 15 +
packages/envvars/setup.py | 21 +
packages/npm-support/CHANGELOG.md | 17 +
packages/npm-support/LICENSE.md | 32 ++
packages/npm-support/MANIFEST.in | 1 +
packages/npm-support/PKG-INFO | 132 ++++++
packages/npm-support/README.md | 120 ++++++
.../lektor_npm_support.egg-info/PKG-INFO | 131 ++++++
.../lektor_npm_support.egg-info/SOURCES.txt | 12 +
.../dependency_links.txt | 1 +
.../lektor_npm_support.egg-info/entry_points.txt | 3 +
.../lektor_npm_support.egg-info/top_level.txt | 1 +
packages/npm-support/lektor_npm_support.py | 143 +++++++
packages/npm-support/setup.cfg | 10 +
packages/npm-support/setup.py | 34 ++
packages/patches/environs.patch | 11 +
packages/patches/envvars.patch | 22 +
packages/patches/npm-support.patch | 14 +
45 files changed, 3254 insertions(+)
diff --git a/packages/environs/CHANGELOG.md b/packages/environs/CHANGELOG.md
new file mode 100644
index 0000000..ecacb75
--- /dev/null
+++ b/packages/environs/CHANGELOG.md
@@ -0,0 +1,259 @@
+# 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.
diff --git a/packages/environs/CONTRIBUTING.md b/packages/environs/CONTRIBUTING.md
new file mode 100644
index 0000000..becb151
--- /dev/null
+++ b/packages/environs/CONTRIBUTING.md
@@ -0,0 +1,31 @@
+# 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
+```
diff --git a/packages/environs/LICENSE b/packages/environs/LICENSE
new file mode 100644
index 0000000..f42c016
--- /dev/null
+++ b/packages/environs/LICENSE
@@ -0,0 +1,19 @@
+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.
diff --git a/packages/environs/MANIFEST.in b/packages/environs/MANIFEST.in
new file mode 100644
index 0000000..87602e8
--- /dev/null
+++ b/packages/environs/MANIFEST.in
@@ -0,0 +1,2 @@
+include LICENSE
+include *.rst *.md
diff --git a/packages/environs/PKG-INFO b/packages/environs/PKG-INFO
new file mode 100644
index 0000000..7f50360
--- /dev/null
+++ b/packages/environs/PKG-INFO
@@ -0,0 +1,458 @@
+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@xxxxxxxxx
+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")
+ ```
+
+ 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 proxied 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.
+
+Keywords: environment variables parsing config configuration 12factor envvars
+Platform: UNKNOWN
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Natural Language :: English
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Typing :: Typed
+Requires-Python: >=3.5.3
+Description-Content-Type: text/markdown
+Provides-Extra: django
+Provides-Extra: tests
+Provides-Extra: lint
+Provides-Extra: dev
diff --git a/packages/environs/README.md b/packages/environs/README.md
new file mode 100644
index 0000000..ab52e32
--- /dev/null
+++ b/packages/environs/README.md
@@ -0,0 +1,430 @@
+# 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")
+```
+
+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 proxied 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.
diff --git a/packages/environs/environs.egg-info/PKG-INFO b/packages/environs/environs.egg-info/PKG-INFO
new file mode 100644
index 0000000..75871a9
--- /dev/null
+++ b/packages/environs/environs.egg-info/PKG-INFO
@@ -0,0 +1,454 @@
+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@xxxxxxxxx
+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")
+ ```
+
+ 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 proxied 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.
+
+Keywords: environment variables parsing config configuration 12factor envvars
+Platform: UNKNOWN
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Natural Language :: English
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Typing :: Typed
+Requires-Python: >=3.5.3
+Description-Content-Type: text/markdown
diff --git a/packages/environs/environs.egg-info/SOURCES.txt b/packages/environs/environs.egg-info/SOURCES.txt
new file mode 100644
index 0000000..b7c6352
--- /dev/null
+++ b/packages/environs/environs.egg-info/SOURCES.txt
@@ -0,0 +1,16 @@
+CHANGELOG.md
+CONTRIBUTING.md
+LICENSE
+MANIFEST.in
+README.md
+pyproject.toml
+setup.cfg
+setup.py
+environs/__init__.py
+environs/py.typed
+environs.egg-info/PKG-INFO
+environs.egg-info/SOURCES.txt
+environs.egg-info/dependency_links.txt
+environs.egg-info/not-zip-safe
+environs.egg-info/requires.txt
+environs.egg-info/top_level.txt
\ No newline at end of file
diff --git a/packages/environs/environs.egg-info/dependency_links.txt b/packages/environs/environs.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/packages/environs/environs.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/packages/environs/environs.egg-info/not-zip-safe b/packages/environs/environs.egg-info/not-zip-safe
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/packages/environs/environs.egg-info/not-zip-safe
@@ -0,0 +1 @@
+
diff --git a/packages/environs/environs.egg-info/requires.txt b/packages/environs/environs.egg-info/requires.txt
new file mode 100644
index 0000000..6044479
--- /dev/null
+++ b/packages/environs/environs.egg-info/requires.txt
@@ -0,0 +1,2 @@
+marshmallow>=2.7.0
+python-dotenv
diff --git a/packages/environs/environs.egg-info/top_level.txt b/packages/environs/environs.egg-info/top_level.txt
new file mode 100644
index 0000000..a412994
--- /dev/null
+++ b/packages/environs/environs.egg-info/top_level.txt
@@ -0,0 +1 @@
+environs
diff --git a/packages/environs/environs/__init__.py b/packages/environs/environs/__init__.py
new file mode 100644
index 0000000..69d4431
--- /dev/null
+++ b/packages/environs/environs/__init__.py
@@ -0,0 +1,393 @@
+import collections
+import contextlib
+import inspect
+import functools
+import json as pyjson
+import logging
+import os
+import re
+import typing
+import types
+from collections.abc import Mapping
+from urllib.parse import urlparse, ParseResult
+from pathlib import Path
+
+import marshmallow as ma
+from dotenv.main import load_dotenv, _walk_to_root
+
+__version__ = "8.0.0"
+__all__ = ["EnvError", "Env"]
+
+MARSHMALLOW_VERSION_INFO = tuple(int(part) for part in ma.__version__.split(".") if part.isdigit())
+_PROXIED_PATTERN = re.compile(r"\s*{{\s*(\S*)\s*}}\s*")
+
+_T = typing.TypeVar("_T")
+_StrType = str
+_BoolType = bool
+_IntType = int
+
+ErrorMapping = typing.Mapping[str, typing.List[str]]
+ErrorList = typing.List[str]
+FieldFactory = typing.Callable[..., ma.fields.Field]
+Subcast = typing.Union[typing.Type, typing.Callable[..., _T]]
+FieldType = typing.Type[ma.fields.Field]
+FieldOrFactory = typing.Union[FieldType, FieldFactory]
+ParserMethod = typing.Callable[..., _T]
+
+
+class EnvError(ValueError):
+ """Raised when an environment variable or if a required environment variable is unset."""
+
+
+class EnvValidationError(EnvError):
+ def __init__(self, message: str, error_messages: typing.Union[ErrorList, ErrorMapping]):
+ self.error_messages = error_messages
+ super().__init__(message)
+
+
+class EnvSealedError(TypeError, EnvError):
+ pass
+
+
+class ParserConflictError(ValueError):
+ """Raised when adding a custom parser that conflicts with a built-in parser method."""
+
+
+def _field2method(
+ field_or_factory: FieldOrFactory, method_name: str, *, preprocess: typing.Callable = None
+) -> ParserMethod:
+ def method(
+ self: "Env", name: str, default: typing.Any = ma.missing, subcast: Subcast = None, **kwargs
+ ) -> _T:
+ if self._sealed:
+ raise EnvSealedError("Env has already been sealed. New values cannot be parsed.")
+ missing = kwargs.pop("missing", None) or default
+ if isinstance(field_or_factory, type) and issubclass(field_or_factory, ma.fields.Field):
+ field = field_or_factory(missing=missing, **kwargs)
+ else:
+ field = field_or_factory(subcast=subcast, missing=missing, **kwargs)
+ parsed_key, raw_value, proxied_key = self._get_from_environ(name, ma.missing)
+ self._fields[parsed_key] = field
+ source_key = proxied_key or parsed_key
+ if raw_value is ma.missing and field.missing is ma.missing:
+ message = "Environment variable not set."
+ if self.eager:
+ raise EnvValidationError('Environment variable "{}" not set'.format(source_key), [message])
+ else:
+ self._errors[parsed_key].append(message)
+ if raw_value or raw_value == "":
+ value = raw_value
+ else:
+ value = field.missing
+ if preprocess:
+ value = preprocess(value, subcast=subcast, **kwargs)
+ try:
+ value = field.deserialize(value)
+ except ma.ValidationError as error:
+ if self.eager:
+ raise EnvValidationError(
+ 'Environment variable "{}" invalid: {}'.format(source_key, error.args[0]), error.messages
+ ) from error
+ self._errors[parsed_key].extend(error.messages)
+ else:
+ self._values[parsed_key] = value
+ return value
+
+ method.__name__ = method_name
+ return method
+
+
+def _func2method(func: typing.Callable, method_name: str) -> ParserMethod:
+ def method(
+ self: "Env", name: str, default: typing.Any = ma.missing, subcast: typing.Type = None, **kwargs
+ ):
+ if self._sealed:
+ raise EnvSealedError("Env has already been sealed. New values cannot be parsed.")
+ parsed_key, raw_value, proxied_key = self._get_from_environ(name, default)
+ if raw_value is ma.missing:
+ raise EnvError('Environment variable "{}" not set'.format(proxied_key or parsed_key))
+ value = func(raw_value, **kwargs)
+ self._fields[parsed_key] = ma.fields.Field(**kwargs)
+ self._values[parsed_key] = value
+ return value
+
+ method.__name__ = method_name
+ return method
+
+
+# From webargs
+def _dict2schema(dct, schema_class=ma.Schema):
+ """Generate a `marshmallow.Schema` class given a dictionary of
+ `Fields <marshmallow.fields.Field>`.
+ """
+ if hasattr(schema_class, "from_dict"): # marshmallow 3
+ return schema_class.from_dict(dct)
+ attrs = dct.copy()
+
+ class Meta:
+ strict = True
+
+ attrs["Meta"] = Meta
+ return type("", (schema_class,), attrs)
+
+
+def _make_list_field(*, subcast: typing.Optional[type], **kwargs) -> ma.fields.List:
+ inner_field = ma.Schema.TYPE_MAPPING[subcast] if subcast else ma.fields.Field
+ return ma.fields.List(inner_field, **kwargs)
+
+
+def _preprocess_list(value: typing.Union[str, typing.Iterable], **kwargs) -> typing.Iterable:
+ if ma.utils.is_iterable_but_not_string(value):
+ return value
+ return typing.cast(str, value).split(",") if value != "" else []
+
+
+def _preprocess_dict(
+ value: typing.Union[str, typing.Mapping],
+ # TODO: Rename subcast to subcast_values and re-order arguments for next major release
+ subcast: Subcast,
+ subcast_key: Subcast = None,
+ **kwargs
+) -> typing.Mapping:
+ if isinstance(value, Mapping):
+ return value
+
+ return {
+ (subcast_key(key.strip()) if subcast_key else key.strip()): (
+ subcast(val.strip()) if subcast else val.strip()
+ )
+ for key, val in (item.split("=") for item in value.split(",") if value)
+ }
+
+
+def _preprocess_json(value: str, **kwargs):
+ return pyjson.loads(value)
+
+
+def _dj_db_url_parser(value: str, **kwargs) -> dict:
+ try:
+ import dj_database_url
+ except ImportError as error:
+ raise RuntimeError(
+ "The dj_db_url parser requires the dj-database-url package. "
+ "You can install it with: pip install dj-database-url"
+ ) from error
+ return dj_database_url.parse(value, **kwargs)
+
+
+def _dj_email_url_parser(value: str, **kwargs) -> dict:
+ try:
+ import dj_email_url
+ except ImportError as error:
+ raise RuntimeError(
+ "The dj_email_url parser requires the dj-email-url package. "
+ "You can install it with: pip install dj-email-url"
+ ) from error
+ return dj_email_url.parse(value, **kwargs)
+
+
+def _dj_cache_url_parser(value: str, **kwargs) -> dict:
+ try:
+ import django_cache_url
+ except ImportError as error:
+ raise RuntimeError(
+ "The dj_cache_url parser requires the django-cache-url package. "
+ "You can install it with: pip install django-cache-url"
+ ) from error
+ return django_cache_url.parse(value, **kwargs)
+
+
+class URLField(ma.fields.URL):
+ def _serialize(self, value: ParseResult, *args, **kwargs) -> str:
+ return value.geturl()
+
+ # Override deserialize rather than _deserialize because we need
+ # to call urlparse *after* validation has occurred
+ def deserialize(self, value: str, attr: str = None, data: typing.Mapping = None, **kwargs) -> ParseResult:
+ ret = super().deserialize(value, attr, data, **kwargs)
+ return urlparse(ret)
+
+
+class PathField(ma.fields.Str):
+ def _deserialize(self, value, *args, **kwargs) -> Path:
+ ret = super()._deserialize(value, *args, **kwargs)
+ return Path(ret)
+
+
+class LogLevelField(ma.fields.Int):
+ def _format_num(self, value) -> int:
+ try:
+ return super()._format_num(value)
+ except (TypeError, ValueError) as error:
+ value = value.upper()
+ if hasattr(logging, value) and isinstance(getattr(logging, value), int):
+ return getattr(logging, value)
+ else:
+ raise ma.ValidationError("Not a valid log level.") from error
+
+
+class Env:
+ """An environment variable reader."""
+
+ __call__ = _field2method(ma.fields.Field, "__call__") # type: ParserMethod
+
+ int = _field2method(ma.fields.Int, "int")
+ bool = _field2method(ma.fields.Bool, "bool")
+ str = _field2method(ma.fields.Str, "str")
+ float = _field2method(ma.fields.Float, "float")
+ decimal = _field2method(ma.fields.Decimal, "decimal")
+ list = _field2method(_make_list_field, "list", preprocess=_preprocess_list)
+ dict = _field2method(ma.fields.Dict, "dict", preprocess=_preprocess_dict)
+ json = _field2method(ma.fields.Field, "json", preprocess=_preprocess_json)
+ datetime = _field2method(ma.fields.DateTime, "datetime")
+ date = _field2method(ma.fields.Date, "date")
+ path = _field2method(PathField, "path")
+ log_level = _field2method(LogLevelField, "log_level")
+ timedelta = _field2method(ma.fields.TimeDelta, "timedelta")
+ uuid = _field2method(ma.fields.UUID, "uuid")
+ url = _field2method(URLField, "url")
+ dj_db_url = _func2method(_dj_db_url_parser, "dj_db_url")
+ dj_email_url = _func2method(_dj_email_url_parser, "dj_email_url")
+ dj_cache_url = _func2method(_dj_cache_url_parser, "dj_cache_url")
+
+ def __init__(self, *, eager: _BoolType = True):
+ self.eager = eager
+ self._sealed = False # type: bool
+ self._fields = {} # type: typing.Dict[_StrType, ma.fields.Field]
+ self._values = {} # type: typing.Dict[_StrType, typing.Any]
+ self._errors = collections.defaultdict(list) # type: ErrorMapping
+ self._prefix = None # type: typing.Optional[_StrType]
+ self.__custom_parsers__ = {} # type: typing.Dict[_StrType, ParserMethod]
+
+ def __repr__(self) -> _StrType:
+ return "<{} {}>".format(self.__class__.__name__, self._values)
+
+ @staticmethod
+ def read_env(
+ path: _StrType = None,
+ recurse: _BoolType = True,
+ verbose: _BoolType = False,
+ override: _BoolType = False,
+ ) -> None:
+ """Read a .env file into os.environ.
+
+ If .env is not found in the directory from which this method is called,
+ the default behavior is to recurse up the directory tree until a .env
+ file is found. If you do not wish to recurse up the tree, you may pass
+ False as a second positional argument.
+ """
+ if path is None:
+ # By default, start search from the same directory this function is called
+ current_frame = inspect.currentframe()
+ if not current_frame:
+ raise RuntimeError("Could not get current call frame.")
+ frame = typing.cast(types.FrameType, current_frame.f_back)
+ caller_dir = Path(frame.f_code.co_filename).parent.resolve()
+ start = caller_dir / ".env"
+ else:
+ if Path(path).is_dir():
+ raise ValueError("path must be a filename, not a directory.")
+ start = Path(path)
+ # TODO: Remove str casts when we drop Python 3.5
+ if recurse:
+ start_dir, env_name = os.path.split(str(start))
+ if not start_dir: # Only a filename was given
+ start_dir = os.getcwd()
+ for dirname in _walk_to_root(start_dir):
+ check_path = Path(dirname) / env_name
+ if check_path.exists():
+ load_dotenv(str(check_path), verbose=verbose, override=override)
+ return
+ else:
+ load_dotenv(str(start), verbose=verbose, override=override)
+
+ @contextlib.contextmanager
+ def prefixed(self, prefix: _StrType) -> typing.Iterator["Env"]:
+ """Context manager for parsing envvars with a common prefix."""
+ try:
+ old_prefix = self._prefix
+ if old_prefix is None:
+ self._prefix = prefix
+ else:
+ self._prefix = "{}{}".format(old_prefix, prefix)
+ yield self
+ finally:
+ # explicitly reset the stored prefix on completion and exceptions
+ self._prefix = None
+ self._prefix = old_prefix
+
+ def seal(self):
+ """Validate parsed values and prevent new values from being added.
+
+ :raises: environs.EnvValidationError
+ """
+ self._sealed = True
+ if self._errors:
+ error_messages = dict(self._errors)
+ self._errors = {}
+ raise EnvValidationError(
+ "Environment variables invalid: {}".format(error_messages), error_messages
+ )
+
+ def __getattr__(self, name: _StrType):
+ try:
+ return functools.partial(self.__custom_parsers__[name], self)
+ except KeyError as error:
+ raise AttributeError("{} has no attribute {}".format(self, name)) from error
+
+ def add_parser(self, name: _StrType, func: typing.Callable) -> None:
+ """Register a new parser method with the name ``name``. ``func`` must
+ receive the input value for an environment variable.
+ """
+ if hasattr(self, name):
+ raise ParserConflictError(
+ "Env already has a method with name '{}'. Use a different name.".format(name)
+ )
+ self.__custom_parsers__[name] = _func2method(func, method_name=name)
+ return None
+
+ def parser_for(self, name: _StrType) -> typing.Callable[[typing.Callable], typing.Callable]:
+ """Decorator that registers a new parser method with the name ``name``.
+ The decorated function must receive the input value for an environment variable.
+ """
+
+ def decorator(func: typing.Callable) -> typing.Callable:
+ self.add_parser(name, func)
+ return func
+
+ return decorator
+
+ def add_parser_from_field(self, name: _StrType, field_cls: typing.Type[ma.fields.Field]):
+ """Register a new parser method with name ``name``, given a marshmallow ``Field``."""
+ self.__custom_parsers__[name] = _field2method(field_cls, method_name=name)
+
+ def dump(self) -> typing.Mapping[_StrType, typing.Any]:
+ """Dump parsed environment variables to a dictionary of simple data types (numbers
+ and strings).
+ """
+ schema = _dict2schema(self._fields)()
+ dump_result = schema.dump(self._values)
+ return dump_result.data if MARSHMALLOW_VERSION_INFO[0] < 3 else dump_result
+
+ def _get_from_environ(
+ self, key: _StrType, default: typing.Any, *, proxied: _BoolType = False
+ ) -> typing.Tuple[_StrType, typing.Any, typing.Optional[_StrType]]:
+ """Access a value from os.environ. Handles proxied variables, e.g. SMTP_LOGIN={{MAILGUN_LOGIN}}.
+
+ Returns a tuple (envvar_key, envvar_value, proxied_key). The ``envvar_key`` will be different from
+ the passed key for proxied variables. proxied_key will be None if the envvar isn't proxied.
+
+ The ``proxied`` flag is recursively passed if a proxy lookup is required to get a
+ proxy env key.
+ """
+ env_key = self._get_key(key, omit_prefix=proxied)
+ value = os.environ.get(env_key, default)
+ if hasattr(value, "strip"):
+ match = _PROXIED_PATTERN.match(value)
+ if match: # Proxied variable
+ proxied_key = match.groups()[0]
+ return (key, self._get_from_environ(proxied_key, default, proxied=True)[1], proxied_key)
+ return env_key, value, None
+
+ def _get_key(self, key: _StrType, *, omit_prefix: _BoolType = False) -> _StrType:
+ return self._prefix + key if self._prefix and not omit_prefix else key
diff --git a/packages/environs/environs/py.typed b/packages/environs/environs/py.typed
new file mode 100644
index 0000000..e5aff4f
--- /dev/null
+++ b/packages/environs/environs/py.typed
@@ -0,0 +1 @@
+# Marker file for PEP 561.
\ No newline at end of file
diff --git a/packages/environs/pyproject.toml b/packages/environs/pyproject.toml
new file mode 100644
index 0000000..0a9deb6
--- /dev/null
+++ b/packages/environs/pyproject.toml
@@ -0,0 +1,3 @@
+[tool.black]
+line-length = 110
+target-version = ['py35', 'py36', 'py37', 'py38']
diff --git a/packages/environs/setup.cfg b/packages/environs/setup.cfg
new file mode 100644
index 0000000..f5ee4ef
--- /dev/null
+++ b/packages/environs/setup.cfg
@@ -0,0 +1,19 @@
+[bdist_wheel]
+universal = 1
+
+[flake8]
+ignore = E203, E266, E501, W503
+max-line-length = 110
+max-complexity = 18
+select = B,C,E,F,W,T4,B9
+
+[mypy]
+ignore_missing_imports = true
+warn_unreachable = true
+warn_unused_ignores = true
+warn_redundant_casts = true
+
+[egg_info]
+tag_build =
+tag_date = 0
+
diff --git a/packages/environs/setup.py b/packages/environs/setup.py
new file mode 100644
index 0000000..01b2ae3
--- /dev/null
+++ b/packages/environs/setup.py
@@ -0,0 +1,66 @@
+import re
+from setuptools import setup
+
+INSTALL_REQUIRES = ["marshmallow>=2.7.0", "python-dotenv"]
+DJANGO_REQUIRES = ["dj-database-url", "dj-email-url", "django-cache-url"]
+EXTRAS_REQUIRE = {
+ "django": DJANGO_REQUIRES,
+ "tests": ["pytest"] + DJANGO_REQUIRES,
+ "lint": ["flake8==3.8.2", "flake8-bugbear==20.1.4", "mypy==0.770", "pre-commit~=2.4"],
+}
+EXTRAS_REQUIRE["dev"] = EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["lint"] + ["tox"]
+PYTHON_REQUIRES = ">=3.5.3"
+
+
+def find_version(fname):
+ version = ""
+ with open(fname) as fp:
+ reg = re.compile(r'__version__ = [\'"]([^\'"]*)[\'"]')
+ for line in fp:
+ m = reg.match(line)
+ if m:
+ version = m.group(1)
+ break
+ if not version:
+ raise RuntimeError("Cannot find version information")
+ return version
+
+
+def read(fname):
+ with open(fname) as fp:
+ content = fp.read()
+ return content
+
+
+setup(
+ name="environs",
+ packages=["environs"],
+ package_data={"environs": ["py.typed"]},
+ version=find_version("environs/__init__.py"),
+ description="simplified environment variable parsing",
+ long_description=read("README.md"),
+ long_description_content_type="text/markdown",
+ author="Steven Loria",
+ author_email="sloria1@xxxxxxxxx",
+ url="https://github.com/sloria/environs",
+ install_requires=INSTALL_REQUIRES,
+ license="MIT",
+ zip_safe=False,
+ python_requires=PYTHON_REQUIRES,
+ keywords="environment variables parsing config configuration 12factor envvars",
+ classifiers=[
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: MIT License",
+ "Natural Language :: English",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.5",
+ "Programming Language :: Python :: 3.6",
+ "Programming Language :: Python :: 3.7",
+ "Programming Language :: Python :: 3.8",
+ "Typing :: Typed",
+ ],
+ project_urls={
+ "Issues": "https://github.com/sloria/environs/issues",
+ "Changelog": "https://github.com/sloria/environs/blob/master/CHANGELOG.md",
+ },
+)
diff --git a/packages/envvars/LICENSE b/packages/envvars/LICENSE
new file mode 100644
index 0000000..34265df
--- /dev/null
+++ b/packages/envvars/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 Sebastian Vetter
+
+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.
+
diff --git a/packages/envvars/MANIFEST.in b/packages/envvars/MANIFEST.in
new file mode 100644
index 0000000..4ea5ff5
--- /dev/null
+++ b/packages/envvars/MANIFEST.in
@@ -0,0 +1,2 @@
+include README.rst LICENSE
+prune *.pyc
diff --git a/packages/envvars/PKG-INFO b/packages/envvars/PKG-INFO
new file mode 100644
index 0000000..b05ad8a
--- /dev/null
+++ b/packages/envvars/PKG-INFO
@@ -0,0 +1,106 @@
+Metadata-Version: 1.1
+Name: lektor-envvars
+Version: 18.6.12.4
+Summary: A Lektor plugin making environment variables available in templates.
+Home-page: https://www.github.com/elbaschid/lektor-envvars
+Author: Sebastian Vetter
+Author-email: seb@xxxxxxxxx
+License: MIT
+Description: lektor-envvars
+ ##############
+
+ .. image:: https://circleci.com/gh/elbaschid/lektor-envvars.svg?style=svg
+ :target: https://circleci.com/gh/elbaschid/lektor-envvars
+
+
+ Why this project?
+ -----------------
+
+ **TL;DR** You can use environment variables in your Lektor templates.
+
+ I've been working with `Lektor <https://www.getlektor.com/docs/plugins/>`_ as as
+ static site generator in quite a few projects and really enjoy it. Most recently
+ I work on a project that used an environment variable to create slightly
+ different version of the site for ``development``, ``staging`` and ``production``.
+
+ Lektor doesn't have a way to add *environment variables* into the templates, so
+ I started building my own little plugin.
+
+
+ How to install it in Lektor
+ ---------------------------
+
+ You can easily install this plugin following the `Lektor docs
+ <https://www.getlektor.com/docs/plugins/>`_. All you need to do is run::
+
+ $ lektor plugin add lektor-envvars
+
+ This will automatically install the plugin and add it to your project
+ configuration.
+
+
+ Using environment variables
+ ---------------------------
+
+ You are able to access environment variables using the ``envvars`` function
+ inside your Jinja2 template. This function is added whenever lektor is running
+ a new build.
+
+ All environment variables are prefixed with ``LEKTOR_`` by default. Let's look
+ at a simple example with an environment varialbe ``LEKTOR_DEBUG=true``::
+
+ $ export LEKTOR_DEBUG=true
+
+ You can access this variable inside any Jinja2 template::
+
+ {{ envvars('DEBUG') }}
+
+ which will display ``true`` instead.
+
+
+ Converting values
+ -----------------
+
+ That's a great start but what if you want this to be a boolean value instead of
+ the string ``true``? You simply convert the value::
+
+ {{ envvars('DEBUG', bool) }}
+
+ or you can now even do::
+
+ {% if envvars('DEBUG', bool) %}
+ ...
+ {% endif %}
+
+
+ Custom prefixes (or no prefix)
+ ------------------------------
+
+ If you don't like the ``LEKTOR_`` prefix, you can either use your own prefix by
+ setting the prefix in the ``configs/lektor-envvars.ini`` file::
+
+ [envvars]
+ prefix = MY_OWN_
+
+ You can now use ``MY_OWN_DEBUG`` instead of ``LEKTOR_DEBUG``. This means that
+ all environment variables need to be prefixed with ``MY_OWN_`` now instead.
+
+ You can also ignore the prefix all together::
+
+ {{ envvars('DEBUG', no_prefix=True) }}
+
+ which will give you access to the environment variable ``DEBUG``.
+
+
+ License
+ -------
+
+ This code is licensed under the `MIT License`_.
+
+ .. _`MIT License`: https://github.com/elbaschid/lektor-envvars/blob/master/LICENSE
+
+Platform: UNKNOWN
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: Implementation :: CPython
diff --git a/packages/envvars/README.rst b/packages/envvars/README.rst
new file mode 100644
index 0000000..1d8c374
--- /dev/null
+++ b/packages/envvars/README.rst
@@ -0,0 +1,92 @@
+lektor-envvars
+##############
+
+.. image:: https://circleci.com/gh/elbaschid/lektor-envvars.svg?style=svg
+ :target: https://circleci.com/gh/elbaschid/lektor-envvars
+
+
+Why this project?
+-----------------
+
+**TL;DR** You can use environment variables in your Lektor templates.
+
+I've been working with `Lektor <https://www.getlektor.com/docs/plugins/>`_ as as
+static site generator in quite a few projects and really enjoy it. Most recently
+I work on a project that used an environment variable to create slightly
+different version of the site for ``development``, ``staging`` and ``production``.
+
+Lektor doesn't have a way to add *environment variables* into the templates, so
+I started building my own little plugin.
+
+
+How to install it in Lektor
+---------------------------
+
+You can easily install this plugin following the `Lektor docs
+<https://www.getlektor.com/docs/plugins/>`_. All you need to do is run::
+
+ $ lektor plugin add lektor-envvars
+
+This will automatically install the plugin and add it to your project
+configuration.
+
+
+Using environment variables
+---------------------------
+
+You are able to access environment variables using the ``envvars`` function
+inside your Jinja2 template. This function is added whenever lektor is running
+a new build.
+
+All environment variables are prefixed with ``LEKTOR_`` by default. Let's look
+at a simple example with an environment varialbe ``LEKTOR_DEBUG=true``::
+
+ $ export LEKTOR_DEBUG=true
+
+You can access this variable inside any Jinja2 template::
+
+ {{ envvars('DEBUG') }}
+
+which will display ``true`` instead.
+
+
+Converting values
+-----------------
+
+That's a great start but what if you want this to be a boolean value instead of
+the string ``true``? You simply convert the value::
+
+ {{ envvars('DEBUG', bool) }}
+
+or you can now even do::
+
+ {% if envvars('DEBUG', bool) %}
+ ...
+ {% endif %}
+
+
+Custom prefixes (or no prefix)
+------------------------------
+
+If you don't like the ``LEKTOR_`` prefix, you can either use your own prefix by
+setting the prefix in the ``configs/lektor-envvars.ini`` file::
+
+ [envvars]
+ prefix = MY_OWN_
+
+You can now use ``MY_OWN_DEBUG`` instead of ``LEKTOR_DEBUG``. This means that
+all environment variables need to be prefixed with ``MY_OWN_`` now instead.
+
+You can also ignore the prefix all together::
+
+ {{ envvars('DEBUG', no_prefix=True) }}
+
+which will give you access to the environment variable ``DEBUG``.
+
+
+License
+-------
+
+This code is licensed under the `MIT License`_.
+
+.. _`MIT License`: https://github.com/elbaschid/lektor-envvars/blob/master/LICENSE
diff --git a/packages/envvars/lektor_envvars.egg-info/PKG-INFO b/packages/envvars/lektor_envvars.egg-info/PKG-INFO
new file mode 100644
index 0000000..b05ad8a
--- /dev/null
+++ b/packages/envvars/lektor_envvars.egg-info/PKG-INFO
@@ -0,0 +1,106 @@
+Metadata-Version: 1.1
+Name: lektor-envvars
+Version: 18.6.12.4
+Summary: A Lektor plugin making environment variables available in templates.
+Home-page: https://www.github.com/elbaschid/lektor-envvars
+Author: Sebastian Vetter
+Author-email: seb@xxxxxxxxx
+License: MIT
+Description: lektor-envvars
+ ##############
+
+ .. image:: https://circleci.com/gh/elbaschid/lektor-envvars.svg?style=svg
+ :target: https://circleci.com/gh/elbaschid/lektor-envvars
+
+
+ Why this project?
+ -----------------
+
+ **TL;DR** You can use environment variables in your Lektor templates.
+
+ I've been working with `Lektor <https://www.getlektor.com/docs/plugins/>`_ as as
+ static site generator in quite a few projects and really enjoy it. Most recently
+ I work on a project that used an environment variable to create slightly
+ different version of the site for ``development``, ``staging`` and ``production``.
+
+ Lektor doesn't have a way to add *environment variables* into the templates, so
+ I started building my own little plugin.
+
+
+ How to install it in Lektor
+ ---------------------------
+
+ You can easily install this plugin following the `Lektor docs
+ <https://www.getlektor.com/docs/plugins/>`_. All you need to do is run::
+
+ $ lektor plugin add lektor-envvars
+
+ This will automatically install the plugin and add it to your project
+ configuration.
+
+
+ Using environment variables
+ ---------------------------
+
+ You are able to access environment variables using the ``envvars`` function
+ inside your Jinja2 template. This function is added whenever lektor is running
+ a new build.
+
+ All environment variables are prefixed with ``LEKTOR_`` by default. Let's look
+ at a simple example with an environment varialbe ``LEKTOR_DEBUG=true``::
+
+ $ export LEKTOR_DEBUG=true
+
+ You can access this variable inside any Jinja2 template::
+
+ {{ envvars('DEBUG') }}
+
+ which will display ``true`` instead.
+
+
+ Converting values
+ -----------------
+
+ That's a great start but what if you want this to be a boolean value instead of
+ the string ``true``? You simply convert the value::
+
+ {{ envvars('DEBUG', bool) }}
+
+ or you can now even do::
+
+ {% if envvars('DEBUG', bool) %}
+ ...
+ {% endif %}
+
+
+ Custom prefixes (or no prefix)
+ ------------------------------
+
+ If you don't like the ``LEKTOR_`` prefix, you can either use your own prefix by
+ setting the prefix in the ``configs/lektor-envvars.ini`` file::
+
+ [envvars]
+ prefix = MY_OWN_
+
+ You can now use ``MY_OWN_DEBUG`` instead of ``LEKTOR_DEBUG``. This means that
+ all environment variables need to be prefixed with ``MY_OWN_`` now instead.
+
+ You can also ignore the prefix all together::
+
+ {{ envvars('DEBUG', no_prefix=True) }}
+
+ which will give you access to the environment variable ``DEBUG``.
+
+
+ License
+ -------
+
+ This code is licensed under the `MIT License`_.
+
+ .. _`MIT License`: https://github.com/elbaschid/lektor-envvars/blob/master/LICENSE
+
+Platform: UNKNOWN
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: Implementation :: CPython
diff --git a/packages/envvars/lektor_envvars.egg-info/SOURCES.txt b/packages/envvars/lektor_envvars.egg-info/SOURCES.txt
new file mode 100644
index 0000000..f5f878e
--- /dev/null
+++ b/packages/envvars/lektor_envvars.egg-info/SOURCES.txt
@@ -0,0 +1,11 @@
+LICENSE
+MANIFEST.in
+README.rst
+lektor_envvars.py
+setup.cfg
+setup.py
+lektor_envvars.egg-info/PKG-INFO
+lektor_envvars.egg-info/SOURCES.txt
+lektor_envvars.egg-info/dependency_links.txt
+lektor_envvars.egg-info/entry_points.txt
+lektor_envvars.egg-info/top_level.txt
\ No newline at end of file
diff --git a/packages/envvars/lektor_envvars.egg-info/dependency_links.txt b/packages/envvars/lektor_envvars.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/packages/envvars/lektor_envvars.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/packages/envvars/lektor_envvars.egg-info/entry_points.txt b/packages/envvars/lektor_envvars.egg-info/entry_points.txt
new file mode 100644
index 0000000..3c4ccf3
--- /dev/null
+++ b/packages/envvars/lektor_envvars.egg-info/entry_points.txt
@@ -0,0 +1,3 @@
+[lektor.plugins]
+envvars = lektor_envvars:EnvvarsPlugin
+
diff --git a/packages/envvars/lektor_envvars.egg-info/top_level.txt b/packages/envvars/lektor_envvars.egg-info/top_level.txt
new file mode 100644
index 0000000..f1daf87
--- /dev/null
+++ b/packages/envvars/lektor_envvars.egg-info/top_level.txt
@@ -0,0 +1 @@
+lektor_envvars
diff --git a/packages/envvars/lektor_envvars.py b/packages/envvars/lektor_envvars.py
new file mode 100644
index 0000000..034b127
--- /dev/null
+++ b/packages/envvars/lektor_envvars.py
@@ -0,0 +1,34 @@
+from environs import Env
+from lektor.pluginsystem import Plugin
+
+__version__ = "18.6.12.4"
+
+DEFAULT_PREFIX = "LEKTOR_"
+
+
+class LektorEnv:
+ def __init__(self, config=None):
+ self.env = Env()
+
+ if not config:
+ self.prefix = DEFAULT_PREFIX
+ else:
+ self.prefix = config.get("envvar.prefix", DEFAULT_PREFIX)
+
+ def envvars(self, name, var_type=None, no_prefix=False):
+ prefix = "" if no_prefix else self.prefix
+
+ with self.env.prefixed(prefix):
+ if var_type:
+ return getattr(self.env, var_type)(name)
+ else:
+ return self.env(name)
+
+
+class EnvvarsPlugin(Plugin):
+ name = "Environment Variables"
+ description = "A plugin making environment variables available in templates."
+
+ def on_setup_env(self, **extra):
+ config = self.get_config()
+ self.env.jinja_env.globals.update({"envvars": LektorEnv(config).envvars})
diff --git a/packages/envvars/setup.cfg b/packages/envvars/setup.cfg
new file mode 100644
index 0000000..9997f99
--- /dev/null
+++ b/packages/envvars/setup.cfg
@@ -0,0 +1,15 @@
+[wheel]
+universal = 1
+
+[flake8]
+ignore = F401
+max_line_length = 100
+exclude = .git,__pycache__,venv
+
+[tool:pytest]
+testpaths = tests.py
+
+[egg_info]
+tag_build =
+tag_date = 0
+
diff --git a/packages/envvars/setup.py b/packages/envvars/setup.py
new file mode 100644
index 0000000..1f78b84
--- /dev/null
+++ b/packages/envvars/setup.py
@@ -0,0 +1,21 @@
+from setuptools import setup
+
+
+setup(
+ name="lektor-envvars",
+ version="18.6.12.4",
+ description="A Lektor plugin making environment variables available in templates.",
+ long_description="\n\n".join([open("README.rst").read()]),
+ license="MIT",
+ author="Sebastian Vetter",
+ author_email="seb@xxxxxxxxx",
+ url="https://www.github.com/elbaschid/lektor-envvars",
+ py_modules=["lektor_envvars"],
+ entry_points={"lektor.plugins": ["envvars = lektor_envvars:EnvvarsPlugin"]},
+ classifiers=[
+ "License :: OSI Approved :: MIT License",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: Implementation :: CPython",
+ ],
+)
diff --git a/packages/npm-support/CHANGELOG.md b/packages/npm-support/CHANGELOG.md
new file mode 100644
index 0000000..8ea0991
--- /dev/null
+++ b/packages/npm-support/CHANGELOG.md
@@ -0,0 +1,17 @@
+# Change Log
+
+## 0.1.4
+- Bumped version number
+
+## 0.1.3
+- Change the content type of long_description to text/markdown
+
+## 0.1.2
+- Added the content of README.md as the long_description field to setup.py as requested by https://github.com/lektor/lektor-website/issues/203
+
+## 0.1.1
+- Fixed bugs in README.md.
+- Added a working Parcel example.
+
+## 0.1
+- Initial release
diff --git a/packages/npm-support/LICENSE.md b/packages/npm-support/LICENSE.md
new file mode 100644
index 0000000..a9d0e2c
--- /dev/null
+++ b/packages/npm-support/LICENSE.md
@@ -0,0 +1,32 @@
+Copyright (c) 2015-2017 by Armin Ronacher and lektor-webpack-support authors.
+Copyright (c) 2018 by Baruch Sterin.
+
+Some rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ * The names of the contributors may not be used to endorse or
+ promote products derived from this software without specific
+ prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/packages/npm-support/MANIFEST.in b/packages/npm-support/MANIFEST.in
new file mode 100644
index 0000000..0e52f9e
--- /dev/null
+++ b/packages/npm-support/MANIFEST.in
@@ -0,0 +1 @@
+include README.md LICENSE.md CHANGELOG.md
diff --git a/packages/npm-support/PKG-INFO b/packages/npm-support/PKG-INFO
new file mode 100644
index 0000000..59f9afb
--- /dev/null
+++ b/packages/npm-support/PKG-INFO
@@ -0,0 +1,132 @@
+Metadata-Version: 2.1
+Name: lektor-npm-support
+Version: 0.1.4
+Summary: Adds support for using npm/yarn to build assets in Lektor
+Home-page: http://github.com/sterin/lektor-npm-support
+Author: Baruch Sterin
+Author-email: lektor-npm-support@xxxxxxxxxxx
+License: BSD
+Description: # lektor-npm-support
+
+ [![Build Status](https://travis-ci.org/sterin/lektor-npm-support.svg)](https://travis-ci.org/sterin/lektor-npm-support)
+ [![Build status](https://ci.appveyor.com/api/projects/status/6op1csefpi9l8hbg?svg=true)](https://ci.appveyor.com/project/sterin/lektor-npm-support)
+ [![Code Coverage](https://codecov.io/gh/sterin/lektor-npm-support/branch/master/graph/badge.svg)](https://codecov.io/gh/sterin/lektor-npm-support)
+
+ `lektor-npm-support` makes it easy to use [Parcel](https://parcel.js.org), [webpack](https://webpack.js.org), [browserify](http://browserify.org/), or any other tool to build assets for [Lektor](https://github.com/lektor/lektor) projects.
+
+ ## Enabling the Plugin
+
+ To enable the plugin, run this command while inside your Lektor project directory:
+
+ ```bash
+ lektor plugins add lektor-npm-support
+ ```
+
+ ## Example: Creating a [Parcel](https://parceljs.org/) Project
+
+ Create a `parcel/` folder and inside that folder create the following files:
+
+ ### `configs/npm-support.ini`
+
+ This file instructs the plugin how to generate the assets:
+
+ ```ini
+ [parcel]
+ npm = yarn
+ watch_script = watch
+ build_script = build
+ ```
+
+ * The section name `[parcel]` is the name of the folder where the Parcel project is located.
+ * `npm` is the package manager command used to build the project. This example will use [Yarn](https://yarnpkg.com).
+ * `watch_script` is the npm script used in `lektor server -f npm`,
+ * `build_script` is the npm script used in `lektor build -f npm`.
+
+ This plugin supports more than one such entry.
+
+ ### `parcel/package.json`
+
+ This is a standard `package.json` file. It should contain two entries in the `scripts` section. The `build` script is used during `lektor build -f npm`, and the `watch` script is used during `lektor server -f npm`.
+
+ ```json
+ {
+ "name": "my-parcel-project",
+ "version": "1.0.0",
+ "scripts": {
+ "watch": "NODE_ENV=development parcel --out-dir=../assets/static/gen --out-file=main.js --public-url=./assets/ main.js",
+ "build": "NODE_ENV=production parcel build --out-dir=../assets/static/gen --out-file=main.js --public-url=./assets/ main.js"
+ },
+ "private": true
+ }
+ ```
+
+ Now we can use `yarn add` to add Parcel, [Babel](https://babeljs.io/) and [Sass](https://sass-lang.com/):
+
+ ```
+ $ cd </path/to/your/lektor/project>/parcel
+ $ yarn add parcel-bundler babel-preset-env node-sass
+ ```
+
+ ### `parcel/babelr.rc`
+
+ Next up is a simple Babel config file, using the recommended `env` preset.
+
+ ```json
+ {
+ "presets": ["env"]
+ }
+ ```
+
+ ### `parcel/main.scss`
+
+ A simple SCSS file.
+
+ ```scss
+ body {
+ border: 10px solid red;
+ }
+ ```
+
+ ### `parcel/main.js`
+
+ A simple Javascript file that imports the SCSS file so that Parcel will know to include it as well.
+
+ ```javascript
+ import './main.scss';
+ ```
+
+ ## Running the Server
+
+ Now you're ready to go. When you run `lektor server` nothing wil happen,
+ instead you need to now run it as `lektor server -f npm` which
+ will enable the Parcel build. Parcel will automatically build your files
+ into `assets/static/gen` and this is where Lektor will then pick up the
+ files. This is done so that you can ship the generated assets
+ to others that might not have these tools, which simplifies using a
+ Lektor website that use this plugin.
+
+ ## Manual Builds
+
+ To manually trigger a build that also invokes webpack you can use `lektor build -f npm`.
+
+ ## Including The Files
+
+ Now you need to include the files in your template. This will do it:
+
+ ```html
+ <link rel="stylesheet" href="{{ '/static/gen/main.css'| asseturl }}">
+ <script type=text/javascript src="{{ '/static/gen/main.js'| asseturl }}" charset="utf-8"></script>
+ ```
+
+ ## Complete Working Example
+
+ The `examples` folder of this repository contains working projects.
+
+
+ ## Credits
+
+ This plugin is based on the official [lektor-webpack-support](https://github.com/lektor/lektor-webpack-support) Lektor plugin by [Armin Ronacher](http://lucumr.pocoo.org/about/).
+
+Platform: UNKNOWN
+Description-Content-Type: text/markdown
+Provides-Extra: test
diff --git a/packages/npm-support/README.md b/packages/npm-support/README.md
new file mode 100644
index 0000000..235c5b5
--- /dev/null
+++ b/packages/npm-support/README.md
@@ -0,0 +1,120 @@
+# lektor-npm-support
+
+[![Build Status](https://travis-ci.org/sterin/lektor-npm-support.svg)](https://travis-ci.org/sterin/lektor-npm-support)
+[![Build status](https://ci.appveyor.com/api/projects/status/6op1csefpi9l8hbg?svg=true)](https://ci.appveyor.com/project/sterin/lektor-npm-support)
+[![Code Coverage](https://codecov.io/gh/sterin/lektor-npm-support/branch/master/graph/badge.svg)](https://codecov.io/gh/sterin/lektor-npm-support)
+
+`lektor-npm-support` makes it easy to use [Parcel](https://parcel.js.org), [webpack](https://webpack.js.org), [browserify](http://browserify.org/), or any other tool to build assets for [Lektor](https://github.com/lektor/lektor) projects.
+
+## Enabling the Plugin
+
+To enable the plugin, run this command while inside your Lektor project directory:
+
+```bash
+lektor plugins add lektor-npm-support
+```
+
+## Example: Creating a [Parcel](https://parceljs.org/) Project
+
+Create a `parcel/` folder and inside that folder create the following files:
+
+### `configs/npm-support.ini`
+
+This file instructs the plugin how to generate the assets:
+
+```ini
+[parcel]
+npm = yarn
+watch_script = watch
+build_script = build
+```
+
+* The section name `[parcel]` is the name of the folder where the Parcel project is located.
+* `npm` is the package manager command used to build the project. This example will use [Yarn](https://yarnpkg.com).
+* `watch_script` is the npm script used in `lektor server -f npm`,
+* `build_script` is the npm script used in `lektor build -f npm`.
+
+This plugin supports more than one such entry.
+
+### `parcel/package.json`
+
+This is a standard `package.json` file. It should contain two entries in the `scripts` section. The `build` script is used during `lektor build -f npm`, and the `watch` script is used during `lektor server -f npm`.
+
+```json
+{
+ "name": "my-parcel-project",
+ "version": "1.0.0",
+ "scripts": {
+ "watch": "NODE_ENV=development parcel --out-dir=../assets/static/gen --out-file=main.js --public-url=./assets/ main.js",
+ "build": "NODE_ENV=production parcel build --out-dir=../assets/static/gen --out-file=main.js --public-url=./assets/ main.js"
+ },
+ "private": true
+}
+```
+
+Now we can use `yarn add` to add Parcel, [Babel](https://babeljs.io/) and [Sass](https://sass-lang.com/):
+
+```
+$ cd </path/to/your/lektor/project>/parcel
+$ yarn add parcel-bundler babel-preset-env node-sass
+```
+
+### `parcel/babelr.rc`
+
+Next up is a simple Babel config file, using the recommended `env` preset.
+
+```json
+{
+ "presets": ["env"]
+}
+```
+
+### `parcel/main.scss`
+
+A simple SCSS file.
+
+```scss
+body {
+ border: 10px solid red;
+}
+```
+
+### `parcel/main.js`
+
+A simple Javascript file that imports the SCSS file so that Parcel will know to include it as well.
+
+```javascript
+import './main.scss';
+```
+
+## Running the Server
+
+Now you're ready to go. When you run `lektor server` nothing wil happen,
+instead you need to now run it as `lektor server -f npm` which
+will enable the Parcel build. Parcel will automatically build your files
+into `assets/static/gen` and this is where Lektor will then pick up the
+files. This is done so that you can ship the generated assets
+to others that might not have these tools, which simplifies using a
+Lektor website that use this plugin.
+
+## Manual Builds
+
+To manually trigger a build that also invokes webpack you can use `lektor build -f npm`.
+
+## Including The Files
+
+Now you need to include the files in your template. This will do it:
+
+```html
+<link rel="stylesheet" href="{{ '/static/gen/main.css'| asseturl }}">
+<script type=text/javascript src="{{ '/static/gen/main.js'| asseturl }}" charset="utf-8"></script>
+```
+
+## Complete Working Example
+
+The `examples` folder of this repository contains working projects.
+
+
+## Credits
+
+This plugin is based on the official [lektor-webpack-support](https://github.com/lektor/lektor-webpack-support) Lektor plugin by [Armin Ronacher](http://lucumr.pocoo.org/about/).
diff --git a/packages/npm-support/lektor_npm_support.egg-info/PKG-INFO b/packages/npm-support/lektor_npm_support.egg-info/PKG-INFO
new file mode 100644
index 0000000..c3fdd30
--- /dev/null
+++ b/packages/npm-support/lektor_npm_support.egg-info/PKG-INFO
@@ -0,0 +1,131 @@
+Metadata-Version: 2.1
+Name: lektor-npm-support
+Version: 0.1.4
+Summary: Adds support for using npm/yarn to build assets in Lektor
+Home-page: http://github.com/sterin/lektor-npm-support
+Author: Baruch Sterin
+Author-email: lektor-npm-support@xxxxxxxxxxx
+License: BSD
+Description: # lektor-npm-support
+
+ [![Build Status](https://travis-ci.org/sterin/lektor-npm-support.svg)](https://travis-ci.org/sterin/lektor-npm-support)
+ [![Build status](https://ci.appveyor.com/api/projects/status/6op1csefpi9l8hbg?svg=true)](https://ci.appveyor.com/project/sterin/lektor-npm-support)
+ [![Code Coverage](https://codecov.io/gh/sterin/lektor-npm-support/branch/master/graph/badge.svg)](https://codecov.io/gh/sterin/lektor-npm-support)
+
+ `lektor-npm-support` makes it easy to use [Parcel](https://parcel.js.org), [webpack](https://webpack.js.org), [browserify](http://browserify.org/), or any other tool to build assets for [Lektor](https://github.com/lektor/lektor) projects.
+
+ ## Enabling the Plugin
+
+ To enable the plugin, run this command while inside your Lektor project directory:
+
+ ```bash
+ lektor plugins add lektor-npm-support
+ ```
+
+ ## Example: Creating a [Parcel](https://parceljs.org/) Project
+
+ Create a `parcel/` folder and inside that folder create the following files:
+
+ ### `configs/npm-support.ini`
+
+ This file instructs the plugin how to generate the assets:
+
+ ```ini
+ [parcel]
+ npm = yarn
+ watch_script = watch
+ build_script = build
+ ```
+
+ * The section name `[parcel]` is the name of the folder where the Parcel project is located.
+ * `npm` is the package manager command used to build the project. This example will use [Yarn](https://yarnpkg.com).
+ * `watch_script` is the npm script used in `lektor server -f npm`,
+ * `build_script` is the npm script used in `lektor build -f npm`.
+
+ This plugin supports more than one such entry.
+
+ ### `parcel/package.json`
+
+ This is a standard `package.json` file. It should contain two entries in the `scripts` section. The `build` script is used during `lektor build -f npm`, and the `watch` script is used during `lektor server -f npm`.
+
+ ```json
+ {
+ "name": "my-parcel-project",
+ "version": "1.0.0",
+ "scripts": {
+ "watch": "NODE_ENV=development parcel --out-dir=../assets/static/gen --out-file=main.js --public-url=./assets/ main.js",
+ "build": "NODE_ENV=production parcel build --out-dir=../assets/static/gen --out-file=main.js --public-url=./assets/ main.js"
+ },
+ "private": true
+ }
+ ```
+
+ Now we can use `yarn add` to add Parcel, [Babel](https://babeljs.io/) and [Sass](https://sass-lang.com/):
+
+ ```
+ $ cd </path/to/your/lektor/project>/parcel
+ $ yarn add parcel-bundler babel-preset-env node-sass
+ ```
+
+ ### `parcel/babelr.rc`
+
+ Next up is a simple Babel config file, using the recommended `env` preset.
+
+ ```json
+ {
+ "presets": ["env"]
+ }
+ ```
+
+ ### `parcel/main.scss`
+
+ A simple SCSS file.
+
+ ```scss
+ body {
+ border: 10px solid red;
+ }
+ ```
+
+ ### `parcel/main.js`
+
+ A simple Javascript file that imports the SCSS file so that Parcel will know to include it as well.
+
+ ```javascript
+ import './main.scss';
+ ```
+
+ ## Running the Server
+
+ Now you're ready to go. When you run `lektor server` nothing wil happen,
+ instead you need to now run it as `lektor server -f npm` which
+ will enable the Parcel build. Parcel will automatically build your files
+ into `assets/static/gen` and this is where Lektor will then pick up the
+ files. This is done so that you can ship the generated assets
+ to others that might not have these tools, which simplifies using a
+ Lektor website that use this plugin.
+
+ ## Manual Builds
+
+ To manually trigger a build that also invokes webpack you can use `lektor build -f npm`.
+
+ ## Including The Files
+
+ Now you need to include the files in your template. This will do it:
+
+ ```html
+ <link rel="stylesheet" href="{{ '/static/gen/main.css'| asseturl }}">
+ <script type=text/javascript src="{{ '/static/gen/main.js'| asseturl }}" charset="utf-8"></script>
+ ```
+
+ ## Complete Working Example
+
+ The `examples` folder of this repository contains working projects.
+
+
+ ## Credits
+
+ This plugin is based on the official [lektor-webpack-support](https://github.com/lektor/lektor-webpack-support) Lektor plugin by [Armin Ronacher](http://lucumr.pocoo.org/about/).
+
+Platform: UNKNOWN
+Description-Content-Type: text/markdown
diff --git a/packages/npm-support/lektor_npm_support.egg-info/SOURCES.txt b/packages/npm-support/lektor_npm_support.egg-info/SOURCES.txt
new file mode 100644
index 0000000..3cc0cb5
--- /dev/null
+++ b/packages/npm-support/lektor_npm_support.egg-info/SOURCES.txt
@@ -0,0 +1,12 @@
+CHANGELOG.md
+LICENSE.md
+MANIFEST.in
+README.md
+lektor_npm_support.py
+setup.cfg
+setup.py
+lektor_npm_support.egg-info/PKG-INFO
+lektor_npm_support.egg-info/SOURCES.txt
+lektor_npm_support.egg-info/dependency_links.txt
+lektor_npm_support.egg-info/entry_points.txt
+lektor_npm_support.egg-info/top_level.txt
\ No newline at end of file
diff --git a/packages/npm-support/lektor_npm_support.egg-info/dependency_links.txt b/packages/npm-support/lektor_npm_support.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/packages/npm-support/lektor_npm_support.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/packages/npm-support/lektor_npm_support.egg-info/entry_points.txt b/packages/npm-support/lektor_npm_support.egg-info/entry_points.txt
new file mode 100644
index 0000000..b307dc1
--- /dev/null
+++ b/packages/npm-support/lektor_npm_support.egg-info/entry_points.txt
@@ -0,0 +1,3 @@
+[lektor.plugins]
+npm-support = lektor_npm_support:NPMSupportPlugin
+
diff --git a/packages/npm-support/lektor_npm_support.egg-info/top_level.txt b/packages/npm-support/lektor_npm_support.egg-info/top_level.txt
new file mode 100644
index 0000000..0a1f839
--- /dev/null
+++ b/packages/npm-support/lektor_npm_support.egg-info/top_level.txt
@@ -0,0 +1 @@
+lektor_npm_support
diff --git a/packages/npm-support/lektor_npm_support.py b/packages/npm-support/lektor_npm_support.py
new file mode 100644
index 0000000..decf563
--- /dev/null
+++ b/packages/npm-support/lektor_npm_support.py
@@ -0,0 +1,143 @@
+import os
+import threading
+import collections
+from builtins import object
+
+
+from lektor.pluginsystem import Plugin
+from lektor.reporter import reporter
+from lektor.utils import locate_executable, portable_popen
+
+
+popen_args_type = collections.namedtuple('popen_args_type', ['args', 'cwd'])
+
+
+class ProcessSequence(object):
+
+ def __init__(self, procs):
+ self.mutex = threading.Lock()
+ self.procs = list(reversed(procs))
+ self.current = None
+ self._start_next_process()
+
+ def _start_next_process(self):
+ self.current = None
+ if self.procs:
+ p = self.procs.pop()
+ self.current = portable_popen(p.args, cwd=p.cwd)
+
+ def kill(self):
+ with self.mutex:
+ if self.current:
+ self.current.kill()
+ self.procs = []
+
+ def wait(self):
+ while True:
+ if self.current is None:
+ return
+ self.current.wait()
+ if self.current.returncode != 0:
+ return
+ with self.mutex:
+ self._start_next_process()
+
+
+class ProcessManager(object):
+
+ def __init__(self):
+ self.cv = threading.Condition()
+ self.procs = set()
+
+ def _thread(self, p):
+ try:
+ p.wait()
+ except:
+ pass
+ finally:
+ with self.cv:
+ if p in self.procs:
+ self.procs.remove(p)
+ self.cv.notifyAll()
+
+ def start(self, *procs):
+ p = ProcessSequence(procs)
+ self.procs.add(p)
+ threading.Thread(target=self._thread, args=(p,)).start()
+
+ def kill(self):
+ with self.cv:
+ for p in self.procs:
+ p.kill()
+ self.procs = []
+
+ def wait(self):
+ with self.cv:
+ while self.procs:
+ self.cv.wait()
+
+ def __bool__(self):
+ with self.cv:
+ return bool(self.procs)
+
+
+class NPMRunner(object):
+
+ def __init__(self, folder, npm, build_script, watch_script):
+ self.folder = folder
+ self.npm = npm
+ self.build_script = build_script
+ self.watch_script = watch_script
+
+ def npm_args(self, *args):
+ return popen_args_type([self.npm] + list(args), self.folder)
+
+ def build(self, proc):
+ proc.start(self.npm_args('install'), self.npm_args('run', self.build_script))
+
+ def watch(self, proc):
+ proc.start(self.npm_args('install'), self.npm_args('run', self.watch_script))
+
+
+class NPMSupportPlugin(Plugin):
+ name = 'npm Support Plugin'
+ description = "Adds support for using npm/yarn to build assets in Lektor"
+
+ def __init__(self, *args, **kwargs):
+ Plugin.__init__(self, *args, **kwargs)
+ self.proc_manager = ProcessManager()
+
+ def is_enabled(self, extra_flags):
+ return 'npm' in extra_flags
+
+ def runners(self):
+ config = self.get_config()
+ for section in config.itersections():
+ props = config.section_as_dict(section)
+ yield NPMRunner(
+ folder=os.path.join(self.env.root_path, section),
+ npm=props.get('npm', 'npm'),
+ build_script=props.get('build_script', 'build'),
+ watch_script=props.get('watch_script', 'watch')
+ )
+
+ def on_server_spawn(self, extra_flags, **extra):
+ if self.is_enabled(extra_flags):
+ reporter.report_generic('Starting npm watchers')
+ for r in self.runners():
+ r.watch(self.proc_manager)
+
+ def on_server_stop(self, **extra):
+ if self.proc_manager:
+ reporter.report_generic('Stopping npm watchers')
+ self.proc_manager.kill()
+ reporter.report_generic('Stopped npm watchers')
+
+ def on_before_build_all(self, builder, **extra):
+ if self.proc_manager or not self.is_enabled(builder.extra_flags):
+ return
+ reporter.report_generic('Starting npm build')
+ for r in self.runners():
+ r.build(self.proc_manager)
+ self.proc_manager.wait()
+ reporter.report_generic('Finished npm build')
diff --git a/packages/npm-support/setup.cfg b/packages/npm-support/setup.cfg
new file mode 100644
index 0000000..6b47807
--- /dev/null
+++ b/packages/npm-support/setup.cfg
@@ -0,0 +1,10 @@
+[bdist_wheel]
+universal = 1
+
+[aliases]
+test = pytest
+
+[egg_info]
+tag_build =
+tag_date = 0
+
diff --git a/packages/npm-support/setup.py b/packages/npm-support/setup.py
new file mode 100644
index 0000000..af10498
--- /dev/null
+++ b/packages/npm-support/setup.py
@@ -0,0 +1,34 @@
+import os
+from setuptools import setup
+
+tests_require = [
+ 'lektor',
+ 'pytest',
+ 'pytest-cov',
+ 'pytest-mock'
+]
+
+
+def read(fname):
+ return open(os.path.join(os.path.dirname(__file__), fname)).read()
+
+
+setup(
+ name='lektor-npm-support',
+ author=u'Baruch Sterin',
+ author_email='lektor-npm-support@xxxxxxxxxxx',
+ version='0.1.4',
+ url='http://github.com/sterin/lektor-npm-support',
+ license='BSD',
+ description="Adds support for using npm/yarn to build assets in Lektor",
+ long_description=read('README.md'),
+ long_description_content_type='text/markdown',
+ py_modules=['lektor_npm_support'],
+ setup_requires=['pytest-runner'],
+ tests_require=tests_require,
+ entry_points={
+ 'lektor.plugins': [
+ 'npm-support = lektor_npm_support:NPMSupportPlugin',
+ ]
+ }
+)
diff --git a/packages/patches/environs.patch b/packages/patches/environs.patch
new file mode 100644
index 0000000..8316d6d
--- /dev/null
+++ b/packages/patches/environs.patch
@@ -0,0 +1,11 @@
+diff -ur environs.orig/setup.py environs/setup.py
+--- environs.orig/setup.py 2020-05-27 20:21:19.000000000 -0700
++++ environs/setup.py 2020-10-13 10:58:51.411999575 -0700
+@@ -44,7 +44,6 @@
+ author_email="sloria1@xxxxxxxxx",
+ url="https://github.com/sloria/environs",
+ install_requires=INSTALL_REQUIRES,
+- extras_require=EXTRAS_REQUIRE,
+ license="MIT",
+ zip_safe=False,
+ python_requires=PYTHON_REQUIRES,
diff --git a/packages/patches/envvars.patch b/packages/patches/envvars.patch
new file mode 100644
index 0000000..f4a65a1
--- /dev/null
+++ b/packages/patches/envvars.patch
@@ -0,0 +1,22 @@
+diff -ur envvars.orig/lektor_envvars.egg-info/SOURCES.txt envvars/lektor_envvars.egg-info/SOURCES.txt
+--- envvars.orig/lektor_envvars.egg-info/SOURCES.txt 2020-10-13 11:01:26.640115570 -0700
++++ envvars/lektor_envvars.egg-info/SOURCES.txt 2020-10-13 11:01:25.756114909 -0700
+@@ -8,5 +8,4 @@
+ lektor_envvars.egg-info/SOURCES.txt
+ lektor_envvars.egg-info/dependency_links.txt
+ lektor_envvars.egg-info/entry_points.txt
+-lektor_envvars.egg-info/requires.txt
+ lektor_envvars.egg-info/top_level.txt
+\ ã??ã?¡ã?¤ã?«æ?«å°¾ã?«æ?¹è¡?ã??ã??ã??ã?¾ã??ã??
+envvars.orig/lektor_envvars.egg-info ã?®ã?¿ã?«å?å?¨: requires.txt
+diff -ur envvars.orig/setup.py envvars/setup.py
+--- envvars.orig/setup.py 2020-10-13 11:01:09.036102429 -0700
++++ envvars/setup.py 2020-10-13 11:01:22.500112479 -0700
+@@ -11,7 +11,6 @@
+ author_email="seb@xxxxxxxxx",
+ url="https://www.github.com/elbaschid/lektor-envvars",
+ py_modules=["lektor_envvars"],
+- install_requires=["lektor", "environs"],
+ entry_points={"lektor.plugins": ["envvars = lektor_envvars:EnvvarsPlugin"]},
+ classifiers=[
+ "License :: OSI Approved :: MIT License",
diff --git a/packages/patches/npm-support.patch b/packages/patches/npm-support.patch
new file mode 100644
index 0000000..6ed94cb
--- /dev/null
+++ b/packages/patches/npm-support.patch
@@ -0,0 +1,14 @@
+diff -ur npm-support.orig/setup.py npm-support/setup.py
+--- npm-support.orig/setup.py 2020-10-13 10:59:31.300029385 -0700
++++ npm-support/setup.py 2020-10-13 10:59:45.204039777 -0700
+@@ -24,10 +24,8 @@
+ long_description=read('README.md'),
+ long_description_content_type='text/markdown',
+ py_modules=['lektor_npm_support'],
+- install_requires=['future'],
+ setup_requires=['pytest-runner'],
+ tests_require=tests_require,
+- extras_require={'test': tests_require},
+ entry_points={
+ 'lektor.plugins': [
+ 'npm-support = lektor_npm_support:NPMSupportPlugin',
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits