├── .cruft.json ├── .github ├── FUNDING.yml └── workflows │ ├── lint.yml │ └── test.yml ├── .gitignore ├── .isort.cfg ├── ACKNOWLEDGEMENTS.md ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── art ├── logo.png ├── logo.xcf ├── logo_large.png └── logo_large.xcf ├── docs ├── ACKNOWLEDGEMENTS.md ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CODING_STANDARD.md ├── CONTRIBUTING.md ├── art └── index.md ├── github_deploy_key.enc ├── mkdocs.yml ├── poetry.lock ├── preconvert ├── __init__.py ├── converters.py ├── exceptions.py ├── output │ ├── __init__.py │ ├── bson.py │ ├── convert.py │ ├── json.py │ ├── msgpack.py │ └── simplejson.py └── register.py ├── pyproject.toml ├── scripts ├── clean.sh ├── done.sh ├── lint.sh └── test.sh ├── setup.cfg ├── templates └── text.mako ├── test.sh ├── tests ├── __init__.py ├── constants.py └── test_output.py └── update_docs.sh /.cruft.json: -------------------------------------------------------------------------------- 1 | { 2 | "template": "https://github.com/timothycrosley/cookiecutter-python.git", 3 | "commit": "70bd5343b7321f49ee8d699a94481c5a73d4e380", 4 | "context": { 5 | "cookiecutter": { 6 | "full_name": "Timothy Crosley", 7 | "email": "timothy.crosley@gmail.com", 8 | "github_username": "timothycrosley", 9 | "project_name": "preconvert", 10 | "description": "A Library to enable preconversion of any Python type into one that is easily serializable", 11 | "version": "0.0.6", 12 | "_template": "https://github.com/timothycrosley/cookiecutter-python.git" 13 | } 14 | }, 15 | "directory": null 16 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: "timothycrosley" 2 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | python-version: [3.8] 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - name: pip cache 16 | uses: actions/cache@v1 17 | with: 18 | path: ~/.cache/pip 19 | key: lint-pip-${{ hashFiles('**/pyproject.toml') }} 20 | restore-keys: | 21 | lint-pip- 22 | 23 | - name: Set up Python ${{ matrix.python-version }} 24 | uses: actions/setup-python@v1 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | 28 | - name: Install dependencies 29 | run: | 30 | python -m pip install --upgrade pip 31 | python -m pip install --upgrade poetry 32 | poetry install 33 | 34 | - name: Lint 35 | run: ./scripts/lint.sh 36 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | fail-fast: false 10 | matrix: 11 | python-version: [3.6, 3.7, 3.8] 12 | os: [ubuntu-latest, ubuntu-18.04, macos-latest, windows-latest] 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Ubuntu cache 17 | uses: actions/cache@v1 18 | if: startsWith(matrix.os, 'ubuntu') 19 | with: 20 | path: ~/.cache/pip 21 | key: 22 | ${{ matrix.os }}-${{ matrix.python-version }}-${{ hashFiles('**/pyproject.toml') }} 23 | restore-keys: | 24 | ${{ matrix.os }}-${{ matrix.python-version }}- 25 | 26 | - name: macOS cache 27 | uses: actions/cache@v1 28 | if: startsWith(matrix.os, 'macOS') 29 | with: 30 | path: ~/Library/Caches/pip 31 | key: 32 | ${{ matrix.os }}-${{ matrix.python-version }}-${{ hashFiles('**/pyproject.toml') }} 33 | restore-keys: | 34 | ${{ matrix.os }}-${{ matrix.python-version }}- 35 | 36 | - name: Windows cache 37 | uses: actions/cache@v1 38 | if: startsWith(matrix.os, 'windows') 39 | with: 40 | path: c:\users\runneradmin\appdata\local\pip\cache 41 | key: 42 | ${{ matrix.os }}-${{ matrix.python-version }}-${{ hashFiles('**/pyproject.toml') }} 43 | restore-keys: | 44 | ${{ matrix.os }}-${{ matrix.python-version }}- 45 | 46 | - name: Set up Python ${{ matrix.python-version }} 47 | uses: actions/setup-python@v1 48 | with: 49 | python-version: ${{ matrix.python-version }} 50 | 51 | - name: Install dependencies 52 | run: | 53 | python -m pip install --upgrade pip 54 | python -m pip install --upgrade poetry 55 | poetry install 56 | - name: Test 57 | shell: bash 58 | run: | 59 | poetry run pytest tests/ -s --cov=preconvert/ --cov-report=term-missing ${@-} 60 | poetry run coverage xml 61 | - name: Report Coverage 62 | if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.8' 63 | uses: codecov/codecov-action@v1.0.6 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | .DS_Store 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | build 10 | eggs 11 | .eggs 12 | parts 13 | var 14 | sdist 15 | develop-eggs 16 | .installed.cfg 17 | lib 18 | lib64 19 | MANIFEST 20 | 21 | # Installer logs 22 | pip-log.txt 23 | npm-debug.log 24 | pip-selfcheck.json 25 | 26 | # Unit test / coverage reports 27 | .coverage 28 | .tox 29 | nosetests.xml 30 | htmlcov 31 | .cache 32 | .pytest_cache 33 | .mypy_cache 34 | 35 | # Translations 36 | *.mo 37 | 38 | # Mr Developer 39 | .mr.developer.cfg 40 | .project 41 | .pydevproject 42 | 43 | # SQLite 44 | test_exp_framework 45 | 46 | # npm 47 | node_modules/ 48 | 49 | # dolphin 50 | .directory 51 | libpeerconnection.log 52 | 53 | # setuptools 54 | dist 55 | 56 | # IDE Files 57 | atlassian-ide-plugin.xml 58 | .idea/ 59 | *.swp 60 | *.kate-swp 61 | .ropeproject/ 62 | 63 | # Python3 Venv Files 64 | .venv/ 65 | bin/ 66 | include/ 67 | lib/ 68 | lib64 69 | pyvenv.cfg 70 | share/ 71 | venv/ 72 | .python-version 73 | 74 | # Cython 75 | *.c 76 | 77 | # Emacs backup 78 | *~ 79 | 80 | # VSCode 81 | /.vscode 82 | 83 | # Automatically generated files 84 | docs/preconvert 85 | site/ 86 | out 87 | -------------------------------------------------------------------------------- /.isort.cfg: -------------------------------------------------------------------------------- 1 | [settings] 2 | multi_line_output=3 3 | include_trailing_comma=True 4 | force_grid_wrap=0 5 | use_parentheses=True 6 | line_length=100 7 | -------------------------------------------------------------------------------- /ACKNOWLEDGEMENTS.md: -------------------------------------------------------------------------------- 1 | Contributors 2 | =================== 3 | 4 | ## Core Developers 5 | - Timothy Edmund Crosley (@timothycrosley) 6 | 7 | ## Notable Bug Reporters 8 | - 9 | 10 | ## Code Contributors 11 | - 12 | 13 | ## Documenters 14 | - 15 | 16 | -------------------------------------------- 17 | 18 | A sincere thanks to everyone who helps make preconvert into a great Python3 project! 19 | 20 | ~Timothy Crosley 21 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Install the latest 2 | =================== 3 | 4 | To install the latest version of preconvert simply run: 5 | 6 | ```bash 7 | pip3 install preconvert --upgrade 8 | ``` 9 | 10 | Ideally, within a virtual environment. 11 | 12 | Changelog 13 | ========= 14 | ### 1.0.0 - TBD 15 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing to preconvert 2 | ======== 3 | 4 | Looking for a useful open source project to contribute to? 5 | Want your contributions to be warmly welcomed and acknowledged? 6 | Welcome! You have found the right place. 7 | 8 | ## Getting preconvert set up for local development 9 | The first step when contributing to any project is getting it set up on your local machine. preconvert aims to make this as simple as possible. 10 | 11 | Account Requirements: 12 | 13 | - [A valid GitHub account](https://github.com/join) 14 | 15 | Base System Requirements: 16 | 17 | - Python3.5+ 18 | - pipenv 19 | - bash or a bash compatible shell (should be auto-installed on Linux / Mac) 20 | 21 | Once you have verified that you system matches the base requirements you can start to get the project working by following these steps: 22 | 23 | 1. [Fork the project on GitHub](https://github.com/timothycrosley/preconvert/fork). 24 | 2. Clone your fork to your local file system: 25 | `git clone https://github.com/$GITHUB_ACCOUNT/preconvert.git` 26 | 3. `cd preconvert 27 | 4. `pipenv sync` 28 | 29 | Install preconvert itself with `pip install .` or `pip install -e .` (for editable mode). 30 | 31 | ## Making a contribution 32 | Congrats! You're now ready to make a contribution! Use the following as a guide to help you reach a successful pull-request: 33 | 34 | 1. Check the [issues page](https://github.com/timothycrosley/preconvert/issues) on GitHub to see if the task you want to complete is listed there. 35 | - If it's listed there, write a comment letting others know you are working on it. 36 | - If it's not listed in GitHub issues, go ahead and log a new issue. Then add a comment letting everyone know you have it under control. 37 | - If you're not sure if it's something that is good for the main preconvert project and want immediate feedback, you can discuss it [here](https://gitter.im/timothycrosley/preconvert). 38 | 2. Create an issue branch for your local work `git checkout -b issue/$ISSUE-NUMBER`. 39 | 3. Do your magic here. 40 | 4. Ensure your code matches the [HOPE-8 Coding Standard](https://github.com/hugapi/HOPE/blob/master/all/HOPE-8--Style-Guide-for-Hug-Code.md#hope-8----style-guide-for-hug-code) used by the project. 41 | 5. Submit a pull request to the main project repository via GitHub. 42 | 43 | Thanks for the contribution! It will quickly get reviewed, and, once accepted, will result in your name being added to the ACKNOWLEDGEMENTS.md list :). 44 | 45 | ## Thank you! 46 | I can not tell you how thankful I am for the hard work done by preconvert contributors like *you*. 47 | 48 | Thank you! 49 | 50 | ~Timothy Crosley 51 | 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Timothy Crosley 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 | [![preconvert - Supercharge Your Serializers](https://raw.github.com/timothycrosley/preconvert/main/art/logo_large.png)](https://timothycrosley.github.io/preconvert/) 2 | =================== 3 | 4 | [![PyPI version](https://badge.fury.io/py/preconvert.svg)](http://badge.fury.io/py/preconvert) 5 | [![Test Status](https://github.com/timothycrosley/preconvert/workflows/Test/badge.svg?branch=main)](https://github.com/timothycrosley/preconvert/actions?query=workflow%3ATest) 6 | [![Lint Status](https://github.com/timothycrosley/preconvert/workflows/Lint/badge.svg?branch=main)](https://github.com/timothycrosley/preconvert/actions?query=workflow%3ALint) 7 | [![codecov](https://codecov.io/gh/timothycrosley/preconvert/branch/main/graph/badge.svg)](https://codecov.io/gh/timothycrosley/preconvert) 8 | [![Gitter](https://badges.gitter.im/preconvert/community.svg)](https://gitter.im/preconvert/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 9 | [![License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://pypi.python.org/pypi/hug/) 10 | [![Downloads](https://pepy.tech/badge/preconvert)](https://pepy.tech/project/preconvert) 11 | 12 | _________________ 13 | 14 | [Read Latest Documentation](https://timothycrosley.github.io/preconvert/) - [Browse GitHub Code Repository](https://github.com/timothycrosley/preconvert/) 15 | _________________ 16 | 17 | Preconvert is a library that extends existing serializiers (json, simplejson, bson, msgpack, ..) to be capable of converting *all* the types you use. 18 | It accomplishes this by efficiently preconverting just the types the serializers aren't aware of (things like dataclasses and namedtuples) into basic built-in types that all 19 | serializers can understand. It then provides a mechanism for you to build custom preconverters, and preconvert_plugins that automatically take effect when installed via pip. 20 | 21 | ## Quickstart 22 | 23 | 1. Install preconvert using pip: 24 | 25 | pip3 install preconvert 26 | 27 | 2. Replace existing json (or other serialization library) with preconvert equivalent: 28 | 29 | from preconvert.output import simplejson as json 30 | 31 | ... 32 | 33 | json.dumps(MY_COMPLEX_OBJECT_WITH_DATA_CLASSSES) 34 | 35 | 3. If required, define preconverters for any custom types, even if they aren't under your control: 36 | 37 | import numpy 38 | from preconvert import json 39 | 40 | 41 | class Employee: 42 | 43 | def __init__(self, first_name, last_name): 44 | self.first_name = first_name 45 | self.last_name = last_name 46 | 47 | def __preconvert__(self): 48 | return {'name': {'first': self.first_name, 'last': self.last_name}} 49 | 50 | 51 | @preconvert.always(numpy.integer) 52 | def numpy_integer_to_python_int(numpy_int): 53 | return int(numpy_int) 54 | 55 | 56 | json.dumps({ 57 | 'employee': Employee('Timothy', 'Crosley'), 58 | 'height_inches': numpy.int_(73) 59 | }) 60 | 61 | 4. Enjoy a more comprehensive and configurable serializer! 62 | 63 | **NOTE:** We use NumPy integers as an example above. 64 | However, you can get this functionality for free simply by installing the [preconvert_numpy extension](https://github.com/timothycrosley/preconvert_numpy): `pip install preconvert_numpy`. 65 | Once you do this any call to `preconvert.output.(json|msgpack|bson|simplejson).dumps` will automatically convert these NumPy objects to the appropriate type for you. 66 | 67 | ## Why? 68 | 69 | Have you ever tried to `json.dumps` a data structure, only to be surprised when your DataClass throws an exception, or your namedtuple outputs as a list? 70 | Preconvert was created to solve this problem across common serialization formats. 71 | 72 | 73 | Before preconvert: 74 | 75 | ```python 76 | import sys 77 | import json 78 | from dataclasses import dataclass 79 | 80 | 81 | @dataclass 82 | class InventoryItem: 83 | """Class for keeping track of an item in inventory.""" 84 | name: str 85 | unit_price: float 86 | quantity_on_hand: int = 0 87 | 88 | def total_cost(self) -> float: 89 | return self.unit_price * self.quantity_on_hand 90 | 91 | 92 | my_store_inventory = [InventoryItem("beer", unit_price=0.0, quantity_on_hand=sys.maxsize), InventoryItem("bacon", unit_price=2.5, quantity_on_hand=3)] 93 | json.dumps(my_store_inventory) 94 | 95 | output >>> 96 | 97 | 177 98 | 178 99 | --> 179 raise TypeError(f'Object of type {o.__class__.__name__} ' 100 | 180 f'is not JSON serializable') 101 | 181 102 | 103 | TypeError: Object of type InventoryItem is not JSON serializable 104 | 105 | D: 106 | ``` 107 | 108 | After preconvert: 109 | 110 | ```python 111 | import sys 112 | import json 113 | from preconvert.output import json 114 | 115 | 116 | @dataclass 117 | class InventoryItem: 118 | """Class for keeping track of an item in inventory.""" 119 | name: str 120 | unit_price: float 121 | quantity_on_hand: int = 0 122 | 123 | def total_cost(self) -> float: 124 | return self.unit_price * self.quantity_on_hand 125 | 126 | 127 | my_store_inventory = [ 128 | InventoryItem("beer", unit_price=0.0, quantity_on_hand=sys.maxsize), 129 | InventoryItem("bacon", unit_price=2.5, quantity_on_hand=3) 130 | ] 131 | json.dumps(my_store_inventory) 132 | 133 | >>> [ 134 | { 135 | "name": "beer", 136 | "unit_price": 0.0, 137 | "quantity_on_hand": 9223372036854775807 138 | }, 139 | { 140 | "name": "bacon", 141 | "unit_price": 2.5, 142 | "quantity_on_hand": 3 143 | } 144 | ] 145 | 146 | :D 147 | ``` 148 | 149 | ## What Type Conversions are Included? 150 | 151 | preconvert aims to include preconverters for all the common standard library types that lead to serialization exceptions. 152 | Currently, the following types are handled out of the box when outputting via `preconvert.output.(json|msgpack|bson|simplejson).dumps`: 153 | 154 | - `dataclasses` 155 | - `datetime.datetime` 156 | - `datetime.date` 157 | - `datetime.timedelta` 158 | - `bytes` 159 | - `Collection` 160 | - `GeneratorType` 161 | - `Mapping` 162 | - `Decimal` 163 | - `Enum` 164 | - `NamedTuple` 165 | 166 | See: [`preconvert.converters`](https://timothycrosley.github.io/preconvert/preconvert/converters/) for a complete and up-to-date reference. 167 | 168 | Additionally, plugins can be built for any set of objects that are commonly used, but extend beyond the stdlib: 169 | 170 | 171 | | Object Collections | Plugin | 172 | | ------------------------------------------| -------------------------------------------------------------------------| 173 | | [NumPy](https://www.numpy.org/) | [preconvert_numpy](https://github.com/timothycrosley/preconvert_numpy) | 174 | 175 | Once a plugin is installed via pip its conversions will automatically take place when `preconvert.output.(json|msgpack|bson|simplejson).dumps` is called. 176 | 177 | ## Design goals: 178 | 179 | - Easy utilization from existing projects 180 | - Enable conversion from complex to simple types independant of desired output format 181 | - Provide built in conversion for common types that are not universally supported (dataclasses, namedtuple, etc...) 182 | - Provide a way to build custom preconverts or override built-in preconverts 183 | - Ability to build preconverts that are dependent on the destination format 184 | - Minimal overhead when utilized with common serialization formats 185 | 186 | ## How do I use this? 187 | 188 | If your project uses one of our built-in supported serializers (json, msgpak, bson) 189 | you can simply replace your existing serializer import with a preconvert one: 190 | 191 | `from preconvert.outputs import json` 192 | 193 | OR 194 | 195 | `from preconvert.outputs import simplejson as json` 196 | 197 | OR 198 | 199 | `from preconvert.outputs import msgpack` 200 | 201 | OR 202 | 203 | `from preconvert.outputs import bson` 204 | 205 | If not you can inject preconvert before usage of any other serializers, often by setting a `default` or `on_onknown` parameter: 206 | 207 | ``` 208 | import preconvert 209 | import my_serializer 210 | 211 | my_serializer.dumps(default=preconvert.default_serializable) 212 | ``` 213 | 214 | ## How do I extend this? 215 | 216 | Want to add preconversion to your own custom types? For OOP projects, one easy way to do this is to add a `__preconvert__` method to your object: 217 | 218 | ```python 219 | class MyCustomClass(object): 220 | def __init__(self, first_name, children=()): 221 | self.first_name = first_name 222 | self.children = children 223 | 224 | def __preconvert__(self): 225 | return {'first': self.first_name, 'children': children} 226 | ``` 227 | 228 | For other entities, such as objects you do not control, you can register a new preconvert using the `preconvert.always` decorator: 229 | 230 | ```python 231 | import preconvert 232 | 233 | 234 | @preconvert.always(SomeFrameworkObject) 235 | def convert_framework_object(instance): 236 | return {'name': instance.name} 237 | ``` 238 | 239 | You can also, optionally, specify preconversions per an intended serialization format: 240 | 241 | ```python 242 | import preconvert 243 | 244 | 245 | @preconvert.json(SomeFrameworkObject) 246 | def convert_framework_object(instance): 247 | return {'json': {'name': instance.name}} 248 | 249 | 250 | @preconvert.msgpack(SomeFrameworkObject) 251 | def convert_framework_object(instance): 252 | return ['name', instance.name] 253 | ``` 254 | 255 | Finally, you can resister any modules that contain preconverters to package 'preconvert.converters' entrypoints, and they will take effect automatically as long as the package that contains them is installed. 256 | See the [preconvert_numpy](https://github.com/timothycrosley/preconvert_numpy/blob/main/pyproject.toml#L28) for an example of how this works. 257 | -------------------------------------------------------------------------------- /art/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timothycrosley/preconvert/828a35998908162695543ae7781b0527485cda77/art/logo.png -------------------------------------------------------------------------------- /art/logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timothycrosley/preconvert/828a35998908162695543ae7781b0527485cda77/art/logo.xcf -------------------------------------------------------------------------------- /art/logo_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timothycrosley/preconvert/828a35998908162695543ae7781b0527485cda77/art/logo_large.png -------------------------------------------------------------------------------- /art/logo_large.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timothycrosley/preconvert/828a35998908162695543ae7781b0527485cda77/art/logo_large.xcf -------------------------------------------------------------------------------- /docs/ACKNOWLEDGEMENTS.md: -------------------------------------------------------------------------------- 1 | ../ACKNOWLEDGEMENTS.md -------------------------------------------------------------------------------- /docs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ../CHANGELOG.md -------------------------------------------------------------------------------- /docs/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # HOPE 11 -- Code of Conduct 2 | 3 | | | | 4 | | ------------| ------------------------------------------- | 5 | | HOPE: | 11 | 6 | | Title: | Code of Conduct | 7 | | Author(s): | Timothy Crosley | 8 | | Status: | Active | 9 | | Type: | Process | 10 | | Created: | 17-August-2019 | 11 | | Updated: | 17-August-2019 | 12 | 13 | ## Abstract 14 | 15 | Defines the Code of Conduct for Hug and all related projects. 16 | 17 | ## Our Pledge 18 | 19 | In the interest of fostering an open and welcoming environment, we as 20 | contributors and maintainers pledge to making participation in our project and 21 | our community a harassment-free experience for everyone, regardless of age, body 22 | size, disability, ethnicity, sex characteristics, gender identity and expression, 23 | level of experience, education, socio-economic status, nationality, personal 24 | appearance, race, religion, or sexual identity and orientation. 25 | 26 | ## Our Standards 27 | 28 | Examples of behavior that contributes to creating a positive environment 29 | include: 30 | 31 | * Using welcoming and inclusive language 32 | * Being respectful of differing viewpoints and experiences 33 | * Gracefully accepting constructive criticism 34 | * Focusing on what is best for the community 35 | * Showing empathy towards other community members 36 | 37 | Examples of unacceptable behavior by participants include: 38 | 39 | * The use of sexualized language or imagery and unwelcome sexual attention or 40 | advances 41 | * Trolling, insulting/derogatory comments, and personal or political attacks 42 | * Public or private harassment 43 | * Publishing others' private information, such as a physical or electronic 44 | address, without explicit permission 45 | * Other conduct which could reasonably be considered inappropriate in a 46 | professional setting 47 | 48 | ## Our Responsibilities 49 | 50 | Project maintainers are responsible for clarifying the standards of acceptable 51 | behavior and are expected to take appropriate and fair corrective action in 52 | response to any instances of unacceptable behavior. 53 | 54 | Project maintainers have the right and responsibility to remove, edit, or 55 | reject comments, commits, code, wiki edits, issues, and other contributions 56 | that are not aligned to this Code of Conduct, or to ban temporarily or 57 | permanently any contributor for other behaviors that they deem inappropriate, 58 | threatening, offensive, or harmful. 59 | 60 | ## Scope 61 | 62 | This Code of Conduct applies both within project spaces and in public spaces 63 | when an individual is representing the project or its community. Examples of 64 | representing a project or community include using an official project e-mail 65 | address, posting via an official social media account, or acting as an appointed 66 | representative at an online or offline event. Representation of a project may be 67 | further defined and clarified by project maintainers. 68 | 69 | ## Enforcement 70 | 71 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 72 | reported by contacting [timothy.crosley@gmail.com](mailto:timothy.crosley@gmail.com). All 73 | complaints will be reviewed and investigated and will result in a response that 74 | is deemed necessary and appropriate to the circumstances. Confidentiality will be maintained 75 | with regard to the reporter of an incident. 76 | Further details of specific enforcement policies may be posted separately. 77 | 78 | Project maintainers who do not follow or enforce the Code of Conduct in good 79 | faith may face temporary or permanent repercussions as determined by other 80 | members of the project's leadership. 81 | 82 | ## Attribution 83 | 84 | This Code of Conduct is adapted from the [Contributor Covenant][https://www.contributor-covenant.org], version 1.4, 85 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 86 | 87 | For answers to common questions about this code of conduct, see 88 | https://www.contributor-covenant.org/faq 89 | -------------------------------------------------------------------------------- /docs/CODING_STANDARD.md: -------------------------------------------------------------------------------- 1 | # HOPE 8 -- Style Guide for Hug Code 2 | 3 | | | | 4 | | ------------| ------------------------------------------- | 5 | | HOPE: | 8 | 6 | | Title: | Style Guide for Hug Code | 7 | | Author(s): | Timothy Crosley | 8 | | Status: | Active | 9 | | Type: | Process | 10 | | Created: | 19-May-2019 | 11 | | Updated: | 17-August-2019 | 12 | 13 | ## Introduction 14 | 15 | This document gives coding conventions for the Hug code comprising the Hug core as well as all official interfaces, extensions, and plugins for the framework. 16 | Optionally, projects that use Hug are encouraged to follow this HOPE and link to it as a reference. 17 | 18 | ## PEP 8 Foundation 19 | 20 | All guidelines in this document are in addition to those defined in Python's [PEP 8](https://www.python.org/dev/peps/pep-0008/) and [PEP 257](https://www.python.org/dev/peps/pep-0257/) guidelines. 21 | 22 | ## Line Length 23 | 24 | Too short of lines discourage descriptive variable names where they otherwise make sense. 25 | Too long of lines reduce overall readability and make it hard to compare 2 files side by side. 26 | There is no perfect number: but for Hug, we've decided to cap the lines at 100 characters. 27 | 28 | ## Descriptive Variable names 29 | 30 | Naming things is hard. Hug has a few strict guidelines on the usage of variable names, which hopefully will reduce some of the guesswork: 31 | - No one character variable names. 32 | - Except for x, y, and z as coordinates. 33 | - It's not okay to override built-in functions. 34 | - Except for `id`. Guido himself thought that shouldn't have been moved to the system module. It's too commonly used, and alternatives feel very artificial. 35 | - Avoid Acronyms, Abbreviations, or any other short forms - unless they are almost universally understand. 36 | 37 | ## Adding new modules 38 | 39 | New modules added to the a project that follows the HOPE-8 standard should all live directly within the base `PROJECT_NAME/` directory without nesting. If the modules are meant only for internal use within the project, they should be prefixed with a leading underscore. For example, def _internal_function. Modules should contain a docstring at the top that gives a general explanation of the purpose and then restates the project's use of the MIT license. 40 | There should be a `tests/test_$MODULE_NAME.py` file created to correspond to every new module that contains test coverage for the module. Ideally, tests should be 1:1 (one test object per code object, one test method per code method) to the extent cleanly possible. 41 | 42 | ## Automated Code Cleaners 43 | 44 | All code submitted to Hug should be formatted using Black and isort. 45 | Black should be run with the line length set to 100, and isort with Black compatible settings in place. 46 | 47 | ## Automated Code Linting 48 | 49 | All code submitted to hug should run through the following tools: 50 | 51 | - Black and isort verification. 52 | - Flake8 53 | - flake8-bugbear 54 | - Bandit 55 | - pep8-naming 56 | - vulture 57 | - safety 58 | -------------------------------------------------------------------------------- /docs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ../CONTRIBUTING.md -------------------------------------------------------------------------------- /docs/art: -------------------------------------------------------------------------------- 1 | ../art/ -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /github_deploy_key.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timothycrosley/preconvert/828a35998908162695543ae7781b0527485cda77/github_deploy_key.enc -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: preconvert 2 | theme: 3 | name: 'material' 4 | palette: 5 | primary: 'green' 6 | accent: 'lightgreen' 7 | logo: 'art/logo.png' 8 | favicon: 'art/logo.png' 9 | 10 | repo_name: timothycrosley/preconvert 11 | repo_url: https://github.com/timothycrosley/preconvert 12 | nav: 13 | - preconvert: index.md 14 | - Changelog: CHANGELOG.md 15 | - Reference: 16 | - Preconvert: 'preconvert/index.md' 17 | - Register: 'preconvert/register.md' 18 | - Converters: 'preconvert/converters.md' 19 | - Exceptions: 'preconvert/exceptions.md' 20 | - Output: 'preconvert/output/index.md' 21 | - 'Output - JSON': 'preconvert/output/json.md' 22 | - 'Output - SimpleJSON': 'preconvert/output/simplejson.md' 23 | - 'Output - MsgPack': 'preconvert/output/msgpack.md' 24 | - 'Output - BSON': 'preconvert/output/bson.md' 25 | - 'Output - Convert': 'preconvert/output/convert.md' 26 | - Contributing: 27 | - 'Contributing Guide': 'CONTRIBUTING.md' 28 | - 'Coding Standard': 'CODING_STANDARD.md' 29 | - 'Code of Conduct': 'CODE_OF_CONDUCT.md' 30 | - 'Acknowledgements': 'ACKNOWLEDGEMENTS.md' 31 | 32 | markdown_extensions: 33 | - admonition 34 | - codehilite 35 | - extra 36 | -------------------------------------------------------------------------------- /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 = "0.17.0" 12 | description = "Better dates & times for Python" 13 | category = "dev" 14 | optional = false 15 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 16 | 17 | [package.dependencies] 18 | python-dateutil = ">=2.7.0" 19 | 20 | [[package]] 21 | name = "atomicwrites" 22 | version = "1.4.0" 23 | description = "Atomic file writes." 24 | category = "dev" 25 | optional = false 26 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 27 | 28 | [[package]] 29 | name = "attrs" 30 | version = "20.3.0" 31 | description = "Classes Without Boilerplate" 32 | category = "dev" 33 | optional = false 34 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 35 | 36 | [package.extras] 37 | dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] 38 | docs = ["furo", "sphinx", "zope.interface"] 39 | tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] 40 | tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] 41 | 42 | [[package]] 43 | name = "bandit" 44 | version = "1.7.0" 45 | description = "Security oriented static analyser for python code." 46 | category = "dev" 47 | optional = false 48 | python-versions = ">=3.5" 49 | 50 | [package.dependencies] 51 | colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} 52 | GitPython = ">=1.0.1" 53 | PyYAML = ">=5.3.1" 54 | six = ">=1.10.0" 55 | stevedore = ">=1.20.0" 56 | 57 | [[package]] 58 | name = "binaryornot" 59 | version = "0.4.4" 60 | description = "Ultra-lightweight pure Python package to check if a file is binary or text." 61 | category = "dev" 62 | optional = false 63 | python-versions = "*" 64 | 65 | [package.dependencies] 66 | chardet = ">=3.0.2" 67 | 68 | [[package]] 69 | name = "black" 70 | version = "20.8b1" 71 | description = "The uncompromising code formatter." 72 | category = "dev" 73 | optional = false 74 | python-versions = ">=3.6" 75 | 76 | [package.dependencies] 77 | appdirs = "*" 78 | click = ">=7.1.2" 79 | dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""} 80 | mypy-extensions = ">=0.4.3" 81 | pathspec = ">=0.6,<1" 82 | regex = ">=2020.1.8" 83 | toml = ">=0.10.1" 84 | typed-ast = ">=1.4.0" 85 | typing-extensions = ">=3.7.4" 86 | 87 | [package.extras] 88 | colorama = ["colorama (>=0.4.3)"] 89 | d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] 90 | 91 | [[package]] 92 | name = "bson" 93 | version = "0.5.10" 94 | description = "BSON codec for Python" 95 | category = "dev" 96 | optional = false 97 | python-versions = "*" 98 | 99 | [package.dependencies] 100 | python-dateutil = ">=2.4.0" 101 | six = ">=1.9.0" 102 | 103 | [[package]] 104 | name = "certifi" 105 | version = "2020.12.5" 106 | description = "Python package for providing Mozilla's CA Bundle." 107 | category = "dev" 108 | optional = false 109 | python-versions = "*" 110 | 111 | [[package]] 112 | name = "chardet" 113 | version = "4.0.0" 114 | description = "Universal encoding detector for Python 2 and 3" 115 | category = "dev" 116 | optional = false 117 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 118 | 119 | [[package]] 120 | name = "click" 121 | version = "7.1.2" 122 | description = "Composable command line interface toolkit" 123 | category = "dev" 124 | optional = false 125 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 126 | 127 | [[package]] 128 | name = "colorama" 129 | version = "0.4.4" 130 | description = "Cross-platform colored terminal text." 131 | category = "dev" 132 | optional = false 133 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 134 | 135 | [[package]] 136 | name = "cookiecutter" 137 | version = "1.7.2" 138 | description = "A command-line utility that creates projects from project templates, e.g. creating a Python package project from a Python package project template." 139 | category = "dev" 140 | optional = false 141 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 142 | 143 | [package.dependencies] 144 | binaryornot = ">=0.4.4" 145 | click = ">=7.0" 146 | Jinja2 = "<3.0.0" 147 | jinja2-time = ">=0.2.0" 148 | MarkupSafe = "<2.0.0" 149 | poyo = ">=0.5.0" 150 | python-slugify = ">=4.0.0" 151 | requests = ">=2.23.0" 152 | six = ">=1.10" 153 | 154 | [[package]] 155 | name = "coverage" 156 | version = "5.3.1" 157 | description = "Code coverage measurement for Python" 158 | category = "dev" 159 | optional = false 160 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" 161 | 162 | [package.extras] 163 | toml = ["toml"] 164 | 165 | [[package]] 166 | name = "cruft" 167 | version = "2.6.0" 168 | description = "Allows you to maintain all the necessary cruft for packaging and building projects separate from the code you intentionally write. Built on-top of CookieCutter." 169 | category = "dev" 170 | optional = false 171 | python-versions = ">=3.6,<4.0" 172 | 173 | [package.dependencies] 174 | click = ">=7.1.2,<8.0.0" 175 | cookiecutter = ">=1.6,<2.0" 176 | gitpython = ">=3.0,<4.0" 177 | typer = ">=0.3.1,<0.4.0" 178 | 179 | [package.extras] 180 | pyproject = ["toml (>=0.10,<0.11)"] 181 | examples = ["examples (>=1.0.2,<2.0.0)"] 182 | 183 | [[package]] 184 | name = "dataclasses" 185 | version = "0.8" 186 | description = "A backport of the dataclasses module for Python 3.6" 187 | category = "dev" 188 | optional = false 189 | python-versions = ">=3.6, <3.7" 190 | 191 | [[package]] 192 | name = "dparse" 193 | version = "0.5.1" 194 | description = "A parser for Python dependency files" 195 | category = "dev" 196 | optional = false 197 | python-versions = ">=3.5" 198 | 199 | [package.dependencies] 200 | packaging = "*" 201 | pyyaml = "*" 202 | toml = "*" 203 | 204 | [package.extras] 205 | pipenv = ["pipenv"] 206 | 207 | [[package]] 208 | name = "flake8" 209 | version = "3.8.4" 210 | description = "the modular source code checker: pep8 pyflakes and co" 211 | category = "dev" 212 | optional = false 213 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" 214 | 215 | [package.dependencies] 216 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 217 | mccabe = ">=0.6.0,<0.7.0" 218 | pycodestyle = ">=2.6.0a1,<2.7.0" 219 | pyflakes = ">=2.2.0,<2.3.0" 220 | 221 | [[package]] 222 | name = "flake8-bugbear" 223 | version = "20.11.1" 224 | description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." 225 | category = "dev" 226 | optional = false 227 | python-versions = ">=3.6" 228 | 229 | [package.dependencies] 230 | attrs = ">=19.2.0" 231 | flake8 = ">=3.0.0" 232 | 233 | [package.extras] 234 | dev = ["coverage", "black", "hypothesis", "hypothesmith"] 235 | 236 | [[package]] 237 | name = "future" 238 | version = "0.18.2" 239 | description = "Clean single-source support for Python 3 and 2" 240 | category = "dev" 241 | optional = false 242 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 243 | 244 | [[package]] 245 | name = "gitdb" 246 | version = "4.0.5" 247 | description = "Git Object Database" 248 | category = "dev" 249 | optional = false 250 | python-versions = ">=3.4" 251 | 252 | [package.dependencies] 253 | smmap = ">=3.0.1,<4" 254 | 255 | [[package]] 256 | name = "gitpython" 257 | version = "3.1.12" 258 | description = "Python Git Library" 259 | category = "dev" 260 | optional = false 261 | python-versions = ">=3.4" 262 | 263 | [package.dependencies] 264 | gitdb = ">=4.0.1,<5" 265 | 266 | [[package]] 267 | name = "idna" 268 | version = "2.10" 269 | description = "Internationalized Domain Names in Applications (IDNA)" 270 | category = "dev" 271 | optional = false 272 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 273 | 274 | [[package]] 275 | name = "importlib-metadata" 276 | version = "3.4.0" 277 | description = "Read metadata from Python packages" 278 | category = "dev" 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 (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] 289 | 290 | [[package]] 291 | name = "iniconfig" 292 | version = "1.1.1" 293 | description = "iniconfig: brain-dead simple config-ini parsing" 294 | category = "dev" 295 | optional = false 296 | python-versions = "*" 297 | 298 | [[package]] 299 | name = "isort" 300 | version = "5.7.0" 301 | description = "A Python utility / library to sort Python imports." 302 | category = "dev" 303 | optional = false 304 | python-versions = ">=3.6,<4.0" 305 | 306 | [package.extras] 307 | pipfile_deprecated_finder = ["pipreqs", "requirementslib"] 308 | requirements_deprecated_finder = ["pipreqs", "pip-api"] 309 | colors = ["colorama (>=0.4.3,<0.5.0)"] 310 | 311 | [[package]] 312 | name = "jinja2" 313 | version = "2.11.2" 314 | description = "A very fast and expressive template engine." 315 | category = "dev" 316 | optional = false 317 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 318 | 319 | [package.dependencies] 320 | MarkupSafe = ">=0.23" 321 | 322 | [package.extras] 323 | i18n = ["Babel (>=0.8)"] 324 | 325 | [[package]] 326 | name = "jinja2-time" 327 | version = "0.2.0" 328 | description = "Jinja2 Extension for Dates and Times" 329 | category = "dev" 330 | optional = false 331 | python-versions = "*" 332 | 333 | [package.dependencies] 334 | arrow = "*" 335 | jinja2 = "*" 336 | 337 | [[package]] 338 | name = "joblib" 339 | version = "1.0.0" 340 | description = "Lightweight pipelining with Python functions" 341 | category = "dev" 342 | optional = false 343 | python-versions = ">=3.6" 344 | 345 | [[package]] 346 | name = "livereload" 347 | version = "2.6.3" 348 | description = "Python LiveReload is an awesome tool for web developers" 349 | category = "dev" 350 | optional = false 351 | python-versions = "*" 352 | 353 | [package.dependencies] 354 | six = "*" 355 | tornado = {version = "*", markers = "python_version > \"2.7\""} 356 | 357 | [[package]] 358 | name = "lunr" 359 | version = "0.5.8" 360 | description = "A Python implementation of Lunr.js" 361 | category = "dev" 362 | optional = false 363 | python-versions = "*" 364 | 365 | [package.dependencies] 366 | future = ">=0.16.0" 367 | nltk = {version = ">=3.2.5", optional = true, markers = "python_version > \"2.7\" and extra == \"languages\""} 368 | six = ">=1.11.0" 369 | 370 | [package.extras] 371 | languages = ["nltk (>=3.2.5,<3.5)", "nltk (>=3.2.5)"] 372 | 373 | [[package]] 374 | name = "mako" 375 | version = "1.1.4" 376 | description = "A super-fast templating language that borrows the best ideas from the existing templating languages." 377 | category = "dev" 378 | optional = false 379 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 380 | 381 | [package.dependencies] 382 | MarkupSafe = ">=0.9.2" 383 | 384 | [package.extras] 385 | babel = ["babel"] 386 | lingua = ["lingua"] 387 | 388 | [[package]] 389 | name = "markdown" 390 | version = "3.3.3" 391 | description = "Python implementation of Markdown." 392 | category = "dev" 393 | optional = false 394 | python-versions = ">=3.6" 395 | 396 | [package.dependencies] 397 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 398 | 399 | [package.extras] 400 | testing = ["coverage", "pyyaml"] 401 | 402 | [[package]] 403 | name = "markupsafe" 404 | version = "1.1.1" 405 | description = "Safely add untrusted strings to HTML/XML markup." 406 | category = "dev" 407 | optional = false 408 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" 409 | 410 | [[package]] 411 | name = "mccabe" 412 | version = "0.6.1" 413 | description = "McCabe checker, plugin for flake8" 414 | category = "dev" 415 | optional = false 416 | python-versions = "*" 417 | 418 | [[package]] 419 | name = "mkdocs" 420 | version = "1.1.2" 421 | description = "Project documentation with Markdown." 422 | category = "dev" 423 | optional = false 424 | python-versions = ">=3.5" 425 | 426 | [package.dependencies] 427 | click = ">=3.3" 428 | Jinja2 = ">=2.10.1" 429 | livereload = ">=2.5.1" 430 | lunr = {version = "0.5.8", extras = ["languages"]} 431 | Markdown = ">=3.2.1" 432 | PyYAML = ">=3.10" 433 | tornado = ">=5.0" 434 | 435 | [[package]] 436 | name = "mkdocs-material" 437 | version = "6.2.5" 438 | description = "A Material Design theme for MkDocs" 439 | category = "dev" 440 | optional = false 441 | python-versions = "*" 442 | 443 | [package.dependencies] 444 | markdown = ">=3.2" 445 | mkdocs = ">=1.1" 446 | mkdocs-material-extensions = ">=1.0" 447 | Pygments = ">=2.4" 448 | pymdown-extensions = ">=7.0" 449 | 450 | [[package]] 451 | name = "mkdocs-material-extensions" 452 | version = "1.0.1" 453 | description = "Extension pack for Python Markdown." 454 | category = "dev" 455 | optional = false 456 | python-versions = ">=3.5" 457 | 458 | [package.dependencies] 459 | mkdocs-material = ">=5.0.0" 460 | 461 | [[package]] 462 | name = "msgpack" 463 | version = "1.0.2" 464 | description = "MessagePack (de)serializer." 465 | category = "dev" 466 | optional = false 467 | python-versions = "*" 468 | 469 | [[package]] 470 | name = "mypy" 471 | version = "0.790" 472 | description = "Optional static typing for Python" 473 | category = "dev" 474 | optional = false 475 | python-versions = ">=3.5" 476 | 477 | [package.dependencies] 478 | mypy-extensions = ">=0.4.3,<0.5.0" 479 | typed-ast = ">=1.4.0,<1.5.0" 480 | typing-extensions = ">=3.7.4" 481 | 482 | [package.extras] 483 | dmypy = ["psutil (>=4.0)"] 484 | 485 | [[package]] 486 | name = "mypy-extensions" 487 | version = "0.4.3" 488 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 489 | category = "dev" 490 | optional = false 491 | python-versions = "*" 492 | 493 | [[package]] 494 | name = "nltk" 495 | version = "3.5" 496 | description = "Natural Language Toolkit" 497 | category = "dev" 498 | optional = false 499 | python-versions = "*" 500 | 501 | [package.dependencies] 502 | click = "*" 503 | joblib = "*" 504 | regex = "*" 505 | tqdm = "*" 506 | 507 | [package.extras] 508 | all = ["requests", "numpy", "python-crfsuite", "scikit-learn", "twython", "pyparsing", "scipy", "matplotlib", "gensim"] 509 | corenlp = ["requests"] 510 | machine_learning = ["gensim", "numpy", "python-crfsuite", "scikit-learn", "scipy"] 511 | plot = ["matplotlib"] 512 | tgrep = ["pyparsing"] 513 | twitter = ["twython"] 514 | 515 | [[package]] 516 | name = "numpy" 517 | version = "1.19.5" 518 | description = "NumPy is the fundamental package for array computing with Python." 519 | category = "dev" 520 | optional = false 521 | python-versions = ">=3.6" 522 | 523 | [[package]] 524 | name = "packaging" 525 | version = "20.8" 526 | description = "Core utilities for Python packages" 527 | category = "dev" 528 | optional = false 529 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 530 | 531 | [package.dependencies] 532 | pyparsing = ">=2.0.2" 533 | 534 | [[package]] 535 | name = "pathspec" 536 | version = "0.8.1" 537 | description = "Utility library for gitignore style pattern matching of file paths." 538 | category = "dev" 539 | optional = false 540 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 541 | 542 | [[package]] 543 | name = "pbr" 544 | version = "5.5.1" 545 | description = "Python Build Reasonableness" 546 | category = "dev" 547 | optional = false 548 | python-versions = ">=2.6" 549 | 550 | [[package]] 551 | name = "pdoc3" 552 | version = "0.9.2" 553 | description = "Auto-generate API documentation for Python projects." 554 | category = "dev" 555 | optional = false 556 | python-versions = ">= 3.5" 557 | 558 | [package.dependencies] 559 | mako = "*" 560 | markdown = ">=3.0" 561 | 562 | [[package]] 563 | name = "pluggy" 564 | version = "0.13.1" 565 | description = "plugin and hook calling mechanisms for python" 566 | category = "dev" 567 | optional = false 568 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 569 | 570 | [package.dependencies] 571 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 572 | 573 | [package.extras] 574 | dev = ["pre-commit", "tox"] 575 | 576 | [[package]] 577 | name = "poyo" 578 | version = "0.5.0" 579 | description = "A lightweight YAML Parser for Python. 🐓" 580 | category = "dev" 581 | optional = false 582 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 583 | 584 | [[package]] 585 | name = "preconvert-numpy" 586 | version = "0.0.3" 587 | description = "Preconverts common numpy types to their serializable (jsonifiable, msgpackable, etc...) form." 588 | category = "dev" 589 | optional = false 590 | python-versions = ">=3.5" 591 | 592 | [package.dependencies] 593 | numpy = "*" 594 | preconvert = ">=0.0.2" 595 | 596 | [package.extras] 597 | bson = ["pymongo"] 598 | msgpack = ["msgpack"] 599 | simplejson = ["simplejson"] 600 | 601 | [[package]] 602 | name = "py" 603 | version = "1.10.0" 604 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 605 | category = "dev" 606 | optional = false 607 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 608 | 609 | [[package]] 610 | name = "pycodestyle" 611 | version = "2.6.0" 612 | description = "Python style guide checker" 613 | category = "dev" 614 | optional = false 615 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 616 | 617 | [[package]] 618 | name = "pyflakes" 619 | version = "2.2.0" 620 | description = "passive checker of Python programs" 621 | category = "dev" 622 | optional = false 623 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 624 | 625 | [[package]] 626 | name = "pygments" 627 | version = "2.7.4" 628 | description = "Pygments is a syntax highlighting package written in Python." 629 | category = "dev" 630 | optional = false 631 | python-versions = ">=3.5" 632 | 633 | [[package]] 634 | name = "pymdown-extensions" 635 | version = "8.1" 636 | description = "Extension pack for Python Markdown." 637 | category = "dev" 638 | optional = false 639 | python-versions = ">=3.6" 640 | 641 | [package.dependencies] 642 | Markdown = ">=3.2" 643 | 644 | [[package]] 645 | name = "pyparsing" 646 | version = "2.4.7" 647 | description = "Python parsing module" 648 | category = "dev" 649 | optional = false 650 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 651 | 652 | [[package]] 653 | name = "pytest" 654 | version = "6.2.1" 655 | description = "pytest: simple powerful testing with Python" 656 | category = "dev" 657 | optional = false 658 | python-versions = ">=3.6" 659 | 660 | [package.dependencies] 661 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 662 | attrs = ">=19.2.0" 663 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 664 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 665 | iniconfig = "*" 666 | packaging = "*" 667 | pluggy = ">=0.12,<1.0.0a1" 668 | py = ">=1.8.2" 669 | toml = "*" 670 | 671 | [package.extras] 672 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] 673 | 674 | [[package]] 675 | name = "pytest-cov" 676 | version = "2.11.0" 677 | description = "Pytest plugin for measuring coverage." 678 | category = "dev" 679 | optional = false 680 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 681 | 682 | [package.dependencies] 683 | coverage = ">=5.2.1" 684 | pytest = ">=4.6" 685 | 686 | [package.extras] 687 | testing = ["fields", "hunter", "process-tests (==2.0.2)", "six", "pytest-xdist", "virtualenv"] 688 | 689 | [[package]] 690 | name = "pytest-cover" 691 | version = "3.0.0" 692 | description = "Pytest plugin for measuring coverage. Forked from `pytest-cov`." 693 | category = "dev" 694 | optional = false 695 | python-versions = "*" 696 | 697 | [package.dependencies] 698 | pytest-cov = ">=2.0" 699 | 700 | [[package]] 701 | name = "pytest-coverage" 702 | version = "0.0" 703 | description = "Pytest plugin for measuring coverage. Forked from `pytest-cov`." 704 | category = "dev" 705 | optional = false 706 | python-versions = "*" 707 | 708 | [package.dependencies] 709 | pytest-cover = "*" 710 | 711 | [[package]] 712 | name = "python-dateutil" 713 | version = "2.8.1" 714 | description = "Extensions to the standard Python datetime module" 715 | category = "dev" 716 | optional = false 717 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 718 | 719 | [package.dependencies] 720 | six = ">=1.5" 721 | 722 | [[package]] 723 | name = "python-slugify" 724 | version = "4.0.1" 725 | description = "A Python Slugify application that handles Unicode" 726 | category = "dev" 727 | optional = false 728 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 729 | 730 | [package.dependencies] 731 | text-unidecode = ">=1.3" 732 | 733 | [package.extras] 734 | unidecode = ["Unidecode (>=1.1.1)"] 735 | 736 | [[package]] 737 | name = "pyyaml" 738 | version = "5.3.1" 739 | description = "YAML parser and emitter for Python" 740 | category = "dev" 741 | optional = false 742 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 743 | 744 | [[package]] 745 | name = "regex" 746 | version = "2020.11.13" 747 | description = "Alternative regular expression module, to replace re." 748 | category = "dev" 749 | optional = false 750 | python-versions = "*" 751 | 752 | [[package]] 753 | name = "requests" 754 | version = "2.25.1" 755 | description = "Python HTTP for Humans." 756 | category = "dev" 757 | optional = false 758 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 759 | 760 | [package.dependencies] 761 | certifi = ">=2017.4.17" 762 | chardet = ">=3.0.2,<5" 763 | idna = ">=2.5,<3" 764 | urllib3 = ">=1.21.1,<1.27" 765 | 766 | [package.extras] 767 | security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] 768 | socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] 769 | 770 | [[package]] 771 | name = "safety" 772 | version = "1.10.3" 773 | description = "Checks installed dependencies for known vulnerabilities." 774 | category = "dev" 775 | optional = false 776 | python-versions = ">=3.5" 777 | 778 | [package.dependencies] 779 | Click = ">=6.0" 780 | dparse = ">=0.5.1" 781 | packaging = "*" 782 | requests = "*" 783 | 784 | [[package]] 785 | name = "simplejson" 786 | version = "3.17.2" 787 | description = "Simple, fast, extensible JSON encoder/decoder for Python" 788 | category = "dev" 789 | optional = false 790 | python-versions = ">=2.5, !=3.0.*, !=3.1.*, !=3.2.*" 791 | 792 | [[package]] 793 | name = "six" 794 | version = "1.15.0" 795 | description = "Python 2 and 3 compatibility utilities" 796 | category = "dev" 797 | optional = false 798 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 799 | 800 | [[package]] 801 | name = "smmap" 802 | version = "3.0.4" 803 | description = "A pure Python implementation of a sliding window memory map manager" 804 | category = "dev" 805 | optional = false 806 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 807 | 808 | [[package]] 809 | name = "stevedore" 810 | version = "3.3.0" 811 | description = "Manage dynamic plugins for Python applications" 812 | category = "dev" 813 | optional = false 814 | python-versions = ">=3.6" 815 | 816 | [package.dependencies] 817 | importlib-metadata = {version = ">=1.7.0", markers = "python_version < \"3.8\""} 818 | pbr = ">=2.0.0,<2.1.0 || >2.1.0" 819 | 820 | [[package]] 821 | name = "text-unidecode" 822 | version = "1.3" 823 | description = "The most basic Text::Unidecode port" 824 | category = "dev" 825 | optional = false 826 | python-versions = "*" 827 | 828 | [[package]] 829 | name = "toml" 830 | version = "0.10.2" 831 | description = "Python Library for Tom's Obvious, Minimal Language" 832 | category = "dev" 833 | optional = false 834 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 835 | 836 | [[package]] 837 | name = "tornado" 838 | version = "6.1" 839 | description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." 840 | category = "dev" 841 | optional = false 842 | python-versions = ">= 3.5" 843 | 844 | [[package]] 845 | name = "tqdm" 846 | version = "4.56.0" 847 | description = "Fast, Extensible Progress Meter" 848 | category = "dev" 849 | optional = false 850 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" 851 | 852 | [package.extras] 853 | dev = ["py-make (>=0.1.0)", "twine", "wheel"] 854 | telegram = ["requests"] 855 | 856 | [[package]] 857 | name = "typed-ast" 858 | version = "1.4.2" 859 | description = "a fork of Python 2 and 3 ast modules with type comment support" 860 | category = "dev" 861 | optional = false 862 | python-versions = "*" 863 | 864 | [[package]] 865 | name = "typer" 866 | version = "0.3.2" 867 | description = "Typer, build great CLIs. Easy to code. Based on Python type hints." 868 | category = "dev" 869 | optional = false 870 | python-versions = ">=3.6" 871 | 872 | [package.dependencies] 873 | click = ">=7.1.1,<7.2.0" 874 | 875 | [package.extras] 876 | test = ["pytest-xdist (>=1.32.0,<2.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "mypy (==0.782)", "black (>=19.10b0,<20.0b0)", "isort (>=5.0.6,<6.0.0)", "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)"] 877 | all = ["colorama (>=0.4.3,<0.5.0)", "shellingham (>=1.3.0,<2.0.0)"] 878 | dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)"] 879 | doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=5.4.0,<6.0.0)", "markdown-include (>=0.5.1,<0.6.0)"] 880 | 881 | [[package]] 882 | name = "typing-extensions" 883 | version = "3.7.4.3" 884 | description = "Backported and Experimental Type Hints for Python 3.5+" 885 | category = "dev" 886 | optional = false 887 | python-versions = "*" 888 | 889 | [[package]] 890 | name = "urllib3" 891 | version = "1.26.2" 892 | description = "HTTP library with thread-safe connection pooling, file post, and more." 893 | category = "dev" 894 | optional = false 895 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" 896 | 897 | [package.extras] 898 | brotli = ["brotlipy (>=0.6.0)"] 899 | secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] 900 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] 901 | 902 | [[package]] 903 | name = "vulture" 904 | version = "2.3" 905 | description = "Find dead code" 906 | category = "dev" 907 | optional = false 908 | python-versions = ">=3.6" 909 | 910 | [package.dependencies] 911 | toml = "*" 912 | 913 | [[package]] 914 | name = "zipp" 915 | version = "3.4.0" 916 | description = "Backport of pathlib-compatible object wrapper for zip files" 917 | category = "dev" 918 | optional = false 919 | python-versions = ">=3.6" 920 | 921 | [package.extras] 922 | docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] 923 | testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] 924 | 925 | [metadata] 926 | lock-version = "1.1" 927 | python-versions = "^3.6" 928 | content-hash = "67735292a97784624a6686ce58888595de1b2513cdc375c327788baa79fb7305" 929 | 930 | [metadata.files] 931 | appdirs = [ 932 | {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, 933 | {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, 934 | ] 935 | arrow = [ 936 | {file = "arrow-0.17.0-py2.py3-none-any.whl", hash = "sha256:e098abbd9af3665aea81bdd6c869e93af4feb078e98468dd351c383af187aac5"}, 937 | {file = "arrow-0.17.0.tar.gz", hash = "sha256:ff08d10cda1d36c68657d6ad20d74fbea493d980f8b2d45344e00d6ed2bf6ed4"}, 938 | ] 939 | atomicwrites = [ 940 | {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, 941 | {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, 942 | ] 943 | attrs = [ 944 | {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, 945 | {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, 946 | ] 947 | bandit = [ 948 | {file = "bandit-1.7.0-py3-none-any.whl", hash = "sha256:216be4d044209fa06cf2a3e51b319769a51be8318140659719aa7a115c35ed07"}, 949 | {file = "bandit-1.7.0.tar.gz", hash = "sha256:8a4c7415254d75df8ff3c3b15cfe9042ecee628a1e40b44c15a98890fbfc2608"}, 950 | ] 951 | binaryornot = [ 952 | {file = "binaryornot-0.4.4-py2.py3-none-any.whl", hash = "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4"}, 953 | {file = "binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061"}, 954 | ] 955 | black = [ 956 | {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, 957 | ] 958 | bson = [ 959 | {file = "bson-0.5.10.tar.gz", hash = "sha256:d6511b2ab051139a9123c184de1a04227262173ad593429d21e443d6462d6590"}, 960 | ] 961 | certifi = [ 962 | {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, 963 | {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, 964 | ] 965 | chardet = [ 966 | {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, 967 | {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, 968 | ] 969 | click = [ 970 | {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, 971 | {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, 972 | ] 973 | colorama = [ 974 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 975 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 976 | ] 977 | cookiecutter = [ 978 | {file = "cookiecutter-1.7.2-py2.py3-none-any.whl", hash = "sha256:430eb882d028afb6102c084bab6cf41f6559a77ce9b18dc6802e3bc0cc5f4a30"}, 979 | {file = "cookiecutter-1.7.2.tar.gz", hash = "sha256:efb6b2d4780feda8908a873e38f0e61778c23f6a2ea58215723bcceb5b515dac"}, 980 | ] 981 | coverage = [ 982 | {file = "coverage-5.3.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:fabeeb121735d47d8eab8671b6b031ce08514c86b7ad8f7d5490a7b6dcd6267d"}, 983 | {file = "coverage-5.3.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:7e4d159021c2029b958b2363abec4a11db0ce8cd43abb0d9ce44284cb97217e7"}, 984 | {file = "coverage-5.3.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:378ac77af41350a8c6b8801a66021b52da8a05fd77e578b7380e876c0ce4f528"}, 985 | {file = "coverage-5.3.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e448f56cfeae7b1b3b5bcd99bb377cde7c4eb1970a525c770720a352bc4c8044"}, 986 | {file = "coverage-5.3.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:cc44e3545d908ecf3e5773266c487ad1877be718d9dc65fc7eb6e7d14960985b"}, 987 | {file = "coverage-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:08b3ba72bd981531fd557f67beee376d6700fba183b167857038997ba30dd297"}, 988 | {file = "coverage-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:8dacc4073c359f40fcf73aede8428c35f84639baad7e1b46fce5ab7a8a7be4bb"}, 989 | {file = "coverage-5.3.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ee2f1d1c223c3d2c24e3afbb2dd38be3f03b1a8d6a83ee3d9eb8c36a52bee899"}, 990 | {file = "coverage-5.3.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:9a9d4ff06804920388aab69c5ea8a77525cf165356db70131616acd269e19b36"}, 991 | {file = "coverage-5.3.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:782a5c7df9f91979a7a21792e09b34a658058896628217ae6362088b123c8500"}, 992 | {file = "coverage-5.3.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:fda29412a66099af6d6de0baa6bd7c52674de177ec2ad2630ca264142d69c6c7"}, 993 | {file = "coverage-5.3.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:f2c6888eada180814b8583c3e793f3f343a692fc802546eed45f40a001b1169f"}, 994 | {file = "coverage-5.3.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8f33d1156241c43755137288dea619105477961cfa7e47f48dbf96bc2c30720b"}, 995 | {file = "coverage-5.3.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b239711e774c8eb910e9b1ac719f02f5ae4bf35fa0420f438cdc3a7e4e7dd6ec"}, 996 | {file = "coverage-5.3.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:f54de00baf200b4539a5a092a759f000b5f45fd226d6d25a76b0dff71177a714"}, 997 | {file = "coverage-5.3.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:be0416074d7f253865bb67630cf7210cbc14eb05f4099cc0f82430135aaa7a3b"}, 998 | {file = "coverage-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:c46643970dff9f5c976c6512fd35768c4a3819f01f61169d8cdac3f9290903b7"}, 999 | {file = "coverage-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9a4f66259bdd6964d8cf26142733c81fb562252db74ea367d9beb4f815478e72"}, 1000 | {file = "coverage-5.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c6e5174f8ca585755988bc278c8bb5d02d9dc2e971591ef4a1baabdf2d99589b"}, 1001 | {file = "coverage-5.3.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:3911c2ef96e5ddc748a3c8b4702c61986628bb719b8378bf1e4a6184bbd48fe4"}, 1002 | {file = "coverage-5.3.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c5ec71fd4a43b6d84ddb88c1df94572479d9a26ef3f150cef3dacefecf888105"}, 1003 | {file = "coverage-5.3.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f51dbba78d68a44e99d484ca8c8f604f17e957c1ca09c3ebc2c7e3bbd9ba0448"}, 1004 | {file = "coverage-5.3.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:a2070c5affdb3a5e751f24208c5c4f3d5f008fa04d28731416e023c93b275277"}, 1005 | {file = "coverage-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:535dc1e6e68fad5355f9984d5637c33badbdc987b0c0d303ee95a6c979c9516f"}, 1006 | {file = "coverage-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:a4857f7e2bc6921dbd487c5c88b84f5633de3e7d416c4dc0bb70256775551a6c"}, 1007 | {file = "coverage-5.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fac3c432851038b3e6afe086f777732bcf7f6ebbfd90951fa04ee53db6d0bcdd"}, 1008 | {file = "coverage-5.3.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:cd556c79ad665faeae28020a0ab3bda6cd47d94bec48e36970719b0b86e4dcf4"}, 1009 | {file = "coverage-5.3.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a66ca3bdf21c653e47f726ca57f46ba7fc1f260ad99ba783acc3e58e3ebdb9ff"}, 1010 | {file = "coverage-5.3.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:ab110c48bc3d97b4d19af41865e14531f300b482da21783fdaacd159251890e8"}, 1011 | {file = "coverage-5.3.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:e52d3d95df81c8f6b2a1685aabffadf2d2d9ad97203a40f8d61e51b70f191e4e"}, 1012 | {file = "coverage-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:fa10fee7e32213f5c7b0d6428ea92e3a3fdd6d725590238a3f92c0de1c78b9d2"}, 1013 | {file = "coverage-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ce6f3a147b4b1a8b09aae48517ae91139b1b010c5f36423fa2b866a8b23df879"}, 1014 | {file = "coverage-5.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:93a280c9eb736a0dcca19296f3c30c720cb41a71b1f9e617f341f0a8e791a69b"}, 1015 | {file = "coverage-5.3.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3102bb2c206700a7d28181dbe04d66b30780cde1d1c02c5f3c165cf3d2489497"}, 1016 | {file = "coverage-5.3.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8ffd4b204d7de77b5dd558cdff986a8274796a1e57813ed005b33fd97e29f059"}, 1017 | {file = "coverage-5.3.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:a607ae05b6c96057ba86c811d9c43423f35e03874ffb03fbdcd45e0637e8b631"}, 1018 | {file = "coverage-5.3.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:3a3c3f8863255f3c31db3889f8055989527173ef6192a283eb6f4db3c579d830"}, 1019 | {file = "coverage-5.3.1-cp38-cp38-win32.whl", hash = "sha256:ff1330e8bc996570221b450e2d539134baa9465f5cb98aff0e0f73f34172e0ae"}, 1020 | {file = "coverage-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:3498b27d8236057def41de3585f317abae235dd3a11d33e01736ffedb2ef8606"}, 1021 | {file = "coverage-5.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ceb499d2b3d1d7b7ba23abe8bf26df5f06ba8c71127f188333dddcf356b4b63f"}, 1022 | {file = "coverage-5.3.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:3b14b1da110ea50c8bcbadc3b82c3933974dbeea1832e814aab93ca1163cd4c1"}, 1023 | {file = "coverage-5.3.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:76b2775dda7e78680d688daabcb485dc87cf5e3184a0b3e012e1d40e38527cc8"}, 1024 | {file = "coverage-5.3.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:cef06fb382557f66d81d804230c11ab292d94b840b3cb7bf4450778377b592f4"}, 1025 | {file = "coverage-5.3.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:6f61319e33222591f885c598e3e24f6a4be3533c1d70c19e0dc59e83a71ce27d"}, 1026 | {file = "coverage-5.3.1-cp39-cp39-win32.whl", hash = "sha256:cc6f8246e74dd210d7e2b56c76ceaba1cc52b025cd75dbe96eb48791e0250e98"}, 1027 | {file = "coverage-5.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:2757fa64e11ec12220968f65d086b7a29b6583d16e9a544c889b22ba98555ef1"}, 1028 | {file = "coverage-5.3.1-pp36-none-any.whl", hash = "sha256:723d22d324e7997a651478e9c5a3120a0ecbc9a7e94071f7e1954562a8806cf3"}, 1029 | {file = "coverage-5.3.1-pp37-none-any.whl", hash = "sha256:c89b558f8a9a5a6f2cfc923c304d49f0ce629c3bd85cb442ca258ec20366394c"}, 1030 | {file = "coverage-5.3.1.tar.gz", hash = "sha256:38f16b1317b8dd82df67ed5daa5f5e7c959e46579840d77a67a4ceb9cef0a50b"}, 1031 | ] 1032 | cruft = [ 1033 | {file = "cruft-2.6.0-py3-none-any.whl", hash = "sha256:80e32a2fd8103f3c57c96af1c25d96d748072727a8563c58a65eece56a02b441"}, 1034 | {file = "cruft-2.6.0.tar.gz", hash = "sha256:bbeea9fb69812afd74a8140cca5ae7fdab761d4df50b137f2437fab9e72c4580"}, 1035 | ] 1036 | dataclasses = [ 1037 | {file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"}, 1038 | {file = "dataclasses-0.8.tar.gz", hash = "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"}, 1039 | ] 1040 | dparse = [ 1041 | {file = "dparse-0.5.1-py3-none-any.whl", hash = "sha256:e953a25e44ebb60a5c6efc2add4420c177f1d8404509da88da9729202f306994"}, 1042 | {file = "dparse-0.5.1.tar.gz", hash = "sha256:a1b5f169102e1c894f9a7d5ccf6f9402a836a5d24be80a986c7ce9eaed78f367"}, 1043 | ] 1044 | flake8 = [ 1045 | {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"}, 1046 | {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, 1047 | ] 1048 | flake8-bugbear = [ 1049 | {file = "flake8-bugbear-20.11.1.tar.gz", hash = "sha256:528020129fea2dea33a466b9d64ab650aa3e5f9ffc788b70ea4bc6cf18283538"}, 1050 | {file = "flake8_bugbear-20.11.1-py36.py37.py38-none-any.whl", hash = "sha256:f35b8135ece7a014bc0aee5b5d485334ac30a6da48494998cc1fabf7ec70d703"}, 1051 | ] 1052 | future = [ 1053 | {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, 1054 | ] 1055 | gitdb = [ 1056 | {file = "gitdb-4.0.5-py3-none-any.whl", hash = "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac"}, 1057 | {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"}, 1058 | ] 1059 | gitpython = [ 1060 | {file = "GitPython-3.1.12-py3-none-any.whl", hash = "sha256:867ec3dfb126aac0f8296b19fb63b8c4a399f32b4b6fafe84c4b10af5fa9f7b5"}, 1061 | {file = "GitPython-3.1.12.tar.gz", hash = "sha256:42dbefd8d9e2576c496ed0059f3103dcef7125b9ce16f9d5f9c834aed44a1dac"}, 1062 | ] 1063 | idna = [ 1064 | {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, 1065 | {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, 1066 | ] 1067 | importlib-metadata = [ 1068 | {file = "importlib_metadata-3.4.0-py3-none-any.whl", hash = "sha256:ace61d5fc652dc280e7b6b4ff732a9c2d40db2c0f92bc6cb74e07b73d53a1771"}, 1069 | {file = "importlib_metadata-3.4.0.tar.gz", hash = "sha256:fa5daa4477a7414ae34e95942e4dd07f62adf589143c875c133c1e53c4eff38d"}, 1070 | ] 1071 | iniconfig = [ 1072 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, 1073 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, 1074 | ] 1075 | isort = [ 1076 | {file = "isort-5.7.0-py3-none-any.whl", hash = "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc"}, 1077 | {file = "isort-5.7.0.tar.gz", hash = "sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e"}, 1078 | ] 1079 | jinja2 = [ 1080 | {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, 1081 | {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, 1082 | ] 1083 | jinja2-time = [ 1084 | {file = "jinja2-time-0.2.0.tar.gz", hash = "sha256:d14eaa4d315e7688daa4969f616f226614350c48730bfa1692d2caebd8c90d40"}, 1085 | {file = "jinja2_time-0.2.0-py2.py3-none-any.whl", hash = "sha256:d3eab6605e3ec8b7a0863df09cc1d23714908fa61aa6986a845c20ba488b4efa"}, 1086 | ] 1087 | joblib = [ 1088 | {file = "joblib-1.0.0-py3-none-any.whl", hash = "sha256:75ead23f13484a2a414874779d69ade40d4fa1abe62b222a23cd50d4bc822f6f"}, 1089 | {file = "joblib-1.0.0.tar.gz", hash = "sha256:7ad866067ac1fdec27d51c8678ea760601b70e32ff1881d4dc8e1171f2b64b24"}, 1090 | ] 1091 | livereload = [ 1092 | {file = "livereload-2.6.3.tar.gz", hash = "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"}, 1093 | ] 1094 | lunr = [ 1095 | {file = "lunr-0.5.8-py2.py3-none-any.whl", hash = "sha256:aab3f489c4d4fab4c1294a257a30fec397db56f0a50273218ccc3efdbf01d6ca"}, 1096 | {file = "lunr-0.5.8.tar.gz", hash = "sha256:c4fb063b98eff775dd638b3df380008ae85e6cb1d1a24d1cd81a10ef6391c26e"}, 1097 | ] 1098 | mako = [ 1099 | {file = "Mako-1.1.4.tar.gz", hash = "sha256:17831f0b7087c313c0ffae2bcbbd3c1d5ba9eeac9c38f2eb7b50e8c99fe9d5ab"}, 1100 | ] 1101 | markdown = [ 1102 | {file = "Markdown-3.3.3-py3-none-any.whl", hash = "sha256:c109c15b7dc20a9ac454c9e6025927d44460b85bd039da028d85e2b6d0bcc328"}, 1103 | {file = "Markdown-3.3.3.tar.gz", hash = "sha256:5d9f2b5ca24bc4c7a390d22323ca4bad200368612b5aaa7796babf971d2b2f18"}, 1104 | ] 1105 | markupsafe = [ 1106 | {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, 1107 | {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, 1108 | {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, 1109 | {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, 1110 | {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, 1111 | {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, 1112 | {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, 1113 | {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, 1114 | {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, 1115 | {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, 1116 | {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, 1117 | {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, 1118 | {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, 1119 | {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, 1120 | {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, 1121 | {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, 1122 | {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, 1123 | {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, 1124 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, 1125 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, 1126 | {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, 1127 | {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, 1128 | {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, 1129 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, 1130 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, 1131 | {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, 1132 | {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, 1133 | {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, 1134 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, 1135 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, 1136 | {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, 1137 | {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, 1138 | {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, 1139 | ] 1140 | mccabe = [ 1141 | {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, 1142 | {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, 1143 | ] 1144 | mkdocs = [ 1145 | {file = "mkdocs-1.1.2-py3-none-any.whl", hash = "sha256:096f52ff52c02c7e90332d2e53da862fde5c062086e1b5356a6e392d5d60f5e9"}, 1146 | {file = "mkdocs-1.1.2.tar.gz", hash = "sha256:f0b61e5402b99d7789efa032c7a74c90a20220a9c81749da06dbfbcbd52ffb39"}, 1147 | ] 1148 | mkdocs-material = [ 1149 | {file = "mkdocs-material-6.2.5.tar.gz", hash = "sha256:26900f51e177eb7dcfc8140ffe33c71b22ffa2920271e093679f0670b78e7e8b"}, 1150 | {file = "mkdocs_material-6.2.5-py2.py3-none-any.whl", hash = "sha256:04574cbaeb12671da66cd58904d6066dd269239f4a1bdb819c2c6e1ac9d9947a"}, 1151 | ] 1152 | mkdocs-material-extensions = [ 1153 | {file = "mkdocs-material-extensions-1.0.1.tar.gz", hash = "sha256:6947fb7f5e4291e3c61405bad3539d81e0b3cd62ae0d66ced018128af509c68f"}, 1154 | {file = "mkdocs_material_extensions-1.0.1-py3-none-any.whl", hash = "sha256:d90c807a88348aa6d1805657ec5c0b2d8d609c110e62b9dce4daf7fa981fa338"}, 1155 | ] 1156 | msgpack = [ 1157 | {file = "msgpack-1.0.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:b6d9e2dae081aa35c44af9c4298de4ee72991305503442a5c74656d82b581fe9"}, 1158 | {file = "msgpack-1.0.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:a99b144475230982aee16b3d249170f1cccebf27fb0a08e9f603b69637a62192"}, 1159 | {file = "msgpack-1.0.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1026dcc10537d27dd2d26c327e552f05ce148977e9d7b9f1718748281b38c841"}, 1160 | {file = "msgpack-1.0.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:fe07bc6735d08e492a327f496b7850e98cb4d112c56df69b0c844dbebcbb47f6"}, 1161 | {file = "msgpack-1.0.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:9ea52fff0473f9f3000987f313310208c879493491ef3ccf66268eff8d5a0326"}, 1162 | {file = "msgpack-1.0.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:26a1759f1a88df5f1d0b393eb582ec022326994e311ba9c5818adc5374736439"}, 1163 | {file = "msgpack-1.0.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:497d2c12426adcd27ab83144057a705efb6acc7e85957a51d43cdcf7f258900f"}, 1164 | {file = "msgpack-1.0.2-cp36-cp36m-win32.whl", hash = "sha256:e89ec55871ed5473a041c0495b7b4e6099f6263438e0bd04ccd8418f92d5d7f2"}, 1165 | {file = "msgpack-1.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a4355d2193106c7aa77c98fc955252a737d8550320ecdb2e9ac701e15e2943bc"}, 1166 | {file = "msgpack-1.0.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:d6c64601af8f3893d17ec233237030e3110f11b8a962cb66720bf70c0141aa54"}, 1167 | {file = "msgpack-1.0.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f484cd2dca68502de3704f056fa9b318c94b1539ed17a4c784266df5d6978c87"}, 1168 | {file = "msgpack-1.0.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f3e6aaf217ac1c7ce1563cf52a2f4f5d5b1f64e8729d794165db71da57257f0c"}, 1169 | {file = "msgpack-1.0.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:8521e5be9e3b93d4d5e07cb80b7e32353264d143c1f072309e1863174c6aadb1"}, 1170 | {file = "msgpack-1.0.2-cp37-cp37m-win32.whl", hash = "sha256:31c17bbf2ae5e29e48d794c693b7ca7a0c73bd4280976d408c53df421e838d2a"}, 1171 | {file = "msgpack-1.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8ffb24a3b7518e843cd83538cf859e026d24ec41ac5721c18ed0c55101f9775b"}, 1172 | {file = "msgpack-1.0.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:b28c0876cce1466d7c2195d7658cf50e4730667196e2f1355c4209444717ee06"}, 1173 | {file = "msgpack-1.0.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:87869ba567fe371c4555d2e11e4948778ab6b59d6cc9d8460d543e4cfbbddd1c"}, 1174 | {file = "msgpack-1.0.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b55f7db883530b74c857e50e149126b91bb75d35c08b28db12dcb0346f15e46e"}, 1175 | {file = "msgpack-1.0.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:ac25f3e0513f6673e8b405c3a80500eb7be1cf8f57584be524c4fa78fe8e0c83"}, 1176 | {file = "msgpack-1.0.2-cp38-cp38-win32.whl", hash = "sha256:0cb94ee48675a45d3b86e61d13c1e6f1696f0183f0715544976356ff86f741d9"}, 1177 | {file = "msgpack-1.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:e36a812ef4705a291cdb4a2fd352f013134f26c6ff63477f20235138d1d21009"}, 1178 | {file = "msgpack-1.0.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:2a5866bdc88d77f6e1370f82f2371c9bc6fc92fe898fa2dec0c5d4f5435a2694"}, 1179 | {file = "msgpack-1.0.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:92be4b12de4806d3c36810b0fe2aeedd8d493db39e2eb90742b9c09299eb5759"}, 1180 | {file = "msgpack-1.0.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:de6bd7990a2c2dabe926b7e62a92886ccbf809425c347ae7de277067f97c2887"}, 1181 | {file = "msgpack-1.0.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5a9ee2540c78659a1dd0b110f73773533ee3108d4e1219b5a15a8d635b7aca0e"}, 1182 | {file = "msgpack-1.0.2-cp39-cp39-win32.whl", hash = "sha256:c747c0cc08bd6d72a586310bda6ea72eeb28e7505990f342552315b229a19b33"}, 1183 | {file = "msgpack-1.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:d8167b84af26654c1124857d71650404336f4eb5cc06900667a493fc619ddd9f"}, 1184 | {file = "msgpack-1.0.2.tar.gz", hash = "sha256:fae04496f5bc150eefad4e9571d1a76c55d021325dcd484ce45065ebbdd00984"}, 1185 | ] 1186 | mypy = [ 1187 | {file = "mypy-0.790-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:bd03b3cf666bff8d710d633d1c56ab7facbdc204d567715cb3b9f85c6e94f669"}, 1188 | {file = "mypy-0.790-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:2170492030f6faa537647d29945786d297e4862765f0b4ac5930ff62e300d802"}, 1189 | {file = "mypy-0.790-cp35-cp35m-win_amd64.whl", hash = "sha256:e86bdace26c5fe9cf8cb735e7cedfe7850ad92b327ac5d797c656717d2ca66de"}, 1190 | {file = "mypy-0.790-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e97e9c13d67fbe524be17e4d8025d51a7dca38f90de2e462243ab8ed8a9178d1"}, 1191 | {file = "mypy-0.790-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0d34d6b122597d48a36d6c59e35341f410d4abfa771d96d04ae2c468dd201abc"}, 1192 | {file = "mypy-0.790-cp36-cp36m-win_amd64.whl", hash = "sha256:72060bf64f290fb629bd4a67c707a66fd88ca26e413a91384b18db3876e57ed7"}, 1193 | {file = "mypy-0.790-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:eea260feb1830a627fb526d22fbb426b750d9f5a47b624e8d5e7e004359b219c"}, 1194 | {file = "mypy-0.790-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c614194e01c85bb2e551c421397e49afb2872c88b5830e3554f0519f9fb1c178"}, 1195 | {file = "mypy-0.790-cp37-cp37m-win_amd64.whl", hash = "sha256:0a0d102247c16ce93c97066443d11e2d36e6cc2a32d8ccc1f705268970479324"}, 1196 | {file = "mypy-0.790-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cf4e7bf7f1214826cf7333627cb2547c0db7e3078723227820d0a2490f117a01"}, 1197 | {file = "mypy-0.790-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:af4e9ff1834e565f1baa74ccf7ae2564ae38c8df2a85b057af1dbbc958eb6666"}, 1198 | {file = "mypy-0.790-cp38-cp38-win_amd64.whl", hash = "sha256:da56dedcd7cd502ccd3c5dddc656cb36113dd793ad466e894574125945653cea"}, 1199 | {file = "mypy-0.790-py3-none-any.whl", hash = "sha256:2842d4fbd1b12ab422346376aad03ff5d0805b706102e475e962370f874a5122"}, 1200 | {file = "mypy-0.790.tar.gz", hash = "sha256:2b21ba45ad9ef2e2eb88ce4aeadd0112d0f5026418324176fd494a6824b74975"}, 1201 | ] 1202 | mypy-extensions = [ 1203 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 1204 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 1205 | ] 1206 | nltk = [ 1207 | {file = "nltk-3.5.zip", hash = "sha256:845365449cd8c5f9731f7cb9f8bd6fd0767553b9d53af9eb1b3abf7700936b35"}, 1208 | ] 1209 | numpy = [ 1210 | {file = "numpy-1.19.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc6bd4fd593cb261332568485e20a0712883cf631f6f5e8e86a52caa8b2b50ff"}, 1211 | {file = "numpy-1.19.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:aeb9ed923be74e659984e321f609b9ba54a48354bfd168d21a2b072ed1e833ea"}, 1212 | {file = "numpy-1.19.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8b5e972b43c8fc27d56550b4120fe6257fdc15f9301914380b27f74856299fea"}, 1213 | {file = "numpy-1.19.5-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:43d4c81d5ffdff6bae58d66a3cd7f54a7acd9a0e7b18d97abb255defc09e3140"}, 1214 | {file = "numpy-1.19.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:a4646724fba402aa7504cd48b4b50e783296b5e10a524c7a6da62e4a8ac9698d"}, 1215 | {file = "numpy-1.19.5-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:2e55195bc1c6b705bfd8ad6f288b38b11b1af32f3c8289d6c50d47f950c12e76"}, 1216 | {file = "numpy-1.19.5-cp36-cp36m-win32.whl", hash = "sha256:39b70c19ec771805081578cc936bbe95336798b7edf4732ed102e7a43ec5c07a"}, 1217 | {file = "numpy-1.19.5-cp36-cp36m-win_amd64.whl", hash = "sha256:dbd18bcf4889b720ba13a27ec2f2aac1981bd41203b3a3b27ba7a33f88ae4827"}, 1218 | {file = "numpy-1.19.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:603aa0706be710eea8884af807b1b3bc9fb2e49b9f4da439e76000f3b3c6ff0f"}, 1219 | {file = "numpy-1.19.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:cae865b1cae1ec2663d8ea56ef6ff185bad091a5e33ebbadd98de2cfa3fa668f"}, 1220 | {file = "numpy-1.19.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:36674959eed6957e61f11c912f71e78857a8d0604171dfd9ce9ad5cbf41c511c"}, 1221 | {file = "numpy-1.19.5-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:06fab248a088e439402141ea04f0fffb203723148f6ee791e9c75b3e9e82f080"}, 1222 | {file = "numpy-1.19.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6149a185cece5ee78d1d196938b2a8f9d09f5a5ebfbba66969302a778d5ddd1d"}, 1223 | {file = "numpy-1.19.5-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:50a4a0ad0111cc1b71fa32dedd05fa239f7fb5a43a40663269bb5dc7877cfd28"}, 1224 | {file = "numpy-1.19.5-cp37-cp37m-win32.whl", hash = "sha256:d051ec1c64b85ecc69531e1137bb9751c6830772ee5c1c426dbcfe98ef5788d7"}, 1225 | {file = "numpy-1.19.5-cp37-cp37m-win_amd64.whl", hash = "sha256:a12ff4c8ddfee61f90a1633a4c4afd3f7bcb32b11c52026c92a12e1325922d0d"}, 1226 | {file = "numpy-1.19.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cf2402002d3d9f91c8b01e66fbb436a4ed01c6498fffed0e4c7566da1d40ee1e"}, 1227 | {file = "numpy-1.19.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1ded4fce9cfaaf24e7a0ab51b7a87be9038ea1ace7f34b841fe3b6894c721d1c"}, 1228 | {file = "numpy-1.19.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:012426a41bc9ab63bb158635aecccc7610e3eff5d31d1eb43bc099debc979d94"}, 1229 | {file = "numpy-1.19.5-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:759e4095edc3c1b3ac031f34d9459fa781777a93ccc633a472a5468587a190ff"}, 1230 | {file = "numpy-1.19.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:a9d17f2be3b427fbb2bce61e596cf555d6f8a56c222bd2ca148baeeb5e5c783c"}, 1231 | {file = "numpy-1.19.5-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:99abf4f353c3d1a0c7a5f27699482c987cf663b1eac20db59b8c7b061eabd7fc"}, 1232 | {file = "numpy-1.19.5-cp38-cp38-win32.whl", hash = "sha256:384ec0463d1c2671170901994aeb6dce126de0a95ccc3976c43b0038a37329c2"}, 1233 | {file = "numpy-1.19.5-cp38-cp38-win_amd64.whl", hash = "sha256:811daee36a58dc79cf3d8bdd4a490e4277d0e4b7d103a001a4e73ddb48e7e6aa"}, 1234 | {file = "numpy-1.19.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c843b3f50d1ab7361ca4f0b3639bf691569493a56808a0b0c54a051d260b7dbd"}, 1235 | {file = "numpy-1.19.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d6631f2e867676b13026e2846180e2c13c1e11289d67da08d71cacb2cd93d4aa"}, 1236 | {file = "numpy-1.19.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7fb43004bce0ca31d8f13a6eb5e943fa73371381e53f7074ed21a4cb786c32f8"}, 1237 | {file = "numpy-1.19.5-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2ea52bd92ab9f768cc64a4c3ef8f4b2580a17af0a5436f6126b08efbd1838371"}, 1238 | {file = "numpy-1.19.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:400580cbd3cff6ffa6293df2278c75aef2d58d8d93d3c5614cd67981dae68ceb"}, 1239 | {file = "numpy-1.19.5-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:df609c82f18c5b9f6cb97271f03315ff0dbe481a2a02e56aeb1b1a985ce38e60"}, 1240 | {file = "numpy-1.19.5-cp39-cp39-win32.whl", hash = "sha256:ab83f24d5c52d60dbc8cd0528759532736b56db58adaa7b5f1f76ad551416a1e"}, 1241 | {file = "numpy-1.19.5-cp39-cp39-win_amd64.whl", hash = "sha256:0eef32ca3132a48e43f6a0f5a82cb508f22ce5a3d6f67a8329c81c8e226d3f6e"}, 1242 | {file = "numpy-1.19.5-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:a0d53e51a6cb6f0d9082decb7a4cb6dfb33055308c4c44f53103c073f649af73"}, 1243 | {file = "numpy-1.19.5.zip", hash = "sha256:a76f502430dd98d7546e1ea2250a7360c065a5fdea52b2dffe8ae7180909b6f4"}, 1244 | ] 1245 | packaging = [ 1246 | {file = "packaging-20.8-py2.py3-none-any.whl", hash = "sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858"}, 1247 | {file = "packaging-20.8.tar.gz", hash = "sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093"}, 1248 | ] 1249 | pathspec = [ 1250 | {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, 1251 | {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, 1252 | ] 1253 | pbr = [ 1254 | {file = "pbr-5.5.1-py2.py3-none-any.whl", hash = "sha256:b236cde0ac9a6aedd5e3c34517b423cd4fd97ef723849da6b0d2231142d89c00"}, 1255 | {file = "pbr-5.5.1.tar.gz", hash = "sha256:5fad80b613c402d5b7df7bd84812548b2a61e9977387a80a5fc5c396492b13c9"}, 1256 | ] 1257 | pdoc3 = [ 1258 | {file = "pdoc3-0.9.2.tar.gz", hash = "sha256:9df5d931f25f353c69c46819a3bd03ef96dd286f2a70bb1b93a23a781f91faa1"}, 1259 | ] 1260 | pluggy = [ 1261 | {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, 1262 | {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, 1263 | ] 1264 | poyo = [ 1265 | {file = "poyo-0.5.0-py2.py3-none-any.whl", hash = "sha256:3e2ca8e33fdc3c411cd101ca395668395dd5dc7ac775b8e809e3def9f9fe041a"}, 1266 | {file = "poyo-0.5.0.tar.gz", hash = "sha256:e26956aa780c45f011ca9886f044590e2d8fd8b61db7b1c1cf4e0869f48ed4dd"}, 1267 | ] 1268 | preconvert-numpy = [ 1269 | {file = "preconvert_numpy-0.0.3-py3-none-any.whl", hash = "sha256:018130f17ddbc9f672d6f518f5d3fc1166f631d08408753ec5f08319d4f75102"}, 1270 | {file = "preconvert_numpy-0.0.3.tar.gz", hash = "sha256:8482b71ac2d07afbd17d760d338e7b551cd57b2ffbae94308615ac089b6a42a3"}, 1271 | ] 1272 | py = [ 1273 | {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, 1274 | {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, 1275 | ] 1276 | pycodestyle = [ 1277 | {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, 1278 | {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, 1279 | ] 1280 | pyflakes = [ 1281 | {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, 1282 | {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, 1283 | ] 1284 | pygments = [ 1285 | {file = "Pygments-2.7.4-py3-none-any.whl", hash = "sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435"}, 1286 | {file = "Pygments-2.7.4.tar.gz", hash = "sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337"}, 1287 | ] 1288 | pymdown-extensions = [ 1289 | {file = "pymdown-extensions-8.1.tar.gz", hash = "sha256:565583c5964ac8253896ef4a7f14023075503ca6514d7d470b343290b96fc6da"}, 1290 | {file = "pymdown_extensions-8.1-py2.py3-none-any.whl", hash = "sha256:c0b285fdd6e8438895b0c4422847af012f32a487ae083ffafa4c21a151b4983b"}, 1291 | ] 1292 | pyparsing = [ 1293 | {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, 1294 | {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, 1295 | ] 1296 | pytest = [ 1297 | {file = "pytest-6.2.1-py3-none-any.whl", hash = "sha256:1969f797a1a0dbd8ccf0fecc80262312729afea9c17f1d70ebf85c5e76c6f7c8"}, 1298 | {file = "pytest-6.2.1.tar.gz", hash = "sha256:66e419b1899bc27346cb2c993e12c5e5e8daba9073c1fbce33b9807abc95c306"}, 1299 | ] 1300 | pytest-cov = [ 1301 | {file = "pytest-cov-2.11.0.tar.gz", hash = "sha256:e90e034cde61dacb1394639a33f449725c591025b182d69752c1dd0bfec639a7"}, 1302 | {file = "pytest_cov-2.11.0-py2.py3-none-any.whl", hash = "sha256:626a8a6ab188656c4f84b67d22436d6c494699d917e567e0048dda6e7f59e028"}, 1303 | ] 1304 | pytest-cover = [ 1305 | {file = "pytest-cover-3.0.0.tar.gz", hash = "sha256:5bdb6c1cc3dd75583bb7bc2c57f5e1034a1bfcb79d27c71aceb0b16af981dbf4"}, 1306 | {file = "pytest_cover-3.0.0-py2.py3-none-any.whl", hash = "sha256:578249955eb3b5f3991209df6e532bb770b647743b7392d3d97698dc02f39ebb"}, 1307 | ] 1308 | pytest-coverage = [ 1309 | {file = "pytest-coverage-0.0.tar.gz", hash = "sha256:db6af2cbd7e458c7c9fd2b4207cee75258243c8a81cad31a7ee8cfad5be93c05"}, 1310 | {file = "pytest_coverage-0.0-py2.py3-none-any.whl", hash = "sha256:dedd084c5e74d8e669355325916dc011539b190355021b037242514dee546368"}, 1311 | ] 1312 | python-dateutil = [ 1313 | {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, 1314 | {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, 1315 | ] 1316 | python-slugify = [ 1317 | {file = "python-slugify-4.0.1.tar.gz", hash = "sha256:69a517766e00c1268e5bbfc0d010a0a8508de0b18d30ad5a1ff357f8ae724270"}, 1318 | ] 1319 | pyyaml = [ 1320 | {file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"}, 1321 | {file = "PyYAML-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76"}, 1322 | {file = "PyYAML-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2"}, 1323 | {file = "PyYAML-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c"}, 1324 | {file = "PyYAML-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2"}, 1325 | {file = "PyYAML-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648"}, 1326 | {file = "PyYAML-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"}, 1327 | {file = "PyYAML-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf"}, 1328 | {file = "PyYAML-5.3.1-cp38-cp38-win32.whl", hash = "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97"}, 1329 | {file = "PyYAML-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee"}, 1330 | {file = "PyYAML-5.3.1-cp39-cp39-win32.whl", hash = "sha256:ad9c67312c84def58f3c04504727ca879cb0013b2517c85a9a253f0cb6380c0a"}, 1331 | {file = "PyYAML-5.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:6034f55dab5fea9e53f436aa68fa3ace2634918e8b5994d82f3621c04ff5ed2e"}, 1332 | {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, 1333 | ] 1334 | regex = [ 1335 | {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, 1336 | {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, 1337 | {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, 1338 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, 1339 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, 1340 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, 1341 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, 1342 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, 1343 | {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, 1344 | {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, 1345 | {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, 1346 | {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, 1347 | {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, 1348 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, 1349 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, 1350 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, 1351 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, 1352 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, 1353 | {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, 1354 | {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, 1355 | {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, 1356 | {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, 1357 | {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, 1358 | {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, 1359 | {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, 1360 | {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, 1361 | {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, 1362 | {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, 1363 | {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, 1364 | {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, 1365 | {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, 1366 | {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, 1367 | {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, 1368 | {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, 1369 | {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, 1370 | {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, 1371 | {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, 1372 | {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, 1373 | {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, 1374 | {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, 1375 | {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, 1376 | ] 1377 | requests = [ 1378 | {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, 1379 | {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, 1380 | ] 1381 | safety = [ 1382 | {file = "safety-1.10.3-py2.py3-none-any.whl", hash = "sha256:5f802ad5df5614f9622d8d71fedec2757099705c2356f862847c58c6dfe13e84"}, 1383 | {file = "safety-1.10.3.tar.gz", hash = "sha256:30e394d02a20ac49b7f65292d19d38fa927a8f9582cdfd3ad1adbbc66c641ad5"}, 1384 | ] 1385 | simplejson = [ 1386 | {file = "simplejson-3.17.2-cp27-cp27m-macosx_10_13_x86_64.whl", hash = "sha256:2d3eab2c3fe52007d703a26f71cf649a8c771fcdd949a3ae73041ba6797cfcf8"}, 1387 | {file = "simplejson-3.17.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:813846738277729d7db71b82176204abc7fdae2f566e2d9fcf874f9b6472e3e6"}, 1388 | {file = "simplejson-3.17.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:292c2e3f53be314cc59853bd20a35bf1f965f3bc121e007ab6fd526ed412a85d"}, 1389 | {file = "simplejson-3.17.2-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:0dd9d9c738cb008bfc0862c9b8fa6743495c03a0ed543884bf92fb7d30f8d043"}, 1390 | {file = "simplejson-3.17.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:42b8b8dd0799f78e067e2aaae97e60d58a8f63582939af60abce4c48631a0aa4"}, 1391 | {file = "simplejson-3.17.2-cp27-cp27m-win32.whl", hash = "sha256:8042040af86a494a23c189b5aa0ea9433769cc029707833f261a79c98e3375f9"}, 1392 | {file = "simplejson-3.17.2-cp27-cp27m-win_amd64.whl", hash = "sha256:034550078a11664d77bc1a8364c90bb7eef0e44c2dbb1fd0a4d92e3997088667"}, 1393 | {file = "simplejson-3.17.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:fed0f22bf1313ff79c7fc318f7199d6c2f96d4de3234b2f12a1eab350e597c06"}, 1394 | {file = "simplejson-3.17.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:2e7b57c2c146f8e4dadf84977a83f7ee50da17c8861fd7faf694d55e3274784f"}, 1395 | {file = "simplejson-3.17.2-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:da3c55cdc66cfc3fffb607db49a42448785ea2732f055ac1549b69dcb392663b"}, 1396 | {file = "simplejson-3.17.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:c1cb29b1fced01f97e6d5631c3edc2dadb424d1f4421dad079cb13fc97acb42f"}, 1397 | {file = "simplejson-3.17.2-cp33-cp33m-win32.whl", hash = "sha256:8f713ea65958ef40049b6c45c40c206ab363db9591ff5a49d89b448933fa5746"}, 1398 | {file = "simplejson-3.17.2-cp33-cp33m-win_amd64.whl", hash = "sha256:344e2d920a7f27b4023c087ab539877a1e39ce8e3e90b867e0bfa97829824748"}, 1399 | {file = "simplejson-3.17.2-cp34-cp34m-win32.whl", hash = "sha256:05b43d568300c1cd43f95ff4bfcff984bc658aa001be91efb3bb21df9d6288d3"}, 1400 | {file = "simplejson-3.17.2-cp34-cp34m-win_amd64.whl", hash = "sha256:cff6453e25204d3369c47b97dd34783ca820611bd334779d22192da23784194b"}, 1401 | {file = "simplejson-3.17.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8acf76443cfb5c949b6e781c154278c059b09ac717d2757a830c869ba000cf8d"}, 1402 | {file = "simplejson-3.17.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:869a183c8e44bc03be1b2bbcc9ec4338e37fa8557fc506bf6115887c1d3bb956"}, 1403 | {file = "simplejson-3.17.2-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:5c659a0efc80aaaba57fcd878855c8534ecb655a28ac8508885c50648e6e659d"}, 1404 | {file = "simplejson-3.17.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:72d8a3ffca19a901002d6b068cf746be85747571c6a7ba12cbcf427bfb4ed971"}, 1405 | {file = "simplejson-3.17.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:4b3442249d5e3893b90cb9f72c7d6ce4d2ea144d2c0d9f75b9ae1e5460f3121a"}, 1406 | {file = "simplejson-3.17.2-cp35-cp35m-win32.whl", hash = "sha256:e058c7656c44fb494a11443191e381355388443d543f6fc1a245d5d238544396"}, 1407 | {file = "simplejson-3.17.2-cp35-cp35m-win_amd64.whl", hash = "sha256:934115642c8ba9659b402c8bdbdedb48651fb94b576e3b3efd1ccb079609b04a"}, 1408 | {file = "simplejson-3.17.2-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:ffd4e4877a78c84d693e491b223385e0271278f5f4e1476a4962dca6824ecfeb"}, 1409 | {file = "simplejson-3.17.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:10fc250c3edea4abc15d930d77274ddb8df4803453dde7ad50c2f5565a18a4bb"}, 1410 | {file = "simplejson-3.17.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:76ac9605bf2f6d9b56abf6f9da9047a8782574ad3531c82eae774947ae99cc3f"}, 1411 | {file = "simplejson-3.17.2-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:7f10f8ba9c1b1430addc7dd385fc322e221559d3ae49b812aebf57470ce8de45"}, 1412 | {file = "simplejson-3.17.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:bc00d1210567a4cdd215ac6e17dc00cb9893ee521cee701adfd0fa43f7c73139"}, 1413 | {file = "simplejson-3.17.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:af4868da7dd53296cd7630687161d53a7ebe2e63814234631445697bd7c29f46"}, 1414 | {file = "simplejson-3.17.2-cp36-cp36m-win32.whl", hash = "sha256:7d276f69bfc8c7ba6c717ba8deaf28f9d3c8450ff0aa8713f5a3280e232be16b"}, 1415 | {file = "simplejson-3.17.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a55c76254d7cf8d4494bc508e7abb993a82a192d0db4552421e5139235604625"}, 1416 | {file = "simplejson-3.17.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:9a2b7543559f8a1c9ed72724b549d8cc3515da7daf3e79813a15bdc4a769de25"}, 1417 | {file = "simplejson-3.17.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:311f5dc2af07361725033b13cc3d0351de3da8bede3397d45650784c3f21fbcf"}, 1418 | {file = "simplejson-3.17.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2862beabfb9097a745a961426fe7daf66e1714151da8bb9a0c430dde3d59c7c0"}, 1419 | {file = "simplejson-3.17.2-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:afebfc3dd3520d37056f641969ce320b071bc7a0800639c71877b90d053e087f"}, 1420 | {file = "simplejson-3.17.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:d4813b30cb62d3b63ccc60dd12f2121780c7a3068db692daeb90f989877aaf04"}, 1421 | {file = "simplejson-3.17.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3fabde09af43e0cbdee407555383063f8b45bfb52c361bc5da83fcffdb4fd278"}, 1422 | {file = "simplejson-3.17.2-cp37-cp37m-win32.whl", hash = "sha256:ceaa28a5bce8a46a130cd223e895080e258a88d51bf6e8de2fc54a6ef7e38c34"}, 1423 | {file = "simplejson-3.17.2-cp37-cp37m-win_amd64.whl", hash = "sha256:9551f23e09300a9a528f7af20e35c9f79686d46d646152a0c8fc41d2d074d9b0"}, 1424 | {file = "simplejson-3.17.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:c94dc64b1a389a416fc4218cd4799aa3756f25940cae33530a4f7f2f54f166da"}, 1425 | {file = "simplejson-3.17.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b59aa298137ca74a744c1e6e22cfc0bf9dca3a2f41f51bc92eb05695155d905a"}, 1426 | {file = "simplejson-3.17.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ad8f41c2357b73bc9e8606d2fa226233bf4d55d85a8982ecdfd55823a6959995"}, 1427 | {file = "simplejson-3.17.2-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:845a14f6deb124a3bcb98a62def067a67462a000e0508f256f9c18eff5847efc"}, 1428 | {file = "simplejson-3.17.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d0b64409df09edb4c365d95004775c988259efe9be39697d7315c42b7a5e7e94"}, 1429 | {file = "simplejson-3.17.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:55d65f9cc1b733d85ef95ab11f559cce55c7649a2160da2ac7a078534da676c8"}, 1430 | {file = "simplejson-3.17.2.tar.gz", hash = "sha256:75ecc79f26d99222a084fbdd1ce5aad3ac3a8bd535cd9059528452da38b68841"}, 1431 | ] 1432 | six = [ 1433 | {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, 1434 | {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, 1435 | ] 1436 | smmap = [ 1437 | {file = "smmap-3.0.4-py2.py3-none-any.whl", hash = "sha256:54c44c197c819d5ef1991799a7e30b662d1e520f2ac75c9efbeb54a742214cf4"}, 1438 | {file = "smmap-3.0.4.tar.gz", hash = "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"}, 1439 | ] 1440 | stevedore = [ 1441 | {file = "stevedore-3.3.0-py3-none-any.whl", hash = "sha256:50d7b78fbaf0d04cd62411188fa7eedcb03eb7f4c4b37005615ceebe582aa82a"}, 1442 | {file = "stevedore-3.3.0.tar.gz", hash = "sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee"}, 1443 | ] 1444 | text-unidecode = [ 1445 | {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"}, 1446 | {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, 1447 | ] 1448 | toml = [ 1449 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 1450 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 1451 | ] 1452 | tornado = [ 1453 | {file = "tornado-6.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32"}, 1454 | {file = "tornado-6.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c"}, 1455 | {file = "tornado-6.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05"}, 1456 | {file = "tornado-6.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910"}, 1457 | {file = "tornado-6.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b"}, 1458 | {file = "tornado-6.1-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675"}, 1459 | {file = "tornado-6.1-cp35-cp35m-win32.whl", hash = "sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5"}, 1460 | {file = "tornado-6.1-cp35-cp35m-win_amd64.whl", hash = "sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68"}, 1461 | {file = "tornado-6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb"}, 1462 | {file = "tornado-6.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c"}, 1463 | {file = "tornado-6.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921"}, 1464 | {file = "tornado-6.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558"}, 1465 | {file = "tornado-6.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c"}, 1466 | {file = "tornado-6.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085"}, 1467 | {file = "tornado-6.1-cp36-cp36m-win32.whl", hash = "sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575"}, 1468 | {file = "tornado-6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795"}, 1469 | {file = "tornado-6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f"}, 1470 | {file = "tornado-6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102"}, 1471 | {file = "tornado-6.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4"}, 1472 | {file = "tornado-6.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd"}, 1473 | {file = "tornado-6.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01"}, 1474 | {file = "tornado-6.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d"}, 1475 | {file = "tornado-6.1-cp37-cp37m-win32.whl", hash = "sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df"}, 1476 | {file = "tornado-6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37"}, 1477 | {file = "tornado-6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95"}, 1478 | {file = "tornado-6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a"}, 1479 | {file = "tornado-6.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5"}, 1480 | {file = "tornado-6.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288"}, 1481 | {file = "tornado-6.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f"}, 1482 | {file = "tornado-6.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6"}, 1483 | {file = "tornado-6.1-cp38-cp38-win32.whl", hash = "sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326"}, 1484 | {file = "tornado-6.1-cp38-cp38-win_amd64.whl", hash = "sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c"}, 1485 | {file = "tornado-6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5"}, 1486 | {file = "tornado-6.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe"}, 1487 | {file = "tornado-6.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea"}, 1488 | {file = "tornado-6.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2"}, 1489 | {file = "tornado-6.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0"}, 1490 | {file = "tornado-6.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd"}, 1491 | {file = "tornado-6.1-cp39-cp39-win32.whl", hash = "sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c"}, 1492 | {file = "tornado-6.1-cp39-cp39-win_amd64.whl", hash = "sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4"}, 1493 | {file = "tornado-6.1.tar.gz", hash = "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791"}, 1494 | ] 1495 | tqdm = [ 1496 | {file = "tqdm-4.56.0-py2.py3-none-any.whl", hash = "sha256:4621f6823bab46a9cc33d48105753ccbea671b68bab2c50a9f0be23d4065cb5a"}, 1497 | {file = "tqdm-4.56.0.tar.gz", hash = "sha256:fe3d08dd00a526850568d542ff9de9bbc2a09a791da3c334f3213d8d0bbbca65"}, 1498 | ] 1499 | typed-ast = [ 1500 | {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"}, 1501 | {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"}, 1502 | {file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"}, 1503 | {file = "typed_ast-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400"}, 1504 | {file = "typed_ast-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606"}, 1505 | {file = "typed_ast-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64"}, 1506 | {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07"}, 1507 | {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc"}, 1508 | {file = "typed_ast-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a"}, 1509 | {file = "typed_ast-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151"}, 1510 | {file = "typed_ast-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3"}, 1511 | {file = "typed_ast-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41"}, 1512 | {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f"}, 1513 | {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581"}, 1514 | {file = "typed_ast-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37"}, 1515 | {file = "typed_ast-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd"}, 1516 | {file = "typed_ast-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496"}, 1517 | {file = "typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc"}, 1518 | {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"}, 1519 | {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea"}, 1520 | {file = "typed_ast-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787"}, 1521 | {file = "typed_ast-1.4.2-cp38-cp38-win32.whl", hash = "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2"}, 1522 | {file = "typed_ast-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937"}, 1523 | {file = "typed_ast-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1"}, 1524 | {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6"}, 1525 | {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166"}, 1526 | {file = "typed_ast-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d"}, 1527 | {file = "typed_ast-1.4.2-cp39-cp39-win32.whl", hash = "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b"}, 1528 | {file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"}, 1529 | {file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"}, 1530 | ] 1531 | typer = [ 1532 | {file = "typer-0.3.2-py3-none-any.whl", hash = "sha256:ba58b920ce851b12a2d790143009fa00ac1d05b3ff3257061ff69dbdfc3d161b"}, 1533 | {file = "typer-0.3.2.tar.gz", hash = "sha256:5455d750122cff96745b0dec87368f56d023725a7ebc9d2e54dd23dc86816303"}, 1534 | ] 1535 | typing-extensions = [ 1536 | {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, 1537 | {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, 1538 | {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, 1539 | ] 1540 | urllib3 = [ 1541 | {file = "urllib3-1.26.2-py2.py3-none-any.whl", hash = "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"}, 1542 | {file = "urllib3-1.26.2.tar.gz", hash = "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08"}, 1543 | ] 1544 | vulture = [ 1545 | {file = "vulture-2.3-py2.py3-none-any.whl", hash = "sha256:f39de5e6f1df1f70c3b50da54f1c8d494159e9ca3d01a9b89eac929600591703"}, 1546 | {file = "vulture-2.3.tar.gz", hash = "sha256:03d5a62bcbe9ceb9a9b0575f42d71a2d414070229f2e6f95fa6e7c71aaaed967"}, 1547 | ] 1548 | zipp = [ 1549 | {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, 1550 | {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, 1551 | ] 1552 | -------------------------------------------------------------------------------- /preconvert/__init__.py: -------------------------------------------------------------------------------- 1 | """A Library to enable preconversion of any Python type into one that is easily serializable""" 2 | import pkg_resources 3 | 4 | from preconvert import exceptions, output 5 | from preconvert.output.convert import default_serializer 6 | from preconvert.register import bson, converter, json, msgpack 7 | 8 | for plugin in pkg_resources.iter_entry_points("preconvert.converters"): 9 | plugin.load() 10 | 11 | __version__ = "0.0.6" 12 | __all__ = [ 13 | "converter", 14 | "json", 15 | "bson", 16 | "msgpack", 17 | "exceptions", 18 | "output", 19 | "default_serializer", 20 | "__version__", 21 | ] 22 | -------------------------------------------------------------------------------- /preconvert/converters.py: -------------------------------------------------------------------------------- 1 | import base64 2 | from datetime import date, datetime, timedelta 3 | from decimal import Decimal 4 | from enum import Enum 5 | from types import GeneratorType 6 | from typing import Any, Collection, Dict, Mapping, NamedTuple, Union 7 | from uuid import UUID 8 | 9 | from preconvert import register 10 | from preconvert.exceptions import Unconvertable 11 | 12 | try: 13 | import dataclasses 14 | 15 | dataclasses_loaded = True 16 | except ImportError: 17 | dataclasses_loaded = False 18 | 19 | if dataclasses_loaded: 20 | 21 | @register.converter(object) 22 | def convert_data_class(instance): 23 | if dataclasses.is_dataclass(instance): 24 | return dataclasses.asdict(instance) 25 | else: 26 | raise Unconvertable(instance) 27 | 28 | 29 | register.converter(Collection)(list) 30 | register.converter(GeneratorType)(tuple) 31 | register.converter(Mapping)(dict) 32 | register.converter(Decimal, UUID)(str) 33 | 34 | 35 | @register.converter(date, datetime) 36 | def datetime_converter(item): 37 | return item.isoformat() 38 | 39 | 40 | @register.converter(timedelta) 41 | def time_delta_converter(item): 42 | return item.total_seconds() 43 | 44 | 45 | @register.converter(Enum) 46 | def use_value_attribute(item): 47 | return item.value 48 | 49 | 50 | @register.converter(NamedTuple) 51 | def convert_namedtuple(instance: Any) -> Union[Dict, tuple]: 52 | """Converts a tuple of type namedtuple to a dict. 53 | This isn't registered as injecting this via registration won't work because it will never be 54 | falling through to as tuples convert to list. 55 | 56 | if the tuple isn't a named one, it will return the tuple unchanged 57 | """ 58 | if hasattr(instance, "_asdict"): 59 | return instance._asdict() 60 | 61 | return instance 62 | 63 | 64 | @register.converter(bytes) 65 | def byte_converter(item): 66 | try: 67 | return item.decode("utf8") 68 | except UnicodeDecodeError: 69 | return base64.b64encode(item) 70 | -------------------------------------------------------------------------------- /preconvert/exceptions.py: -------------------------------------------------------------------------------- 1 | """Defines all exceptions that can be thrown by the preconvert project""" 2 | 3 | 4 | class Error(Exception): 5 | """Base class for exceptions thrown from the preconvert project""" 6 | 7 | pass 8 | 9 | 10 | class ExistingConverter(Error): 11 | """Should be raised when a converter already exists for a specified type""" 12 | 13 | def __init__(self, kind, existing, new): 14 | super().__init__( 15 | self, 16 | ( 17 | "A new converter ({new}) is being registered for {kind} " 18 | "but an existing one exists already exists: {existing}. " 19 | "If intended, use override=True" 20 | ).format(kind=kind, existing=existing, new=new), 21 | ) 22 | 23 | self.kind = kind 24 | self.existing = existing 25 | self.new = new 26 | 27 | 28 | class Unconvertable(Error): 29 | """Raised when the provided item is not convertable using the provided converter(s)""" 30 | 31 | def __init__(self, item): 32 | super().__init__( 33 | self, 34 | "Object of type {} is not convertible " "into a serializable type".format(type(item)), 35 | ) 36 | self.item = item 37 | -------------------------------------------------------------------------------- /preconvert/output/__init__.py: -------------------------------------------------------------------------------- 1 | """Exposes all output formatters that have built-in support for preconversion 2 | 3 | Note: the interesting try: catch: pattern is done as their isn't a guarantee that the user has 4 | any of the given output formatters installed, which is required for preconvert to plug-in 5 | it's preconversion. 6 | """ 7 | from preconvert.output import convert, json 8 | 9 | try: 10 | from preconvert.output import bson 11 | except ImportError: 12 | pass 13 | 14 | try: 15 | from preconvert.output import msgpack 16 | except ImportError: 17 | pass 18 | 19 | try: 20 | from preconvert.output import simplejson 21 | except ImportError: 22 | pass 23 | -------------------------------------------------------------------------------- /preconvert/output/bson.py: -------------------------------------------------------------------------------- 1 | import bson 2 | from bson import * 3 | 4 | from preconvert.converters import convert_namedtuple 5 | from preconvert.output import convert 6 | 7 | 8 | def dumps(content, *args, on_unknown=convert.bson, **kwargs): # type: ignore 9 | """BSON dumps with preconversion for common unserializable types in place""" 10 | if isinstance(content, tuple): 11 | content = convert_namedtuple(content) 12 | return bson.dumps(content, on_unknown=on_unknown, *args, **kwargs) 13 | 14 | 15 | def dump(content, *args, on_unknown=convert.bson, **kwargs): # type: ignore 16 | """BSON dump with preconversion for common unserializable types in place""" 17 | if isinstance(content, tuple): 18 | content = convert_namedtuple(content) 19 | return bson.dump(content, on_unknown=on_unknown, *args, **kwargs) 20 | -------------------------------------------------------------------------------- /preconvert/output/convert.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | from functools import partial 3 | from itertools import chain 4 | from typing import Any, Callable, Dict, Iterable, Text, Union 5 | 6 | from preconvert.exceptions import Unconvertable 7 | from preconvert.register import converters 8 | 9 | 10 | class PreconversionSource(Enum): 11 | """All globally available conversion sources""" 12 | 13 | ALL_PACKAGES = 1 14 | PRECONVERT = 2 15 | 16 | 17 | def default_serializer( 18 | item: Any, 19 | namespace: Text = "base", 20 | base_namespace: Text = "base", 21 | using: Union[Iterable[Text], PreconversionSource] = PreconversionSource.ALL_PACKAGES, 22 | store: Dict[Text, Dict[Text, Dict[Any, Callable]]] = converters, 23 | ): 24 | if hasattr(item, "__preconvert__"): 25 | return item.__preconvert__() 26 | 27 | package_stores: Any 28 | if using == PreconversionSource.ALL_PACKAGES: 29 | package_stores = store.values() 30 | elif using == PreconversionSource.PRECONVERT: 31 | package_stores = (store["preconvert"],) 32 | elif isinstance(using, Iterable): 33 | package_stores = tuple(store[use_package] for use_package in using) 34 | 35 | if base_namespace and namespace != base_namespace: 36 | preconverters = chain( 37 | *( 38 | chain( 39 | package_store.get(namespace, {}).items(), 40 | package_store["base"].items(), 41 | ) 42 | for package_store in package_stores 43 | ) 44 | ) 45 | else: 46 | preconverters = chain(*(store[base_namespace].items() for package_store in package_stores)) 47 | 48 | for kind, transformer in reversed(tuple(preconverters)): 49 | if isinstance(item, kind): 50 | return transformer(item) 51 | 52 | if hasattr(item, "__iter__"): 53 | return list(item) 54 | 55 | raise Unconvertable(item) 56 | 57 | 58 | json = partial(default_serializer, namespace="json") 59 | bson = partial(default_serializer, namespace="bson") 60 | msgpack = partial(default_serializer, namespace="msgpack") 61 | -------------------------------------------------------------------------------- /preconvert/output/json.py: -------------------------------------------------------------------------------- 1 | import json 2 | from json import * 3 | 4 | from preconvert.converters import convert_namedtuple 5 | from preconvert.output import convert 6 | 7 | 8 | def dumps(content, *args, default=convert.json, **kwargs): # type: ignore 9 | """JSON dumps with preconversion for common unserializable types in place""" 10 | if isinstance(content, tuple): 11 | content = convert_namedtuple(content) 12 | return json.dumps(content, default=default, *args, **kwargs) 13 | 14 | 15 | def dump(content, *args, default=convert.json, **kwargs): # type: ignore 16 | """JSON dump with preconversion for common unserializable types in place""" 17 | if isinstance(content, tuple): 18 | content = convert_namedtuple(content) 19 | return json.dump(content, default=default, *args, **kwargs) 20 | -------------------------------------------------------------------------------- /preconvert/output/msgpack.py: -------------------------------------------------------------------------------- 1 | import msgpack 2 | from msgpack import * 3 | 4 | from preconvert.converters import convert_namedtuple 5 | from preconvert.output import convert 6 | 7 | 8 | def pack(content, *args, default=convert.msgpack, **kwargs): # type: ignore 9 | """Msgpacks with preconversion for common unserializable types in place""" 10 | if isinstance(content, tuple): 11 | content = convert_namedtuple(content) 12 | return msgpack.pack(content, default=default, *args, **kwargs) 13 | 14 | 15 | def packb(content, *args, default=convert.msgpack, **kwargs): # type: ignore 16 | """Msgpacks with preconversion for common unserializable types in place""" 17 | if isinstance(content, tuple): 18 | content = convert_namedtuple(content) 19 | return msgpack.packb(content, default=default, *args, **kwargs) 20 | 21 | 22 | def dump(content, *args, default=convert.msgpack, **kwargs): # type: ignore 23 | """Msgpack dump with preconversion for common unserializable types in place""" 24 | if isinstance(content, tuple): 25 | content = convert_namedtuple(content) 26 | return msgpack.dump(content, default=default, *args, **kwargs) 27 | 28 | 29 | def dumps(content, *args, default=convert.msgpack, **kwargs): # type: ignore 30 | """Msgpacks dump with preconversion for common unserializable types in place""" 31 | if isinstance(content, tuple): 32 | content = convert_namedtuple(content) 33 | return msgpack.dumps(content, default=default, *args, **kwargs) 34 | -------------------------------------------------------------------------------- /preconvert/output/simplejson.py: -------------------------------------------------------------------------------- 1 | from functools import partial 2 | 3 | import simplejson 4 | from simplejson import * 5 | 6 | from preconvert.output import convert 7 | 8 | dumps = partial(simplejson.dumps, default=convert.json) # type: ignore 9 | dump = partial(simplejson.dump, default=convert.json) # type: ignore 10 | -------------------------------------------------------------------------------- /preconvert/register.py: -------------------------------------------------------------------------------- 1 | """This module handles the registration of preconverters""" 2 | from collections import OrderedDict 3 | from enum import Enum 4 | from functools import partial 5 | from typing import Any, Callable, Dict, Text, Union 6 | 7 | from preconvert.exceptions import ExistingConverter 8 | 9 | converters: Dict[Text, Dict[Text, Dict[Text, Callable]]] = {"preconvert": {"base": OrderedDict()}} 10 | 11 | 12 | class AutoPackage(Enum): 13 | """Provides options for the automatic determination of a package name""" 14 | 15 | FUNCTION = 1 16 | PRECONVERT = 2 17 | FUNCTION_OR_PRECONVERT = 3 18 | 19 | 20 | def converter( 21 | *kinds: Any, 22 | scope: Text = "base", 23 | store: Dict[Text, Dict[Text, Dict[Text, Callable]]] = converters, 24 | override: bool = False, 25 | package: Union[Text, AutoPackage] = AutoPackage.FUNCTION_OR_PRECONVERT, 26 | ) -> Callable: 27 | """A decorator that registers the wrapped function as a pre-converter for the provided types 28 | in the provided `store` data structure or a default global one. 29 | 30 | Returns the decorated function unchanged. 31 | """ 32 | 33 | def register_converter(function): 34 | nonlocal package 35 | nonlocal scope 36 | 37 | if package == AutoPackage.FUNCTION_OR_PRECONVERT: 38 | package = getattr(function, "__package__", None) or "preconvert" 39 | if package == AutoPackage.FUNCTION: 40 | package = function.__package__ 41 | elif package == AutoPackage.PRECONVERT: 42 | package = "preconvert" 43 | 44 | package = store.setdefault(package, {}) 45 | scope = package.setdefault(scope, OrderedDict()) 46 | 47 | if not override: 48 | for kind in kinds: 49 | if kind in scope: 50 | raise ExistingConverter(kind, scope, function) 51 | 52 | for kind in kinds: # we redo this loop simply to guard against partial application 53 | scope[kind] = function 54 | 55 | return function 56 | 57 | return register_converter 58 | 59 | 60 | always = converter # Name alias to represent always converting for all serialization types. 61 | json = partial(converter, scope="json") 62 | bson = partial(converter, scope="bson") 63 | msgpack = partial(converter, scope="msgpack") 64 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "preconvert" 3 | version = "0.0.6" 4 | description = "A Library to enable preconversion of any Python type into one that is easily serializable" 5 | authors = ["Timothy Crosley "] 6 | license = "MIT" 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.6" 10 | 11 | [tool.poetry.dev-dependencies] 12 | black = "^20.8b1" 13 | isort = "^5.7.0" 14 | mypy = "^0.790" 15 | flake8 = "^3.8.4" 16 | safety = "^1.10.3" 17 | bandit = "^1.7.0" 18 | vulture = "^2.3" 19 | flake8-bugbear = "^20.11.1" 20 | pytest = "^6.2.1" 21 | mkdocs = "^1.1.2" 22 | pdoc3 = "^0.9.2" 23 | simplejson = "^3.17.2" 24 | msgpack = "^1.0.2" 25 | bson = "^0.5.10" 26 | mkdocs-material = "^6.2.5" 27 | pytest-coverage = "^0.0" 28 | preconvert_numpy = "^0.0.3" 29 | cruft = "^2.6.0" 30 | 31 | [build-system] 32 | requires = ["poetry-core>=1.0.0"] 33 | build-backend = "poetry.core.masonry.api" 34 | 35 | [tool.black] 36 | line-length = 100 37 | 38 | [tool.isort] 39 | profile = "hug" 40 | -------------------------------------------------------------------------------- /scripts/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | 4 | poetry run isort preconvert/ tests/ 5 | poetry run black preconvert/ tests/ 6 | -------------------------------------------------------------------------------- /scripts/done.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | 4 | ./scripts/clean.sh 5 | ./scripts/test.sh 6 | -------------------------------------------------------------------------------- /scripts/lint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | 4 | poetry run cruft check 5 | poetry run mypy --ignore-missing-imports preconvert/ 6 | poetry run isort --check --diff preconvert/ tests/ 7 | poetry run black --check preconvert/ tests/ 8 | poetry run flake8 preconvert/ tests/ 9 | poetry run safety check 10 | poetry run bandit -r preconvert/ 11 | -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | 4 | ./scripts/lint.sh 5 | poetry run pytest -s --cov=preconvert/ --cov=tests --cov-report=term-missing ${@-} --cov-report html 6 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 100 3 | extend-ignore = 4 | F401 # preconvert does a lot of imports to expand functionality 5 | F403 # preconvert heavily utilizes import * 6 | E203 # https://github.com/psf/black/blob/master/docs/the_black_code_style.md#slices 7 | -------------------------------------------------------------------------------- /templates/text.mako: -------------------------------------------------------------------------------- 1 | ## Define mini-templates for each portion of the doco. 2 | 3 | <%! 4 | def indent(s, spaces=4): 5 | new = s.replace('\n', '\n' + ' ' * spaces) 6 | return ' ' * spaces + new.strip() 7 | %> 8 | 9 | <%def name="deflist(s)">:${indent(s)[1:]} 10 | 11 | <%def name="h3(s)">### ${s} 12 | 13 | 14 | <%def name="function(func)" buffered="True"> 15 | <% 16 | returns = show_type_annotations and func.return_annotation() or '' 17 | if returns: 18 | returns = ' -> ' + returns 19 | %> 20 | ${"##### " + func.name} 21 | 22 | ```python3 23 | def ( 24 | ${",\n ".join(func.params(annotate=show_type_annotations))} 25 | )${returns} 26 | ``` 27 | ${func.docstring[2:]} 28 | 29 | 30 | <%def name="variable(var)" buffered="True"> 31 | ```python3 32 | ${var.name} 33 | ``` 34 | ${var.docstring | deflist} 35 | 36 | 37 | <%def name="class_(cls)" buffered="True"> 38 | ${"##### " + cls.name} 39 | 40 | ```python3 41 | class ( 42 | ${",\n ".join(cls.params(annotate=show_type_annotations))} 43 | ) 44 | ``` 45 | ${cls.docstring | deflist} 46 | <% 47 | class_vars = cls.class_variables(show_inherited_members, sort=sort_identifiers) 48 | static_methods = cls.functions(show_inherited_members, sort=sort_identifiers) 49 | inst_vars = cls.instance_variables(show_inherited_members, sort=sort_identifiers) 50 | methods = cls.methods(show_inherited_members, sort=sort_identifiers) 51 | mro = cls.mro() 52 | subclasses = cls.subclasses() 53 | %> 54 | % if mro: 55 | ${h3('Ancestors (in MRO)')} 56 | % for c in mro: 57 | * ${c.refname} 58 | % endfor 59 | 60 | % endif 61 | % if subclasses: 62 | ${h3('Descendants')} 63 | % for c in subclasses: 64 | * ${c.refname} 65 | % endfor 66 | 67 | % endif 68 | % if class_vars: 69 | ${h3('Class variables')} 70 | % for v in class_vars: 71 | ${variable(v) | indent} 72 | 73 | % endfor 74 | % endif 75 | % if static_methods: 76 | ${h3('Static methods')} 77 | % for f in static_methods: 78 | ${function(f) | indent} 79 | 80 | % endfor 81 | % endif 82 | % if inst_vars: 83 | ${h3('Instance variables')} 84 | % for v in inst_vars: 85 | ${variable(v) | indent} 86 | 87 | % endfor 88 | % endif 89 | % if methods: 90 | ${h3('Methods')} 91 | % for m in methods: 92 | ${function(m) | indent} 93 | 94 | % endfor 95 | % endif 96 | 97 | 98 | ## Start the output logic for an entire module. 99 | 100 | <% 101 | variables = module.variables() 102 | classes = module.classes() 103 | functions = module.functions() 104 | submodules = module.submodules() 105 | heading = 'Namespace' if module.is_namespace else 'Module' 106 | %> 107 | 108 | ${heading} ${module.name} 109 | =${'=' * (len(module.name) + len(heading))} 110 | ${module.docstring} 111 | 112 | 113 | % if submodules: 114 | Sub-modules 115 | ----------- 116 | % for m in submodules: 117 | * [${m.name}](${m.name.split(".")[-1]}) 118 | % endfor 119 | % endif 120 | 121 | % if variables: 122 | Variables 123 | --------- 124 | % for v in variables: 125 | ${variable(v)} 126 | 127 | % endfor 128 | % endif 129 | 130 | % if functions: 131 | Functions 132 | --------- 133 | % for f in functions: 134 | ${function(f)} 135 | 136 | % endfor 137 | % endif 138 | 139 | % if classes: 140 | Classes 141 | ------- 142 | % for c in classes: 143 | ${class_(c)} 144 | 145 | % endfor 146 | % endif 147 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | 3 | ./lint.sh 4 | pipenv run pytest -s --cov=preconvert --cov=tests --cov-report=term-missing ${@} 5 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timothycrosley/preconvert/828a35998908162695543ae7781b0527485cda77/tests/__init__.py -------------------------------------------------------------------------------- /tests/constants.py: -------------------------------------------------------------------------------- 1 | """Provides constants that can be used across all test cases""" 2 | import os 3 | 4 | TEST_DIRECTORY = os.path.dirname(os.path.realpath(__file__)) 5 | BASE_DIRECTORY = os.path.realpath(os.path.join(TEST_DIRECTORY, "..")) 6 | -------------------------------------------------------------------------------- /tests/test_output.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | from collections import namedtuple 4 | from datetime import datetime, timedelta 5 | from decimal import Decimal 6 | 7 | import pytest 8 | 9 | import preconvert 10 | from preconvert import converters 11 | 12 | from .constants import BASE_DIRECTORY 13 | 14 | 15 | def test_json(): 16 | """Tests outputting a variety of Python data types to JSON using preconvert""" 17 | now = datetime.now() 18 | one_day = timedelta(days=1) 19 | test_data = {"text": "text", "datetime": now, "bytes": b"bytes", "delta": one_day} 20 | output = preconvert.output.json.dumps(test_data) 21 | assert "text" in output 22 | assert "bytes" in output 23 | assert str(one_day.total_seconds()) in output 24 | assert now.isoformat() in output 25 | 26 | class NewObject(object): 27 | pass 28 | 29 | test_data["non_serializable"] = NewObject() 30 | with pytest.raises(preconvert.exceptions.Unconvertable): 31 | preconvert.output.json.dumps(test_data) 32 | 33 | class NamedTupleObject(namedtuple("BaseTuple", ("name", "value"))): 34 | pass 35 | 36 | data = NamedTupleObject("name", "value") 37 | converted = json.loads(preconvert.output.json.dumps(data)) 38 | assert converted == {"name": "name", "value": "value"} 39 | 40 | data = set((1, 2, 3, 3)) 41 | assert json.loads(preconvert.output.json.dumps(data)) == [1, 2, 3] 42 | 43 | data = (number for number in range(1, 4)) 44 | assert json.loads(preconvert.output.json.dumps(data)) == [1, 2, 3] 45 | 46 | data = [Decimal(1.5), Decimal("155.23"), Decimal("1234.25")] 47 | assert json.loads(preconvert.output.json.dumps(data)) == [ 48 | "1.5", 49 | "155.23", 50 | "1234.25", 51 | ] 52 | 53 | assert json.loads(preconvert.output.json.dumps(b"a", ensure_ascii=True)) == "a" 54 | 55 | class MyCrazyObject(object): 56 | pass 57 | 58 | @preconvert.converter(MyCrazyObject) 59 | def convert(instance): 60 | return "Like anyone could convert this" 61 | 62 | crazy_object_json = json.loads(preconvert.output.json.dumps(MyCrazyObject())) 63 | assert crazy_object_json == "Like anyone could convert this" 64 | 65 | assert json.loads( 66 | preconvert.output.json.dumps( 67 | {"data": ["Τη γλώσσα μου έδωσαν ελληνική"]}, ensure_ascii=False 68 | ) 69 | ) == {"data": ["Τη γλώσσα μου έδωσαν ελληνική"]} 70 | -------------------------------------------------------------------------------- /update_docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | 3 | wget https://raw.githubusercontent.com/hugapi/HOPE/master/all/HOPE-8--Style-Guide-for-Hug-Code.md -O docs/CODING_STANDARD.md 4 | wget https://raw.githubusercontent.com/hugapi/HOPE/master/all/HOPE-11-Code-of-Conduct.md -O docs/CODE_OF_CONDUCT.md 5 | pipenv run pdoc3 -o docs preconvert --template-dir templates --force -c show_type_annotations=True 6 | pipenv run mkdocs gh-deploy 7 | --------------------------------------------------------------------------------