diff --git a/.flake8 b/.flake8 index 321a3929..60b05147 100644 --- a/.flake8 +++ b/.flake8 @@ -1,18 +1,19 @@ [flake8] -select = C,D,E,F,W +select = B,B9,C,D,E,F,N,S,W max-complexity = 10 docstring-convention = google exclude = .venv,.git,.tox,docs,venv,bin,lib,deps,build,.eggs +max-line-length = 80 -# To work with Black -max-line-length = 88 -# E501: line too long -# W503: Line break occurred before a binary operator +# E501: line too long => covered by B950 +# W503: Line break occurred before a binary operator => Disabled for Black compatibility # E203: Whitespace before ':' # D202 No blank lines allowed after function docstring # W504 line break after binary operator -ignore = W503 -# E501, +ignore = W503, E501 # E203, # D202, # W504 + +# For avoiding issue with bandit +per-file-ignores = tests/*:S101 diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 6bcce42f..a09db44f 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,7 +1,6 @@ --- name: Feature request about: Suggest an idea for this project - --- **Is your feature request related to a problem? Please describe.** @@ -14,4 +13,4 @@ A clear and concise description of what you want to happen. A clear and concise description of any alternative solutions or features you've considered. **Additional context** -Add any other context or screenshots about the feature request here. \ No newline at end of file +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/issue.md b/.github/ISSUE_TEMPLATE/issue.md index 67edf36c..5793e974 100644 --- a/.github/ISSUE_TEMPLATE/issue.md +++ b/.github/ISSUE_TEMPLATE/issue.md @@ -1,13 +1,13 @@ --- name: Issue about: Create a report to help us improve - --- **Describe the bug** A clear and concise description of what the bug is. **log** + ``` Add your logs here. -``` \ No newline at end of file +``` diff --git a/.github/stale.yml b/.github/stale.yml index 78973bca..239ed5cf 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -13,4 +13,4 @@ markComment: > This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. # Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false \ No newline at end of file +closeComment: false diff --git a/.gitignore b/.gitignore index 6893bef0..23a1fdb6 100644 --- a/.gitignore +++ b/.gitignore @@ -129,4 +129,4 @@ dmypy.json .pyre/ # Editor -/.vscode \ No newline at end of file +/.vscode diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..991a0ec2 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,51 @@ +repos: + - repo: local + hooks: + - id: black + name: black + entry: black + language: system + types: [python] + require_serial: true + - id: flake8 + name: flake8 + entry: flake8 + language: system + types: [python] + require_serial: true + - id: check-added-large-files + name: Check for added large files + entry: check-added-large-files + language: system + - id: check-toml + name: Check Toml + entry: check-toml + language: system + types: [toml] + - id: check-yaml + name: Check Yaml + entry: check-yaml + language: system + types: [yaml] + - id: end-of-file-fixer + name: Fix End of Files + entry: end-of-file-fixer + language: system + types: [text] + stages: [commit, push, manual] + - id: trailing-whitespace + name: Trim Trailing Whitespace + entry: trailing-whitespace-fixer + language: system + types: [text] + stages: [commit, push, manual] + - id: reorder-python-imports + name: Reorder python imports + entry: reorder-python-imports + language: system + types: [python] + args: [--application-directories=src] + - repo: https://github.com/prettier/prettier + rev: 2.0.5 + hooks: + - id: prettier diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9cbd4be8..56251df5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,8 +15,8 @@ en participant à la documentation. Vous aurez besoin de Python 3.6+ et des outils suivants: -- [Poetry](https://python-poetry.org) -- [Nox](https://nox.thea.codes/en/stable) +- [Poetry](https://python-poetry.org) +- [Nox](https://nox.thea.codes/en/stable) Installez le package avec les dépendances de développement: @@ -26,6 +26,10 @@ Vous pouvez maintenant utiliser une session interactive Python: `$ poetry run python` +Je vous recommande d'installer un pre-commit-hook pour lancer automatiquement quelques vérfication avant de commit vos modifications. + +`$ nox -s pre-commit -- install` + ## Tester le projet Dérouler la suite de tests complète: @@ -45,12 +49,12 @@ Les tests unitaires sont dans le répertoire `tests` et utilisent le framework p ### Soumettre votre Pull Request (PR) -Oouvrez une [pull requet](https://github.com/hacf-fr/meteofrance-api/pulls) pour proposer des changements à ce projet. +Ouvrez une [pull request](https://github.com/hacf-fr/meteofrance-api/pulls) pour proposer des changements à ce projet. Votre pull request doit vérifier les conditions suivantes pour être acceptée: -- La suite de tests Nox doit réussir sans erreurs ni warning. -- Doit inclure des tests unitaires. Ce projet maintien une couverture de code à 100%. +- La suite de tests Nox doit réussir sans erreurs ni warning. +- Doit inclure des tests unitaires. Ce projet maintien une couverture de code à 100%. ### Proposer une nouvelle fonctionnalité @@ -67,8 +71,8 @@ improvements ideas, or contribute to the documentation. You need Python 3.6+ and the following tools: -- [Poetry](https://python-poetry.org) -- [Nox](https://nox.thea.codes/en/stable) +- [Poetry](https://python-poetry.org) +- [Nox](https://nox.thea.codes/en/stable) Install the package with development requirements: @@ -78,6 +82,10 @@ You can now run an interactive Python session, or the command-line interface: `$ poetry run python` +I recommand to install a pre-commit-hook to have some checks done automatically before you commit your changes. + +`$ nox -s pre-commit -- install` + ### How to test the project Run the full test suite: @@ -96,12 +104,12 @@ Unit tests are located in the tests directory, and are written using the pytest ### How to submit changes -Open a [pull requet](https://github.com/hacf-fr/meteofrance-api/pulls) to submit changes to this project. +Open a [pull request](https://github.com/hacf-fr/meteofrance-api/pulls) to submit changes to this project. Your pull request needs to meet the following guidelines for acceptance: -- The Nox test suite must pass without errors and warnings. -- Include unit tests. This project maintains 100% code coverage. +- The Nox test suite must pass without errors and warnings. +- Include unit tests. This project maintains 100% code coverage. ### Feature suggestion diff --git a/README.md b/README.md index 690ca204..d5e0772f 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,12 @@ Météo-France utilisée par les applications moblies officielles. Le client permet: -- Rechercher des lieux de prévisions. -- Accéder aux prévisions météorologiques horraires ou quotidiennes. -- Accéder aux prévisions de pluie dans l'heure quand disponibles. -- Accéder aux alertes météo pour chaque département français et l'Andorre. Deux - bulletins sont disponibles : un synthétique et un second avec l'évolution des alertes - pour les prochaines 24 heures (exemple [ici](http://vigilance.meteofrance.com/Bulletin_sans.html?a=dept32&b=2&c=)). +- Rechercher des lieux de prévisions. +- Accéder aux prévisions météorologiques horraires ou quotidiennes. +- Accéder aux prévisions de pluie dans l'heure quand disponibles. +- Accéder aux alertes météo pour chaque département français et l'Andorre. Deux + bulletins sont disponibles : un synthétique et un second avec l'évolution des alertes + pour les prochaines 24 heures (exemple [ici](http://vigilance.meteofrance.com/Bulletin_sans.html?a=dept32&b=2&c=)). Ce package a été développé avec l'intention d'être utilisé par [Home-Assistant](https://home-assistant.io/) mais il peut être utilsé dans d'autres contextes. @@ -55,17 +55,17 @@ used by the official moblie applications. The client allows: -- Search a forecast location. -- Fetch daily or hourly weather forecast. -- Fetch rain forecast within the next hour if available. -- Fetch the weather alerts or phenomenoms for each French department or Andorre. - Two bulletin are availabe: one basic and an other advanced with the timelaps evolution for the next 24 hours (example [here](http://vigilance.meteofrance.com/Bulletin_sans.html?a=dept32&b=2&c=)). +- Search a forecast location. +- Fetch daily or hourly weather forecast. +- Fetch rain forecast within the next hour if available. +- Fetch the weather alerts or phenomenoms for each French department or Andorre. + Two bulletin are availabe: one basic and an other advanced with the timelaps evolution for the next 24 hours (example [here](http://vigilance.meteofrance.com/Bulletin_sans.html?a=dept32&b=2&c=)). This package have been developed to be used with [Home-Assistant](https://home-assistant.io/) but it can be used in other contexts. ### Installation -To use the `meteofrance` Python module, you have to install this package first: +To use the `meteofrance` Python module, you have to install this package first: `pip install meteofrance-api` @@ -76,23 +76,13 @@ You will find an example ot usage in a Python program in the [integration test]( Contributions are welcomed. Please check the guidelines in [`CONTRIBUTING.md`](CONTRIBUTING.md). [commits-shield]: https://img.shields.io/github/commit-activity/y/hacf-fr/meteofrance-api.svg?style=for-the-badge - [commits]: https://github.com/hacf-fr/meteofrance-api/commits/master - [license-shield]: https://img.shields.io/github/license/hacf-fr/meteofrance-api.svg?style=for-the-badge - [releases-shield]: https://img.shields.io/github/release/hacf-fr/meteofrance-api.svg?style=for-the-badge - [releases]: https://github.com/hacf-fr/meteofrance-api/releases - [build-shield]: https://img.shields.io/github/workflow/status/hacf-fr/meteofrance-api/Python%20package?style=for-the-badge - [build]: https://github.com/hacf-fr/meteofrance-api/actions?query=workflow%3A%22Python+package%22 - [codecov-shield]: https://img.shields.io/codecov/c/github/hacf-fr/meteofrance-api?style=for-the-badge - [codecov]: https://codecov.io/gh/hacf-fr/meteofrance-api - [pypi-shield]: https://img.shields.io/pypi/v/meteofrance-api?style=for-the-badge - [pypi]: https://pypi.org/project/meteofrance-api/ diff --git a/noxfile.py b/noxfile.py index f425d5f1..c7f0e9dd 100644 --- a/noxfile.py +++ b/noxfile.py @@ -2,14 +2,16 @@ import contextlib import tempfile from pathlib import Path -from typing import Iterator, cast +from textwrap import dedent +from typing import cast +from typing import Iterator import nox from nox.sessions import Session python_versions = ["3.8", "3.7", "3.6"] package = "meteofrance_api" -nox.options.sessions = "lint", "tests" +nox.options.sessions = "pre-commit", "safety", "tests" locations = "src", "tests", "noxfile.py" @@ -107,6 +109,87 @@ def install(session: Session, *args: str) -> None: session.install(f"--constraint={requirements}", *args) +def activate_virtualenv_in_precommit_hooks(session: Session) -> None: + """Activate virtualenv in hooks installed by pre-commit. + + This function patches git hooks installed by pre-commit to activate the + session's virtual environment. This allows pre-commit to locate hooks in + that environment when invoked from git. + + Args: + session: The Session object. + """ + if session.bin is None: + return + + virtualenv = session.env.get("VIRTUAL_ENV") + if virtualenv is None: + return + + hookdir = Path(".git") / "hooks" + if not hookdir.is_dir(): + return + + for hook in hookdir.iterdir(): + if hook.name.endswith(".sample") or not hook.is_file(): + continue + + text = hook.read_text() + bindir = repr(session.bin)[1:-1] # strip quotes + if not ( + Path("A") == Path("a") and bindir.lower() in text.lower() or bindir in text + ): + continue + + lines = text.splitlines() + if not (lines[0].startswith("#!") and "python" in lines[0].lower()): + continue + + header = dedent( + f"""\ + import os + os.environ["VIRTUAL_ENV"] = {virtualenv!r} + os.environ["PATH"] = os.pathsep.join(( + {session.bin!r}, + os.environ.get("PATH", ""), + )) + """ + ) + + lines.insert(1, header) + hook.write_text("\n".join(lines)) + + +@nox.session(name="pre-commit", python="3.8") +def precommit(session: Session) -> None: + """Lint using pre-commit.""" + args = session.posargs or ["run", "--all-files", "--show-diff-on-failure"] + install( + session, + "black", + "flake8", + "flake8-bandit", + "flake8-bugbear", + "flake8-docstrings", + "pep8-naming", + "pre-commit", + "pre-commit-hooks", + "reorder-python-imports", + ) + session.run("pre-commit", *args) + if args and args[0] == "install": + activate_virtualenv_in_precommit_hooks(session) + + +@nox.session(python="3.8") +def safety(session: Session) -> None: + """Scan dependencies for insecure packages.""" + poetry = Poetry(session) + with poetry.export("--dev", "--without-hashes") as requirements: + install(session, "safety") + session.run("safety", "check", f"--file={requirements}", "--bare") + + @nox.session(python=python_versions) def tests(session: Session) -> None: """Run the test suite.""" @@ -118,15 +201,6 @@ def tests(session: Session) -> None: session.notify("coverage") -@nox.session(python=python_versions) -def lint(session): - """Lint using flake8.""" - args = session.posargs or locations - install_package(session) - install(session, "flake8", "flake8-docstrings") - session.run("flake8", *args) - - @nox.session def coverage(session: Session) -> None: """Produce the coverage report.""" diff --git a/poetry.lock b/poetry.lock index 144ed7eb..5fc886ba 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,3 +1,22 @@ +[[package]] +category = "dev" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +name = "appdirs" +optional = false +python-versions = "*" +version = "1.4.4" + +[[package]] +category = "dev" +description = "Utilities for refactoring imports in python-like syntax." +name = "aspy.refactor-imports" +optional = false +python-versions = ">=3.6.1" +version = "2.1.1" + +[package.dependencies] +cached-property = "*" + [[package]] category = "dev" description = "Atomic file writes." @@ -21,6 +40,49 @@ dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.int docs = ["sphinx", "zope.interface"] tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +[[package]] +category = "dev" +description = "Security oriented static analyser for python code." +name = "bandit" +optional = false +python-versions = "*" +version = "1.6.2" + +[package.dependencies] +GitPython = ">=1.0.1" +PyYAML = ">=3.13" +colorama = ">=0.3.9" +six = ">=1.10.0" +stevedore = ">=1.20.0" + +[[package]] +category = "dev" +description = "The uncompromising code formatter." +name = "black" +optional = false +python-versions = ">=3.6" +version = "19.10b0" + +[package.dependencies] +appdirs = "*" +attrs = ">=18.1.0" +click = ">=6.5" +pathspec = ">=0.6,<1" +regex = "*" +toml = ">=0.9.4" +typed-ast = ">=1.4.0" + +[package.extras] +d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] + +[[package]] +category = "dev" +description = "A decorator for caching properties in classes." +name = "cached-property" +optional = false +python-versions = "*" +version = "1.5.1" + [[package]] category = "main" description = "Python package for providing Mozilla's CA Bundle." @@ -29,6 +91,14 @@ optional = false python-versions = "*" version = "2020.6.20" +[[package]] +category = "dev" +description = "Validate configuration and produce human readable error messages." +name = "cfgv" +optional = false +python-versions = ">=3.6.1" +version = "3.1.0" + [[package]] category = "main" description = "Universal encoding detector for Python 2 and 3" @@ -37,6 +107,14 @@ optional = false python-versions = "*" version = "3.0.4" +[[package]] +category = "dev" +description = "Composable command line interface toolkit" +name = "click" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "7.1.2" + [[package]] category = "dev" description = "Hosted coverage reports for GitHub, Bitbucket and Gitlab" @@ -52,7 +130,7 @@ requests = ">=2.7.9" [[package]] category = "dev" description = "Cross-platform colored terminal text." -marker = "sys_platform == \"win32\"" +marker = "sys_platform == \"win32\" or platform_system == \"Windows\"" name = "colorama" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -74,6 +152,38 @@ version = "*" [package.extras] toml = ["toml"] +[[package]] +category = "dev" +description = "Distribution utilities" +name = "distlib" +optional = false +python-versions = "*" +version = "0.3.1" + +[[package]] +category = "dev" +description = "A parser for Python dependency files" +name = "dparse" +optional = false +python-versions = ">=3.5" +version = "0.5.1" + +[package.dependencies] +packaging = "*" +pyyaml = "*" +toml = "*" + +[package.extras] +pipenv = ["pipenv"] + +[[package]] +category = "dev" +description = "A platform independent file lock." +name = "filelock" +optional = false +python-versions = "*" +version = "3.0.12" + [[package]] category = "dev" description = "the modular source code checker: pep8 pyflakes and co" @@ -91,6 +201,32 @@ pyflakes = ">=2.2.0,<2.3.0" python = "<3.8" version = "*" +[[package]] +category = "dev" +description = "Automated security testing with bandit and flake8." +name = "flake8-bandit" +optional = false +python-versions = "*" +version = "2.1.2" + +[package.dependencies] +bandit = "*" +flake8 = "*" +flake8-polyfill = "*" +pycodestyle = "*" + +[[package]] +category = "dev" +description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." +name = "flake8-bugbear" +optional = false +python-versions = ">=3.6" +version = "20.1.4" + +[package.dependencies] +attrs = ">=19.2.0" +flake8 = ">=3.0.0" + [[package]] category = "dev" description = "Extension for flake8 which uses pydocstyle to check docstrings" @@ -103,6 +239,50 @@ version = "1.5.0" flake8 = ">=3" pydocstyle = ">=2.1" +[[package]] +category = "dev" +description = "Polyfill package for Flake8 plugins" +name = "flake8-polyfill" +optional = false +python-versions = "*" +version = "1.0.2" + +[package.dependencies] +flake8 = "*" + +[[package]] +category = "dev" +description = "Git Object Database" +name = "gitdb" +optional = false +python-versions = ">=3.4" +version = "4.0.5" + +[package.dependencies] +smmap = ">=3.0.1,<4" + +[[package]] +category = "dev" +description = "Python Git Library" +name = "gitpython" +optional = false +python-versions = ">=3.4" +version = "3.1.7" + +[package.dependencies] +gitdb = ">=4.0.1,<5" + +[[package]] +category = "dev" +description = "File identification library for Python" +name = "identify" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +version = "1.4.25" + +[package.extras] +license = ["editdistance"] + [[package]] category = "main" description = "Internationalized Domain Names in Applications (IDNA)" @@ -127,6 +307,23 @@ zipp = ">=0.5" docs = ["sphinx", "rst.linker"] testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] +[[package]] +category = "dev" +description = "Read resources from Python packages" +marker = "python_version < \"3.7\"" +name = "importlib-resources" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +version = "3.0.0" + +[package.dependencies] +[package.dependencies.zipp] +python = "<3.8" +version = ">=0.4" + +[package.extras] +docs = ["sphinx", "rst.linker", "jaraco.packaging"] + [[package]] category = "dev" description = "McCabe checker, plugin for flake8" @@ -143,6 +340,14 @@ optional = false python-versions = ">=3.5" version = "8.4.0" +[[package]] +category = "dev" +description = "Node.js virtual environment builder" +name = "nodeenv" +optional = false +python-versions = "*" +version = "1.4.0" + [[package]] category = "dev" description = "Core utilities for Python packages" @@ -155,6 +360,33 @@ version = "20.4" pyparsing = ">=2.0.2" six = "*" +[[package]] +category = "dev" +description = "Utility library for gitignore style pattern matching of file paths." +name = "pathspec" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.8.0" + +[[package]] +category = "dev" +description = "Python Build Reasonableness" +name = "pbr" +optional = false +python-versions = "*" +version = "5.4.5" + +[[package]] +category = "dev" +description = "Check PEP-8 naming conventions, plugin for flake8" +name = "pep8-naming" +optional = false +python-versions = "*" +version = "0.11.1" + +[package.dependencies] +flake8-polyfill = ">=1.0.2,<2" + [[package]] category = "dev" description = "plugin and hook calling mechanisms for python" @@ -171,6 +403,42 @@ version = ">=0.12" [package.extras] dev = ["pre-commit", "tox"] +[[package]] +category = "dev" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +name = "pre-commit" +optional = false +python-versions = ">=3.6.1" +version = "2.6.0" + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +toml = "*" +virtualenv = ">=20.0.8" + +[package.dependencies.importlib-metadata] +python = "<3.8" +version = "*" + +[package.dependencies.importlib-resources] +python = "<3.7" +version = "*" + +[[package]] +category = "dev" +description = "Some out-of-the-box hooks for pre-commit." +name = "pre-commit-hooks" +optional = false +python-versions = ">=3.6.1" +version = "3.1.0" + +[package.dependencies] +"ruamel.yaml" = ">=0.15" +toml = "*" + [[package]] category = "dev" description = "library with cross-python path, ini-parsing, io, code, log facilities" @@ -263,6 +531,33 @@ optional = false python-versions = "*" version = "2020.1" +[[package]] +category = "dev" +description = "YAML parser and emitter for Python" +name = "pyyaml" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "5.3.1" + +[[package]] +category = "dev" +description = "Alternative regular expression module, to replace re." +name = "regex" +optional = false +python-versions = "*" +version = "2020.7.14" + +[[package]] +category = "dev" +description = "Tool for reordering python imports" +name = "reorder-python-imports" +optional = false +python-versions = ">=3.6.1" +version = "2.3.4" + +[package.dependencies] +"aspy.refactor-imports" = ">=2.1.0" + [[package]] category = "main" description = "Python HTTP for Humans." @@ -297,6 +592,47 @@ six = "*" fixture = ["fixtures"] test = ["fixtures", "mock", "purl", "pytest", "sphinx", "testrepository (>=0.0.18)", "testtools"] +[[package]] +category = "dev" +description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +name = "ruamel.yaml" +optional = false +python-versions = "*" +version = "0.16.10" + +[package.dependencies] +[package.dependencies."ruamel.yaml.clib"] +python = "<3.9" +version = ">=0.1.2" + +[package.extras] +docs = ["ryd"] +jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] + +[[package]] +category = "dev" +description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" +marker = "platform_python_implementation == \"CPython\" and python_version < \"3.9\"" +name = "ruamel.yaml.clib" +optional = false +python-versions = "*" +version = "0.2.0" + +[[package]] +category = "dev" +description = "Checks installed dependencies for known vulnerabilities." +name = "safety" +optional = false +python-versions = ">=3.5" +version = "1.9.0" + +[package.dependencies] +Click = ">=6.0" +dparse = ">=0.5.1" +packaging = "*" +requests = "*" +setuptools = "*" + [[package]] category = "dev" description = "Python 2 and 3 compatibility utilities" @@ -305,6 +641,14 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" version = "1.15.0" +[[package]] +category = "dev" +description = "A pure Python implementation of a sliding window memory map manager" +name = "smmap" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "3.0.4" + [[package]] category = "dev" description = "This package provides 26 stemmers for 25 languages generated from Snowball algorithms." @@ -313,6 +657,21 @@ optional = false python-versions = "*" version = "2.0.0" +[[package]] +category = "dev" +description = "Manage dynamic plugins for Python applications" +name = "stevedore" +optional = false +python-versions = ">=3.6" +version = "3.2.0" + +[package.dependencies] +pbr = ">=2.0.0,<2.1.0 || >2.1.0" + +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=1.7.0" + [[package]] category = "dev" description = "Python Library for Tom's Obvious, Minimal Language" @@ -321,6 +680,14 @@ optional = false python-versions = "*" version = "0.10.1" +[[package]] +category = "dev" +description = "a fork of Python 2 and 3 ast modules with type comment support" +name = "typed-ast" +optional = false +python-versions = "*" +version = "1.4.1" + [[package]] category = "main" description = "HTTP library with thread-safe connection pooling, file post, and more." @@ -334,6 +701,32 @@ brotli = ["brotlipy (>=0.6.0)"] secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"] socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] +[[package]] +category = "dev" +description = "Virtual Python Environment builder" +name = "virtualenv" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +version = "20.0.28" + +[package.dependencies] +appdirs = ">=1.4.3,<2" +distlib = ">=0.3.1,<1" +filelock = ">=3.0.0,<4" +six = ">=1.9.0,<2" + +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=0.12,<2" + +[package.dependencies.importlib-resources] +python = "<3.7" +version = ">=1.0" + +[package.extras] +docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"] +testing = ["coverage (>=5)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "pytest-xdist (>=1.31.0)", "packaging (>=20.0)", "xonsh (>=0.9.16)"] + [[package]] category = "dev" description = "Measures the displayed width of unicode strings in a terminal" @@ -356,10 +749,18 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["jaraco.itertools", "func-timeout"] [metadata] -content-hash = "b2d2c9cdca0ee4823df524bd87b755788dde849df30ef7c366f6bf68a124e5bf" -python-versions = "^3.6" +content-hash = "c57b5c4cde2414b4374c41059dfcc1c2a3c23cb58bc5e36a888ec0fa2ebc6705" +python-versions = "^3.6.1" [metadata.files] +appdirs = [ + {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, + {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, +] +"aspy.refactor-imports" = [ + {file = "aspy.refactor_imports-2.1.1-py2.py3-none-any.whl", hash = "sha256:9df76bf19ef81620068b785a386740ab3c8939fcbdcebf20c4a4e0057230d782"}, + {file = "aspy.refactor_imports-2.1.1.tar.gz", hash = "sha256:eec8d1a73bedf64ffb8b589ad919a030c1fb14acf7d1ce0ab192f6eedae895c5"}, +] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, @@ -368,14 +769,34 @@ attrs = [ {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, ] +bandit = [ + {file = "bandit-1.6.2-py2.py3-none-any.whl", hash = "sha256:336620e220cf2d3115877685e264477ff9d9abaeb0afe3dc7264f55fa17a3952"}, + {file = "bandit-1.6.2.tar.gz", hash = "sha256:41e75315853507aa145d62a78a2a6c5e3240fe14ee7c601459d0df9418196065"}, +] +black = [ + {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"}, + {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"}, +] +cached-property = [ + {file = "cached-property-1.5.1.tar.gz", hash = "sha256:9217a59f14a5682da7c4b8829deadbfc194ac22e9908ccf7c8820234e80a1504"}, + {file = "cached_property-1.5.1-py2.py3-none-any.whl", hash = "sha256:3a026f1a54135677e7da5ce819b0c690f156f37976f3e30c5430740725203d7f"}, +] certifi = [ {file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"}, {file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"}, ] +cfgv = [ + {file = "cfgv-3.1.0-py2.py3-none-any.whl", hash = "sha256:1ccf53320421aeeb915275a196e23b3b8ae87dea8ac6698b1638001d4a486d53"}, + {file = "cfgv-3.1.0.tar.gz", hash = "sha256:c8e8f552ffcc6194f4e18dd4f68d9aef0c0d58ae7e7be8c82bee3c5e9edfa513"}, +] chardet = [ {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, ] +click = [ + {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, + {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, +] codecov = [ {file = "codecov-2.1.8-py2.py3-none-any.whl", hash = "sha256:65e8a8008e43eb45a9404bf68f8d4a60d36de3827ef2287971c94940128eba1e"}, {file = "codecov-2.1.8-py3.8.egg", hash = "sha256:fa7985ac6a3886cf68e3420ee1b5eb4ed30c4bdceec0f332d17ab69f545fbc90"}, @@ -421,14 +842,49 @@ coverage = [ {file = "coverage-5.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:b8f58c7db64d8f27078cbf2a4391af6aa4e4767cc08b37555c4ae064b8558d9b"}, {file = "coverage-5.2.1.tar.gz", hash = "sha256:a34cb28e0747ea15e82d13e14de606747e9e484fb28d63c999483f5d5188e89b"}, ] +distlib = [ + {file = "distlib-0.3.1-py2.py3-none-any.whl", hash = "sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb"}, + {file = "distlib-0.3.1.zip", hash = "sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1"}, +] +dparse = [ + {file = "dparse-0.5.1-py3-none-any.whl", hash = "sha256:e953a25e44ebb60a5c6efc2add4420c177f1d8404509da88da9729202f306994"}, + {file = "dparse-0.5.1.tar.gz", hash = "sha256:a1b5f169102e1c894f9a7d5ccf6f9402a836a5d24be80a986c7ce9eaed78f367"}, +] +filelock = [ + {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, + {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, +] flake8 = [ {file = "flake8-3.8.3-py2.py3-none-any.whl", hash = "sha256:15e351d19611c887e482fb960eae4d44845013cc142d42896e9862f775d8cf5c"}, {file = "flake8-3.8.3.tar.gz", hash = "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208"}, ] +flake8-bandit = [ + {file = "flake8_bandit-2.1.2.tar.gz", hash = "sha256:687fc8da2e4a239b206af2e54a90093572a60d0954f3054e23690739b0b0de3b"}, +] +flake8-bugbear = [ + {file = "flake8-bugbear-20.1.4.tar.gz", hash = "sha256:bd02e4b009fb153fe6072c31c52aeab5b133d508095befb2ffcf3b41c4823162"}, + {file = "flake8_bugbear-20.1.4-py36.py37.py38-none-any.whl", hash = "sha256:a3ddc03ec28ba2296fc6f89444d1c946a6b76460f859795b35b77d4920a51b63"}, +] flake8-docstrings = [ {file = "flake8-docstrings-1.5.0.tar.gz", hash = "sha256:3d5a31c7ec6b7367ea6506a87ec293b94a0a46c0bce2bb4975b7f1d09b6f3717"}, {file = "flake8_docstrings-1.5.0-py2.py3-none-any.whl", hash = "sha256:a256ba91bc52307bef1de59e2a009c3cf61c3d0952dbe035d6ff7208940c2edc"}, ] +flake8-polyfill = [ + {file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"}, + {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, +] +gitdb = [ + {file = "gitdb-4.0.5-py3-none-any.whl", hash = "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac"}, + {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"}, +] +gitpython = [ + {file = "GitPython-3.1.7-py3-none-any.whl", hash = "sha256:fa3b92da728a457dd75d62bb5f3eb2816d99a7fe6c67398e260637a40e3fafb5"}, + {file = "GitPython-3.1.7.tar.gz", hash = "sha256:2db287d71a284e22e5c2846042d0602465c7434d910406990d5b74df4afb0858"}, +] +identify = [ + {file = "identify-1.4.25-py2.py3-none-any.whl", hash = "sha256:ccd88716b890ecbe10920659450a635d2d25de499b9a638525a48b48261d989b"}, + {file = "identify-1.4.25.tar.gz", hash = "sha256:110ed090fec6bce1aabe3c72d9258a9de82207adeaa5a05cd75c635880312f9a"}, +] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, @@ -437,6 +893,10 @@ importlib-metadata = [ {file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"}, {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"}, ] +importlib-resources = [ + {file = "importlib_resources-3.0.0-py2.py3-none-any.whl", hash = "sha256:d028f66b66c0d5732dae86ba4276999855e162a749c92620a38c1d779ed138a7"}, + {file = "importlib_resources-3.0.0.tar.gz", hash = "sha256:19f745a6eca188b490b1428c8d1d4a0d2368759f32370ea8fb89cad2ab1106c3"}, +] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, @@ -445,14 +905,37 @@ more-itertools = [ {file = "more-itertools-8.4.0.tar.gz", hash = "sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5"}, {file = "more_itertools-8.4.0-py3-none-any.whl", hash = "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2"}, ] +nodeenv = [ + {file = "nodeenv-1.4.0-py2.py3-none-any.whl", hash = "sha256:4b0b77afa3ba9b54f4b6396e60b0c83f59eaeb2d63dc3cc7a70f7f4af96c82bc"}, +] packaging = [ {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"}, ] +pathspec = [ + {file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"}, + {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, +] +pbr = [ + {file = "pbr-5.4.5-py2.py3-none-any.whl", hash = "sha256:579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8"}, + {file = "pbr-5.4.5.tar.gz", hash = "sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c"}, +] +pep8-naming = [ + {file = "pep8-naming-0.11.1.tar.gz", hash = "sha256:a1dd47dd243adfe8a83616e27cf03164960b507530f155db94e10b36a6cd6724"}, + {file = "pep8_naming-0.11.1-py2.py3-none-any.whl", hash = "sha256:f43bfe3eea7e0d73e8b5d07d6407ab47f2476ccaeff6937c84275cd30b016738"}, +] pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, ] +pre-commit = [ + {file = "pre_commit-2.6.0-py2.py3-none-any.whl", hash = "sha256:e8b1315c585052e729ab7e99dcca5698266bedce9067d21dc909c23e3ceed626"}, + {file = "pre_commit-2.6.0.tar.gz", hash = "sha256:1657663fdd63a321a4a739915d7d03baedd555b25054449090f97bb0cb30a915"}, +] +pre-commit-hooks = [ + {file = "pre_commit_hooks-3.1.0-py2.py3-none-any.whl", hash = "sha256:32e07d6bd511e26ac3d7b7aafdd2e49d0f1efdb7fc772156386004b9e6f66dbe"}, + {file = "pre_commit_hooks-3.1.0.tar.gz", hash = "sha256:78642bdda65d524a6c91faaf4b322f18fc561e4377e8651d8502c6073e4a19d9"}, +] py = [ {file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"}, {file = "py-1.9.0.tar.gz", hash = "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"}, @@ -485,6 +968,46 @@ pytz = [ {file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"}, {file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"}, ] +pyyaml = [ + {file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"}, + {file = "PyYAML-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76"}, + {file = "PyYAML-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2"}, + {file = "PyYAML-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c"}, + {file = "PyYAML-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2"}, + {file = "PyYAML-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648"}, + {file = "PyYAML-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"}, + {file = "PyYAML-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf"}, + {file = "PyYAML-5.3.1-cp38-cp38-win32.whl", hash = "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97"}, + {file = "PyYAML-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee"}, + {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, +] +regex = [ + {file = "regex-2020.7.14-cp27-cp27m-win32.whl", hash = "sha256:e46d13f38cfcbb79bfdb2964b0fe12561fe633caf964a77a5f8d4e45fe5d2ef7"}, + {file = "regex-2020.7.14-cp27-cp27m-win_amd64.whl", hash = "sha256:6961548bba529cac7c07af2fd4d527c5b91bb8fe18995fed6044ac22b3d14644"}, + {file = "regex-2020.7.14-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c50a724d136ec10d920661f1442e4a8b010a4fe5aebd65e0c2241ea41dbe93dc"}, + {file = "regex-2020.7.14-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8a51f2c6d1f884e98846a0a9021ff6861bdb98457879f412fdc2b42d14494067"}, + {file = "regex-2020.7.14-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:9c568495e35599625f7b999774e29e8d6b01a6fb684d77dee1f56d41b11b40cd"}, + {file = "regex-2020.7.14-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:51178c738d559a2d1071ce0b0f56e57eb315bcf8f7d4cf127674b533e3101f88"}, + {file = "regex-2020.7.14-cp36-cp36m-win32.whl", hash = "sha256:9eddaafb3c48e0900690c1727fba226c4804b8e6127ea409689c3bb492d06de4"}, + {file = "regex-2020.7.14-cp36-cp36m-win_amd64.whl", hash = "sha256:14a53646369157baa0499513f96091eb70382eb50b2c82393d17d7ec81b7b85f"}, + {file = "regex-2020.7.14-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:1269fef3167bb52631ad4fa7dd27bf635d5a0790b8e6222065d42e91bede4162"}, + {file = "regex-2020.7.14-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d0a5095d52b90ff38592bbdc2644f17c6d495762edf47d876049cfd2968fbccf"}, + {file = "regex-2020.7.14-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:4c037fd14c5f4e308b8370b447b469ca10e69427966527edcab07f52d88388f7"}, + {file = "regex-2020.7.14-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bc3d98f621898b4a9bc7fecc00513eec8f40b5b83913d74ccb445f037d58cd89"}, + {file = "regex-2020.7.14-cp37-cp37m-win32.whl", hash = "sha256:46bac5ca10fb748d6c55843a931855e2727a7a22584f302dd9bb1506e69f83f6"}, + {file = "regex-2020.7.14-cp37-cp37m-win_amd64.whl", hash = "sha256:0dc64ee3f33cd7899f79a8d788abfbec168410be356ed9bd30bbd3f0a23a7204"}, + {file = "regex-2020.7.14-cp38-cp38-manylinux1_i686.whl", hash = "sha256:5ea81ea3dbd6767873c611687141ec7b06ed8bab43f68fad5b7be184a920dc99"}, + {file = "regex-2020.7.14-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:bbb332d45b32df41200380fff14712cb6093b61bd142272a10b16778c418e98e"}, + {file = "regex-2020.7.14-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:c11d6033115dc4887c456565303f540c44197f4fc1a2bfb192224a301534888e"}, + {file = "regex-2020.7.14-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:75aaa27aa521a182824d89e5ab0a1d16ca207318a6b65042b046053cfc8ed07a"}, + {file = "regex-2020.7.14-cp38-cp38-win32.whl", hash = "sha256:d6cff2276e502b86a25fd10c2a96973fdb45c7a977dca2138d661417f3728341"}, + {file = "regex-2020.7.14-cp38-cp38-win_amd64.whl", hash = "sha256:7a2dd66d2d4df34fa82c9dc85657c5e019b87932019947faece7983f2089a840"}, + {file = "regex-2020.7.14.tar.gz", hash = "sha256:3a3af27a8d23143c49a3420efe5b3f8cf1a48c6fc8bc6856b03f638abc1833bb"}, +] +reorder-python-imports = [ + {file = "reorder_python_imports-2.3.4-py2.py3-none-any.whl", hash = "sha256:59e5f7a4a40181188c9563e60d13068a0bbfb68333c6554403a1a80a9d20603e"}, + {file = "reorder_python_imports-2.3.4.tar.gz", hash = "sha256:508dbbe34b48505a29b4cdb964819c12309dbd4ba3f82e0eb7c02c915f2c6f88"}, +] requests = [ {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"}, {file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"}, @@ -493,22 +1016,86 @@ requests-mock = [ {file = "requests-mock-1.8.0.tar.gz", hash = "sha256:e68f46844e4cee9d447150343c9ae875f99fa8037c6dcf5f15bf1fe9ab43d226"}, {file = "requests_mock-1.8.0-py2.py3-none-any.whl", hash = "sha256:11215c6f4df72702aa357f205cf1e537cffd7392b3e787b58239bde5fb3db53b"}, ] +"ruamel.yaml" = [ + {file = "ruamel.yaml-0.16.10-py2.py3-none-any.whl", hash = "sha256:0962fd7999e064c4865f96fb1e23079075f4a2a14849bcdc5cdba53a24f9759b"}, + {file = "ruamel.yaml-0.16.10.tar.gz", hash = "sha256:099c644a778bf72ffa00524f78dd0b6476bca94a1da344130f4bf3381ce5b954"}, +] +"ruamel.yaml.clib" = [ + {file = "ruamel.yaml.clib-0.2.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9c6d040d0396c28d3eaaa6cb20152cb3b2f15adf35a0304f4f40a3cf9f1d2448"}, + {file = "ruamel.yaml.clib-0.2.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4d55386129291b96483edcb93b381470f7cd69f97585829b048a3d758d31210a"}, + {file = "ruamel.yaml.clib-0.2.0-cp27-cp27m-win32.whl", hash = "sha256:8073c8b92b06b572e4057b583c3d01674ceaf32167801fe545a087d7a1e8bf52"}, + {file = "ruamel.yaml.clib-0.2.0-cp27-cp27m-win_amd64.whl", hash = "sha256:615b0396a7fad02d1f9a0dcf9f01202bf9caefee6265198f252c865f4227fcc6"}, + {file = "ruamel.yaml.clib-0.2.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:a0ff786d2a7dbe55f9544b3f6ebbcc495d7e730df92a08434604f6f470b899c5"}, + {file = "ruamel.yaml.clib-0.2.0-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:ea4362548ee0cbc266949d8a441238d9ad3600ca9910c3fe4e82ee3a50706973"}, + {file = "ruamel.yaml.clib-0.2.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:77556a7aa190be9a2bd83b7ee075d3df5f3c5016d395613671487e79b082d784"}, + {file = "ruamel.yaml.clib-0.2.0-cp35-cp35m-win32.whl", hash = "sha256:392b7c371312abf27fb549ec2d5e0092f7ef6e6c9f767bfb13e83cb903aca0fd"}, + {file = "ruamel.yaml.clib-0.2.0-cp35-cp35m-win_amd64.whl", hash = "sha256:ed5b3698a2bb241b7f5cbbe277eaa7fe48b07a58784fba4f75224fd066d253ad"}, + {file = "ruamel.yaml.clib-0.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7aee724e1ff424757b5bd8f6c5bbdb033a570b2b4683b17ace4dbe61a99a657b"}, + {file = "ruamel.yaml.clib-0.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d0d3ac228c9bbab08134b4004d748cf9f8743504875b3603b3afbb97e3472947"}, + {file = "ruamel.yaml.clib-0.2.0-cp36-cp36m-win32.whl", hash = "sha256:f9dcc1ae73f36e8059589b601e8e4776b9976effd76c21ad6a855a74318efd6e"}, + {file = "ruamel.yaml.clib-0.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1e77424825caba5553bbade750cec2277ef130647d685c2b38f68bc03453bac6"}, + {file = "ruamel.yaml.clib-0.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d10e9dd744cf85c219bf747c75194b624cc7a94f0c80ead624b06bfa9f61d3bc"}, + {file = "ruamel.yaml.clib-0.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:550168c02d8de52ee58c3d8a8193d5a8a9491a5e7b2462d27ac5bf63717574c9"}, + {file = "ruamel.yaml.clib-0.2.0-cp37-cp37m-win32.whl", hash = "sha256:57933a6986a3036257ad7bf283529e7c19c2810ff24c86f4a0cfeb49d2099919"}, + {file = "ruamel.yaml.clib-0.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b1b7fcee6aedcdc7e62c3a73f238b3d080c7ba6650cd808bce8d7761ec484070"}, + {file = "ruamel.yaml.clib-0.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:be018933c2f4ee7de55e7bd7d0d801b3dfb09d21dad0cce8a97995fd3e44be30"}, + {file = "ruamel.yaml.clib-0.2.0.tar.gz", hash = "sha256:b66832ea8077d9b3f6e311c4a53d06273db5dc2db6e8a908550f3c14d67e718c"}, +] +safety = [ + {file = "safety-1.9.0-py2.py3-none-any.whl", hash = "sha256:86c1c4a031fe35bd624fce143fbe642a0234d29f7cbf7a9aa269f244a955b087"}, + {file = "safety-1.9.0.tar.gz", hash = "sha256:23bf20690d4400edc795836b0c983c2b4cbbb922233108ff925b7dd7750f00c9"}, +] six = [ {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, ] +smmap = [ + {file = "smmap-3.0.4-py2.py3-none-any.whl", hash = "sha256:54c44c197c819d5ef1991799a7e30b662d1e520f2ac75c9efbeb54a742214cf4"}, + {file = "smmap-3.0.4.tar.gz", hash = "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"}, +] snowballstemmer = [ {file = "snowballstemmer-2.0.0-py2.py3-none-any.whl", hash = "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0"}, {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, ] +stevedore = [ + {file = "stevedore-3.2.0-py3-none-any.whl", hash = "sha256:c8f4f0ebbc394e52ddf49de8bcc3cf8ad2b4425ebac494106bbc5e3661ac7633"}, + {file = "stevedore-3.2.0.tar.gz", hash = "sha256:38791aa5bed922b0a844513c5f9ed37774b68edc609e5ab8ab8d8fe0ce4315e5"}, +] toml = [ {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"}, ] +typed-ast = [ + {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, + {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"}, + {file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"}, + {file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"}, + {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"}, + {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"}, + {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"}, + {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"}, + {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"}, + {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"}, + {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"}, + {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"}, + {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"}, + {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"}, + {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"}, + {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"}, + {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"}, + {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"}, + {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"}, + {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, + {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, +] urllib3 = [ {file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"}, {file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"}, ] +virtualenv = [ + {file = "virtualenv-20.0.28-py2.py3-none-any.whl", hash = "sha256:8f582a030156282a9ee9d319984b759a232b07f86048c1d6a9e394afa44e78c8"}, + {file = "virtualenv-20.0.28.tar.gz", hash = "sha256:688a61d7976d82b92f7906c367e83bb4b3f0af96f8f75bfcd3da95608fe8ac6c"}, +] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, diff --git a/pyproject.toml b/pyproject.toml index e105d0c5..11ced4d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ classifiers = [ [tool.poetry.dependencies] -python = "^3.6" +python = "^3.6.1" requests = "^2.24.0" pytz = "^2020.1" @@ -35,6 +35,14 @@ coverage = {version = "^5.2.1", extras = ["toml"]} flake8 = "^3.8.3" flake8-docstrings = "^1.5.0" codecov = "^2.1.8" +pre-commit = "^2.6.0" +pre-commit-hooks = "^3.1.0" +black = "^19.10b0" +reorder_python_imports = "^2.3.4" +flake8-bugbear = "^20.1.4" +flake8-bandit = "^2.1.2" +safety = "^1.9.0" +pep8-naming = "^0.11.1" [tool.coverage.paths] source = ["src", "*/site-packages"] @@ -51,4 +59,3 @@ fail_under = 100 [build-system] requires = ["poetry>=0.12"] build-backend = "poetry.masonry.api" - diff --git a/src/meteofrance/client.py b/src/meteofrance/client.py index 5312e2b7..490180dd 100644 --- a/src/meteofrance/client.py +++ b/src/meteofrance/client.py @@ -1,11 +1,19 @@ # -*- coding: utf-8 -*- """Météo-France weather forecast python API.""" - from typing import List -from .const import COASTAL_DEPARTMENT_LIST, METEOFRANCE_API_TOKEN, METEOFRANCE_API_URL -from .model import CurrentPhenomenons, Forecast, Full, PictureOfTheDay, Place, Rain -from .session import MeteoFranceSession, MeteoFranceWSSession, MeteoNetSession +from .const import COASTAL_DEPARTMENT_LIST +from .const import METEOFRANCE_API_TOKEN +from .const import METEOFRANCE_API_URL +from .model import CurrentPhenomenons +from .model import Forecast +from .model import Full +from .model import PictureOfTheDay +from .model import Place +from .model import Rain +from .session import MeteoFranceSession +from .session import MeteoFranceWSSession +from .session import MeteoNetSession # TODO: http://webservice.meteofrance.com/observation # TODO: investigate bulletincote, montagne, etc... diff --git a/src/meteofrance/helpers.py b/src/meteofrance/helpers.py index e3c857ed..6ba87bc9 100644 --- a/src/meteofrance/helpers.py +++ b/src/meteofrance/helpers.py @@ -1,19 +1,18 @@ # -*- coding: utf-8 -*- """Météo-France helpers.""" - import math from datetime import datetime -from typing import List, Tuple +from typing import List +from typing import Tuple -from pytz import timezone, utc +from pytz import timezone +from pytz import utc -from .const import ( - ALERT_COLOR_LIST_EN, - ALERT_COLOR_LIST_FR, - ALERT_TYPE_LIST_EN, - ALERT_TYPE_LIST_FR, - COASTAL_DEPARTMENT_LIST, -) +from .const import ALERT_COLOR_LIST_EN +from .const import ALERT_COLOR_LIST_FR +from .const import ALERT_TYPE_LIST_EN +from .const import ALERT_TYPE_LIST_FR +from .const import COASTAL_DEPARTMENT_LIST from .model.place import Place @@ -68,7 +67,7 @@ def haversine(coord1: Tuple[float, float], coord2: Tuple[float, float]) -> float coord1 and coord2 are tuple with latitude and longitude in degrees. source: https://janakiev.com/blog/gps-points-distance-python/ """ - R = 6372800 # Earth radius in meters + radius = 6372800 # Earth radius in meters lat1, lon1 = coord1 lat2, lon2 = coord2 phi1, phi2 = math.radians(lat1), math.radians(lat2) @@ -80,7 +79,7 @@ def haversine(coord1: Tuple[float, float], coord2: Tuple[float, float]) -> float + math.cos(phi1) * math.cos(phi2) * math.sin(dlambda / 2) ** 2 ) - return 2 * R * math.atan2(math.sqrt(a), math.sqrt(1 - a)) + return 2 * radius * math.atan2(math.sqrt(a), math.sqrt(1 - a)) def sort_places_versus_distance_from_coordinates( diff --git a/src/meteofrance/model/__init__.py b/src/meteofrance/model/__init__.py index 76f1d4d0..6dbc643b 100644 --- a/src/meteofrance/model/__init__.py +++ b/src/meteofrance/model/__init__.py @@ -3,6 +3,7 @@ from .picture_of_the_day import PictureOfTheDay from .place import Place from .rain import Rain -from .warning import CurrentPhenomenons, Full +from .warning import CurrentPhenomenons +from .warning import Full __all__ = ["Forecast", "Place", "PictureOfTheDay", "Rain", "CurrentPhenomenons", "Full"] diff --git a/src/meteofrance/model/forecast.py b/src/meteofrance/model/forecast.py index b92cb24d..1030d017 100644 --- a/src/meteofrance/model/forecast.py +++ b/src/meteofrance/model/forecast.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- """Météo-France weather forecast python API. Forecast class.""" - from datetime import datetime from pytz import utc diff --git a/src/meteofrance/model/rain.py b/src/meteofrance/model/rain.py index afcf9739..b28befc1 100644 --- a/src/meteofrance/model/rain.py +++ b/src/meteofrance/model/rain.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- """Météo-France weather forecast python API. Rain class.""" - from datetime import datetime from typing import Optional diff --git a/src/meteofrance/session.py b/src/meteofrance/session.py index 853c9564..e3e8dc21 100644 --- a/src/meteofrance/session.py +++ b/src/meteofrance/session.py @@ -1,14 +1,12 @@ # -*- coding: utf-8 -*- """Météo-France weather forecast python API.""" +from requests import Response +from requests import Session -from requests import Response, Session - -from .const import ( - METEOFRANCE_API_TOKEN, - METEOFRANCE_API_URL, - METEOFRANCE_WS_API_URL, - METEONET_API_URL, -) +from .const import METEOFRANCE_API_TOKEN +from .const import METEOFRANCE_API_URL +from .const import METEOFRANCE_WS_API_URL +from .const import METEONET_API_URL class MeteoFranceSession(Session): diff --git a/tests/test_exception.py b/tests/test_exception.py index 67507fe3..2c045350 100644 --- a/tests/test_exception.py +++ b/tests/test_exception.py @@ -1,6 +1,5 @@ # coding: utf-8 """Tests for meteofrance module. Exception classes.""" - import pytest from meteofrance.exceptions import MeteoFranceException diff --git a/tests/test_forecast.py b/tests/test_forecast.py index a81f72fc..6041ea12 100644 --- a/tests/test_forecast.py +++ b/tests/test_forecast.py @@ -3,11 +3,10 @@ import time from datetime import datetime +from .const import MOUNTAIN_CITY from meteofrance.client import MeteoFranceClient from meteofrance.model import Place -from .const import MOUNTAIN_CITY - def test_forecast_france(): """Test weather forecast results from API.""" diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 5a6ca669..e47d4c18 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -1,15 +1,12 @@ # coding: utf-8 """Tests for meteofrance module. Helpers.""" - import pytest -from meteofrance.helpers import ( - get_phenomenon_name_from_indice, - get_warning_text_status_from_indice_color, - is_coastal_department, - readeable_phenomenoms_dict, - sort_places_versus_distance_from_coordinates, -) +from meteofrance.helpers import get_phenomenon_name_from_indice +from meteofrance.helpers import get_warning_text_status_from_indice_color +from meteofrance.helpers import is_coastal_department +from meteofrance.helpers import readeable_phenomenoms_dict +from meteofrance.helpers import sort_places_versus_distance_from_coordinates from meteofrance.model import Place diff --git a/tests/test_picture_of_the_day.py b/tests/test_picture_of_the_day.py index eeef4d49..5c35669f 100644 --- a/tests/test_picture_of_the_day.py +++ b/tests/test_picture_of_the_day.py @@ -1,6 +1,5 @@ # coding: utf-8 """Tests Météo-France module. PictureOfTheDay class.""" - from meteofrance.client import MeteoFranceClient diff --git a/tests/test_place.py b/tests/test_place.py index 27457ef1..53d85695 100644 --- a/tests/test_place.py +++ b/tests/test_place.py @@ -1,6 +1,5 @@ # coding: utf-8 """Tests Météo-France module. Place class.""" - from meteofrance.client import MeteoFranceClient diff --git a/tests/test_rain.py b/tests/test_rain.py index 389a21b3..e09ce9c6 100644 --- a/tests/test_rain.py +++ b/tests/test_rain.py @@ -1,6 +1,5 @@ # coding: utf-8 """Tests Météo-France module. Forecast class.""" - import pytest import requests