diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..cd2093c --- /dev/null +++ b/.flake8 @@ -0,0 +1,6 @@ +[flake8] +max-line-length = 120 +exclude = .git,__pycache__,build,dist +ignore = W503 +per-file-ignores = + __init__.py: F401 diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index aa65fdb..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,177 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/OpenCageGeocoder.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/OpenCageGeocoder.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/OpenCageGeocoder" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/OpenCageGeocoder" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index ab34d07..0000000 --- a/docs/conf.py +++ /dev/null @@ -1,266 +0,0 @@ -# -*- coding: utf-8 -*- - -# pylint: disable=redefined-builtin - -# -# OpenCage Geocoder documentation build configuration file, created by -# sphinx-quickstart on Sat Jun 7 14:38:18 2014. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('../')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# 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.intersphinx', - 'sphinx.ext.ifconfig', - 'sphinx.ext.viewcode', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'OpenCage Geocoder' -copyright = u'2014, Rory McCann' - -# 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 = '1' -# The full version, including alpha/beta/rc tags. -release = '1' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'default' - -# 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 -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# 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'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'OpenCageGeocoderdoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - #'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - #'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - #'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'OpenCageGeocoder.tex', u'OpenCage Geocoder Documentation', u'Rory McCann', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'opencagegeocoder', u'OpenCage Geocoder Documentation', [u'Rory McCann'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'OpenCageGeocoder', u'OpenCage Geocoder Documentation', u'Rory McCann', 'OpenCageGeocoder', 'One line description of project.', 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False - - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/docs/hacking.rst b/docs/hacking.rst deleted file mode 100644 index 8d5b907..0000000 --- a/docs/hacking.rst +++ /dev/null @@ -1,7 +0,0 @@ -Hacking -======= - -Tests ------ - -Run ``tox`` to run all unittests on all supported python versions (2.6, 2.7, 3.2, 3.3). diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index e006b1f..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,140 +0,0 @@ -.. OpenCage Geocoder documentation master file, created by - sphinx-quickstart on Sat Jun 7 14:38:18 2014. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to OpenCage Geocoder's documentation! -============================================= - -.. toctree:: - :maxdepth: 2 - - hacking - -.. autoclass:: opencage.geocoder.OpenCageGeocode - :members: - -.. autoclass:: opencage.geocoder.InvalidInputError - -.. autoclass:: opencage.geocoder.RateLimitExceededError - -.. autoclass:: opencage.geocoder.UnknownError - -Sample Return Format --------------------- - -Results from OpenCage Geocode - - >>> geocoder = OpenCageGeocode('your-key-here') - >>> geocoder.geocode("London") - [{u'annotations': {}, - u'bounds': {u'northeast': {'lat': 51.6918741, 'lng': 0.3340155}, - u'southwest': {'lat': 51.2867602, 'lng': -0.510375}}, - u'components': {u'city': u'London', - u'country': u'United Kingdom', - u'country_code': u'gb', - u'county': u'London', - u'state': u'England', - u'state_district': u'Greater London'}, - u'formatted': u'London, London, Greater London, England, United Kingdom, gb', - u'geometry': {'lat': 51.5073219, 'lng': -0.1276474}}, - {u'annotations': {}, - u'bounds': {u'northeast': {'lat': 43.148097, 'lng': -81.0860295}, - u'southwest': {'lat': 42.828097, 'lng': -81.4060295}}, - u'components': {u'city': u'London', - u'country': u'Canada', - u'country_code': u'ca', - u'state': u'Ontario'}, - u'formatted': u'London, Ontario, Canada, ca', - u'geometry': {'lat': 42.988097, 'lng': -81.2460295}}, - {u'annotations': {}, - u'bounds': {u'northeast': {'lat': 37.15226, 'lng': -84.0359569}, - u'southwest': {'lat': 37.079759, 'lng': -84.1262619}}, - u'components': {u'city': u'London', - u'country': u'United States of America', - u'country_code': u'us', - u'county': u'Laurel County', - u'state': u'Kentucky'}, - u'formatted': u'London, Laurel County, Kentucky, United States of America, us', - u'geometry': {'lat': 37.1289771, 'lng': -84.0832646}}, - {u'annotations': {}, - u'bounds': {u'northeast': {'lat': 43.0677775, 'lng': -88.9928881}, - u'southwest': {'lat': 43.0277775, 'lng': -89.0328881}}, - u'components': {u'country': u'United States of America', - u'country_code': u'us', - u'county': u'Dane County', - u'hamlet': u'London', - u'state': u'Wisconsin'}, - u'formatted': u'London, Dane County, Wisconsin, United States of America, us', - u'geometry': {'lat': 43.0477775, 'lng': -89.0128881}}, - {u'annotations': {}, - u'bounds': {u'northeast': {'lat': 39.921786, 'lng': -83.3899969}, - u'southwest': {'lat': 39.85928, 'lng': -83.4789229}}, - u'components': {u'city': u'London', - u'country': u'United States of America', - u'country_code': u'us', - u'county': u'Madison County', - u'state': u'Ohio'}, - u'formatted': u'London, Madison County, Ohio, United States of America, us', - u'geometry': {'lat': 39.8864493, 'lng': -83.448253}}, - {u'annotations': {}, - u'bounds': {u'northeast': {'lat': 36.4884367, 'lng': -119.4385394}, - u'southwest': {'lat': 36.4734452, 'lng': -119.4497698}}, - u'components': {u'country': u'United States of America', - u'country_code': u'us', - u'county': u'Tulare County', - u'state': u'California', - u'village': u'London'}, - u'formatted': u'London, Tulare County, California, United States of America, us', - u'geometry': {'lat': 36.4760619, 'lng': -119.4431785}}, - {u'annotations': {}, - u'bounds': {u'northeast': {'lat': 35.33814, 'lng': -93.1873749}, - u'southwest': {'lat': 35.315577, 'lng': -93.2726929}}, - u'components': {u'city': u'London', - u'country': u'United States of America', - u'country_code': u'us', - u'county': u'Pope County', - u'state': u'Arkansas'}, - u'formatted': u'London, Pope County, Arkansas, United States of America, us', - u'geometry': {'lat': 35.326859, 'lng': -93.2405016007635}}, - {u'annotations': {}, - u'bounds': {u'northeast': {'lat': 38.2143567, 'lng': -81.3486944}, - u'southwest': {'lat': 38.1743567, 'lng': -81.3886944}}, - u'components': {u'country': u'United States of America', - u'country_code': u'us', - u'county': u'Kanawha County', - u'hamlet': u'London', - u'state': u'West Virginia'}, - u'formatted': u'London, Kanawha County, West Virginia, United States of America, us', - u'geometry': {'lat': 38.1943567, 'lng': -81.3686944}}, - {u'annotations': {}, - u'bounds': {u'northeast': {'lat': 32.2509892, 'lng': -94.9243839}, - u'southwest': {'lat': 32.2109892, 'lng': -94.9643839}}, - u'components': {u'country': u'United States of America', - u'country_code': u'us', - u'county': u'Rusk County', - u'hamlet': u'London', - u'state': u'Texas'}, - u'formatted': u'London, Rusk County, Texas, United States of America, us', - u'geometry': {'lat': 32.2309892, 'lng': -94.9443839}}, - {u'annotations': {}, - u'bounds': {u'northeast': {'lat': 40.9303338, 'lng': -82.6093412}, - u'southwest': {'lat': 40.8903338, 'lng': -82.6493412}}, - u'components': {u'country': u'United States of America', - u'country_code': u'us', - u'county': u'Richland County', - u'hamlet': u'London', - u'state': u'Ohio'}, - u'formatted': u'London, Richland County, Ohio, United States of America, us', - u'geometry': {'lat': 40.9103338, 'lng': -82.6293412}}] - - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index cd9bca1..0000000 --- a/docs/make.bat +++ /dev/null @@ -1,242 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=_build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -set I18NSPHINXOPTS=%SPHINXOPTS% . -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. xml to make Docutils-native XML files - echo. pseudoxml to make pseudoxml-XML files for display purposes - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - - -%SPHINXBUILD% 2> nul -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\OpenCageGeocoder.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\OpenCageGeocoder.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdf" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdfja" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf-ja - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The XML files are in %BUILDDIR%/xml. - goto end -) - -if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. - goto end -) - -:end diff --git a/opencage/batch.py b/opencage/batch.py index f585f21..45793a1 100644 --- a/opencage/batch.py +++ b/opencage/batch.py @@ -11,7 +11,13 @@ from tqdm import tqdm import certifi import backoff -from opencage.geocoder import OpenCageGeocode, OpenCageGeocodeError, _query_for_reverse_geocoding, floatify_latlng +from opencage.geocoder import ( + OpenCageGeocode, + OpenCageGeocodeError, + _query_for_reverse_geocoding, + floatify_latlng +) + class OpenCageBatchGeocoder(): @@ -76,16 +82,21 @@ async def geocode(self, csv_input, csv_output): async def test_request(self): try: - async with OpenCageGeocode(self.options.api_key, domain=self.options.api_domain, sslcontext=self.sslcontext, user_agent_comment=self.user_agent_comment) as geocoder: + async with OpenCageGeocode( + self.options.api_key, + domain=self.options.api_domain, + sslcontext=self.sslcontext, + user_agent_comment=self.user_agent_comment + ) as geocoder: result = await geocoder.geocode_async('Kendall Sq, Cambridge, MA', raw_response=True) free = False with suppress(KeyError): free = result['rate']['limit'] == 2500 - return { 'error': None, 'free': free } + return {'error': None, 'free': free} except Exception as exc: - return { 'error': exc } + return {'error': exc} async def read_input(self, csv_input, queue): any_warnings = False @@ -132,18 +143,20 @@ async def read_one_line(self, row, row_id): if self.options.command == 'reverse': if len(address) != 2: - self.log(f"Line {row_id} - Expected two comma-separated values for reverse geocoding, got {address}") + self.log( + f"Line {row_id} - Expected two comma-separated values for reverse geocoding, got {address}") else: # _query_for_reverse_geocoding attempts to convert into numbers. We rather have it fail # now than during the actual geocoding try: _query_for_reverse_geocoding(address[0], address[1]) - except: - self.log(f"Line {row_id} - Does not look like latitude and longitude: '{address[0]}' and '{address[1]}'") + except BaseException: + self.log( + f"Line {row_id} - Does not look like latitude and longitude: '{address[0]}' and '{address[1]}'") warnings = True address = [] - return { 'row_id': row_id, 'address': ','.join(address), 'original_columns': row, 'warnings': warnings } + return {'row_id': row_id, 'address': ','.join(address), 'original_columns': row, 'warnings': warnings} async def worker(self, csv_output, queue, progress): while True: @@ -163,8 +176,8 @@ async def geocode_one_address(self, csv_output, row_id, address, original_column def on_backoff(details): if not self.options.quiet: sys.stderr.write("Backing off {wait:0.1f} seconds afters {tries} tries " - "calling function {target} with args {args} and kwargs " - "{kwargs}\n".format(**details)) + "calling function {target} with args {args} and kwargs " + "{kwargs}\n".format(**details)) @backoff.on_exception(backoff.expo, asyncio.TimeoutError, @@ -172,10 +185,15 @@ def on_backoff(details): max_tries=self.options.retries, on_backoff=on_backoff) async def _geocode_one_address(): - async with OpenCageGeocode(self.options.api_key, domain=self.options.api_domain, sslcontext=self.sslcontext, user_agent_comment=self.user_agent_comment) as geocoder: + async with OpenCageGeocode( + self.options.api_key, + domain=self.options.api_domain, + sslcontext=self.sslcontext, + user_agent_comment=self.user_agent_comment + ) as geocoder: geocoding_results = None response = None - params = { 'no_annotations': 1, 'raw_response': True, **self.options.optional_api_params } + params = {'no_annotations': 1, 'raw_response': True, **self.options.optional_api_params} try: if self.options.command == 'reverse': @@ -205,13 +223,25 @@ async def _geocode_one_address(): 'response': response }) - await self.write_one_geocoding_result(csv_output, row_id, geocoding_result, response, original_columns) + await self.write_one_geocoding_result( + csv_output, + row_id, + geocoding_result, + response, + original_columns + ) except Exception as exc: traceback.print_exception(exc, file=sys.stderr) await _geocode_one_address() - async def write_one_geocoding_result(self, csv_output, row_id, geocoding_result, raw_response, original_columns): + async def write_one_geocoding_result( + self, + csv_output, + row_id, + geocoding_result, + raw_response, + original_columns): row = original_columns for column in self.options.add_columns: @@ -226,9 +256,12 @@ async def write_one_geocoding_result(self, csv_output, row_id, geocoding_result, elif column in geocoding_result['geometry']: row.append(self.deep_get_result_value(geocoding_result, ['geometry', column], '')) elif column == 'FIPS': - row.append(self.deep_get_result_value(geocoding_result, ['annotations', 'FIPS', 'county'], '')) + row.append( + self.deep_get_result_value( + geocoding_result, [ + 'annotations', 'FIPS', 'county'], '')) elif column == 'json': - row.append(json.dumps(geocoding_result, separators=(',', ':'))) # Compact JSON + row.append(json.dumps(geocoding_result, separators=(',', ':'))) # Compact JSON else: row.append('') diff --git a/opencage/command_line.py b/opencage/command_line.py index 5bda93f..66eefe4 100644 --- a/opencage/command_line.py +++ b/opencage/command_line.py @@ -8,6 +8,7 @@ from opencage.batch import OpenCageBatchGeocoder from opencage.version import __version__ + def main(args=sys.argv[1:]): options = parse_args(args) @@ -22,6 +23,7 @@ def main(args=sys.argv[1:]): geocoder(csv_input=reader, csv_output=writer) + def parse_args(args): if len(args) == 0: print("To display help use 'opencage -h', 'opencage forward -h' or 'opencage reverse -h'", file=sys.stderr) @@ -33,13 +35,27 @@ def parse_args(args): subparsers = parser.add_subparsers(dest='command') subparsers.required = True - subparser_forward = subparsers.add_parser('forward', help="Forward geocode a file (input is address, add coordinates)") - subparser_reverse = subparsers.add_parser('reverse', help="Reverse geocode a file (input is coordinates, add full address)") + subparser_forward = subparsers.add_parser( + 'forward', help="Forward geocode a file (input is address, add coordinates)") + subparser_reverse = subparsers.add_parser( + 'reverse', help="Reverse geocode a file (input is coordinates, add full address)") for subparser in [subparser_forward, subparser_reverse]: subparser.add_argument("--api-key", required=True, type=api_key_type, help="Your OpenCage API key") - subparser.add_argument("--input", required=True, type=argparse.FileType('r', encoding='utf-8'), help="Input file name", metavar='FILENAME') - subparser.add_argument("--output", required=True, type=str, help="Output file name", metavar='FILENAME') + subparser.add_argument( + "--input", + required=True, + type=argparse.FileType( + 'r', + encoding='utf-8'), + help="Input file name", + metavar='FILENAME') + subparser.add_argument( + "--output", + required=True, + type=str, + help="Output file name", + metavar='FILENAME') add_optional_arguments(subparser) @@ -49,7 +65,9 @@ def parse_args(args): if options.overwrite: os.remove(options.output) else: - print(f"Error: The output file '{options.output}' already exists. You can add --overwrite to your command.", file=sys.stderr) + print( + f"Error: The output file '{options.output}' already exists. You can add --overwrite to your command.", + file=sys.stderr) sys.exit(1) if 0 in options.input_columns: @@ -60,18 +78,47 @@ def parse_args(args): def add_optional_arguments(parser): - parser.add_argument("--headers", action="store_true", help="If the first row should be treated as a header row") + parser.add_argument( + "--headers", + action="store_true", + help="If the first row should be treated as a header row") default_input_cols = '1,2' if re.match(r'.*reverse', parser.prog) else '1' - parser.add_argument("--input-columns", type=comma_separated_type(int), default=default_input_cols, help=f"Comma-separated list of integers (default '{default_input_cols}')", metavar='') - default_add_cols = 'lat,lng,_type,_category,country_code,country,state,county,_normalized_city,postcode,road,house_number,confidence,formatted' - parser.add_argument("--add-columns", type=comma_separated_type(str), default=default_add_cols, help=f"Comma-separated list of output columns (default '{default_add_cols}')", metavar='') - parser.add_argument("--workers", type=ranged_type(int, 1, 20), default=1, help="Number of parallel geocoding requests (default 1)", metavar='') - parser.add_argument("--timeout", type=ranged_type(int, 1, 60), default=10, help="Timeout in seconds (default 10)", metavar='') - parser.add_argument("--retries", type=ranged_type(int, 1, 60), default=10, help="Number of retries (default 5)", metavar='') - parser.add_argument("--api-domain", type=str, default="api.opencagedata.com", help="API domain (default api.opencagedata.com)", metavar='') - parser.add_argument("--optional-api-params", type=comma_separated_dict_type, default="", help="Extra parameters for each request (e.g. language=fr,no_dedupe=1)", metavar='') - parser.add_argument("--limit", type=int, default=0, help="Stop after this number of lines in the input", metavar='') - parser.add_argument("--unordered", action="store_true", help="Allow the output lines to be in different order (can be faster)") + parser.add_argument( + "--input-columns", + type=comma_separated_type(int), + default=default_input_cols, + help=f"Comma-separated list of integers (default '{default_input_cols}')", + metavar='') + default_add_cols = ( + 'lat,lng,_type,_category,country_code,country,state,county,_normalized_city,' + 'postcode,road,house_number,confidence,formatted' + ) + parser.add_argument( + "--add-columns", + type=comma_separated_type(str), + default=default_add_cols, + help=f"Comma-separated list of output columns (default '{default_add_cols}')", + metavar='') + parser.add_argument("--workers", type=ranged_type(int, 1, 20), default=1, + help="Number of parallel geocoding requests (default 1)", metavar='') + parser.add_argument("--timeout", type=ranged_type(int, 1, 60), default=10, + help="Timeout in seconds (default 10)", metavar='') + parser.add_argument("--retries", type=ranged_type(int, 1, 60), default=10, + help="Number of retries (default 5)", metavar='') + parser.add_argument("--api-domain", type=str, default="api.opencagedata.com", + help="API domain (default api.opencagedata.com)", metavar='') + parser.add_argument("--optional-api-params", type=comma_separated_dict_type, default="", + help="Extra parameters for each request (e.g. language=fr,no_dedupe=1)", metavar='') + parser.add_argument( + "--limit", + type=int, + default=0, + help="Stop after this number of lines in the input", + metavar='') + parser.add_argument( + "--unordered", + action="store_true", + help="Allow the output lines to be in different order (can be faster)") parser.add_argument("--dry-run", action="store_true", help="Read the input file but no geocoding") parser.add_argument("--no-progress", action="store_true", help="Display no progress bar") parser.add_argument("--quiet", action="store_true", help="No progress bar and no messages") @@ -80,6 +127,7 @@ def add_optional_arguments(parser): return parser + def api_key_type(apikey): pattern = re.compile(r"^(oc_gc_)?[0-9a-f]{32}$") diff --git a/opencage/geocoder.py b/opencage/geocoder.py index b4a91d0..ec7aa69 100644 --- a/opencage/geocoder.py +++ b/opencage/geocoder.py @@ -17,9 +17,11 @@ DEFAULT_DOMAIN = 'api.opencagedata.com' + def backoff_max_time(): return int(os.environ.get('BACKOFF_MAX_TIME', '120')) + class OpenCageGeocodeError(Exception): """Base class for all errors/exceptions that can happen when geocoding.""" @@ -38,7 +40,7 @@ def __init__(self, bad_value): self.bad_value = bad_value def __unicode__(self): - return "Input must be a unicode string, not "+repr(self.bad_value)[:100] + return "Input must be a unicode string, not " + repr(self.bad_value)[:100] __str__ = __unicode__ @@ -104,8 +106,8 @@ class SSLError(OpenCageGeocodeError): def __unicode__(self): """Convert exception to a string.""" return ("SSL Certificate error connecting to OpenCage API. This is usually due to " - "outdated CA root certificates of the operating system. " - ) + "outdated CA root certificates of the operating system. " + ) __str__ = __unicode__ @@ -131,7 +133,13 @@ class OpenCageGeocode: session = None - def __init__(self, key, protocol='https', domain=DEFAULT_DOMAIN, sslcontext=None, user_agent_comment=None): + def __init__( + self, + key, + protocol='https', + domain=DEFAULT_DOMAIN, + sslcontext=None, + user_agent_comment=None): """Constructor.""" self.key = key @@ -262,7 +270,7 @@ def _opencage_request(self, params): if self.session: response = self.session.get(self.url, params=params, headers=self._opencage_headers('aiohttp')) else: - response = requests.get(self.url, params=params, headers=self._opencage_headers('requests')) # pylint: disable=missing-timeout + response = requests.get(self.url, params=params, headers=self._opencage_headers('requests')) try: response_json = response.json() @@ -334,8 +342,8 @@ def _parse_request(self, query, params): if not isinstance(query, str): raise InvalidInputError(bad_value=query) - data = { 'q': query, 'key': self.key } - data.update(params) # Add user parameters + data = {'q': query, 'key': self.key} + data.update(params) # Add user parameters return data diff --git a/pylintrc b/pylintrc deleted file mode 100644 index 9191b74..0000000 --- a/pylintrc +++ /dev/null @@ -1,8 +0,0 @@ -[FORMAT] -max-line-length=110 - -[MESSAGES CONTROL] -; C0114 Missing module docstring (missing-module-docstring) -; C0116 Missing function or method docstring (missing-function-docstring) -; R0801 Similar lines in ... files (duplicate-code) -disable=C0114,C0116,R0801 diff --git a/setup.py b/setup.py index 8044906..a2edcc3 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -#/usr/bin/env python +#!/usr/bin/env python import os import sys @@ -72,7 +72,7 @@ test_suite='pytest', tests_require=[ 'responses>=0.25.7', - 'pylint==2.17.4', + 'flake8>=7.0.0', 'pytest>=7.4.0' ], ) diff --git a/test/__init__.py b/test/__init__.py index 956ba6f..5e36bb7 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -1,2 +1,2 @@ import sys -sys.path.insert(0,'.') +sys.path.insert(0, '.') diff --git a/test/cli/test_cli_args.py b/test/cli/test_cli_args.py index dd516eb..43011f4 100644 --- a/test/cli/test_cli_args.py +++ b/test/cli/test_cli_args.py @@ -4,6 +4,7 @@ from opencage.command_line import parse_args + @pytest.fixture(autouse=True) def around(): yield @@ -12,6 +13,7 @@ def around(): except FileNotFoundError: pass + def assert_parse_args_error(args, message, capfd): with pytest.raises(SystemExit): parse_args(args) @@ -19,6 +21,7 @@ def assert_parse_args_error(args, message, capfd): _, err = capfd.readouterr() assert message in err + def test_required_arguments(capfd): assert_parse_args_error( [], @@ -26,6 +29,7 @@ def test_required_arguments(capfd): capfd ) + def test_invalid_command(capfd): assert_parse_args_error( [ @@ -35,6 +39,7 @@ def test_invalid_command(capfd): capfd ) + def test_version_number(capfd): with pytest.raises(SystemExit): parse_args(['--version']) @@ -42,6 +47,7 @@ def test_version_number(capfd): assert __version__ in out + def test_invalid_api_key(capfd): assert_parse_args_error( [ @@ -54,6 +60,7 @@ def test_invalid_api_key(capfd): capfd ) + def test_existing_output_file(capfd): assert_parse_args_error( [ @@ -66,6 +73,7 @@ def test_existing_output_file(capfd): capfd ) + def test_argument_range(capfd): assert_parse_args_error( [ @@ -79,6 +87,7 @@ def test_argument_range(capfd): capfd ) + def test_zero_based_list(capfd): assert_parse_args_error( [ @@ -128,10 +137,11 @@ def test_full_argument_list(): assert args.dry_run is True assert args.unordered is True assert args.api_domain == "bulk.opencagedata.com" - assert args.optional_api_params == { "extra": "1" } + assert args.optional_api_params == {"extra": "1"} assert args.no_progress is True assert args.quiet is True + def test_defaults(): args = parse_args([ "forward", @@ -144,8 +154,21 @@ def test_defaults(): assert args.limit == 0 assert args.headers is False assert args.input_columns == [1] - assert args.add_columns == ["lat", "lng", "_type", "_category", "country_code", "country", "state", - "county", "_normalized_city", "postcode", "road", "house_number", "confidence", "formatted"] + assert args.add_columns == [ + "lat", + "lng", + "_type", + "_category", + "country_code", + "country", + "state", + "county", + "_normalized_city", + "postcode", + "road", + "house_number", + "confidence", + "formatted"] assert args.workers == 1 assert args.timeout == 10 assert args.retries == 10 @@ -156,6 +179,7 @@ def test_defaults(): assert args.no_progress is False assert args.quiet is False + def test_reverse_input_columns(): args = parse_args([ "reverse", diff --git a/test/cli/test_cli_run.py b/test/cli/test_cli_run.py index b3b7102..fa0fc2b 100644 --- a/test/cli/test_cli_run.py +++ b/test/cli/test_cli_run.py @@ -5,8 +5,9 @@ from opencage.command_line import main # NOTE: Testing keys https://opencagedata.com/api#testingkeys -TEST_APIKEY_200 = '6d0e711d72d74daeb2b0bfd2a5cdfdba' # always returns same address -TEST_APIKEY_401 = '11111111111111111111111111111111' # invalid key +TEST_APIKEY_200 = '6d0e711d72d74daeb2b0bfd2a5cdfdba' # always returns same address +TEST_APIKEY_401 = '11111111111111111111111111111111' # invalid key + @pytest.fixture(autouse=True) def around(): @@ -16,6 +17,7 @@ def around(): except FileNotFoundError: pass + def assert_output(path, length, lines): assert pathlib.Path(path).exists() @@ -27,6 +29,7 @@ def assert_output(path, length, lines): for i, expected in enumerate(lines): assert actual[i].strip() == expected + def test_forward(): main([ "forward", @@ -43,6 +46,7 @@ def test_forward(): lines=['Rathausmarkt 1,Hamburg,20095,Germany,de,Germany,48153,Münster'] ) + def test_reverse(): main([ "reverse", @@ -58,6 +62,7 @@ def test_reverse(): lines=['51.9526622,7.6324709,de,Germany,48153'] ) + def test_headers(): main([ "forward", @@ -78,6 +83,7 @@ def test_headers(): ] ) + def test_input_errors(capfd): main([ "reverse", @@ -109,6 +115,7 @@ def test_input_errors(capfd): ] ) + def test_empty_result(): # 'NOWHERE-INTERESTING' is guaranteed to return no result # https://opencagedata.com/api#testingkeys @@ -144,6 +151,7 @@ def test_invalid_api_key(capfd): _, err = capfd.readouterr() assert 'Your API key is not authorized' in err + def test_dryrun(capfd): main([ "forward", diff --git a/test/test_all.py b/test/test_all.py index 9ebccc5..01b59d9 100644 --- a/test/test_all.py +++ b/test/test_all.py @@ -16,11 +16,12 @@ def _any_result_around(results, lat=None, lon=None): for result in results: - if (abs(result['geometry']['lat'] - lat) < 0.05 and - abs(result['geometry']['lng'] - lon) < 0.05): + if (abs(result['geometry']['lat'] - lat) < 0.05 + and abs(result['geometry']['lng'] - lon) < 0.05): return True return False + @responses.activate def test_gb_postcode(): responses.add( @@ -59,6 +60,7 @@ def test_munster(): results = geocoder.geocode("Münster") assert _any_result_around(results, lat=51.9625101, lon=7.6251879) + @responses.activate def test_donostia(): responses.add( diff --git a/test/test_async.py b/test/test_async.py index 00ce1b6..746a9a1 100644 --- a/test/test_async.py +++ b/test/test_async.py @@ -6,16 +6,18 @@ # NOTE: Testing keys https://opencagedata.com/api#testingkeys + @pytest.mark.asyncio async def test_success(): async with OpenCageGeocode('6d0e711d72d74daeb2b0bfd2a5cdfdba') as geocoder: results = await geocoder.geocode_async("EC1M 5RF") assert any( - abs(result['geometry']['lat'] - 51.952659 < 0.05 and - abs(result['geometry']['lng'] - 7.632473) < 0.05) + abs(result['geometry']['lat'] - 51.952659 < 0.05 + and abs(result['geometry']['lng'] - 7.632473) < 0.05) for result in results ) + @pytest.mark.asyncio async def test_failure(): async with OpenCageGeocode('6c79ee8e1ca44ad58ad1fc493ba9542f') as geocoder: @@ -24,6 +26,7 @@ async def test_failure(): assert str(excinfo.value) == 'Your API key has been blocked or suspended.' + @pytest.mark.asyncio async def test_without_async_session(): geocoder = OpenCageGeocode('4372eff77b8343cebfc843eb4da4ddc4') @@ -33,6 +36,7 @@ async def test_without_async_session(): assert str(excinfo.value) == 'Async methods must be used inside an async context.' + @pytest.mark.asyncio async def test_using_non_async_method(): async with OpenCageGeocode('6d0e711d72d74daeb2b0bfd2a5cdfdba') as geocoder: diff --git a/test/test_batch.py b/test/test_batch.py index e9484ba..3139dd5 100644 --- a/test/test_batch.py +++ b/test/test_batch.py @@ -2,6 +2,7 @@ batch = OpenCageBatchGeocoder({}) + def test_deep_get_result_value(): result = { 'annotations': { @@ -14,11 +15,11 @@ def test_deep_get_result_value(): } } - assert batch.deep_get_result_value(result, ['hello', 'world']) == None + assert batch.deep_get_result_value(result, ['hello', 'world']) is None assert batch.deep_get_result_value(result, ['components', 'street']) == 'Main Road' - assert batch.deep_get_result_value(result, ['components', 'city']) == None + assert batch.deep_get_result_value(result, ['components', 'city']) is None assert batch.deep_get_result_value(result, ['components', 'city'], '') == '' - assert batch.deep_get_result_value([], ['hello', 'world']) == None - assert batch.deep_get_result_value(None, ['hello', 'world']) == None + assert batch.deep_get_result_value([], ['hello', 'world']) is None + assert batch.deep_get_result_value(None, ['hello', 'world']) is None diff --git a/test/test_error_blocked.py b/test/test_error_blocked.py index afb70f7..b55df6f 100644 --- a/test/test_error_blocked.py +++ b/test/test_error_blocked.py @@ -7,7 +7,8 @@ from opencage.geocoder import ForbiddenError -geocoder = OpenCageGeocode('2e10e5e828262eb243ec0b54681d699a') # will always return 403 +geocoder = OpenCageGeocode('2e10e5e828262eb243ec0b54681d699a') # will always return 403 + @responses.activate def test_api_key_blocked(): diff --git a/test/test_error_invalid_input.py b/test/test_error_invalid_input.py index e0ff04e..8eb8fa0 100644 --- a/test/test_error_invalid_input.py +++ b/test/test_error_invalid_input.py @@ -7,6 +7,7 @@ geocoder = OpenCageGeocode('abcde') + @responses.activate def test_must_be_unicode_string(): responses.add( diff --git a/test/test_error_not_authorized.py b/test/test_error_not_authorized.py index 4183cf5..15a95a7 100644 --- a/test/test_error_not_authorized.py +++ b/test/test_error_not_authorized.py @@ -8,6 +8,7 @@ geocoder = OpenCageGeocode('unauthorized-key') + @responses.activate def test_api_key_not_authorized(): responses.add( diff --git a/test/test_error_ratelimit_exceeded.py b/test/test_error_ratelimit_exceeded.py index 2522fd0..4e0ab08 100644 --- a/test/test_error_ratelimit_exceeded.py +++ b/test/test_error_ratelimit_exceeded.py @@ -8,6 +8,7 @@ geocoder = OpenCageGeocode('abcde') + @responses.activate def test_no_rate_limit(): responses.add( diff --git a/test/test_error_ssl.py b/test/test_error_ssl.py index 4e9cfb6..58e9529 100644 --- a/test/test_error_ssl.py +++ b/test/test_error_ssl.py @@ -7,6 +7,8 @@ # NOTE: Testing keys https://opencagedata.com/api#testingkeys # Connect to a host that has an invalid certificate + + @pytest.mark.asyncio async def test_sslerror(): bad_domain = 'wrong.host.badssl.com' @@ -17,6 +19,8 @@ async def test_sslerror(): # Connect to OpenCage API domain but use certificate of another domain # This tests that sslcontext can be set. + + @pytest.mark.asyncio async def test_sslerror_wrong_certificate(): sslcontext = ssl.create_default_context(cafile='test/fixtures/badssl-com-chain.pem') diff --git a/test/test_error_unknown.py b/test/test_error_unknown.py index be310cf..05e3ad4 100644 --- a/test/test_error_unknown.py +++ b/test/test_error_unknown.py @@ -7,6 +7,7 @@ geocoder = OpenCageGeocode('abcde') + @responses.activate def test_http_500_status(): responses.add( @@ -21,6 +22,7 @@ def test_http_500_status(): assert str(excinfo.value) == '500 status code from API' + @responses.activate def test_non_json(): "These kinds of errors come from webserver and may not be JSON" @@ -39,6 +41,7 @@ def test_non_json(): assert str(excinfo.value) == 'Non-JSON result from server' + @responses.activate def test_no_results_key(): responses.add( diff --git a/test/test_flotify_dict.py b/test/test_flotify_dict.py index d55e1e6..26cdf36 100644 --- a/test/test_flotify_dict.py +++ b/test/test_flotify_dict.py @@ -1,24 +1,31 @@ from opencage.geocoder import floatify_latlng + def test_string(): assert floatify_latlng("123") == "123" + def test_empty_dict(): assert floatify_latlng({}) == {} + def test_empty_list(): assert floatify_latlng([]) == [] + def test_dict_with_floats(): assert floatify_latlng({'geom': {'lat': 12.01, 'lng': -0.9}}) == {'geom': {'lat': 12.01, 'lng': -0.9}} + def dict_with_stringified_floats(): assert floatify_latlng({'geom': {'lat': "12.01", 'lng': "-0.9"}}) == {'geom': {'lat': 12.01, 'lng': -0.9}} + def dict_with_list(): assert floatify_latlng( {'results': [{'geom': {'lat': "12.01", 'lng': "-0.9"}}, {'geometry': {'lat': '0.1', 'lng': '10'}}]} - ) == {'results': [{'geom': {'lat': 12.01, 'lng': -0.9}}, {'geometry': {'lat': 0.1, 'lng': 10}}]} + ) == {'results': [{'geom': {'lat': 12.01, 'lng': -0.9}}, {'geometry': {'lat': 0.1, 'lng': 10}}]} + def list_with_things(): assert floatify_latlng([{'foo': 'bar'}]) == [{'foo': 'bar'}] diff --git a/test/test_headers.py b/test/test_headers.py index 644ddb4..86e489e 100644 --- a/test/test_headers.py +++ b/test/test_headers.py @@ -13,7 +13,9 @@ geocoder = OpenCageGeocode('abcde', user_agent_comment='OpenCage Test') -user_agent_format = re.compile(r'^opencage-python/[\d\.]+ Python/[\d\.]+ (requests|aiohttp)/[\d\.]+ \(OpenCage Test\)$') +user_agent_format = re.compile( + r'^opencage-python/[\d\.]+ Python/[\d\.]+ (requests|aiohttp)/[\d\.]+ \(OpenCage Test\)$') + @responses.activate def test_sync(): @@ -25,7 +27,7 @@ def test_sync(): ) geocoder.geocode("EC1M 5RF") - + # Check the User-Agent header in the most recent request request = responses.calls[-1].request user_agent = request.headers['User-Agent'] diff --git a/test/test_reverse.py b/test/test_reverse.py index f7c5aae..8c39058 100644 --- a/test/test_reverse.py +++ b/test/test_reverse.py @@ -1,11 +1,13 @@ from opencage.geocoder import _query_for_reverse_geocoding -def _expected_output(input_latlng, expected_output): # pylint: disable=no-self-argument + +def _expected_output(input_latlng, expected_output): def test(): lat, lng = input_latlng assert _query_for_reverse_geocoding(lat, lng) == expected_output return test + def test_reverse(): _expected_output((10, 10), "10,10") _expected_output((10.0, 10.0), "10.0,10.0") diff --git a/test/test_session.py b/test/test_session.py index 449eb9e..d9dfa88 100644 --- a/test/test_session.py +++ b/test/test_session.py @@ -8,13 +8,15 @@ from opencage.geocoder import OpenCageGeocode from opencage.geocoder import NotAuthorizedError + def _any_result_around(results, lat=None, lon=None): for result in results: - if (abs(result['geometry']['lat'] - lat) < 0.05 and - abs(result['geometry']['lng'] - lon) < 0.05): + if (abs(result['geometry']['lat'] - lat) < 0.05 + and abs(result['geometry']['lng'] - lon) < 0.05): return True return False + @responses.activate def test_success(): with OpenCageGeocode('abcde') as geocoder: @@ -28,6 +30,7 @@ def test_success(): results = geocoder.geocode("EC1M 5RF") assert _any_result_around(results, lat=51.5201666, lon=-0.0985142) + @responses.activate def test_failure(): with OpenCageGeocode('unauthorized-key') as geocoder: diff --git a/tox.ini b/tox.ini index e67f6fc..516cd79 100644 --- a/tox.ini +++ b/tox.ini @@ -23,7 +23,7 @@ commands = usedevelop = True deps = responses - pylint==2.17.4 + flake8>=7.0.0 pytest commands = - pylint opencage examples/demo.py setup.py test + flake8 opencage examples/demo.py setup.py test