diff --git a/.condarc b/.condarc deleted file mode 100644 index b2344324..00000000 --- a/.condarc +++ /dev/null @@ -1,4 +0,0 @@ -channels: - - michaelsjp - -show_channel_urls: True \ No newline at end of file diff --git a/.coveragerc b/.coveragerc index a5f7fcee..d5b163f1 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,5 +1,23 @@ +[run] +branch = False +source = codecov +omit = + */venv/* + */.venv/* + */.env/* + */.tox/* + */docs/* + tests/* + setup.py + [report] omit = - */python?.?/* - */site-packages/nose/* - *__init__* + */venv/* + */.venv/* + */.env/* + */.tox/* + */docs/* + tests/* + setup.py +exclude_lines = + pragma: no cover diff --git a/.github/workflows/ci-production.yml b/.github/workflows/ci-production.yml new file mode 100644 index 00000000..4ba3fc9e --- /dev/null +++ b/.github/workflows/ci-production.yml @@ -0,0 +1,91 @@ +name: Continous Integration + +on: + push: + branches: + - main + - master + release: + types: + - created + +jobs: + linux-tests: + strategy: + fail-fast: false + matrix: + config: + - python-version: 3.6 + tox: 36 + - python-version: 3.7 + tox: 37 + - python-version: 3.8 + tox: 38 + - python-version: 3.9 + tox: 39 + - python-version: pypy-3.6 + tox: py3 + - python-version: pypy-3.7 + tox: py3 + poetry-version: [ 1.1.4 ] + os: [ macos-latest, windows-2019, ubuntu-20.04, ubuntu-18.04 ] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - name: Set up testing Python ${{ matrix.config.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.config.python-version }} + architecture: x64 + - name: Set up base Python 3.9 + uses: actions/setup-python@v2 + with: + python-version: 3.9 + architecture: x64 + - name: Python Poetry Action + uses: abatilo/actions-poetry@v2.1.0 + with: + poetry-version: ${{ matrix.poetry-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox + - name: Run Tox + run: tox -e py${{ matrix.config.tox }} + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + flags: unittests + env_vars: OS,PYTHON + name: codecov-umbrella + fail_ci_if_error: true + verbose: true + build-and-publish: + name: Build and publish Python distributions 📦 to PyPI and TestPyPI + runs-on: ubuntu-20.04 + needs: + - linux-tests + steps: + - uses: actions/checkout@v2 + - name: Set up base Python 3.9 + uses: actions/setup-python@v2 + with: + python-version: 3.9 + - name: Python Poetry Action + uses: abatilo/actions-poetry@v2.1.0 + with: + poetry-version: 1.1.4 + - name: Publish distribution 📦 with test.pypi.org + if: startsWith(github.ref, 'refs/tags') + run: | + poetry config repositories.testpypi https://test.pypi.org/legacy/ + poetry config pypi-token.testpypi ${{ secrets.TEST_PYPI_API_TOKEN }} + poetry build + poetry publish -r testpypi + - name: Publish distribution 📦 to PyPI + if: startsWith(github.ref, 'refs/tags') + run: | + poetry config pypi-token.pypi ${{ secrets.PYPI_API_TOKEN }} + poetry build + poetry publish diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 6053fbc8..2ce29e38 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -1,38 +1,80 @@ name: tests -on: +on: pull_request: branches: '**' - push: - branches: - - master jobs: - build: - runs-on: ${{ matrix.os }} + lint: + runs-on: ubuntu-20.04 + steps: + - name: checkout + uses: actions/checkout@v2 + - name: Install Python + uses: actions/setup-python@v2 + with: + python-version: 3.9 + - name: Python Poetry Action + uses: abatilo/actions-poetry@v2.1.0 + with: + poetry-version: 1.1.4 + - name: Install lint dependencies + run: | + pip install tox pytest pytest-cov + - name: Install and run pre-commit + uses: pre-commit/action@v2.0.0 + with: + extra_args: --all-files + test: + needs: + - lint strategy: + fail-fast: false matrix: - os: [ubuntu-20.04] - python_version: [ - 3.7, - 3.8, - 3.9, - pypy3 - ] + config: + - python-version: 3.6 + tox: 36 + - python-version: 3.7 + tox: 37 + - python-version: 3.8 + tox: 38 + - python-version: 3.9 + tox: 39 + - python-version: pypy-3.6 + tox: py3 + - python-version: pypy-3.7 + tox: py3 + poetry-version: [ 1.1.4 ] + os: [ macos-latest, windows-2019, ubuntu-20.04, ubuntu-18.04 ] + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python_version }} + - name: Set up testing Python ${{ matrix.config.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.config.python-version }} + architecture: x64 + - name: Set up base Python 3.9 uses: actions/setup-python@v2 with: - python-version: ${{ matrix.python_version }} + python-version: 3.9 + architecture: x64 + - name: Python Poetry Action + uses: abatilo/actions-poetry@v2.1.0 + with: + poetry-version: ${{ matrix.poetry-version }} - name: Install dependencies run: | - pip install -r requirements-dev.txt - - name: nosetests - run: | - nosetests --with-coverage --cover-erase --cover-package=openrouteservice -v - - name: coveralls - run: | - coveralls --service=github - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + python -m pip install --upgrade pip + pip install tox + - name: Run Tox + run: tox -e py${{ matrix.config.tox }} + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + flags: unittests + env_vars: OS,PYTHON + name: codecov-umbrella + fail_ci_if_error: true + verbose: true diff --git a/.github/workflows/conda-package.yml b/.github/workflows/conda-package.yml deleted file mode 100644 index c4148ff8..00000000 --- a/.github/workflows/conda-package.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Conda Package - -on: - push: - tags: - - 'v*.*.*' - -jobs: - publish: - runs-on: Ubuntu-20.04 - steps: - - uses: actions/checkout@v1 - - name: publish-to-conda - uses: MichaelsJP/conda-package-publish-action@v1.0.0 - with: - subDir: 'conda.recipe' - AnacondaToken: ${{ secrets.ANACONDA_TOKEN }} - platforms: 'all' - override: true \ No newline at end of file diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml deleted file mode 100644 index c881861c..00000000 --- a/.github/workflows/python-package.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Python package -on: - push: - tags: - - 'v*.*.*' -jobs: - build-and-publish: - name: Build and publish Python distributions 📦 to PyPI and TestPyPI - runs-on: ubuntu-18.04 - steps: - - uses: actions/checkout@master - - name: Set up Python 3.7 - uses: actions/setup-python@v1 - with: - python-version: 3.7 - - name: Install pypa/build - run: >- - python -m - pip install - build - --user - - name: Build a binary wheel and a source tarball - run: >- - python -m - build - --sdist - --wheel - --outdir dist/ - . - - name: Publish distribution 📦 to Test PyPI - uses: pypa/gh-action-pypi-publish@master - with: - password: ${{ secrets.TEST_PYPI_API_TOKEN }} - repository_url: https://test.pypi.org/legacy/ - - name: Publish distribution 📦 to PyPI - if: startsWith(github.ref, 'refs/tags') - uses: pypa/gh-action-pypi-publish@master - with: - password: ${{ secrets.PYPI_API_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 785caccc..c63a90b3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.tox/ .venv/ .coverage **/.ipynb_checkpoints/ @@ -16,3 +17,6 @@ test.py cover/ conda/ +*coverage.xml +/setup.py +/requirements.txt diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..2d319e18 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,55 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + exclude: | + (?x)( + ^conda.recipe/meta.yaml + ) + - id: check-json + - id: forbid-new-submodules + - id: mixed-line-ending + args: [ '--fix=lf' ] + description: Forces to replace line ending by the UNIX 'lf' character. + - id: pretty-format-json + args: [ '--no-sort-keys' ] + - id: no-commit-to-branch + args: [ --branch, master ] + - id: no-commit-to-branch + args: [ --branch, main ] + + - repo: https://github.com/ambv/black + rev: stable + hooks: + - id: black + args: # arguments to configure black + - --line-length=80 + language_version: python3.9 + - repo: https://gitlab.com/pycqa/flake8 + rev: "3.8.4" + hooks: + - id: flake8 + exclude: | + (?x)( + ^test/* | + ^docs/* + ) + args: + - "--max-line-length=120" + - "--ignore=P101,D202,D401" + additional_dependencies: + [ + "flake8-bugbear==19.8.0", + "flake8-coding==1.3.2", + "flake8-comprehensions==3.0.1", + "flake8-debugger==3.2.1", + "flake8-deprecated==1.3", + "flake8-pep3101==1.2.1", + "flake8-polyfill==1.0.2", + "flake8-print==3.1.4", + "flake8-string-format==0.2.3", + "flake8-docstrings==1.5.0", + ] diff --git a/MANIFEST.in b/MANIFEST.in index c4bf4561..9561fb10 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1 @@ -include README.rst \ No newline at end of file +include README.rst diff --git a/README.rst b/README.rst index 9d5084e9..6359d901 100644 --- a/README.rst +++ b/README.rst @@ -2,9 +2,9 @@ :target: https://github.com/GIScience/openrouteservice-py/actions :alt: Build status -.. image:: https://coveralls.io/repos/github/GIScience/openrouteservice-py/badge.svg?branch=master - :target: https://coveralls.io/github/GIScience/openrouteservice-py?branch=master - :alt: Coveralls coverage +.. image:: https://codecov.io/gh/GIScience/openrouteservice-py/branch/master/graph/badge.svg?token=QqGC8XfCiI + :target: https://codecov.io/gh/GIScience/openrouteservice-py + :alt: Codecov coverage .. image:: https://readthedocs.org/projects/openrouteservice-py/badge/?version=latest :target: http://openrouteservice-py.readthedocs.io/en/latest/?badge=latest @@ -14,14 +14,6 @@ :target: https://badge.fury.io/py/openrouteservice :alt: PyPI version -.. image:: https://github.com/GIScience/openrouteservice-py/workflows/Conda%20Package/badge.svg?branch=master - :target: https://anaconda.org/MichaelsJP/openrouteservice - :alt: Conda Build - -.. image:: https://anaconda.org/michaelsjp/openrouteservice/badges/version.svg - :target: https://anaconda.org/MichaelsJP/openrouteservice - :alt: Conda Version - .. image:: https://mybinder.org/badge_logo.svg :target: https://mybinder.org/v2/gh/GIScience/openrouteservice-py/master?filepath=examples%2Fbasic_example.ipynb :alt: MyBinder @@ -78,11 +70,22 @@ By using this library, you agree to the ORS `terms and conditions`_. Requirements ----------------------------- -openrouteservice-py is tested against CPython 3.7, 3.8 and 3.9, and PyPy3. +openrouteservice-py is tested against Python 3.6, 3.7, 3.8 and 3.9, and PyPy3.6 and PyPy3.7. + +For setting up a testing environment, install **poetry** first. + +For Linux and osx:: + + curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - + +For windows:: + + (Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python - -For setting up a testing environment, install ``requirements-dev.txt``:: +Then create a venv and install the dependencies with poetry:: - pip install -r requirements-dev.txt + python -m venv .venv && source .venv/bin/activate + poetry install -vv Installation ------------------------------ @@ -100,7 +103,7 @@ Testing --------------------------------- If you want to run the unit tests, see Requirements_. ``cd`` to the library directory and run:: - nosetests -v + pytest -v ``-v`` flag for verbose output (recommended). diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..53aa06ab --- /dev/null +++ b/codecov.yml @@ -0,0 +1,7 @@ +parsers: + gcov: + branch_detection: + conditional: yes + loop: yes + method: no + macro: no diff --git a/conda.recipe/bld.bat b/conda.recipe/bld.bat deleted file mode 100644 index 447706ab..00000000 --- a/conda.recipe/bld.bat +++ /dev/null @@ -1,3 +0,0 @@ -cd %RECIPE_DIR%\.. -"%PYTHON%" setup.py install -if errorlevel 1 exit 1 \ No newline at end of file diff --git a/conda.recipe/build.sh b/conda.recipe/build.sh deleted file mode 100644 index aa59b4dc..00000000 --- a/conda.recipe/build.sh +++ /dev/null @@ -1,2 +0,0 @@ -cd $RECIPE_DIR/.. -$PYTHON setup.py install \ No newline at end of file diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml deleted file mode 100644 index 5f7725eb..00000000 --- a/conda.recipe/meta.yaml +++ /dev/null @@ -1,43 +0,0 @@ -{% set name = "openrouteservice" %} -{% set version = "2.3.3" %} - -package: - name: "{{ name|lower }}" - version: "{{ version }}" - -source: - git_url: https://github.com/GIScience/openrouteservice-py.git - git_rev: "v{{ version }}" - - -requirements: - build: - - python>=3.4 - - pip - - requests>=2.0 - - nose>=1.0 - - responses>=0.10 - - coveralls>=1.7.0 - - coverage>=4.5.0 - run: - - requests>=2.0 -test: - imports: - - openrouteservice - source_files: - - openrouteservice - - test - requires: - - nose>1.0 - - requests>=2.0 - - responses>=0.10 - - coveralls>=1.7.0 - - coverage>=4.5.0 - commands: - - nosetests -v - -about: - home: https://github.com/GIScience/openrouteservice-py - license: Apache - license_family: BSD - license_file: LICENSE diff --git a/docs/Makefile b/docs/Makefile index 02f605fd..447beb33 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -17,4 +17,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/source/conf.py b/docs/source/conf.py index 52361ccc..352e3b56 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -20,7 +20,7 @@ import sys # sys.path.insert(0, 'C:\\Users\\gisadmin\\Documents\\Dev\\Git\\Uni\\ORS\\infrastructure\\SDK\\openrouteservice-python-api\\openrouteservice') -sys.path.insert(0, os.path.abspath('../..')) +sys.path.insert(0, os.path.abspath("../..")) # -- General configuration ------------------------------------------------ @@ -31,37 +31,33 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.todo', - 'sphinx.ext.coverage' -] +extensions = ["sphinx.ext.autodoc", "sphinx.ext.todo", "sphinx.ext.coverage"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['.templates'] +templates_path = [".templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'openrouteservice-py' -copyright = u'2018, Nils Nolde' -author = u'Nils Nolde' +project = u"openrouteservice-py" +copyright = u"2018, Nils Nolde" +author = u"Nils Nolde" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = u'0.4' +version = u"0.4" # The full version, including alpha/beta/rc tags. -release = u'0.4' +release = u"0.4" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -76,7 +72,7 @@ exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True @@ -86,7 +82,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'alabaster' +html_theme = "alabaster" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -97,7 +93,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['.static'] +html_static_path = [".static"] # Custom sidebar templates, must be a dictionary that maps document names # to template names. @@ -105,19 +101,19 @@ # This is required for the alabaster theme # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars html_sidebars = { - '**': [ - 'about.html', - 'navigation.html', - 'relations.html', # needs 'show_related': True theme option to display - 'searchbox.html', - 'donate.html', + "**": [ + "about.html", + "navigation.html", + "relations.html", # needs 'show_related': True theme option to display + "searchbox.html", + "donate.html", ] } # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. -htmlhelp_basename = 'openrouteservice-pydoc' +htmlhelp_basename = "openrouteservice-pydoc" # -- Options for LaTeX output --------------------------------------------- @@ -125,15 +121,12 @@ # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # 'preamble': '', - # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -143,8 +136,13 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'openrouteservice-py.tex', u'openrouteservice-py Documentation', - u'Nils Nolde', 'manual'), + ( + master_doc, + "openrouteservice-py.tex", + u"openrouteservice-py Documentation", + u"Nils Nolde", + "manual", + ), ] # -- Options for manual page output --------------------------------------- @@ -152,8 +150,13 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'openrouteservice-py', u'openrouteservice-py Documentation', - [author], 1) + ( + master_doc, + "openrouteservice-py", + u"openrouteservice-py Documentation", + [author], + 1, + ) ] # -- Options for Texinfo output ------------------------------------------- @@ -162,7 +165,13 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'openrouteservice-py', u'openrouteservice-py Documentation', - author, 'openrouteservice-py', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "openrouteservice-py", + u"openrouteservice-py Documentation", + author, + "openrouteservice-py", + "One line description of project.", + "Miscellaneous", + ), ] diff --git a/docs/source/index.rst b/docs/source/index.rst index 51085657..34578f23 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -17,6 +17,6 @@ Indices and tables .. toctree:: :maxdepth: 4 - + readme_link - openrouteservice \ No newline at end of file + openrouteservice diff --git a/docs/source/modules.rst b/docs/source/modules.rst index 08a26361..b45c4804 100644 --- a/docs/source/modules.rst +++ b/docs/source/modules.rst @@ -3,4 +3,3 @@ docs .. toctree:: :maxdepth: 4 - diff --git a/docs/source/readme_link.rst b/docs/source/readme_link.rst index 38ba8043..a6210d3d 100644 --- a/docs/source/readme_link.rst +++ b/docs/source/readme_link.rst @@ -1 +1 @@ -.. include:: ../../README.rst \ No newline at end of file +.. include:: ../../README.rst diff --git a/environment.yml b/environment.yml index b68d89d3..0d21131d 100644 --- a/environment.yml +++ b/environment.yml @@ -7,4 +7,4 @@ dependencies: - python - folium - pip: - - openrouteservice \ No newline at end of file + - openrouteservice diff --git a/openrouteservice/__init__.py b/openrouteservice/__init__.py index a092a179..16448c14 100644 --- a/openrouteservice/__init__.py +++ b/openrouteservice/__init__.py @@ -17,22 +17,23 @@ # the License. # -__version__ = "2.2.2" +"""Initialize openrouteservice.""" +import pkg_resources + +__version__ = pkg_resources.get_distribution("openrouteservice").version def get_ordinal(number): - """Produces an ordinal (1st, 2nd, 3rd, 4th) from a number""" + """Produces an ordinal (1st, 2nd, 3rd, 4th) from a number.""" if number == 1: - return 'st' + return "st" elif number == 2: - return 'nd' + return "nd" elif number == 3: - return 'rd' + return "rd" else: - return 'th' + return "th" -from openrouteservice.client import Client -## Allow sphinx to pick up these symbols for the documentation. -# __all__ = ["Client"] +from openrouteservice.client import Client # noqa diff --git a/openrouteservice/client.py b/openrouteservice/client.py index 5455773d..ea763c40 100644 --- a/openrouteservice/client.py +++ b/openrouteservice/client.py @@ -16,10 +16,7 @@ # License for the specific language governing permissions and limitations under # the License. # - -""" -Core client functionality, common across all API requests. -""" +"""Core client functionality, common across all API requests.""" from datetime import datetime from datetime import timedelta @@ -34,26 +31,30 @@ try: # Python 3 from urllib.parse import urlencode -except ImportError: # Python 2 - from urllib import urlencode +except ImportError: # pragma: no cover # Python 2 + from urllib import urlencode # noqa _USER_AGENT = "ORSClientPython.v{}".format(__version__) _DEFAULT_BASE_URL = "https://api.openrouteservice.org" -_RETRIABLE_STATUSES = set([503]) +_RETRIABLE_STATUSES = set([503]) # noqa class Client(object): """Performs requests to the ORS API services.""" - def __init__(self, - key=None, - base_url=_DEFAULT_BASE_URL, - timeout=60, - retry_timeout=60, - requests_kwargs=None, - retry_over_query_limit=True): + def __init__( + self, + key=None, + base_url=_DEFAULT_BASE_URL, + timeout=60, + retry_timeout=60, + requests_kwargs=None, + retry_over_query_limit=True, + ): """ + Initialize the openrouteservice client. + :param key: ORS API key. :type key: string @@ -86,33 +87,38 @@ def __init__(self, if self._base_url == _DEFAULT_BASE_URL and key is None: raise ValueError( - "No API key was specified. Please visit https://openrouteservice.org/sign-up to create one.") + "No API key was specified. Please visit https://openrouteservice.org/sign-up to create one." + ) self._timeout = timeout self._retry_over_query_limit = retry_over_query_limit self._retry_timeout = timedelta(seconds=retry_timeout) self._requests_kwargs = requests_kwargs or {} - self._requests_kwargs.update({ - "headers": { - "User-Agent": _USER_AGENT, - 'Content-type': 'application/json', - "Authorization": self._key - }, - "timeout": self._timeout, - }) + self._requests_kwargs.update( + { + "headers": { + "User-Agent": _USER_AGENT, + "Content-type": "application/json", + "Authorization": self._key, + }, + "timeout": self._timeout, + } + ) self._req = None - def request(self, - url, - get_params=None, - first_request_time=None, - retry_counter=0, - requests_kwargs=None, - post_json=None, - dry_run=None): - """Performs HTTP GET/POST with credentials, returning the body as - JSON. + def request( + self, + url, + get_params=None, + first_request_time=None, + retry_counter=0, + requests_kwargs=None, + post_json=None, + dry_run=None, + ): + """ + Performs HTTP GET/POST with credentials, returning the body as JSON. :param url: URL path for the request. Should begin with a slash. :type url: string @@ -140,7 +146,7 @@ def request(self, :raises ApiError: when the API returns an error. :raises Timeout: if the request timed out. - + :rtype: dict from JSON response. """ @@ -160,9 +166,10 @@ def request(self, # Jitter this value by 50% and pause. time.sleep(delay_seconds * (random.random() + 0.5)) - authed_url = self._generate_auth_url(url, - get_params, - ) + authed_url = self._generate_auth_url( + url, + get_params, + ) # Default to the client-level self.requests_kwargs, with method-level # requests_kwargs arg overriding. @@ -178,44 +185,69 @@ def request(self, # Only print URL and parameters for dry_run if dry_run: - print("url:\n{}\nHeaders:\n{}".format(self._base_url + authed_url, - json.dumps(final_requests_kwargs, indent=2))) + print( # noqa + "url:\n{}\nHeaders:\n{}".format( + self._base_url + authed_url, + json.dumps(final_requests_kwargs, indent=2), + ) + ) return try: - response = requests_method(self._base_url + authed_url, - **final_requests_kwargs) + response = requests_method( + self._base_url + authed_url, **final_requests_kwargs + ) self._req = response.request - except requests.exceptions.Timeout: + except requests.exceptions.Timeout: # pragma: no cover raise exceptions.Timeout() if response.status_code in _RETRIABLE_STATUSES: # Retry request. - warnings.warn('Server down.\nRetrying for the {0}{1} time.'.format(retry_counter + 1, - get_ordinal(retry_counter + 1)), - UserWarning, - stacklevel=1) + warnings.warn( + "Server down.\nRetrying for the {0}{1} time.".format( + retry_counter + 1, get_ordinal(retry_counter + 1) + ), + UserWarning, + stacklevel=1, + ) - return self.request(url, get_params, first_request_time, - retry_counter + 1, requests_kwargs, post_json) + return self.request( + url, + get_params, + first_request_time, + retry_counter + 1, + requests_kwargs, + post_json, + ) try: result = self._get_body(response) return result except exceptions._RetriableRequest as e: - if isinstance(e, exceptions._OverQueryLimit) and not self._retry_over_query_limit: + if ( + isinstance(e, exceptions._OverQueryLimit) + and not self._retry_over_query_limit # noqa + ): raise - warnings.warn('Rate limit exceeded. Retrying for the {0}{1} time.'.format(retry_counter + 1, - get_ordinal(retry_counter + 1)), - UserWarning, - stacklevel=1) + warnings.warn( + "Rate limit exceeded. Retrying for the {0}{1} time.".format( + retry_counter + 1, get_ordinal(retry_counter + 1) + ), + UserWarning, + stacklevel=1, + ) # Retry request. - return self.request(url, get_params, first_request_time, - retry_counter + 1, requests_kwargs, - post_json) + return self.request( + url, + get_params, + first_request_time, + retry_counter + 1, + requests_kwargs, + post_json, + ) @property def req(self): @@ -227,29 +259,23 @@ def _get_body(response): """Returns the body of a response object, raises status code exceptions if necessary.""" try: body = response.json() - except json.JSONDecodeError: + except json.JSONDecodeError: # pragma: no cover raise exceptions.HTTPError(response.status_code) # error = body.get('error') status_code = response.status_code - + if status_code == 429: - raise exceptions._OverQueryLimit( - status_code, - body - ) + raise exceptions._OverQueryLimit(status_code, body) if status_code != 200: - raise exceptions.ApiError( - status_code, - body - ) + raise exceptions.ApiError(status_code, body) return body @staticmethod def _generate_auth_url(path, params): - """Returns the path and query string portion of the request URL, first - adding any necessary parameters. + """ + Returns the path and query string portion of the request URL, first adding any necessary parameters. :param path: The path portion of the URL. :type path: string @@ -269,22 +295,23 @@ def _generate_auth_url(path, params): return path + "?" + _urlencode_params(params) -from openrouteservice.directions import directions -from openrouteservice.distance_matrix import distance_matrix -from openrouteservice.elevation import elevation_point -from openrouteservice.elevation import elevation_line -from openrouteservice.isochrones import isochrones -from openrouteservice.geocode import pelias_search -from openrouteservice.geocode import pelias_autocomplete -from openrouteservice.geocode import pelias_structured -from openrouteservice.geocode import pelias_reverse -from openrouteservice.places import places -from openrouteservice.optimization import optimization +from openrouteservice.directions import directions # noqa +from openrouteservice.distance_matrix import distance_matrix # noqa +from openrouteservice.elevation import elevation_point # noqa +from openrouteservice.elevation import elevation_line # noqa +from openrouteservice.isochrones import isochrones # noqa +from openrouteservice.geocode import pelias_search # noqa +from openrouteservice.geocode import pelias_autocomplete # noqa +from openrouteservice.geocode import pelias_structured # noqa +from openrouteservice.geocode import pelias_reverse # noqa +from openrouteservice.places import places # noqa +from openrouteservice.optimization import optimization # noqa def _make_api_method(func): """ Provides a single entry point for modifying all API methods. + For now this is limited to allowing the client object to be modified with an `extra_params` keyword arg to each method, that is then used as the params for each web service request. @@ -299,7 +326,7 @@ def wrapper(*args, **kwargs): result = func(*args, **kwargs) try: del args[0]._extra_params - except AttributeError: + except AttributeError: # pragma: no cover pass return result @@ -337,21 +364,24 @@ def _urlencode_params(params): try: - unicode + unicode # noqa + # NOTE(cbro): `unicode` was removed in Python 3. In Python 3, NameError is # raised here, and caught below. - def _normalize_for_urlencode(value): + def _normalize_for_urlencode(value): # pragma: no cover """(Python 2) Converts the value to a `str` (raw bytes).""" - if isinstance(value, unicode): - return value.encode('utf8') + if isinstance(value, unicode): # noqa + return value.encode("utf8") if isinstance(value, str): return value return _normalize_for_urlencode(str(value)) + except NameError: + def _normalize_for_urlencode(value): """(Python 3) No-op.""" # urlencode in Python 3 handles all the types we are passing it. diff --git a/openrouteservice/convert.py b/openrouteservice/convert.py index c219b5f1..8fc02584 100644 --- a/openrouteservice/convert.py +++ b/openrouteservice/convert.py @@ -16,31 +16,29 @@ # License for the specific language governing permissions and limitations under # the License. # - -"""Converts Python types to string representations suitable for ORS API server. -""" +"""Converts Python types to string representations suitable for ORS API server.""" def _pipe_list(arg): - """Convert list of values to pipe-delimited string""" + """Convert list of values to pipe-delimited string.""" if not _is_list(arg): raise TypeError( - "Expected a list or tuple, " - "but got {}".format(type(arg).__name__)) + "Expected a list or tuple, " "but got {}".format(type(arg).__name__) + ) return "|".join(map(str, arg)) def _comma_list(arg): - """Convert list to comma-separated string""" + """Convert list to comma-separated string.""" if not _is_list(arg): raise TypeError( - "Expected a list or tuple, " - "but got {}".format(type(arg).__name__)) + "Expected a list or tuple, " "but got {}".format(type(arg).__name__) + ) return ",".join(map(str, arg)) def _convert_bool(boolean): - """Convert to stringified boolean""" + """Convert to stringified boolean.""" return str(boolean).lower() @@ -65,12 +63,14 @@ def _format_float(arg): :rtype: string """ - return ("{}".format(round(float(arg), 6)).rstrip("0").rstrip(".")) + return "{}".format(round(float(arg), 6)).rstrip("0").rstrip(".") def _build_coords(arg): - """Converts one or many lng/lat pair(s) to a comma-separated, pipe - delimited string. Coordinates will be rounded to 5 digits. + """ + Converts one or many lng/lat pair(s) to a comma-separated, pipe delimited string. + + Coordinates will be rounded to 5 digits. For example: @@ -79,7 +79,7 @@ def _build_coords(arg): :param arg: The lat/lon pair(s). :type arg: list or tuple - + :rtype: str """ if _is_list(arg): @@ -87,15 +87,16 @@ def _build_coords(arg): else: raise TypeError( "Expected a list or tuple of lng/lat tuples or lists, " - "but got {}".format(type(arg).__name__)) + "but got {}".format(type(arg).__name__) + ) def _concat_coords(arg): """Turn the passed coordinate tuple(s) in comma separated coordinate tuple(s). - + :param arg: coordinate pair(s) :type arg: list or tuple - + :rtype: list of strings """ if all(_is_list(tup) for tup in arg): @@ -111,9 +112,11 @@ def _is_list(arg): return False if isinstance(arg, str): # Python 3-only, as str has __iter__ return False - return (not _has_method(arg, "strip") - and _has_method(arg, "__getitem__") - or _has_method(arg, "__iter__")) + return ( + not _has_method(arg, "strip") + and _has_method(arg, "__getitem__") # noqa + or _has_method(arg, "__iter__") # noqa + ) def _has_method(arg, method): @@ -131,13 +134,13 @@ def _has_method(arg, method): def decode_polyline(polyline, is3d=False): """Decodes a Polyline string into a GeoJSON geometry. - + :param polyline: An encoded polyline, only the geometry. :type polyline: string - + :param is3d: Specifies if geometry contains Z component. :type is3d: boolean - + :returns: GeoJSON Linestring geometry :rtype: dict """ @@ -152,7 +155,7 @@ def decode_polyline(polyline, is3d=False): index += 1 result += b << shift shift += 5 - if b < 0x1f: + if b < 0x1F: break lat += (~result >> 1) if (result & 1) != 0 else (result >> 1) @@ -163,7 +166,7 @@ def decode_polyline(polyline, is3d=False): index += 1 result += b << shift shift += 5 - if b < 0x1f: + if b < 0x1F: break lng += ~(result >> 1) if (result & 1) != 0 else (result >> 1) @@ -175,18 +178,24 @@ def decode_polyline(polyline, is3d=False): index += 1 result += b << shift shift += 5 - if b < 0x1f: + if b < 0x1F: break if (result & 1) != 0: z += ~(result >> 1) else: - z += (result >> 1) + z += result >> 1 - points.append([round(lng * 1e-5, 6), round(lat * 1e-5, 6), round(z * 1e-2, 1)]) + points.append( + [ + round(lng * 1e-5, 6), + round(lat * 1e-5, 6), + round(z * 1e-2, 1), + ] + ) else: points.append([round(lng * 1e-5, 6), round(lat * 1e-5, 6)]) - geojson = {u'type': u'LineString', u'coordinates': points} + geojson = {u"type": u"LineString", u"coordinates": points} return geojson diff --git a/openrouteservice/deprecation.py b/openrouteservice/deprecation.py index 03310189..78871ef5 100644 --- a/openrouteservice/deprecation.py +++ b/openrouteservice/deprecation.py @@ -15,12 +15,18 @@ # the License. # +"""Prints a deprecation warning.""" + import warnings def warning(old_name, new_name): - """Deprecation warning""" + """Deprecation warning.""" - warnings.warn('{} will be deprecated in v2.0. Please use {} instead'.format(old_name, new_name), - DeprecationWarning, - stacklevel=2) + warnings.warn( + "{} will be deprecated in v2.0. Please use {} instead".format( + old_name, new_name + ), + DeprecationWarning, + stacklevel=2, + ) diff --git a/openrouteservice/directions.py b/openrouteservice/directions.py index 39f0475d..2d9f6403 100644 --- a/openrouteservice/directions.py +++ b/openrouteservice/directions.py @@ -16,7 +16,6 @@ # License for the specific language governing permissions and limitations under # the License. # - """Performs requests to the ORS directions API.""" from openrouteservice import deprecation @@ -25,34 +24,36 @@ import warnings -def directions(client, - coordinates, - profile='driving-car', - format_out=None, - format='json', - preference=None, - units=None, - language=None, - geometry=None, - geometry_simplify=None, - instructions=None, - instructions_format=None, - alternative_routes=None, - roundabout_exits=None, - attributes=None, - maneuvers=None, - radiuses=None, - bearings=None, - skip_segments=None, - continue_straight=None, - elevation=None, - extra_info=None, - suppress_warnings=None, - optimized=None, - optimize_waypoints=None, - options=None, - validate=True, - dry_run=None): +def directions( + client, + coordinates, + profile="driving-car", + format_out=None, + format="json", + preference=None, + units=None, + language=None, + geometry=None, + geometry_simplify=None, + instructions=None, + instructions_format=None, + alternative_routes=None, + roundabout_exits=None, + attributes=None, + maneuvers=None, + radiuses=None, + bearings=None, + skip_segments=None, + continue_straight=None, + elevation=None, + extra_info=None, + suppress_warnings=None, + optimized=None, + optimize_waypoints=None, + options=None, + validate=True, + dry_run=None, +): """Get directions between an origin point and a destination point. For more information, visit https://go.openrouteservice.org/documentation/. @@ -185,7 +186,7 @@ def directions(client, :param validate: Specifies whether parameters should be validated before sending the request. Default True. :type validate: bool - + :param dry_run: Print URL and parameters without sending the request. :param dry_run: boolean @@ -199,18 +200,24 @@ def directions(client, # call optimization endpoint and get new order of waypoints if optimize_waypoints is not None and not dry_run: if len(coordinates) <= 3: - warnings.warn("Less than 4 coordinates, nothing to optimize!", UserWarning) + warnings.warn( + "Less than 4 coordinates, nothing to optimize!", UserWarning + ) elif options: - warnings.warn("Options are not compatible with optimization.", UserWarning) - elif preference == 'shortest': - warnings.warn("Shortest is not compatible with optimization.", UserWarning) + warnings.warn( + "Options are not compatible with optimization.", UserWarning + ) + elif preference == "shortest": + warnings.warn( + "Shortest is not compatible with optimization.", UserWarning + ) else: coordinates = _optimize_waypoint_order(client, coordinates, profile) params = {"coordinates": coordinates} if format_out: - deprecation.warning('format_out', 'format') + deprecation.warning("format_out", "format") format = format_out or format @@ -248,7 +255,7 @@ def directions(client, params["radiuses"] = radiuses if maneuvers is not None: - params['maneuvers'] = maneuvers + params["maneuvers"] = maneuvers if bearings: params["bearings"] = bearings @@ -266,48 +273,41 @@ def directions(client, params["extra_info"] = extra_info if suppress_warnings is not None: - params['suppress_warnings'] = suppress_warnings + params["suppress_warnings"] = suppress_warnings if optimized is not None: - if (bearings or continue_straight) and optimized in (True, 'true'): - params["optimized"] = 'false' - print("Set optimized='false' due to incompatible parameter settings.") + if (bearings or continue_straight) and optimized in (True, "true"): + params["optimized"] = "false" + print( # noqa + "Set optimized='false' due to incompatible parameter settings." + ) else: params["optimized"] = optimized if options: - params['options'] = options + params["options"] = options - return client.request("/v2/directions/" + profile + '/' + format, {}, post_json=params, dry_run=dry_run) + return client.request( + "/v2/directions/" + profile + "/" + format, + {}, + post_json=params, + dry_run=dry_run, + ) def _optimize_waypoint_order(client, coordinates, profile): - start = coordinates[0] end = coordinates[-1] - veh = [Vehicle( - id=0, - profile=profile, - start=start, - end=end - )] + veh = [Vehicle(id=0, profile=profile, start=start, end=end)] jobs = [] for idx, coord in enumerate(coordinates[1:-1]): - jobs.append(Job( - id=idx, - location=coord - )) - - params = { - 'jobs': jobs, - 'vehicles': veh - } - - optimization_res = optimization(client, **params) + jobs.append(Job(id=idx, location=coord)) - coordinates = [] - for step in optimization_res['routes'][0]['steps']: - coordinates.append(step['location']) + params = {"jobs": jobs, "vehicles": veh} - return coordinates + optimization_res = optimization(client, **params) # pragma: no cover + coordinates = [] # pragma: no cover + for step in optimization_res["routes"][0]["steps"]: # pragma: no cover + coordinates.append(step["location"]) # pragma: no cover + return coordinates # pragma: no cover diff --git a/openrouteservice/distance_matrix.py b/openrouteservice/distance_matrix.py index 7a38f045..9bccca8d 100644 --- a/openrouteservice/distance_matrix.py +++ b/openrouteservice/distance_matrix.py @@ -16,21 +16,23 @@ # License for the specific language governing permissions and limitations under # the License. # - """Performs requests to the ORS Matrix API.""" -def distance_matrix(client, locations, - profile='driving-car', - sources=None, - destinations=None, - metrics=None, - resolve_locations=None, - units=None, - optimized=None, - validate=True, - dry_run=None): - """ Gets travel distance and time for a matrix of origins and destinations. +def distance_matrix( + client, + locations, + profile="driving-car", + sources=None, + destinations=None, + metrics=None, + resolve_locations=None, + units=None, + optimized=None, + validate=True, + dry_run=None, +): + """Gets travel distance and time for a matrix of origins and destinations. :param locations: One or more pairs of lng/lat values. :type locations: a single location, or a list of locations, where a @@ -39,7 +41,7 @@ def distance_matrix(client, locations, :param profile: Specifies the mode of transport to use when calculating directions. One of ["driving-car", "driving-hgv", "foot-walking", "foot-hiking", "cycling-regular", "cycling-road", - "cycling-safe", "cycling-mountain", "cycling-tour", + "cycling-safe", "cycling-mountain", "cycling-tour", "cycling-electric",]. Default "driving-car". :type profile: string @@ -56,7 +58,7 @@ def distance_matrix(client, locations, :type metrics: list of strings :param resolve_locations: Specifies whether given locations are resolved or - not. If set 'true', every element in destinations and sources will + not. If set 'true', every element in destinations and sources will contain the name element that identifies the name of the closest street. Default False. :type resolve_locations: boolean @@ -65,20 +67,20 @@ def distance_matrix(client, locations, One of ["m", "km", "m"]. Default "m". :type units: string - :param optimized: Specifies whether Dijkstra algorithm ('false') or any - available technique to speed up shortest-path routing ('true') is used. + :param optimized: Specifies whether Dijkstra algorithm ('false') or any + available technique to speed up shortest-path routing ('true') is used. For normal Dijkstra the number of visited nodes is limited to 100000. Default True :type optimized: boolean :param validate: Specifies whether parameters should be validated before sending the request. Default True. :type validate: bool - + :param dry_run: Print URL and parameters without sending the request. :param dry_run: boolean - + :raises ValueError: When profile parameter has wrong value. - + :rtype: call to Client.request() """ @@ -87,10 +89,10 @@ def distance_matrix(client, locations, } if sources: - params['sources'] = sources + params["sources"] = sources if destinations: - params['destinations'] = destinations + params["destinations"] = destinations if profile: params["profile"] = profile @@ -113,4 +115,9 @@ def distance_matrix(client, locations, if optimized is not None: params["optimized"] = optimized - return client.request("/v2/matrix/" + profile + '/json', {}, post_json=params, dry_run=dry_run) + return client.request( + "/v2/matrix/" + profile + "/json", + {}, + post_json=params, + dry_run=dry_run, + ) diff --git a/openrouteservice/elevation.py b/openrouteservice/elevation.py index 16b8d6bd..eb1b4364 100644 --- a/openrouteservice/elevation.py +++ b/openrouteservice/elevation.py @@ -14,83 +14,94 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under # the License. - """Performs requests to the ORS elevation API.""" -def elevation_point(client, format_in, geometry, - format_out='geojson', - dataset='srtm', - validate=True, - dry_run=None): +def elevation_point( + client, + format_in, + geometry, + format_out="geojson", + dataset="srtm", + validate=True, + dry_run=None, +): """ - POSTs 2D point to be enriched with elevation. - + POSTs 2D point to be enriched with elevation. # noqa + :param format_in: Format of input geometry. One of ['geojson', 'point'] :type format_in: string - - :param geometry: Point geometry + + :param geometry: Point geometry :type geometry: depending on format_in, either list of coordinates or Point geojson - + :param format_out: Format of output geometry, one of ['geojson', 'point'] :type format_out: string - + :param dataset: Elevation dataset to be used. Currently only SRTM v4.1 available. :type dataset: string - + :param dry_run: Print URL and parameters without sending the request. :param dry_run: boolean - + :returns: correctly formatted parameters :rtype: Client.request() """ params = { - 'format_in': format_in, - 'geometry': geometry, - 'format_out': format_out, - 'dataset': dataset + "format_in": format_in, + "geometry": geometry, + "format_out": format_out, + "dataset": dataset, } - return client.request('/elevation/point', {}, post_json=params, dry_run=dry_run) + return client.request( + "/elevation/point", {}, post_json=params, dry_run=dry_run + ) -def elevation_line(client, format_in, geometry, - format_out='geojson', - dataset='srtm', - validate=True, - dry_run=None): +def elevation_line( + client, + format_in, + geometry, + format_out="geojson", + dataset="srtm", + validate=True, + dry_run=None, +): """ - POSTs 2D point to be enriched with elevation. - + POSTs 2D point to be enriched with elevation. # noqa + :param format_in: Format of input geometry. One of ['geojson', 'polyline', 'encodedpolyline'] :type format_in: string - - :param geometry: Point geometry + + :param geometry: Point geometry :type geometry: depending on format_in, either list of coordinates, LineString geojson or string - + :param format_out: Format of output geometry, one of ['geojson', 'polyline', 'encodedpolyline'] :type format_out: string - + :param dataset: Elevation dataset to be used. Currently only SRTM v4.1 available. :type dataset: string - + :param dry_run: Print URL and parameters without sending the request. :param dry_run: boolean - + :returns: correctly formatted parameters :rtype: Client.request() """ params = { - 'format_in': format_in, - 'geometry': geometry, - 'format_out': format_out, - 'dataset': dataset + "format_in": format_in, + "geometry": geometry, + "format_out": format_out, + "dataset": dataset, } - return client.request('/elevation/line', {}, post_json=params, dry_run=dry_run) + return client.request( + "/elevation/line", {}, post_json=params, dry_run=dry_run + ) diff --git a/openrouteservice/exceptions.py b/openrouteservice/exceptions.py index f5f9597c..1e0a5416 100644 --- a/openrouteservice/exceptions.py +++ b/openrouteservice/exceptions.py @@ -16,51 +16,50 @@ # License for the specific language governing permissions and limitations under # the License. # - -""" -Defines exceptions that are thrown by the ORS client. -""" +"""Defines exceptions that are thrown by the ORS client.""" class ValidationError(Exception): - """Something went wrong during cerberus validation""" + """Something went wrong during cerberus validation.""" - def __init__(self, errors): - msg = '\n'.join(["{}".format(str(errors))]) + def __init__(self, errors): # noqa + msg = "\n".join(["{}".format(str(errors))]) Exception.__init__(self, msg) class ApiError(Exception): """Represents an exception returned by the remote API.""" - def __init__(self, status, message=None): + def __init__(self, status, message=None): # noqa self.status = status self.message = message - def __str__(self): + def __str__(self): # noqa if self.message is None: return str(self.status) else: - return "%s (%s)" % (self.status, self.message) + return "%s (%s)" % (self.status, self.message) # noqa class HTTPError(Exception): """An unexpected HTTP error occurred.""" - def __init__(self, status_code): + def __init__(self, status_code): # noqa self.status_code = status_code - def __str__(self): - return "HTTP Error: %d" % self.status_code + def __str__(self): # noqa + return "HTTP Error: %d" % self.status_code # noqa class Timeout(Exception): """The request timed out.""" + pass class _RetriableRequest(Exception): """Signifies that the request can be retried.""" + pass @@ -70,4 +69,5 @@ class _OverQueryLimit(ApiError, _RetriableRequest): Normally we treat this as a retriable condition, but we allow the calling code to specify that these requests should not be retried. """ + pass diff --git a/openrouteservice/geocode.py b/openrouteservice/geocode.py index 023ce264..c61ec588 100644 --- a/openrouteservice/geocode.py +++ b/openrouteservice/geocode.py @@ -16,28 +16,29 @@ # License for the specific language governing permissions and limitations under # the License. # - """Performs requests to the ORS geocode API (direct Pelias clone).""" from openrouteservice import convert -def pelias_search(client, text, - focus_point=None, - rect_min_x=None, - rect_min_y=None, - rect_max_x=None, - rect_max_y=None, - circle_point=None, - circle_radius=None, - sources=None, - layers=None, - country=None, - size=None, - validate=True, - dry_run=None): +def pelias_search( + client, + text, + focus_point=None, + rect_min_x=None, + rect_min_y=None, + rect_max_x=None, + rect_max_y=None, + circle_point=None, + circle_radius=None, + sources=None, + layers=None, + country=None, + size=None, + validate=True, + dry_run=None, +): """ - Geocoding is the process of converting addresses into geographic - coordinates. + Geocoding is the process of converting addresses into geographic coordinates. This endpoint queries directly against a Pelias instance. @@ -82,7 +83,7 @@ def pelias_search(client, text, :param size: The amount of results returned. Default 10. :type size: integer - + :param dry_run: Print URL and parameters without sending the request. :param dry_run: boolean @@ -92,59 +93,67 @@ def pelias_search(client, text, :rtype: call to Client.request() """ - params = {'text': text} + params = {"text": text} if focus_point: - params['focus.point.lon'] = convert._format_float(focus_point[0]) - params['focus.point.lat'] = convert._format_float(focus_point[1]) + params["focus.point.lon"] = convert._format_float(focus_point[0]) + params["focus.point.lat"] = convert._format_float(focus_point[1]) if rect_min_x: - params['boundary.rect.min_lon'] = convert._format_float(rect_min_x) # + params["boundary.rect.min_lon"] = convert._format_float(rect_min_x) # if rect_min_y: - params['boundary.rect.min_lat'] = convert._format_float(rect_min_y) # + params["boundary.rect.min_lat"] = convert._format_float(rect_min_y) # if rect_max_x: - params['boundary.rect.max_lon'] = convert._format_float(rect_max_x) # + params["boundary.rect.max_lon"] = convert._format_float(rect_max_x) # if rect_max_y: - params['boundary.rect.max_lat'] = convert._format_float(rect_max_y) # + params["boundary.rect.max_lat"] = convert._format_float(rect_max_y) # if circle_point: - params['boundary.circle.lon'] = convert._format_float(circle_point[0]) # - params['boundary.circle.lat'] = convert._format_float(circle_point[1]) # + params["boundary.circle.lon"] = convert._format_float( + circle_point[0] + ) # + params["boundary.circle.lat"] = convert._format_float( + circle_point[1] + ) # if circle_radius: - params['boundary.circle.radius'] = circle_radius + params["boundary.circle.radius"] = circle_radius if sources: - params['sources'] = convert._comma_list(sources) + params["sources"] = convert._comma_list(sources) if layers: - params['layers'] = convert._comma_list(layers) + params["layers"] = convert._comma_list(layers) if country: - params['boundary.country'] = country + params["boundary.country"] = country if size: - params['size'] = size + params["size"] = size return client.request("/geocode/search", params, dry_run=dry_run) -def pelias_autocomplete(client, text, - focus_point=None, - rect_min_x=None, - rect_min_y=None, - rect_max_x=None, - rect_max_y=None, - country=None, - sources=None, - layers=None, - validate=True, - dry_run=None): +def pelias_autocomplete( + client, + text, + focus_point=None, + rect_min_x=None, + rect_min_y=None, + rect_max_x=None, + rect_max_y=None, + country=None, + sources=None, + layers=None, + validate=True, + dry_run=None, +): """ Autocomplete geocoding can be used alongside /search to enable real-time feedback. + It represents a type-ahead functionality, which helps to find the desired location, without to require a fully specified search term. @@ -183,7 +192,7 @@ def pelias_autocomplete(client, text, https://github.com/pelias/documentation/blob/master/search.md#filter-by-data-type for details. :type layers: list of strings - + :param dry_run: Print URL and parameters without sending the request. :param dry_run: boolean @@ -193,51 +202,53 @@ def pelias_autocomplete(client, text, :rtype: dict from JSON response """ - params = {'text': text} + params = {"text": text} if focus_point: - params['focus.point.lon'] = convert._format_float(focus_point[0]) - params['focus.point.lat'] = convert._format_float(focus_point[1]) + params["focus.point.lon"] = convert._format_float(focus_point[0]) + params["focus.point.lat"] = convert._format_float(focus_point[1]) if rect_min_x: - params['boundary.rect.min_lon '] = convert._format_float(rect_min_x) + params["boundary.rect.min_lon "] = convert._format_float(rect_min_x) if rect_min_y: - params['boundary.rect.min_lat '] = convert._format_float(rect_min_y) + params["boundary.rect.min_lat "] = convert._format_float(rect_min_y) if rect_max_x: - params['boundary.rect.max_lon '] = convert._format_float(rect_max_x) + params["boundary.rect.max_lon "] = convert._format_float(rect_max_x) if rect_max_y: - params['boundary.rect.max_lon '] = convert._format_float(rect_max_y) + params["boundary.rect.max_lon "] = convert._format_float(rect_max_y) if country: - params['boundary.country'] = country + params["boundary.country"] = country if sources: - params['sources'] = convert._comma_list(sources) + params["sources"] = convert._comma_list(sources) if layers: - params['layers'] = convert._comma_list(layers) + params["layers"] = convert._comma_list(layers) return client.request("/geocode/autocomplete", params, dry_run=dry_run) -def pelias_structured(client, - address=None, - neighbourhood=None, - borough=None, - locality=None, - county=None, - region=None, - postalcode=None, - country=None, - validate=True, - dry_run=None, - # size=None - ): +def pelias_structured( + client, + address=None, + neighbourhood=None, + borough=None, + locality=None, + county=None, + region=None, + postalcode=None, + country=None, + validate=True, + dry_run=None, + # size=None +): """ With structured geocoding, you can search for the individual parts of a location. + Structured geocoding is an option on the search endpoint, which allows you to define a query that maintains the individual fields. @@ -275,7 +286,7 @@ def pelias_structured(client, :param country: Highest-level divisions supported in a search. Can be a full name or abbreviation. :type country: string - + :param dry_run: Print URL and parameters without sending the request. :param dry_run: boolean @@ -284,46 +295,48 @@ def pelias_structured(client, :rtype: dict from JSON response """ - params = dict() + params = {} if address: - params['address'] = address + params["address"] = address if neighbourhood: - params['neighbourhood'] = neighbourhood + params["neighbourhood"] = neighbourhood if borough: - params['borough'] = borough + params["borough"] = borough if locality: - params['locality'] = locality + params["locality"] = locality if county: - params['county'] = county + params["county"] = county if region: - params['region'] = region + params["region"] = region if postalcode: - params['postalcode'] = postalcode + params["postalcode"] = postalcode if country: - params['country'] = country + params["country"] = country return client.request("/geocode/search/structured", params, dry_run=dry_run) -def pelias_reverse(client, point, - circle_radius=None, - sources=None, - layers=None, - country=None, - size=None, - validate=True, - dry_run=None): +def pelias_reverse( + client, + point, + circle_radius=None, + sources=None, + layers=None, + country=None, + size=None, + validate=True, + dry_run=None, +): """ - Reverse geocoding is the process of converting geographic coordinates into a - human-readable address. + Reverse geocoding is the process of converting geographic coordinates into a human-readable address. This endpoint queries directly against a Pelias instance. @@ -349,7 +362,7 @@ def pelias_reverse(client, point, :param size: The amount of results returned. Default 10. :type size: integer - + :param dry_run: Print URL and parameters without sending the request. :param dry_run: boolean @@ -358,24 +371,24 @@ def pelias_reverse(client, point, :rtype: dict from JSON response """ - params = dict() - - params['point.lon'] = convert._format_float(point[0]) - params['point.lat'] = convert._format_float(point[1]) + params = { + "point.lon": convert._format_float(point[0]), + "point.lat": convert._format_float(point[1]), + } if circle_radius: - params['boundary.circle.radius'] = str(circle_radius) + params["boundary.circle.radius"] = str(circle_radius) if sources: - params['sources'] = convert._comma_list(sources) + params["sources"] = convert._comma_list(sources) if layers: - params['layers'] = convert._comma_list(layers) + params["layers"] = convert._comma_list(layers) if country: - params['boundary.country'] = country + params["boundary.country"] = country if size: - params['size'] = size + params["size"] = size return client.request("/geocode/reverse", params, dry_run=dry_run) diff --git a/openrouteservice/isochrones.py b/openrouteservice/isochrones.py index 12436892..d80fe757 100644 --- a/openrouteservice/isochrones.py +++ b/openrouteservice/isochrones.py @@ -14,26 +14,28 @@ # License for the specific language governing permissions and limitations under # the License. # - """Performs requests to the ORS isochrones API.""" from openrouteservice import deprecation -def isochrones(client, locations, - profile='driving-car', - range_type='time', - range=None, - intervals=None, - segments=None, - interval=None, - units=None, - location_type=None, - smoothing=None, - attributes=None, - validate=True, - dry_run=None): - """ Gets travel distance and time for a matrix of origins and destinations. +def isochrones( + client, + locations, + profile="driving-car", + range_type="time", + range=None, + intervals=None, + segments=None, + interval=None, + units=None, + location_type=None, + smoothing=None, + attributes=None, + validate=True, + dry_run=None, +): + """Gets travel distance and time for a matrix of origins and destinations. :param locations: One pair of lng/lat values. :type locations: list or tuple of lng,lat values @@ -68,7 +70,7 @@ def isochrones(client, locations, :param units: Specifies the unit system to use when displaying results. One of ["m", "km", "m"]. Default "m". :type units: string - + :param location_type: 'start' treats the location(s) as starting point, 'destination' as goal. Default 'start'. :type location_type: string @@ -85,48 +87,51 @@ def isochrones(client, locations, :param validate: Specifies whether parameters should be validated before sending the request. Default True. :type validate: bool - + :param dry_run: Print URL and parameters without sending the request. :param dry_run: boolean - + :raises ValueError: When parameter has invalid value(s). - + :rtype: call to Client.request() """ - params = { - "locations": locations - } + params = {"locations": locations} - if profile: + if profile: # pragma: no cover params["profile"] = profile - if range_type: + if range_type: # pragma: no cover params["range_type"] = range_type - if intervals: - deprecation.warning('intervals', 'range') + if intervals: # pragma: no cover + deprecation.warning("intervals", "range") range = range or intervals - params['range'] = range + params["range"] = range - if segments: - deprecation.warning('segments', 'interval') + if segments: # pragma: no cover + deprecation.warning("segments", "interval") interval = interval or segments - if interval: - params['interval'] = interval + if interval: # pragma: no cover + params["interval"] = interval - if units: + if units: # pragma: no cover params["units"] = units - if location_type: + if location_type: # pragma: no cover params["location_type"] = location_type - if smoothing: + if smoothing: # pragma: no cover params["smoothing"] = smoothing - if attributes: + if attributes: # pragma: no cover params["attributes"] = attributes - return client.request("/v2/isochrones/" + profile + '/geojson', {}, post_json=params, dry_run=dry_run) + return client.request( + "/v2/isochrones/" + profile + "/geojson", + {}, + post_json=params, + dry_run=dry_run, + ) diff --git a/openrouteservice/optimization.py b/openrouteservice/optimization.py index 0c05c8ce..c15250ca 100644 --- a/openrouteservice/optimization.py +++ b/openrouteservice/optimization.py @@ -14,18 +14,20 @@ # License for the specific language governing permissions and limitations under # the License. # - """Performs requests to the ORS optimization API.""" -def optimization(client, - jobs=None, - vehicles=None, - shipments=None, - matrix=None, - geometry=None, - dry_run=None): - """Optimize a fleet of vehicles on a number of jobs. +def optimization( + client, + jobs=None, + vehicles=None, + shipments=None, + matrix=None, + geometry=None, + dry_run=None, +): + """# noqa + Optimize a fleet of vehicles on a number of jobs. For more information, visit https://github.com/VROOM-Project/vroom/blob/master/docs/API.md. @@ -63,38 +65,40 @@ def optimization(client, :rtype: dict """ - assert all([isinstance(x, Vehicle) for x in vehicles]) + assert all([isinstance(x, Vehicle) for x in vehicles]) # noqa params = {"vehicles": [vehicle.__dict__ for vehicle in vehicles]} if jobs: - assert all([isinstance(x, Job) for x in jobs]) - params['jobs'] = [job.__dict__ for job in jobs] + assert all([isinstance(x, Job) for x in jobs]) # noqa + params["jobs"] = [job.__dict__ for job in jobs] if shipments: - assert all([isinstance(x, Shipment) for x in shipments]) - params['shipments'] = list() + assert all([isinstance(x, Shipment) for x in shipments]) # noqa + params["shipments"] = [] for shipment in shipments: - shipment_dict = dict() - if getattr(shipment, 'pickup'): + shipment_dict = {} + if hasattr(shipment, "pickup"): assert isinstance(shipment.pickup, ShipmentStep) - shipment_dict['pickup'] = shipment.pickup.__dict__ - if getattr(shipment, 'delivery'): + shipment_dict["pickup"] = shipment.pickup.__dict__ + if hasattr(shipment, "delivery"): assert isinstance(shipment.delivery, ShipmentStep) - shipment_dict['delivery'] = shipment.delivery.__dict__ - shipment_dict['amount'] = shipment.amount - shipment_dict['skills'] = shipment.skills - shipment_dict['priority'] = shipment.priority + shipment_dict["delivery"] = shipment.delivery.__dict__ + shipment_dict["amount"] = shipment.amount + shipment_dict["skills"] = shipment.skills + shipment_dict["priority"] = shipment.priority - params['shipments'].append(shipment_dict) + params["shipments"].append(shipment_dict) if geometry is not None: params.update({"options": {"g": geometry}}) if matrix: - params['matrix'] = matrix + params["matrix"] = matrix - return client.request("/optimization", {}, post_json=params, dry_run=dry_run) + return client.request( + "/optimization", {}, post_json=params, dry_run=dry_run + ) class Job(object): @@ -103,16 +107,18 @@ class Job(object): Full documentation at https://github.com/VROOM-Project/vroom/blob/master/docs/API.md#jobs. """ - def __init__(self, - id, - location=None, - location_index=None, - service=None, - amount=None, - skills=None, - priority=None, - time_windows=None - ): + + def __init__( + self, + id, + location=None, + location_index=None, + service=None, + amount=None, + skills=None, + priority=None, + time_windows=None, + ): """ Create a job object for the optimization endpoint. @@ -172,13 +178,15 @@ class ShipmentStep(object): Full documentation at https://github.com/VROOM-Project/vroom/blob/master/docs/API.md#shipments. """ - def __init__(self, - id=None, - location=None, - location_index=None, - service=None, - time_windows=None - ): + + def __init__( + self, + id=None, + location=None, + location_index=None, + service=None, + time_windows=None, + ): """ Create a shipment step object for the optimization endpoint. @@ -220,13 +228,15 @@ class Shipment(object): Full documentation at https://github.com/VROOM-Project/vroom/blob/master/docs/API.md#shipments. """ - def __init__(self, - pickup=None, - delivery=None, - amount=None, - skills=None, - priority=None - ): + + def __init__( + self, + pickup=None, + delivery=None, + amount=None, + skills=None, + priority=None, + ): """ Create a shipment object for the optimization endpoint. @@ -269,16 +279,18 @@ class Vehicle(object): Full documentation at https://github.com/VROOM-Project/vroom/blob/master/docs/API.md#vehicles. """ - def __init__(self, - id, - profile='driving-car', - start=None, - start_index=None, - end=None, - end_index=None, - capacity=None, - skills=None, - time_window=None): + def __init__( + self, + id, + profile="driving-car", + start=None, + start_index=None, + end=None, + end_index=None, + capacity=None, + skills=None, + time_window=None, + ): """ Create a Vehicle object for the optimization endpoint. diff --git a/openrouteservice/places.py b/openrouteservice/places.py index bc0675ac..d1390cf4 100644 --- a/openrouteservice/places.py +++ b/openrouteservice/places.py @@ -14,25 +14,26 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under # the License. - """Performs requests to the ORS Places API.""" from openrouteservice import convert -def places(client, request, - geojson=None, - bbox=None, - buffer=None, - filter_category_ids=None, - filter_category_group_ids=None, - filters_custom=None, - limit=None, - sortby=None, - validate=True, - dry_run=None - ): - """ Gets POI's filtered by specified parameters. +def places( + client, + request, + geojson=None, + bbox=None, + buffer=None, + filter_category_ids=None, + filter_category_group_ids=None, + filters_custom=None, + limit=None, + sortby=None, + validate=True, + dry_run=None, +): + """Gets POI's filtered by specified parameters. :param request: Type of request. One of ['pois', 'list', 'stats']. 'pois': returns geojson of pois; @@ -55,7 +56,7 @@ def places(client, request, :param filter_category_group_ids: Filter by ORS custom high-level category groups. See https://github.com/GIScience/openrouteservice-docs#places-response - for the mappings. + for the mappings. :type attributes: list of integer :param filters_custom: Specify additional filters by key/value. Default ORS @@ -69,47 +70,49 @@ def places(client, request, :param limit: limit for POI queries. :type limit: integer base_url='http://localhost:5000' - - :param sortby: Sorts the returned features by 'distance' or 'category'. + + :param sortby: Sorts the returned features by 'distance' or 'category'. For request='pois' only. :type sortby: string - + :param dry_run: Print URL and parameters without sending the request. :param dry_run: boolean - + :rtype: call to Client.request() """ params = { - 'request': request, - 'filters': dict(), - 'geometry': dict(), + "request": request, + "filters": {}, + "geometry": {}, } - if request != 'category_list': + if request != "category_list": if geojson: - params['geometry']['geojson'] = geojson + params["geometry"]["geojson"] = geojson if bbox: - params['geometry']['bbox'] = bbox + params["geometry"]["bbox"] = bbox if buffer: - params['geometry']['buffer'] = buffer + params["geometry"]["buffer"] = buffer if filter_category_ids and convert._is_list(filter_category_ids): - params['filters']['category_ids'] = filter_category_ids + params["filters"]["category_ids"] = filter_category_ids - if filter_category_group_ids and convert._is_list(filter_category_group_ids): - params['filters']['category_group_ids'] = filter_category_group_ids + if filter_category_group_ids and convert._is_list( + filter_category_group_ids + ): + params["filters"]["category_group_ids"] = filter_category_group_ids if filters_custom: for f in filters_custom: - params['filters'][f] = filters_custom[f] + params["filters"][f] = filters_custom[f] if limit: - params['limit'] = limit + params["limit"] = limit if sortby: - params['sortby'] = sortby + params["sortby"] = sortby - return client.request('/pois', {}, post_json=params, dry_run=dry_run) + return client.request("/pois", {}, post_json=params, dry_run=dry_run) diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..198e5e95 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,644 @@ +[[package]] +name = "appdirs" +version = "1.4.4" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "atomicwrites" +version = "1.4.0" +description = "Atomic file writes." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "attrs" +version = "21.2.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] + +[[package]] +name = "certifi" +version = "2020.12.5" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "cfgv" +version = "3.0.0" +description = "Validate configuration and produce human readable error messages." +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "chardet" +version = "4.0.0" +description = "Universal encoding detector for Python 2 and 3" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "coverage" +version = "5.5" +description = "Code coverage measurement for Python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.dependencies] +toml = {version = "*", optional = true, markers = "extra == \"toml\""} + +[package.extras] +toml = ["toml"] + +[[package]] +name = "distlib" +version = "0.3.1" +description = "Distribution utilities" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "filelock" +version = "3.0.12" +description = "A platform independent file lock." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "identify" +version = "1.6.2" +description = "File identification library for Python" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" + +[package.extras] +license = ["editdistance"] + +[[package]] +name = "idna" +version = "2.10" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "importlib-metadata" +version = "4.0.1" +description = "Read metadata from Python packages" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} +zipp = ">=0.5" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] + +[[package]] +name = "importlib-resources" +version = "5.1.4" +description = "Read resources from Python packages" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy"] + +[[package]] +name = "iniconfig" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "nodeenv" +version = "1.6.0" +description = "Node.js virtual environment builder" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "packaging" +version = "20.9" +description = "Core utilities for Python packages" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +pyparsing = ">=2.0.2" + +[[package]] +name = "pluggy" +version = "0.13.1" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} + +[package.extras] +dev = ["pre-commit", "tox"] + +[[package]] +name = "poetry-semver" +version = "0.1.0" +description = "A semantic versioning library for Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "poetry2conda" +version = "0.3.0" +description = "Convert pyproject.toml to environment.yaml" +category = "main" +optional = false +python-versions = ">=3.6,<4.0" + +[package.dependencies] +poetry-semver = ">=0.1.0,<0.2.0" +toml = ">=0.10.0,<0.11.0" + +[[package]] +name = "pre-commit" +version = "2.1.1" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} +importlib-resources = {version = "*", markers = "python_version < \"3.7\""} +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +toml = "*" +virtualenv = ">=15.2" + +[[package]] +name = "py" +version = "1.10.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pyparsing" +version = "2.4.7" +description = "Python parsing module" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "pytest" +version = "6.2.4" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<1.0.0a1" +py = ">=1.8.2" +toml = "*" + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "2.12.0" +description = "Pytest plugin for measuring coverage." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests (==2.0.2)", "six", "pytest-xdist", "virtualenv"] + +[[package]] +name = "pyyaml" +version = "5.4.1" +description = "YAML parser and emitter for Python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[[package]] +name = "requests" +version = "2.25.1" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +certifi = ">=2017.4.17" +chardet = ">=3.0.2,<5" +idna = ">=2.5,<3" +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] + +[[package]] +name = "responses" +version = "0.13.3" +description = "A utility library for mocking out the `requests` Python library." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +requests = ">=2.0" +six = "*" +urllib3 = ">=1.25.10" + +[package.extras] +tests = ["coverage (>=3.7.1,<6.0.0)", "pytest-cov", "pytest-localserver", "flake8", "pytest (>=4.6,<5.0)", "pytest (>=4.6)", "mypy"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "tox" +version = "3.23.1" +description = "tox is a generic virtualenv management and test command line tool" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[package.dependencies] +colorama = {version = ">=0.4.1", markers = "platform_system == \"Windows\""} +filelock = ">=3.0.0" +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +packaging = ">=14" +pluggy = ">=0.12.0" +py = ">=1.4.17" +six = ">=1.14.0" +toml = ">=0.9.4" +virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2,<20.0.3 || >20.0.3,<20.0.4 || >20.0.4,<20.0.5 || >20.0.5,<20.0.6 || >20.0.6,<20.0.7 || >20.0.7" + +[package.extras] +docs = ["pygments-github-lexers (>=0.0.5)", "sphinx (>=2.0.0)", "sphinxcontrib-autoprogram (>=0.1.5)", "towncrier (>=18.5.0)"] +testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "psutil (>=5.6.1)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-randomly (>=1.0.0)", "pytest-xdist (>=1.22.2)", "pathlib2 (>=2.3.3)"] + +[[package]] +name = "typing-extensions" +version = "3.10.0.0" +description = "Backported and Experimental Type Hints for Python 3.5+" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "urllib3" +version = "1.26.4" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotlipy (>=0.6.0)"] + +[[package]] +name = "virtualenv" +version = "20.4.7" +description = "Virtual Python Environment builder" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" + +[package.dependencies] +appdirs = ">=1.4.3,<2" +distlib = ">=0.3.1,<1" +filelock = ">=3.0.0,<4" +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +importlib-resources = {version = ">=1.0", markers = "python_version < \"3.7\""} +six = ">=1.9.0,<2" + +[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 (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)", "xonsh (>=0.9.16)"] + +[[package]] +name = "yapf" +version = "0.31.0" +description = "A formatter for Python code." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "zipp" +version = "3.4.1" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] + +[metadata] +lock-version = "1.1" +python-versions = ">=3.6, <4.0" +content-hash = "d33e8de61e41e8ad73d0e32e8f5457d0ff7a449e26425e1a122b92340936d4a3" + +[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"}, +] +atomicwrites = [ + {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, + {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, +] +attrs = [ + {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, + {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, +] +certifi = [ + {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, + {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, +] +cfgv = [ + {file = "cfgv-3.0.0-py2.py3-none-any.whl", hash = "sha256:f22b426ed59cd2ab2b54ff96608d846c33dfb8766a67f0b4a6ce130ce244414f"}, + {file = "cfgv-3.0.0.tar.gz", hash = "sha256:04b093b14ddf9fd4d17c53ebfd55582d27b76ed30050193c14e560770c5360eb"}, +] +chardet = [ + {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, + {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, +] +colorama = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] +coverage = [ + {file = "coverage-5.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"}, + {file = "coverage-5.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b"}, + {file = "coverage-5.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669"}, + {file = "coverage-5.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90"}, + {file = "coverage-5.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c"}, + {file = "coverage-5.5-cp27-cp27m-win32.whl", hash = "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a"}, + {file = "coverage-5.5-cp27-cp27m-win_amd64.whl", hash = "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81"}, + {file = "coverage-5.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6"}, + {file = "coverage-5.5-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0"}, + {file = "coverage-5.5-cp310-cp310-win_amd64.whl", hash = "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae"}, + {file = "coverage-5.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb"}, + {file = "coverage-5.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160"}, + {file = "coverage-5.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"}, + {file = "coverage-5.5-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701"}, + {file = "coverage-5.5-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793"}, + {file = "coverage-5.5-cp35-cp35m-win32.whl", hash = "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e"}, + {file = "coverage-5.5-cp35-cp35m-win_amd64.whl", hash = "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3"}, + {file = "coverage-5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066"}, + {file = "coverage-5.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a"}, + {file = "coverage-5.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465"}, + {file = "coverage-5.5-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb"}, + {file = "coverage-5.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821"}, + {file = "coverage-5.5-cp36-cp36m-win32.whl", hash = "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45"}, + {file = "coverage-5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184"}, + {file = "coverage-5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a"}, + {file = "coverage-5.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53"}, + {file = "coverage-5.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d"}, + {file = "coverage-5.5-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638"}, + {file = "coverage-5.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3"}, + {file = "coverage-5.5-cp37-cp37m-win32.whl", hash = "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a"}, + {file = "coverage-5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a"}, + {file = "coverage-5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6"}, + {file = "coverage-5.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2"}, + {file = "coverage-5.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759"}, + {file = "coverage-5.5-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873"}, + {file = "coverage-5.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a"}, + {file = "coverage-5.5-cp38-cp38-win32.whl", hash = "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6"}, + {file = "coverage-5.5-cp38-cp38-win_amd64.whl", hash = "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502"}, + {file = "coverage-5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b"}, + {file = "coverage-5.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529"}, + {file = "coverage-5.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b"}, + {file = "coverage-5.5-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff"}, + {file = "coverage-5.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b"}, + {file = "coverage-5.5-cp39-cp39-win32.whl", hash = "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6"}, + {file = "coverage-5.5-cp39-cp39-win_amd64.whl", hash = "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03"}, + {file = "coverage-5.5-pp36-none-any.whl", hash = "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079"}, + {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"}, + {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, +] +distlib = [ + {file = "distlib-0.3.1-py2.py3-none-any.whl", hash = "sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb"}, + {file = "distlib-0.3.1.zip", hash = "sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1"}, +] +filelock = [ + {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, + {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, +] +identify = [ + {file = "identify-1.6.2-py2.py3-none-any.whl", hash = "sha256:8f9879b5b7cca553878d31548a419ec2f227d3328da92fe8202bc5e546d5cbc3"}, + {file = "identify-1.6.2.tar.gz", hash = "sha256:1c2014f6985ed02e62b2e6955578acf069cb2c54859e17853be474bfe7e13bed"}, +] +idna = [ + {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, + {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, +] +importlib-metadata = [ + {file = "importlib_metadata-4.0.1-py3-none-any.whl", hash = "sha256:d7eb1dea6d6a6086f8be21784cc9e3bcfa55872b52309bc5fad53a8ea444465d"}, + {file = "importlib_metadata-4.0.1.tar.gz", hash = "sha256:8c501196e49fb9df5df43833bdb1e4328f64847763ec8a50703148b73784d581"}, +] +importlib-resources = [ + {file = "importlib_resources-5.1.4-py3-none-any.whl", hash = "sha256:e962bff7440364183203d179d7ae9ad90cb1f2b74dcb84300e88ecc42dca3351"}, + {file = "importlib_resources-5.1.4.tar.gz", hash = "sha256:54161657e8ffc76596c4ede7080ca68cb02962a2e074a2586b695a93a925d36e"}, +] +iniconfig = [ + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, + {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, +] +nodeenv = [ + {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"}, + {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"}, +] +packaging = [ + {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, + {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, +] +pluggy = [ + {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, + {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, +] +poetry-semver = [ + {file = "poetry-semver-0.1.0.tar.gz", hash = "sha256:d809b612aa27b39bf2d0fc9d31b4f4809b0e972646c5f19cfa46c725b7638810"}, + {file = "poetry_semver-0.1.0-py2.py3-none-any.whl", hash = "sha256:4e6349bd7231cc657f0e1930f7b204e87e33dfd63eef5cac869363969515083a"}, +] +poetry2conda = [ + {file = "poetry2conda-0.3.0-py3-none-any.whl", hash = "sha256:218618d37331bd6d3d3007edcf21d71802990a0ce9c27e8bb23f739cfa82ed03"}, + {file = "poetry2conda-0.3.0.tar.gz", hash = "sha256:574b6295ff877ff8fb56fe2034160ff9ee9db55a3f3c2faec65458e69125491b"}, +] +pre-commit = [ + {file = "pre_commit-2.1.1-py2.py3-none-any.whl", hash = "sha256:09ebe467f43ce24377f8c2f200fe3cd2570d328eb2ce0568c8e96ce19da45fa6"}, + {file = "pre_commit-2.1.1.tar.gz", hash = "sha256:f8d555e31e2051892c7f7b3ad9f620bd2c09271d87e9eedb2ad831737d6211eb"}, +] +py = [ + {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, + {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, +] +pyparsing = [ + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, +] +pytest = [ + {file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"}, + {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"}, +] +pytest-cov = [ + {file = "pytest-cov-2.12.0.tar.gz", hash = "sha256:8535764137fecce504a49c2b742288e3d34bc09eed298ad65963616cc98fd45e"}, + {file = "pytest_cov-2.12.0-py2.py3-none-any.whl", hash = "sha256:95d4933dcbbacfa377bb60b29801daa30d90c33981ab2a79e9ab4452c165066e"}, +] +pyyaml = [ + {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, + {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, + {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, + {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, + {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"}, + {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, + {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, + {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"}, + {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, + {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, + {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, +] +requests = [ + {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, + {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, +] +responses = [ + {file = "responses-0.13.3-py2.py3-none-any.whl", hash = "sha256:b54067596f331786f5ed094ff21e8d79e6a1c68ef625180a7d34808d6f36c11b"}, + {file = "responses-0.13.3.tar.gz", hash = "sha256:18a5b88eb24143adbf2b4100f328a2f5bfa72fbdacf12d97d41f07c26c45553d"}, +] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] +toml = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] +tox = [ + {file = "tox-3.23.1-py2.py3-none-any.whl", hash = "sha256:b0b5818049a1c1997599d42012a637a33f24c62ab8187223fdd318fa8522637b"}, + {file = "tox-3.23.1.tar.gz", hash = "sha256:307a81ddb82bd463971a273f33e9533a24ed22185f27db8ce3386bff27d324e3"}, +] +typing-extensions = [ + {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, + {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, + {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"}, +] +urllib3 = [ + {file = "urllib3-1.26.4-py2.py3-none-any.whl", hash = "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df"}, + {file = "urllib3-1.26.4.tar.gz", hash = "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"}, +] +virtualenv = [ + {file = "virtualenv-20.4.7-py2.py3-none-any.whl", hash = "sha256:2b0126166ea7c9c3661f5b8e06773d28f83322de7a3ff7d06f0aed18c9de6a76"}, + {file = "virtualenv-20.4.7.tar.gz", hash = "sha256:14fdf849f80dbb29a4eb6caa9875d476ee2a5cf76a5f5415fa2f1606010ab467"}, +] +yapf = [ + {file = "yapf-0.31.0-py2.py3-none-any.whl", hash = "sha256:e3a234ba8455fe201eaa649cdac872d590089a18b661e39bbac7020978dd9c2e"}, + {file = "yapf-0.31.0.tar.gz", hash = "sha256:408fb9a2b254c302f49db83c59f9aa0b4b0fd0ec25be3a5c51181327922ff63d"}, +] +zipp = [ + {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, + {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..780cc8b3 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,29 @@ +[tool.poetry] +name = "openrouteservice" +version = "2.3.3" +description = "Python client for requests to openrouteservice API services." +authors = ["Julian Psotta "] +readme = 'README.rst' +license = "Apache2" + +[tool.poetry.dependencies] +python = ">=3.6, <4.0" +requests = ">=2.0" +responses = ">=0.12" +poetry2conda = "^0.3.0" +#pytest-random-order = "^1.0.4" + + +[tool.poetry.dev-dependencies] +pytest = ">=4.1.0" +pytest-cov = ">=2.0.0" +yapf = ">=0.30.0" +importlib-metadata = ">=2.1.1" +virtualenv = { version = ">=20.4.2", python = ">=3.6, <4.0" } +tox = { version = ">=3.21.4", python = ">=3.6, <4.0" } +pre-commit = { version = ">=2.1.1", python = ">=3.6, <4.0" } +coverage = "^5.4" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 98e37272..00000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,5 +0,0 @@ -requests>=2.0 -nose>=1.0 -responses>=0.10 -coveralls>=1.7.0 -coverage>=4.5.0 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 856cb457..00000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -requests>=2.0 diff --git a/setup.py b/setup.py deleted file mode 100644 index 7be4a511..00000000 --- a/setup.py +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: utf-8 -*- -import sys -import os.path - -try: - from setuptools import setup -except ImportError: - from distutils.core import setup - -if sys.version_info <= (2, 6): - error = 'Requires Python Version 2.7 or above... exiting.' - print(sys.stderr, error) - sys.exit(1) - -here = os.path.abspath(os.path.dirname(__file__)) - - -def readme(): - with open(os.path.join(here, 'README.rst')) as f: - return f.read() - - -setup( - name='openrouteservice', - version='2.3.3', - description='Python client for requests to openrouteservice API services', - long_description=readme(), - long_description_content_type='text/x-rst', - classifiers=[ - 'Development Status :: 4 - Beta', - 'License :: OSI Approved :: Apache Software License', - 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy' - ], - keywords='routing accessibility router OSM ORS openrouteservice openstreetmap isochrone POI elevation DEM', - url='https://github.com/GIScience/openrouteservice-py', - author='Nils Nolde', - author_email='nils.nolde@gmail.com', - license='Apache-2.0', - packages=['openrouteservice'], - install_requires=[ - 'requests>=2.0'], - include_package_data=True, - test_suite='nose.collector', - tests_require=['nose>1.0', - 'requests>=2.0', - 'responses>=0.10', - 'coveralls>=1.7.0', - 'coverage>=4.5.0'], - zip_safe=False -) diff --git a/test/__init__.py b/test/__init__.py index 5c1ba40b..0c5773dd 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -33,9 +33,8 @@ class TestCase(unittest.TestCase): - def setUp(self): - self.key = 'sample_key' + self.key = "sample_key" self.client = openrouteservice.Client(self.key) def assertURLEqual(self, first, second, msg=None): diff --git a/test/test_client.py b/test/test_client.py index 6df98587..f1673db1 100644 --- a/test/test_client.py +++ b/test/test_client.py @@ -16,8 +16,6 @@ # License for the specific language governing permissions and limitations under # the License. # - - """Tests for client module.""" import responses @@ -29,7 +27,6 @@ class ClientTest(_test.TestCase): - def test_no_api_key(self): with self.assertRaises(ValueError): client = openrouteservice.Client() @@ -41,91 +38,123 @@ def test_invalid_api_key(self): client.directions(PARAM_LINE) def test_urlencode(self): - encoded_params = openrouteservice.client._urlencode_params([("address", "=Sydney ~")]) + encoded_params = openrouteservice.client._urlencode_params( + [("address", "=Sydney ~")] + ) self.assertEqual("address=%3DSydney+~", encoded_params) @responses.activate def test_raise_over_query_limit(self): - valid_query = ENDPOINT_DICT['directions'] - responses.add(responses.POST, - 'https://api.openrouteservice.org/v2/directions/{}/geojson'.format(valid_query['profile']), - json=valid_query, - status=429, - content_type='application/json') + valid_query = ENDPOINT_DICT["directions"] + responses.add( + responses.POST, + "https://api.openrouteservice.org/v2/directions/{}/geojson".format( + valid_query["profile"] + ), + json=valid_query, + status=429, + content_type="application/json", + ) with self.assertRaises(openrouteservice.exceptions._OverQueryLimit): - client = openrouteservice.Client(key=self.key, retry_over_query_limit=False) + client = openrouteservice.Client( + key=self.key, retry_over_query_limit=False + ) client.directions(**valid_query) with self.assertRaises(openrouteservice.exceptions.Timeout): - client = openrouteservice.Client(key=self.key, retry_over_query_limit=True, retry_timeout=3) + client = openrouteservice.Client( + key=self.key, retry_over_query_limit=True, retry_timeout=3 + ) client.directions(**valid_query) @responses.activate def test_raise_timeout_retriable_requests(self): - # Mock query gives 503 as HTTP status, code should try a few times to + # Mock query gives 503 as HTTP status, code should try a few times to # request the same and then fail on Timout() error. retry_timeout = 3 - valid_query = ENDPOINT_DICT['directions'] - responses.add(responses.POST, - 'https://api.openrouteservice.org/v2/directions/{}/geojson'.format(valid_query['profile']), - json=valid_query, - status=503, - content_type='application/json') - - client = openrouteservice.Client(key=self.key, - retry_timeout=retry_timeout) + valid_query = ENDPOINT_DICT["directions"] + responses.add( + responses.POST, + "https://api.openrouteservice.org/v2/directions/{}/geojson".format( + valid_query["profile"] + ), + json=valid_query, + status=503, + content_type="application/json", + ) + + client = openrouteservice.Client( + key=self.key, retry_timeout=retry_timeout + ) start = time.time() with self.assertRaises(openrouteservice.exceptions.Timeout): client.directions(**valid_query) end = time.time() - self.assertTrue(retry_timeout < end - start < 2 * retry_timeout) + self.assertTrue(retry_timeout < end - start < 3 * retry_timeout) @responses.activate def test_host_override_with_parameters(self): # Test if it's possible to override host for individual hosting. - responses.add(responses.GET, - "https://foo.com/bar", - body='{"status":"OK","results":[]}', - status=200, - content_type="application/json") + responses.add( + responses.GET, + "https://foo.com/bar", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) client = openrouteservice.Client(base_url="https://foo.com") - client.request("/bar", {'bunny': 'pretty', 'fox': 'prettier'}) + client.request("/bar", {"bunny": "pretty", "fox": "prettier"}) + + request = client.req - self.assertURLEqual("https://foo.com/bar?bunny=pretty&fox=prettier", - responses.calls[0].request.url) + self.assertEqual( + "https://foo.com/bar?bunny=pretty&fox=prettier", request.url + ) + self.assertEqual("GET", request.method) + self.assertEqual({"bunny": "pretty", "fox": "prettier"}, request.params) + + self.assertURLEqual( + "https://foo.com/bar?bunny=pretty&fox=prettier", + responses.calls[0].request.url, + ) self.assertEqual(1, len(responses.calls)) @responses.activate def test_dry_run(self): # Test that nothing is requested when dry_run is 'true' - responses.add(responses.GET, - 'https://api.openrouteservice.org/directions', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') + responses.add( + responses.GET, + "https://api.openrouteservice.org/directions", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) - req = self.client.request(get_params={'format_out': 'geojson'}, - url='directions/', - dry_run='true') + req = self.client.request( + get_params={"format_out": "geojson"}, + url="directions/", + dry_run="true", + ) self.assertEqual(0, len(responses.calls)) @responses.activate def test_no_get_parameter(self): - - responses.add(responses.POST, - 'https://api.openrouteservice.org/directions', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - req = self.client.request(post_json={}, - url='v2/directions/driving-car/json', - dry_run='true') + responses.add( + responses.POST, + "https://api.openrouteservice.org/directions", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + req = self.client.request( + post_json={}, url="v2/directions/driving-car/json", dry_run="true" + ) self.assertEqual(0, len(responses.calls)) @@ -134,14 +163,20 @@ def test_no_get_parameter(self): @responses.activate def test_key_in_header(self): # Test that API key is being put in the Authorization header - query = ENDPOINT_DICT['directions'] - - responses.add(responses.POST, - 'https://api.openrouteservice.org/v2/directions/{}/geojson'.format(query['profile']), - json=ENDPOINT_DICT['directions'], - status=200, - content_type='application/json') + query = ENDPOINT_DICT["directions"] + + responses.add( + responses.POST, + "https://api.openrouteservice.org/v2/directions/{}/geojson".format( + query["profile"] + ), + json=ENDPOINT_DICT["directions"], + status=200, + content_type="application/json", + ) resp = self.client.directions(**query) - self.assertDictContainsSubset({'Authorization': self.key}, responses.calls[0].request.headers) + self.assertDictContainsSubset( + {"Authorization": self.key}, responses.calls[0].request.headers + ) diff --git a/test/test_convert.py b/test/test_convert.py index 25974a96..e0cea774 100644 --- a/test/test_convert.py +++ b/test/test_convert.py @@ -16,7 +16,6 @@ # License for the specific language governing permissions and limitations under # the License. # - """Tests for the convert module.""" import unittest @@ -25,7 +24,6 @@ class ConvertTest(unittest.TestCase): - def test_build_single_coord_tuple(self): expected = "1,2" ll = (1, 2) @@ -38,10 +36,10 @@ def test_build_single_coord_tuple(self): convert._build_coords(1) with self.assertRaises(TypeError): - convert._build_coords({'lat': 1, 'lon': 2}) + convert._build_coords({"lat": 1, "lon": 2}) with self.assertRaises(TypeError): - convert._build_coords('1,2') + convert._build_coords("1,2") def test_build_multi_coord_tuple(self): expected = "1,2|3,4" @@ -59,35 +57,37 @@ def test_build_multi_coord_tuple(self): self.assertEqual(expected, convert._build_coords(ll)) with self.assertRaises(TypeError): - convert._build_coords({{'lat': 1, 'lon': 2}, {'lat': 3, 'lon': 4}}) + convert._build_coords({{"lat": 1, "lon": 2}, {"lat": 3, "lon": 4}}) with self.assertRaises(TypeError): - convert._build_coords('[1,2],[3,4]') + convert._build_coords("[1,2],[3,4]") def test_convert_bool(self): - self.assertEqual('true', convert._convert_bool('True')) - self.assertEqual('true', convert._convert_bool('true')) - self.assertEqual('true', convert._convert_bool(True)) + self.assertEqual("true", convert._convert_bool("True")) + self.assertEqual("true", convert._convert_bool("true")) + self.assertEqual("true", convert._convert_bool(True)) def test_polyline_decode_3d(self): - syd_mel_route = (r"mlqlHat`t@OiACMvAs@HCPGJ?JAJBRFTRLJPNHDNDJ" - "@D?fACRAZCPAb@AF?HAfBQJEDAn@QFC@QD_@@QFe@Bg" - "@@KBy@?M@a@@q@?iE?C?OGgAkEwUQ{@c@gBQeAYeCIe" - "AWmDAIImACUOyBIeAC}@Ey@?QLC@_@@KBiAVmDF]Ni@" - "Zu@RYBA^_@~A{A`Ai@JCPGf@Qf@]X_@BMAMIKuBTI?G" - "E?A?ADOnCsB\c@DGDIl@sAJUFMBGJUP[DCD@DP@l@?R" - "?h@Bx@PnAAl@?BAFc@rAAB?@BRHBFEN[FQFQRg@Rw@J" - "g@Ny@DUDOJe@N_ADm@BkBGcC@s@Du@l@eEZgBP_AHe@" - "He@Fc@RuATaA?SCWAGIOQS[Qu@Ym@C}@R{@`@m@p@Wj" - "@]nAGBE?KGAE?E?KVcB`@eB^mAn@uALUJSj@y@fA}@f" - "@k@BGHM^k@r@qAHSLU^i@bA_Af@q@PYFKHIHCJ?RLFN" - "XjAj@tDj@rERzBLzCHp@xAdKLf@RXTDNEBCFGDEDE@G" - "@GDKBGRc@Xi@N[JUf@u@l@o@f@c@h@]XMfQ}D|EcAlA" - "ORIJQ?C?CAUKOSGwAMa@M_EsBcBqA_A{@k@q@sCcEi@" - "gAWo@[gAYyAMy@y@aNMyAc@uDS_As@uBMc@Ig@SeBKc" - "@Uy@AI@A]GGCMIiCmAGCWMqAk@") - - points = convert.decode_polyline(syd_mel_route, True)['coordinates'] + syd_mel_route = ( + r"mlqlHat`t@OiACMvAs@HCPGJ?JAJBRFTRLJPNHDNDJ" + "@D?fACRAZCPAb@AF?HAfBQJEDAn@QFC@QD_@@QFe@Bg" + "@@KBy@?M@a@@q@?iE?C?OGgAkEwUQ{@c@gBQeAYeCIe" + "AWmDAIImACUOyBIeAC}@Ey@?QLC@_@@KBiAVmDF]Ni@" + "Zu@RYBA^_@~A{A`Ai@JCPGf@Qf@]X_@BMAMIKuBTI?G" + "E?A?ADOnCsB\c@DGDIl@sAJUFMBGJUP[DCD@DP@l@?R" + "?h@Bx@PnAAl@?BAFc@rAAB?@BRHBFEN[FQFQRg@Rw@J" + "g@Ny@DUDOJe@N_ADm@BkBGcC@s@Du@l@eEZgBP_AHe@" + "He@Fc@RuATaA?SCWAGIOQS[Qu@Ym@C}@R{@`@m@p@Wj" + "@]nAGBE?KGAE?E?KVcB`@eB^mAn@uALUJSj@y@fA}@f" + "@k@BGHM^k@r@qAHSLU^i@bA_Af@q@PYFKHIHCJ?RLFN" + "XjAj@tDj@rERzBLzCHp@xAdKLf@RXTDNEBCFGDEDE@G" + "@GDKBGRc@Xi@N[JUf@u@l@o@f@c@h@]XMfQ}D|EcAlA" + "ORIJQ?C?CAUKOSGwAMa@M_EsBcBqA_A{@k@q@sCcEi@" + "gAWo@[gAYyAMy@y@aNMyAc@uDS_As@uBMc@Ig@SeBKc" + "@Uy@AI@A]GGCMIiCmAGCWMqAk@" + ) + + points = convert.decode_polyline(syd_mel_route, True)["coordinates"] self.assertEqual(len(points[0]), 3) self.assertAlmostEqual(8.69201, points[0][0], places=5) self.assertAlmostEqual(49.410151, points[0][1], places=5) @@ -97,9 +97,9 @@ def test_polyline_decode_3d(self): self.assertAlmostEqual(12.5, points[-1][2], places=2) def test_polyline_decode_2d(self): - syd_mel_route = (r"u`rgFswjpAKD") + syd_mel_route = r"u`rgFswjpAKD" - points = convert.decode_polyline(syd_mel_route, False)['coordinates'] + points = convert.decode_polyline(syd_mel_route, False)["coordinates"] self.assertEqual(len(points[0]), 2) self.assertAlmostEqual([13.3313, 38.10843], points[0], places=5) self.assertAlmostEqual([13.33127, 38.10849], points[1], places=5) diff --git a/test/test_deprecation_warning.py b/test/test_deprecation_warning.py index 9594d9ff..0377f861 100644 --- a/test/test_deprecation_warning.py +++ b/test/test_deprecation_warning.py @@ -6,7 +6,7 @@ # Cause all warnings to always be triggered. warnings.simplefilter("always") # Trigger a warning. - deprecation.warning('foo', 'bar') + deprecation.warning("foo", "bar") # Verify some things assert len(w) == 1 assert issubclass(w[-1].category, DeprecationWarning) diff --git a/test/test_directions.py b/test/test_directions.py index f75ea08f..b6e2db8f 100644 --- a/test/test_directions.py +++ b/test/test_directions.py @@ -16,7 +16,6 @@ # License for the specific language governing permissions and limitations under # the License. # - """Tests for the directions module.""" import responses @@ -25,30 +24,52 @@ import test as _test from copy import deepcopy -import openrouteservice +from openrouteservice import exceptions from test.test_helper import ENDPOINT_DICT class DirectionsTest(_test.TestCase): - valid_query = ENDPOINT_DICT['directions'] + valid_query = ENDPOINT_DICT["directions"] @responses.activate def test_directions(self): - responses.add(responses.POST, - 'https://api.openrouteservice.org/v2/directions/{}/geojson'.format(self.valid_query['profile']), - json=self.valid_query, - status=200, - content_type='application/json') + responses.add( + responses.POST, + "https://api.openrouteservice.org/v2/directions/{}/geojson".format( + self.valid_query["profile"] + ), + json=self.valid_query, + status=200, + content_type="application/json", + ) + + resp = self.client.directions(**self.valid_query) + + self.assertEqual(resp, self.valid_query) + self.assertIn("sample_key", responses.calls[0].request.headers.values()) + + @responses.activate + def test_directions_incompatible_parameters(self): + self.valid_query["optimized"] = True + responses.add( + responses.POST, + "https://api.openrouteservice.org/v2/directions/{}/geojson".format( + self.valid_query["profile"] + ), + json=self.valid_query, + status=200, + content_type="application/json", + ) resp = self.client.directions(**self.valid_query) self.assertEqual(resp, self.valid_query) - self.assertIn('sample_key', responses.calls[0].request.headers.values()) + self.assertIn("sample_key", responses.calls[0].request.headers.values()) def test_format_out_deprecation(self): bad_query = deepcopy(self.valid_query) - bad_query['format_out'] = "json" - bad_query['dry_run'] = True + bad_query["format_out"] = "json" + bad_query["dry_run"] = True with warnings.catch_warnings(record=True) as w: # Cause all warnings to always be triggered. @@ -62,31 +83,67 @@ def test_format_out_deprecation(self): def test_optimized_waypoints(self): query = deepcopy(self.valid_query) - query['coordinates'] = [[8.688641, 49.420577], [8.680916, 49.415776],[8.688641, 49.420577], [8.680916, 49.415776]] - query['optimize_waypoints'] = True - - responses.add(responses.POST, - 'https://api.openrouteservice.org/v2/directions/{}/geojson'.format(query['profile']), - json=query, - status=200, - content_type='application/json') + query["coordinates"] = [ + [8.688641, 49.420577], + [8.680916, 49.415776], + [8.688641, 49.420577], + [8.680916, 49.415776], + ] + query["optimize_waypoints"] = True + + responses.add( + responses.POST, + "https://api.openrouteservice.org/v2/directions/{}/geojson".format( + query["profile"] + ), + json=query, + status=200, + content_type="application/json", + ) # Too exhausting to really test this - with self.assertRaises(openrouteservice.exceptions.ApiError): + with self.assertRaises(exceptions.ApiError): + resp = self.client.directions(**query) + + def test_optimized_waypoints_shuffle(self): + query = deepcopy(self.valid_query) + query["coordinates"] = [ + [8.688641, 49.420577], + [8.680916, 49.415776], + [8.688641, 49.420577], + [8.680916, 49.415776], + ] + query["optimize_waypoints"] = True + query.pop("options") + + responses.add( + responses.POST, + "https://api.openrouteservice.org/v2/directions/{}/geojson".format( + query["profile"] + ), + json=query, + status=200, + content_type="application/json", + ) + with self.assertRaises(exceptions.ApiError): resp = self.client.directions(**query) @responses.activate def test_optimize_warnings(self): query = deepcopy(self.valid_query) - query['optimize_waypoints'] = True + query["optimize_waypoints"] = True # Test Coordinates - responses.add(responses.POST, - 'https://api.openrouteservice.org/v2/directions/{}/geojson'.format(query['profile']), - json=query, - status=200, - content_type='application/json') + responses.add( + responses.POST, + "https://api.openrouteservice.org/v2/directions/{}/geojson".format( + query["profile"] + ), + json=query, + status=200, + content_type="application/json", + ) with warnings.catch_warnings(record=True) as w: # Cause all warnings to always be triggered. @@ -99,14 +156,23 @@ def test_optimize_warnings(self): assert "4 coordinates" in str(w[-1].message) # Test Options - - query['coordinates'] = [[8.688641, 49.420577], [8.680916, 49.415776],[8.688641, 49.420577], [8.680916, 49.415776]] - responses.add(responses.POST, - 'https://api.openrouteservice.org/v2/directions/{}/geojson'.format(query['profile']), - json=query, - status=200, - content_type='application/json') + query["coordinates"] = [ + [8.688641, 49.420577], + [8.680916, 49.415776], + [8.688641, 49.420577], + [8.680916, 49.415776], + ] + + responses.add( + responses.POST, + "https://api.openrouteservice.org/v2/directions/{}/geojson".format( + query["profile"] + ), + json=query, + status=200, + content_type="application/json", + ) with warnings.catch_warnings(record=True) as w: # Cause all warnings to always be triggered. @@ -120,14 +186,18 @@ def test_optimize_warnings(self): # Test Preference - query['options'] = None - query['preference'] = 'shortest' - - responses.add(responses.POST, - 'https://api.openrouteservice.org/v2/directions/{}/geojson'.format(query['profile']), - json=query, - status=200, - content_type='application/json') + query["options"] = None + query["preference"] = "shortest" + + responses.add( + responses.POST, + "https://api.openrouteservice.org/v2/directions/{}/geojson".format( + query["profile"] + ), + json=query, + status=200, + content_type="application/json", + ) with warnings.catch_warnings(record=True) as w: # Cause all warnings to always be triggered. diff --git a/test/test_distance_matrix.py b/test/test_distance_matrix.py index d1360607..6047af6c 100644 --- a/test/test_distance_matrix.py +++ b/test/test_distance_matrix.py @@ -16,7 +16,6 @@ # License for the specific language governing permissions and limitations under # the License. # - """Tests for the distance matrix module.""" import responses import test as _test @@ -25,18 +24,22 @@ class DistanceMatrixTest(_test.TestCase): - valid_query = ENDPOINT_DICT['distance_matrix'] + valid_query = ENDPOINT_DICT["distance_matrix"] @responses.activate def test_matrix(self): query = self.valid_query.copy() - query['locations'] = tuple([tuple(x) for x in PARAM_LINE]) + query["locations"] = tuple([tuple(x) for x in PARAM_LINE]) - responses.add(responses.POST, - 'https://api.openrouteservice.org/v2/matrix/{}/json'.format(query['profile']), - json=query, - status=200, - content_type='application/json') + responses.add( + responses.POST, + "https://api.openrouteservice.org/v2/matrix/{}/json".format( + query["profile"] + ), + json=query, + status=200, + content_type="application/json", + ) resp = self.client.distance_matrix(**query) self.assertEqual(resp, self.valid_query) diff --git a/test/test_elevation.py b/test/test_elevation.py index 518041fe..be9073f3 100644 --- a/test/test_elevation.py +++ b/test/test_elevation.py @@ -14,7 +14,6 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under # the License. - """Tests for the distance matrix module.""" import responses import test as _test @@ -23,15 +22,17 @@ class ElevationTest(_test.TestCase): - valid_query = ENDPOINT_DICT['elevation_line'] + valid_query = ENDPOINT_DICT["elevation_line"] @responses.activate def test_elevation_line(self): - responses.add(responses.POST, - 'https://api.openrouteservice.org/elevation/line', - json=self.valid_query, - status=200, - content_type='application/json') + responses.add( + responses.POST, + "https://api.openrouteservice.org/elevation/line", + json=self.valid_query, + status=200, + content_type="application/json", + ) resp = self.client.elevation_line(**self.valid_query) @@ -40,12 +41,14 @@ def test_elevation_line(self): @responses.activate def test_elevation_point(self): - query = ENDPOINT_DICT['elevation_point'] - responses.add(responses.POST, - 'https://api.openrouteservice.org/elevation/point', - json=self.valid_query, - status=200, - content_type='application/json') + query = ENDPOINT_DICT["elevation_point"] + responses.add( + responses.POST, + "https://api.openrouteservice.org/elevation/point", + json=self.valid_query, + status=200, + content_type="application/json", + ) resp = self.client.elevation_point(**query) diff --git a/test/test_exceptions.py b/test/test_exceptions.py index 7441454c..c617b4b9 100644 --- a/test/test_exceptions.py +++ b/test/test_exceptions.py @@ -1,5 +1,11 @@ -from openrouteservice.exceptions import ValidationError, ApiError, \ - HTTPError, Timeout, _RetriableRequest, _OverQueryLimit +from openrouteservice.exceptions import ( + ValidationError, + ApiError, + HTTPError, + Timeout, + _RetriableRequest, + _OverQueryLimit, +) import test as _test @@ -7,33 +13,32 @@ class ExceptionTest(_test.TestCase): - def test_ValidationError(self): - exception = ValidationError('hamspam') + exception = ValidationError("hamspam") pprint(exception.__dict__) self.assertIsInstance(exception, Exception) def test_ApIError(self): - exception = ApiError(500, 'hamspam') + exception = ApiError(500, "hamspam") pprint(exception.__dict__) self.assertEqual(exception.status, 500) - self.assertEqual(exception.message, 'hamspam') + self.assertEqual(exception.message, "hamspam") - self.assertEqual(str(exception), '500 (hamspam)') + self.assertEqual(str(exception), "500 (hamspam)") exception = ApiError(500) - self.assertEqual(str(exception), '500') + self.assertEqual(str(exception), "500") def test_HTTPError(self): exception = HTTPError(500) self.assertEqual(exception.status_code, 500) - self.assertEqual(str(exception), 'HTTP Error: 500') + self.assertEqual(str(exception), "HTTP Error: 500") def test_Timeout(self): exception = Timeout() @@ -46,10 +51,10 @@ def test_RetriableRequest(self): self.assertIsInstance(exception, Exception) def test_OverQueryLimit(self): - exception = _OverQueryLimit(500, 'hamspam') + exception = _OverQueryLimit(500, "hamspam") self.assertIsInstance(exception, Exception) self.assertIsInstance(exception, ApiError) self.assertIsInstance(exception, _RetriableRequest) - self.assertEqual(str(exception), '500 (hamspam)') + self.assertEqual(str(exception), "500 (hamspam)") diff --git a/test/test_geocode.py b/test/test_geocode.py index 9dc37d14..18106a2d 100644 --- a/test/test_geocode.py +++ b/test/test_geocode.py @@ -15,8 +15,6 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under # the License. - - """Tests for the Pelias geocoding module.""" import responses @@ -26,67 +24,79 @@ class GeocodingPeliasTest(_test.TestCase): - search = ENDPOINT_DICT['pelias_search'] - autocomplete = ENDPOINT_DICT['pelias_autocomplete'] - structured = ENDPOINT_DICT['pelias_structured'] - reverse = ENDPOINT_DICT['pelias_reverse'] + search = ENDPOINT_DICT["pelias_search"] + autocomplete = ENDPOINT_DICT["pelias_autocomplete"] + structured = ENDPOINT_DICT["pelias_structured"] + reverse = ENDPOINT_DICT["pelias_reverse"] @responses.activate def test_pelias_search(self): - responses.add(responses.GET, - 'https://api.openrouteservice.org/geocode/search', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') + responses.add( + responses.GET, + "https://api.openrouteservice.org/geocode/search", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) results = self.client.pelias_search(**self.search) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( - 'https://api.openrouteservice.org/geocode/search?boundary.circle.lat=48.23424&boundary.circle.lon=8.34234&boundary.circle.radius=50&boundary.country=de&boundary.rect.max_lat=501&boundary.rect.max_lon=501&boundary.rect.min_lat=500&boundary.rect.min_lon=500&focus.point.lat=48.23424&focus.point.lon=8.34234&layers=locality%2Ccounty%2Cregion&size=50&sources=osm%2Cwof%2Cgn&text=Heidelberg', - responses.calls[0].request.url) + "https://api.openrouteservice.org/geocode/search?boundary.circle.lat=48.23424&boundary.circle.lon=8.34234&boundary.circle.radius=50&boundary.country=de&boundary.rect.max_lat=501&boundary.rect.max_lon=501&boundary.rect.min_lat=500&boundary.rect.min_lon=500&focus.point.lat=48.23424&focus.point.lon=8.34234&layers=locality%2Ccounty%2Cregion&size=50&sources=osm%2Cwof%2Cgn&text=Heidelberg", + responses.calls[0].request.url, + ) @responses.activate def test_pelias_autocomplete(self): - responses.add(responses.GET, - 'https://api.openrouteservice.org/geocode/autocomplete', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') + responses.add( + responses.GET, + "https://api.openrouteservice.org/geocode/autocomplete", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) results = self.client.pelias_autocomplete(**self.autocomplete) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( - 'https://api.openrouteservice.org/geocode/autocomplete?boundary.country=de&boundary.rect.max_lon%09=500&boundary.rect.min_lat%09=500&boundary.rect.min_lon%09=500&focus.point.lat=48.23424&focus.point.lon=8.34234&layers=locality%2Ccounty%2Cregion&sources=osm%2Cwof%2Cgn&text=Heidelberg', - responses.calls[0].request.url) + "https://api.openrouteservice.org/geocode/autocomplete?boundary.country=de&boundary.rect.max_lon%09=500&boundary.rect.min_lat%09=500&boundary.rect.min_lon%09=500&focus.point.lat=48.23424&focus.point.lon=8.34234&layers=locality%2Ccounty%2Cregion&sources=osm%2Cwof%2Cgn&text=Heidelberg", + responses.calls[0].request.url, + ) @responses.activate def test_pelias_structured(self): - responses.add(responses.GET, - 'https://api.openrouteservice.org/geocode/search/structured', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') + responses.add( + responses.GET, + "https://api.openrouteservice.org/geocode/search/structured", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) results = self.client.pelias_structured(**self.structured) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( - 'https://api.openrouteservice.org/geocode/search/structured?address=Berliner+Stra%C3%9Fe+45&borough=Heidelberg&country=de&county=Rhein-Neckar-Kreis&locality=Heidelberg&neighbourhood=Neuenheimer+Feld&postalcode=69120®ion=Baden-W%C3%BCrttemberg', - responses.calls[0].request.url) + "https://api.openrouteservice.org/geocode/search/structured?address=Berliner+Stra%C3%9Fe+45&borough=Heidelberg&country=de&county=Rhein-Neckar-Kreis&locality=Heidelberg&neighbourhood=Neuenheimer+Feld&postalcode=69120®ion=Baden-W%C3%BCrttemberg", + responses.calls[0].request.url, + ) @responses.activate def test_pelias_reverse(self): - responses.add(responses.GET, - 'https://api.openrouteservice.org/geocode/reverse', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') + responses.add( + responses.GET, + "https://api.openrouteservice.org/geocode/reverse", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) results = self.client.pelias_reverse(**self.reverse) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( - 'https://api.openrouteservice.org/geocode/reverse?boundary.circle.radius=50&boundary.country=de&layers=locality%2Ccounty%2Cregion&point.lat=48.23424&point.lon=8.34234&size=50&sources=osm%2Cwof%2Cgn', - responses.calls[0].request.url) + "https://api.openrouteservice.org/geocode/reverse?boundary.circle.radius=50&boundary.country=de&layers=locality%2Ccounty%2Cregion&point.lat=48.23424&point.lon=8.34234&size=50&sources=osm%2Cwof%2Cgn", + responses.calls[0].request.url, + ) diff --git a/test/test_helper.py b/test/test_helper.py index 916002e5..f2d12b85 100644 --- a/test/test_helper.py +++ b/test/test_helper.py @@ -9,267 +9,219 @@ PARAM_LIST_ONE = [PARAM_INT_SMALL, PARAM_INT_SMALL] PARAM_LIST_TWO = [PARAM_LIST_ONE, PARAM_LIST_ONE] -PARAM_GEOJSON_POINT = {'type': 'Point', 'coordinates': PARAM_POINT} -PARAM_GEOJSON_LINE = {'type': 'LineString', 'coordinates': PARAM_LINE} -PARAM_GEOJSON_POLY = {'type': 'Polygon', 'coordinates': PARAM_POLY} +PARAM_GEOJSON_POINT = {"type": "Point", "coordinates": PARAM_POINT} +PARAM_GEOJSON_LINE = {"type": "LineString", "coordinates": PARAM_LINE} +PARAM_GEOJSON_POLY = {"type": "Polygon", "coordinates": PARAM_POLY} ENDPOINT_DICT = { - 'directions': { - 'coordinates': PARAM_LINE, - 'profile': 'driving-car', - 'preference': 'fastest', - 'format': 'geojson', - 'units': 'mi', - 'language': 'en', - 'geometry': 'true', - 'geometry_simplify': 'false', - 'maneuvers': True, - 'suppress_warnings': False, - 'instructions': 'false', - 'instructions_format': 'html', - 'alternative_routes': { - 'share_factor': 0.6, - 'target_count': 2, - 'weight_factor': 1.4 + "directions": { + "coordinates": PARAM_LINE, + "profile": "driving-car", + "preference": "fastest", + "format": "geojson", + "units": "mi", + "language": "en", + "geometry": "true", + "geometry_simplify": "false", + "maneuvers": True, + "suppress_warnings": False, + "instructions": "false", + "instructions_format": "html", + "alternative_routes": { + "share_factor": 0.6, + "target_count": 2, + "weight_factor": 1.4, }, - 'roundabout_exits': 'true', - 'attributes': ['avgspeed'], - 'radiuses': PARAM_LIST_ONE, - 'bearings': PARAM_LIST_TWO, - 'skip_segments': [0, 1], - 'elevation': 'true', - 'extra_info': ['roadaccessrestrictions'], - 'optimized': 'false', - 'continue_straight': True, - 'options': {'avoid_features': ['highways', 'tollways']} + "roundabout_exits": "true", + "attributes": ["avgspeed"], + "radiuses": PARAM_LIST_ONE, + "bearings": PARAM_LIST_TWO, + "skip_segments": [0, 1], + "elevation": "true", + "extra_info": ["roadaccessrestrictions"], + "optimized": "false", + "continue_straight": True, + "options": {"avoid_features": ["highways", "tollways"]}, }, - 'isochrones': { - 'locations': PARAM_LINE, - 'profile': 'cycling-regular', - 'range_type': 'distance', - 'range': [PARAM_INT_BIG], - 'units': 'm', - 'location_type': 'destination', - 'attributes': ['area', 'reachfactor'], - 'interval': [PARAM_INT_SMALL] + "isochrones": { + "locations": PARAM_LINE, + "profile": "cycling-regular", + "range_type": "distance", + "range": [PARAM_INT_BIG], + "units": "m", + "location_type": "destination", + "attributes": ["area", "reachfactor"], + "interval": [PARAM_INT_SMALL], }, - 'distance_matrix': { - 'locations': PARAM_LINE, - 'sources': [1], - 'destinations': [0], - 'profile': 'driving-car', - 'metrics': ['duration', 'distance'], - 'resolve_locations': 'true', - 'units': 'mi', - 'optimized': 'false' + "distance_matrix": { + "locations": PARAM_LINE, + "sources": [1], + "destinations": [0], + "profile": "driving-car", + "metrics": ["duration", "distance"], + "resolve_locations": "true", + "units": "mi", + "optimized": "false", }, - 'elevation_point': { - 'format_in': 'geojson', - 'format_out': 'point', - 'geometry': PARAM_GEOJSON_POINT, - 'dataset': 'srtm' + "elevation_point": { + "format_in": "geojson", + "format_out": "point", + "geometry": PARAM_GEOJSON_POINT, + "dataset": "srtm", }, - 'elevation_line': { - 'format_in': 'geojson', - 'format_out': 'polyline', - 'geometry': PARAM_GEOJSON_LINE, - 'dataset': 'srtm' + "elevation_line": { + "format_in": "geojson", + "format_out": "polyline", + "geometry": PARAM_GEOJSON_LINE, + "dataset": "srtm", }, - 'pelias_search': { - 'text': 'Heidelberg', - 'focus_point': PARAM_POINT, - 'rect_min_x': PARAM_INT_BIG, - 'rect_min_y': PARAM_INT_BIG, - 'rect_max_x': PARAM_INT_BIG + 1, - 'rect_max_y': PARAM_INT_BIG + 1, - 'circle_point': PARAM_POINT, - 'circle_radius': PARAM_INT_SMALL, - 'sources': ['osm', 'wof', 'gn'], - 'layers': ['locality', 'county', 'region'], - 'country': 'de', - 'size': PARAM_INT_SMALL, + "pelias_search": { + "text": "Heidelberg", + "focus_point": PARAM_POINT, + "rect_min_x": PARAM_INT_BIG, + "rect_min_y": PARAM_INT_BIG, + "rect_max_x": PARAM_INT_BIG + 1, + "rect_max_y": PARAM_INT_BIG + 1, + "circle_point": PARAM_POINT, + "circle_radius": PARAM_INT_SMALL, + "sources": ["osm", "wof", "gn"], + "layers": ["locality", "county", "region"], + "country": "de", + "size": PARAM_INT_SMALL, }, - 'pelias_autocomplete': { - 'text': 'Heidelberg', - 'focus_point': PARAM_POINT, - 'rect_min_x': PARAM_INT_BIG, - 'rect_min_y': PARAM_INT_BIG, - 'rect_max_x': PARAM_INT_BIG, - 'rect_max_y': PARAM_INT_BIG, - 'sources': ['osm', 'wof', 'gn'], - 'layers': ['locality', 'county', 'region'], - 'country': 'de', + "pelias_autocomplete": { + "text": "Heidelberg", + "focus_point": PARAM_POINT, + "rect_min_x": PARAM_INT_BIG, + "rect_min_y": PARAM_INT_BIG, + "rect_max_x": PARAM_INT_BIG, + "rect_max_y": PARAM_INT_BIG, + "sources": ["osm", "wof", "gn"], + "layers": ["locality", "county", "region"], + "country": "de", }, - 'pelias_structured': { - 'address': 'Berliner Straße 45', - 'neighbourhood': 'Neuenheimer Feld', - 'borough': 'Heidelberg', - 'locality': 'Heidelberg', - 'county': 'Rhein-Neckar-Kreis', - 'region': 'Baden-Württemberg', - 'postalcode': 69120, - 'country': 'de', + "pelias_structured": { + "address": "Berliner Straße 45", + "neighbourhood": "Neuenheimer Feld", + "borough": "Heidelberg", + "locality": "Heidelberg", + "county": "Rhein-Neckar-Kreis", + "region": "Baden-Württemberg", + "postalcode": 69120, + "country": "de", }, - 'pelias_reverse': { - 'point': PARAM_POINT, - 'circle_radius': PARAM_INT_SMALL, - 'sources': ['osm', 'wof', 'gn'], - 'layers': ['locality', 'county', 'region'], - 'country': 'de', - 'size': PARAM_INT_SMALL, + "pelias_reverse": { + "point": PARAM_POINT, + "circle_radius": PARAM_INT_SMALL, + "sources": ["osm", "wof", "gn"], + "layers": ["locality", "county", "region"], + "country": "de", + "size": PARAM_INT_SMALL, }, - 'pois': { - 'request': 'pois', - 'geojson': PARAM_GEOJSON_POINT, - 'bbox': PARAM_LINE, - 'buffer': PARAM_INT_SMALL, - 'filter_category_ids': [PARAM_INT_SMALL], - 'filter_category_group_ids': [PARAM_INT_BIG], - 'filters_custom': { - 'name': 'Deli', - 'wheelchair': ['yes', 'limited'], - 'smoking': ['dedicated', 'separated'], - 'fee': ['yes', 'no'] + "pois": { + "request": "pois", + "geojson": PARAM_GEOJSON_POINT, + "bbox": PARAM_LINE, + "buffer": PARAM_INT_SMALL, + "filter_category_ids": [PARAM_INT_SMALL], + "filter_category_group_ids": [PARAM_INT_BIG], + "filters_custom": { + "name": "Deli", + "wheelchair": ["yes", "limited"], + "smoking": ["dedicated", "separated"], + "fee": ["yes", "no"], }, - 'limit': PARAM_INT_SMALL, - 'sortby': 'distance', + "limit": PARAM_INT_SMALL, + "sortby": "distance", }, - 'optimization': { + "optimization": { "shipments": [ - { - "pickup": { - "id": 0, - "location": [ - 8.688641, - 49.420577 - ], - "location_index": 0, - "service": 500, - "time_windows": [ - [ - 50, - 50 - ] - ] + { + "pickup": { + "id": 0, + "location": [8.688641, 49.420577], + "location_index": 0, + "service": 500, + "time_windows": [[50, 50]], + }, + "delivery": { + "id": 0, + "location": [8.688641, 49.420577], + "location_index": 0, + "service": 500, + "time_windows": [[50, 50]], + }, + "amount": [50], + "skills": [50, 50], + "priority": 50, }, - "delivery": { - "id": 0, - "location": [ - 8.688641, - 49.420577 - ], - "location_index": 0, - "service": 500, - "time_windows": [ - [ - 50, - 50 - ] - ] + { + "pickup": { + "id": 1, + "location": [8.680916, 49.415776], + "location_index": 1, + "service": 500, + "time_windows": [[50, 50]], + }, + "delivery": { + "id": 1, + "location": [8.680916, 49.415776], + "location_index": 1, + "service": 500, + "time_windows": [[50, 50]], + }, + "amount": [50], + "skills": [50, 50], + "priority": 50, }, - "amount": [ - 50 - ], - "skills": [ - 50, - 50 - ], - "priority": 50 - }, - { - "pickup": { - "id": 1, - "location": [ - 8.680916, - 49.415776 - ], - "location_index": 1, - "service": 500, - "time_windows": [ - [ - 50, - 50 - ] - ] - }, - "delivery": { - "id": 1, - "location": [ - 8.680916, - 49.415776 - ], - "location_index": 1, - "service": 500, - "time_windows": [ - [ - 50, - 50 - ] - ] - }, - "amount": [ - 50 - ], - "skills": [ - 50, - 50 - ], - "priority": 50 - } ], "jobs": [ - { - "id": 0, - "location": PARAM_LINE[0], - "location_index": 0, - "service": PARAM_INT_BIG, - "amount": [PARAM_INT_SMALL], - "skills": PARAM_LIST_ONE, - "priority": PARAM_INT_SMALL, - "time_windows": [PARAM_LIST_ONE] - }, - { - "id": 1, - "location": PARAM_LINE[1], - "location_index": 1, - "service": PARAM_INT_BIG, - "amount": [PARAM_INT_SMALL], - "skills": PARAM_LIST_ONE, - "priority": PARAM_INT_SMALL, - "time_windows": [PARAM_LIST_ONE] - } + { + "id": 0, + "location": PARAM_LINE[0], + "location_index": 0, + "service": PARAM_INT_BIG, + "amount": [PARAM_INT_SMALL], + "skills": PARAM_LIST_ONE, + "priority": PARAM_INT_SMALL, + "time_windows": [PARAM_LIST_ONE], + }, + { + "id": 1, + "location": PARAM_LINE[1], + "location_index": 1, + "service": PARAM_INT_BIG, + "amount": [PARAM_INT_SMALL], + "skills": PARAM_LIST_ONE, + "priority": PARAM_INT_SMALL, + "time_windows": [PARAM_LIST_ONE], + }, ], "vehicles": [ - { - "id": 0, - "profile": "driving-car", - "start": PARAM_LINE[0], - "start_index": 0, - "end_index": 0, - "end": PARAM_LINE[0], - "capacity": [ - PARAM_INT_SMALL - ], - "skills": PARAM_LIST_ONE, - "time_window": PARAM_LIST_ONE - }, - { - "id": 1, - "profile": "driving-car", - "start": PARAM_LINE[1], - "start_index": 1, - "end_index": 1, - "end": PARAM_LINE[1], - "capacity": [ - PARAM_INT_SMALL - ], - "skills": PARAM_LIST_ONE, - "time_window": PARAM_LIST_ONE - }, + { + "id": 0, + "profile": "driving-car", + "start": PARAM_LINE[0], + "start_index": 0, + "end_index": 0, + "end": PARAM_LINE[0], + "capacity": [PARAM_INT_SMALL], + "skills": PARAM_LIST_ONE, + "time_window": PARAM_LIST_ONE, + }, + { + "id": 1, + "profile": "driving-car", + "start": PARAM_LINE[1], + "start_index": 1, + "end_index": 1, + "end": PARAM_LINE[1], + "capacity": [PARAM_INT_SMALL], + "skills": PARAM_LIST_ONE, + "time_window": PARAM_LIST_ONE, + }, ], - "options": { - 'g': False - }, - "matrix": PARAM_LIST_TWO - } -} \ No newline at end of file + "options": {"g": False}, + "matrix": PARAM_LIST_TWO, + }, +} diff --git a/test/test_isochrones.py b/test/test_isochrones.py index 5cf0c135..214c333a 100644 --- a/test/test_isochrones.py +++ b/test/test_isochrones.py @@ -14,24 +14,26 @@ # License for the specific language governing permissions and limitations under # the License. # - """Tests for the distance matrix module.""" import responses import test as _test -from test.test_helper import PARAM_POINT, ENDPOINT_DICT +from test.test_helper import ENDPOINT_DICT class IsochronesTest(_test.TestCase): - @responses.activate def test_isochrones(self): - query = ENDPOINT_DICT['isochrones'] + query = ENDPOINT_DICT["isochrones"] - responses.add(responses.POST, - 'https://api.openrouteservice.org/v2/isochrones/{}/geojson'.format(query['profile']), - json=query, - status=200, - content_type='application/json') + responses.add( + responses.POST, + "https://api.openrouteservice.org/v2/isochrones/{}/geojson".format( + query["profile"] + ), + json=query, + status=200, + content_type="application/json", + ) resp = self.client.isochrones(**query) diff --git a/test/test_optimization.py b/test/test_optimization.py index c2ced67a..929e0d3c 100644 --- a/test/test_optimization.py +++ b/test/test_optimization.py @@ -16,7 +16,6 @@ # License for the specific language governing permissions and limitations under # the License. # - """Tests for the distance matrix module.""" import responses import test as _test @@ -28,48 +27,58 @@ class OptimizationTest(_test.TestCase): - def _get_params(self): jobs, vehicles, shipments = list(), list(), list() for idx, coord in enumerate(PARAM_LINE): - jobs.append(Job(idx, location=coord, - service=PARAM_INT_BIG, - location_index=idx, - amount=[PARAM_INT_SMALL], - skills=PARAM_LIST_ONE, - priority=PARAM_INT_SMALL, - time_windows=[PARAM_LIST_ONE] - )) - - vehicles.append(Vehicle(idx, profile='driving-car', - start=coord, - start_index=idx, - end=coord, - end_index=idx, - capacity=[PARAM_INT_SMALL], - skills=PARAM_LIST_ONE, - time_window=PARAM_LIST_ONE)) - - shipments.append(Shipment( - pickup=ShipmentStep( + jobs.append( + Job( idx, location=coord, - location_index=idx, service=PARAM_INT_BIG, - time_windows=[PARAM_LIST_ONE] - ), - delivery=ShipmentStep( - idx, - location=coord, location_index=idx, - service=PARAM_INT_BIG, - time_windows=[PARAM_LIST_ONE] - ), - amount=[PARAM_INT_SMALL], - skills=PARAM_LIST_ONE, - priority=PARAM_INT_SMALL - )) + amount=[PARAM_INT_SMALL], + skills=PARAM_LIST_ONE, + priority=PARAM_INT_SMALL, + time_windows=[PARAM_LIST_ONE], + ) + ) + + vehicles.append( + Vehicle( + idx, + profile="driving-car", + start=coord, + start_index=idx, + end=coord, + end_index=idx, + capacity=[PARAM_INT_SMALL], + skills=PARAM_LIST_ONE, + time_window=PARAM_LIST_ONE, + ) + ) + + shipments.append( + Shipment( + pickup=ShipmentStep( + idx, + location=coord, + location_index=idx, + service=PARAM_INT_BIG, + time_windows=[PARAM_LIST_ONE], + ), + delivery=ShipmentStep( + idx, + location=coord, + location_index=idx, + service=PARAM_INT_BIG, + time_windows=[PARAM_LIST_ONE], + ), + amount=[PARAM_INT_SMALL], + skills=PARAM_LIST_ONE, + priority=PARAM_INT_SMALL, + ) + ) return jobs, vehicles, shipments @@ -77,21 +86,32 @@ def test_jobs_vehicles_classes(self): jobs, vehicles, shipments = self._get_params() - self.assertEqual(ENDPOINT_DICT['optimization']['jobs'], [j.__dict__ for j in jobs]) - self.assertEqual(ENDPOINT_DICT['optimization']['vehicles'], [v.__dict__ for v in vehicles]) + self.assertEqual( + ENDPOINT_DICT["optimization"]["jobs"], [j.__dict__ for j in jobs] + ) + self.assertEqual( + ENDPOINT_DICT["optimization"]["vehicles"], + [v.__dict__ for v in vehicles], + ) @responses.activate def test_full_optimization(self): - query = deepcopy(ENDPOINT_DICT['optimization']) + query = deepcopy(ENDPOINT_DICT["optimization"]) jobs, vehicles, shipments = self._get_params() - responses.add(responses.POST, - 'https://api.openrouteservice.org/optimization', - json={}, - status=200, - content_type='application/json') - - self.client.optimization(jobs, vehicles, shipments, geometry=False, matrix=PARAM_LIST_TWO) - - self.assertEqual(query, json.loads(responses.calls[0].request.body.decode('utf-8'))) + responses.add( + responses.POST, + "https://api.openrouteservice.org/optimization", + json={}, + status=200, + content_type="application/json", + ) + + self.client.optimization( + jobs, vehicles, shipments, geometry=False, matrix=PARAM_LIST_TWO + ) + + self.assertEqual( + query, json.loads(responses.calls[0].request.body.decode("utf-8")) + ) diff --git a/test/test_places.py b/test/test_places.py index a7328e69..20164f3d 100644 --- a/test/test_places.py +++ b/test/test_places.py @@ -16,7 +16,6 @@ # License for the specific language governing permissions and limitations under # the License. # - """Tests for the distance matrix module.""" import responses import test as _test @@ -25,15 +24,16 @@ class PlacesTest(_test.TestCase): - @responses.activate def test_pois(self): - query = ENDPOINT_DICT['pois'] - responses.add(responses.POST, - 'https://api.openrouteservice.org/pois', - json=query, - status=200, - content_type='application/json') + query = ENDPOINT_DICT["pois"] + responses.add( + responses.POST, + "https://api.openrouteservice.org/pois", + json=query, + status=200, + content_type="application/json", + ) resp = self.client.places(**query) diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..7b387533 --- /dev/null +++ b/tox.ini @@ -0,0 +1,12 @@ +[tox] +envlist = py36,py37,py38,py39,pypy3 +isolated_build = true + +[testenv] +commands = + poetry install -v + pytest +whitelist_externals = poetry + +[pytest] +addopts = -x --cov=openrouteservice --cov-report=xml