├── .github
├── dependabot.yml
└── workflows
│ ├── automerge.yml
│ ├── docs.yml
│ └── test.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── ROADMAP.md
├── assets
└── readme.gif
├── docs
├── docs
│ ├── index.md
│ └── release-notes.md
├── docs_assets
│ ├── fastapi-help.png
│ └── startproject-help.png
└── mkdocs.yml
├── manage_fastapi
├── __init__.py
├── __main__.py
├── config.py
├── constants.py
├── context.py
├── generator.py
├── helpers.py
├── main.py
└── templates
│ ├── __init__.py
│ ├── app
│ ├── __init__.py
│ ├── cookiecutter.json
│ ├── hooks
│ │ └── post_gen_project.py
│ └── {{ cookiecutter.folder_name }}
│ │ ├── __init__.py
│ │ ├── api
│ │ ├── __init__.py
│ │ └── v1.py
│ │ ├── crud.py
│ │ ├── models.py
│ │ └── schemas.py
│ └── project
│ ├── __init__.py
│ ├── cookiecutter.json
│ ├── hooks
│ └── post_gen_project.py
│ └── {{ cookiecutter.folder_name }}
│ ├── .pre-commit-config.yaml
│ ├── Dockerfile
│ ├── LICENSE
│ ├── README.md
│ ├── app
│ ├── __init__.py
│ ├── core
│ │ ├── __init__.py
│ │ └── config.py
│ ├── database.py
│ └── main.py
│ ├── docker-compose.yaml
│ ├── pyproject.toml
│ ├── requirements.txt
│ ├── setup.cfg
│ ├── tests
│ └── __init__.py
│ ├── {{ cookiecutter.env }}
│ └── {{ cookiecutter.gitignore }}
├── poetry.lock
├── pyproject.toml
├── scripts
└── check_typing.sh
├── setup.cfg
└── tests
├── __init__.py
├── test_startapp.py
└── test_startproject.py
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "pip"
4 | directory: "/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/"
5 | schedule:
6 | interval: "monthly"
7 |
8 | - package-ecosystem: "pip"
9 | directory: "/"
10 | schedule:
11 | interval: "monthly"
12 |
--------------------------------------------------------------------------------
/.github/workflows/automerge.yml:
--------------------------------------------------------------------------------
1 | name: Automerge
2 | on: [push, pull_request]
3 |
4 |
5 | jobs:
6 | automerge:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: fastify/github-action-merge-dependabot@v2.1.1
10 | with:
11 | github-token: ${{ secrets.GITHUB_TOKEN }}
12 |
--------------------------------------------------------------------------------
/.github/workflows/docs.yml:
--------------------------------------------------------------------------------
1 | name: docs
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | deploy:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v2
13 | - uses: actions/setup-python@v2
14 | with:
15 | python-version: 3.x
16 | - run: pip install mkdocs-material
17 | - run: mkdocs gh-deploy --config-file=docs/mkdocs.yml --force
18 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | on:
4 | push:
5 | branches: ["master"]
6 | pull_request:
7 | branches: ["master"]
8 |
9 | jobs:
10 | test:
11 | runs-on: "${{ matrix.os }}"
12 | strategy:
13 | matrix:
14 | os: [ubuntu-latest, windows-latest, macos-latest]
15 | python-version: [3.6, 3.7, 3.8, 3.9]
16 | fail-fast: true
17 |
18 | steps:
19 | - uses: actions/checkout@v2
20 | - name: Set up Python
21 | uses: actions/setup-python@v2
22 | with:
23 | python-version: ${{ matrix.python-version }}
24 | - name: Install Poetry
25 | run: pip install poetry
26 | - name: Install Dependencies
27 | run: poetry install
28 | - name: Test
29 | run: poetry run pytest tests/ --cov=manage_fastapi --cov-report=term-missing:skip-covered --cov-report=xml
30 | - name: Upload coverage
31 | uses: codecov/codecov-action@v1
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Editors
2 | .vscode/
3 | .idea/
4 |
5 | # Vagrant
6 | .vagrant/
7 |
8 | # Mac/OSX
9 | .DS_Store
10 |
11 | # Windows
12 | Thumbs.db
13 |
14 | # Source for the following rules: https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore
15 | # Byte-compiled / optimized / DLL files
16 | __pycache__/
17 | *.py[cod]
18 | *$py.class
19 |
20 | site
21 |
22 | # Distribution / packaging
23 | .Python
24 | build/
25 | develop-eggs/
26 | dist/
27 | downloads/
28 | eggs/
29 | .eggs/
30 | lib/
31 | lib64/
32 | parts/
33 | sdist/
34 | var/
35 | wheels/
36 | *.egg-info/
37 | .installed.cfg
38 | *.egg
39 | MANIFEST
40 |
41 | # PyInstaller
42 | # Usually these files are written by a python script from a template
43 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
44 | *.manifest
45 | *.spec
46 |
47 | # Installer logs
48 | pip-log.txt
49 | pip-delete-this-directory.txt
50 |
51 | # Unit test / coverage reports
52 | htmlcov/
53 | .tox/
54 | .nox/
55 | .coverage
56 | .coverage.*
57 | .cache
58 | nosetests.xml
59 | coverage.xml
60 | *.cover
61 | .hypothesis/
62 | .pytest_cache/
63 |
64 | # PyBuilder
65 | target/
66 |
67 | # pyenv
68 | .python-version
69 |
70 | # celery beat schedule file
71 | celerybeat-schedule
72 |
73 | # SageMath parsed files
74 | *.sage.py
75 |
76 | # Environments
77 | .env
78 | .venv
79 | env/
80 | venv/
81 | ENV/
82 | env.bak/
83 | venv.bak/
84 |
85 | # Rope project settings
86 | .ropeproject
87 |
88 | # mypy
89 | .mypy_cache/
90 | .dmypy.json
91 | dmypy.json
92 |
93 | # Temporary Files
94 | tmp
95 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/myint/autoflake
3 | rev: v1.4
4 | hooks:
5 | - id: autoflake
6 | exclude: .*/__init__.py|.*/templates/.*
7 | args:
8 | - --in-place
9 | - --remove-all-unused-imports
10 | - --expand-star-imports
11 | - --remove-duplicate-keys
12 | - --remove-unused-variables
13 | - repo: local
14 | hooks:
15 | - id: flake8
16 | name: flake8
17 | entry: flake8
18 | exclude: .*/templates/.*
19 | language: system
20 | types: [python]
21 | - repo: https://github.com/pre-commit/mirrors-isort
22 | rev: v5.4.2
23 | hooks:
24 | - id: isort
25 | exclude: .*/templates/.*
26 | args: ["--profile", "black"]
27 | - repo: local
28 | hooks:
29 | - id: mypy
30 | name: mypy
31 | entry: mypy
32 | language: system
33 | exclude: .*/templates/.*
34 | types: [python]
35 | - repo: https://github.com/pre-commit/pre-commit-hooks
36 | rev: v3.3.0
37 | hooks:
38 | - id: trailing-whitespace
39 | - id: end-of-file-fixer
40 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Manage FastAPI
2 |
3 | We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's:
4 |
5 | - Reporting a bug
6 | - Discussing the current state of the code
7 | - Submitting a fix
8 | - Proposing new features
9 | - Becoming a maintainer
10 |
11 | ## We Develop with Github
12 |
13 | We use github to host code, to track issues and feature requests, as well as accept pull requests.
14 |
15 | ## We Use [Github Flow](https://guides.github.com/introduction/flow/index.html), So All Code Changes Happen Through Pull Requests
16 |
17 | Pull requests are the best way to propose changes to the codebase (we use [Github Flow](https://guides.github.com/introduction/flow/index.html)). We actively welcome your pull requests:
18 |
19 | 1. Fork the repo and create your branch from `master`.
20 | 2. If you've added code that should be tested, add tests.
21 | 3. If you've changed APIs, update the documentation.
22 | 4. Ensure the test suite passes.
23 | 5. Make sure your code lints.
24 | 6. Issue that pull request!
25 |
26 | ## Report bugs using Github's [issues](https://github.com/ycd/manage-fastapi/issues)
27 |
28 | We use GitHub issues to track public bugs. Report a bug by [opening a new issue](); it's that easy!
29 |
30 | ## Write bug reports with detail, background, and sample code
31 |
32 | [This is a good example](http://stackoverflow.com/q/12488905/180626) of a bug report.
33 |
34 | **Great Bug Reports** tend to have:
35 |
36 | - A quick summary and/or background.
37 | - Steps to reproduce.
38 | - Be specific!
39 | - Give sample code if you can.
40 | - Express what you expected would happen.
41 | - Express what actually happens.
42 | - Notes (possibly including why you think this might be happening, or stuff you tried that didn't work)
43 |
44 | People *love* thorough bug reports. I'm not even kidding.
45 |
46 | ## License
47 |
48 | By contributing, you agree that your contributions will be licensed under its MIT License.
49 |
50 | ## References
51 |
52 | This document was adapted from the open-source contribution document created by [Brian A. Danielak](https://gist.github.com/briandk) based on the [Facebook's Draft](https://github.com/facebook/draft-js/blob/a9316a723f9e918afde44dea68b5f9f39b7d9b00/CONTRIBUTING.md) contributing guidelines.
53 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Yağızcan Değirmenci
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
manage-fastapi
3 |
4 | [manage-fastapi](https://github.com/ycd/manage-fastapi) Project generator and manager for FastAPI
5 |
6 |
7 | 
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ---
26 |
27 | **Source Code**: View it on [Github](https://github.com/ycd/manage-fastapi/)
28 |
29 | ---
30 |
31 |
32 | ## Features 🚀
33 |
34 | * #### Creates customizable **project boilerplate.**
35 | * #### Creates customizable **app boilerplate.**
36 | * #### Handles the project structuring for you.
37 | * #### Optional Dockerfile generation.
38 | * #### Optional docker-compose generation for your project needs.
39 | * #### Optional pre-commit hook generation.
40 |
41 |
42 | ## Installation 📌
43 |
44 | * Prerequisites
45 | * Python 3.6 +
46 |
47 | Manage FastAPI can be installed by running
48 |
49 | ```python
50 | pip install manage-fastapi
51 | ```
52 |
53 |
54 | ## Getting started 🎈
55 |
56 | Easiest way to start is using the defaults:
57 |
58 | ```bash
59 | fastapi startproject [name]
60 | ```
61 |
62 | But there is an **interactive** mode!
63 |
64 | ```bash
65 | fastapi startproject [name] --interactive
66 | ```
67 |
68 |
69 |
70 | ## Command line options 🧰
71 |
72 | Manage FastAPI provides three different commands.
73 |
74 | You can list them with
75 |
76 | ```bash
77 | fastapi --help
78 | ```
79 |
80 |
81 |
82 | The idea is to have a highly customizable CLI, but at the same time a simple interface for new users. You can see the available options for `startproject` running `fastapi startproject --help`:
83 |
84 |
85 |
86 | The other commands are already available but the current implementation is too shallow. More details about `startapp` and `run` commands will be provided once they have more functionalities, at the moment you can run `startapp` by just:
87 |
88 | ```bash
89 | fastapi startapp {name}
90 | ```
91 |
92 | On the other hand, the `run` command expects you to have a `startproject` structure:
93 |
94 | ```bash
95 | fastapi run
96 | ```
97 |
98 | ## License
99 |
100 | This project is licensed under the terms of the MIT license.
101 |
--------------------------------------------------------------------------------
/ROADMAP.md:
--------------------------------------------------------------------------------
1 | # Manage FastAPI Roadmap
2 |
3 | Hi there! :wave:
4 |
5 | The package plans are here. If you want to contribute with new ideas, or develop the ones that are listed, read our contributing guidelines! 🤓
6 |
7 | ## Checklist
8 |
9 | ### Must
10 |
11 | * [X] License support on `startproject`.
12 | * [X] Docker/Docker-compose support on `startproject`.
13 | * [X] Add basic linter tools on `startproject` (flake8, mypy and isort).
14 | * [X] Add `.pre-commit-config.yaml` on `startproject`.
15 | * [X] Integrate databases on `startproject`.
16 | - [ ] SQLALchemy
17 | - [X] PostgreSQL
18 | - [ ] MySQL
19 | - [ ] SQLite
20 | - [ ] Async SQLAlchemy
21 | - [ ] PostgreSQL
22 | - [ ] MySQL
23 | - [ ] SQLite
24 | - [ ] Gino (only supports PostgreSQL)
25 | - [ ] Tortoise
26 | - [ ] PostgreSQL
27 | - [ ] MySQL
28 | - [ ] SQLite
29 | - [ ] MongoDB
30 | * [ ] Different Authentication support on `startproject`.
31 | * [X] Support `startapp` command.
32 | - [X] Simple app creation.
33 | - [ ] Append the APIRouter to the FastAPI app.
34 | - [ ] Add `--app-file` and `--app-variable` options on `startapp`.
35 | * [ ] Add tests.
36 | * [X] Fix documentation accordingly.
37 |
38 | ### Nice to have
39 |
40 | * [ ] VSCode debugger support on `startproject` (available via docker).
41 | * [ ] Support different CI on `startproject`.
42 | * [ ] Add support for `hypercorn` on `run`.
43 | * [ ] Create `migrations`/`migrate` command.
44 | * [ ] Add `logger` to `startproject` structure.
45 | * [ ] Base CRUD class to `startproject`.
46 |
47 | ### Additional
48 |
49 | * [ ] Script to copy `index.md` to `README.md` and verify if they are the same.
50 |
51 | ## Questions
52 |
53 | * Should we support .git by default?
54 | * Should CORSMiddleware be optional?
55 |
--------------------------------------------------------------------------------
/assets/readme.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/assets/readme.gif
--------------------------------------------------------------------------------
/docs/docs/index.md:
--------------------------------------------------------------------------------
1 |
2 | Manage FastAPI projects easily
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ---
21 |
22 | **Documentation**: View it on [website](https://ycd.github.io/manage-fastapi/)
23 |
24 | **Source Code**: View it on [Github](https://github.com/ycd/manage-fastapi/)
25 |
26 |
27 | ---
28 |
29 | ## Features 🚀
30 |
31 | * #### Creates customizable **project boilerplate.**
32 | * #### Creates customizable **app boilerplate.**
33 | * #### Handles the project structuring for you.
34 |
35 | ## Installation
36 |
37 | Manage FastAPI can be installed by running `pip install manage-fastapi`. It requires Python 3.6+ to run.
38 |
39 | ## Usage
40 |
41 | To get started right away with sensible defaults:
42 |
43 | ```bash
44 | fastapi startproject {name}
45 | ```
46 |
47 | You can run _Manage FastAPI_ as a package if running it as a script doesn’t work:
48 |
49 | ```bash
50 | python -m fastapi startproject {name}
51 | ```
52 |
53 | ## Command line options
54 |
55 | Manage FastAPI has three commands for now. You can list them by running `fastapi --help`:
56 |
57 |
58 |
59 | The idea is to have a highly customizable CLI, but at the same time a simple interface for new users. You can see the available options for `startproject` running `fastapi startproject --help`:
60 |
61 |
62 |
63 | The other commands are already available but the current implementation is too shallow. More details about `startapp` and `run` commands will be provided once they have more functionalities, at the moment you can run `startapp` by just:
64 |
65 | ```bash
66 | fastapi startapp {name}
67 | ```
68 |
69 | On the other hand, the `run` command expects you to have a `startproject` structure:
70 |
71 | ```bash
72 | fastapi run
73 | ```
74 |
75 | ## License
76 |
77 | This project is licensed under the terms of the MIT license.
78 |
--------------------------------------------------------------------------------
/docs/docs/release-notes.md:
--------------------------------------------------------------------------------
1 | ## Release Notes 📣
2 |
3 | ### Latest Changes
4 |
5 | ### 1.0.1
6 |
7 | * Added MySQL support.
8 |
9 | ### 1.0.0
10 |
11 | * Add `run` command, previously known as `run-server`.
12 | * Create a roadmap.
13 | * Massive design update on the package logic. File template (cookiecutter) base instead of variable.
14 |
15 | ### 0.1.60
16 |
17 | * Delete run-server command
18 | * Delete show-models command
19 | * Create new template for settings without database
20 | * Small fix for project utils
21 |
22 | ### 0.1.52
23 |
24 | * Temporary fix for Path issue when running with uvicorn
25 |
26 | ### 0.1.51
27 |
28 | * Little update on API template
29 |
30 | ### 0.1.5
31 |
32 | * Added showmodels
33 | * Added runserver
34 | * Fix little bugs
35 | * Update docs
36 |
37 | ### 0.1.41
38 |
39 | * Quick fix for a little bug
40 |
41 | ### 0.1.4
42 |
43 | * Changed project architecture
44 | * Increased travis tests
45 |
46 | ### 0.1.3
47 |
48 | * Make database optional
49 | * Now Manage FastAPI has support for MongoDB, PostgreSQL, SQLite, MySQL, Tortoise ORM
50 |
51 | ### 0.1.2
52 |
53 | * Add tests
54 | * Fix and relocate success message
55 | * Add travis
56 |
57 | ### 0.1.1
58 |
59 | * Added documentation
60 | * Fixed typos
61 | * Additional response for successfuly creation.
62 |
63 | ### 0.1.0
64 |
65 | * Prototype of project with two functionalities.
66 |
--------------------------------------------------------------------------------
/docs/docs_assets/fastapi-help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/docs/docs_assets/fastapi-help.png
--------------------------------------------------------------------------------
/docs/docs_assets/startproject-help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/docs/docs_assets/startproject-help.png
--------------------------------------------------------------------------------
/docs/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: Manage FastAPI
2 | theme:
3 | name: material
4 | palette:
5 | primary: 'green'
6 | accent: 'orange'
7 | font:
8 | text: 'Ubuntu'
9 | repo_name: ycd/Manage-FastAPI
10 | repo_url: https://github.com/ycd/manage-fastapi
11 |
12 | nav:
13 | - Manage FastAPI: index.md
14 | - Manage Projects:
15 | - Start new project: managing_projects/startproject.md
16 | - Manage Apps:
17 | - Start new app: managing_apps/startapp.md
18 | - Release Notes: 'release-notes.md'
19 |
20 |
21 | markdown_extensions:
22 | - toc:
23 | permalink: true
24 | - markdown.extensions.codehilite:
25 | guess_lang: false
26 | - admonition
27 | - codehilite
28 | - extra
29 | - tables
30 | - smarty
31 | - pymdownx.tabbed
32 |
--------------------------------------------------------------------------------
/manage_fastapi/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/manage_fastapi/__init__.py
--------------------------------------------------------------------------------
/manage_fastapi/__main__.py:
--------------------------------------------------------------------------------
1 | from .main import app
2 |
3 | app(prog_name="fastapi")
4 |
--------------------------------------------------------------------------------
/manage_fastapi/config.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | TEMPLATES_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "templates")
4 |
5 | try:
6 | import fastapi
7 |
8 | FASTAPI_VERSION = fastapi.__version__
9 | except ModuleNotFoundError:
10 | FASTAPI_VERSION = "0.70.0"
11 |
--------------------------------------------------------------------------------
/manage_fastapi/constants.py:
--------------------------------------------------------------------------------
1 | from enum import Enum, EnumMeta
2 |
3 |
4 | class BaseMetadataEnum(EnumMeta):
5 | def __contains__(self, other):
6 | try:
7 | self(other)
8 | except ValueError:
9 | return False
10 | else:
11 | return True
12 |
13 |
14 | class BaseEnum(str, Enum, metaclass=BaseMetadataEnum):
15 | """Base enum class."""
16 |
17 |
18 | class PackageManager(BaseEnum):
19 | PIP = "pip"
20 | POETRY = "poetry"
21 |
22 |
23 | class PythonVersion(BaseEnum):
24 | THREE_DOT_SIX = "3.6"
25 | THREE_DOT_SEV = "3.7"
26 | THREE_DOT_EIG = "3.8"
27 | THREE_DOT_NIN = "3.9"
28 |
29 |
30 | class License(BaseEnum):
31 | MIT = "MIT"
32 | BSD = "BSD"
33 | GNU = "GNU"
34 | APACHE = "Apache"
35 |
36 |
37 | class Database(BaseEnum):
38 | POSTGRES = "Postgres"
39 | MYSQL = "MySQL"
40 |
--------------------------------------------------------------------------------
/manage_fastapi/context.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 | from datetime import datetime
3 | from typing import Optional
4 |
5 | from pydantic import BaseModel, EmailStr, root_validator
6 |
7 | from manage_fastapi.config import FASTAPI_VERSION
8 | from manage_fastapi.constants import Database, License, PackageManager, PythonVersion
9 |
10 |
11 | class AppContext(BaseModel):
12 | name: str
13 | folder_name: str
14 | snake_name: str
15 |
16 | @root_validator(pre=True)
17 | def validate_app(cls, values: dict):
18 | values["folder_name"] = values["name"].lower().replace(" ", "-").strip()
19 | values["snake_name"] = values["folder_name"].replace("-", "_")
20 | return values
21 |
22 |
23 | class ProjectContext(BaseModel):
24 | name: str
25 | folder_name: str
26 | packaging: PackageManager
27 |
28 | username: Optional[str] = None
29 | email: Optional[EmailStr] = None
30 |
31 | python: PythonVersion
32 | fastapi: str = FASTAPI_VERSION
33 |
34 | license: Optional[License]
35 | year: int
36 |
37 | pre_commit: bool
38 | docker: bool
39 |
40 | database: Optional[Database]
41 |
42 | @root_validator(pre=True)
43 | def validate_project(cls, values: dict):
44 | try:
45 | values["username"] = subprocess.check_output(
46 | ["git", "config", "--get", "user.name"]
47 | )
48 | values["email"] = subprocess.check_output(
49 | ["git", "config", "--get", "user.email"]
50 | )
51 | except subprocess.CalledProcessError:
52 | ...
53 | values["folder_name"] = values["name"].lower().replace(" ", "-").strip()
54 | values["year"] = datetime.today().year
55 | return values
56 |
57 | class Config:
58 | use_enum_values = True
59 |
--------------------------------------------------------------------------------
/manage_fastapi/generator.py:
--------------------------------------------------------------------------------
1 | import os
2 | from typing import TypeVar
3 |
4 | import typer
5 | from cookiecutter.exceptions import OutputDirExistsException
6 | from cookiecutter.main import cookiecutter
7 | from pydantic.main import BaseModel
8 |
9 | from manage_fastapi.config import TEMPLATES_DIR
10 | from manage_fastapi.context import AppContext, ProjectContext
11 |
12 | ContextType = TypeVar("ContextType", bound=BaseModel)
13 |
14 |
15 | def fill_template(template_name: str, context: ContextType):
16 | try:
17 | cookiecutter(
18 | os.path.join(TEMPLATES_DIR, template_name),
19 | extra_context=context.dict(),
20 | no_input=True,
21 | )
22 | except OutputDirExistsException:
23 | typer.echo(f"Folder '{context.folder_name}' already exists. 😞")
24 | else:
25 | typer.echo(f"FastAPI {template_name} created successfully! 🎉")
26 |
27 |
28 | def generate_app(context: AppContext):
29 | fill_template("app", context)
30 |
31 |
32 | def generate_project(context: ProjectContext):
33 | fill_template("project", context)
34 |
--------------------------------------------------------------------------------
/manage_fastapi/helpers.py:
--------------------------------------------------------------------------------
1 | import re
2 | from typing import TypeVar
3 |
4 | import questionary
5 |
6 | EnumType = TypeVar("EnumType")
7 |
8 |
9 | def camel_to_snake(text: str) -> str:
10 | return re.sub(r"(? questionary.Question:
14 | prompt = camel_to_snake(choices.__name__).replace("_", " ") # type: ignore
15 | return questionary.select(f"Select the {prompt}: ", choices=list(choices))
16 |
17 |
18 | def binary_question(option: str) -> questionary.Question:
19 | return questionary.confirm(f"Do you want {option}?", default=False)
20 |
--------------------------------------------------------------------------------
/manage_fastapi/main.py:
--------------------------------------------------------------------------------
1 | import os
2 | import subprocess
3 | from typing import Optional
4 |
5 | import pkg_resources
6 | import typer
7 | from questionary.form import form
8 |
9 | from manage_fastapi.constants import Database, License, PackageManager, PythonVersion
10 | from manage_fastapi.context import AppContext, ProjectContext
11 | from manage_fastapi.generator import generate_app, generate_project
12 | from manage_fastapi.helpers import binary_question, question
13 |
14 | app = typer.Typer(
15 | add_completion=False,
16 | help="Managing FastAPI projects made easy!",
17 | name="Manage FastAPI",
18 | )
19 |
20 |
21 | @app.command(help="Creates a FastAPI project.")
22 | def startproject(
23 | name: str,
24 | interactive: bool = typer.Option(False, help="Run in interactive mode."),
25 | database: Optional[Database] = typer.Option(None, case_sensitive=False),
26 | docker: bool = typer.Option(False),
27 | license_: Optional[License] = typer.Option(None, "--license", case_sensitive=False),
28 | packaging: PackageManager = typer.Option(PackageManager.PIP),
29 | pre_commit: bool = typer.Option(False, "--pre-commit"),
30 | python: PythonVersion = typer.Option(PythonVersion.THREE_DOT_EIG),
31 | ):
32 | if interactive:
33 | result = form(
34 | packaging=question(PackageManager),
35 | python=question(PythonVersion),
36 | license=question(License),
37 | pre_commit=binary_question("pre commit"),
38 | docker=binary_question("docker"),
39 | database=question(Database),
40 | ).ask()
41 | context = ProjectContext(name=name, **result)
42 | else:
43 | context = ProjectContext(
44 | name=name,
45 | packaging=packaging,
46 | python=python,
47 | license=license_,
48 | pre_commit=pre_commit,
49 | docker=docker,
50 | database=database,
51 | )
52 | generate_project(context)
53 |
54 |
55 | @app.command(help="Creates a FastAPI component.")
56 | def startapp(name: str):
57 | context = AppContext(name=name)
58 | generate_app(context)
59 |
60 |
61 | @app.command(help="Run a FastAPI application.")
62 | def run(prod: bool = typer.Option(False)):
63 | args = []
64 | if not prod:
65 | args.append("--reload")
66 | app_file = os.getenv("FASTAPI_APP", "app.main")
67 | subprocess.call(["uvicorn", f"{app_file}:app", *args])
68 |
69 |
70 | def version_callback(value: bool):
71 | if value:
72 | version = pkg_resources.get_distribution("manage-fastapi").version
73 | typer.echo(f"manage-fastapi, version {version}")
74 | raise typer.Exit()
75 |
76 |
77 | @app.callback()
78 | def main(
79 | version: bool = typer.Option(
80 | None,
81 | "--version",
82 | callback=version_callback,
83 | is_eager=True,
84 | help="Show the Manage FastAPI version information.",
85 | )
86 | ):
87 | ...
88 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/manage_fastapi/templates/__init__.py
--------------------------------------------------------------------------------
/manage_fastapi/templates/app/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/manage_fastapi/templates/app/__init__.py
--------------------------------------------------------------------------------
/manage_fastapi/templates/app/cookiecutter.json:
--------------------------------------------------------------------------------
1 | {
2 | "folder_name": "{{ cookiecutter.folder_name }}",
3 | "name": "{{ cookiecutter.name }}",
4 | "snake_name": "{{ cookiecutter.snake_name }}"
5 | }
6 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/app/hooks/post_gen_project.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/manage_fastapi/templates/app/hooks/post_gen_project.py
--------------------------------------------------------------------------------
/manage_fastapi/templates/app/{{ cookiecutter.folder_name }}/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/manage_fastapi/templates/app/{{ cookiecutter.folder_name }}/__init__.py
--------------------------------------------------------------------------------
/manage_fastapi/templates/app/{{ cookiecutter.folder_name }}/api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/manage_fastapi/templates/app/{{ cookiecutter.folder_name }}/api/__init__.py
--------------------------------------------------------------------------------
/manage_fastapi/templates/app/{{ cookiecutter.folder_name }}/api/v1.py:
--------------------------------------------------------------------------------
1 | from fastapi import APIRouter
2 |
3 | router = APIRouter()
4 |
5 |
6 | @router.get("/")
7 | def get_{{ cookiecutter.snake_name }}():
8 | return "{{ cookiecutter.name }} app created!"
9 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/app/{{ cookiecutter.folder_name }}/crud.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/manage_fastapi/templates/app/{{ cookiecutter.folder_name }}/crud.py
--------------------------------------------------------------------------------
/manage_fastapi/templates/app/{{ cookiecutter.folder_name }}/models.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/manage_fastapi/templates/app/{{ cookiecutter.folder_name }}/models.py
--------------------------------------------------------------------------------
/manage_fastapi/templates/app/{{ cookiecutter.folder_name }}/schemas.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/manage_fastapi/templates/app/{{ cookiecutter.folder_name }}/schemas.py
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/manage_fastapi/templates/project/__init__.py
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/cookiecutter.json:
--------------------------------------------------------------------------------
1 | {
2 | "database": "{{ cookiecutter.database }}",
3 | "docker": "{{ cookiecutter.docker }}",
4 | "email": "{{ cookiecutter.email }}",
5 | "env": ".env",
6 | "fastapi": "{{ cookiecutter.fastapi }}",
7 | "folder_name": "{{ cookiecutter.folder_name }}",
8 | "gitignore": ".gitignore",
9 | "license": "{{ cookiecutter.license }}",
10 | "name": "{{ cookiecutter.name }}",
11 | "packaging": "{{ cookiecutter.packaging }}",
12 | "pre_commit": "{{ cookiecutter.pre_commit }}",
13 | "python": "{{ cookiecutter.python }}",
14 | "username": "{{ cookiecutter.username }}",
15 | "year": "{{ cookiecutter.year }}"
16 | }
17 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/hooks/post_gen_project.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from manage_fastapi.constants import PackageManager
4 |
5 |
6 | def remove_paths(paths: list):
7 | base_dir = os.getcwd()
8 |
9 | for path in paths:
10 | path = os.path.join(base_dir, path)
11 | if path and os.path.exists(path):
12 | if os.path.isdir(path):
13 | os.rmdir(path)
14 | else:
15 | os.unlink(path)
16 |
17 |
18 | def set_packaging():
19 | packaging = "{{ cookiecutter.packaging }}"
20 | if packaging == PackageManager.PIP:
21 | remove_paths(["poetry.lock", "pyproject.toml"])
22 | elif packaging == PackageManager.POETRY:
23 | remove_paths(["requirements.txt"])
24 |
25 |
26 | def set_pre_commit():
27 | pre_commit: bool = eval("{{ cookiecutter.pre_commit }}")
28 | if pre_commit is False:
29 | remove_paths([".pre-commit-config.yaml", "setup.cfg"])
30 |
31 |
32 | def set_docker():
33 | docker: bool = eval("{{ cookiecutter.docker }}")
34 | if docker is False:
35 | remove_paths(["Dockerfile", "docker-compose.yaml"])
36 |
37 |
38 | def set_database():
39 | database = "{{ cookiecutter.database }}"
40 | if database == "None":
41 | remove_paths(["app/database.py"])
42 |
43 |
44 | def set_license():
45 | license_ = "{{ cookiecutter.license }}"
46 | if license_ == "None":
47 | remove_paths(["LICENSE"])
48 |
49 |
50 | # TODO(Marcelo): Alter config.py location according to the project complexity.
51 | # def set_config_location():
52 | # database = "{{ cookiecutter.database }}"
53 | # if database == "None":
54 | # remove_paths(["app/core/config.py"])
55 | # else:
56 | # remove_paths(["app/config.py"])
57 |
58 |
59 | def main():
60 | set_database()
61 | set_docker()
62 | set_license()
63 | set_packaging()
64 | set_pre_commit()
65 |
66 |
67 | if __name__ == "__main__":
68 | main()
69 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/myint/autoflake
3 | rev: v1.4
4 | hooks:
5 | - id: autoflake
6 | exclude: .*/__init__.py
7 | args:
8 | - --in-place
9 | - --remove-all-unused-imports
10 | - --expand-star-imports
11 | - --remove-duplicate-keys
12 | - --remove-unused-variables
13 | - repo: local
14 | hooks:
15 | - id: flake8
16 | name: flake8
17 | entry: flake8
18 | language: system
19 | types: [python]
20 | - repo: https://github.com/pre-commit/mirrors-isort
21 | rev: v5.4.2
22 | hooks:
23 | - id: isort
24 | args: ["--profile", "black"]
25 | - repo: local
26 | hooks:
27 | - id: mypy
28 | name: mypy
29 | entry: mypy
30 | language: system
31 | types: [python]
32 | - repo: https://github.com/pre-commit/pre-commit-hooks
33 | rev: v3.3.0
34 | hooks:
35 | - id: trailing-whitespace
36 | - id: end-of-file-fixer
37 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM tiangolo/uvicorn-gunicorn-fastapi:python{{ cookiecutter.python }}
2 |
3 | ENV PYTHONPATH "${PYTHONPATH}:/"
4 | ENV PORT=8000
5 | {% if cookiecutter.packaging == "poetry" %}
6 | # Install Poetry
7 | RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | POETRY_HOME=/opt/poetry python && \
8 | cd /usr/local/bin && \
9 | ln -s /opt/poetry/bin/poetry && \
10 | poetry config virtualenvs.create false
11 |
12 | # Copy using poetry.lock* in case it doesn't exist yet
13 | COPY ./pyproject.toml ./poetry.lock* /app/
14 |
15 | RUN poetry install --no-root --no-dev
16 | {% else %}
17 | RUN pip install --upgrade pip
18 |
19 | COPY ./requirements.txt /app/
20 |
21 | RUN pip install -r requirements.txt
22 | {% endif %}
23 | COPY ./app /app
24 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/LICENSE:
--------------------------------------------------------------------------------
1 | {%- if cookiecutter.license == "MIT" -%}
2 | MIT License
3 |
4 | Copyright (c) {{ cookiecutter.year }} {{ cookiecutter.username }}
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | {%- elif cookiecutter.license == "BSD-3" -%}
24 | BSD 3-Clause License
25 |
26 | Copyright (c) {{ cookiecutter.year}}, {{ cookiecutter.username }}
27 | All rights reserved.
28 |
29 | Redistribution and use in source and binary forms, with or without
30 | modification, are permitted provided that the following conditions are met:
31 |
32 | 1. Redistributions of source code must retain the above copyright notice, this
33 | list of conditions and the following disclaimer.
34 |
35 | 2. Redistributions in binary form must reproduce the above copyright notice,
36 | this list of conditions and the following disclaimer in the documentation
37 | and/or other materials provided with the distribution.
38 |
39 | 3. Neither the name of the copyright holder nor the names of its
40 | contributors may be used to endorse or promote products derived from
41 | this software without specific prior written permission.
42 |
43 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
44 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
46 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
47 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
49 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
50 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
51 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 | {%- elif cookiecutter.license == "GNU GPL v3.0" -%}
54 | GNU GENERAL PUBLIC LICENSE
55 | Version 3, 29 June 2007
56 |
57 | Copyright (C) 2007 Free Software Foundation, Inc.
58 | Everyone is permitted to copy and distribute verbatim copies
59 | of this license document, but changing it is not allowed.
60 |
61 | Preamble
62 |
63 | The GNU General Public License is a free, copyleft license for
64 | software and other kinds of works.
65 |
66 | The licenses for most software and other practical works are designed
67 | to take away your freedom to share and change the works. By contrast,
68 | the GNU General Public License is intended to guarantee your freedom to
69 | share and change all versions of a program--to make sure it remains free
70 | software for all its users. We, the Free Software Foundation, use the
71 | GNU General Public License for most of our software; it applies also to
72 | any other work released this way by its authors. You can apply it to
73 | your programs, too.
74 |
75 | When we speak of free software, we are referring to freedom, not
76 | price. Our General Public Licenses are designed to make sure that you
77 | have the freedom to distribute copies of free software (and charge for
78 | them if you wish), that you receive source code or can get it if you
79 | want it, that you can change the software or use pieces of it in new
80 | free programs, and that you know you can do these things.
81 |
82 | To protect your rights, we need to prevent others from denying you
83 | these rights or asking you to surrender the rights. Therefore, you have
84 | certain responsibilities if you distribute copies of the software, or if
85 | you modify it: responsibilities to respect the freedom of others.
86 |
87 | For example, if you distribute copies of such a program, whether
88 | gratis or for a fee, you must pass on to the recipients the same
89 | freedoms that you received. You must make sure that they, too, receive
90 | or can get the source code. And you must show them these terms so they
91 | know their rights.
92 |
93 | Developers that use the GNU GPL protect your rights with two steps:
94 | (1) assert copyright on the software, and (2) offer you this License
95 | giving you legal permission to copy, distribute and/or modify it.
96 |
97 | For the developers' and authors' protection, the GPL clearly explains
98 | that there is no warranty for this free software. For both users' and
99 | authors' sake, the GPL requires that modified versions be marked as
100 | changed, so that their problems will not be attributed erroneously to
101 | authors of previous versions.
102 |
103 | Some devices are designed to deny users access to install or run
104 | modified versions of the software inside them, although the manufacturer
105 | can do so. This is fundamentally incompatible with the aim of
106 | protecting users' freedom to change the software. The systematic
107 | pattern of such abuse occurs in the area of products for individuals to
108 | use, which is precisely where it is most unacceptable. Therefore, we
109 | have designed this version of the GPL to prohibit the practice for those
110 | products. If such problems arise substantially in other domains, we
111 | stand ready to extend this provision to those domains in future versions
112 | of the GPL, as needed to protect the freedom of users.
113 |
114 | Finally, every program is threatened constantly by software patents.
115 | States should not allow patents to restrict development and use of
116 | software on general-purpose computers, but in those that do, we wish to
117 | avoid the special danger that patents applied to a free program could
118 | make it effectively proprietary. To prevent this, the GPL assures that
119 | patents cannot be used to render the program non-free.
120 |
121 | The precise terms and conditions for copying, distribution and
122 | modification follow.
123 |
124 | TERMS AND CONDITIONS
125 |
126 | 0. Definitions.
127 |
128 | "This License" refers to version 3 of the GNU General Public License.
129 |
130 | "Copyright" also means copyright-like laws that apply to other kinds of
131 | works, such as semiconductor masks.
132 |
133 | "The Program" refers to any copyrightable work licensed under this
134 | License. Each licensee is addressed as "you". "Licensees" and
135 | "recipients" may be individuals or organizations.
136 |
137 | To "modify" a work means to copy from or adapt all or part of the work
138 | in a fashion requiring copyright permission, other than the making of an
139 | exact copy. The resulting work is called a "modified version" of the
140 | earlier work or a work "based on" the earlier work.
141 |
142 | A "covered work" means either the unmodified Program or a work based
143 | on the Program.
144 |
145 | To "propagate" a work means to do anything with it that, without
146 | permission, would make you directly or secondarily liable for
147 | infringement under applicable copyright law, except executing it on a
148 | computer or modifying a private copy. Propagation includes copying,
149 | distribution (with or without modification), making available to the
150 | public, and in some countries other activities as well.
151 |
152 | To "convey" a work means any kind of propagation that enables other
153 | parties to make or receive copies. Mere interaction with a user through
154 | a computer network, with no transfer of a copy, is not conveying.
155 |
156 | An interactive user interface displays "Appropriate Legal Notices"
157 | to the extent that it includes a convenient and prominently visible
158 | feature that (1) displays an appropriate copyright notice, and (2)
159 | tells the user that there is no warranty for the work (except to the
160 | extent that warranties are provided), that licensees may convey the
161 | work under this License, and how to view a copy of this License. If
162 | the interface presents a list of user commands or options, such as a
163 | menu, a prominent item in the list meets this criterion.
164 |
165 | 1. Source Code.
166 |
167 | The "source code" for a work means the preferred form of the work
168 | for making modifications to it. "Object code" means any non-source
169 | form of a work.
170 |
171 | A "Standard Interface" means an interface that either is an official
172 | standard defined by a recognized standards body, or, in the case of
173 | interfaces specified for a particular programming language, one that
174 | is widely used among developers working in that language.
175 |
176 | The "System Libraries" of an executable work include anything, other
177 | than the work as a whole, that (a) is included in the normal form of
178 | packaging a Major Component, but which is not part of that Major
179 | Component, and (b) serves only to enable use of the work with that
180 | Major Component, or to implement a Standard Interface for which an
181 | implementation is available to the public in source code form. A
182 | "Major Component", in this context, means a major essential component
183 | (kernel, window system, and so on) of the specific operating system
184 | (if any) on which the executable work runs, or a compiler used to
185 | produce the work, or an object code interpreter used to run it.
186 |
187 | The "Corresponding Source" for a work in object code form means all
188 | the source code needed to generate, install, and (for an executable
189 | work) run the object code and to modify the work, including scripts to
190 | control those activities. However, it does not include the work's
191 | System Libraries, or general-purpose tools or generally available free
192 | programs which are used unmodified in performing those activities but
193 | which are not part of the work. For example, Corresponding Source
194 | includes interface definition files associated with source files for
195 | the work, and the source code for shared libraries and dynamically
196 | linked subprograms that the work is specifically designed to require,
197 | such as by intimate data communication or control flow between those
198 | subprograms and other parts of the work.
199 |
200 | The Corresponding Source need not include anything that users
201 | can regenerate automatically from other parts of the Corresponding
202 | Source.
203 |
204 | The Corresponding Source for a work in source code form is that
205 | same work.
206 |
207 | 2. Basic Permissions.
208 |
209 | All rights granted under this License are granted for the term of
210 | copyright on the Program, and are irrevocable provided the stated
211 | conditions are met. This License explicitly affirms your unlimited
212 | permission to run the unmodified Program. The output from running a
213 | covered work is covered by this License only if the output, given its
214 | content, constitutes a covered work. This License acknowledges your
215 | rights of fair use or other equivalent, as provided by copyright law.
216 |
217 | You may make, run and propagate covered works that you do not
218 | convey, without conditions so long as your license otherwise remains
219 | in force. You may convey covered works to others for the sole purpose
220 | of having them make modifications exclusively for you, or provide you
221 | with facilities for running those works, provided that you comply with
222 | the terms of this License in conveying all material for which you do
223 | not control copyright. Those thus making or running the covered works
224 | for you must do so exclusively on your behalf, under your direction
225 | and control, on terms that prohibit them from making any copies of
226 | your copyrighted material outside their relationship with you.
227 |
228 | Conveying under any other circumstances is permitted solely under
229 | the conditions stated below. Sublicensing is not allowed; section 10
230 | makes it unnecessary.
231 |
232 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
233 |
234 | No covered work shall be deemed part of an effective technological
235 | measure under any applicable law fulfilling obligations under article
236 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
237 | similar laws prohibiting or restricting circumvention of such
238 | measures.
239 |
240 | When you convey a covered work, you waive any legal power to forbid
241 | circumvention of technological measures to the extent such circumvention
242 | is effected by exercising rights under this License with respect to
243 | the covered work, and you disclaim any intention to limit operation or
244 | modification of the work as a means of enforcing, against the work's
245 | users, your or third parties' legal rights to forbid circumvention of
246 | technological measures.
247 |
248 | 4. Conveying Verbatim Copies.
249 |
250 | You may convey verbatim copies of the Program's source code as you
251 | receive it, in any medium, provided that you conspicuously and
252 | appropriately publish on each copy an appropriate copyright notice;
253 | keep intact all notices stating that this License and any
254 | non-permissive terms added in accord with section 7 apply to the code;
255 | keep intact all notices of the absence of any warranty; and give all
256 | recipients a copy of this License along with the Program.
257 |
258 | You may charge any price or no price for each copy that you convey,
259 | and you may offer support or warranty protection for a fee.
260 |
261 | 5. Conveying Modified Source Versions.
262 |
263 | You may convey a work based on the Program, or the modifications to
264 | produce it from the Program, in the form of source code under the
265 | terms of section 4, provided that you also meet all of these conditions:
266 |
267 | a) The work must carry prominent notices stating that you modified
268 | it, and giving a relevant date.
269 |
270 | b) The work must carry prominent notices stating that it is
271 | released under this License and any conditions added under section
272 | 7. This requirement modifies the requirement in section 4 to
273 | "keep intact all notices".
274 |
275 | c) You must license the entire work, as a whole, under this
276 | License to anyone who comes into possession of a copy. This
277 | License will therefore apply, along with any applicable section 7
278 | additional terms, to the whole of the work, and all its parts,
279 | regardless of how they are packaged. This License gives no
280 | permission to license the work in any other way, but it does not
281 | invalidate such permission if you have separately received it.
282 |
283 | d) If the work has interactive user interfaces, each must display
284 | Appropriate Legal Notices; however, if the Program has interactive
285 | interfaces that do not display Appropriate Legal Notices, your
286 | work need not make them do so.
287 |
288 | A compilation of a covered work with other separate and independent
289 | works, which are not by their nature extensions of the covered work,
290 | and which are not combined with it such as to form a larger program,
291 | in or on a volume of a storage or distribution medium, is called an
292 | "aggregate" if the compilation and its resulting copyright are not
293 | used to limit the access or legal rights of the compilation's users
294 | beyond what the individual works permit. Inclusion of a covered work
295 | in an aggregate does not cause this License to apply to the other
296 | parts of the aggregate.
297 |
298 | 6. Conveying Non-Source Forms.
299 |
300 | You may convey a covered work in object code form under the terms
301 | of sections 4 and 5, provided that you also convey the
302 | machine-readable Corresponding Source under the terms of this License,
303 | in one of these ways:
304 |
305 | a) Convey the object code in, or embodied in, a physical product
306 | (including a physical distribution medium), accompanied by the
307 | Corresponding Source fixed on a durable physical medium
308 | customarily used for software interchange.
309 |
310 | b) Convey the object code in, or embodied in, a physical product
311 | (including a physical distribution medium), accompanied by a
312 | written offer, valid for at least three years and valid for as
313 | long as you offer spare parts or customer support for that product
314 | model, to give anyone who possesses the object code either (1) a
315 | copy of the Corresponding Source for all the software in the
316 | product that is covered by this License, on a durable physical
317 | medium customarily used for software interchange, for a price no
318 | more than your reasonable cost of physically performing this
319 | conveying of source, or (2) access to copy the
320 | Corresponding Source from a network server at no charge.
321 |
322 | c) Convey individual copies of the object code with a copy of the
323 | written offer to provide the Corresponding Source. This
324 | alternative is allowed only occasionally and noncommercially, and
325 | only if you received the object code with such an offer, in accord
326 | with subsection 6b.
327 |
328 | d) Convey the object code by offering access from a designated
329 | place (gratis or for a charge), and offer equivalent access to the
330 | Corresponding Source in the same way through the same place at no
331 | further charge. You need not require recipients to copy the
332 | Corresponding Source along with the object code. If the place to
333 | copy the object code is a network server, the Corresponding Source
334 | may be on a different server (operated by you or a third party)
335 | that supports equivalent copying facilities, provided you maintain
336 | clear directions next to the object code saying where to find the
337 | Corresponding Source. Regardless of what server hosts the
338 | Corresponding Source, you remain obligated to ensure that it is
339 | available for as long as needed to satisfy these requirements.
340 |
341 | e) Convey the object code using peer-to-peer transmission, provided
342 | you inform other peers where the object code and Corresponding
343 | Source of the work are being offered to the general public at no
344 | charge under subsection 6d.
345 |
346 | A separable portion of the object code, whose source code is excluded
347 | from the Corresponding Source as a System Library, need not be
348 | included in conveying the object code work.
349 |
350 | A "User Product" is either (1) a "consumer product", which means any
351 | tangible personal property which is normally used for personal, family,
352 | or household purposes, or (2) anything designed or sold for incorporation
353 | into a dwelling. In determining whether a product is a consumer product,
354 | doubtful cases shall be resolved in favor of coverage. For a particular
355 | product received by a particular user, "normally used" refers to a
356 | typical or common use of that class of product, regardless of the status
357 | of the particular user or of the way in which the particular user
358 | actually uses, or expects or is expected to use, the product. A product
359 | is a consumer product regardless of whether the product has substantial
360 | commercial, industrial or non-consumer uses, unless such uses represent
361 | the only significant mode of use of the product.
362 |
363 | "Installation Information" for a User Product means any methods,
364 | procedures, authorization keys, or other information required to install
365 | and execute modified versions of a covered work in that User Product from
366 | a modified version of its Corresponding Source. The information must
367 | suffice to ensure that the continued functioning of the modified object
368 | code is in no case prevented or interfered with solely because
369 | modification has been made.
370 |
371 | If you convey an object code work under this section in, or with, or
372 | specifically for use in, a User Product, and the conveying occurs as
373 | part of a transaction in which the right of possession and use of the
374 | User Product is transferred to the recipient in perpetuity or for a
375 | fixed term (regardless of how the transaction is characterized), the
376 | Corresponding Source conveyed under this section must be accompanied
377 | by the Installation Information. But this requirement does not apply
378 | if neither you nor any third party retains the ability to install
379 | modified object code on the User Product (for example, the work has
380 | been installed in ROM).
381 |
382 | The requirement to provide Installation Information does not include a
383 | requirement to continue to provide support service, warranty, or updates
384 | for a work that has been modified or installed by the recipient, or for
385 | the User Product in which it has been modified or installed. Access to a
386 | network may be denied when the modification itself materially and
387 | adversely affects the operation of the network or violates the rules and
388 | protocols for communication across the network.
389 |
390 | Corresponding Source conveyed, and Installation Information provided,
391 | in accord with this section must be in a format that is publicly
392 | documented (and with an implementation available to the public in
393 | source code form), and must require no special password or key for
394 | unpacking, reading or copying.
395 |
396 | 7. Additional Terms.
397 |
398 | "Additional permissions" are terms that supplement the terms of this
399 | License by making exceptions from one or more of its conditions.
400 | Additional permissions that are applicable to the entire Program shall
401 | be treated as though they were included in this License, to the extent
402 | that they are valid under applicable law. If additional permissions
403 | apply only to part of the Program, that part may be used separately
404 | under those permissions, but the entire Program remains governed by
405 | this License without regard to the additional permissions.
406 |
407 | When you convey a copy of a covered work, you may at your option
408 | remove any additional permissions from that copy, or from any part of
409 | it. (Additional permissions may be written to require their own
410 | removal in certain cases when you modify the work.) You may place
411 | additional permissions on material, added by you to a covered work,
412 | for which you have or can give appropriate copyright permission.
413 |
414 | Notwithstanding any other provision of this License, for material you
415 | add to a covered work, you may (if authorized by the copyright holders of
416 | that material) supplement the terms of this License with terms:
417 |
418 | a) Disclaiming warranty or limiting liability differently from the
419 | terms of sections 15 and 16 of this License; or
420 |
421 | b) Requiring preservation of specified reasonable legal notices or
422 | author attributions in that material or in the Appropriate Legal
423 | Notices displayed by works containing it; or
424 |
425 | c) Prohibiting misrepresentation of the origin of that material, or
426 | requiring that modified versions of such material be marked in
427 | reasonable ways as different from the original version; or
428 |
429 | d) Limiting the use for publicity purposes of names of licensors or
430 | authors of the material; or
431 |
432 | e) Declining to grant rights under trademark law for use of some
433 | trade names, trademarks, or service marks; or
434 |
435 | f) Requiring indemnification of licensors and authors of that
436 | material by anyone who conveys the material (or modified versions of
437 | it) with contractual assumptions of liability to the recipient, for
438 | any liability that these contractual assumptions directly impose on
439 | those licensors and authors.
440 |
441 | All other non-permissive additional terms are considered "further
442 | restrictions" within the meaning of section 10. If the Program as you
443 | received it, or any part of it, contains a notice stating that it is
444 | governed by this License along with a term that is a further
445 | restriction, you may remove that term. If a license document contains
446 | a further restriction but permits relicensing or conveying under this
447 | License, you may add to a covered work material governed by the terms
448 | of that license document, provided that the further restriction does
449 | not survive such relicensing or conveying.
450 |
451 | If you add terms to a covered work in accord with this section, you
452 | must place, in the relevant source files, a statement of the
453 | additional terms that apply to those files, or a notice indicating
454 | where to find the applicable terms.
455 |
456 | Additional terms, permissive or non-permissive, may be stated in the
457 | form of a separately written license, or stated as exceptions;
458 | the above requirements apply either way.
459 |
460 | 8. Termination.
461 |
462 | You may not propagate or modify a covered work except as expressly
463 | provided under this License. Any attempt otherwise to propagate or
464 | modify it is void, and will automatically terminate your rights under
465 | this License (including any patent licenses granted under the third
466 | paragraph of section 11).
467 |
468 | However, if you cease all violation of this License, then your
469 | license from a particular copyright holder is reinstated (a)
470 | provisionally, unless and until the copyright holder explicitly and
471 | finally terminates your license, and (b) permanently, if the copyright
472 | holder fails to notify you of the violation by some reasonable means
473 | prior to 60 days after the cessation.
474 |
475 | Moreover, your license from a particular copyright holder is
476 | reinstated permanently if the copyright holder notifies you of the
477 | violation by some reasonable means, this is the first time you have
478 | received notice of violation of this License (for any work) from that
479 | copyright holder, and you cure the violation prior to 30 days after
480 | your receipt of the notice.
481 |
482 | Termination of your rights under this section does not terminate the
483 | licenses of parties who have received copies or rights from you under
484 | this License. If your rights have been terminated and not permanently
485 | reinstated, you do not qualify to receive new licenses for the same
486 | material under section 10.
487 |
488 | 9. Acceptance Not Required for Having Copies.
489 |
490 | You are not required to accept this License in order to receive or
491 | run a copy of the Program. Ancillary propagation of a covered work
492 | occurring solely as a consequence of using peer-to-peer transmission
493 | to receive a copy likewise does not require acceptance. However,
494 | nothing other than this License grants you permission to propagate or
495 | modify any covered work. These actions infringe copyright if you do
496 | not accept this License. Therefore, by modifying or propagating a
497 | covered work, you indicate your acceptance of this License to do so.
498 |
499 | 10. Automatic Licensing of Downstream Recipients.
500 |
501 | Each time you convey a covered work, the recipient automatically
502 | receives a license from the original licensors, to run, modify and
503 | propagate that work, subject to this License. You are not responsible
504 | for enforcing compliance by third parties with this License.
505 |
506 | An "entity transaction" is a transaction transferring control of an
507 | organization, or substantially all assets of one, or subdividing an
508 | organization, or merging organizations. If propagation of a covered
509 | work results from an entity transaction, each party to that
510 | transaction who receives a copy of the work also receives whatever
511 | licenses to the work the party's predecessor in interest had or could
512 | give under the previous paragraph, plus a right to possession of the
513 | Corresponding Source of the work from the predecessor in interest, if
514 | the predecessor has it or can get it with reasonable efforts.
515 |
516 | You may not impose any further restrictions on the exercise of the
517 | rights granted or affirmed under this License. For example, you may
518 | not impose a license fee, royalty, or other charge for exercise of
519 | rights granted under this License, and you may not initiate litigation
520 | (including a cross-claim or counterclaim in a lawsuit) alleging that
521 | any patent claim is infringed by making, using, selling, offering for
522 | sale, or importing the Program or any portion of it.
523 |
524 | 11. Patents.
525 |
526 | A "contributor" is a copyright holder who authorizes use under this
527 | License of the Program or a work on which the Program is based. The
528 | work thus licensed is called the contributor's "contributor version".
529 |
530 | A contributor's "essential patent claims" are all patent claims
531 | owned or controlled by the contributor, whether already acquired or
532 | hereafter acquired, that would be infringed by some manner, permitted
533 | by this License, of making, using, or selling its contributor version,
534 | but do not include claims that would be infringed only as a
535 | consequence of further modification of the contributor version. For
536 | purposes of this definition, "control" includes the right to grant
537 | patent sublicenses in a manner consistent with the requirements of
538 | this License.
539 |
540 | Each contributor grants you a non-exclusive, worldwide, royalty-free
541 | patent license under the contributor's essential patent claims, to
542 | make, use, sell, offer for sale, import and otherwise run, modify and
543 | propagate the contents of its contributor version.
544 |
545 | In the following three paragraphs, a "patent license" is any express
546 | agreement or commitment, however denominated, not to enforce a patent
547 | (such as an express permission to practice a patent or covenant not to
548 | sue for patent infringement). To "grant" such a patent license to a
549 | party means to make such an agreement or commitment not to enforce a
550 | patent against the party.
551 |
552 | If you convey a covered work, knowingly relying on a patent license,
553 | and the Corresponding Source of the work is not available for anyone
554 | to copy, free of charge and under the terms of this License, through a
555 | publicly available network server or other readily accessible means,
556 | then you must either (1) cause the Corresponding Source to be so
557 | available, or (2) arrange to deprive yourself of the benefit of the
558 | patent license for this particular work, or (3) arrange, in a manner
559 | consistent with the requirements of this License, to extend the patent
560 | license to downstream recipients. "Knowingly relying" means you have
561 | actual knowledge that, but for the patent license, your conveying the
562 | covered work in a country, or your recipient's use of the covered work
563 | in a country, would infringe one or more identifiable patents in that
564 | country that you have reason to believe are valid.
565 |
566 | If, pursuant to or in connection with a single transaction or
567 | arrangement, you convey, or propagate by procuring conveyance of, a
568 | covered work, and grant a patent license to some of the parties
569 | receiving the covered work authorizing them to use, propagate, modify
570 | or convey a specific copy of the covered work, then the patent license
571 | you grant is automatically extended to all recipients of the covered
572 | work and works based on it.
573 |
574 | A patent license is "discriminatory" if it does not include within
575 | the scope of its coverage, prohibits the exercise of, or is
576 | conditioned on the non-exercise of one or more of the rights that are
577 | specifically granted under this License. You may not convey a covered
578 | work if you are a party to an arrangement with a third party that is
579 | in the business of distributing software, under which you make payment
580 | to the third party based on the extent of your activity of conveying
581 | the work, and under which the third party grants, to any of the
582 | parties who would receive the covered work from you, a discriminatory
583 | patent license (a) in connection with copies of the covered work
584 | conveyed by you (or copies made from those copies), or (b) primarily
585 | for and in connection with specific products or compilations that
586 | contain the covered work, unless you entered into that arrangement,
587 | or that patent license was granted, prior to 28 March 2007.
588 |
589 | Nothing in this License shall be construed as excluding or limiting
590 | any implied license or other defenses to infringement that may
591 | otherwise be available to you under applicable patent law.
592 |
593 | 12. No Surrender of Others' Freedom.
594 |
595 | If conditions are imposed on you (whether by court order, agreement or
596 | otherwise) that contradict the conditions of this License, they do not
597 | excuse you from the conditions of this License. If you cannot convey a
598 | covered work so as to satisfy simultaneously your obligations under this
599 | License and any other pertinent obligations, then as a consequence you may
600 | not convey it at all. For example, if you agree to terms that obligate you
601 | to collect a royalty for further conveying from those to whom you convey
602 | the Program, the only way you could satisfy both those terms and this
603 | License would be to refrain entirely from conveying the Program.
604 |
605 | 13. Use with the GNU Affero General Public License.
606 |
607 | Notwithstanding any other provision of this License, you have
608 | permission to link or combine any covered work with a work licensed
609 | under version 3 of the GNU Affero General Public License into a single
610 | combined work, and to convey the resulting work. The terms of this
611 | License will continue to apply to the part which is the covered work,
612 | but the special requirements of the GNU Affero General Public License,
613 | section 13, concerning interaction through a network will apply to the
614 | combination as such.
615 |
616 | 14. Revised Versions of this License.
617 |
618 | The Free Software Foundation may publish revised and/or new versions of
619 | the GNU General Public License from time to time. Such new versions will
620 | be similar in spirit to the present version, but may differ in detail to
621 | address new problems or concerns.
622 |
623 | Each version is given a distinguishing version number. If the
624 | Program specifies that a certain numbered version of the GNU General
625 | Public License "or any later version" applies to it, you have the
626 | option of following the terms and conditions either of that numbered
627 | version or of any later version published by the Free Software
628 | Foundation. If the Program does not specify a version number of the
629 | GNU General Public License, you may choose any version ever published
630 | by the Free Software Foundation.
631 |
632 | If the Program specifies that a proxy can decide which future
633 | versions of the GNU General Public License can be used, that proxy's
634 | public statement of acceptance of a version permanently authorizes you
635 | to choose that version for the Program.
636 |
637 | Later license versions may give you additional or different
638 | permissions. However, no additional obligations are imposed on any
639 | author or copyright holder as a result of your choosing to follow a
640 | later version.
641 |
642 | 15. Disclaimer of Warranty.
643 |
644 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
645 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
646 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
647 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
648 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
649 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
650 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
651 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
652 |
653 | 16. Limitation of Liability.
654 |
655 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
656 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
657 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
658 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
659 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
660 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
661 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
662 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
663 | SUCH DAMAGES.
664 |
665 | 17. Interpretation of Sections 15 and 16.
666 |
667 | If the disclaimer of warranty and limitation of liability provided
668 | above cannot be given local legal effect according to their terms,
669 | reviewing courts shall apply local law that most closely approximates
670 | an absolute waiver of all civil liability in connection with the
671 | Program, unless a warranty or assumption of liability accompanies a
672 | copy of the Program in return for a fee.
673 |
674 | END OF TERMS AND CONDITIONS
675 |
676 | How to Apply These Terms to Your New Programs
677 |
678 | If you develop a new program, and you want it to be of the greatest
679 | possible use to the public, the best way to achieve this is to make it
680 | free software which everyone can redistribute and change under these terms.
681 |
682 | To do so, attach the following notices to the program. It is safest
683 | to attach them to the start of each source file to most effectively
684 | state the exclusion of warranty; and each file should have at least
685 | the "copyright" line and a pointer to where the full notice is found.
686 |
687 |
688 | Copyright (C)
689 |
690 | This program is free software: you can redistribute it and/or modify
691 | it under the terms of the GNU General Public License as published by
692 | the Free Software Foundation, either version 3 of the License, or
693 | (at your option) any later version.
694 |
695 | This program is distributed in the hope that it will be useful,
696 | but WITHOUT ANY WARRANTY; without even the implied warranty of
697 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
698 | GNU General Public License for more details.
699 |
700 | You should have received a copy of the GNU General Public License
701 | along with this program. If not, see .
702 |
703 | Also add information on how to contact you by electronic and paper mail.
704 |
705 | If the program does terminal interaction, make it output a short
706 | notice like this when it starts in an interactive mode:
707 |
708 | Copyright (C)
709 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
710 | This is free software, and you are welcome to redistribute it
711 | under certain conditions; type `show c' for details.
712 |
713 | The hypothetical commands `show w' and `show c' should show the appropriate
714 | parts of the General Public License. Of course, your program's commands
715 | might be different; for a GUI interface, you would use an "about box".
716 |
717 | You should also get your employer (if you work as a programmer) or school,
718 | if any, to sign a "copyright disclaimer" for the program, if necessary.
719 | For more information on this, and how to apply and follow the GNU GPL, see
720 | .
721 |
722 | The GNU General Public License does not permit incorporating your program
723 | into proprietary programs. If your program is a subroutine library, you
724 | may consider it more useful to permit linking proprietary applications with
725 | the library. If this is what you want to do, use the GNU Lesser General
726 | Public License instead of this License. But first, please read
727 | .
728 | {%- elif cookiecutter.license == "Apache Software License 2.0" -%}
729 | Apache License
730 | Version 2.0, January 2004
731 | http://www.apache.org/licenses/
732 |
733 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
734 |
735 | 1. Definitions.
736 |
737 | "License" shall mean the terms and conditions for use, reproduction,
738 | and distribution as defined by Sections 1 through 9 of this document.
739 |
740 | "Licensor" shall mean the copyright owner or entity authorized by
741 | the copyright owner that is granting the License.
742 |
743 | "Legal Entity" shall mean the union of the acting entity and all
744 | other entities that control, are controlled by, or are under common
745 | control with that entity. For the purposes of this definition,
746 | "control" means (i) the power, direct or indirect, to cause the
747 | direction or management of such entity, whether by contract or
748 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
749 | outstanding shares, or (iii) beneficial ownership of such entity.
750 |
751 | "You" (or "Your") shall mean an individual or Legal Entity
752 | exercising permissions granted by this License.
753 |
754 | "Source" form shall mean the preferred form for making modifications,
755 | including but not limited to software source code, documentation
756 | source, and configuration files.
757 |
758 | "Object" form shall mean any form resulting from mechanical
759 | transformation or translation of a Source form, including but
760 | not limited to compiled object code, generated documentation,
761 | and conversions to other media types.
762 |
763 | "Work" shall mean the work of authorship, whether in Source or
764 | Object form, made available under the License, as indicated by a
765 | copyright notice that is included in or attached to the work
766 | (an example is provided in the Appendix below).
767 |
768 | "Derivative Works" shall mean any work, whether in Source or Object
769 | form, that is based on (or derived from) the Work and for which the
770 | editorial revisions, annotations, elaborations, or other modifications
771 | represent, as a whole, an original work of authorship. For the purposes
772 | of this License, Derivative Works shall not include works that remain
773 | separable from, or merely link (or bind by name) to the interfaces of,
774 | the Work and Derivative Works thereof.
775 |
776 | "Contribution" shall mean any work of authorship, including
777 | the original version of the Work and any modifications or additions
778 | to that Work or Derivative Works thereof, that is intentionally
779 | submitted to Licensor for inclusion in the Work by the copyright owner
780 | or by an individual or Legal Entity authorized to submit on behalf of
781 | the copyright owner. For the purposes of this definition, "submitted"
782 | means any form of electronic, verbal, or written communication sent
783 | to the Licensor or its representatives, including but not limited to
784 | communication on electronic mailing lists, source code control systems,
785 | and issue tracking systems that are managed by, or on behalf of, the
786 | Licensor for the purpose of discussing and improving the Work, but
787 | excluding communication that is conspicuously marked or otherwise
788 | designated in writing by the copyright owner as "Not a Contribution."
789 |
790 | "Contributor" shall mean Licensor and any individual or Legal Entity
791 | on behalf of whom a Contribution has been received by Licensor and
792 | subsequently incorporated within the Work.
793 |
794 | 2. Grant of Copyright License. Subject to the terms and conditions of
795 | this License, each Contributor hereby grants to You a perpetual,
796 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
797 | copyright license to reproduce, prepare Derivative Works of,
798 | publicly display, publicly perform, sublicense, and distribute the
799 | Work and such Derivative Works in Source or Object form.
800 |
801 | 3. Grant of Patent License. Subject to the terms and conditions of
802 | this License, each Contributor hereby grants to You a perpetual,
803 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
804 | (except as stated in this section) patent license to make, have made,
805 | use, offer to sell, sell, import, and otherwise transfer the Work,
806 | where such license applies only to those patent claims licensable
807 | by such Contributor that are necessarily infringed by their
808 | Contribution(s) alone or by combination of their Contribution(s)
809 | with the Work to which such Contribution(s) was submitted. If You
810 | institute patent litigation against any entity (including a
811 | cross-claim or counterclaim in a lawsuit) alleging that the Work
812 | or a Contribution incorporated within the Work constitutes direct
813 | or contributory patent infringement, then any patent licenses
814 | granted to You under this License for that Work shall terminate
815 | as of the date such litigation is filed.
816 |
817 | 4. Redistribution. You may reproduce and distribute copies of the
818 | Work or Derivative Works thereof in any medium, with or without
819 | modifications, and in Source or Object form, provided that You
820 | meet the following conditions:
821 |
822 | (a) You must give any other recipients of the Work or
823 | Derivative Works a copy of this License; and
824 |
825 | (b) You must cause any modified files to carry prominent notices
826 | stating that You changed the files; and
827 |
828 | (c) You must retain, in the Source form of any Derivative Works
829 | that You distribute, all copyright, patent, trademark, and
830 | attribution notices from the Source form of the Work,
831 | excluding those notices that do not pertain to any part of
832 | the Derivative Works; and
833 |
834 | (d) If the Work includes a "NOTICE" text file as part of its
835 | distribution, then any Derivative Works that You distribute must
836 | include a readable copy of the attribution notices contained
837 | within such NOTICE file, excluding those notices that do not
838 | pertain to any part of the Derivative Works, in at least one
839 | of the following places: within a NOTICE text file distributed
840 | as part of the Derivative Works; within the Source form or
841 | documentation, if provided along with the Derivative Works; or,
842 | within a display generated by the Derivative Works, if and
843 | wherever such third-party notices normally appear. The contents
844 | of the NOTICE file are for informational purposes only and
845 | do not modify the License. You may add Your own attribution
846 | notices within Derivative Works that You distribute, alongside
847 | or as an addendum to the NOTICE text from the Work, provided
848 | that such additional attribution notices cannot be construed
849 | as modifying the License.
850 |
851 | You may add Your own copyright statement to Your modifications and
852 | may provide additional or different license terms and conditions
853 | for use, reproduction, or distribution of Your modifications, or
854 | for any such Derivative Works as a whole, provided Your use,
855 | reproduction, and distribution of the Work otherwise complies with
856 | the conditions stated in this License.
857 |
858 | 5. Submission of Contributions. Unless You explicitly state otherwise,
859 | any Contribution intentionally submitted for inclusion in the Work
860 | by You to the Licensor shall be under the terms and conditions of
861 | this License, without any additional terms or conditions.
862 | Notwithstanding the above, nothing herein shall supersede or modify
863 | the terms of any separate license agreement you may have executed
864 | with Licensor regarding such Contributions.
865 |
866 | 6. Trademarks. This License does not grant permission to use the trade
867 | names, trademarks, service marks, or product names of the Licensor,
868 | except as required for reasonable and customary use in describing the
869 | origin of the Work and reproducing the content of the NOTICE file.
870 |
871 | 7. Disclaimer of Warranty. Unless required by applicable law or
872 | agreed to in writing, Licensor provides the Work (and each
873 | Contributor provides its Contributions) on an "AS IS" BASIS,
874 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
875 | implied, including, without limitation, any warranties or conditions
876 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
877 | PARTICULAR PURPOSE. You are solely responsible for determining the
878 | appropriateness of using or redistributing the Work and assume any
879 | risks associated with Your exercise of permissions under this License.
880 |
881 | 8. Limitation of Liability. In no event and under no legal theory,
882 | whether in tort (including negligence), contract, or otherwise,
883 | unless required by applicable law (such as deliberate and grossly
884 | negligent acts) or agreed to in writing, shall any Contributor be
885 | liable to You for damages, including any direct, indirect, special,
886 | incidental, or consequential damages of any character arising as a
887 | result of this License or out of the use or inability to use the
888 | Work (including but not limited to damages for loss of goodwill,
889 | work stoppage, computer failure or malfunction, or any and all
890 | other commercial damages or losses), even if such Contributor
891 | has been advised of the possibility of such damages.
892 |
893 | 9. Accepting Warranty or Additional Liability. While redistributing
894 | the Work or Derivative Works thereof, You may choose to offer,
895 | and charge a fee for, acceptance of support, warranty, indemnity,
896 | or other liability obligations and/or rights consistent with this
897 | License. However, in accepting such obligations, You may act only
898 | on Your own behalf and on Your sole responsibility, not on behalf
899 | of any other Contributor, and only if You agree to indemnify,
900 | defend, and hold each Contributor harmless for any liability
901 | incurred by, or claims asserted against, such Contributor by reason
902 | of your accepting any such warranty or additional liability.
903 |
904 | END OF TERMS AND CONDITIONS
905 |
906 | APPENDIX: How to apply the Apache License to your work.
907 |
908 | To apply the Apache License to your work, attach the following
909 | boilerplate notice, with the fields enclosed by brackets "[]"
910 | replaced with your own identifying information. (Don't include
911 | the brackets!) The text should be enclosed in the appropriate
912 | comment syntax for the file format. We also recommend that a
913 | file or class name and description of purpose be included on the
914 | same "printed page" as the copyright notice for easier
915 | identification within third-party archives.
916 |
917 | Copyright [yyyy] [name of copyright owner]
918 |
919 | Licensed under the Apache License, Version 2.0 (the "License");
920 | you may not use this file except in compliance with the License.
921 | You may obtain a copy of the License at
922 |
923 | http://www.apache.org/licenses/LICENSE-2.0
924 |
925 | Unless required by applicable law or agreed to in writing, software
926 | distributed under the License is distributed on an "AS IS" BASIS,
927 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
928 | See the License for the specific language governing permissions and
929 | limitations under the License.
930 | {% endif %}
931 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/README.md:
--------------------------------------------------------------------------------
1 | # {{ cookiecutter.name }}
2 |
3 | This project was generated via [manage-fastapi](https://ycd.github.io/manage-fastapi/)! :tada:
4 |
5 | ## License
6 |
7 | This project is licensed under the terms of the {{ cookiecutter.license }} license.
8 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/app/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/app/__init__.py
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/app/core/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/app/core/__init__.py
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/app/core/config.py:
--------------------------------------------------------------------------------
1 | {% if cookiecutter.database == "Postgres" %}
2 | from typing import Any, Dict, List, Optional, Union
3 |
4 | from pydantic import AnyHttpUrl, BaseSettings, PostgresDsn, validator
5 | {% elif cookiecutter.database == "MySQL" %}
6 | from typing import Any, Dict, List, Optional, Union
7 |
8 | from pydantic import AnyHttpUrl, BaseSettings, validator
9 | {% else %}
10 | from typing import List, Union
11 |
12 | from pydantic import AnyHttpUrl, BaseSettings, validator
13 |
14 | {% endif %}
15 |
16 | class Settings(BaseSettings):
17 | PROJECT_NAME: str
18 | BACKEND_CORS_ORIGINS: List[AnyHttpUrl] = []
19 |
20 | @validator("BACKEND_CORS_ORIGINS", pre=True)
21 | def assemble_cors_origins(cls, v: Union[str, List[str]]) -> Union[List[str], str]:
22 | if isinstance(v, str) and not v.startswith("["):
23 | return [i.strip() for i in v.split(",")]
24 | elif isinstance(v, (list, str)):
25 | return v
26 | raise ValueError(v)
27 |
28 | {% if cookiecutter.database == "Postgres" -%}
29 | POSTGRES_SERVER: str
30 | POSTGRES_USER: str
31 | POSTGRES_PASSWORD: str
32 | POSTGRES_DB: str
33 | DATABASE_URI: Optional[PostgresDsn] = None
34 |
35 | @validator("DATABASE_URI", pre=True)
36 | def assemble_db_connection(cls, v: Optional[str], values: Dict[str, Any]) -> Any:
37 | if isinstance(v, str):
38 | return v
39 | return PostgresDsn.build(
40 | scheme="postgresql",
41 | user=values.get("POSTGRES_USER"),
42 | password=values.get("POSTGRES_PASSWORD"),
43 | host=values.get("POSTGRES_SERVER"),
44 | path=f"/{values.get('POSTGRES_DB') or ''}",
45 | )
46 | {% elif cookiecutter.database == "MySQL" -%}
47 | MYSQL_USER: str
48 | MYSQL_PASSWORD: str
49 | MYSQL_HOST: str
50 | MYSQL_PORT: str
51 | MYSQL_DATABASE: str
52 | DATABASE_URI: Optional[str] = None
53 |
54 | @validator("DATABASE_URI", pre=True)
55 | def assemble_db_connection(cls, v: Optional[str], values: Dict[str, Any]) -> Any:
56 | if isinstance(v, str):
57 | return v
58 | return f"mysql://{values.get('MYSQL_USER')}:{values.get('MYSQL_PASSWORD')}@{values.get('MYSQL_HOST')}:" \
59 | f"{values.get('MYSQL_PORT')}/{values.get('MYSQL_DATABASE')}"
60 | {%- endif %}
61 |
62 | class Config:
63 | case_sensitive = True
64 | env_file = ".env"
65 |
66 |
67 | settings = Settings()
68 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/app/database.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy import create_engine
2 | from sqlalchemy.ext.declarative import as_declarative, declared_attr
3 | from sqlalchemy.orm import sessionmaker
4 |
5 | from app.core.config import settings
6 |
7 | engine = create_engine(settings.DATABASE_URI, pool_pre_ping=True)
8 | SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
9 |
10 |
11 | @as_declarative()
12 | class Base:
13 |
14 | @declared_attr
15 | def __tablename__(cls) -> str:
16 | return cls.__name__.lower()
17 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/app/main.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.middleware.cors import CORSMiddleware
3 |
4 | from app.core.config import settings
5 |
6 |
7 | def get_application():
8 | _app = FastAPI(title=settings.PROJECT_NAME)
9 |
10 | _app.add_middleware(
11 | CORSMiddleware,
12 | allow_origins=[str(origin) for origin in settings.BACKEND_CORS_ORIGINS],
13 | allow_credentials=True,
14 | allow_methods=["*"],
15 | allow_headers=["*"],
16 | )
17 |
18 | return _app
19 |
20 |
21 | app = get_application()
22 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | version: "3.8"
2 |
3 | services:
4 | app:
5 | build: .
6 | env_file:
7 | - .env
8 | ports:
9 | - "8000:8000"
10 |
11 | {% if cookiecutter.database == "Postgres" %}
12 | database:
13 | image: postgres:12
14 | env_file:
15 | - .env
16 | ports:
17 | - "5432:5432"
18 | {% elif cookiecutter.database == "MySQL" %}
19 | database:
20 | image: mysql:5.7
21 | env_file:
22 | - .env
23 | ports:
24 | - "3306:3306"
25 | {% endif %}
26 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "{{ cookiecutter.name }}"
3 | version = "0.1.0"
4 | description = ""
5 | {% if cookiecutter.username != None %}authors = ["{{ cookiecutter.username }} <{{ cookiecutter.email }}>"]{% endif %}
6 |
7 | [tool.poetry.dependencies]
8 | python = "^{{ cookiecutter.python }}"
9 | fastapi = "^{{ cookiecutter.fastapi }}"
10 |
11 | [tool.poetry.dev-dependencies]
12 | pytest = "^5.2"
13 | pytest-cov = "^2.10.1"
14 | {%- if cookiecutter.pre_commit == "True" %}
15 | autoflake = "^1.4"
16 | flake8 = "^3.8.4"
17 | mypy = "^0.790"
18 | isort = "^5.0"
19 | pre-commit = "^2.8.2"
20 | black = "^20.8b1"
21 | {%- endif %}
22 |
23 | [build-system]
24 | requires = ["poetry-core>=1.0.0"]
25 | build-backend = "poetry.core.masonry.api"
26 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/requirements.txt:
--------------------------------------------------------------------------------
1 | fastapi=={{ cookiecutter.fastapi }}
2 | uvicorn==0.12.2
3 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/setup.cfg:
--------------------------------------------------------------------------------
1 | [isort]
2 | profile = black
3 | known_first_party = app
4 |
5 | [flake8]
6 | max-complexity = 7
7 | statistics = True
8 | max-line-length = 88
9 | ignore = W503,E203
10 | per-file-ignores =
11 | __init__.py: F401
12 |
13 | [mypy]
14 | plugins = pydantic.mypy
15 | ignore_missing_imports = True
16 | follow_imports = skip
17 | strict_optional = True
18 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/tests/__init__.py
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/{{ cookiecutter.env }}:
--------------------------------------------------------------------------------
1 | PROJECT_NAME={{ cookiecutter.name }}
2 | BACKEND_CORS_ORIGINS=["http://localhost:8000", "https://localhost:8000", "http://localhost", "https://localhost"]
3 |
4 | {% if cookiecutter.database == "Postgres" %}
5 | POSTGRES_USER=postgres
6 | POSTGRES_PASSWORD=postgres
7 | POSTGRES_SERVER=database
8 | POSTGRES_DB=app
9 | {% elif cookiecutter.database == "MySQL" %}
10 | MYSQL_ROOT_PASSWORD=development
11 | MYSQL_USER=user
12 | MYSQL_PASSWORD=password
13 | MYSQL_HOST=database
14 | MYSQL_PORT=3306
15 | MYSQL_DATABASE=app
16 | {% endif %}
17 |
--------------------------------------------------------------------------------
/manage_fastapi/templates/project/{{ cookiecutter.folder_name }}/{{ cookiecutter.gitignore }}:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
98 | __pypackages__/
99 |
100 | # Celery stuff
101 | celerybeat-schedule
102 | celerybeat.pid
103 |
104 | # SageMath parsed files
105 | *.sage.py
106 |
107 | # Environments
108 | .env
109 | .venv
110 | env/
111 | venv/
112 | ENV/
113 | env.bak/
114 | venv.bak/
115 |
116 | # Spyder project settings
117 | .spyderproject
118 | .spyproject
119 |
120 | # Rope project settings
121 | .ropeproject
122 |
123 | # mkdocs documentation
124 | /site
125 |
126 | # mypy
127 | .mypy_cache/
128 | .dmypy.json
129 | dmypy.json
130 |
131 | # Pyre type checker
132 | .pyre/
133 |
134 | # pytype static type analyzer
135 | .pytype/
136 |
137 | # Cython debug symbols
138 | cython_debug/
139 |
140 | # Text Editor
141 | .vscode
142 |
--------------------------------------------------------------------------------
/poetry.lock:
--------------------------------------------------------------------------------
1 | [[package]]
2 | name = "appdirs"
3 | version = "1.4.4"
4 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
5 | category = "dev"
6 | optional = false
7 | python-versions = "*"
8 |
9 | [[package]]
10 | name = "arrow"
11 | version = "1.1.1"
12 | description = "Better dates & times for Python"
13 | category = "main"
14 | optional = false
15 | python-versions = ">=3.6"
16 |
17 | [package.dependencies]
18 | python-dateutil = ">=2.7.0"
19 | typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
20 |
21 | [[package]]
22 | name = "atomicwrites"
23 | version = "1.4.0"
24 | description = "Atomic file writes."
25 | category = "dev"
26 | optional = false
27 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
28 |
29 | [[package]]
30 | name = "attrs"
31 | version = "21.2.0"
32 | description = "Classes Without Boilerplate"
33 | category = "dev"
34 | optional = false
35 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
36 |
37 | [package.extras]
38 | dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"]
39 | docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
40 | tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
41 | tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
42 |
43 | [[package]]
44 | name = "autoflake"
45 | version = "1.4"
46 | description = "Removes unused imports and unused variables"
47 | category = "dev"
48 | optional = false
49 | python-versions = "*"
50 |
51 | [package.dependencies]
52 | pyflakes = ">=1.1.0"
53 |
54 | [[package]]
55 | name = "backports.entry-points-selectable"
56 | version = "1.1.0"
57 | description = "Compatibility shim providing selectable entry points for older implementations"
58 | category = "dev"
59 | optional = false
60 | python-versions = ">=2.7"
61 |
62 | [package.dependencies]
63 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
64 |
65 | [package.extras]
66 | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
67 | testing = ["pytest (>=4.6)", "pytest-flake8", "pytest-cov", "pytest-black (>=0.3.7)", "pytest-mypy", "pytest-checkdocs (>=2.4)", "pytest-enabler (>=1.0.1)"]
68 |
69 | [[package]]
70 | name = "binaryornot"
71 | version = "0.4.4"
72 | description = "Ultra-lightweight pure Python package to check if a file is binary or text."
73 | category = "main"
74 | optional = false
75 | python-versions = "*"
76 |
77 | [package.dependencies]
78 | chardet = ">=3.0.2"
79 |
80 | [[package]]
81 | name = "black"
82 | version = "20.8b1"
83 | description = "The uncompromising code formatter."
84 | category = "dev"
85 | optional = false
86 | python-versions = ">=3.6"
87 |
88 | [package.dependencies]
89 | appdirs = "*"
90 | click = ">=7.1.2"
91 | dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""}
92 | mypy-extensions = ">=0.4.3"
93 | pathspec = ">=0.6,<1"
94 | regex = ">=2020.1.8"
95 | toml = ">=0.10.1"
96 | typed-ast = ">=1.4.0"
97 | typing-extensions = ">=3.7.4"
98 |
99 | [package.extras]
100 | colorama = ["colorama (>=0.4.3)"]
101 | d = ["aiohttp (>=3.3.2)", "aiohttp-cors"]
102 |
103 | [[package]]
104 | name = "certifi"
105 | version = "2021.5.30"
106 | description = "Python package for providing Mozilla's CA Bundle."
107 | category = "main"
108 | optional = false
109 | python-versions = "*"
110 |
111 | [[package]]
112 | name = "cfgv"
113 | version = "3.3.1"
114 | description = "Validate configuration and produce human readable error messages."
115 | category = "dev"
116 | optional = false
117 | python-versions = ">=3.6.1"
118 |
119 | [[package]]
120 | name = "chardet"
121 | version = "4.0.0"
122 | description = "Universal encoding detector for Python 2 and 3"
123 | category = "main"
124 | optional = false
125 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
126 |
127 | [[package]]
128 | name = "charset-normalizer"
129 | version = "2.0.4"
130 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
131 | category = "main"
132 | optional = false
133 | python-versions = ">=3.5.0"
134 |
135 | [package.extras]
136 | unicode_backport = ["unicodedata2"]
137 |
138 | [[package]]
139 | name = "click"
140 | version = "8.0.1"
141 | description = "Composable command line interface toolkit"
142 | category = "main"
143 | optional = false
144 | python-versions = ">=3.6"
145 |
146 | [package.dependencies]
147 | colorama = {version = "*", markers = "platform_system == \"Windows\""}
148 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
149 |
150 | [[package]]
151 | name = "colorama"
152 | version = "0.4.4"
153 | description = "Cross-platform colored terminal text."
154 | category = "main"
155 | optional = false
156 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
157 |
158 | [[package]]
159 | name = "cookiecutter"
160 | version = "1.7.3"
161 | description = "A command-line utility that creates projects from project templates, e.g. creating a Python package project from a Python package project template."
162 | category = "main"
163 | optional = false
164 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
165 |
166 | [package.dependencies]
167 | binaryornot = ">=0.4.4"
168 | click = ">=7.0"
169 | Jinja2 = ">=2.7,<4.0.0"
170 | jinja2-time = ">=0.2.0"
171 | poyo = ">=0.5.0"
172 | python-slugify = ">=4.0.0"
173 | requests = ">=2.23.0"
174 | six = ">=1.10"
175 |
176 | [[package]]
177 | name = "coverage"
178 | version = "6.2"
179 | description = "Code coverage measurement for Python"
180 | category = "dev"
181 | optional = false
182 | python-versions = ">=3.6"
183 |
184 | [package.dependencies]
185 | tomli = {version = "*", optional = true, markers = "extra == \"toml\""}
186 |
187 | [package.extras]
188 | toml = ["tomli"]
189 |
190 | [[package]]
191 | name = "dataclasses"
192 | version = "0.8"
193 | description = "A backport of the dataclasses module for Python 3.6"
194 | category = "main"
195 | optional = false
196 | python-versions = ">=3.6, <3.7"
197 |
198 | [[package]]
199 | name = "distlib"
200 | version = "0.3.2"
201 | description = "Distribution utilities"
202 | category = "dev"
203 | optional = false
204 | python-versions = "*"
205 |
206 | [[package]]
207 | name = "dnspython"
208 | version = "2.1.0"
209 | description = "DNS toolkit"
210 | category = "main"
211 | optional = false
212 | python-versions = ">=3.6"
213 |
214 | [package.extras]
215 | dnssec = ["cryptography (>=2.6)"]
216 | doh = ["requests", "requests-toolbelt"]
217 | idna = ["idna (>=2.1)"]
218 | curio = ["curio (>=1.2)", "sniffio (>=1.1)"]
219 | trio = ["trio (>=0.14.0)", "sniffio (>=1.1)"]
220 |
221 | [[package]]
222 | name = "email-validator"
223 | version = "1.1.3"
224 | description = "A robust email syntax and deliverability validation library for Python 2.x/3.x."
225 | category = "main"
226 | optional = false
227 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
228 |
229 | [package.dependencies]
230 | dnspython = ">=1.15.0"
231 | idna = ">=2.0.0"
232 |
233 | [[package]]
234 | name = "filelock"
235 | version = "3.0.12"
236 | description = "A platform independent file lock."
237 | category = "dev"
238 | optional = false
239 | python-versions = "*"
240 |
241 | [[package]]
242 | name = "flake8"
243 | version = "4.0.1"
244 | description = "the modular source code checker: pep8 pyflakes and co"
245 | category = "dev"
246 | optional = false
247 | python-versions = ">=3.6"
248 |
249 | [package.dependencies]
250 | importlib-metadata = {version = "<4.3", markers = "python_version < \"3.8\""}
251 | mccabe = ">=0.6.0,<0.7.0"
252 | pycodestyle = ">=2.8.0,<2.9.0"
253 | pyflakes = ">=2.4.0,<2.5.0"
254 |
255 | [[package]]
256 | name = "identify"
257 | version = "2.2.13"
258 | description = "File identification library for Python"
259 | category = "dev"
260 | optional = false
261 | python-versions = ">=3.6.1"
262 |
263 | [package.extras]
264 | license = ["editdistance-s"]
265 |
266 | [[package]]
267 | name = "idna"
268 | version = "3.2"
269 | description = "Internationalized Domain Names in Applications (IDNA)"
270 | category = "main"
271 | optional = false
272 | python-versions = ">=3.5"
273 |
274 | [[package]]
275 | name = "importlib-metadata"
276 | version = "4.2.0"
277 | description = "Read metadata from Python packages"
278 | category = "main"
279 | optional = false
280 | python-versions = ">=3.6"
281 |
282 | [package.dependencies]
283 | typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
284 | zipp = ">=0.5"
285 |
286 | [package.extras]
287 | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
288 | testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
289 |
290 | [[package]]
291 | name = "importlib-resources"
292 | version = "5.2.2"
293 | description = "Read resources from Python packages"
294 | category = "dev"
295 | optional = false
296 | python-versions = ">=3.6"
297 |
298 | [package.dependencies]
299 | zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""}
300 |
301 | [package.extras]
302 | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
303 | testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy"]
304 |
305 | [[package]]
306 | name = "iniconfig"
307 | version = "1.1.1"
308 | description = "iniconfig: brain-dead simple config-ini parsing"
309 | category = "dev"
310 | optional = false
311 | python-versions = "*"
312 |
313 | [[package]]
314 | name = "isort"
315 | version = "5.10.1"
316 | description = "A Python utility / library to sort Python imports."
317 | category = "dev"
318 | optional = false
319 | python-versions = ">=3.6.1,<4.0"
320 |
321 | [package.extras]
322 | pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
323 | requirements_deprecated_finder = ["pipreqs", "pip-api"]
324 | colors = ["colorama (>=0.4.3,<0.5.0)"]
325 | plugins = ["setuptools"]
326 |
327 | [[package]]
328 | name = "jinja2"
329 | version = "3.0.1"
330 | description = "A very fast and expressive template engine."
331 | category = "main"
332 | optional = false
333 | python-versions = ">=3.6"
334 |
335 | [package.dependencies]
336 | MarkupSafe = ">=2.0"
337 |
338 | [package.extras]
339 | i18n = ["Babel (>=2.7)"]
340 |
341 | [[package]]
342 | name = "jinja2-time"
343 | version = "0.2.0"
344 | description = "Jinja2 Extension for Dates and Times"
345 | category = "main"
346 | optional = false
347 | python-versions = "*"
348 |
349 | [package.dependencies]
350 | arrow = "*"
351 | jinja2 = "*"
352 |
353 | [[package]]
354 | name = "markupsafe"
355 | version = "2.0.1"
356 | description = "Safely add untrusted strings to HTML/XML markup."
357 | category = "main"
358 | optional = false
359 | python-versions = ">=3.6"
360 |
361 | [[package]]
362 | name = "mccabe"
363 | version = "0.6.1"
364 | description = "McCabe checker, plugin for flake8"
365 | category = "dev"
366 | optional = false
367 | python-versions = "*"
368 |
369 | [[package]]
370 | name = "mypy"
371 | version = "0.790"
372 | description = "Optional static typing for Python"
373 | category = "dev"
374 | optional = false
375 | python-versions = ">=3.5"
376 |
377 | [package.dependencies]
378 | mypy-extensions = ">=0.4.3,<0.5.0"
379 | typed-ast = ">=1.4.0,<1.5.0"
380 | typing-extensions = ">=3.7.4"
381 |
382 | [package.extras]
383 | dmypy = ["psutil (>=4.0)"]
384 |
385 | [[package]]
386 | name = "mypy-extensions"
387 | version = "0.4.3"
388 | description = "Experimental type system extensions for programs checked with the mypy typechecker."
389 | category = "dev"
390 | optional = false
391 | python-versions = "*"
392 |
393 | [[package]]
394 | name = "nodeenv"
395 | version = "1.6.0"
396 | description = "Node.js virtual environment builder"
397 | category = "dev"
398 | optional = false
399 | python-versions = "*"
400 |
401 | [[package]]
402 | name = "packaging"
403 | version = "21.0"
404 | description = "Core utilities for Python packages"
405 | category = "dev"
406 | optional = false
407 | python-versions = ">=3.6"
408 |
409 | [package.dependencies]
410 | pyparsing = ">=2.0.2"
411 |
412 | [[package]]
413 | name = "pathspec"
414 | version = "0.9.0"
415 | description = "Utility library for gitignore style pattern matching of file paths."
416 | category = "dev"
417 | optional = false
418 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
419 |
420 | [[package]]
421 | name = "platformdirs"
422 | version = "2.3.0"
423 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
424 | category = "dev"
425 | optional = false
426 | python-versions = ">=3.6"
427 |
428 | [package.extras]
429 | docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"]
430 | test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"]
431 |
432 | [[package]]
433 | name = "pluggy"
434 | version = "0.13.1"
435 | description = "plugin and hook calling mechanisms for python"
436 | category = "dev"
437 | optional = false
438 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
439 |
440 | [package.dependencies]
441 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
442 |
443 | [package.extras]
444 | dev = ["pre-commit", "tox"]
445 |
446 | [[package]]
447 | name = "poyo"
448 | version = "0.5.0"
449 | description = "A lightweight YAML Parser for Python. 🐓"
450 | category = "main"
451 | optional = false
452 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
453 |
454 | [[package]]
455 | name = "pre-commit"
456 | version = "2.16.0"
457 | description = "A framework for managing and maintaining multi-language pre-commit hooks."
458 | category = "dev"
459 | optional = false
460 | python-versions = ">=3.6.1"
461 |
462 | [package.dependencies]
463 | cfgv = ">=2.0.0"
464 | identify = ">=1.0.0"
465 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
466 | importlib-resources = {version = "<5.3", markers = "python_version < \"3.7\""}
467 | nodeenv = ">=0.11.1"
468 | pyyaml = ">=5.1"
469 | toml = "*"
470 | virtualenv = ">=20.0.8"
471 |
472 | [[package]]
473 | name = "prompt-toolkit"
474 | version = "3.0.19"
475 | description = "Library for building powerful interactive command lines in Python"
476 | category = "main"
477 | optional = false
478 | python-versions = ">=3.6.1"
479 |
480 | [package.dependencies]
481 | wcwidth = "*"
482 |
483 | [[package]]
484 | name = "py"
485 | version = "1.10.0"
486 | description = "library with cross-python path, ini-parsing, io, code, log facilities"
487 | category = "dev"
488 | optional = false
489 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
490 |
491 | [[package]]
492 | name = "pycodestyle"
493 | version = "2.8.0"
494 | description = "Python style guide checker"
495 | category = "dev"
496 | optional = false
497 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
498 |
499 | [[package]]
500 | name = "pydantic"
501 | version = "1.8.2"
502 | description = "Data validation and settings management using python 3.6 type hinting"
503 | category = "main"
504 | optional = false
505 | python-versions = ">=3.6.1"
506 |
507 | [package.dependencies]
508 | dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""}
509 | email-validator = {version = ">=1.0.3", optional = true, markers = "extra == \"email\""}
510 | typing-extensions = ">=3.7.4.3"
511 |
512 | [package.extras]
513 | dotenv = ["python-dotenv (>=0.10.4)"]
514 | email = ["email-validator (>=1.0.3)"]
515 |
516 | [[package]]
517 | name = "pyflakes"
518 | version = "2.4.0"
519 | description = "passive checker of Python programs"
520 | category = "dev"
521 | optional = false
522 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
523 |
524 | [[package]]
525 | name = "pyparsing"
526 | version = "2.4.7"
527 | description = "Python parsing module"
528 | category = "dev"
529 | optional = false
530 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
531 |
532 | [[package]]
533 | name = "pytest"
534 | version = "6.2.5"
535 | description = "pytest: simple powerful testing with Python"
536 | category = "dev"
537 | optional = false
538 | python-versions = ">=3.6"
539 |
540 | [package.dependencies]
541 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
542 | attrs = ">=19.2.0"
543 | colorama = {version = "*", markers = "sys_platform == \"win32\""}
544 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
545 | iniconfig = "*"
546 | packaging = "*"
547 | pluggy = ">=0.12,<2.0"
548 | py = ">=1.8.2"
549 | toml = "*"
550 |
551 | [package.extras]
552 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
553 |
554 | [[package]]
555 | name = "pytest-cov"
556 | version = "3.0.0"
557 | description = "Pytest plugin for measuring coverage."
558 | category = "dev"
559 | optional = false
560 | python-versions = ">=3.6"
561 |
562 | [package.dependencies]
563 | coverage = {version = ">=5.2.1", extras = ["toml"]}
564 | pytest = ">=4.6"
565 |
566 | [package.extras]
567 | testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"]
568 |
569 | [[package]]
570 | name = "python-dateutil"
571 | version = "2.8.2"
572 | description = "Extensions to the standard Python datetime module"
573 | category = "main"
574 | optional = false
575 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
576 |
577 | [package.dependencies]
578 | six = ">=1.5"
579 |
580 | [[package]]
581 | name = "python-slugify"
582 | version = "5.0.2"
583 | description = "A Python Slugify application that handles Unicode"
584 | category = "main"
585 | optional = false
586 | python-versions = ">=3.6"
587 |
588 | [package.dependencies]
589 | text-unidecode = ">=1.3"
590 |
591 | [package.extras]
592 | unidecode = ["Unidecode (>=1.1.1)"]
593 |
594 | [[package]]
595 | name = "pyyaml"
596 | version = "5.4.1"
597 | description = "YAML parser and emitter for Python"
598 | category = "dev"
599 | optional = false
600 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
601 |
602 | [[package]]
603 | name = "questionary"
604 | version = "1.10.0"
605 | description = "Python library to build pretty command line user prompts ⭐️"
606 | category = "main"
607 | optional = false
608 | python-versions = ">=3.6,<4.0"
609 |
610 | [package.dependencies]
611 | prompt_toolkit = ">=2.0,<4.0"
612 |
613 | [package.extras]
614 | docs = ["Sphinx (>=3.3,<4.0)", "sphinx-rtd-theme (>=0.5.0,<0.6.0)", "sphinx-autobuild (>=2020.9.1,<2021.0.0)", "sphinx-copybutton (>=0.3.1,<0.4.0)", "sphinx-autodoc-typehints (>=1.11.1,<2.0.0)"]
615 |
616 | [[package]]
617 | name = "regex"
618 | version = "2021.8.28"
619 | description = "Alternative regular expression module, to replace re."
620 | category = "dev"
621 | optional = false
622 | python-versions = "*"
623 |
624 | [[package]]
625 | name = "requests"
626 | version = "2.26.0"
627 | description = "Python HTTP for Humans."
628 | category = "main"
629 | optional = false
630 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
631 |
632 | [package.dependencies]
633 | certifi = ">=2017.4.17"
634 | charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""}
635 | idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""}
636 | urllib3 = ">=1.21.1,<1.27"
637 |
638 | [package.extras]
639 | socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
640 | use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
641 |
642 | [[package]]
643 | name = "six"
644 | version = "1.16.0"
645 | description = "Python 2 and 3 compatibility utilities"
646 | category = "main"
647 | optional = false
648 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
649 |
650 | [[package]]
651 | name = "text-unidecode"
652 | version = "1.3"
653 | description = "The most basic Text::Unidecode port"
654 | category = "main"
655 | optional = false
656 | python-versions = "*"
657 |
658 | [[package]]
659 | name = "toml"
660 | version = "0.10.2"
661 | description = "Python Library for Tom's Obvious, Minimal Language"
662 | category = "dev"
663 | optional = false
664 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
665 |
666 | [[package]]
667 | name = "tomli"
668 | version = "1.2.2"
669 | description = "A lil' TOML parser"
670 | category = "dev"
671 | optional = false
672 | python-versions = ">=3.6"
673 |
674 | [[package]]
675 | name = "typed-ast"
676 | version = "1.4.3"
677 | description = "a fork of Python 2 and 3 ast modules with type comment support"
678 | category = "dev"
679 | optional = false
680 | python-versions = "*"
681 |
682 | [[package]]
683 | name = "typer"
684 | version = "0.4.0"
685 | description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
686 | category = "main"
687 | optional = false
688 | python-versions = ">=3.6"
689 |
690 | [package.dependencies]
691 | click = ">=7.1.1,<9.0.0"
692 |
693 | [package.extras]
694 | all = ["colorama (>=0.4.3,<0.5.0)", "shellingham (>=1.3.0,<2.0.0)"]
695 | dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)"]
696 | doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=5.4.0,<6.0.0)", "markdown-include (>=0.5.1,<0.6.0)"]
697 | test = ["shellingham (>=1.3.0,<2.0.0)", "pytest (>=4.4.0,<5.4.0)", "pytest-cov (>=2.10.0,<3.0.0)", "coverage (>=5.2,<6.0)", "pytest-xdist (>=1.32.0,<2.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "mypy (==0.910)", "black (>=19.10b0,<20.0b0)", "isort (>=5.0.6,<6.0.0)"]
698 |
699 | [[package]]
700 | name = "typing-extensions"
701 | version = "3.10.0.2"
702 | description = "Backported and Experimental Type Hints for Python 3.5+"
703 | category = "main"
704 | optional = false
705 | python-versions = "*"
706 |
707 | [[package]]
708 | name = "urllib3"
709 | version = "1.26.6"
710 | description = "HTTP library with thread-safe connection pooling, file post, and more."
711 | category = "main"
712 | optional = false
713 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
714 |
715 | [package.extras]
716 | brotli = ["brotlipy (>=0.6.0)"]
717 | secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
718 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
719 |
720 | [[package]]
721 | name = "virtualenv"
722 | version = "20.7.2"
723 | description = "Virtual Python Environment builder"
724 | category = "dev"
725 | optional = false
726 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
727 |
728 | [package.dependencies]
729 | "backports.entry-points-selectable" = ">=1.0.4"
730 | distlib = ">=0.3.1,<1"
731 | filelock = ">=3.0.0,<4"
732 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
733 | importlib-resources = {version = ">=1.0", markers = "python_version < \"3.7\""}
734 | platformdirs = ">=2,<3"
735 | six = ">=1.9.0,<2"
736 |
737 | [package.extras]
738 | docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"]
739 | testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"]
740 |
741 | [[package]]
742 | name = "wcwidth"
743 | version = "0.2.5"
744 | description = "Measures the displayed width of unicode strings in a terminal"
745 | category = "main"
746 | optional = false
747 | python-versions = "*"
748 |
749 | [[package]]
750 | name = "zipp"
751 | version = "3.5.0"
752 | description = "Backport of pathlib-compatible object wrapper for zip files"
753 | category = "main"
754 | optional = false
755 | python-versions = ">=3.6"
756 |
757 | [package.extras]
758 | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
759 | testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
760 |
761 | [metadata]
762 | lock-version = "1.1"
763 | python-versions = "^3.6.1"
764 | content-hash = "38a90a2c0ecbb4dc455cba579120a318b53157176abb1e3d94cf5d5c7b535249"
765 |
766 | [metadata.files]
767 | appdirs = [
768 | {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
769 | {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
770 | ]
771 | arrow = [
772 | {file = "arrow-1.1.1-py3-none-any.whl", hash = "sha256:77a60a4db5766d900a2085ce9074c5c7b8e2c99afeaa98ad627637ff6f292510"},
773 | {file = "arrow-1.1.1.tar.gz", hash = "sha256:dee7602f6c60e3ec510095b5e301441bc56288cb8f51def14dcb3079f623823a"},
774 | ]
775 | atomicwrites = [
776 | {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
777 | {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
778 | ]
779 | attrs = [
780 | {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"},
781 | {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"},
782 | ]
783 | autoflake = [
784 | {file = "autoflake-1.4.tar.gz", hash = "sha256:61a353012cff6ab94ca062823d1fb2f692c4acda51c76ff83a8d77915fba51ea"},
785 | ]
786 | "backports.entry-points-selectable" = [
787 | {file = "backports.entry_points_selectable-1.1.0-py2.py3-none-any.whl", hash = "sha256:a6d9a871cde5e15b4c4a53e3d43ba890cc6861ec1332c9c2428c92f977192acc"},
788 | {file = "backports.entry_points_selectable-1.1.0.tar.gz", hash = "sha256:988468260ec1c196dab6ae1149260e2f5472c9110334e5d51adcb77867361f6a"},
789 | ]
790 | binaryornot = [
791 | {file = "binaryornot-0.4.4-py2.py3-none-any.whl", hash = "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4"},
792 | {file = "binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061"},
793 | ]
794 | black = [
795 | {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"},
796 | ]
797 | certifi = [
798 | {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"},
799 | {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"},
800 | ]
801 | cfgv = [
802 | {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
803 | {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
804 | ]
805 | chardet = [
806 | {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"},
807 | {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"},
808 | ]
809 | charset-normalizer = [
810 | {file = "charset-normalizer-2.0.4.tar.gz", hash = "sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"},
811 | {file = "charset_normalizer-2.0.4-py3-none-any.whl", hash = "sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b"},
812 | ]
813 | click = [
814 | {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"},
815 | {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"},
816 | ]
817 | colorama = [
818 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
819 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
820 | ]
821 | cookiecutter = [
822 | {file = "cookiecutter-1.7.3-py2.py3-none-any.whl", hash = "sha256:f8671531fa96ab14339d0c59b4f662a4f12a2ecacd94a0f70a3500843da588e2"},
823 | {file = "cookiecutter-1.7.3.tar.gz", hash = "sha256:6b9a4d72882e243be077a7397d0f1f76fe66cf3df91f3115dbb5330e214fa457"},
824 | ]
825 | coverage = [
826 | {file = "coverage-6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6dbc1536e105adda7a6312c778f15aaabe583b0e9a0b0a324990334fd458c94b"},
827 | {file = "coverage-6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:174cf9b4bef0db2e8244f82059a5a72bd47e1d40e71c68ab055425172b16b7d0"},
828 | {file = "coverage-6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:92b8c845527eae547a2a6617d336adc56394050c3ed8a6918683646328fbb6da"},
829 | {file = "coverage-6.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c7912d1526299cb04c88288e148c6c87c0df600eca76efd99d84396cfe00ef1d"},
830 | {file = "coverage-6.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d2033d5db1d58ae2d62f095e1aefb6988af65b4b12cb8987af409587cc0739"},
831 | {file = "coverage-6.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3feac4084291642165c3a0d9eaebedf19ffa505016c4d3db15bfe235718d4971"},
832 | {file = "coverage-6.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:276651978c94a8c5672ea60a2656e95a3cce2a3f31e9fb2d5ebd4c215d095840"},
833 | {file = "coverage-6.2-cp310-cp310-win32.whl", hash = "sha256:f506af4f27def639ba45789fa6fde45f9a217da0be05f8910458e4557eed020c"},
834 | {file = "coverage-6.2-cp310-cp310-win_amd64.whl", hash = "sha256:3f7c17209eef285c86f819ff04a6d4cbee9b33ef05cbcaae4c0b4e8e06b3ec8f"},
835 | {file = "coverage-6.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:13362889b2d46e8d9f97c421539c97c963e34031ab0cb89e8ca83a10cc71ac76"},
836 | {file = "coverage-6.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:22e60a3ca5acba37d1d4a2ee66e051f5b0e1b9ac950b5b0cf4aa5366eda41d47"},
837 | {file = "coverage-6.2-cp311-cp311-win_amd64.whl", hash = "sha256:b637c57fdb8be84e91fac60d9325a66a5981f8086c954ea2772efe28425eaf64"},
838 | {file = "coverage-6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f467bbb837691ab5a8ca359199d3429a11a01e6dfb3d9dcc676dc035ca93c0a9"},
839 | {file = "coverage-6.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2641f803ee9f95b1f387f3e8f3bf28d83d9b69a39e9911e5bfee832bea75240d"},
840 | {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1219d760ccfafc03c0822ae2e06e3b1248a8e6d1a70928966bafc6838d3c9e48"},
841 | {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9a2b5b52be0a8626fcbffd7e689781bf8c2ac01613e77feda93d96184949a98e"},
842 | {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8e2c35a4c1f269704e90888e56f794e2d9c0262fb0c1b1c8c4ee44d9b9e77b5d"},
843 | {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5d6b09c972ce9200264c35a1d53d43ca55ef61836d9ec60f0d44273a31aa9f17"},
844 | {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e3db840a4dee542e37e09f30859f1612da90e1c5239a6a2498c473183a50e781"},
845 | {file = "coverage-6.2-cp36-cp36m-win32.whl", hash = "sha256:4e547122ca2d244f7c090fe3f4b5a5861255ff66b7ab6d98f44a0222aaf8671a"},
846 | {file = "coverage-6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:01774a2c2c729619760320270e42cd9e797427ecfddd32c2a7b639cdc481f3c0"},
847 | {file = "coverage-6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb8b8ee99b3fffe4fd86f4c81b35a6bf7e4462cba019997af2fe679365db0c49"},
848 | {file = "coverage-6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:619346d57c7126ae49ac95b11b0dc8e36c1dd49d148477461bb66c8cf13bb521"},
849 | {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0a7726f74ff63f41e95ed3a89fef002916c828bb5fcae83b505b49d81a066884"},
850 | {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cfd9386c1d6f13b37e05a91a8583e802f8059bebfccde61a418c5808dea6bbfa"},
851 | {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:17e6c11038d4ed6e8af1407d9e89a2904d573be29d51515f14262d7f10ef0a64"},
852 | {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c254b03032d5a06de049ce8bca8338a5185f07fb76600afff3c161e053d88617"},
853 | {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dca38a21e4423f3edb821292e97cec7ad38086f84313462098568baedf4331f8"},
854 | {file = "coverage-6.2-cp37-cp37m-win32.whl", hash = "sha256:600617008aa82032ddeace2535626d1bc212dfff32b43989539deda63b3f36e4"},
855 | {file = "coverage-6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:bf154ba7ee2fd613eb541c2bc03d3d9ac667080a737449d1a3fb342740eb1a74"},
856 | {file = "coverage-6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9afb5b746781fc2abce26193d1c817b7eb0e11459510fba65d2bd77fe161d9e"},
857 | {file = "coverage-6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edcada2e24ed68f019175c2b2af2a8b481d3d084798b8c20d15d34f5c733fa58"},
858 | {file = "coverage-6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a9c8c4283e17690ff1a7427123ffb428ad6a52ed720d550e299e8291e33184dc"},
859 | {file = "coverage-6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f614fc9956d76d8a88a88bb41ddc12709caa755666f580af3a688899721efecd"},
860 | {file = "coverage-6.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9365ed5cce5d0cf2c10afc6add145c5037d3148585b8ae0e77cc1efdd6aa2953"},
861 | {file = "coverage-6.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8bdfe9ff3a4ea37d17f172ac0dff1e1c383aec17a636b9b35906babc9f0f5475"},
862 | {file = "coverage-6.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:63c424e6f5b4ab1cf1e23a43b12f542b0ec2e54f99ec9f11b75382152981df57"},
863 | {file = "coverage-6.2-cp38-cp38-win32.whl", hash = "sha256:49dbff64961bc9bdd2289a2bda6a3a5a331964ba5497f694e2cbd540d656dc1c"},
864 | {file = "coverage-6.2-cp38-cp38-win_amd64.whl", hash = "sha256:9a29311bd6429be317c1f3fe4bc06c4c5ee45e2fa61b2a19d4d1d6111cb94af2"},
865 | {file = "coverage-6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03b20e52b7d31be571c9c06b74746746d4eb82fc260e594dc662ed48145e9efd"},
866 | {file = "coverage-6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:215f8afcc02a24c2d9a10d3790b21054b58d71f4b3c6f055d4bb1b15cecce685"},
867 | {file = "coverage-6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a4bdeb0a52d1d04123b41d90a4390b096f3ef38eee35e11f0b22c2d031222c6c"},
868 | {file = "coverage-6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c332d8f8d448ded473b97fefe4a0983265af21917d8b0cdcb8bb06b2afe632c3"},
869 | {file = "coverage-6.2-cp39-cp39-win32.whl", hash = "sha256:6e1394d24d5938e561fbeaa0cd3d356207579c28bd1792f25a068743f2d5b282"},
870 | {file = "coverage-6.2-cp39-cp39-win_amd64.whl", hash = "sha256:86f2e78b1eff847609b1ca8050c9e1fa3bd44ce755b2ec30e70f2d3ba3844644"},
871 | {file = "coverage-6.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:5829192582c0ec8ca4a2532407bc14c2f338d9878a10442f5d03804a95fac9de"},
872 | {file = "coverage-6.2.tar.gz", hash = "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8"},
873 | ]
874 | dataclasses = [
875 | {file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"},
876 | {file = "dataclasses-0.8.tar.gz", hash = "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"},
877 | ]
878 | distlib = [
879 | {file = "distlib-0.3.2-py2.py3-none-any.whl", hash = "sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c"},
880 | {file = "distlib-0.3.2.zip", hash = "sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736"},
881 | ]
882 | dnspython = [
883 | {file = "dnspython-2.1.0-py3-none-any.whl", hash = "sha256:95d12f6ef0317118d2a1a6fc49aac65ffec7eb8087474158f42f26a639135216"},
884 | {file = "dnspython-2.1.0.zip", hash = "sha256:e4a87f0b573201a0f3727fa18a516b055fd1107e0e5477cded4a2de497df1dd4"},
885 | ]
886 | email-validator = [
887 | {file = "email_validator-1.1.3-py2.py3-none-any.whl", hash = "sha256:5675c8ceb7106a37e40e2698a57c056756bf3f272cfa8682a4f87ebd95d8440b"},
888 | {file = "email_validator-1.1.3.tar.gz", hash = "sha256:aa237a65f6f4da067119b7df3f13e89c25c051327b2b5b66dc075f33d62480d7"},
889 | ]
890 | filelock = [
891 | {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"},
892 | {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"},
893 | ]
894 | flake8 = [
895 | {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"},
896 | {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
897 | ]
898 | identify = [
899 | {file = "identify-2.2.13-py2.py3-none-any.whl", hash = "sha256:7199679b5be13a6b40e6e19ea473e789b11b4e3b60986499b1f589ffb03c217c"},
900 | {file = "identify-2.2.13.tar.gz", hash = "sha256:7bc6e829392bd017236531963d2d937d66fc27cadc643ac0aba2ce9f26157c79"},
901 | ]
902 | idna = [
903 | {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"},
904 | {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"},
905 | ]
906 | importlib-metadata = [
907 | {file = "importlib_metadata-4.2.0-py3-none-any.whl", hash = "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b"},
908 | {file = "importlib_metadata-4.2.0.tar.gz", hash = "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"},
909 | ]
910 | importlib-resources = [
911 | {file = "importlib_resources-5.2.2-py3-none-any.whl", hash = "sha256:2480d8e07d1890056cb53c96e3de44fead9c62f2ba949b0f2e4c4345f4afa977"},
912 | {file = "importlib_resources-5.2.2.tar.gz", hash = "sha256:a65882a4d0fe5fbf702273456ba2ce74fe44892c25e42e057aca526b702a6d4b"},
913 | ]
914 | iniconfig = [
915 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
916 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
917 | ]
918 | isort = [
919 | {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
920 | {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
921 | ]
922 | jinja2 = [
923 | {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"},
924 | {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"},
925 | ]
926 | jinja2-time = [
927 | {file = "jinja2-time-0.2.0.tar.gz", hash = "sha256:d14eaa4d315e7688daa4969f616f226614350c48730bfa1692d2caebd8c90d40"},
928 | {file = "jinja2_time-0.2.0-py2.py3-none-any.whl", hash = "sha256:d3eab6605e3ec8b7a0863df09cc1d23714908fa61aa6986a845c20ba488b4efa"},
929 | ]
930 | markupsafe = [
931 | {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"},
932 | {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"},
933 | {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"},
934 | {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"},
935 | {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"},
936 | {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"},
937 | {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"},
938 | {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"},
939 | {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"},
940 | {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"},
941 | {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"},
942 | {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"},
943 | {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"},
944 | {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"},
945 | {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"},
946 | {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"},
947 | {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"},
948 | {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"},
949 | {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"},
950 | {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"},
951 | {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"},
952 | {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"},
953 | {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"},
954 | {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"},
955 | {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"},
956 | {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"},
957 | {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"},
958 | {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"},
959 | {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"},
960 | {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"},
961 | {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"},
962 | {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"},
963 | {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"},
964 | {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"},
965 | {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"},
966 | {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"},
967 | {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"},
968 | {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"},
969 | {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"},
970 | {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"},
971 | {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"},
972 | {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"},
973 | {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"},
974 | {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"},
975 | {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"},
976 | {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"},
977 | {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"},
978 | {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"},
979 | {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"},
980 | {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"},
981 | {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"},
982 | {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"},
983 | {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"},
984 | {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"},
985 | {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"},
986 | {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"},
987 | {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"},
988 | {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"},
989 | {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"},
990 | {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"},
991 | {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"},
992 | {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"},
993 | {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"},
994 | {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"},
995 | {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"},
996 | {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"},
997 | {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"},
998 | {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"},
999 | {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"},
1000 | ]
1001 | mccabe = [
1002 | {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
1003 | {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
1004 | ]
1005 | mypy = [
1006 | {file = "mypy-0.790-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:bd03b3cf666bff8d710d633d1c56ab7facbdc204d567715cb3b9f85c6e94f669"},
1007 | {file = "mypy-0.790-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:2170492030f6faa537647d29945786d297e4862765f0b4ac5930ff62e300d802"},
1008 | {file = "mypy-0.790-cp35-cp35m-win_amd64.whl", hash = "sha256:e86bdace26c5fe9cf8cb735e7cedfe7850ad92b327ac5d797c656717d2ca66de"},
1009 | {file = "mypy-0.790-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e97e9c13d67fbe524be17e4d8025d51a7dca38f90de2e462243ab8ed8a9178d1"},
1010 | {file = "mypy-0.790-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0d34d6b122597d48a36d6c59e35341f410d4abfa771d96d04ae2c468dd201abc"},
1011 | {file = "mypy-0.790-cp36-cp36m-win_amd64.whl", hash = "sha256:72060bf64f290fb629bd4a67c707a66fd88ca26e413a91384b18db3876e57ed7"},
1012 | {file = "mypy-0.790-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:eea260feb1830a627fb526d22fbb426b750d9f5a47b624e8d5e7e004359b219c"},
1013 | {file = "mypy-0.790-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c614194e01c85bb2e551c421397e49afb2872c88b5830e3554f0519f9fb1c178"},
1014 | {file = "mypy-0.790-cp37-cp37m-win_amd64.whl", hash = "sha256:0a0d102247c16ce93c97066443d11e2d36e6cc2a32d8ccc1f705268970479324"},
1015 | {file = "mypy-0.790-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cf4e7bf7f1214826cf7333627cb2547c0db7e3078723227820d0a2490f117a01"},
1016 | {file = "mypy-0.790-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:af4e9ff1834e565f1baa74ccf7ae2564ae38c8df2a85b057af1dbbc958eb6666"},
1017 | {file = "mypy-0.790-cp38-cp38-win_amd64.whl", hash = "sha256:da56dedcd7cd502ccd3c5dddc656cb36113dd793ad466e894574125945653cea"},
1018 | {file = "mypy-0.790-py3-none-any.whl", hash = "sha256:2842d4fbd1b12ab422346376aad03ff5d0805b706102e475e962370f874a5122"},
1019 | {file = "mypy-0.790.tar.gz", hash = "sha256:2b21ba45ad9ef2e2eb88ce4aeadd0112d0f5026418324176fd494a6824b74975"},
1020 | ]
1021 | mypy-extensions = [
1022 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
1023 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
1024 | ]
1025 | nodeenv = [
1026 | {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"},
1027 | {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"},
1028 | ]
1029 | packaging = [
1030 | {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"},
1031 | {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"},
1032 | ]
1033 | pathspec = [
1034 | {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
1035 | {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
1036 | ]
1037 | platformdirs = [
1038 | {file = "platformdirs-2.3.0-py3-none-any.whl", hash = "sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"},
1039 | {file = "platformdirs-2.3.0.tar.gz", hash = "sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f"},
1040 | ]
1041 | pluggy = [
1042 | {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
1043 | {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
1044 | ]
1045 | poyo = [
1046 | {file = "poyo-0.5.0-py2.py3-none-any.whl", hash = "sha256:3e2ca8e33fdc3c411cd101ca395668395dd5dc7ac775b8e809e3def9f9fe041a"},
1047 | {file = "poyo-0.5.0.tar.gz", hash = "sha256:e26956aa780c45f011ca9886f044590e2d8fd8b61db7b1c1cf4e0869f48ed4dd"},
1048 | ]
1049 | pre-commit = [
1050 | {file = "pre_commit-2.16.0-py2.py3-none-any.whl", hash = "sha256:758d1dc9b62c2ed8881585c254976d66eae0889919ab9b859064fc2fe3c7743e"},
1051 | {file = "pre_commit-2.16.0.tar.gz", hash = "sha256:fe9897cac830aa7164dbd02a4e7b90cae49630451ce88464bca73db486ba9f65"},
1052 | ]
1053 | prompt-toolkit = [
1054 | {file = "prompt_toolkit-3.0.19-py3-none-any.whl", hash = "sha256:7089d8d2938043508aa9420ec18ce0922885304cddae87fb96eebca942299f88"},
1055 | {file = "prompt_toolkit-3.0.19.tar.gz", hash = "sha256:08360ee3a3148bdb5163621709ee322ec34fc4375099afa4bbf751e9b7b7fa4f"},
1056 | ]
1057 | py = [
1058 | {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"},
1059 | {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"},
1060 | ]
1061 | pycodestyle = [
1062 | {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"},
1063 | {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"},
1064 | ]
1065 | pydantic = [
1066 | {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"},
1067 | {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"},
1068 | {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:589eb6cd6361e8ac341db97602eb7f354551482368a37f4fd086c0733548308e"},
1069 | {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:10e5622224245941efc193ad1d159887872776df7a8fd592ed746aa25d071840"},
1070 | {file = "pydantic-1.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99a9fc39470010c45c161a1dc584997f1feb13f689ecf645f59bb4ba623e586b"},
1071 | {file = "pydantic-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a83db7205f60c6a86f2c44a61791d993dff4b73135df1973ecd9eed5ea0bda20"},
1072 | {file = "pydantic-1.8.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:41b542c0b3c42dc17da70554bc6f38cbc30d7066d2c2815a94499b5684582ecb"},
1073 | {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:ea5cb40a3b23b3265f6325727ddfc45141b08ed665458be8c6285e7b85bd73a1"},
1074 | {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:18b5ea242dd3e62dbf89b2b0ec9ba6c7b5abaf6af85b95a97b00279f65845a23"},
1075 | {file = "pydantic-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:234a6c19f1c14e25e362cb05c68afb7f183eb931dd3cd4605eafff055ebbf287"},
1076 | {file = "pydantic-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:021ea0e4133e8c824775a0cfe098677acf6fa5a3cbf9206a376eed3fc09302cd"},
1077 | {file = "pydantic-1.8.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e710876437bc07bd414ff453ac8ec63d219e7690128d925c6e82889d674bb505"},
1078 | {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:ac8eed4ca3bd3aadc58a13c2aa93cd8a884bcf21cb019f8cfecaae3b6ce3746e"},
1079 | {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4a03cbbe743e9c7247ceae6f0d8898f7a64bb65800a45cbdc52d65e370570820"},
1080 | {file = "pydantic-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:8621559dcf5afacf0069ed194278f35c255dc1a1385c28b32dd6c110fd6531b3"},
1081 | {file = "pydantic-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b223557f9510cf0bfd8b01316bf6dd281cf41826607eada99662f5e4963f316"},
1082 | {file = "pydantic-1.8.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:244ad78eeb388a43b0c927e74d3af78008e944074b7d0f4f696ddd5b2af43c62"},
1083 | {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:05ef5246a7ffd2ce12a619cbb29f3307b7c4509307b1b49f456657b43529dc6f"},
1084 | {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:54cd5121383f4a461ff7644c7ca20c0419d58052db70d8791eacbbe31528916b"},
1085 | {file = "pydantic-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:4be75bebf676a5f0f87937c6ddb061fa39cbea067240d98e298508c1bda6f3f3"},
1086 | {file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"},
1087 | {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"},
1088 | ]
1089 | pyflakes = [
1090 | {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"},
1091 | {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"},
1092 | ]
1093 | pyparsing = [
1094 | {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
1095 | {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
1096 | ]
1097 | pytest = [
1098 | {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
1099 | {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
1100 | ]
1101 | pytest-cov = [
1102 | {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"},
1103 | {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"},
1104 | ]
1105 | python-dateutil = [
1106 | {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
1107 | {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
1108 | ]
1109 | python-slugify = [
1110 | {file = "python-slugify-5.0.2.tar.gz", hash = "sha256:f13383a0b9fcbe649a1892b9c8eb4f8eab1d6d84b84bb7a624317afa98159cab"},
1111 | {file = "python_slugify-5.0.2-py2.py3-none-any.whl", hash = "sha256:6d8c5df75cd4a7c3a2d21e257633de53f52ab0265cd2d1dc62a730e8194a7380"},
1112 | ]
1113 | pyyaml = [
1114 | {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"},
1115 | {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"},
1116 | {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"},
1117 | {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"},
1118 | {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"},
1119 | {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"},
1120 | {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"},
1121 | {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"},
1122 | {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"},
1123 | {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"},
1124 | {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"},
1125 | {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"},
1126 | {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"},
1127 | {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"},
1128 | {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"},
1129 | {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"},
1130 | {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"},
1131 | {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"},
1132 | {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"},
1133 | {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"},
1134 | {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"},
1135 | {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"},
1136 | {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"},
1137 | {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"},
1138 | {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"},
1139 | {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"},
1140 | {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"},
1141 | {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"},
1142 | {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"},
1143 | ]
1144 | questionary = [
1145 | {file = "questionary-1.10.0-py3-none-any.whl", hash = "sha256:fecfcc8cca110fda9d561cb83f1e97ecbb93c613ff857f655818839dac74ce90"},
1146 | {file = "questionary-1.10.0.tar.gz", hash = "sha256:600d3aefecce26d48d97eee936fdb66e4bc27f934c3ab6dd1e292c4f43946d90"},
1147 | ]
1148 | regex = [
1149 | {file = "regex-2021.8.28-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9d05ad5367c90814099000442b2125535e9d77581855b9bee8780f1b41f2b1a2"},
1150 | {file = "regex-2021.8.28-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3bf1bc02bc421047bfec3343729c4bbbea42605bcfd6d6bfe2c07ade8b12d2a"},
1151 | {file = "regex-2021.8.28-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f6a808044faae658f546dd5f525e921de9fa409de7a5570865467f03a626fc0"},
1152 | {file = "regex-2021.8.28-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a617593aeacc7a691cc4af4a4410031654f2909053bd8c8e7db837f179a630eb"},
1153 | {file = "regex-2021.8.28-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79aef6b5cd41feff359acaf98e040844613ff5298d0d19c455b3d9ae0bc8c35a"},
1154 | {file = "regex-2021.8.28-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0fc1f8f06977c2d4f5e3d3f0d4a08089be783973fc6b6e278bde01f0544ff308"},
1155 | {file = "regex-2021.8.28-cp310-cp310-win32.whl", hash = "sha256:6eebf512aa90751d5ef6a7c2ac9d60113f32e86e5687326a50d7686e309f66ed"},
1156 | {file = "regex-2021.8.28-cp310-cp310-win_amd64.whl", hash = "sha256:ac88856a8cbccfc14f1b2d0b829af354cc1743cb375e7f04251ae73b2af6adf8"},
1157 | {file = "regex-2021.8.28-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c206587c83e795d417ed3adc8453a791f6d36b67c81416676cad053b4104152c"},
1158 | {file = "regex-2021.8.28-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8690ed94481f219a7a967c118abaf71ccc440f69acd583cab721b90eeedb77c"},
1159 | {file = "regex-2021.8.28-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:328a1fad67445550b982caa2a2a850da5989fd6595e858f02d04636e7f8b0b13"},
1160 | {file = "regex-2021.8.28-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c7cb4c512d2d3b0870e00fbbac2f291d4b4bf2634d59a31176a87afe2777c6f0"},
1161 | {file = "regex-2021.8.28-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66256b6391c057305e5ae9209941ef63c33a476b73772ca967d4a2df70520ec1"},
1162 | {file = "regex-2021.8.28-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8e44769068d33e0ea6ccdf4b84d80c5afffe5207aa4d1881a629cf0ef3ec398f"},
1163 | {file = "regex-2021.8.28-cp36-cp36m-win32.whl", hash = "sha256:08d74bfaa4c7731b8dac0a992c63673a2782758f7cfad34cf9c1b9184f911354"},
1164 | {file = "regex-2021.8.28-cp36-cp36m-win_amd64.whl", hash = "sha256:abb48494d88e8a82601af905143e0de838c776c1241d92021e9256d5515b3645"},
1165 | {file = "regex-2021.8.28-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b4c220a1fe0d2c622493b0a1fd48f8f991998fb447d3cd368033a4b86cf1127a"},
1166 | {file = "regex-2021.8.28-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a332404baa6665b54e5d283b4262f41f2103c255897084ec8f5487ce7b9e8e"},
1167 | {file = "regex-2021.8.28-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c61dcc1cf9fd165127a2853e2c31eb4fb961a4f26b394ac9fe5669c7a6592892"},
1168 | {file = "regex-2021.8.28-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ee329d0387b5b41a5dddbb6243a21cb7896587a651bebb957e2d2bb8b63c0791"},
1169 | {file = "regex-2021.8.28-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f60667673ff9c249709160529ab39667d1ae9fd38634e006bec95611f632e759"},
1170 | {file = "regex-2021.8.28-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b844fb09bd9936ed158ff9df0ab601e2045b316b17aa8b931857365ea8586906"},
1171 | {file = "regex-2021.8.28-cp37-cp37m-win32.whl", hash = "sha256:4cde065ab33bcaab774d84096fae266d9301d1a2f5519d7bd58fc55274afbf7a"},
1172 | {file = "regex-2021.8.28-cp37-cp37m-win_amd64.whl", hash = "sha256:1413b5022ed6ac0d504ba425ef02549a57d0f4276de58e3ab7e82437892704fc"},
1173 | {file = "regex-2021.8.28-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ed4b50355b066796dacdd1cf538f2ce57275d001838f9b132fab80b75e8c84dd"},
1174 | {file = "regex-2021.8.28-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28fc475f560d8f67cc8767b94db4c9440210f6958495aeae70fac8faec631797"},
1175 | {file = "regex-2021.8.28-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdc178caebd0f338d57ae445ef8e9b737ddf8fbc3ea187603f65aec5b041248f"},
1176 | {file = "regex-2021.8.28-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:999ad08220467b6ad4bd3dd34e65329dd5d0df9b31e47106105e407954965256"},
1177 | {file = "regex-2021.8.28-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:808ee5834e06f57978da3e003ad9d6292de69d2bf6263662a1a8ae30788e080b"},
1178 | {file = "regex-2021.8.28-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d5111d4c843d80202e62b4fdbb4920db1dcee4f9366d6b03294f45ed7b18b42e"},
1179 | {file = "regex-2021.8.28-cp38-cp38-win32.whl", hash = "sha256:473858730ef6d6ff7f7d5f19452184cd0caa062a20047f6d6f3e135a4648865d"},
1180 | {file = "regex-2021.8.28-cp38-cp38-win_amd64.whl", hash = "sha256:31a99a4796bf5aefc8351e98507b09e1b09115574f7c9dbb9cf2111f7220d2e2"},
1181 | {file = "regex-2021.8.28-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:04f6b9749e335bb0d2f68c707f23bb1773c3fb6ecd10edf0f04df12a8920d468"},
1182 | {file = "regex-2021.8.28-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b006628fe43aa69259ec04ca258d88ed19b64791693df59c422b607b6ece8bb"},
1183 | {file = "regex-2021.8.28-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:121f4b3185feaade3f85f70294aef3f777199e9b5c0c0245c774ae884b110a2d"},
1184 | {file = "regex-2021.8.28-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a577a21de2ef8059b58f79ff76a4da81c45a75fe0bfb09bc8b7bb4293fa18983"},
1185 | {file = "regex-2021.8.28-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1743345e30917e8c574f273f51679c294effba6ad372db1967852f12c76759d8"},
1186 | {file = "regex-2021.8.28-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e1e8406b895aba6caa63d9fd1b6b1700d7e4825f78ccb1e5260551d168db38ed"},
1187 | {file = "regex-2021.8.28-cp39-cp39-win32.whl", hash = "sha256:ed283ab3a01d8b53de3a05bfdf4473ae24e43caee7dcb5584e86f3f3e5ab4374"},
1188 | {file = "regex-2021.8.28-cp39-cp39-win_amd64.whl", hash = "sha256:610b690b406653c84b7cb6091facb3033500ee81089867ee7d59e675f9ca2b73"},
1189 | {file = "regex-2021.8.28.tar.gz", hash = "sha256:f585cbbeecb35f35609edccb95efd95a3e35824cd7752b586503f7e6087303f1"},
1190 | ]
1191 | requests = [
1192 | {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"},
1193 | {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"},
1194 | ]
1195 | six = [
1196 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
1197 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
1198 | ]
1199 | text-unidecode = [
1200 | {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"},
1201 | {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"},
1202 | ]
1203 | toml = [
1204 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
1205 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
1206 | ]
1207 | tomli = [
1208 | {file = "tomli-1.2.2-py3-none-any.whl", hash = "sha256:f04066f68f5554911363063a30b108d2b5a5b1a010aa8b6132af78489fe3aade"},
1209 | {file = "tomli-1.2.2.tar.gz", hash = "sha256:c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee"},
1210 | ]
1211 | typed-ast = [
1212 | {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"},
1213 | {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"},
1214 | {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"},
1215 | {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"},
1216 | {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"},
1217 | {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"},
1218 | {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"},
1219 | {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"},
1220 | {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"},
1221 | {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"},
1222 | {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"},
1223 | {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"},
1224 | {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"},
1225 | {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"},
1226 | {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"},
1227 | {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"},
1228 | {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"},
1229 | {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"},
1230 | {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"},
1231 | {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"},
1232 | {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"},
1233 | {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"},
1234 | {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"},
1235 | {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"},
1236 | {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"},
1237 | {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"},
1238 | {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"},
1239 | {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"},
1240 | {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"},
1241 | {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"},
1242 | ]
1243 | typer = [
1244 | {file = "typer-0.4.0-py3-none-any.whl", hash = "sha256:d81169725140423d072df464cad1ff25ee154ef381aaf5b8225352ea187ca338"},
1245 | {file = "typer-0.4.0.tar.gz", hash = "sha256:63c3aeab0549750ffe40da79a1b524f60e08a2cbc3126c520ebf2eeaf507f5dd"},
1246 | ]
1247 | typing-extensions = [
1248 | {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"},
1249 | {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"},
1250 | {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"},
1251 | ]
1252 | urllib3 = [
1253 | {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"},
1254 | {file = "urllib3-1.26.6.tar.gz", hash = "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"},
1255 | ]
1256 | virtualenv = [
1257 | {file = "virtualenv-20.7.2-py2.py3-none-any.whl", hash = "sha256:e4670891b3a03eb071748c569a87cceaefbf643c5bac46d996c5a45c34aa0f06"},
1258 | {file = "virtualenv-20.7.2.tar.gz", hash = "sha256:9ef4e8ee4710826e98ff3075c9a4739e2cb1040de6a2a8d35db0055840dc96a0"},
1259 | ]
1260 | wcwidth = [
1261 | {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
1262 | {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
1263 | ]
1264 | zipp = [
1265 | {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"},
1266 | {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"},
1267 | ]
1268 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | authors = [
3 | "ycd ",
4 | "Marcelo Trylesinski ",
5 | ]
6 | description = "Managing FastAPI projects made easy."
7 | homepage = "https://github.com/ycd/manage-fastapi"
8 | license = "MIT"
9 | name = "manage-fastapi"
10 | readme = "README.md"
11 | repository = "https://github.com/ycd/manage-fastapi"
12 | version = "1.1.1"
13 |
14 | classifiers = [
15 | "Topic :: Software Development :: Build Tools",
16 | "Topic :: Software Development :: Libraries :: Python Modules",
17 | "Intended Audience :: Developers",
18 | "License :: OSI Approved :: MIT License",
19 | "Operating System :: OS Independent",
20 | "Programming Language :: Python :: 3",
21 | "Programming Language :: Python",
22 | "Programming Language :: Python :: 3 :: Only",
23 | "Programming Language :: Python :: 3.6",
24 | "Programming Language :: Python :: 3.7",
25 | "Programming Language :: Python :: 3.8",
26 | "Programming Language :: Python :: 3.9",
27 | ]
28 |
29 | [tool.poetry.dependencies]
30 | cookiecutter = "^1.7.2"
31 | pydantic = {extras = ["email"], version = "^1.7.2"}
32 | python = "^3.6.1"
33 | questionary = "^1.10.0"
34 | typer = "^0.4.0"
35 |
36 | [tool.poetry.dev-dependencies]
37 | autoflake = "^1.4"
38 | black = "^20.8b1"
39 | flake8 = "^4.0.1"
40 | isort = "^5.10"
41 | mypy = "^0.790"
42 | pre-commit = "^2.16.0"
43 | pytest = "^6.2"
44 | pytest-cov = "^3.0.0"
45 |
46 | [tool.poetry.scripts]
47 | fastapi = 'manage_fastapi.main:app'
48 |
49 | [build-system]
50 | build-backend = "poetry.masonry.api"
51 | requires = ["poetry>=0.12"]
52 |
--------------------------------------------------------------------------------
/scripts/check_typing.sh:
--------------------------------------------------------------------------------
1 | find manage_fastapi/. -type f -name "*.py" | xargs mypy
2 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [isort]
2 | profile = black
3 | known_first_party = manage_fastapi
4 | skip = */templates/*
5 |
6 | [flake8]
7 | max-complexity = 7
8 | statistics = True
9 | max-line-length = 88
10 | ignore = W503,E203
11 | per-file-ignores =
12 | __init__.py: F401
13 |
14 | [mypy]
15 | plugins = pydantic.mypy
16 | ignore_missing_imports = True
17 | follow_imports = skip
18 | strict_optional = True
19 |
20 | [coverage:run]
21 | omit = */templates/*
22 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BilalAlpaslan/manage-fastapi/5284e941d606e530d9369f85b99f371d25ff630e/tests/__init__.py
--------------------------------------------------------------------------------
/tests/test_startapp.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from typer.testing import CliRunner
4 |
5 | from manage_fastapi.main import app
6 |
7 | runner = CliRunner()
8 |
9 | CREATED_SUCCESSFULLY = "FastAPI app created successfully! 🎉\n"
10 | ALREADY_EXISTS = "Folder 'potato' already exists. 😞\n"
11 |
12 |
13 | def test_startproject_default(tmp_path: Path):
14 | with runner.isolated_filesystem(temp_dir=tmp_path):
15 | result = runner.invoke(app, ["startapp", "potato"])
16 | assert result.output == CREATED_SUCCESSFULLY
17 | assert result.exit_code == 0
18 |
--------------------------------------------------------------------------------
/tests/test_startproject.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 |
3 | from typer.testing import CliRunner
4 |
5 | from manage_fastapi.main import app
6 |
7 | runner = CliRunner()
8 |
9 | CREATED_SUCCESSFULLY = "FastAPI project created successfully! 🎉\n"
10 | ALREADY_EXISTS = "Folder 'potato' already exists. 😞\n"
11 |
12 |
13 | def test_startproject_default(tmp_path: Path):
14 | with runner.isolated_filesystem(temp_dir=tmp_path):
15 | result = runner.invoke(app, ["startproject", "potato"])
16 | assert result.output == CREATED_SUCCESSFULLY
17 | assert result.exit_code == 0
18 |
19 |
20 | def test_startproject_already_exists(tmp_path: Path):
21 | with runner.isolated_filesystem(temp_dir=tmp_path):
22 | result = runner.invoke(app, ["startproject", "potato"])
23 | assert result.output == CREATED_SUCCESSFULLY
24 | assert result.exit_code == 0
25 |
26 | result = runner.invoke(app, ["startproject", "potato"])
27 | assert result.output == ALREADY_EXISTS
28 | assert result.exit_code == 0
29 |
--------------------------------------------------------------------------------