From c8487c82280bf12c11ee671b865b00ec1573bd09 Mon Sep 17 00:00:00 2001 From: Julian Psotta Date: Thu, 4 Feb 2021 14:06:19 +0100 Subject: [PATCH 01/15] migrate to poetry --- .gitignore | 3 +++ pyproject.toml | 32 +++++++++++++++++++++++++ requirements-dev.txt | 5 ---- requirements.txt | 1 - setup.py | 57 -------------------------------------------- 5 files changed, 35 insertions(+), 63 deletions(-) create mode 100644 pyproject.toml delete mode 100644 requirements-dev.txt delete mode 100644 requirements.txt delete mode 100644 setup.py diff --git a/.gitignore b/.gitignore index 785caccc..dc28986d 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ test.py cover/ conda/ +/coverage.xml +/poetry.lock +/setup.py diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..2bbff03d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,32 @@ +[tool.poetry] +name = "openrouteservice" +version = "2.3.3" +description = "Python client for requests to openrouteservice API services." +authors = ["Nils Nolde ", "Julian Psotta "] +readme = 'README.rst' +license = "Apache2" + +[tool.dephell.main] +from = { format = "poetry", path = "pyproject.toml" } +to = { format = "setuppy", path = "setup.py" } + +[tool.poetry.dependencies] +python = ">=3.6.0,<4" +requests = ">=2.0" +setuptools = ">=53.0.0" +responses = ">=0.12.1" +dephell = ">=0.8.3" + +[tool.poetry.dev-dependencies] +responses = ">=0.10" +coveralls = ">=1.7.0" +tox = ">=3.21.4" +pytest = ">=4.6.11" +pytest-cov = ">=2.11.1" + +[tool.poetry.extras] +test = ["pytest", "pytest-cov", "tox", "responses", "coveralls"] + +[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 -) From fdd535b9bbd66d39106ceda9a51e40aa57fddee1 Mon Sep 17 00:00:00 2001 From: Julian Psotta Date: Thu, 4 Feb 2021 14:29:46 +0100 Subject: [PATCH 02/15] remove test extras --- pyproject.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2bbff03d..e97391a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,9 +24,6 @@ tox = ">=3.21.4" pytest = ">=4.6.11" pytest-cov = ">=2.11.1" -[tool.poetry.extras] -test = ["pytest", "pytest-cov", "tox", "responses", "coveralls"] - [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" From 47f51bdd915fb888a85452dfe39538d26f1ed1d7 Mon Sep 17 00:00:00 2001 From: Julian Psotta Date: Thu, 4 Feb 2021 14:29:55 +0100 Subject: [PATCH 03/15] add tox configuration --- tox.ini | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tox.ini diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..61d15308 --- /dev/null +++ b/tox.ini @@ -0,0 +1,13 @@ +[tox] +envlist = py36,py37,py38,py39 +isolated_build = true + +[testenv] +commands = + poetry install -v + pytest +whitelist_externals = poetry + +[pytest] +addopts = -x --cov=openrouteservice +script_launch_mode = subprocess From c37e9a997c851b55d877894308a17f5ae0748ccf Mon Sep 17 00:00:00 2001 From: Julian Psotta Date: Thu, 4 Feb 2021 14:30:36 +0100 Subject: [PATCH 04/15] get version from global variable. it only needs to be declared once. --- openrouteservice/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openrouteservice/__init__.py b/openrouteservice/__init__.py index a092a179..860db4d7 100644 --- a/openrouteservice/__init__.py +++ b/openrouteservice/__init__.py @@ -16,8 +16,9 @@ # License for the specific language governing permissions and limitations under # the License. # +import pkg_resources -__version__ = "2.2.2" +__version__ = pkg_resources.get_distribution('openrouteservice').version def get_ordinal(number): From 6d43db26c4b2ebe5c472befdf7789d916e8b108f Mon Sep 17 00:00:00 2001 From: Julian Psotta Date: Thu, 4 Feb 2021 14:31:38 +0100 Subject: [PATCH 05/15] apply github action to use poetry and tox --- .github/workflows/ci-tests.yml | 38 ++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 6053fbc8..e44db5da 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -8,29 +8,37 @@ on: - master jobs: - build: - runs-on: ${{ matrix.os }} + test: 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 + poetry-version: [ 1.1.4 ] + os: [ 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 Python ${{ matrix.config.python-version }} uses: actions/setup-python@v2 with: - python-version: ${{ matrix.python_version }} + python-version: ${{ matrix.config.python-version }} + - name: Python Poetry Action + uses: abatilo/actions-poetry@v2.1.0 + with: + poetry-version: 1.1.2 - name: Install dependencies run: | - pip install -r requirements-dev.txt - - name: nosetests - run: | - nosetests --with-coverage --cover-erase --cover-package=openrouteservice -v + pip install tox + - name: Run Tox + run: tox -e py${{ matrix.config.tox }} - name: coveralls run: | coveralls --service=github From 6fdc48f85ed8dc4718dee58173a3be23b5d5d32f Mon Sep 17 00:00:00 2001 From: Julian Psotta Date: Thu, 4 Feb 2021 14:39:08 +0100 Subject: [PATCH 06/15] add coverall dep --- .github/workflows/ci-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index e44db5da..e271929d 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -36,7 +36,7 @@ jobs: poetry-version: 1.1.2 - name: Install dependencies run: | - pip install tox + pip install tox coverall - name: Run Tox run: tox -e py${{ matrix.config.tox }} - name: coveralls From a482273ddfd89ffd0848e6e0d8487c4a2c640352 Mon Sep 17 00:00:00 2001 From: Julian Psotta Date: Thu, 4 Feb 2021 14:39:20 +0100 Subject: [PATCH 07/15] add requirements to ignore. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index dc28986d..9ebf3962 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ conda/ /coverage.xml /poetry.lock /setup.py +/requirements.txt From d39d88c5638566eb9dcb9126cd02e5276735561f Mon Sep 17 00:00:00 2001 From: Julian Psotta Date: Thu, 4 Feb 2021 14:43:32 +0100 Subject: [PATCH 08/15] fix typo --- .github/workflows/ci-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index e271929d..8202202a 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -36,7 +36,7 @@ jobs: poetry-version: 1.1.2 - name: Install dependencies run: | - pip install tox coverall + pip install tox coveralls - name: Run Tox run: tox -e py${{ matrix.config.tox }} - name: coveralls From 6d9a6e39be43e3b706e8b2c0603e204a236d02dc Mon Sep 17 00:00:00 2001 From: Julian Psotta Date: Thu, 4 Feb 2021 14:47:08 +0100 Subject: [PATCH 09/15] change assert to fail less often. --- test/test_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_client.py b/test/test_client.py index 6df98587..cbf5fbda 100644 --- a/test/test_client.py +++ b/test/test_client.py @@ -80,7 +80,7 @@ def test_raise_timeout_retriable_requests(self): 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): From 194555cd19a45067597e563ab79e8f4b311a7134 Mon Sep 17 00:00:00 2001 From: Julian Psotta Date: Thu, 4 Feb 2021 15:32:17 +0100 Subject: [PATCH 10/15] add pre-commit with black, pep8 and various file checks --- .pre-commit-config.yaml | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..f6c2019f --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,51 @@ +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 ] + - repo: https://github.com/ambv/black + rev: stable + hooks: + - id: black + args: # arguments to configure black + - --line-length=80 + - 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", + ] From ced1e0adf03de896f092e0fa472fac4d613433fb Mon Sep 17 00:00:00 2001 From: Julian Psotta Date: Thu, 4 Feb 2021 15:34:54 +0100 Subject: [PATCH 11/15] run pre-commit on whole project. it is now fixed with black and compatible to pep8 excluding some rules. --- .condarc | 2 +- .github/workflows/ci-tests.yml | 4 +- .github/workflows/conda-package.yml | 2 +- .github/workflows/python-package.yml | 2 +- MANIFEST.in | 2 +- conda.recipe/bld.bat | 2 +- conda.recipe/build.sh | 2 +- conda.recipe/meta.yaml | 2 +- docs/Makefile | 2 +- docs/source/conf.py | 77 ++--- docs/source/index.rst | 4 +- docs/source/modules.rst | 1 - docs/source/readme_link.rst | 2 +- environment.yml | 2 +- openrouteservice/__init__.py | 18 +- openrouteservice/client.py | 184 ++++++----- openrouteservice/convert.py | 67 ++-- openrouteservice/deprecation.py | 14 +- openrouteservice/directions.py | 120 ++++---- openrouteservice/distance_matrix.py | 51 ++-- openrouteservice/elevation.py | 85 +++--- openrouteservice/exceptions.py | 26 +- openrouteservice/geocode.py | 207 +++++++------ openrouteservice/isochrones.py | 59 ++-- openrouteservice/optimization.py | 130 ++++---- openrouteservice/places.py | 69 +++-- pyproject.toml | 2 + test/__init__.py | 3 +- test/test_client.py | 136 +++++---- test/test_convert.py | 58 ++-- test/test_deprecation_warning.py | 2 +- test/test_directions.py | 107 ++++--- test/test_distance_matrix.py | 19 +- test/test_elevation.py | 29 +- test/test_exceptions.py | 27 +- test/test_geocode.py | 78 ++--- test/test_helper.py | 436 ++++++++++++--------------- test/test_isochrones.py | 18 +- test/test_optimization.py | 114 ++++--- test/test_places.py | 16 +- 40 files changed, 1167 insertions(+), 1014 deletions(-) diff --git a/.condarc b/.condarc index b2344324..f39314a9 100644 --- a/.condarc +++ b/.condarc @@ -1,4 +1,4 @@ channels: - michaelsjp -show_channel_urls: True \ No newline at end of file +show_channel_urls: True diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 8202202a..d5769b6e 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -1,10 +1,10 @@ name: tests -on: +on: pull_request: branches: '**' push: - branches: + branches: - master jobs: diff --git a/.github/workflows/conda-package.yml b/.github/workflows/conda-package.yml index c4148ff8..de08c850 100644 --- a/.github/workflows/conda-package.yml +++ b/.github/workflows/conda-package.yml @@ -16,4 +16,4 @@ jobs: subDir: 'conda.recipe' AnacondaToken: ${{ secrets.ANACONDA_TOKEN }} platforms: 'all' - override: true \ No newline at end of file + override: true diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index c881861c..608262ee 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -36,4 +36,4 @@ jobs: 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 + password: ${{ secrets.PYPI_API_TOKEN }} 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/conda.recipe/bld.bat b/conda.recipe/bld.bat index 447706ab..3563cff6 100644 --- a/conda.recipe/bld.bat +++ b/conda.recipe/bld.bat @@ -1,3 +1,3 @@ cd %RECIPE_DIR%\.. "%PYTHON%" setup.py install -if errorlevel 1 exit 1 \ No newline at end of file +if errorlevel 1 exit 1 diff --git a/conda.recipe/build.sh b/conda.recipe/build.sh index aa59b4dc..abebc130 100644 --- a/conda.recipe/build.sh +++ b/conda.recipe/build.sh @@ -1,2 +1,2 @@ cd $RECIPE_DIR/.. -$PYTHON setup.py install \ No newline at end of file +$PYTHON setup.py install diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml index 5f7725eb..23fe1e91 100644 --- a/conda.recipe/meta.yaml +++ b/conda.recipe/meta.yaml @@ -1,6 +1,6 @@ {% set name = "openrouteservice" %} {% set version = "2.3.3" %} - +# TODO update to be conform with poetry package: name: "{{ name|lower }}" version: "{{ version }}" 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 860db4d7..16448c14 100644 --- a/openrouteservice/__init__.py +++ b/openrouteservice/__init__.py @@ -16,24 +16,24 @@ # License for the specific language governing permissions and limitations under # the License. # + +"""Initialize openrouteservice.""" import pkg_resources -__version__ = pkg_resources.get_distribution('openrouteservice').version +__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..55859398 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 @@ -40,20 +37,24 @@ _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,13 +185,18 @@ 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: @@ -192,30 +204,50 @@ def request(self, 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): @@ -232,24 +264,18 @@ def _get_body(response): # 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. @@ -337,21 +364,18 @@ def _urlencode_params(params): try: - unicode # NOTE(cbro): `unicode` was removed in Python 3. In Python 3, NameError is # raised here, and caught below. def _normalize_for_urlencode(value): - """(Python 2) Converts the value to a `str` (raw bytes).""" - if isinstance(value, unicode): - 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..3173a33a 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,43 @@ 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 - )) + jobs.append(Job(id=idx, location=coord)) - params = { - 'jobs': jobs, - 'vehicles': veh - } + params = {"jobs": jobs, "vehicles": veh} optimization_res = optimization(client, **params) coordinates = [] - for step in optimization_res['routes'][0]['steps']: - coordinates.append(step['location']) + for step in optimization_res["routes"][0]["steps"]: + coordinates.append(step["location"]) return coordinates 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..98000e03 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 f"{self.status} ({self.message})" 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 f"HTTP Error: {self.status_code}" 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..313fcafd 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,18 +87,16 @@ 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: params["profile"] = profile @@ -105,17 +105,17 @@ def isochrones(client, locations, params["range_type"] = range_type if intervals: - deprecation.warning('intervals', 'range') + deprecation.warning("intervals", "range") range = range or intervals - params['range'] = range + params["range"] = range if segments: - deprecation.warning('segments', 'interval') + deprecation.warning("segments", "interval") interval = interval or segments if interval: - params['interval'] = interval + params["interval"] = interval if units: params["units"] = units @@ -129,4 +129,9 @@ def isochrones(client, locations, if attributes: 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/pyproject.toml b/pyproject.toml index e97391a8..c23a4144 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,8 @@ coveralls = ">=1.7.0" tox = ">=3.21.4" pytest = ">=4.6.11" pytest-cov = ">=2.11.1" +yapf = "^0.30.0" +pre-commit = ">=2.1.1" [build-system] requires = ["poetry-core>=1.0.0"] 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 cbf5fbda..f3ebcea2 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,40 +38,55 @@ 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): @@ -85,47 +97,57 @@ def test_raise_timeout_retriable_requests(self): @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"}) - self.assertURLEqual("https://foo.com/bar?bunny=pretty&fox=prettier", - responses.calls[0].request.url) + 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') + 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') + req = self.client.request( + post_json={}, url="v2/directions/driving-car/json", dry_run="true" + ) self.assertEqual(0, len(responses.calls)) @@ -134,14 +156,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..0d232a06 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 @@ -30,25 +29,29 @@ 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()) + 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,14 +65,23 @@ 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): @@ -78,15 +90,19 @@ def test_optimized_waypoints(self): @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 +115,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 +145,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..3fe77c87 100644 --- a/test/test_isochrones.py +++ b/test/test_isochrones.py @@ -14,7 +14,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 @@ -22,16 +21,19 @@ 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) From aed118b02086487cf493e12472250e4a6e233a3f Mon Sep 17 00:00:00 2001 From: Julian Psotta Date: Thu, 4 Feb 2021 15:35:13 +0100 Subject: [PATCH 12/15] add coverage to ignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9ebf3962..175d290d 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,7 @@ test.py cover/ conda/ -/coverage.xml +*coverage.xml /poetry.lock /setup.py /requirements.txt From 06ec5e3fa30508db52dc5f13670612d6481f5076 Mon Sep 17 00:00:00 2001 From: Julian Psotta Date: Thu, 4 Feb 2021 15:35:27 +0100 Subject: [PATCH 13/15] add coverage run config --- .coveragerc | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.coveragerc b/.coveragerc index a5f7fcee..3d60f1ca 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,5 +1,17 @@ +[run] +branch = True +concurrency = multiprocessing +omit = + */venv/* + */.venv/* + */.env/* + */.tox/* + [report] omit = - */python?.?/* - */site-packages/nose/* - *__init__* + */venv/* + */.venv/* + */.env/* + */.tox/* +exclude_lines = + pragma: no cover From f2cefe482c2b7adde98a394fd0a5f413f314fd05 Mon Sep 17 00:00:00 2001 From: Julian Psotta Date: Thu, 4 Feb 2021 15:38:13 +0100 Subject: [PATCH 14/15] add linting step --- .github/workflows/ci-tests.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index d5769b6e..242bd0f0 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -8,7 +8,26 @@ on: - master jobs: + 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: Install lint dependencies + run: | + python -m pip install --upgrade pip + pip install pre-commit pycodestyle + - 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: From ac33a7b364db3c12efe788f2dc3e6f8c3356343e Mon Sep 17 00:00:00 2001 From: Julian Psotta Date: Thu, 4 Feb 2021 15:41:33 +0100 Subject: [PATCH 15/15] add more os --- .github/workflows/ci-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 242bd0f0..9e6ce423 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -41,7 +41,7 @@ jobs: - python-version: 3.9 tox: 39 poetry-version: [ 1.1.4 ] - os: [ ubuntu-20.04, ubuntu-18.04 ] + os: [ macos-11.0, windows-2019, ubuntu-20.04, ubuntu-18.04 ] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2