diff -Nru isbnlib-3.5.6/.appveyor.yml isbnlib-3.9.3/.appveyor.yml --- isbnlib-3.5.6/.appveyor.yml 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/.appveyor.yml 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,58 @@ +version: '3.9.3.{build}' +branches: + only: + - /v3.9.3/ +environment: + matrix: + - TOXENV: "py36" + TOXPYTHON: "C:\\Python36-x64\\python.exe" + PYTHON_HOME: "C:\\Python36-x64" + PYTHON_VERSION: "3.6" + PYTHON_ARCH: "64" + + - TOXENV: "py35" + TOXPYTHON: "C:\\Python35\\python.exe" + PYTHON_HOME: "C:\\Python35" + PYTHON_VERSION: "3.5" + PYTHON_ARCH: "64" + + - TOXENV: "py34" + TOXPYTHON: "C:\\Python34-x64\\python.exe" + PYTHON_HOME: "C:\\Python34-x64" + PYTHON_VERSION: "3.4" + PYTHON_ARCH: "32" + + - TOXENV: "py27" + TOXPYTHON: "C:\\Python27-x64\\python.exe" + PYTHON_HOME: "C:\\Python27-x64" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "64" + + - TOXENV: "py27" + TOXPYTHON: "C:\\Python27\\python.exe" + PYTHON_HOME: "C:\\Python27" + PYTHON_VERSION: "2.7" + PYTHON_ARCH: "32" + +init: + - "ECHO %TOXENV%" + - "ECHO %TOXPYTHON% %PYTHON_VERSION% %PYTHON_ARCH%" + +install: + - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py') + - "%TOXPYTHON% C:/get-pip.py" + - "%PYTHON_HOME%/Scripts/pip.exe install -r requirements-appveyor.txt" + +build: false # First tests then build (is python not C) + +test_script: + - "%PYTHON_HOME%\\Scripts\\tox -e %TOXENV%" + +# clone_folder: 'c:\\projects\\isbnlib' + +# after_test: +# - "%TOXPYTHON% setup.py bdist_wheel" +# - ps: "ls dist" + +# artifacts: +# - path: 'dist\\*.whl' diff -Nru isbnlib-3.5.6/appveyor.yml isbnlib-3.9.3/appveyor.yml --- isbnlib-3.5.6/appveyor.yml 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/appveyor.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -version: '3.5.6.{build}' -branches: - only: - - /v3.5.6/ -environment: - matrix: - - TOXENV: "py27" - TOXPYTHON: "C:\\Python27\\python.exe" - PYTHON_HOME: "C:\\Python27" - PYTHON_VERSION: "2.7" - PYTHON_ARCH: "32" - - - TOXENV: "py34" - TOXPYTHON: "C:\\Python34-x64\\python.exe" - PYTHON_HOME: "C:\\Python34-x64" - PYTHON_VERSION: "3.4" - PYTHON_ARCH: "64" - - - TOXENV: "py27" - TOXPYTHON: "C:\\Python27-x64\\python.exe" - PYTHON_HOME: "C:\\Python27-x64" - PYTHON_VERSION: "2.7" - PYTHON_ARCH: "64" - - - TOXENV: "py33" - TOXPYTHON: "C:\\Python33\\python.exe" - PYTHON_HOME: "C:\\Python33" - PYTHON_VERSION: "3.3" - PYTHON_ARCH: "32" - -init: - - "ECHO %TOXENV%" - - "ECHO %TOXPYTHON% %PYTHON_VERSION% %PYTHON_ARCH%" - -install: - - ps: (new-object net.webclient).DownloadFile('https://raw.github.com/pypa/pip/master/contrib/get-pip.py', 'C:/get-pip.py') - - "%TOXPYTHON% C:/get-pip.py" - - "%PYTHON_HOME%/Scripts/pip.exe install -r requirements-appveyor.txt" - -build: false # First tests then build (is python not C) - -test_script: - - "%PYTHON_HOME%\\Scripts\\tox -e %TOXENV%" - -# clone_folder: 'c:\\projects\\isbnlib' - -# after_test: -# - "%TOXPYTHON% setup.py bdist_wheel" -# - ps: "ls dist" - -# artifacts: -# - path: 'dist\\*.whl' diff -Nru isbnlib-3.5.6/CHANGES.txt isbnlib-3.9.3/CHANGES.txt --- isbnlib-3.5.6/CHANGES.txt 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/CHANGES.txt 2018-10-05 11:18:35.000000000 +0000 @@ -17,6 +17,29 @@ v3.5.1, 2015-03-10 -- New CoversCache and better unicode printing in Windows. v3.5.2, 2015-03-15 -- Fix bug #19, relative paths on coverscache and data range 20150310. v3.5.3, 2015-03-26 -- Add throttling for web services, data range 20150325 and 'in memory' keys cache. -v3.5.4, 2015-04-10 -- Issue #20, fix bugs #21 and #22 and data range 20150401. +v3.5.4, 2015-04-10 -- Issue #20, fix bugs #21 and #22 and data range 20150401. v3.5.5, 2015-04-22 -- Add logging to vias, fix bug #23, and data range 20150422. -v3.5.6, 2015-06-03 -- Deprecated 'bouth23' and data range 20150603. +v3.5.6, 2015-06-03 -- Deprecated 'bouth23' and data range 20150603. +v3.5.7, 2015-11-22 -- Support for py35 and pypy3 and data range 20151118. +v3.5.8, 2016-03-07 -- Issue #28 (closing down of xISBN service). +v3.5.9, 2016-06-17 -- Improved data quality (close #39 and #40) and new cover (close issue #42). +v3.6.1, 2016-06-21 -- Improved data quality (#39 and #40), new cover (#42) and streamlined. +v3.6.2, 2016-09-06 -- Updated data. +v3.6.3, 2016-11-09 -- Updated data. +v3.6.4, 2016-11-12 -- Fix bug #46. +v3.6.5, 2016-12-08 -- Updated data. +v3.6.6, 2017-01-05 -- Fix bug #47. +v3.6.7, 2017-03-11 -- Updated data. +v3.6.8, 2017-03-31 -- New functions: check_digit10 and check_digit13. +v3.7.1, 2017-05-24 -- Fix #43 (bump middle version). +v3.7.2, 2017-06-19 -- Restore xID (improved data quality close #28). +v3.7.3, 2018-01-08 -- Updated data. +v3.7.4, 2018-01-08 -- Add support for CSL-JSON format (close #48). +v3.8.1, 2018-01-24 -- BREAK: stop support for py26, py33 and isbndb. +v3.8.2, 2018-01-24 -- Fix bug 'in_virtual'. +v3.8.3, 2018-01-29 -- Add 'wcat' to editions. +v3.8.4, 2018-03-06 -- Solve issues with non-ASCII searchs in 'from_words'. +v3.8.5, 2018-06-14 -- NOT RELEASED. +v3.9.1, 2018-07-02 -- Issue #51 (closing down of xISBN service). +v3.9.2, 2018-09-28 -- Updated data. +v3.9.3, 2018-10-05 -- make it easier to override 'WEBService.data'. diff -Nru isbnlib-3.5.6/.checkignore isbnlib-3.9.3/.checkignore --- isbnlib-3.5.6/.checkignore 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/.checkignore 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,3 @@ +# Ignore folder content +isbnlib/test/* +isbnlib/_data/* diff -Nru isbnlib-3.5.6/CODE_OF_CONDUCT.md isbnlib-3.9.3/CODE_OF_CONDUCT.md --- isbnlib-3.5.6/CODE_OF_CONDUCT.md 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/CODE_OF_CONDUCT.md 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [xlcnd@outlook.com]. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + diff -Nru isbnlib-3.5.6/CONTRIBUTING.md isbnlib-3.9.3/CONTRIBUTING.md --- isbnlib-3.5.6/CONTRIBUTING.md 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/CONTRIBUTING.md 2018-10-05 11:18:35.000000000 +0000 @@ -17,7 +17,7 @@ 3. **Fork** the repository on GitHub and **clone it locally** ([help](https://help.github.com/articles/fork-a-repo)). 4. `pip install -r requirements-dev.txt` (at your local directory). -5. Do your code... (**remember the code must run on python 2.6, 2.7, 3.3, 3.4, pypy +5. Do your code... (**remember the code must run on python 2.7, 3.4, 3.5, 3.6 and be OS independent** It is easier if you start to write in python 3 and then adapt for python 2) (you will find [Travis](https://travis-ci.org/xlcnd/isbnlib) very handy for testing with this requirement!) @@ -36,7 +36,7 @@ ## Style Your code **must** be [PEP8](http://legacy.python.org/dev/peps/pep-0008/) compliant -and be concise as possible (check it with +and be concise as possible (use `yapf` then check it with `flake8` and `pylint`). Use doc strings ([PEP257](http://legacy.python.org/dev/peps/pep-0257/)) diff -Nru isbnlib-3.5.6/COPYRIGHT.txt isbnlib-3.9.3/COPYRIGHT.txt --- isbnlib-3.5.6/COPYRIGHT.txt 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/COPYRIGHT.txt 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,16 @@ + +isbnlib - tools for extracting, cleaning and transforming ISBNs +Copyright (C) 2014-2018 Alexandre Lima Conde + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see . diff -Nru isbnlib-3.5.6/.coveragerc isbnlib-3.9.3/.coveragerc --- isbnlib-3.5.6/.coveragerc 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/.coveragerc 2018-10-05 11:18:35.000000000 +0000 @@ -39,3 +39,5 @@ if __name__ == .__main__.: ignore_errors = True + +fail_under = 90 diff -Nru isbnlib-3.5.6/debian/changelog isbnlib-3.9.3/debian/changelog --- isbnlib-3.5.6/debian/changelog 2015-06-24 18:52:05.000000000 +0000 +++ isbnlib-3.9.3/debian/changelog 2018-10-21 10:19:21.000000000 +0000 @@ -1,3 +1,9 @@ +isbnlib (3.9.3-1) unstable; urgency=low + + * New upstream package + + -- Aigars Mahinovs Sun, 21 Oct 2018 13:19:21 +0300 + isbnlib (3.5.6-1) unstable; urgency=low * Initial package upload diff -Nru isbnlib-3.5.6/debian/control isbnlib-3.9.3/debian/control --- isbnlib-3.5.6/debian/control 2015-06-24 18:58:53.000000000 +0000 +++ isbnlib-3.9.3/debian/control 2018-10-21 10:19:21.000000000 +0000 @@ -3,7 +3,7 @@ Section: python Priority: optional Build-Depends: python-setuptools (>= 0.6b3), python3-setuptools, python-all (>= 2.6.6-3), python3-all, debhelper (>= 9), dh-python, python-nose, python3-nose -Standards-Version: 3.9.6 +Standards-Version: 4.2.1 Package: python-isbnlib Architecture: all diff -Nru isbnlib-3.5.6/debian/watch isbnlib-3.9.3/debian/watch --- isbnlib-3.5.6/debian/watch 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/debian/watch 2018-10-21 10:19:21.000000000 +0000 @@ -0,0 +1,4 @@ +version=4 + +opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/isbnlib-$1\.tar\.gz/ \ + https://github.com/xlcnd/isbnlib/tags .*/v?(\d\S*)\.tar\.gz diff -Nru isbnlib-3.5.6/docs/code.rst isbnlib-3.9.3/docs/code.rst --- isbnlib-3.5.6/docs/code.rst 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/docs/code.rst 2018-10-05 11:18:35.000000000 +0000 @@ -14,35 +14,20 @@ Status ------ -.. image:: https://pypip.in/d/isbnlib/badge.png - :target: https://pypi.python.org/pypi/isbnlib/ - :alt: Downloads - -.. image:: https://pypip.in/v/isbnlib/badge.png - :target: https://pypi.python.org/pypi/isbnlib/ - :alt: Latest Version - -.. image:: https://pypip.in/format/isbnlib/badge.png - :target: https://pypi.python.org/pypi/isbnlib/ - :alt: Download format - -.. image:: https://pypip.in/license/isbnlib/badge.png - :target: https://pypi.python.org/pypi/isbnlib/ - :alt: License - -.. image:: https://coveralls.io/repos/xlcnd/isbnlib/badge.svg?branch=v3.5.6 - :target: https://coveralls.io/r/xlcnd/isbnlib?branch=v3.5.6 - :alt: Coverage -.. image:: https://sourcegraph.com/api/repos/github.com/xlcnd/isbnlib/badges/status.svg +.. image:: https://img.shields.io/badge/Sourcegraph-Status-blue.svg :target: https://sourcegraph.com/github.com/xlcnd/isbnlib :alt: Graph -.. image:: https://travis-ci.org/xlcnd/isbnlib.svg?branch=v3.5.6 +.. image:: https://coveralls.io/repos/github/xlcnd/isbnlib/badge.svg?branch=v3.9.3 + :target: https://coveralls.io/github/xlcnd/isbnlib?branch=v3.9.3 + :alt: Coverage Status + +.. image:: https://travis-ci.org/xlcnd/isbnlib.svg?branch=v3.9.3 :target: https://travis-ci.org/xlcnd/isbnlib :alt: Built Status -.. image:: https://ci.appveyor.com/api/projects/status/github/xlcnd/isbnlib?branch=v3.5.6&svg=true +.. image:: https://ci.appveyor.com/api/projects/status/github/xlcnd/isbnlib?branch=v3.9.3&svg=true :target: https://ci.appveyor.com/project/xlcnd/isbnlib :alt: Windows Built Status @@ -54,7 +39,7 @@ ----------------- ``isbnlib`` has a very small code base, so it is a good project to begin your -adventure in open-source... +adventure in open-source... Main Steps @@ -82,7 +67,7 @@ If you don't have experience in these issues, don't be put off by these requirements, see them as a learning opportunity. Thanks! - For full instructions read the CONTRIBUTING_ doc. + For full instructions read the CONTRIBUTING_ doc. .. _sourcegraph: https://sourcegraph.com/github.com/xlcnd/isbnlib diff -Nru isbnlib-3.5.6/docs/conf.py isbnlib-3.9.3/docs/conf.py --- isbnlib-3.5.6/docs/conf.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/docs/conf.py 2018-10-05 11:18:35.000000000 +0000 @@ -45,7 +45,7 @@ # General information about the project. project = u'isbnlib' -copyright = u'2014, Alexandre Conde' +copyright = u'2014-2018, Alexandre Conde' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -54,7 +54,7 @@ # The short X.Y version. version = '3.5' # The full version, including alpha/beta/rc tags. -release = '3.5.6' +release = '3.9.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -94,7 +94,6 @@ # 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 @@ -179,26 +178,23 @@ # Output file base name for HTML help builder. htmlhelp_basename = 'isbnlibdoc' - # -- 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': '', + # 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', 'isbnlib.tex', u'isbnlib Documentation', - u'Alexandre Conde', 'manual'), + ('index', 'isbnlib.tex', u'isbnlib Documentation', u'Alexandre Conde', + 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -221,39 +217,31 @@ # 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', 'isbnlib', u'isbnlib Documentation', - [u'Alexandre Conde'], 1) -] +man_pages = [('index', 'isbnlib', u'isbnlib Documentation', + [u'Alexandre Conde'], 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', 'isbnlib', u'isbnlib Documentation', - u'Alexandre Conde', 'isbnlib', 'One line description of project.', - 'Miscellaneous'), + ('index', 'isbnlib', u'isbnlib Documentation', u'Alexandre Conde', + 'isbnlib', '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 diff -Nru isbnlib-3.5.6/docs/devs.rst isbnlib-3.9.3/docs/devs.rst --- isbnlib-3.5.6/docs/devs.rst 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/docs/devs.rst 2018-10-05 11:18:35.000000000 +0000 @@ -10,7 +10,7 @@ This library works mainly with 'striped' ISBNs (only numbers and X) like '0826497527'. You can strip an ISBN's like string by using ``canonical(isbnlike)``. You can 'mask' the ISBN by using ``mask(isbn)``. So in the examples below, when you see 'isbn' - in the argument, it is a 'striped' ISBN, when the argument is an 'isbnlike' it is a string + in the argument, it is a 'striped' ISBN, when the argument is an 'isbnlike' it is a string like ``ISBN 979-10-90636-07-1`` or even something dirty like ``asdf 979-10-90636-07-1 bla bla``. Two important concepts: **valid ISBN** should be an ISBN that was built according with the rules, @@ -25,7 +25,7 @@ If possible, work with ISBNs in the isbn-13 format (since 2007, only are issued ISBNs in the isbn-13 format). You can always convert isbn-10 to isbn-13, but **not** the reverse. - Read more about ISBN at isbn-international.org_. + Read more about ISBN at isbn-international.org_. @@ -35,85 +35,83 @@ In the namespace ``isbnlib`` you have access to the core methods: ``is_isbn10(isbn10like)`` - Validates as ISBN-10. + Validates as ISBN-10. ``is_isbn13(isbn13like)`` - Validates as ISBN-13. + Validates as ISBN-13. ``to_isbn10(isbn13)`` - Transforms an isbn-13 to isbn-10. + Transforms an isbn-13 to isbn-10. ``to_isbn13(isbn10)`` - Transforms an isbn-10 to isbn-13. + Transforms an isbn-10 to isbn-13. ``canonical(isbnlike)`` - Keeps only numbers and X. You will get strings like `9780321534965`. + Keeps only numbers and X. You will get strings like `9780321534965`. ``clean(isbnlike)`` - Cleans ISBN (only legal characters). + Cleans ISBN (only legal characters). ``notisbn(isbnlike, level='strict')`` - Check with the goal to invalidate isbn-like. + Check with the goal to invalidate isbn-like. ``get_isbnlike(text, level='normal')`` - Extracts all substrings that seem like ISBNs (very useful for scraping). + Extracts all substrings that seem like ISBNs (very useful for scraping). ``get_canonical_isbn(isbnlike, output='bouth')`` - Extracts ISBNs and transform them to the canonical form. + Extracts ISBNs and transform them to the canonical form. ``EAN13(isbnlike)`` - Transforms an `isbnlike` string into an EAN13 number (validated canonical ISBN-13). + Transforms an `isbnlike` string into an EAN13 number (validated canonical ISBN-13). ``info(isbn)`` - Gets the language or country assigned to this ISBN. + Gets the language or country assigned to this ISBN. ``mask(isbn, separator='-')`` - `Mask` (hyphenate) a canonical ISBN. + `Mask` (hyphenate) a canonical ISBN. ``meta(isbn, service='default', cache='default')`` Gives you the main metadata associated with the ISBN. As `service` parameter you can use: - ``'wcat'`` uses **worldcat.org** - (**no key is needed**), ``'goob'`` uses the **Google Books service** (**no key is needed**), - ``'isbndb'`` uses the **isbndb.com** service (**an api key is needed**), - ``'openl'`` uses the **OpenLibrary.org** api (**no key is needed**), ``merge`` uses - a merged record of ``wcat`` and ``goob`` records (**no key is needed**) and - **is the default option**. - You can get an API key for the *isbndb.com service* here_. You can enter API keys - with ``isbnlib.config.add_apikey(service, apikey)``. - The output can be formatted as ``bibtex``, ``msword``, ``endnote``, ``refworks``, + ``'goob'`` uses the **Google Books service** (**no key is needed**) and + **is the default option**, + ``'openl'`` uses the **OpenLibrary.org** api (**no key is needed**). + You can enter API keys + with ``config.add_apikey(service, apikey)`` (see example below). + The output can be formatted as ``bibtex``, ``csl`` (CSL-JSON), ``msword``, ``endnote``, ``refworks``, ``opf`` or ``json`` (BibJSON) bibliographic formats with ``isbnlib.registry.bibformatters``. - ``cache`` only allows two values: 'default' or None. You can change the kind of cache by using + ``cache`` only allows two values: 'default' or None. You can change the kind of cache by using ``isbnlib.registry.set_cache`` (see below). + Now, you can extend the functionality of this function by adding pluggins, more metadata + providers or new bibliographic formatters (check_ for available pluggins). -``editions(isbn, service='wcat')`` +``editions(isbn, service='merge')`` Returns the list of ISBNs of editions related with this ISBN. By default - uses 'wcat', but other providers are avilable: 'thingl' (uses the - service ThingISBN from **LibraryThing**), 'merge' (merges 'wcat' with 'thingl') - and 'any' (first tries 'wcat', if no data, tries 'thingl'). + uses 'merge' (merges 'openl' and 'thingl'), but other providers are available: + 'openl' users **Open Library**, 'thingl' (uses the service ThingISBN from **LibraryThing**) + and 'any' (first tries 'openl', if no data, then 'thingl'). ``isbn_from_words(words)`` - Returns the most probable ISBN from a list of words (for your geographic area). + Returns the most probable ISBN from a list of words (for your geographic area). ``goom(words)`` - Returns a list of references from **Google Books multiple references**. + Returns a list of references from **Google Books multiple references**. ``doi(isbn)`` - Returns a DOI's ISBN-A from a ISBN-13. + Returns a DOI's ISBN-A from a ISBN-13. ``doi2tex(DOI)`` - Returns metadata formated as BibTeX for a given DOI. + Returns metadata formated as BibTeX for a given DOI. ``ren(filename)`` - Renames a file using metadata from an ISBN in his filename. + Renames a file using metadata from an ISBN in his filename. ``desc(isbn)`` - Returns a small description of the book. - *Almost all data available are for US books!* + Returns a small description of the book. + *Almost all data available are for US books!* ``cover(isbn)`` - Downloads an image of the cover of the book or, with - `cover(isbn, mode='url')`, returns an url of the image. - *Almost all data available are for US books!* + Returns a dictionary with the url for cover. + *Almost all data available are for US books!* See files test_core_ and test_ext_ for **a lot of examples**. @@ -142,18 +140,14 @@ * ``vias`` exposes several functions to put calls to services, just by passing the name and a pointer to the service's ``query`` function. - ``vias.parallel`` allows to put threaded calls. You can use ``vias.serial`` + ``vias.parallel`` allows to put threaded calls. You can use ``vias.serial`` to make serial calls and ``vias.multi`` to use several cores. The default is ``vias.serial``, but you can change that in the conf file. -* ``bouth23`` (**DEPRECATED**) a small module to make it possible the code to run - in **bouth** python 2 and python 3. **It will disappear in the next major version!**. - See python-future.org_ for a built-in alternative to ``bouth23``. - -The exceptions raised by these methods can all be catched using ``ISBNLibDevException``. -You **should't raise** this exception in your code, only raise the specific exceptions +The exceptions raised by these methods can all be catched using ``ISBNLibDevException``. +You **should't raise** this exception in your code, only raise the specific exceptions exposed in ``isbnlib.dev`` whose name end in Error. @@ -161,25 +155,74 @@ are only used in ``isbntools`` (*an app and framework* that uses ``isbnlib``). -With ``isbnlib.registry`` you can change the metadata service to be used by default (``setdefaultservice``), +With ``isbnlib.registry`` you can change the metadata service to be used by default (``setdefaultservice``), add a new service (``add_service``), access bibliographic formatters for metadata (``bibformatters``), -set the default formatter (``setdefaultbibformatter``), add new formatters (``add_bibformatter``) and +set the default formatter (``setdefaultbibformatter``), add new formatters (``add_bibformatter``) and set a new cache (``set_cache``) (e.g. to switch off the chache ``set_cache(None)``). The cache only works for calls through ``isbnlib.meta``. These changes only work for the 'current session', so should be done always before calling other methods. -Finally, from ``isbnlib.config`` you can read and set configuration options: -change timeouts with ``setsocketstimeout`` and ``setthreadstimeout``, +Finally, from ``isbnlib.config`` you can read and set configuration options: +change timeouts with ``seturlopentimeout`` and ``setthreadstimeout``, access api keys with ``apikeys`` and add new one with ``add_apikey`` and access and set generic and user-defined options with ``options`` and ``set_option``. +Let us concretize the last point with a small example. + +Suppose you want a small script to get metadata using ``Open Library`` formated in BibTeX. + +A minimal script would be: + + +.. code-block:: python + + from isbnlib import meta + from isbnlib.registry import bibformatters + + SERVICE = 'openl' + + # now you can use the service + isbn = '9780446310789' + bibtex = bibformatters['bibtex'] + print(bibtex(meta(isbn, SERVICE))) + All these classes follow a simple design pattern and, if you follow it, will be very easy to integrate your classes with the rest of the lib. +Plugins +------- + +You can extend the functionality of the library by adding pluggins (for now, just +new metadata providers or new bibliographic formatters). + +Start with this template_ and follow the instructions there. For inspiration take a look +at goob_. + +After install, your pluggin will blend transparently in ``isbnlib``. + +Remember that plugins **must** support python 2.7 and python 3.4+ (see python-future.org_). + +For available pluggins check_ here. + + + +Extra Functionality +------------------- + +To get extra functionality, search_ pypi for packages starting with ``isbnlib`` +**or** type at a terminal: + +.. code-block:: console + + $ pip search isbnlib + + +for a nice formated report! + Merge Metadata @@ -190,16 +233,16 @@ *polling & merge* of several providers **and** a **lot** of cleaning and standardization for fields like ``Authors`` and ``Publisher``. A *simple merge* provider is now the default in ``isbnlib.meta``. -It gives priority to ``wcat`` but overwrites the ``Authors`` field with the value from ``goob``. -Uses the ``merge`` method of ``Metadata`` and *serial* calls to services -by default (faster for fast Internet connections). - -You can change that by using ``vias``'s other methods +It gives priority to ``wcat`` but overwrites the ``Authors``, ``Publisher`` and ``Year`` +fields with values from ``goob`` (if available) or ``openl``. +Uses the ``merge`` method of ``Metadata`` and *parallel* calls to services. + +You can change that by using ``vias``'s other methods (e.g. ``isbnlib.config.set_option('VIAS_MERGE', 'multi')``. You can write your own *merging scheme* by creating a new provider (see_ ``merge`` for an example). - **Take Note**: These classes are optimized for one-calls to services and not for batch calls. +.. note:: These classes are optimized for one-calls to services and not for batch calls. A full featured app! @@ -213,9 +256,8 @@ **You can browse the code, in a very structured way, at** sourcegraph_ or GitHub_. -.. _wcat: https://github.com/xlcnd/isbnlib/blob/master/isbnlib/_wcat.py -.. _isbndb: https://github.com/xlcnd/isbnlib/blob/master/isbnlib/_isbndb.py + .. _see: https://github.com/xlcnd/isbnlib/blob/master/isbnlib/_merge.py @@ -232,3 +274,11 @@ .. _isbn-international.org: https://www.isbn-international.org/content/what-isbn .. _python-future.org: http://python-future.org/compatible_idioms.html + +.. _check: https://pypi.python.org/pypi?%3Aaction=search&term=isbnlib_&submit=search + +.. _template: https://github.com/xlcnd/isbnlib/blob/dev/PLUGIN.zip + +.. _goob: https://github.com/xlcnd/isbnlib/blob/dev/isbnlib/_goob.py + +.. _search: https://pypi.python.org/pypi?%3Aaction=search&term=isbnlib&submit=search diff -Nru isbnlib-3.5.6/docs/info.rst isbnlib-3.9.3/docs/info.rst --- isbnlib-3.5.6/docs/info.rst 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/docs/info.rst 2018-10-05 11:18:35.000000000 +0000 @@ -3,13 +3,23 @@ Info ==== +``isbnlib`` is a (pure) python library that provides several +useful methods and functions to validate, clean, transform, hyphenate and +get metadata for ISBN strings. Its origin was as the core of isbntools_. +This short version, is suitable to be include as a dependency in other projects. +Has a straightforward setup and a very easy programmatic api. + +Runs on py27, py34, py35, py36 and py37. + + +Usage +----- Typical usage (as library): .. code-block:: python - #!/usr/bin/env python import isbnlib ... @@ -53,6 +63,30 @@ Have fun! -.. _here: http://isbndb.com/api/v2/docs + + +Projects using *isbnlib* +------------------------ + +**isbntools** https://github.com/xlcnd/isbntools + +**Spreads** https://github.com/DIYBookScanner/spreads + +**BiblioManager** https://github.com/Phyks/BMC/ + +**libBMC** https://github.com/Phyks/libbmc/ + +**Alessandria** https://gitlab.com/openlabmatera/alessandria + +**Comic Collector** https://github.com/wengole/comiccollector + +**Abelujo** http://www.abelujo.cc/ + +**BibLib** https://pypi.python.org/pypi/biblib + + + .. _pdfminer: https://pypi.python.org/pypi/pdfminer + +.. _isbntools: https://pypi.python.org/pypi/isbntools diff -Nru isbnlib-3.5.6/docs/install.rst isbnlib-3.9.3/docs/install.rst --- isbnlib-3.5.6/docs/install.rst 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/docs/install.rst 2018-10-05 11:18:35.000000000 +0000 @@ -21,8 +21,15 @@ .. code-block:: bash - $ pip install isbnlib-3.5.6.tar.gz + $ pip install isbnlib-3.9.3.tar.gz (first you have to download the file!) +If you use linux systems, you can install using your distribution package +manager (all major distributions have packages ``python-isbnlib`` +and ``python3-isbnlib``), however (usually) are **very old and don't work well anymore**! + + + + diff -Nru isbnlib-3.5.6/.editorconfig isbnlib-3.9.3/.editorconfig --- isbnlib-3.5.6/.editorconfig 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/.editorconfig 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,25 @@ +# EditorConfig.org + +root = true + +[*] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{py,md,rst,txt,conf,cfg}] +charset = utf-8 + +[*.py] +indent_style = space +indent_size = 4 + +[*.{md,rst}] +trim_trailing_whitespace = false + +[{appveyor.yml,.travis.yml}] +indent_style = space +indent_size = 2 + +[Makefile] +indent_style = tab diff -Nru isbnlib-3.5.6/.flake8 isbnlib-3.9.3/.flake8 --- isbnlib-3.5.6/.flake8 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/.flake8 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,3 @@ +ignore=N806,I100,I101,I201,N802,C901,E722,E741 +exclude=*/test/*,*/_data/* +max-complexity=13 diff -Nru isbnlib-3.5.6/.github/CODEOWNERS isbnlib-3.9.3/.github/CODEOWNERS --- isbnlib-3.5.6/.github/CODEOWNERS 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/.github/CODEOWNERS 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,2 @@ +isbnlib/* @xlcnd +docs/* @xlcnd diff -Nru isbnlib-3.5.6/.github/PULL_REQUEST_TEMPLATE.md isbnlib-3.9.3/.github/PULL_REQUEST_TEMPLATE.md --- isbnlib-3.5.6/.github/PULL_REQUEST_TEMPLATE.md 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/.github/PULL_REQUEST_TEMPLATE.md 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,16 @@ +**IMPORTANT** + +Make your pull request against the ``dev`` branch, please! + + + +Changes proposed in this pull request: + +- + +- + +- + + +@xlcnd diff -Nru isbnlib-3.5.6/.gitignore isbnlib-3.9.3/.gitignore --- isbnlib-3.5.6/.gitignore 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/.gitignore 2018-10-05 11:18:35.000000000 +0000 @@ -23,12 +23,14 @@ *.log *.sh .coverage +.bandit .metacache *tasks LAB/ apps/ spin/ LAB_* +*LAB* CHECKLIST TODO *release* diff -Nru isbnlib-3.5.6/.hound.yml isbnlib-3.9.3/.hound.yml --- isbnlib-3.5.6/.hound.yml 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/.hound.yml 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,5 @@ +python: + enabled: true + config_file: .flake8 + +fail_on_violations: true diff -Nru isbnlib-3.5.6/isbnlib/config.py isbnlib-3.9.3/isbnlib/config.py --- isbnlib-3.5.6/isbnlib/config.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/config.py 2018-10-05 11:18:35.000000000 +0000 @@ -3,28 +3,20 @@ # --> Import only external modules! <-- - -import socket - # Timeouts -SOCKETS_TIMEOUT = 12 # seconds -THREADS_TIMEOUT = 11 # seconds +URLOPEN_TIMEOUT = 10 # seconds +THREADS_TIMEOUT = 12 # seconds -def setsocketstimeout(seconds): - """Set the value of SOCKETS_TIMEOUT (in seconds).""" - global SOCKETS_TIMEOUT - SOCKETS_TIMEOUT = seconds - return socket.setdefaulttimeout(SOCKETS_TIMEOUT) - -# socket timeout is not exposed at urllib2 level so I had to import the -# module and set a default value for all the sockets (timeout in seconds) -# however this should be done at top level due to strong side effects... -setsocketstimeout(SOCKETS_TIMEOUT) +# URLOPEN_TIMEOUT is used by webservice +def seturlopentimeout(seconds): # pragma: no cover + """Set the value of URLOPEN_TIMEOUT (in seconds).""" + global URLOPEN_TIMEOUT + URLOPEN_TIMEOUT = seconds # THREADS_TIMEOUT is a parameter used downstream by Thread calls (see vias.py) -def setthreadstimeout(seconds): # pragma: no cover +def setthreadstimeout(seconds): # pragma: no cover """Set the value of THREADS_TIMEOUT (in seconds).""" global THREADS_TIMEOUT THREADS_TIMEOUT = seconds @@ -35,17 +27,14 @@ def add_apikey(service, apikey): # pragma: no cover - """Add API keys. - - add_apikey('isbndb', 'JuHytr6') [is fake!] - """ + """Add API keys.""" apikeys[service] = apikey # Generic Options -options = {'VIAS_MERGE': 'serial'} +options = {'VIAS_MERGE': 'parallel'} -def set_option(option, value): # pragma: no cover +def set_option(option, value): # pragma: no cover """Set the value for option.""" options[option] = value diff -Nru isbnlib-3.5.6/isbnlib/_core.py isbnlib-3.9.3/isbnlib/_core.py --- isbnlib-3.5.6/isbnlib/_core.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_core.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # isbnlib - tools for extracting, cleaning and transforming ISBNs -# Copyright (C) 2014 Alexandre Lima Conde +# Copyright (C) 2014-2018 Alexandre Lima Conde # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -15,8 +15,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . - - """isbnlib main file. Tools for extracting, cleaning, transforming and validating ISBN ids. @@ -27,7 +25,6 @@ LOGGER = logging.getLogger(__name__) - RE_ISBN10 = re.compile(r'ISBN\x20(?=.{13}$)\d{1,5}([- ])\d{1,7}' r'\1\d{1,6}\1(\d|X)$|[- 0-9X]{10,16}') RE_ISBN13 = re.compile(r'97[89]{1}(?:-?\d){10,16}|97[89]{1}[- 0-9]{10,16}') @@ -39,25 +36,24 @@ r'[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9X]$', re.I | re.M | re.S) RE_NORMAL = re.compile(r'97[89]{1}(?:-?\d){10}|\d{9}[0-9X]{1}|' - r'[-0-9X]{10,16}', - re.I | re.M | re.S) + r'[-0-9X]{10,16}', re.I | re.M | re.S) RE_LOOSE = re.compile(r'[- 0-9X]{10,19}', re.I | re.M | re.S) ISBN13_PREFIX = '978' LEGAL = '0123456789xXisbnISBN- ' -def _check_digit10(firstninedigits): +def check_digit10(firstninedigits): """Check sum ISBN-10.""" # minimum checks if len(firstninedigits) != 9: return None try: int(firstninedigits) - except: # pragma: no cover + except Exception: # pragma: no cover return None # checksum - val = sum((i + 2) * int(x) for - i, x in enumerate(reversed(firstninedigits))) + val = sum( + (i + 2) * int(x) for i, x in enumerate(reversed(firstninedigits))) remainder = int(val % 11) if remainder == 0: tenthdigit = 0 @@ -68,18 +64,18 @@ return str(tenthdigit) -def _check_digit13(firsttwelvedigits): +def check_digit13(firsttwelvedigits): """Check sum ISBN-13.""" # minimum checks if len(firsttwelvedigits) != 12: return None try: int(firsttwelvedigits) - except: # pragma: no cover + except Exception: # pragma: no cover return None # checksum - val = sum((i % 2 * 2 + 1) * int(x) for - i, x in enumerate(firsttwelvedigits)) + val = sum( + (i % 2 * 2 + 1) * int(x) for i, x in enumerate(firsttwelvedigits)) thirteenthdigit = 10 - int(val % 10) if thirteenthdigit == 10: thirteenthdigit = '0' @@ -100,20 +96,20 @@ """Validate as ISBN-10.""" isbn10 = canonical(isbn10) if len(isbn10) != 10: - return False # pragma: no cover + return False # pragma: no cover else: - return False if _check_digit10(isbn10[:-1]) != isbn10[-1] else True + return False if check_digit10(isbn10[:-1]) != isbn10[-1] else True def is_isbn13(isbn13): """Validate as ISBN-13.""" isbn13 = canonical(isbn13) if len(isbn13) != 13: - return False # pragma: no cover + return False # pragma: no cover else: if isbn13[0:3] not in ('978', '979'): return False - return False if _check_digit13(isbn13[:-1]) != isbn13[-1] else True + return False if check_digit13(isbn13[:-1]) != isbn13[-1] else True def to_isbn10(isbn13): @@ -125,7 +121,7 @@ if not is_isbn13(isbn13): return None isbn10 = isbn13[3:] - check = _check_digit10(isbn10[:-1]) + check = check_digit10(isbn10[:-1]) # Change check digit return isbn10[:-1] + check if check else None @@ -138,7 +134,7 @@ if not is_isbn10(isbn10): return None isbn13 = ISBN13_PREFIX + isbn10[:-1] - check = _check_digit13(isbn13) + check = check_digit13(isbn13) return isbn13 + check if check else None @@ -167,7 +163,7 @@ """ if level not in ('strict', 'loose'): # pragma: no cover LOGGER.error('level as no option %s', level) - return + return None isbnlike = canonical(isbnlike) if len(isbnlike) not in (10, 13): return True @@ -196,7 +192,7 @@ isbnlike = RE_LOOSE else: LOGGER.error('level as no option %s', level) - return + return None return isbnlike.findall(text) @@ -211,7 +207,7 @@ """ if output not in ('bouth', 'isbn10', 'isbn13'): # pragma: no cover LOGGER.error('output as no option %s', output) - return + return None regex = RE_NORMAL @@ -226,10 +222,10 @@ if len(chars) == 9: # Compute the ISBN-10 checksum digit - check = _check_digit10(buf) + check = check_digit10(buf) else: # Compute the ISBN-13 checksum digit - check = _check_digit13(buf) + check = check_digit13(buf) # If checksum OK return a `canonical` ISBN if str(check) == last: @@ -238,6 +234,7 @@ if output == 'isbn10': return cisbn if len(cisbn) == 10 else to_isbn10(cisbn) return to_isbn13(cisbn) if len(cisbn) == 10 else cisbn + return None def ean13(isbnlike): @@ -247,6 +244,9 @@ return ib if is_isbn13(ib) else None elif len(ib) == 10: return to_isbn13(ib) if is_isbn10(ib) else None + return None + # Alias EAN13 = ean13 +GTIN13 = ean13 diff -Nru isbnlib-3.5.6/isbnlib/_cover.py isbnlib-3.9.3/isbnlib/_cover.py --- isbnlib-3.5.6/isbnlib/_cover.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_cover.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,125 +1,39 @@ # -*- coding: utf-8 -*- -"""Get the cover of the book.""" +"""Get image links of the book's cover.""" import logging -try: # pragma: no cover - # PY3 - from urllib.error import HTTPError, URLError - from urllib.request import Request, urlopen -except ImportError: # pragma: no cover - # PY2 - from urllib2 import Request, urlopen, HTTPError, URLError - -from json import loads - -from .dev._exceptions import ISBNLibHTTPError, ISBNLibURLError -from .dev.webservice import query +from .dev.webquery import query as wquery +LOGGER = logging.getLogger(__name__) -COVERZOOM = 2 -NOIMGSIZE = (15666, 16641, 2690) UA = "isbnlib (gzip)" - -LOGGER = logging.getLogger(__name__) +SERVICE_URL = 'https://www.googleapis.com/books/v1/volumes?q=isbn+{isbn}'\ + '&fields=items/volumeInfo(imageLinks)&maxResults=1' -def bookid(isbn): - """Return the Google's id associated with each ISBN.""" +def cover(isbn): + """Main entry point for cover.""" from .registry import metadata_cache # <-- dynamic - # check the cache fist + # check the cache first cache = metadata_cache - if cache is not None: # pragma: no cover - key = 'gid' + isbn - try: # pragma: no cover + if cache: # pragma: no cover + key = 'img-url-go-' + isbn + try: # pragma: no cover if cache[key]: return cache[key] else: - raise # <-- IMPORTANT: usually the caches don't return error! - except: # pragma: no cover + raise KeyError # <-- IMPORTANT: caches don't return error! + except KeyError: # pragma: no cover pass - url = "https://www.googleapis.com/books/v1/volumes?q="\ - "isbn+{isbn}&fields=items/id&maxResults=1".format(isbn=isbn) - content = query(url, user_agent=UA) + # request to the web service + data = wquery(SERVICE_URL.format(isbn=isbn), user_agent=UA) try: - content = loads(content) - gid = content['items'][0]['id'] - if gid and cache is not None: - cache[key] = gid - return gid - except: # pragma: no cover - return - - -def _download(url, tofile=None): - """Download image.""" - headers = {'User-Agent': UA, 'Pragma': 'no-cache'} - request = Request(url, headers=headers) - try: - response = urlopen(request) - LOGGER.debug('Request headers:\n%s', request.header_items()) - except HTTPError as e: # pragma: no cover - LOGGER.critical('ISBNLibHTTPError for %s with code %s [%s]', - url, e.code, e.msg) - if e.code == 403: - # Google uses this code when the image is not - # available for any size (should use 404), - # but also when you are blacklisted by the service - LOGGER.debug('Cover not available or you are making many requests') - return True # <-- no more attempts to download - if e.code in (401, 429): - raise ISBNLibHTTPError('%s Are you are making many requests?' - % e.code) - if e.code in (502, 504): - raise ISBNLibHTTPError('%s Service temporarily unavailable!' - % e.code) - raise ISBNLibHTTPError('(%s) %s' % (e.code, e.msg)) - except URLError as e: # pragma: no cover - LOGGER.critical('ISBNLibURLError for %s with reason %s', - url, e.reason) - raise ISBNLibURLError(e.reason) - content = response.read() - noimageavailable = len(content) in NOIMGSIZE - if noimageavailable: # pragma: no cover - return False - if tofile: - try: # pragma: no cover - # PY2 - content_type = response.info().getheader('Content-Type') - except: # pragma: no cover - # PY3 - content_type = response.getheader('Content-Type') - _, ext = content_type.split('/') - tofile = tofile.split('.')[0] + '.' + ext.split('-')[-1] - with open(tofile, 'wb') as f: - f.write(content) - else: # pragma: no cover - print(content) - return tofile - - -def _google_cover(gid, isbn, zoom=COVERZOOM, mode='prt'): - """Download the cover from Google.""" - tpl = "http://books.google.com/books/content?id={gid}&printsec=frontcover"\ - "&img=1&zoom={zoom}&edge=curl&source=gbs_api" - url = tpl.format(gid=gid, zoom=zoom) - if mode == 'url': # pragma: no cover - return (url, None) - coverfile = _download(url, tofile=isbn) - while not coverfile: # pragma: no cover - # try a smaller resolution - zoom -= 1 - if zoom > 0: - url = tpl.format(gid=gid, zoom=zoom) - else: - return (None, None) - coverfile = _download(url, tofile=isbn) - return (url, coverfile) if coverfile and coverfile is not True\ - else (url, None) - - -def cover(isbn, size=COVERZOOM, mode='prt'): - """Main entry point for cover.""" - gid = bookid(isbn) - return _google_cover(gid, isbn, zoom=size, mode=mode) if gid\ - else (None, None) + lnks = data['items'][0]['volumeInfo']['imageLinks'] + # put in cache + if cache and lnks: # pragma: no cover + cache[key] = lnks + return lnks + except (KeyError, IndexError): # pragma: no cover + LOGGER.debug('No cover img data for %s', isbn) + return None diff -Nru isbnlib-3.5.6/isbnlib/_data/data4info.py isbnlib-3.9.3/isbnlib/_data/data4info.py --- isbnlib-3.5.6/isbnlib/_data/data4info.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_data/data4info.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,8 +1,295 @@ +# -*- coding: utf-8 -*- # flake8: noqa -# GeneratedWith: mk_data4info.py (isbntools) -# MessageSource: http://www.isbn-international.org/agency?rmxml=1 -# MessageDate: Wed, 3 Jun 2015 11:50:18 CEST -# MessageSerialNumber: 69eba68e-f50d-4193-9a48-c9f378be91f0 -d = {'978-99970': 'Haiti', '978-7': "China, People's Republic", '978-4': 'Japan', '978-5': 'former U.S.S.R', '978-2': 'French language', '978-3': 'German language', '978-0': 'English language', '978-1': 'English language', '978-9968': 'Costa Rica', '978-9961': 'Algeria', '978-9960': 'Saudi Arabia', '978-9963': 'Cyprus', '978-9962': 'Panama', '978-9965': 'Kazakhstan', '978-9964': 'Ghana', '978-9967': 'Kyrgyz Republic', '978-9966': 'Kenya', '978-967': 'Malaysia', '978-966': 'Ukraine', '978-965': 'Israel', '978-964': 'Iran', '978-963': 'Hungary', '978-962': 'Hong Kong, China', '978-961': 'Slovenia', '978-960': 'Greece', '978-9985': 'Estonia', '978-969': 'Pakistan', '978-968': 'Mexico', '978-9984': 'Latvia', '978-99971': 'Myanmar', '978-9983': 'Gambia', '978-99972': 'Faroe Islands', '978-99973': 'Mongolia', '978-99909': 'Malta', '978-99908': 'Malawi', '978-99905': 'Bolivia', '978-99904': 'Cura\xe7ao', '978-99906': 'Kuwait', '978-99901': 'Bahrain', '978-99903': 'Mauritius', '978-99902': 'Reserved Agency', '978-99976': 'Srpska, Republic of', '978-99977': 'Rwanda', '978-974': 'Thailand', '978-975': 'Turkey', '978-976': 'Caribbean Community', '978-977': 'Egypt', '978-970': 'Mexico', '978-971': 'Philippines', '978-972': 'Portugal', '978-973': 'Romania', '978-978': 'Nigeria', '978-979': 'Indonesia', '978-99918': 'Faroe Islands', '978-99919': 'Benin', '978-99916': 'Namibia', '978-99917': 'Brunei Darussalam', '978-99914': 'Suriname', '978-99915': 'Maldives', '978-99912': 'Botswana', '978-99913': 'Andorra', '978-99910': 'Sierra Leone', '978-99911': 'Lesotho', '979-11': 'Korea, Republic', '978-90': 'Netherlands', '978-91': 'Sweden', '978-92': 'International NGO Publishers and EU Organizations', '978-93': 'India', '978-94': 'Netherlands', '978-9982': 'Zambia', '978-9981': 'Morocco', '978-9980': 'Papua New Guinea', '978-9989': 'Macedonia', '978-9988': 'Ghana', '978-99923': 'El Salvador', '978-99922': 'Guatemala', '978-99921': 'Qatar', '978-99920': 'Andorra', '978-99927': 'Albania', '978-99926': 'Honduras', '978-99925': 'Paraguay', '978-99924': 'Nicaragua', '978-99929': 'Mongolia', '978-99928': 'Georgia', '978-9932': "Lao People's Democratic Republic", '978-9933': 'Syria', '978-9930': 'Costa Rica', '978-9931': 'Algeria', '978-9936': 'Afghanistan', '978-9937': 'Nepal', '978-9934': 'Latvia', '978-9935': 'Iceland', '979-12': 'Italy', '978-9938': 'Tunisia', '978-9939': 'Armenia', '978-958': 'Colombia', '978-959': 'Cuba', '978-956': 'Chile', '978-957': 'Taiwan', '978-954': 'Bulgaria', '978-955': 'Sri Lanka', '978-952': 'Finland', '978-953': 'Croatia', '978-950': 'Argentina', '978-951': 'Finland', '978-89': 'Korea, Republic', '978-88': 'Italy', '978-87': 'Denmark', '978-86': 'former Yugoslavia', '978-85': 'Brazil', '978-84': 'Spain', '978-83': 'Poland', '978-82': 'Norway', '978-81': 'India', '978-80': 'former Czechoslovakia', '978-99934': 'Dominican Republic', '978-99935': 'Haiti', '978-99936': 'Bhutan', '978-99937': 'Macau', '978-99930': 'Armenia', '978-99931': 'Seychelles', '978-99932': 'Malta', '978-99933': 'Nepal', '978-620': 'Mauritius', '978-621': 'Philippines', '978-99938': 'Srpska, Republic of', '978-99939': 'Guatemala', '978-9925': 'Cyprus', '978-9924': 'Cambodia', '978-9927': 'Qatar', '978-9926': 'Bosnia and Herzegovina', '978-9929': 'Guatemala', '978-9928': 'Albania', '979-10': 'France', '978-9986': 'Lithuania', '978-9987': 'Tanzania', '978-99941': 'Armenia', '978-99940': 'Georgia', '978-99943': 'Albania', '978-99942': 'Sudan', '978-99945': 'Namibia', '978-99944': 'Ethiopia', '978-99947': 'Tajikistan', '978-99946': 'Nepal', '978-99949': 'Mauritius', '978-99948': 'Eritrea', '978-9950': 'Palestine', '978-9951': 'Kosova', '978-9952': 'Azerbaijan', '978-9953': 'Lebanon', '978-9954': 'Morocco', '978-9955': 'Lithuania', '978-9956': 'Cameroon', '978-9957': 'Jordan', '978-9958': 'Bosnia and Herzegovina', '978-9959': 'Libya', '978-989': 'Portugal', '978-988': 'Hong Kong, China', '978-985': 'Belarus', '978-984': 'Bangladesh', '978-987': 'Argentina', '978-986': 'Taiwan', '978-981': 'Singapore', '978-980': 'Venezuela', '978-983': 'Malaysia', '978-982': 'South Pacific', '978-99952': 'Mali', '978-99953': 'Paraguay', '978-99950': 'Cambodia', '978-99951': 'Reserved Agency', '978-99956': 'Albania', '978-99957': 'Malta', '978-99954': 'Bolivia', '978-99955': 'Srpska, Republic of', '978-99958': 'Bahrain', '978-99959': 'Luxembourg', '978-9943': 'Uzbekistan', '978-9942': 'Ecuador', '978-9941': 'Georgia', '978-9940': 'Montenegro', '978-9947': 'Algeria', '978-9946': 'Korea, P.D.R.', '978-9945': 'Dominican Republic', '978-9944': 'Turkey', '978-9949': 'Estonia', '978-9948': 'United Arab Emirates', '978-615': 'Hungary', '978-614': 'Lebanon', '978-617': 'Ukraine', '978-616': 'Thailand', '978-611': 'Thailand', '978-613': 'Mauritius', '978-612': 'Peru', '978-619': 'Bulgaria', '978-618': 'Greece', '978-99974': 'Bolivia', '978-99967': 'Paraguay', '978-99966': 'Kuwait', '978-99965': 'Macau', '978-99964': 'Nicaragua', '978-99963': 'Cambodia', '978-99962': 'Mongolia', '978-99961': 'El Salvador', '978-99960': 'Malawi', '978-99969': 'Oman', '978-99968': 'Botswana', '978-9976': 'Tanzania', '978-9977': 'Costa Rica', '978-9974': 'Uruguay', '978-9975': 'Moldova', '978-9972': 'Peru', '978-9973': 'Tunisia', '978-9970': 'Uganda', '978-9971': 'Singapore', '978-99975': 'Tajikistan', '978-9978': 'Ecuador', '978-9979': 'Iceland', '978-602': 'Indonesia', '978-603': 'Saudi Arabia', '978-600': 'Iran', '978-601': 'Kazakhstan', '978-606': 'Romania', '978-607': 'Mexico', '978-604': 'Vietnam', '978-605': 'Turkey', '978-608': 'Macedonia', '978-609': 'Lithuania'} -identifiers = (('978-0', '978-1', '978-2', '978-3', '978-4', '978-5', '978-7'), ('978-80', '978-81', '978-82', '978-83', '978-84', '978-85', '978-86', '978-87', '978-88', '978-89', '978-90', '978-91', '978-92', '978-93', '978-94', '979-10', '979-11', '979-12'), ('978-600', '978-601', '978-602', '978-603', '978-604', '978-605', '978-606', '978-607', '978-608', '978-609', '978-611', '978-612', '978-613', '978-614', '978-615', '978-616', '978-617', '978-618', '978-619', '978-620', '978-621', '978-950', '978-951', '978-952', '978-953', '978-954', '978-955', '978-956', '978-957', '978-958', '978-959', '978-960', '978-961', '978-962', '978-963', '978-964', '978-965', '978-966', '978-967', '978-968', '978-969', '978-970', '978-971', '978-972', '978-973', '978-974', '978-975', '978-976', '978-977', '978-978', '978-979', '978-980', '978-981', '978-982', '978-983', '978-984', '978-985', '978-986', '978-987', '978-988', '978-989'), ('978-9924', '978-9925', '978-9926', '978-9927', '978-9928', '978-9929', '978-9930', '978-9931', '978-9932', '978-9933', '978-9934', '978-9935', '978-9936', '978-9937', '978-9938', '978-9939', '978-9940', '978-9941', '978-9942', '978-9943', '978-9944', '978-9945', '978-9946', '978-9947', '978-9948', '978-9949', '978-9950', '978-9951', '978-9952', '978-9953', '978-9954', '978-9955', '978-9956', '978-9957', '978-9958', '978-9959', '978-9960', '978-9961', '978-9962', '978-9963', '978-9964', '978-9965', '978-9966', '978-9967', '978-9968', '978-9970', '978-9971', '978-9972', '978-9973', '978-9974', '978-9975', '978-9976', '978-9977', '978-9978', '978-9979', '978-9980', '978-9981', '978-9982', '978-9983', '978-9984', '978-9985', '978-9986', '978-9987', '978-9988', '978-9989'), ('978-99901', '978-99902', '978-99903', '978-99904', '978-99905', '978-99906', '978-99908', '978-99909', '978-99910', '978-99911', '978-99912', '978-99913', '978-99914', '978-99915', '978-99916', '978-99917', '978-99918', '978-99919', '978-99920', '978-99921', '978-99922', '978-99923', '978-99924', '978-99925', '978-99926', '978-99927', '978-99928', '978-99929', '978-99930', '978-99931', '978-99932', '978-99933', '978-99934', '978-99935', '978-99936', '978-99937', '978-99938', '978-99939', '978-99940', '978-99941', '978-99942', '978-99943', '978-99944', '978-99945', '978-99946', '978-99947', '978-99948', '978-99949', '978-99950', '978-99951', '978-99952', '978-99953', '978-99954', '978-99955', '978-99956', '978-99957', '978-99958', '978-99959', '978-99960', '978-99961', '978-99962', '978-99963', '978-99964', '978-99965', '978-99966', '978-99967', '978-99968', '978-99969', '978-99970', '978-99971', '978-99972', '978-99973', '978-99974', '978-99975', '978-99976', '978-99977')) -RDDATE='2015060310:50:18WEST' +d = { + '978-0': 'English language', + '978-1': 'English language', + '978-2': 'French language', + '978-3': 'German language', + '978-4': 'Japan', + '978-5': 'former U.S.S.R', + '978-600': 'Iran', + '978-601': 'Kazakhstan', + '978-602': 'Indonesia', + '978-603': 'Saudi Arabia', + '978-604': 'Vietnam', + '978-605': 'Turkey', + '978-606': 'Romania', + '978-607': 'Mexico', + '978-608': 'Macedonia', + '978-609': 'Lithuania', + '978-611': 'Thailand', + '978-612': 'Peru', + '978-613': 'Mauritius', + '978-614': 'Lebanon', + '978-615': 'Hungary', + '978-616': 'Thailand', + '978-617': 'Ukraine', + '978-618': 'Greece', + '978-619': 'Bulgaria', + '978-620': 'Mauritius', + '978-621': 'Philippines', + '978-622': 'Iran', + '978-623': 'Indonesia', + '978-65': 'Brazil', + '978-7': "China, People's Republic", + '978-80': 'former Czechoslovakia', + '978-81': 'India', + '978-82': 'Norway', + '978-83': 'Poland', + '978-84': 'Spain', + '978-85': 'Brazil', + '978-86': 'former Yugoslavia', + '978-87': 'Denmark', + '978-88': 'Italy', + '978-89': 'Korea, Republic', + '978-90': 'Netherlands', + '978-91': 'Sweden', + '978-92': 'International NGO Publishers and EU Organizations', + '978-93': 'India', + '978-94': 'Netherlands', + '978-950': 'Argentina', + '978-951': 'Finland', + '978-952': 'Finland', + '978-953': 'Croatia', + '978-954': 'Bulgaria', + '978-955': 'Sri Lanka', + '978-956': 'Chile', + '978-957': 'Taiwan', + '978-958': 'Colombia', + '978-959': 'Cuba', + '978-960': 'Greece', + '978-961': 'Slovenia', + '978-962': 'Hong Kong, China', + '978-963': 'Hungary', + '978-964': 'Iran', + '978-965': 'Israel', + '978-966': 'Ukraine', + '978-967': 'Malaysia', + '978-968': 'Mexico', + '978-969': 'Pakistan', + '978-970': 'Mexico', + '978-971': 'Philippines', + '978-972': 'Portugal', + '978-973': 'Romania', + '978-974': 'Thailand', + '978-975': 'Turkey', + '978-976': 'Caribbean Community', + '978-977': 'Egypt', + '978-978': 'Nigeria', + '978-979': 'Indonesia', + '978-980': 'Venezuela', + '978-981': 'Singapore', + '978-982': 'South Pacific', + '978-983': 'Malaysia', + '978-984': 'Bangladesh', + '978-985': 'Belarus', + '978-986': 'Taiwan', + '978-987': 'Argentina', + '978-988': 'Hong Kong, China', + '978-989': 'Portugal', + '978-9920': 'Morocco', + '978-9921': 'Kuwait', + '978-9922': 'Iraq', + '978-9923': 'Jordan', + '978-9924': 'Cambodia', + '978-9925': 'Cyprus', + '978-9926': 'Bosnia and Herzegovina', + '978-9927': 'Qatar', + '978-9928': 'Albania', + '978-9929': 'Guatemala', + '978-9930': 'Costa Rica', + '978-9931': 'Algeria', + '978-9932': "Lao People's Democratic Republic", + '978-9933': 'Syria', + '978-9934': 'Latvia', + '978-9935': 'Iceland', + '978-9936': 'Afghanistan', + '978-9937': 'Nepal', + '978-9938': 'Tunisia', + '978-9939': 'Armenia', + '978-9940': 'Montenegro', + '978-9941': 'Georgia', + '978-9942': 'Ecuador', + '978-9943': 'Uzbekistan', + '978-9944': 'Turkey', + '978-9945': 'Dominican Republic', + '978-9946': 'Korea, P.D.R.', + '978-9947': 'Algeria', + '978-9948': 'United Arab Emirates', + '978-9949': 'Estonia', + '978-9950': 'Palestine', + '978-9951': 'Kosova', + '978-9952': 'Azerbaijan', + '978-9953': 'Lebanon', + '978-9954': 'Morocco', + '978-9955': 'Lithuania', + '978-9956': 'Cameroon', + '978-9957': 'Jordan', + '978-9958': 'Bosnia and Herzegovina', + '978-9959': 'Libya', + '978-9960': 'Saudi Arabia', + '978-9961': 'Algeria', + '978-9962': 'Panama', + '978-9963': 'Cyprus', + '978-9964': 'Ghana', + '978-9965': 'Kazakhstan', + '978-9966': 'Kenya', + '978-9967': 'Kyrgyz Republic', + '978-9968': 'Costa Rica', + '978-9970': 'Uganda', + '978-9971': 'Singapore', + '978-9972': 'Peru', + '978-9973': 'Tunisia', + '978-9974': 'Uruguay', + '978-9975': 'Moldova', + '978-9976': 'Tanzania', + '978-9977': 'Costa Rica', + '978-9978': 'Ecuador', + '978-9979': 'Iceland', + '978-9980': 'Papua New Guinea', + '978-9981': 'Morocco', + '978-9982': 'Zambia', + '978-9983': 'Gambia', + '978-9984': 'Latvia', + '978-9985': 'Estonia', + '978-9986': 'Lithuania', + '978-9987': 'Tanzania', + '978-9988': 'Ghana', + '978-9989': 'Macedonia', + '978-99901': 'Bahrain', + '978-99902': 'Reserved Agency', + '978-99903': 'Mauritius', + '978-99904': 'Curaçao', + '978-99905': 'Bolivia', + '978-99906': 'Kuwait', + '978-99908': 'Malawi', + '978-99909': 'Malta', + '978-99910': 'Sierra Leone', + '978-99911': 'Lesotho', + '978-99912': 'Botswana', + '978-99913': 'Andorra', + '978-99914': 'International NGO Publishers', + '978-99915': 'Maldives', + '978-99916': 'Namibia', + '978-99917': 'Brunei Darussalam', + '978-99918': 'Faroe Islands', + '978-99919': 'Benin', + '978-99920': 'Andorra', + '978-99921': 'Qatar', + '978-99922': 'Guatemala', + '978-99923': 'El Salvador', + '978-99924': 'Nicaragua', + '978-99925': 'Paraguay', + '978-99926': 'Honduras', + '978-99927': 'Albania', + '978-99928': 'Georgia', + '978-99929': 'Mongolia', + '978-99930': 'Armenia', + '978-99931': 'Seychelles', + '978-99932': 'Malta', + '978-99933': 'Nepal', + '978-99934': 'Dominican Republic', + '978-99935': 'Haiti', + '978-99936': 'Bhutan', + '978-99937': 'Macau', + '978-99938': 'Srpska, Republic of', + '978-99939': 'Guatemala', + '978-99940': 'Georgia', + '978-99941': 'Armenia', + '978-99942': 'Sudan', + '978-99943': 'Albania', + '978-99944': 'Ethiopia', + '978-99945': 'Namibia', + '978-99946': 'Nepal', + '978-99947': 'Tajikistan', + '978-99948': 'Eritrea', + '978-99949': 'Mauritius', + '978-99950': 'Cambodia', + '978-99951': 'Reserved Agency', + '978-99952': 'Mali', + '978-99953': 'Paraguay', + '978-99954': 'Bolivia', + '978-99955': 'Srpska, Republic of', + '978-99956': 'Albania', + '978-99957': 'Malta', + '978-99958': 'Bahrain', + '978-99959': 'Luxembourg', + '978-99960': 'Malawi', + '978-99961': 'El Salvador', + '978-99962': 'Mongolia', + '978-99963': 'Cambodia', + '978-99964': 'Nicaragua', + '978-99965': 'Macau', + '978-99966': 'Kuwait', + '978-99967': 'Paraguay', + '978-99968': 'Botswana', + '978-99969': 'Oman', + '978-99970': 'Haiti', + '978-99971': 'Myanmar', + '978-99972': 'Faroe Islands', + '978-99973': 'Mongolia', + '978-99974': 'Bolivia', + '978-99975': 'Tajikistan', + '978-99976': 'Srpska, Republic of', + '978-99977': 'Rwanda', + '978-99978': 'Mongolia', + '978-99979': 'Honduras', + '978-99980': 'Bhutan', + '978-99981': 'Macau', + '979-10': 'France', + '979-11': 'Korea, Republic', + '979-12': 'Italy' +} +identifiers = (('978-0', '978-1', '978-2', '978-3', '978-4', '978-5', + '978-7'), ('978-65', '978-80', '978-81', '978-82', '978-83', + '978-84', '978-85', '978-86', '978-87', '978-88', + '978-89', '978-90', '978-91', '978-92', '978-93', + '978-94', '979-10', '979-11', '979-12'), + ('978-600', '978-601', '978-602', '978-603', '978-604', + '978-605', '978-606', '978-607', '978-608', '978-609', + '978-611', '978-612', '978-613', '978-614', '978-615', + '978-616', '978-617', '978-618', '978-619', '978-620', + '978-621', '978-622', '978-623', '978-950', '978-951', + '978-952', '978-953', '978-954', '978-955', '978-956', + '978-957', '978-958', '978-959', '978-960', '978-961', + '978-962', '978-963', '978-964', '978-965', '978-966', + '978-967', '978-968', '978-969', '978-970', '978-971', + '978-972', '978-973', '978-974', '978-975', '978-976', + '978-977', '978-978', '978-979', '978-980', '978-981', + '978-982', '978-983', '978-984', '978-985', '978-986', + '978-987', '978-988', '978-989'), + ('978-9920', '978-9921', '978-9922', '978-9923', '978-9924', + '978-9925', '978-9926', '978-9927', '978-9928', '978-9929', + '978-9930', '978-9931', '978-9932', '978-9933', '978-9934', + '978-9935', '978-9936', '978-9937', '978-9938', '978-9939', + '978-9940', '978-9941', '978-9942', '978-9943', '978-9944', + '978-9945', '978-9946', '978-9947', '978-9948', '978-9949', + '978-9950', '978-9951', '978-9952', '978-9953', '978-9954', + '978-9955', '978-9956', '978-9957', '978-9958', '978-9959', + '978-9960', '978-9961', '978-9962', '978-9963', '978-9964', + '978-9965', '978-9966', '978-9967', '978-9968', '978-9970', + '978-9971', '978-9972', '978-9973', '978-9974', '978-9975', + '978-9976', '978-9977', '978-9978', '978-9979', '978-9980', + '978-9981', '978-9982', '978-9983', '978-9984', '978-9985', + '978-9986', '978-9987', '978-9988', '978-9989'), + ('978-99901', '978-99902', '978-99903', '978-99904', + '978-99905', '978-99906', '978-99908', '978-99909', + '978-99910', '978-99911', '978-99912', '978-99913', + '978-99914', '978-99915', '978-99916', '978-99917', + '978-99918', '978-99919', '978-99920', '978-99921', + '978-99922', '978-99923', '978-99924', '978-99925', + '978-99926', '978-99927', '978-99928', '978-99929', + '978-99930', '978-99931', '978-99932', '978-99933', + '978-99934', '978-99935', '978-99936', '978-99937', + '978-99938', '978-99939', '978-99940', '978-99941', + '978-99942', '978-99943', '978-99944', '978-99945', + '978-99946', '978-99947', '978-99948', '978-99949', + '978-99950', '978-99951', '978-99952', '978-99953', + '978-99954', '978-99955', '978-99956', '978-99957', + '978-99958', '978-99959', '978-99960', '978-99961', + '978-99962', '978-99963', '978-99964', '978-99965', + '978-99966', '978-99967', '978-99968', '978-99969', + '978-99970', '978-99971', '978-99972', '978-99973', + '978-99974', '978-99975', '978-99976', '978-99977', + '978-99978', '978-99979', '978-99980', '978-99981')) +RDDATE = '20181004' diff -Nru isbnlib-3.5.6/isbnlib/_data/data4mask.py isbnlib-3.9.3/isbnlib/_data/data4mask.py --- isbnlib-3.5.6/isbnlib/_data/data4mask.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_data/data4mask.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,7 +1,4 @@ +# -*- coding: utf-8 -*- # flake8: noqa -# GeneratedWith: mk_data4mask.py (isbntools) -# MessageSource: http://www.isbn-international.org/agency?rmxml=1 -# MessageDate: Wed, 3 Jun 2015 11:50:18 CEST -# MessageSerialNumber: 69eba68e-f50d-4193-9a48-c9f378be91f0 -ranges = {'978-99970': ((0, 4999999, 1), (5000000, 8999999, 2), (9000000, 9999999, 3)), '978-7': ((0, 999999, 2), (1000000, 4999999, 3), (5000000, 7999999, 4), (8000000, 8999999, 5), (9000000, 9999999, 6)), '978-4': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9499999, 6), (9500000, 9999999, 7)), '978-5': ((0, 49999, 5), (50000, 99999, 4), (100000, 1999999, 2), (2000000, 4209999, 3), (4210000, 4299999, 4), (4300000, 4309999, 3), (4310000, 4399999, 4), (4400000, 4409999, 3), (4410000, 4499999, 4), (4500000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9099999, 6), (9100000, 9199999, 5), (9200000, 9299999, 4), (9300000, 9499999, 5), (9500000, 9500999, 7), (9501000, 9799999, 4), (9800000, 9899999, 5), (9900000, 9909999, 7), (9910000, 9999999, 4)), '978-2': ((0, 1999999, 2), (2000000, 3499999, 3), (3500000, 3999999, 5), (4000000, 6999999, 3), (7000000, 8399999, 4), (8400000, 8999999, 5), (9000000, 9499999, 6), (9500000, 9999999, 7)), '978-3': ((0, 299999, 2), (300000, 339999, 3), (340000, 369999, 4), (370000, 399999, 5), (400000, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9499999, 6), (9500000, 9539999, 7), (9540000, 9699999, 5), (9700000, 9899999, 7), (9900000, 9949999, 5), (9950000, 9999999, 5)), '978-0': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9499999, 6), (9500000, 9999999, 7)), '978-1': ((0, 999999, 2), (1000000, 3999999, 3), (4000000, 5499999, 4), (5500000, 8697999, 5), (8698000, 9989999, 6), (9990000, 9999999, 7)), '978-9968': ((0, 4999999, 2), (5000000, 9399999, 3), (9400000, 9999999, 4)), '978-9961': ((0, 2999999, 1), (3000000, 6999999, 2), (7000000, 9499999, 3), (9500000, 9999999, 4)), '978-9960': ((0, 5999999, 2), (6000000, 8999999, 3), (9000000, 9999999, 4)), '978-9963': ((0, 1999999, 1), (2000000, 2499999, 4), (2500000, 2799999, 3), (2800000, 2999999, 4), (3000000, 5499999, 2), (5500000, 7349999, 3), (7350000, 7499999, 4), (7500000, 9999999, 4)), '978-9962': ((0, 5499999, 2), (5500000, 5599999, 4), (5600000, 5999999, 2), (6000000, 8499999, 3), (8500000, 9999999, 4)), '978-9965': ((0, 3999999, 2), (4000000, 8999999, 3), (9000000, 9999999, 4)), '978-9964': ((0, 6999999, 1), (7000000, 9499999, 2), (9500000, 9999999, 3)), '978-9967': ((0, 3999999, 2), (4000000, 8999999, 3), (9000000, 9999999, 4)), '978-9966': ((0, 1499999, 3), (1500000, 1999999, 4), (2000000, 6999999, 2), (7000000, 7499999, 4), (7500000, 9599999, 3), (9600000, 9999999, 4)), '978-967': ((0, 99999, 2), (100000, 999999, 4), (1000000, 1999999, 5), (2000000, 2999999, 0), (3000000, 4999999, 3), (5000000, 5999999, 4), (6000000, 8999999, 2), (9000000, 9899999, 3), (9900000, 9989999, 4), (9990000, 9999999, 5)), '978-966': ((0, 1299999, 2), (1300000, 1399999, 3), (1400000, 1499999, 2), (1500000, 1699999, 4), (1700000, 1999999, 3), (2000000, 2789999, 4), (2790000, 2899999, 3), (2900000, 2999999, 4), (3000000, 6999999, 3), (7000000, 8999999, 4), (9000000, 9099999, 5), (9100000, 9499999, 3), (9500000, 9799999, 5), (9800000, 9999999, 3)), '978-965': ((0, 1999999, 2), (2000000, 5999999, 3), (6000000, 6999999, 0), (7000000, 7999999, 4), (8000000, 8999999, 0), (9000000, 9999999, 5)), '978-964': ((0, 1499999, 2), (1500000, 2499999, 3), (2500000, 2999999, 4), (3000000, 5499999, 3), (5500000, 8999999, 4), (9000000, 9699999, 5), (9700000, 9899999, 3), (9900000, 9999999, 4)), '978-963': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9999999, 4)), '978-962': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8699999, 5), (8700000, 8999999, 4), (9000000, 9999999, 3)), '978-961': ((0, 1999999, 2), (2000000, 5999999, 3), (6000000, 8999999, 4), (9000000, 9499999, 5), (9500000, 9999999, 0)), '978-960': ((0, 1999999, 2), (2000000, 6599999, 3), (6600000, 6899999, 4), (6900000, 6999999, 3), (7000000, 8499999, 4), (8500000, 9299999, 5), (9300000, 9399999, 2), (9400000, 9799999, 4), (9800000, 9999999, 5)), '978-9985': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 8999999, 3), (9000000, 9999999, 4)), '978-969': ((0, 1999999, 1), (2000000, 2299999, 2), (2300000, 2399999, 5), (2400000, 3999999, 2), (4000000, 7499999, 3), (7500000, 9999999, 4)), '978-968': ((100000, 3999999, 2), (4000000, 4999999, 3), (5000000, 7999999, 4), (8000000, 8999999, 3), (9000000, 9999999, 4)), '978-93': ((0, 999999, 2), (1000000, 4999999, 3), (5000000, 7999999, 4), (8000000, 9499999, 5), (9500000, 9999999, 6)), '978-99971': ((0, 5999999, 1), (6000000, 8499999, 2), (8500000, 9999999, 3)), '978-94': ((0, 5999999, 3), (6000000, 8999999, 4), (9000000, 9999999, 5)), '978-99972': ((0, 4999999, 1), (5000000, 8999999, 2), (9000000, 9999999, 3)), '978-99973': ((0, 3999999, 1), (4000000, 7999999, 2), (8000000, 9999999, 3)), '978-99909': ((0, 3999999, 1), (4000000, 9499999, 2), (9500000, 9999999, 3)), '978-99908': ((0, 999999, 1), (1000000, 8999999, 2), (9000000, 9999999, 3)), '978-99905': ((0, 3999999, 1), (4000000, 7999999, 2), (8000000, 9999999, 3)), '978-99904': ((0, 5999999, 1), (6000000, 8999999, 2), (9000000, 9999999, 3)), '978-99906': ((0, 2999999, 1), (3000000, 5999999, 2), (6000000, 6999999, 3), (7000000, 8999999, 2), (9000000, 9499999, 2), (9500000, 9999999, 3)), '978-99901': ((0, 4999999, 2), (5000000, 7999999, 3), (8000000, 9999999, 2)), '978-99903': ((0, 1999999, 1), (2000000, 8999999, 2), (9000000, 9999999, 3)), '978-99902': ((0, 9999999, 0),), '978-99976': ((0, 1999999, 1), (2000000, 5999999, 2), (6000000, 7999999, 3), (8000000, 9999999, 0)), '978-99977': ((0, 1999999, 1), (2000000, 3999999, 0), (4000000, 6999999, 2), (7000000, 7999999, 3), (8000000, 9999999, 0)), '978-974': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9499999, 5), (9500000, 9999999, 4)), '978-975': ((0, 199999, 5), (200000, 2499999, 2), (2500000, 5999999, 3), (6000000, 9199999, 4), (9200000, 9899999, 5), (9900000, 9999999, 3)), '978-976': ((0, 3999999, 1), (4000000, 5999999, 2), (6000000, 7999999, 3), (8000000, 9499999, 4), (9500000, 9999999, 5)), '978-977': ((0, 1999999, 2), (2000000, 4999999, 3), (5000000, 6999999, 4), (7000000, 8499999, 3), (8500000, 8999999, 5), (9000000, 9999999, 2)), '978-970': ((100000, 5999999, 2), (6000000, 8999999, 3), (9000000, 9099999, 4), (9100000, 9699999, 5), (9700000, 9999999, 4)), '978-971': ((0, 159999, 3), (160000, 199999, 4), (200000, 299999, 2), (300000, 599999, 4), (600000, 4999999, 2), (5000000, 8499999, 3), (8500000, 9099999, 4), (9100000, 9599999, 5), (9600000, 9699999, 4), (9700000, 9899999, 2), (9900000, 9999999, 4)), '978-972': ((0, 1999999, 1), (2000000, 5499999, 2), (5500000, 7999999, 3), (8000000, 9499999, 4), (9500000, 9999999, 5)), '978-973': ((0, 999999, 1), (1000000, 1699999, 3), (1700000, 1999999, 4), (2000000, 5499999, 2), (5500000, 7599999, 3), (7600000, 8499999, 4), (8500000, 8899999, 5), (8900000, 9499999, 4), (9500000, 9999999, 5)), '978-978': ((0, 1999999, 3), (2000000, 2999999, 4), (3000000, 7999999, 5), (8000000, 8999999, 4), (9000000, 9999999, 3)), '978-979': ((0, 999999, 3), (1000000, 1499999, 4), (1500000, 1999999, 5), (2000000, 2999999, 2), (3000000, 3999999, 4), (4000000, 7999999, 3), (8000000, 9499999, 4), (9500000, 9999999, 5)), '978-9959': ((0, 1999999, 1), (2000000, 7999999, 2), (8000000, 9499999, 3), (9500000, 9699999, 4), (9700000, 9799999, 3), (9800000, 9999999, 2)), '978-99918': ((0, 3999999, 1), (4000000, 7999999, 2), (8000000, 9999999, 3)), '978-99919': ((0, 2999999, 1), (3000000, 3999999, 3), (4000000, 6999999, 2), (7000000, 7999999, 2), (8000000, 8499999, 3), (8500000, 8999999, 3), (9000000, 9999999, 3)), '978-99916': ((0, 2999999, 1), (3000000, 6999999, 2), (7000000, 9999999, 3)), '978-99917': ((0, 2999999, 1), (3000000, 8999999, 2), (9000000, 9999999, 3)), '978-99914': ((0, 4999999, 1), (5000000, 8999999, 2), (9000000, 9999999, 3)), '978-99915': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99912': ((0, 3999999, 1), (4000000, 5999999, 3), (6000000, 8999999, 2), (9000000, 9999999, 3)), '978-99913': ((0, 2999999, 1), (3000000, 3599999, 2), (3600000, 5999999, 0), (6000000, 6049999, 3), (6050000, 9999999, 0)), '978-99910': ((0, 2999999, 1), (3000000, 8999999, 2), (9000000, 9999999, 3)), '978-99911': ((0, 5999999, 2), (6000000, 9999999, 3)), '978-9928': ((0, 999999, 2), (1000000, 3999999, 3), (4000000, 4999999, 4), (5000000, 9999999, 0)), '978-90': ((0, 1999999, 2), (2000000, 4999999, 3), (5000000, 6999999, 4), (7000000, 7999999, 5), (8000000, 8499999, 6), (8500000, 8999999, 4), (9000000, 9099999, 2), (9100000, 9399999, 0), (9400000, 9499999, 2), (9500000, 9999999, 0)), '978-91': ((0, 1999999, 1), (2000000, 4999999, 2), (5000000, 6499999, 3), (6500000, 6999999, 0), (7000000, 7999999, 4), (8000000, 8499999, 0), (8500000, 9499999, 5), (9500000, 9699999, 0), (9700000, 9999999, 6)), '978-92': ((0, 5999999, 1), (6000000, 7999999, 2), (8000000, 8999999, 3), (9000000, 9499999, 4), (9500000, 9899999, 5), (9900000, 9999999, 6)), '978-9984': ((0, 4999999, 2), (5000000, 8999999, 3), (9000000, 9999999, 4)), '978-9983': ((0, 7999999, 0), (8000000, 9499999, 2), (9500000, 9899999, 3), (9900000, 9999999, 4)), '978-9982': ((0, 7999999, 2), (8000000, 9899999, 3), (9900000, 9999999, 4)), '978-9981': ((0, 999999, 2), (1000000, 1599999, 3), (1600000, 1999999, 4), (2000000, 7999999, 2), (8000000, 9499999, 3), (9500000, 9999999, 4)), '978-9980': ((0, 3999999, 1), (4000000, 8999999, 2), (9000000, 9899999, 3), (9900000, 9999999, 4)), '978-9989': ((0, 999999, 1), (1000000, 1999999, 3), (2000000, 2999999, 4), (3000000, 5999999, 2), (6000000, 9499999, 3), (9500000, 9999999, 4)), '978-9988': ((0, 2999999, 1), (3000000, 5499999, 2), (5500000, 7499999, 3), (7500000, 9999999, 4)), '978-99923': ((0, 1999999, 1), (2000000, 7999999, 2), (8000000, 9999999, 3)), '978-99922': ((0, 3999999, 1), (4000000, 6999999, 2), (7000000, 9999999, 3)), '978-99921': ((0, 1999999, 1), (2000000, 6999999, 2), (7000000, 7999999, 3), (8000000, 8999999, 1), (9000000, 9999999, 2)), '978-99920': ((0, 4999999, 1), (5000000, 8999999, 2), (9000000, 9999999, 3)), '978-99927': ((0, 2999999, 1), (3000000, 5999999, 2), (6000000, 9999999, 3)), '978-99926': ((0, 999999, 1), (1000000, 5999999, 2), (6000000, 8699999, 3), (8700000, 8999999, 2), (9000000, 9999999, 2)), '978-99925': ((0, 3999999, 1), (4000000, 7999999, 2), (8000000, 9999999, 3)), '978-99924': ((0, 1999999, 1), (2000000, 7999999, 2), (8000000, 9999999, 3)), '978-99929': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99928': ((0, 999999, 1), (1000000, 7999999, 2), (8000000, 9999999, 3)), '978-9932': ((0, 3999999, 2), (4000000, 8499999, 3), (8500000, 9999999, 4)), '978-9933': ((0, 999999, 1), (1000000, 3999999, 2), (4000000, 8999999, 3), (9000000, 9999999, 4)), '978-9930': ((0, 4999999, 2), (5000000, 9399999, 3), (9400000, 9999999, 4)), '978-9931': ((0, 2999999, 2), (3000000, 8999999, 3), (9000000, 9999999, 4)), '978-9936': ((0, 1999999, 1), (2000000, 3999999, 2), (4000000, 7999999, 3), (8000000, 9999999, 4)), '978-9937': ((0, 2999999, 1), (3000000, 4999999, 2), (5000000, 7999999, 3), (8000000, 9999999, 4)), '978-9934': ((0, 999999, 1), (1000000, 4999999, 2), (5000000, 7999999, 3), (8000000, 9999999, 4)), '978-9935': ((0, 999999, 1), (1000000, 3999999, 2), (4000000, 8999999, 3), (9000000, 9999999, 4)), '979-12': ((0, 1999999, 0), (2000000, 2009999, 3), (2010000, 9999999, 0)), '979-11': ((0, 2499999, 2), (2500000, 5499999, 3), (5500000, 8499999, 4), (8500000, 9499999, 5), (9500000, 9999999, 6)), '978-9939': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 8999999, 3), (9000000, 9999999, 4)), '978-958': ((0, 5699999, 2), (5700000, 5999999, 5), (6000000, 7999999, 3), (8000000, 9499999, 4), (9500000, 9999999, 5)), '978-959': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 9999999, 5)), '978-956': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 9999999, 4)), '978-957': ((0, 299999, 2), (300000, 499999, 4), (500000, 1999999, 2), (2000000, 2099999, 4), (2100000, 2799999, 2), (2800000, 3099999, 5), (3100000, 4399999, 2), (4400000, 8199999, 3), (8200000, 9699999, 4), (9700000, 9999999, 5)), '978-954': ((0, 2899999, 2), (2900000, 2999999, 4), (3000000, 7999999, 3), (8000000, 8999999, 4), (9000000, 9299999, 5), (9300000, 9999999, 4)), '978-955': ((0, 1999999, 4), (2000000, 4099999, 2), (4100000, 4399999, 5), (4400000, 4499999, 5), (4500000, 4999999, 4), (5000000, 5499999, 5), (5500000, 7499999, 3), (7500000, 7999999, 4), (8000000, 9499999, 4), (9500000, 9999999, 5)), '978-952': ((0, 1999999, 2), (2000000, 4999999, 3), (5000000, 5999999, 4), (6000000, 6599999, 2), (6600000, 6699999, 4), (6700000, 6999999, 5), (7000000, 7999999, 4), (8000000, 9499999, 2), (9500000, 9899999, 4), (9900000, 9999999, 5)), '978-953': ((0, 999999, 1), (1000000, 1499999, 2), (1500000, 5099999, 3), (5100000, 5499999, 2), (5500000, 5999999, 5), (6000000, 9499999, 4), (9500000, 9999999, 5)), '978-950': ((0, 4999999, 2), (5000000, 8999999, 3), (9000000, 9899999, 4), (9900000, 9999999, 5)), '978-951': ((0, 1999999, 1), (2000000, 5499999, 2), (5500000, 8899999, 3), (8900000, 9499999, 4), (9500000, 9999999, 5)), '978-89': ((0, 2499999, 2), (2500000, 5499999, 3), (5500000, 8499999, 4), (8500000, 9499999, 5), (9500000, 9699999, 6), (9700000, 9899999, 5), (9900000, 9999999, 3)), '978-88': ((0, 1999999, 2), (2000000, 5999999, 3), (6000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9099999, 6), (9100000, 9299999, 3), (9300000, 9399999, 4), (9400000, 9499999, 6), (9500000, 9999999, 5)), '978-87': ((0, 2999999, 2), (3000000, 3999999, 0), (4000000, 6499999, 3), (6500000, 6999999, 0), (7000000, 7999999, 4), (8000000, 8499999, 0), (8500000, 9499999, 5), (9500000, 9699999, 0), (9700000, 9999999, 6)), '978-86': ((0, 2999999, 2), (3000000, 5999999, 3), (6000000, 7999999, 4), (8000000, 8999999, 5), (9000000, 9999999, 6)), '978-85': ((0, 1999999, 2), (2000000, 5499999, 3), (5500000, 5999999, 4), (6000000, 6999999, 5), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9599999, 6), (9600000, 9799999, 2), (9800000, 9999999, 5)), '978-84': ((0, 1399999, 2), (1400000, 1499999, 3), (1500000, 1999999, 5), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9199999, 4), (9200000, 9239999, 6), (9240000, 9299999, 5), (9300000, 9499999, 6), (9500000, 9699999, 5), (9700000, 9999999, 4)), '978-83': ((0, 1999999, 2), (2000000, 5999999, 3), (6000000, 6999999, 5), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9999999, 6)), '978-82': ((0, 1999999, 2), (2000000, 6899999, 3), (6900000, 6999999, 6), (7000000, 8999999, 4), (9000000, 9899999, 5), (9900000, 9999999, 6)), '978-81': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9999999, 6)), '978-80': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9999999, 6)), '978-99934': ((0, 1999999, 1), (2000000, 7999999, 2), (8000000, 9999999, 3)), '978-99935': ((0, 2999999, 1), (3000000, 5999999, 2), (6000000, 6999999, 3), (7000000, 8999999, 1), (9000000, 9999999, 2)), '978-99936': ((0, 999999, 1), (1000000, 5999999, 2), (6000000, 9999999, 3)), '978-99937': ((0, 1999999, 1), (2000000, 5999999, 2), (6000000, 9999999, 3)), '978-99930': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99931': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99932': ((0, 999999, 1), (1000000, 5999999, 2), (6000000, 6999999, 3), (7000000, 7999999, 1), (8000000, 9999999, 2)), '978-99933': ((0, 2999999, 1), (3000000, 5999999, 2), (6000000, 9999999, 3)), '978-620': ((0, 9999999, 1),), '978-621': ((0, 2999999, 2), (3000000, 3999999, 0), (4000000, 5999999, 3), (6000000, 7999999, 0), (8000000, 8999999, 4), (9000000, 9499999, 0), (9500000, 9999999, 5)), '978-99938': ((0, 1999999, 1), (2000000, 5999999, 2), (6000000, 8999999, 3), (9000000, 9999999, 2)), '978-99939': ((0, 5999999, 1), (6000000, 8999999, 2), (9000000, 9999999, 3)), '978-9925': ((0, 2999999, 1), (3000000, 5499999, 2), (5500000, 7349999, 3), (7350000, 9999999, 4)), '978-9924': ((0, 2999999, 0), (3000000, 3999999, 2), (4000000, 4999999, 0), (5000000, 6499999, 3), (6500000, 8999999, 0), (9000000, 9999999, 4)), '978-9927': ((0, 999999, 2), (1000000, 3999999, 3), (4000000, 4999999, 4), (5000000, 9999999, 0)), '978-9926': ((0, 1999999, 1), (2000000, 3999999, 2), (4000000, 7999999, 3), (8000000, 9999999, 4)), '978-9929': ((0, 3999999, 1), (4000000, 5499999, 2), (5500000, 7999999, 3), (8000000, 9999999, 4)), '978-9938': ((0, 7999999, 2), (8000000, 9499999, 3), (9500000, 9999999, 4)), '979-10': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8999999, 4), (9000000, 9759999, 5), (9760000, 9999999, 6)), '978-9987': ((0, 3999999, 2), (4000000, 8799999, 3), (8800000, 9999999, 4)), '978-99941': ((0, 2999999, 1), (3000000, 7999999, 2), (8000000, 9999999, 3)), '978-99940': ((0, 999999, 1), (1000000, 6999999, 2), (7000000, 9999999, 3)), '978-99943': ((0, 2999999, 1), (3000000, 5999999, 2), (6000000, 9999999, 3)), '978-99942': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99945': ((0, 5999999, 1), (6000000, 8999999, 2), (9000000, 9999999, 3)), '978-99944': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99947': ((0, 2999999, 1), (3000000, 6999999, 2), (7000000, 9999999, 3)), '978-99946': ((0, 2999999, 1), (3000000, 5999999, 2), (6000000, 9999999, 3)), '978-99949': ((0, 1999999, 1), (2000000, 8999999, 2), (9000000, 9999999, 3)), '978-99948': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-9950': ((0, 2999999, 2), (3000000, 8499999, 3), (8500000, 9999999, 4)), '978-9951': ((0, 3999999, 2), (4000000, 8499999, 3), (8500000, 9999999, 4)), '978-9952': ((0, 1999999, 1), (2000000, 3999999, 2), (4000000, 7999999, 3), (8000000, 9999999, 4)), '978-9953': ((0, 999999, 1), (1000000, 3999999, 2), (4000000, 5999999, 3), (6000000, 8999999, 2), (9000000, 9999999, 4)), '978-9954': ((0, 1999999, 1), (2000000, 3999999, 2), (4000000, 7999999, 3), (8000000, 9999999, 4)), '978-9955': ((0, 3999999, 2), (4000000, 9299999, 3), (9300000, 9999999, 4)), '978-9956': ((0, 999999, 1), (1000000, 3999999, 2), (4000000, 8999999, 3), (9000000, 9999999, 4)), '978-9957': ((0, 3999999, 2), (4000000, 6999999, 3), (7000000, 8499999, 2), (8500000, 8799999, 4), (8800000, 9999999, 2)), '978-9958': ((0, 199999, 2), (200000, 299999, 3), (300000, 399999, 4), (400000, 899999, 3), (900000, 999999, 4), (1000000, 1899999, 2), (1900000, 1999999, 4), (2000000, 4999999, 2), (5000000, 8999999, 3), (9000000, 9999999, 4)), '978-9986': ((0, 3999999, 2), (4000000, 8999999, 3), (9000000, 9399999, 4), (9400000, 9699999, 3), (9700000, 9999999, 2)), '978-989': ((0, 1999999, 1), (2000000, 5499999, 2), (5500000, 7999999, 3), (8000000, 9499999, 4), (9500000, 9999999, 5)), '978-988': ((0, 1199999, 2), (1200000, 1499999, 5), (1500000, 1699999, 5), (1700000, 1999999, 5), (2000000, 7999999, 3), (8000000, 9699999, 4), (9700000, 9999999, 5)), '978-985': ((0, 3999999, 2), (4000000, 5999999, 3), (6000000, 8999999, 4), (9000000, 9999999, 5)), '978-984': ((0, 3999999, 2), (4000000, 7999999, 3), (8000000, 8999999, 4), (9000000, 9999999, 5)), '978-987': ((0, 999999, 2), (1000000, 1999999, 4), (2000000, 2999999, 5), (3000000, 3599999, 2), (3600000, 3999999, 4), (4000000, 4199999, 4), (4200000, 4399999, 2), (4400000, 4499999, 4), (4500000, 4899999, 5), (4900000, 4999999, 4), (5000000, 8999999, 3), (9000000, 9499999, 4), (9500000, 9999999, 5)), '978-986': ((0, 1199999, 2), (1200000, 5599999, 3), (5600000, 7999999, 4), (8000000, 9999999, 5)), '978-981': ((0, 1199999, 2), (1200000, 1699999, 2), (1700000, 1999999, 5), (2000000, 2899999, 3), (2900000, 2999999, 3), (3000000, 3099999, 4), (3100000, 3999999, 3), (4000000, 9999999, 4)), '978-980': ((0, 1999999, 2), (2000000, 5999999, 3), (6000000, 9999999, 4)), '978-983': ((0, 199999, 2), (200000, 1999999, 3), (2000000, 3999999, 4), (4000000, 4499999, 5), (4500000, 4999999, 2), (5000000, 7999999, 2), (8000000, 8999999, 3), (9000000, 9899999, 4), (9900000, 9999999, 5)), '978-982': ((0, 999999, 2), (1000000, 6999999, 3), (7000000, 8999999, 2), (9000000, 9799999, 4), (9800000, 9999999, 5)), '978-99952': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99953': ((0, 2999999, 1), (3000000, 7999999, 2), (8000000, 9399999, 3), (9400000, 9999999, 2)), '978-99950': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99951': ((0, 9999999, 0),), '978-99956': ((0, 5999999, 2), (6000000, 8599999, 3), (8600000, 9999999, 2)), '978-99957': ((0, 1999999, 1), (2000000, 7999999, 2), (8000000, 9999999, 3)), '978-99954': ((0, 2999999, 1), (3000000, 6999999, 2), (7000000, 8799999, 3), (8800000, 9999999, 2)), '978-99955': ((0, 1999999, 1), (2000000, 5999999, 2), (6000000, 7999999, 3), (8000000, 9999999, 2)), '978-99958': ((0, 4999999, 1), (5000000, 9399999, 2), (9400000, 9499999, 3), (9500000, 9999999, 3)), '978-99959': ((0, 2999999, 1), (3000000, 5999999, 2), (6000000, 9999999, 3)), '978-9943': ((0, 2999999, 2), (3000000, 3999999, 3), (4000000, 9749999, 4), (9750000, 9999999, 3)), '978-9942': ((0, 8499999, 2), (8500000, 8999999, 4), (9000000, 9849999, 3), (9850000, 9999999, 4)), '978-9941': ((0, 999999, 1), (1000000, 3999999, 2), (4000000, 8999999, 3), (9000000, 9999999, 4)), '978-9940': ((0, 1999999, 1), (2000000, 4999999, 2), (5000000, 8999999, 3), (9000000, 9999999, 4)), '978-9947': ((0, 1999999, 1), (2000000, 7999999, 2), (8000000, 9999999, 3)), '978-9946': ((0, 1999999, 1), (2000000, 3999999, 2), (4000000, 8999999, 3), (9000000, 9999999, 4)), '978-9945': ((0, 99999, 2), (100000, 799999, 3), (800000, 3999999, 2), (4000000, 5699999, 3), (5700000, 5799999, 2), (5800000, 8499999, 3), (8500000, 9999999, 4)), '978-9944': ((0, 999999, 4), (1000000, 4999999, 3), (5000000, 5999999, 4), (6000000, 6999999, 2), (7000000, 7999999, 3), (8000000, 8999999, 2), (9000000, 9999999, 3)), '978-9949': ((0, 999999, 1), (1000000, 3999999, 2), (4000000, 7499999, 3), (7500000, 8999999, 2), (9000000, 9999999, 4)), '978-9948': ((0, 3999999, 2), (4000000, 8499999, 3), (8500000, 9999999, 4)), '978-615': ((0, 999999, 2), (1000000, 4999999, 3), (5000000, 7999999, 4), (8000000, 8999999, 5), (9000000, 9999999, 0)), '978-614': ((0, 3999999, 2), (4000000, 7999999, 3), (8000000, 9499999, 4), (9500000, 9999999, 5)), '978-617': ((0, 4999999, 2), (5000000, 6999999, 3), (7000000, 8999999, 4), (9000000, 9999999, 5)), '978-616': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8999999, 4), (9000000, 9999999, 5)), '978-611': ((0, 9999999, 0),), '978-613': ((0, 9999999, 1),), '978-612': ((0, 2999999, 2), (3000000, 3999999, 3), (4000000, 4499999, 4), (4500000, 4999999, 5), (5000000, 9999999, 2)), '978-619': ((0, 1499999, 2), (1500000, 6999999, 3), (7000000, 8999999, 4), (9000000, 9999999, 5)), '978-618': ((0, 1999999, 2), (2000000, 4999999, 3), (5000000, 7999999, 4), (8000000, 9999999, 5)), '978-99974': ((0, 3999999, 0), (4000000, 7999999, 2), (8000000, 9999999, 3)), '978-99967': ((0, 1999999, 1), (2000000, 5999999, 2), (6000000, 8999999, 3), (9000000, 9999999, 0)), '978-99966': ((0, 2999999, 1), (3000000, 6999999, 2), (7000000, 7999999, 3), (8000000, 9499999, 2), (9500000, 9999999, 0)), '978-99965': ((0, 3999999, 1), (4000000, 6999999, 2), (7000000, 9999999, 3)), '978-99964': ((0, 1999999, 1), (2000000, 7999999, 2), (8000000, 9999999, 3)), '978-99963': ((0, 4999999, 2), (5000000, 9199999, 3), (9200000, 9999999, 2)), '978-99962': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99961': ((0, 3999999, 1), (4000000, 8999999, 2), (9000000, 9999999, 3)), '978-99960': ((0, 999999, 1), (1000000, 9499999, 2), (9500000, 9999999, 3)), '978-99969': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99968': ((0, 3999999, 1), (4000000, 5999999, 3), (6000000, 8999999, 2), (9000000, 9999999, 3)), '978-9976': ((0, 5999999, 1), (6000000, 8999999, 2), (9000000, 9899999, 3), (9900000, 9999999, 4)), '978-9977': ((0, 8999999, 2), (9000000, 9899999, 3), (9900000, 9999999, 4)), '978-9974': ((0, 2999999, 1), (3000000, 5499999, 2), (5500000, 7499999, 3), (7500000, 9499999, 4), (9500000, 9999999, 2)), '978-9975': ((0, 999999, 1), (1000000, 2999999, 3), (3000000, 3999999, 4), (4000000, 4499999, 4), (4500000, 8999999, 2), (9000000, 9499999, 3), (9500000, 9999999, 4)), '978-9972': ((0, 999999, 2), (1000000, 1999999, 1), (2000000, 2499999, 3), (2500000, 2999999, 4), (3000000, 5999999, 2), (6000000, 8999999, 3), (9000000, 9999999, 4)), '978-9973': ((0, 599999, 2), (600000, 899999, 3), (900000, 999999, 4), (1000000, 6999999, 2), (7000000, 9699999, 3), (9700000, 9999999, 4)), '978-9970': ((0, 3999999, 2), (4000000, 8999999, 3), (9000000, 9999999, 4)), '978-9971': ((0, 5999999, 1), (6000000, 8999999, 2), (9000000, 9899999, 3), (9900000, 9999999, 4)), '978-99975': ((0, 3999999, 1), (4000000, 7999999, 2), (8000000, 9999999, 3)), '978-9978': ((0, 2999999, 2), (3000000, 3999999, 3), (4000000, 9499999, 2), (9500000, 9899999, 3), (9900000, 9999999, 4)), '978-9979': ((0, 4999999, 1), (5000000, 6499999, 2), (6500000, 6599999, 3), (6600000, 7599999, 2), (7600000, 8999999, 3), (9000000, 9999999, 4)), '978-602': ((0, 799999, 2), (800000, 899999, 4), (900000, 1099999, 4), (1100000, 1199999, 4), (1200000, 1399999, 4), (1400000, 1499999, 5), (1500000, 1699999, 4), (1700000, 1799999, 5), (1800000, 1899999, 5), (1900000, 1999999, 5), (2000000, 6999999, 3), (7000000, 7499999, 5), (7500000, 7999999, 4), (8000000, 9499999, 4), (9500000, 9999999, 5)), '978-603': ((0, 499999, 2), (500000, 4999999, 2), (5000000, 7999999, 3), (8000000, 8999999, 4), (9000000, 9999999, 5)), '978-600': ((0, 999999, 2), (1000000, 4999999, 3), (5000000, 8999999, 4), (9000000, 9999999, 5)), '978-601': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 7999999, 4), (8000000, 8499999, 5), (8500000, 9999999, 2)), '978-606': ((0, 999999, 1), (1000000, 4999999, 2), (5000000, 7999999, 3), (8000000, 9199999, 4), (9200000, 9999999, 5)), '978-607': ((0, 3999999, 2), (4000000, 7499999, 3), (7500000, 9499999, 4), (9500000, 9999999, 5)), '978-604': ((0, 4999999, 1), (5000000, 8999999, 2), (9000000, 9799999, 3), (9800000, 9999999, 4)), '978-605': ((0, 99999, 0), (100000, 299999, 2), (300000, 399999, 3), (400000, 999999, 2), (1000000, 3999999, 3), (4000000, 5999999, 4), (6000000, 8999999, 5), (9000000, 9999999, 4)), '978-608': ((0, 999999, 1), (1000000, 1999999, 2), (2000000, 4499999, 3), (4500000, 6499999, 4), (6500000, 6999999, 5), (7000000, 9999999, 1)), '978-609': ((0, 3999999, 2), (4000000, 7999999, 3), (8000000, 9499999, 4), (9500000, 9999999, 5))} -RDDATE='2015060310:50:18WEST' +ranges = {'978-0': ((0, 1999999, 2), (2000000, 2279999, 3), (2280000, 2289999, 4), (2290000, 3689999, 3), (3690000, 3699999, 4), (3700000, 6389999, 3), (6390000, 6398999, 4), (6399000, 6399999, 7), (6400000, 6479999, 3), (6480000, 6489999, 7), (6490000, 6549999, 3), (6550000, 6559999, 4), (6560000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9499999, 6), (9500000, 9999999, 7)), '978-1': ((0, 999999, 2), (1000000, 3999999, 3), (4000000, 5499999, 4), (5500000, 7169999, 5), (7170000, 7319999, 4), (7320000, 7399999, 7), (7400000, 7749999, 5), (7750000, 7753999, 7), (7754000, 7899999, 5), (7900000, 7999999, 4), (8000000, 8697999, 5), (8698000, 9163999, 6), (9164000, 9165059, 7), (9165060, 9729999, 6), (9730000, 9877999, 4), (9878000, 9989999, 6), (9990000, 9999999, 7)), '978-2': ((0, 1999999, 2), (2000000, 3499999, 3), (3500000, 3999999, 5), (4000000, 4899999, 3), (4900000, 4949999, 6), (4950000, 6999999, 3), (7000000, 8399999, 4), (8400000, 8999999, 5), (9000000, 9197999, 6), (9198000, 9198099, 5), (9198100, 9199429, 6), (9199430, 9199689, 7), (9199690, 9499999, 6), (9500000, 9999999, 7)), '978-3': ((0, 299999, 2), (300000, 339999, 3), (340000, 369999, 4), (370000, 399999, 5), (400000, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9499999, 6), (9500000, 9539999, 7), (9540000, 9699999, 5), (9700000, 9899999, 7), (9900000, 9949999, 5), (9950000, 9999999, 5)), '978-4': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9499999, 6), (9500000, 9999999, 7)), '978-5': ((0, 49999, 5), (50000, 99999, 4), (100000, 1999999, 2), (2000000, 4209999, 3), (4210000, 4299999, 4), (4300000, 4309999, 3), (4310000, 4399999, 4), (4400000, 4409999, 3), (4410000, 4499999, 4), (4500000, 6039999, 3), (6040000, 6049999, 7), (6050000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9099999, 6), (9100000, 9199999, 5), (9200000, 9299999, 4), (9300000, 9499999, 5), (9500000, 9500999, 7), (9501000, 9799999, 4), (9800000, 9899999, 5), (9900000, 9909999, 7), (9910000, 9999999, 4)), '978-600': ((0, 999999, 2), (1000000, 4999999, 3), (5000000, 8999999, 4), (9000000, 9867999, 5), (9868000, 9929999, 4), (9930000, 9959999, 3), (9960000, 9999999, 5)), '978-601': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 7999999, 4), (8000000, 8499999, 5), (8500000, 9999999, 2)), '978-602': ((0, 699999, 2), (700000, 1399999, 4), (1400000, 1499999, 5), (1500000, 1699999, 4), (1700000, 1999999, 5), (2000000, 4999999, 3), (5000000, 5399999, 5), (5400000, 5999999, 4), (6000000, 6199999, 5), (6200000, 6999999, 4), (7000000, 7499999, 5), (7500000, 9499999, 4), (9500000, 9999999, 5)), '978-603': ((0, 499999, 2), (500000, 4999999, 2), (5000000, 7999999, 3), (8000000, 8999999, 4), (9000000, 9999999, 5)), '978-604': ((0, 4999999, 1), (5000000, 8999999, 2), (9000000, 9799999, 3), (9800000, 9999999, 4)), '978-605': ((0, 99999, 0), (100000, 299999, 2), (300000, 399999, 3), (400000, 999999, 2), (1000000, 1999999, 3), (2000000, 2399999, 4), (2400000, 3999999, 3), (4000000, 5999999, 4), (6000000, 7499999, 5), (7500000, 7999999, 4), (8000000, 8999999, 5), (9000000, 9999999, 4)), '978-606': ((0, 999999, 3), (1000000, 4999999, 2), (5000000, 7999999, 3), (8000000, 9099999, 4), (9100000, 9199999, 3), (9200000, 9749999, 5), (9750000, 9999999, 3)), '978-607': ((0, 3999999, 2), (4000000, 7499999, 3), (7500000, 9499999, 4), (9500000, 9999999, 5)), '978-608': ((0, 999999, 1), (1000000, 1999999, 2), (2000000, 4499999, 3), (4500000, 6499999, 4), (6500000, 6999999, 5), (7000000, 9999999, 1)), '978-609': ((0, 3999999, 2), (4000000, 7999999, 3), (8000000, 9499999, 4), (9500000, 9999999, 5)), '978-611': ((0, 9999999, 0),), '978-612': ((0, 2999999, 2), (3000000, 3999999, 3), (4000000, 4499999, 4), (4500000, 4999999, 5), (5000000, 9999999, 2)), '978-613': ((0, 9999999, 1),), '978-614': ((0, 3999999, 2), (4000000, 7999999, 3), (8000000, 9499999, 4), (9500000, 9999999, 5)), '978-615': ((0, 999999, 2), (1000000, 4999999, 3), (5000000, 7999999, 4), (8000000, 8999999, 5), (9000000, 9999999, 0)), '978-616': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8999999, 4), (9000000, 9999999, 5)), '978-617': ((0, 4999999, 2), (5000000, 6999999, 3), (7000000, 8999999, 4), (9000000, 9999999, 5)), '978-618': ((0, 1999999, 2), (2000000, 4999999, 3), (5000000, 7999999, 4), (8000000, 9999999, 5)), '978-619': ((0, 1499999, 2), (1500000, 6999999, 3), (7000000, 8999999, 4), (9000000, 9999999, 5)), '978-620': ((0, 9999999, 1),), '978-621': ((0, 2999999, 2), (3000000, 3999999, 0), (4000000, 5999999, 3), (6000000, 7999999, 0), (8000000, 8999999, 4), (9000000, 9499999, 0), (9500000, 9999999, 5)), '978-622': ((0, 399999, 2), (400000, 1999999, 0), (2000000, 2199999, 3), (2200000, 5999999, 0), (6000000, 6399999, 4), (6400000, 9899999, 0), (9900000, 9999999, 5)), '978-623': ((0, 999999, 2), (1000000, 1999999, 0), (2000000, 2999999, 3), (3000000, 6999999, 0), (7000000, 7999999, 4), (8000000, 9999999, 0)), '978-65': ((0, 4999999, 0), (5000000, 5004999, 4), (5005000, 7999999, 0), (8000000, 8019999, 5), (8020000, 8999999, 0), (9000000, 9000999, 6), (9001000, 9999999, 0)), '978-7': ((0, 999999, 2), (1000000, 4999999, 3), (5000000, 7999999, 4), (8000000, 8999999, 5), (9000000, 9999999, 6)), '978-80': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9989999, 6), (9990000, 9999999, 5)), '978-81': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9999999, 6)), '978-82': ((0, 1999999, 2), (2000000, 6899999, 3), (6900000, 6999999, 6), (7000000, 8999999, 4), (9000000, 9899999, 5), (9900000, 9999999, 6)), '978-83': ((0, 1999999, 2), (2000000, 5999999, 3), (6000000, 6999999, 5), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9999999, 6)), '978-84': ((0, 1199999, 2), (1200000, 1299999, 6), (1300000, 1399999, 4), (1400000, 1499999, 3), (1500000, 1999999, 5), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9199999, 4), (9200000, 9239999, 6), (9240000, 9299999, 5), (9300000, 9499999, 6), (9500000, 9699999, 5), (9700000, 9999999, 4)), '978-85': ((0, 1999999, 2), (2000000, 4549999, 3), (4550000, 4552999, 6), (4553000, 4559999, 5), (4560000, 5289999, 3), (5290000, 5319999, 5), (5320000, 5339999, 4), (5340000, 5399999, 3), (5400000, 5402999, 5), (5403000, 5403999, 5), (5404000, 5404999, 6), (5405000, 5408999, 5), (5409000, 5409999, 6), (5410000, 5439999, 5), (5440000, 5479999, 4), (5480000, 5499999, 5), (5500000, 5999999, 4), (6000000, 6999999, 5), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9249999, 6), (9250000, 9449999, 5), (9450000, 9599999, 4), (9600000, 9799999, 2), (9800000, 9999999, 5)), '978-86': ((0, 2999999, 2), (3000000, 5999999, 3), (6000000, 7999999, 4), (8000000, 8999999, 5), (9000000, 9999999, 6)), '978-87': ((0, 2999999, 2), (3000000, 3999999, 0), (4000000, 6499999, 3), (6500000, 6999999, 0), (7000000, 7999999, 4), (8000000, 8499999, 0), (8500000, 9499999, 5), (9500000, 9699999, 0), (9700000, 9999999, 6)), '978-88': ((0, 1999999, 2), (2000000, 3189999, 3), (3190000, 3229999, 5), (3230000, 3269999, 3), (3270000, 3389999, 4), (3390000, 5489999, 3), (5490000, 5549999, 4), (5550000, 5999999, 3), (6000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9099999, 6), (9100000, 9299999, 3), (9300000, 9399999, 4), (9400000, 9479999, 6), (9480000, 9499999, 5), (9500000, 9999999, 5)), '978-89': ((0, 2499999, 2), (2500000, 5499999, 3), (5500000, 8499999, 4), (8500000, 9499999, 5), (9500000, 9699999, 6), (9700000, 9899999, 5), (9900000, 9999999, 3)), '978-90': ((0, 1999999, 2), (2000000, 4999999, 3), (5000000, 6999999, 4), (7000000, 7999999, 5), (8000000, 8499999, 6), (8500000, 8999999, 4), (9000000, 9099999, 2), (9100000, 9399999, 0), (9400000, 9499999, 2), (9500000, 9999999, 0)), '978-91': ((0, 1999999, 1), (2000000, 4999999, 2), (5000000, 6499999, 3), (6500000, 6999999, 0), (7000000, 7999999, 4), (8000000, 8499999, 0), (8500000, 9499999, 5), (9500000, 9699999, 0), (9700000, 9999999, 6)), '978-92': ((0, 5999999, 1), (6000000, 7999999, 2), (8000000, 8999999, 3), (9000000, 9499999, 4), (9500000, 9899999, 5), (9900000, 9999999, 6)), '978-93': ((0, 999999, 2), (1000000, 4999999, 3), (5000000, 7999999, 4), (8000000, 9499999, 5), (9500000, 9999999, 6)), '978-94': ((0, 5999999, 3), (6000000, 8999999, 4), (9000000, 9999999, 5)), '978-950': ((0, 4999999, 2), (5000000, 8999999, 3), (9000000, 9899999, 4), (9900000, 9999999, 5)), '978-951': ((0, 1999999, 1), (2000000, 5499999, 2), (5500000, 8899999, 3), (8900000, 9499999, 4), (9500000, 9999999, 5)), '978-952': ((0, 1999999, 2), (2000000, 4999999, 3), (5000000, 5999999, 4), (6000000, 6599999, 2), (6600000, 6699999, 4), (6700000, 6999999, 5), (7000000, 7999999, 4), (8000000, 9499999, 2), (9500000, 9899999, 4), (9900000, 9999999, 5)), '978-953': ((0, 999999, 1), (1000000, 1499999, 2), (1500000, 4799999, 3), (4800000, 4999999, 5), (5000000, 5009999, 3), (5010000, 5099999, 5), (5100000, 5499999, 2), (5500000, 5999999, 5), (6000000, 9499999, 4), (9500000, 9999999, 5)), '978-954': ((0, 2899999, 2), (2900000, 2999999, 4), (3000000, 7999999, 3), (8000000, 8999999, 4), (9000000, 9299999, 5), (9300000, 9999999, 4)), '978-955': ((0, 1999999, 4), (2000000, 3399999, 2), (3400000, 3499999, 4), (3500000, 3549999, 4), (3550000, 3599999, 5), (3600000, 3799999, 4), (3800000, 3899999, 5), (3900000, 4099999, 4), (4100000, 4499999, 5), (4500000, 4999999, 4), (5000000, 5499999, 5), (5500000, 7129999, 3), (7130000, 7149999, 5), (7150000, 9499999, 4), (9500000, 9999999, 5)), '978-956': ((0, 899999, 2), (900000, 999999, 5), (1000000, 1999999, 2), (2000000, 5999999, 3), (6000000, 6999999, 4), (7000000, 9999999, 4)), '978-957': ((0, 299999, 2), (300000, 499999, 4), (500000, 1999999, 2), (2000000, 2099999, 4), (2100000, 2799999, 2), (2800000, 3099999, 5), (3100000, 4399999, 2), (4400000, 8199999, 3), (8200000, 9699999, 4), (9700000, 9999999, 5)), '978-958': ((0, 5399999, 2), (5400000, 5599999, 4), (5600000, 5699999, 5), (5700000, 5999999, 5), (6000000, 7999999, 3), (8000000, 9499999, 4), (9500000, 9999999, 5)), '978-959': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 9999999, 5)), '978-960': ((0, 1999999, 2), (2000000, 6599999, 3), (6600000, 6899999, 4), (6900000, 6999999, 3), (7000000, 8499999, 4), (8500000, 9299999, 5), (9300000, 9399999, 2), (9400000, 9799999, 4), (9800000, 9999999, 5)), '978-961': ((0, 1999999, 2), (2000000, 5999999, 3), (6000000, 8999999, 4), (9000000, 9499999, 5), (9500000, 9999999, 0)), '978-962': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8699999, 5), (8700000, 8999999, 4), (9000000, 9999999, 3)), '978-963': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9999999, 4)), '978-964': ((0, 1499999, 2), (1500000, 2499999, 3), (2500000, 2999999, 4), (3000000, 5499999, 3), (5500000, 8999999, 4), (9000000, 9699999, 5), (9700000, 9899999, 3), (9900000, 9999999, 4)), '978-965': ((0, 1999999, 2), (2000000, 5999999, 3), (6000000, 6999999, 0), (7000000, 7999999, 4), (8000000, 8999999, 0), (9000000, 9999999, 5)), '978-966': ((0, 1299999, 2), (1300000, 1399999, 3), (1400000, 1499999, 2), (1500000, 1699999, 4), (1700000, 1999999, 3), (2000000, 2789999, 4), (2790000, 2899999, 3), (2900000, 2999999, 4), (3000000, 6999999, 3), (7000000, 8999999, 4), (9000000, 9099999, 5), (9100000, 9499999, 3), (9500000, 9799999, 5), (9800000, 9999999, 3)), '978-967': ((0, 99999, 2), (100000, 999999, 4), (1000000, 1999999, 5), (2000000, 2499999, 4), (2500000, 2999999, 0), (3000000, 4999999, 3), (5000000, 5999999, 4), (6000000, 8999999, 2), (9000000, 9899999, 3), (9900000, 9989999, 4), (9990000, 9999999, 5)), '978-968': ((100000, 3999999, 2), (4000000, 4999999, 3), (5000000, 7999999, 4), (8000000, 8999999, 3), (9000000, 9999999, 4)), '978-969': ((0, 1999999, 1), (2000000, 2299999, 2), (2300000, 2399999, 5), (2400000, 3999999, 2), (4000000, 7499999, 3), (7500000, 9999999, 4)), '978-970': ((100000, 5999999, 2), (6000000, 8999999, 3), (9000000, 9099999, 4), (9100000, 9699999, 5), (9700000, 9999999, 4)), '978-971': ((0, 159999, 3), (160000, 199999, 4), (200000, 299999, 2), (300000, 599999, 4), (600000, 4999999, 2), (5000000, 8499999, 3), (8500000, 9099999, 4), (9100000, 9599999, 5), (9600000, 9699999, 4), (9700000, 9899999, 2), (9900000, 9999999, 4)), '978-972': ((0, 1999999, 1), (2000000, 5499999, 2), (5500000, 7999999, 3), (8000000, 9499999, 4), (9500000, 9999999, 5)), '978-973': ((0, 999999, 1), (1000000, 1699999, 3), (1700000, 1999999, 4), (2000000, 5499999, 2), (5500000, 7599999, 3), (7600000, 8499999, 4), (8500000, 8899999, 5), (8900000, 9499999, 4), (9500000, 9999999, 5)), '978-974': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8499999, 4), (8500000, 8999999, 5), (9000000, 9499999, 5), (9500000, 9999999, 4)), '978-975': ((0, 199999, 5), (200000, 2399999, 2), (2400000, 2499999, 4), (2500000, 5999999, 3), (6000000, 9199999, 4), (9200000, 9899999, 5), (9900000, 9999999, 3)), '978-976': ((0, 3999999, 1), (4000000, 5999999, 2), (6000000, 7999999, 3), (8000000, 9499999, 4), (9500000, 9999999, 5)), '978-977': ((0, 1999999, 2), (2000000, 4999999, 3), (5000000, 6999999, 4), (7000000, 8499999, 3), (8500000, 8999999, 5), (9000000, 9899999, 2), (9900000, 9999999, 3)), '978-978': ((0, 1999999, 3), (2000000, 2999999, 4), (3000000, 7999999, 5), (8000000, 8999999, 4), (9000000, 9999999, 3)), '978-979': ((0, 999999, 3), (1000000, 1499999, 4), (1500000, 1999999, 5), (2000000, 2999999, 2), (3000000, 3999999, 4), (4000000, 7999999, 3), (8000000, 9499999, 4), (9500000, 9999999, 5)), '978-980': ((0, 1999999, 2), (2000000, 5999999, 3), (6000000, 9999999, 4)), '978-981': ((0, 1699999, 2), (1700000, 1999999, 5), (2000000, 2999999, 3), (3000000, 3099999, 4), (3100000, 3999999, 3), (4000000, 9999999, 4)), '978-982': ((0, 999999, 2), (1000000, 6999999, 3), (7000000, 8999999, 2), (9000000, 9799999, 4), (9800000, 9999999, 5)), '978-983': ((0, 199999, 2), (200000, 1999999, 3), (2000000, 3999999, 4), (4000000, 4499999, 5), (4500000, 4999999, 2), (5000000, 7999999, 2), (8000000, 8999999, 3), (9000000, 9899999, 4), (9900000, 9999999, 5)), '978-984': ((0, 3999999, 2), (4000000, 7999999, 3), (8000000, 8999999, 4), (9000000, 9999999, 5)), '978-985': ((0, 3999999, 2), (4000000, 5999999, 3), (6000000, 8799999, 4), (8800000, 8999999, 3), (9000000, 9999999, 5)), '978-986': ((0, 1199999, 2), (1200000, 5599999, 3), (5600000, 7999999, 4), (8000000, 9999999, 5)), '978-987': ((0, 999999, 2), (1000000, 1999999, 4), (2000000, 2999999, 5), (3000000, 3599999, 2), (3600000, 3999999, 4), (4000000, 4199999, 4), (4200000, 4399999, 2), (4400000, 4499999, 4), (4500000, 4899999, 5), (4900000, 4999999, 4), (5000000, 8999999, 3), (9000000, 9499999, 4), (9500000, 9999999, 5)), '978-988': ((0, 1199999, 2), (1200000, 1499999, 5), (1500000, 1699999, 5), (1700000, 1999999, 5), (2000000, 7699999, 3), (7700000, 7999999, 5), (8000000, 9699999, 4), (9700000, 9999999, 5)), '978-989': ((0, 1999999, 1), (2000000, 5399999, 2), (5400000, 5499999, 5), (5500000, 7999999, 3), (8000000, 9499999, 4), (9500000, 9999999, 5)), '978-9920': ((0, 3499999, 0), (3500000, 3999999, 2), (4000000, 6999999, 0), (7000000, 7999999, 3), (8000000, 9499999, 0), (9500000, 9999999, 4)), '978-9921': ((0, 999999, 1), (1000000, 2999999, 0), (3000000, 3999999, 2), (4000000, 6999999, 0), (7000000, 8999999, 3), (9000000, 9699999, 0), (9700000, 9999999, 4)), '978-9922': ((0, 1999999, 0), (2000000, 2999999, 2), (3000000, 5999999, 0), (6000000, 7999999, 3), (8000000, 8999999, 0), (9000000, 9999999, 4)), '978-9923': ((0, 999999, 1), (1000000, 4999999, 2), (5000000, 6999999, 0), (7000000, 8999999, 3), (9000000, 9699999, 0), (9700000, 9999999, 4)), '978-9924': ((0, 2999999, 0), (3000000, 3999999, 2), (4000000, 4999999, 0), (5000000, 6499999, 3), (6500000, 8999999, 0), (9000000, 9999999, 4)), '978-9925': ((0, 2999999, 1), (3000000, 5499999, 2), (5500000, 7349999, 3), (7350000, 9999999, 4)), '978-9926': ((0, 1999999, 1), (2000000, 3999999, 2), (4000000, 7999999, 3), (8000000, 9999999, 4)), '978-9927': ((0, 999999, 2), (1000000, 3999999, 3), (4000000, 4999999, 4), (5000000, 9999999, 0)), '978-9928': ((0, 999999, 2), (1000000, 3999999, 3), (4000000, 4999999, 4), (5000000, 9999999, 0)), '978-9929': ((0, 3999999, 1), (4000000, 5499999, 2), (5500000, 7999999, 3), (8000000, 9999999, 4)), '978-9930': ((0, 4999999, 2), (5000000, 9399999, 3), (9400000, 9999999, 4)), '978-9931': ((0, 2999999, 2), (3000000, 8999999, 3), (9000000, 9999999, 4)), '978-9932': ((0, 3999999, 2), (4000000, 8499999, 3), (8500000, 9999999, 4)), '978-9933': ((0, 999999, 1), (1000000, 3999999, 2), (4000000, 8999999, 3), (9000000, 9999999, 4)), '978-9934': ((0, 999999, 1), (1000000, 4999999, 2), (5000000, 7999999, 3), (8000000, 9999999, 4)), '978-9935': ((0, 999999, 1), (1000000, 3999999, 2), (4000000, 8999999, 3), (9000000, 9999999, 4)), '978-9936': ((0, 1999999, 1), (2000000, 3999999, 2), (4000000, 7999999, 3), (8000000, 9999999, 4)), '978-9937': ((0, 2999999, 1), (3000000, 4999999, 2), (5000000, 7999999, 3), (8000000, 9999999, 4)), '978-9938': ((0, 7999999, 2), (8000000, 9499999, 3), (9500000, 9999999, 4)), '978-9939': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 8999999, 3), (9000000, 9999999, 4)), '978-9940': ((0, 1999999, 1), (2000000, 4999999, 2), (5000000, 8999999, 3), (9000000, 9999999, 4)), '978-9941': ((0, 999999, 1), (1000000, 3999999, 2), (4000000, 7999999, 3), (8000000, 8999999, 1), (9000000, 9999999, 4)), '978-9942': ((0, 7499999, 2), (7500000, 8499999, 3), (8500000, 8999999, 4), (9000000, 9849999, 3), (9850000, 9999999, 4)), '978-9943': ((0, 2999999, 2), (3000000, 3999999, 3), (4000000, 9749999, 4), (9750000, 9999999, 3)), '978-9944': ((0, 999999, 4), (1000000, 4999999, 3), (5000000, 5999999, 4), (6000000, 6999999, 2), (7000000, 7999999, 3), (8000000, 8999999, 2), (9000000, 9999999, 3)), '978-9945': ((0, 99999, 2), (100000, 799999, 3), (800000, 3999999, 2), (4000000, 5699999, 3), (5700000, 5799999, 2), (5800000, 8499999, 3), (8500000, 9999999, 4)), '978-9946': ((0, 1999999, 1), (2000000, 3999999, 2), (4000000, 8999999, 3), (9000000, 9999999, 4)), '978-9947': ((0, 1999999, 1), (2000000, 7999999, 2), (8000000, 9999999, 3)), '978-9948': ((0, 3999999, 2), (4000000, 8499999, 3), (8500000, 9999999, 4)), '978-9949': ((0, 499999, 2), (500000, 999999, 0), (1000000, 3999999, 2), (4000000, 6999999, 3), (7000000, 7199999, 2), (7200000, 7499999, 4), (7500000, 8999999, 2), (9000000, 9999999, 4)), '978-9950': ((0, 2999999, 2), (3000000, 8499999, 3), (8500000, 9999999, 4)), '978-9951': ((0, 3999999, 2), (4000000, 8499999, 3), (8500000, 9999999, 4)), '978-9952': ((0, 1999999, 1), (2000000, 3999999, 2), (4000000, 7999999, 3), (8000000, 9999999, 4)), '978-9953': ((0, 999999, 1), (1000000, 3999999, 2), (4000000, 5999999, 3), (6000000, 8999999, 2), (9000000, 9299999, 4), (9300000, 9699999, 2), (9700000, 9999999, 3)), '978-9954': ((0, 1999999, 1), (2000000, 3999999, 2), (4000000, 7999999, 3), (8000000, 9899999, 4), (9900000, 9999999, 2)), '978-9955': ((0, 3999999, 2), (4000000, 9299999, 3), (9300000, 9999999, 4)), '978-9956': ((0, 999999, 1), (1000000, 3999999, 2), (4000000, 8999999, 3), (9000000, 9999999, 4)), '978-9957': ((0, 3999999, 2), (4000000, 6499999, 3), (6500000, 6799999, 2), (6800000, 6999999, 3), (7000000, 8499999, 2), (8500000, 8799999, 4), (8800000, 9999999, 2)), '978-9958': ((0, 199999, 2), (200000, 299999, 3), (300000, 399999, 4), (400000, 899999, 3), (900000, 999999, 4), (1000000, 1899999, 2), (1900000, 1999999, 4), (2000000, 4999999, 2), (5000000, 8999999, 3), (9000000, 9999999, 4)), '978-9959': ((0, 1999999, 1), (2000000, 7999999, 2), (8000000, 9499999, 3), (9500000, 9699999, 4), (9700000, 9799999, 3), (9800000, 9999999, 2)), '978-9960': ((0, 5999999, 2), (6000000, 8999999, 3), (9000000, 9999999, 4)), '978-9961': ((0, 2999999, 1), (3000000, 6999999, 2), (7000000, 9499999, 3), (9500000, 9999999, 4)), '978-9962': ((0, 5499999, 2), (5500000, 5599999, 4), (5600000, 5999999, 2), (6000000, 8499999, 3), (8500000, 9999999, 4)), '978-9963': ((0, 1999999, 1), (2000000, 2499999, 4), (2500000, 2799999, 3), (2800000, 2999999, 4), (3000000, 5499999, 2), (5500000, 7349999, 3), (7350000, 7499999, 4), (7500000, 9999999, 4)), '978-9964': ((0, 6999999, 1), (7000000, 9499999, 2), (9500000, 9999999, 3)), '978-9965': ((0, 3999999, 2), (4000000, 8999999, 3), (9000000, 9999999, 4)), '978-9966': ((0, 1499999, 3), (1500000, 1999999, 4), (2000000, 6999999, 2), (7000000, 7499999, 4), (7500000, 9599999, 3), (9600000, 9999999, 4)), '978-9967': ((0, 3999999, 2), (4000000, 8999999, 3), (9000000, 9999999, 4)), '978-9968': ((0, 4999999, 2), (5000000, 9399999, 3), (9400000, 9999999, 4)), '978-9970': ((0, 3999999, 2), (4000000, 8999999, 3), (9000000, 9999999, 4)), '978-9971': ((0, 5999999, 1), (6000000, 8999999, 2), (9000000, 9899999, 3), (9900000, 9999999, 4)), '978-9972': ((0, 999999, 2), (1000000, 1999999, 1), (2000000, 2499999, 3), (2500000, 2999999, 4), (3000000, 5999999, 2), (6000000, 8999999, 3), (9000000, 9999999, 4)), '978-9973': ((0, 599999, 2), (600000, 899999, 3), (900000, 999999, 4), (1000000, 6999999, 2), (7000000, 9699999, 3), (9700000, 9999999, 4)), '978-9974': ((0, 2999999, 1), (3000000, 5499999, 2), (5500000, 7499999, 3), (7500000, 8799999, 4), (8800000, 9099999, 3), (9100000, 9499999, 2), (9500000, 9999999, 2)), '978-9975': ((0, 999999, 1), (1000000, 2999999, 3), (3000000, 3999999, 4), (4000000, 4499999, 4), (4500000, 8999999, 2), (9000000, 9499999, 3), (9500000, 9999999, 4)), '978-9976': ((0, 4999999, 1), (5000000, 5899999, 4), (5900000, 8999999, 2), (9000000, 9899999, 3), (9900000, 9999999, 4)), '978-9977': ((0, 8999999, 2), (9000000, 9899999, 3), (9900000, 9999999, 4)), '978-9978': ((0, 2999999, 2), (3000000, 3999999, 3), (4000000, 9499999, 2), (9500000, 9899999, 3), (9900000, 9999999, 4)), '978-9979': ((0, 4999999, 1), (5000000, 6499999, 2), (6500000, 6599999, 3), (6600000, 7599999, 2), (7600000, 8999999, 3), (9000000, 9999999, 4)), '978-9980': ((0, 3999999, 1), (4000000, 8999999, 2), (9000000, 9899999, 3), (9900000, 9999999, 4)), '978-9981': ((0, 999999, 2), (1000000, 1599999, 3), (1600000, 1999999, 4), (2000000, 7999999, 2), (8000000, 9499999, 3), (9500000, 9999999, 4)), '978-9982': ((0, 7999999, 2), (8000000, 9899999, 3), (9900000, 9999999, 4)), '978-9983': ((0, 7999999, 0), (8000000, 9499999, 2), (9500000, 9899999, 3), (9900000, 9999999, 4)), '978-9984': ((0, 4999999, 2), (5000000, 8999999, 3), (9000000, 9999999, 4)), '978-9985': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 8999999, 3), (9000000, 9999999, 4)), '978-9986': ((0, 3999999, 2), (4000000, 8999999, 3), (9000000, 9399999, 4), (9400000, 9699999, 3), (9700000, 9999999, 2)), '978-9987': ((0, 3999999, 2), (4000000, 8799999, 3), (8800000, 9999999, 4)), '978-9988': ((0, 2999999, 1), (3000000, 5499999, 2), (5500000, 7499999, 3), (7500000, 9999999, 4)), '978-9989': ((0, 999999, 1), (1000000, 1999999, 3), (2000000, 2999999, 4), (3000000, 5999999, 2), (6000000, 9499999, 3), (9500000, 9999999, 4)), '978-99901': ((0, 4999999, 2), (5000000, 7999999, 3), (8000000, 9999999, 2)), '978-99902': ((0, 9999999, 0),), '978-99903': ((0, 1999999, 1), (2000000, 8999999, 2), (9000000, 9999999, 3)), '978-99904': ((0, 5999999, 1), (6000000, 8999999, 2), (9000000, 9999999, 3)), '978-99905': ((0, 3999999, 1), (4000000, 7999999, 2), (8000000, 9999999, 3)), '978-99906': ((0, 2999999, 1), (3000000, 5999999, 2), (6000000, 6999999, 3), (7000000, 8999999, 2), (9000000, 9499999, 2), (9500000, 9999999, 3)), '978-99908': ((0, 999999, 1), (1000000, 8999999, 2), (9000000, 9999999, 3)), '978-99909': ((0, 3999999, 1), (4000000, 9499999, 2), (9500000, 9999999, 3)), '978-99910': ((0, 2999999, 1), (3000000, 8999999, 2), (9000000, 9999999, 3)), '978-99911': ((0, 5999999, 2), (6000000, 9999999, 3)), '978-99912': ((0, 3999999, 1), (4000000, 5999999, 3), (6000000, 8999999, 2), (9000000, 9999999, 3)), '978-99913': ((0, 2999999, 1), (3000000, 3599999, 2), (3600000, 5999999, 0), (6000000, 6049999, 3), (6050000, 9999999, 0)), '978-99914': ((0, 4999999, 1), (5000000, 6999999, 2), (7000000, 7999999, 1), (8000000, 8999999, 2), (9000000, 9999999, 3)), '978-99915': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99916': ((0, 2999999, 1), (3000000, 6999999, 2), (7000000, 9999999, 3)), '978-99917': ((0, 2999999, 1), (3000000, 8999999, 2), (9000000, 9999999, 3)), '978-99918': ((0, 3999999, 1), (4000000, 7999999, 2), (8000000, 9999999, 3)), '978-99919': ((0, 2999999, 1), (3000000, 3999999, 3), (4000000, 6999999, 2), (7000000, 7999999, 2), (8000000, 8499999, 3), (8500000, 8999999, 3), (9000000, 9999999, 3)), '978-99920': ((0, 4999999, 1), (5000000, 8999999, 2), (9000000, 9999999, 3)), '978-99921': ((0, 1999999, 1), (2000000, 6999999, 2), (7000000, 7999999, 3), (8000000, 8999999, 1), (9000000, 9999999, 2)), '978-99922': ((0, 3999999, 1), (4000000, 6999999, 2), (7000000, 9999999, 3)), '978-99923': ((0, 1999999, 1), (2000000, 7999999, 2), (8000000, 9999999, 3)), '978-99924': ((0, 1999999, 1), (2000000, 7999999, 2), (8000000, 9999999, 3)), '978-99925': ((0, 3999999, 1), (4000000, 7999999, 2), (8000000, 9999999, 3)), '978-99926': ((0, 999999, 1), (1000000, 5999999, 2), (6000000, 8699999, 3), (8700000, 8999999, 2), (9000000, 9999999, 2)), '978-99927': ((0, 2999999, 1), (3000000, 5999999, 2), (6000000, 9999999, 3)), '978-99928': ((0, 999999, 1), (1000000, 7999999, 2), (8000000, 9999999, 3)), '978-99929': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99930': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99931': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99932': ((0, 999999, 1), (1000000, 5999999, 2), (6000000, 6999999, 3), (7000000, 7999999, 1), (8000000, 9999999, 2)), '978-99933': ((0, 2999999, 1), (3000000, 5999999, 2), (6000000, 9999999, 3)), '978-99934': ((0, 1999999, 1), (2000000, 7999999, 2), (8000000, 9999999, 3)), '978-99935': ((0, 2999999, 1), (3000000, 5999999, 2), (6000000, 6999999, 3), (7000000, 8999999, 1), (9000000, 9999999, 2)), '978-99936': ((0, 999999, 1), (1000000, 5999999, 2), (6000000, 9999999, 3)), '978-99937': ((0, 1999999, 1), (2000000, 5999999, 2), (6000000, 9999999, 3)), '978-99938': ((0, 1999999, 1), (2000000, 5999999, 2), (6000000, 8999999, 3), (9000000, 9999999, 2)), '978-99939': ((0, 5999999, 1), (6000000, 8999999, 2), (9000000, 9999999, 3)), '978-99940': ((0, 999999, 1), (1000000, 6999999, 2), (7000000, 9999999, 3)), '978-99941': ((0, 2999999, 1), (3000000, 7999999, 2), (8000000, 9999999, 3)), '978-99942': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99943': ((0, 2999999, 1), (3000000, 5999999, 2), (6000000, 9999999, 3)), '978-99944': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99945': ((0, 5999999, 1), (6000000, 8999999, 2), (9000000, 9999999, 3)), '978-99946': ((0, 2999999, 1), (3000000, 5999999, 2), (6000000, 9999999, 3)), '978-99947': ((0, 2999999, 1), (3000000, 6999999, 2), (7000000, 9999999, 3)), '978-99948': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99949': ((0, 1999999, 1), (2000000, 8999999, 2), (9000000, 9999999, 3)), '978-99950': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99951': ((0, 9999999, 0),), '978-99952': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99953': ((0, 2999999, 1), (3000000, 7999999, 2), (8000000, 9399999, 3), (9400000, 9999999, 2)), '978-99954': ((0, 2999999, 1), (3000000, 6999999, 2), (7000000, 8799999, 3), (8800000, 9999999, 2)), '978-99955': ((0, 1999999, 1), (2000000, 5999999, 2), (6000000, 7999999, 3), (8000000, 9999999, 2)), '978-99956': ((0, 5999999, 2), (6000000, 8599999, 3), (8600000, 9999999, 2)), '978-99957': ((0, 1999999, 1), (2000000, 7999999, 2), (8000000, 9399999, 3), (9400000, 9999999, 2)), '978-99958': ((0, 4999999, 1), (5000000, 9399999, 2), (9400000, 9499999, 3), (9500000, 9999999, 3)), '978-99959': ((0, 2999999, 1), (3000000, 5999999, 2), (6000000, 9999999, 3)), '978-99960': ((0, 999999, 1), (1000000, 9499999, 2), (9500000, 9999999, 3)), '978-99961': ((0, 2999999, 1), (3000000, 3999999, 3), (4000000, 8999999, 2), (9000000, 9999999, 3)), '978-99962': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99963': ((0, 4999999, 2), (5000000, 9199999, 3), (9200000, 9999999, 2)), '978-99964': ((0, 1999999, 1), (2000000, 7999999, 2), (8000000, 9999999, 3)), '978-99965': ((0, 2999999, 1), (3000000, 3599999, 3), (3600000, 6299999, 2), (6300000, 9999999, 3)), '978-99966': ((0, 2999999, 1), (3000000, 6999999, 2), (7000000, 7999999, 3), (8000000, 9699999, 2), (9700000, 9999999, 3)), '978-99967': ((0, 999999, 1), (1000000, 1499999, 2), (1500000, 1999999, 0), (2000000, 5999999, 2), (6000000, 8999999, 3), (9000000, 9199999, 3), (9200000, 9499999, 3), (9500000, 9999999, 0)), '978-99968': ((0, 3999999, 1), (4000000, 5999999, 3), (6000000, 8999999, 2), (9000000, 9999999, 3)), '978-99969': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99970': ((0, 4999999, 1), (5000000, 8999999, 2), (9000000, 9999999, 3)), '978-99971': ((0, 4999999, 1), (5000000, 8499999, 2), (8500000, 9999999, 3)), '978-99972': ((0, 4999999, 1), (5000000, 8999999, 2), (9000000, 9999999, 3)), '978-99973': ((0, 3999999, 1), (4000000, 7999999, 2), (8000000, 9999999, 3)), '978-99974': ((0, 999999, 1), (1000000, 2999999, 2), (3000000, 3999999, 3), (4000000, 7999999, 2), (8000000, 9999999, 3)), '978-99975': ((0, 2999999, 1), (3000000, 3999999, 3), (4000000, 7999999, 2), (8000000, 9999999, 3)), '978-99976': ((0, 1999999, 1), (2000000, 5999999, 2), (6000000, 7999999, 3), (8000000, 9999999, 0)), '978-99977': ((0, 1999999, 1), (2000000, 3999999, 0), (4000000, 6999999, 2), (7000000, 7999999, 3), (8000000, 9999999, 0)), '978-99978': ((0, 4999999, 1), (5000000, 7499999, 2), (7500000, 9999999, 3)), '978-99979': ((0, 4999999, 1), (5000000, 7999999, 2), (8000000, 9999999, 3)), '978-99980': ((0, 999999, 1), (1000000, 2999999, 0), (3000000, 5999999, 2), (6000000, 7999999, 0), (8000000, 9999999, 3)), '978-99981': ((0, 1999999, 1), (2000000, 2999999, 0), (3000000, 4999999, 2), (5000000, 8999999, 0), (9000000, 9999999, 3)), '979-10': ((0, 1999999, 2), (2000000, 6999999, 3), (7000000, 8999999, 4), (9000000, 9759999, 5), (9760000, 9999999, 6)), '979-11': ((0, 2499999, 2), (2500000, 5499999, 3), (5500000, 8499999, 4), (8500000, 9499999, 5), (9500000, 9999999, 6)), '979-12': ((0, 1999999, 0), (2000000, 2009999, 3), (2010000, 9999999, 0))} +RDDATE='20181004' diff -Nru isbnlib-3.5.6/isbnlib/_data/__init__.py isbnlib-3.9.3/isbnlib/_data/__init__.py --- isbnlib-3.5.6/isbnlib/_data/__init__.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_data/__init__.py 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1 @@ + diff -Nru isbnlib-3.5.6/isbnlib/_desc.py isbnlib-3.9.3/isbnlib/_desc.py --- isbnlib-3.5.6/isbnlib/_desc.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_desc.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,38 +1,42 @@ # -*- coding: utf-8 -*- """Return a small description of the book.""" +import logging from json import loads from textwrap import fill from .dev.webservice import query as wsquery +LOGGER = logging.getLogger(__name__) UA = "isbnlib (gzip)" +SERVICE_URL = "https://www.googleapis.com/books/v1/volumes?q=isbn:{isbn}"\ + "&fields=items/volumeInfo(description)"\ + "&maxResults=1" def goo_desc(isbn): """Get description from Google Books api.""" from .registry import metadata_cache # <-- dynamic cache = metadata_cache - if cache is not None: # pragma: no cover - key = 'gdesc' + isbn + if cache is not None: # pragma: no cover + key = 'desc-go-' + isbn try: if cache[key]: return cache[key] else: - raise # <-- IMPORTANT: usually the caches don't return error! - except: + raise KeyError # <-- IMPORTANT: caches don't return error! + except KeyError: pass - url = "https://www.googleapis.com/books/v1/volumes?q=isbn+{isbn}"\ - "&fields=items/volumeInfo(description)"\ - "&maxResults=1".format(isbn=isbn) + url = SERVICE_URL.format(isbn=isbn) content = wsquery(url, user_agent=UA) try: content = loads(content) content = content['items'][0]['volumeInfo']['description'] + # TODO don't format content here! content = fill(content, width=75) if content else None - if content and cache is not None: # pragma: no cover + if content and cache is not None: # pragma: no cover cache[key] = content return content - except KeyError: # pragma: no cover - return + except: # pragma: no cover + LOGGER.debug('No description for %s', isbn) diff -Nru isbnlib-3.5.6/isbnlib/dev/_bouth23.py isbnlib-3.9.3/isbnlib/dev/_bouth23.py --- isbnlib-3.5.6/isbnlib/dev/_bouth23.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/dev/_bouth23.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,10 +1,8 @@ # -*- coding: utf-8 -*- # flake8:noqa # pylint: skip-file - """Help code to run in py2 and py3.""" - import sys if sys.version < '3': diff -Nru isbnlib-3.5.6/isbnlib/dev/bouth23.py isbnlib-3.9.3/isbnlib/dev/bouth23.py --- isbnlib-3.5.6/isbnlib/dev/bouth23.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/dev/bouth23.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -# -*- coding: utf-8 -*- -# flake8:noqa -# pylint: skip-file - -"""Help code to run in py2 and py3.""" - - -from ._bouth23 import * diff -Nru isbnlib-3.5.6/isbnlib/dev/_coverscache.py isbnlib-3.9.3/isbnlib/dev/_coverscache.py --- isbnlib-3.5.6/isbnlib/dev/_coverscache.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/dev/_coverscache.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,170 +0,0 @@ -# -*- coding: utf-8 -*- - -"""Read and write cover cache. - - - NOTE - 1. shelve has different incompatible formats in py2 and py3 - 2. if some methods detect that the cache is not consistent - they delete the cache and create a new one. - 3. After purge the cache keeps the records with more hits - and the newests. - 4. The design is for safety not for performance! Increasing - MAXLEN can have an high detrimental impact on performance. - - Examples: - cc = CoversCache('.covers') - cc['9781408835029'] = ( - "http://books.google.com/books/content?id=uUcvgfTYTRnjh"\ - "&printsec=frontcover"\ - "&img=1&zoom=2&edge=curl&source=gbs_api", - ".covers/slot01/9781408835029.jpg" - ) - cc['9781408835029'] - cc.hits('9781408835029') - cc.keys() - cc.files() - cc.sync() - cc.make() - cc.delete() - del cc['9781408835029'] - -""" - -import os -import shutil -import sys -from random import randint - -from ._shelvecache import ShelveCache - -WINDOWS = os.name == 'nt' -PY3 = sys.version > '3' - - -class CoversCache(object): - - """Covers cache.""" - - CACHEFOLDER = '.covers' - INDEXFN = '.index' - WINSHADOWIDX = INDEXFN + '.dat' - MAXLEN = 3000 - NSLOTS = 10 - - def __init__(self, cachepath=CACHEFOLDER): - """Initialize attributes.""" - self.cachepath = cachepath - self._indexpath = os.path.join(cachepath, self.INDEXFN) - if WINDOWS and PY3: - if not os.path.isfile(os.path.join(cachepath, self.WINSHADOWIDX)): - self.make() - elif not os.path.isfile(self._indexpath): - self.make() - self._index = ShelveCache(self._indexpath) - self._index.MAXLEN = self.MAXLEN - if len(self._index) > self.MAXLEN: - self.purge() - - def __getitem__(self, key): - """Read cache.""" - try: - url, pth = self._index[key] - pth = os.path.join(self.cachepath, pth) - return (url, pth) - except: - return None - - def __setitem__(self, key, value): - """Write to cache.""" - url, pth = value - try: - if pth and os.path.isfile(pth) and url: - tocache = os.path.join(self._get_slot(), os.path.basename(pth)) - target = os.path.join(self.cachepath, tocache) - shutil.copyfile(pth, target) - if os.path.isfile(target): - self._index[key] = (url, tocache) - return True - return False - else: - raise - except: - return False - - def __delitem__(self, key): - """Delete record with key.""" - try: - del self._index[key] - return True - except: - return False - - def __len__(self): - """Return the number of keys in cache.""" - return len(self._index.keys()) if self._index.keys() else 0 - - def keys(self): - """Return the number of keys in cache.""" - return self._index.keys() - - def hits(self, key): - """Return the number of hits for key.""" - return self._index.hits(key) - - def _create_slots(self): - for slot in range(self.NSLOTS): - name = "slot%02d" % slot - pth = os.path.join(self.cachepath, name) - if not os.path.exists(pth): - os.mkdir(pth) - - def make(self): - """Init the cache.""" - # 1. Delete if available - if os.path.isdir(self.cachepath): - self.delete() - # 2. Make folder - os.mkdir(self.cachepath) - # 3. Create Index - self._index = ShelveCache(self._indexpath) - # 4. Create slots - self._create_slots() - - def _get_slot(self): - return "slot%02d" % randint(0, self.NSLOTS - 1) - - def files(self): - pths = [] - for root, _, fls in os.walk(self.cachepath): - for fn in fls: - pths.append(os.path.join(root, fn)) - return pths - - def sync(self): - """Sync index entries with disk files.""" - # clear index entries not on disk - checked = [self._indexpath] - for key in self._index.keys(): - url, pth = self._index[key] - pth = os.path.join(self.cachepath, pth) - if not os.path.isfile(pth): - self._index[key] = (url, None) - checked.append(pth) - # delete files not on index - diff = tuple(set(self.files()) - set(checked)) - for fp in diff: - if self.INDEXFN not in fp: - os.remove(fp) - - def purge(self): - try: - self._index.purge() - self.sync() - return True - except: - return False - - def delete(self): - self._index = None - return shutil.rmtree(self.cachepath) diff -Nru isbnlib-3.5.6/isbnlib/dev/_data.py isbnlib-3.9.3/isbnlib/dev/_data.py --- isbnlib-3.5.6/isbnlib/dev/_data.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/dev/_data.py 2018-10-05 11:18:35.000000000 +0000 @@ -9,12 +9,10 @@ # For now you cannot add custom fields! FIELDS = ('ISBN-13', 'Title', 'Authors', 'Publisher', 'Year', 'Language') - LOGGER = logging.getLogger(__name__) class Metadata(object): - """Class for metadata objects.""" def __init__(self, record=None): @@ -36,12 +34,13 @@ def clean(self, broom=normalize_space, exclude=()): """Clean fields of value.""" - self._content.update((k, broom(v)) for k, v - in list(self._content.items()) + self._content.update((k, broom(v)) + for k, v in list(self._content.items()) if k != 'Authors' and k not in exclude) if 'Authors' not in exclude: - self._content['Authors'] = [broom(i) for i in - self._content['Authors']] + self._content['Authors'] = [ + broom(i) for i in self._content['Authors'] + ] self._content['Title'] = self._content['Title'].strip(',.:;-_ ') if self._content['Language'].lower() in ('en', 'eng', 'english'): self._content['Title'] = titlecase(self._content['Title']) @@ -66,13 +65,15 @@ """Delete value.""" self._set_empty() - def merge(self, record, overwrite=(), + def merge(self, + record, + overwrite=(), overrule=lambda x: x == u('') or x == [u('')]): """Merge the record with value.""" # by default do nothing - self._content.update((k, v) for k, v in list(record.items()) - if k in overwrite and not overrule(v) or - self._content[k] == u('')) + self._content.update( + (k, v) for k, v in list(record.items()) + if k in overwrite and not overrule(v) or self._content[k] == u('')) if not self._validate(): # pragma: no cover self._set_empty() LOGGER.debug(record) @@ -83,10 +84,9 @@ """Validate value.""" # 'minimal' check for k in self._content: - if not type(self._content[k]) is type3str(): - if k != 'Authors': - return False - if not type(self._content['Authors']) is list: + if not isinstance(self._content[k], type3str()) and k != 'Authors': + return False + if not isinstance(self._content['Authors'], list): return False return True @@ -98,5 +98,5 @@ def stdmeta(records): """Function API to the class.""" - dt = Metadata(records) - return dt.value + data = Metadata(records) + return data.value diff -Nru isbnlib-3.5.6/isbnlib/dev/_exceptions.py isbnlib-3.9.3/isbnlib/dev/_exceptions.py --- isbnlib-3.5.6/isbnlib/dev/_exceptions.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/dev/_exceptions.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - """ Exceptions for isbnlib.dev The classes in isbnlib.dev should use the exceptions below. @@ -18,7 +17,7 @@ self.message = '%s (%s)' % (self.message, msg) def __str__(self): - return getattr(self, 'message', '') # pragma: no cover + return getattr(self, 'message', '') # pragma: no cover class ISBNLibHTTPError(ISBNLibDevException): diff -Nru isbnlib-3.5.6/isbnlib/dev/_files.py isbnlib-3.9.3/isbnlib/dev/_files.py --- isbnlib-3.5.6/isbnlib/dev/_files.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/dev/_files.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- - """Helper module to work with files.""" - import fnmatch import logging import os @@ -18,7 +16,6 @@ class File(object): - """Easy manipulation of files in the SAME directory.""" def __init__(self, fp): @@ -60,10 +57,10 @@ LOGGER.critical("This (%s) is not a basename!", basename) return False name, ext = os.path.splitext(basename) - if len(name) == 0: + if not name: LOGGER.critical("Not a valid name (lenght 0)!") return False - if len(ext) == 0: + if not ext: LOGGER.critical("Not a valid extension (lenght 0)!") return False return True @@ -81,16 +78,15 @@ try: os.rename(self.basename, new_basename) except OSError as err: - LOGGER.critical("%s", err.message) + LOGGER.critical("%s", err) return False self.basename = new_basename self.name = name self.ext = ext - return True else: LOGGER.info("The file (%s) already exist in the directory!", new_basename) - return True + return True @staticmethod def uxchmod(fp, mode=MODE666): diff -Nru isbnlib-3.5.6/isbnlib/dev/_fmt.py isbnlib-3.9.3/isbnlib/dev/_fmt.py --- isbnlib-3.5.6/isbnlib/dev/_fmt.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/dev/_fmt.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- # flake8: noqa # pylint: skip-file - """Format canonical in bibliographic formats.""" import re @@ -54,6 +53,14 @@ "identifier": [{"type": "ISBN", "id": "$ISBN"}], "publisher": "$Publisher"}''' +csl = r'''{"type":"book", + "id":"$ISBN", + "title":"$Title", + "author": [$AUTHORS], + "issued": {"date_parts": [[$Year]]}, + "ISBN":"$ISBN", + "publisher":"$Publisher"}''' + opf = r""" @@ -76,16 +83,17 @@ Publisher: $Publisher""" templates = { - 'labels': labels, - 'bibtex': bibtex, - 'endnote': endnote, - 'refworks': refworks, - 'msword': msword, - 'json': json, - 'opf': opf - } + 'labels': labels, + 'bibtex': bibtex, + 'endnote': endnote, + 'refworks': refworks, + 'msword': msword, + 'json': json, + 'csl': csl, + 'opf': opf +} -fmts = list(templates.keys()) +_fmts = list(templates.keys()) def _gen_proc(name, canonical): @@ -97,7 +105,7 @@ def _spec_proc(name, fmtrec, authors): """Fix the Authors records.""" - if name not in fmts: + if name not in _fmts: return if name == 'labels': AUTHORS = '\nAuthor: '.join(authors) @@ -112,11 +120,12 @@ person = r"$last"\ r"$first" AUTHORS = '\n'.join( - Template(person).safe_substitute(last_first(a)) - for a in authors) + Template(person).safe_substitute(last_first(a)) for a in authors) elif name == 'json': - AUTHORS = ', '.join('{"name": "$"}'.replace("$", a) - for a in authors) + AUTHORS = ', '.join('{"name": "$"}'.replace("$", a) for a in authors) + elif name == 'csl': + AUTHORS = ', '.join( + '{"literal": "$"}'.replace("$", a) for a in authors) elif name == 'opf': fmtrec = fmtrec.replace('$uid', str(uuid.uuid4())) creator = r' self.MAXLEN: - self.purge() - except: - pass - except: - s = self._sh.open(self.filepath, 'n') - self._keys = [] - s.close() - - def __getitem__(self, key): - """Read cache.""" - if key not in self._keys: - return None - try: - s = self._sh.open(self.filepath, writeback=True) - if s[key]: - s[key]['hits'] += 1 - return s[key]['value'] - else: - return None - except KeyError: - return None - except ValueError: - self.new() - return None - finally: - s.close() - - def __setitem__(self, key, value): - """Write to cache.""" - try: - s = self._sh.open(self.filepath) - s[key] = {'value': value, 'hits': 0, 'timestamp': timestamp()} - self._keys.append(key) - status = True - except: - status = False - finally: - s.close() - return status - - def __delitem__(self, key): - """Delete record with key.""" - if key not in self._keys: - return - try: - s = self._sh.open(self.filepath) - del s[key] - self._keys.remove(key) - except KeyError: - return - except ValueError: - self.new() - return - finally: - s.close() - - def __len__(self): - """Return the number of keys in cache.""" - return len(self.keys()) if self.keys() else 0 - - def keys(self): - """Return list of keys in Cache.""" - if self._keys: - return self._keys - try: - s = self._sh.open(self.filepath) - self._keys = list(s.keys()) - return self._keys - finally: - s.close() - - def ts(self, key): - """Return the timestamp of the record with key.""" - if key not in self._keys: - return None - try: - s = self._sh.open(self.filepath) - ts = s[key]['timestamp'] if s[key] else None - if not ts: - return - fmt = '%Y-%m-%d %H:%M:%S' - return datetime.datetime.fromtimestamp(ts).strftime(fmt) - except KeyError: - return - except ValueError: - self.new() - return - finally: - s.close() - - def hits(self, key): - """Return the number of hits for the record with key.""" - if key not in self._keys: - return None - try: - s = self._sh.open(self.filepath) - hts = s[key]['hits'] if s[key] else None - return hts - except KeyError: - return - except ValueError: - self.new() - return - finally: - s.close() - - def new(self): - """Make new cache.""" - s = self._sh.open(self.filepath, 'n') - s.close() - self._keys = [] - - def purge(self): - """Purge the cache.""" - try: - if len(self.keys()) < self.MAXLEN: - return - s = self._sh.open(self.filepath) - data = [(k, s[k]['timestamp'], s[k]['hits']) for k in s.keys()] - data.sort(key=lambda tup: (-tup[2], -tup[1])) - keep = int(self.CUTOFF * self.MAXLEN) - garbk = [k[0] for k in data[keep:]] - for k in garbk: - del s[k] - self._keys = s.keys() - finally: - s.close() diff -Nru isbnlib-3.5.6/isbnlib/dev/vias.py isbnlib-3.9.3/isbnlib/dev/vias.py --- isbnlib-3.5.6/isbnlib/dev/vias.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/dev/vias.py 2018-10-05 11:18:35.000000000 +0000 @@ -14,9 +14,9 @@ for name, task in named_tasks: try: results[name] = task(arg) - except: # pragma: no cover - LOGGER.debug("No result in 'serial' for %s[%s](%s)", - task, name, arg) + except: # pragma: no cover + LOGGER.debug("No result in 'serial' for %s[%s](%s)", task, name, + arg) results[name] = None return results @@ -29,9 +29,9 @@ def _worker(name, task, arg): try: results[name] = task(arg) - except: # pragma: no cover - LOGGER.debug("No result in 'parallel' for %s[%s](%s)", - task, name, arg) + except: # pragma: no cover + LOGGER.debug("No result in 'parallel' for %s[%s](%s)", task, name, + arg) results[name] = None for name, task in named_tasks: @@ -48,11 +48,11 @@ q = Queue() def _worker(name, task, arg, q): - try: # pragma: no cover + try: # pragma: no cover q.put((name, task(arg))) - except: # pragma: no cover - LOGGER.debug("No result in 'multi' for %s[%s](%s)", - task, name, arg) + except: # pragma: no cover + LOGGER.debug("No result in 'multi' for %s[%s](%s)", task, name, + arg) q.put((name, None)) for name, task in named_tasks: diff -Nru isbnlib-3.5.6/isbnlib/dev/webquery.py isbnlib-3.9.3/isbnlib/dev/webquery.py --- isbnlib-3.5.6/isbnlib/dev/webquery.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/dev/webquery.py 2018-10-05 11:18:35.000000000 +0000 @@ -16,7 +16,6 @@ class WEBQuery(object): - """Base class to query a webservice and parse the result to py objects.""" T = {'id': timestamp()} # noqa @@ -50,7 +49,7 @@ """Parse the data (default JSON -> PY).""" if parser is None: # pragma: no cover return self.data - return parser(self.data) # <-- data is now unicode + return parser(self.data) # <-- data is now unicode def query(url, user_agent=UA, data_checker=None, parser=json.loads): diff -Nru isbnlib-3.5.6/isbnlib/dev/webservice.py isbnlib-3.9.3/isbnlib/dev/webservice.py --- isbnlib-3.5.6/isbnlib/dev/webservice.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/dev/webservice.py 2018-10-05 11:18:35.000000000 +0000 @@ -6,12 +6,16 @@ from ._bouth23 import bstream, s from ._exceptions import ISBNLibHTTPError, ISBNLibURLError +from .. import config -try: # pragma: no cover +# pylint: disable=import-error +# pylint: disable=wrong-import-order +# pylint: disable=no-name-in-module +try: # pragma: no cover from urllib.parse import urlencode from urllib.request import Request, urlopen from urllib.error import HTTPError, URLError -except ImportError: # pragma: no cover +except ImportError: # pragma: no cover from urllib import urlencode from urllib2 import Request, urlopen, HTTPError, URLError @@ -19,8 +23,8 @@ LOGGER = logging.getLogger(__name__) +# pylint: disable=too-few-public-methods class WEBService(object): - """Class to query web services.""" def __init__(self, url, user_agent=UA, values=None, appheaders=None): @@ -31,48 +35,48 @@ # add more user provided headers if appheaders: # pragma: no cover headers.update(appheaders) - # if 'data' it does a PUT request (data must be urlencoded) - data = urlencode(values) if values else None + # if 'data' it does a POST request (data must be urlencoded) + data = urlencode(values).encode('utf8') if values else None self._request = Request(url, data, headers=headers) - self.response = None - def _response(self): + def response(self): """Check errors on response.""" try: - self.response = urlopen(self._request) + response = urlopen(self._request, timeout=config.URLOPEN_TIMEOUT) LOGGER.debug('Request headers:\n%s', self._request.header_items()) except HTTPError as e: # pragma: no cover LOGGER.critical('ISBNLibHTTPError for %s with code %s [%s]', self._url, e.code, e.msg) if e.code in (401, 403, 429): - raise ISBNLibHTTPError('%s Are you making many requests?' - % e.code) + raise ISBNLibHTTPError( + '%s Are you making many requests?' % e.code) if e.code in (502, 504): - raise ISBNLibHTTPError('%s Service temporarily unavailable!' - % e.code) + raise ISBNLibHTTPError( + '%s Service temporarily unavailable!' % e.code) raise ISBNLibHTTPError('(%s) %s' % (e.code, e.msg)) - except URLError as e: # pragma: no cover - LOGGER.critical('ISBNLibURLError for %s with reason %s', - self._url, e.reason) + except URLError as e: # pragma: no cover + LOGGER.critical('ISBNLibURLError for %s with reason %s', self._url, + e.reason) raise ISBNLibURLError(e.reason) + return response if response else None def data(self): """Return the uncompressed data.""" - self._response() - LOGGER.debug('Response headers:\n%s', self.response.info()) - if self.response.info().get('Content-Encoding') == 'gzip': - buf = bstream(self.response.read()) + res = self.response() + LOGGER.debug('Response headers:\n%s', res.info()) + if res.info().get('Content-Encoding') == 'gzip': + buf = bstream(res.read()) f = gzip.GzipFile(fileobj=buf) data = f.read() - else: # pragma: no cover - data = self.response.read() + else: # pragma: no cover + data = res.read() return s(data) def query(url, user_agent=UA, values=None, appheaders=None): """Query to a web service.""" - service = WEBService(url, user_agent=user_agent, values=values, - appheaders=appheaders) + service = WEBService( + url, user_agent=user_agent, values=values, appheaders=appheaders) data = service.data() LOGGER.debug('Raw data from service:\n%s', data) return data diff -Nru isbnlib-3.5.6/isbnlib/_doitotex.py isbnlib-3.9.3/isbnlib/_doitotex.py --- isbnlib-3.5.6/isbnlib/_doitotex.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_doitotex.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - """Return metadata, of a given DOI, formated as BibTeX.""" import logging @@ -8,18 +7,19 @@ LOGGER = logging.getLogger(__name__) - URL = 'http://dx.doi.org/{DOI}' UA = 'isbnlib (gzip)' def doi2tex(doi): """Get the bibtex ref for doi.""" - data = query(URL.format(DOI=doi), - user_agent=UA, - appheaders={'Accept': 'application/x-bibtex; charset=utf-8'} - ) + data = query( + URL.format(DOI=doi), + user_agent=UA, + appheaders={ + 'Accept': 'application/x-bibtex; charset=utf-8', + }) if not data: # pragma: no cover LOGGER.warning('no data return for doi: %s', doi) - return + return None return data diff -Nru isbnlib-3.5.6/isbnlib/_editions.py isbnlib-3.9.3/isbnlib/_editions.py --- isbnlib-3.5.6/isbnlib/_editions.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_editions.py 2018-10-05 11:18:35.000000000 +0000 @@ -4,59 +4,61 @@ import logging from ._core import EAN13 +from .dev import vias from ._exceptions import NotRecognizedServiceError, NotValidISBNError +from ._openled import query as oed from ._thinged import query as ted -from ._wcated import query as wed -PROVIDERS = ('any', 'merge', 'thingl', 'wcat') -TRUEPROVIDERS = ('wcat', 'thingl') # <-- by priority +PROVIDERS = ('any', 'merge', 'openl', 'thingl') +TRUEPROVIDERS = ('openl', 'thingl') # <-- by priority LOGGER = logging.getLogger(__name__) def fake_provider_any(isbn): """Fake provider 'any' service.""" - providers = {'wcat': wed, 'thingl': ted} + providers = {'openl': oed, 'thingl': ted} for provider in TRUEPROVIDERS: data = [] try: data = providers[provider](isbn) - if data: + if len(data) > 1: return data - continue # pragma: no cover - except: # pragma: no cover + continue # pragma: no cover + except Exception: # pragma: no cover continue - return data # pragma: no cover + return data # pragma: no cover def fake_provider_merge(isbn): """Fake provider 'merge' service.""" - data = [] - try: # pragma: no cover - wdata = wed(isbn) - if wdata: - tdata = ted(isbn) - if tdata: - data = list(set(wdata + tdata)) - return data - raise - except: # pragma: no cover + try: # pragma: no cover + named_tasks = (('openl', oed), ('thingl', ted)) + results = vias.parallel(named_tasks, isbn) + odata = results.get('openl', []) + tdata = results.get('thingl', []) + data = list(set(odata + tdata)) return data + except Exception: # pragma: no cover + return [] -def editions(isbn, service='wcat'): +def editions(isbn, service='merge'): """Return the list of ISBNs of editions related with this ISBN.""" isbn = EAN13(isbn) if not isbn: LOGGER.critical('%s is not a valid ISBN', isbn) raise NotValidISBNError(isbn) - if service == 'any': - return fake_provider_any(isbn) + if service not in PROVIDERS: + LOGGER.critical('%s is not a recognized editions provider', service) + raise NotRecognizedServiceError(service) if service == 'merge': return fake_provider_merge(isbn) + if service == 'any': + return fake_provider_any(isbn) - if service not in PROVIDERS: - LOGGER.critical('%s is not a recognized editions provider', service) - raise NotRecognizedServiceError(service) - return wed(isbn) if service == 'wcat' else ted(isbn) + if service == 'openl': + return oed(isbn) + if service == 'thingl': + return ted(isbn) diff -Nru isbnlib-3.5.6/isbnlib/_exceptions.py isbnlib-3.9.3/isbnlib/_exceptions.py --- isbnlib-3.5.6/isbnlib/_exceptions.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_exceptions.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +"""Exceptions for isbnlib.""" import sys @@ -14,7 +15,6 @@ class ISBNLibException(Exception): - """Base class for isbnlib exceptions. This exception should not be raised directly, @@ -22,11 +22,10 @@ """ def __str__(self): - return getattr(self, 'message', '') # pragma: no cover + return getattr(self, 'message', '') # pragma: no cover class NotRecognizedServiceError(ISBNLibException): - """Exception raised when the service is not in config.py.""" def __init__(self, service): @@ -34,7 +33,6 @@ class NotValidISBNError(ISBNLibException): - """Exception raised when the ISBN is not valid.""" def __init__(self, isbnlike): @@ -42,10 +40,9 @@ class PluginNotLoadedError(ISBNLibException): # pragma: no cover - """Exception raised when the plugin's loader doesn't load the plugin. - TODO: Delete this in version 4 + TODO: Delete this in version 4? """ def __init__(self, path): diff -Nru isbnlib-3.5.6/isbnlib/_ext.py isbnlib-3.9.3/isbnlib/_ext.py --- isbnlib-3.5.6/isbnlib/_ext.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_ext.py 2018-10-05 11:18:35.000000000 +0000 @@ -31,10 +31,11 @@ return infogroup(isbn) -def editions(isbn, service='wcat'): +def editions(isbn, service='merge'): """Return the list of ISBNs of editions related with this ISBN. - 'service' can have the values 'any', 'merge', 'thingl' and 'wcat' (default) + 'service' can have the values: + 'any', 'merge' (default), 'wcat', 'openl' and 'thingl' """ return eds(isbn, service) @@ -54,24 +55,24 @@ """Rename a file using metadata from an ISBN in his filename.""" cfp = File(fp) isbn = EAN13(cfp.name) - if not isbn: # pragma: no cover - return + if not isbn: # pragma: no cover + return None data = meta(isbn) author = data.get('Authors', u('UNKNOWN')) - if author != u('UNKNOWN'): # pragma: no cover + if author != u('UNKNOWN'): # pragma: no cover author = last_first(author[0])['last'] year = data.get('Year', u('UNKNOWN')) maxlen = 98 - (20 + len(author) + len(year)) title = data.get('Title', u('UNKNOWN')) if title != u('UNKNOWN'): regex1 = re.compile(r'[.,_!?/\\]') - regex2 = re.compile('\s\s+') + regex2 = re.compile(r'\s\s+') title = regex1.sub(' ', title) title = regex2.sub(' ', title) title = title.strip() - if title == u('UNKNOWN') or not title: # pragma: no cover - return - if ' ' in title: # pragma: no cover + if title == u('UNKNOWN') or not title: # pragma: no cover + return None + if ' ' in title: # pragma: no cover tokens = title.split(' ') stitle = cutoff_tokens(tokens, maxlen) title = ' '.join(stitle) @@ -80,10 +81,10 @@ return cfp.baserename(b2u3(new_name + cfp.ext)) -def cover(isbn, size=2, mode='prt'): - """Download the cover of the ISBN.""" +def cover(isbn): + """Get the img urls of the cover of the ISBN.""" isbn = EAN13(isbn) - return gcover(isbn, size=size, mode=mode) if isbn else None + return gcover(isbn) if isbn else None def desc(isbn): diff -Nru isbnlib-3.5.6/isbnlib/_goob.py isbnlib-3.9.3/isbnlib/_goob.py --- isbnlib-3.5.6/isbnlib/_goob.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_goob.py 2018-10-05 11:18:35.000000000 +0000 @@ -5,12 +5,12 @@ from .dev import stdmeta from .dev._bouth23 import u -from .dev._exceptions import (ISBNNotConsistentError, - NoDataForSelectorError, RecordMappingError) +from .dev._exceptions import (ISBNNotConsistentError, NoDataForSelectorError, + RecordMappingError) from .dev.webquery import query as wquery UA = 'isbnlib (gzip)' -SERVICE_URL = 'https://www.googleapis.com/books/v1/volumes?q=isbn+{isbn}'\ +SERVICE_URL = 'https://www.googleapis.com/books/v1/volumes?q=isbn:{isbn}'\ '&fields=items/volumeInfo(title,authors,publisher,publishedDate,language,'\ 'industryIdentifiers)&maxResults=1' LOGGER = logging.getLogger(__name__) @@ -28,10 +28,10 @@ if 'publishedDate' in records \ and len(records['publishedDate']) >= 4: canonical['Year'] = records['publishedDate'][0:4] - else: # pragma: no cover + else: # pragma: no cover canonical['Year'] = u('') canonical['Language'] = records.get('language', u('')) - except: # pragma: no cover + except: # pragma: no cover LOGGER.debug("RecordMappingError for %s with data %s", isbn, records) raise RecordMappingError(isbn) # call stdmeta for extra cleanning and validation @@ -49,9 +49,11 @@ # consistency check (isbn request = isbn response) if recs: ids = recs.get('industryIdentifiers', '') - if isbn not in repr(ids): # pragma: no cover + if u('ISBN_13') in repr(ids) and \ + isbn not in repr(ids): # pragma: no cover LOGGER.debug('ISBNNotConsistentError for %s (%s)', isbn, repr(ids)) - raise ISBNNotConsistentError("%s not in %s" % (isbn, repr(ids))) + raise ISBNNotConsistentError("{0} not in {1}".format( + isbn, repr(ids))) # map canonical <- records return _mapper(isbn, recs) diff -Nru isbnlib-3.5.6/isbnlib/_goom.py isbnlib-3.9.3/isbnlib/_goom.py --- isbnlib-3.5.6/isbnlib/_goom.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_goom.py 2018-10-05 11:18:35.000000000 +0000 @@ -22,7 +22,7 @@ try: # mapping: canonical <- records if 'industryIdentifiers' not in record: # pragma: no cover - return + return None canonical = {} isbn = None for ident in record['industryIdentifiers']: @@ -30,7 +30,7 @@ isbn = ident['identifier'] break if not isbn: # pragma: no cover - return + return None canonical['ISBN-13'] = isbn canonical['Title'] = record.get('title', u('')).replace(' :', ':') canonical['Authors'] = record.get('authors', []) @@ -38,10 +38,10 @@ if 'publishedDate' in record \ and len(record['publishedDate']) >= 4: canonical['Year'] = record['publishedDate'][0:4] - else: # pragma: no cover + else: # pragma: no cover canonical['Year'] = u('') canonical['Language'] = record.get('language', u('')) - except: # pragma: no cover + except: # pragma: no cover raise RecordMappingError(isbn) # call stdmeta for extra cleanning and validation return stdmeta(canonical) diff -Nru isbnlib-3.5.6/isbnlib/_gwords.py isbnlib-3.9.3/isbnlib/_gwords.py --- isbnlib-3.5.6/isbnlib/_gwords.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_gwords.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,29 +1,44 @@ # -*- coding: utf-8 -*- """Use Google to get an ISBN from words from title and author's name.""" - import logging from ._core import get_canonical_isbn, get_isbnlike from .dev import webservice +try: # pragma: no cover + from urllib.parse import quote +except ImportError: # pragma: no cover + + def quote(x): # pragma: no cover + """Do nothing if PY2.""" + return x + + LOGGER = logging.getLogger(__name__) def goos(words): """Use Google to get an ISBN from words from title and author's name.""" - service_url = "http://www.google.com/search?q={words}+ISBN" - search_url = service_url.format(words=words.replace(' ', '+')) - user_agent = 'w3m/0.5.2' + service_url = "http://www.google.com/search?q=ISBN+" + search_url = service_url + quote(words.replace(' ', '+')) + + user_agent = 'w3m/0.5.3' - content = webservice.query(search_url, user_agent) + content = webservice.query( + search_url, + user_agent=user_agent, + appheaders={ + 'Content-Type': 'text/plain; charset="UTF-8"', + 'Content-Transfer-Encoding': 'Quoted-Printable', + }) isbns = get_isbnlike(content) for item in isbns: isbn = get_canonical_isbn(item, output='isbn13') if isbn: break - if not isbns or not isbn: # pragma: no cover + if not isbns or not isbn: # pragma: no cover LOGGER.debug('No ISBN found for %s', words) - return + return None return isbn diff -Nru isbnlib-3.5.6/isbnlib/_imcache.py isbnlib-3.9.3/isbnlib/_imcache.py --- isbnlib-3.5.6/isbnlib/_imcache.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_imcache.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,13 +1,10 @@ # -*- coding: utf-8 -*- - """Read and write to a dict-like cache.""" - from collections import MutableMapping class IMCache(MutableMapping): - """Read and write to a dict-like cache.""" MAXLEN = 1000 @@ -35,3 +32,15 @@ def __delitem__(self, k): del self.d[k] + + def __bool__(self): + return len(self) != 0 + + # For PY2 compatibility + __nonzero__ = __bool__ + + def __call__(self, k): + try: + return self.__getitem__(k) + except KeyError: + return None diff -Nru isbnlib-3.5.6/isbnlib/__init__.py isbnlib-3.9.3/isbnlib/__init__.py --- isbnlib-3.5.6/isbnlib/__init__.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/__init__.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,33 +1,24 @@ # -*- coding: utf-8 -*- # flake8: noqa # isort:skip_file +"""Library to validate, clean, transform and get metadata of ISBN strings (for devs).""" -"""Define isbnlib API and set lib environment.""" +# Define isbnlib API and set lib environment import logging as _logging from ._exceptions import (quiet_errors, ISBNLibException, - NotRecognizedServiceError, - NotValidISBNError, + NotRecognizedServiceError, NotValidISBNError, PluginNotLoadedError) -# config _logging for lib (NullHandler not available for py26) -try: - _nh = _logging.NullHandler() -except: # pragma: no cover - class NullHandler(_logging.Handler): - def emit(self, record): - pass - _nh = NullHandler() -_logging.getLogger('isbnlib').addHandler(_nh) - # configuration -from . import config # <-- first import +from . import config # <-- first import # main modules -from ._core import (is_isbn10, is_isbn13, to_isbn10, to_isbn13, clean, - canonical, notisbn, get_isbnlike, get_canonical_isbn, - EAN13) +from ._core import (is_isbn10, is_isbn13, to_isbn10, to_isbn13, check_digit10, + check_digit13, clean, canonical, notisbn, get_isbnlike, + get_canonical_isbn, GTIN13, EAN13, RE_ISBN10, RE_ISBN13, + RE_LOOSE, RE_NORMAL, RE_STRICT) from ._ext import (cover, desc, mask, meta, info, editions, isbn_from_words, doi, ren) from ._goom import query as goom @@ -36,20 +27,24 @@ # Ranges Database date from ._data.data4mask import RDDATE +# config _logging for lib +_nh = _logging.NullHandler() +_logging.getLogger('isbnlib').addHandler(_nh) + # alias ISBN13 = EAN13 ean13 = EAN13 # dunders -__all__ = ('is_isbn10', 'is_isbn13', 'clean', 'mask', 'info', 'meta', - 'to_isbn10', 'to_isbn13', 'get_isbnlike', 'notisbn', - 'ean13', 'EAN13', 'cover', 'desc', - 'canonical', 'get_canonical_isbn', 'editions', 'isbn_from_words', - 'quiet_errors', 'config', '__version__', '__support__', - 'doi', 'ren', 'ISBN13', 'ISBNLibException', - 'NotRecognizedServiceError', 'NotValidISBNError', - 'PluginNotLoadedError', 'goom', 'doi2tex', 'RDDATE') +__all__ = ('is_isbn10', 'is_isbn13', 'clean', 'check_digit10', 'check_digit13', + 'mask', 'info', 'meta', 'to_isbn10', 'to_isbn13', 'get_isbnlike', + 'notisbn', 'ean13', 'EAN13', 'cover', 'desc', 'canonical', + 'get_canonical_isbn', 'editions', 'isbn_from_words', 'quiet_errors', + 'config', '__version__', '__support__', 'doi', 'ren', 'ISBN13', + 'GTIN13', 'ISBNLibException', 'NotRecognizedServiceError', + 'NotValidISBNError', 'PluginNotLoadedError', 'goom', 'doi2tex', + 'RDDATE') -__version__ = '3.5.6' # <-- literal IDs -__support__ = 'py26, py27, py33, py34, pypy' # <-- literal IDs +__version__ = '3.9.3' # <-- literal IDs +__support__ = 'py27, py34, py35, py36, py37, pypy, pypy3' # <-- literal IDs diff -Nru isbnlib-3.5.6/isbnlib/_isbndb.py isbnlib-3.9.3/isbnlib/_isbndb.py --- isbnlib-3.5.6/isbnlib/_isbndb.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_isbndb.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -"""Query the isbndb.org service for metadata.""" - -import logging -import re - -from .config import apikeys -from .dev import stdmeta -from .dev._bouth23 import u -from .dev._exceptions import (DataWrongShapeError, ISBNNotConsistentError, - NoAPIKeyError, NoDataForSelectorError, - RecordMappingError) -from .dev.webquery import query as wquery - -UA = 'isbnlib (gzip)' -SERVICE_URL = 'http://isbndb.com/api/v2/json/{apikey}/book/{isbn}' -PATT_YEAR = re.compile(r'\d{4}') -LOGGER = logging.getLogger(__name__) - - -def _mapper(isbn, records): - """Map canonical <- records.""" - # canonical: - # -> ISBN-13, Title, Authors, Publisher, Year, Language - try: - # mapping: canonical <- records - canonical = {} - canonical['ISBN-13'] = u(isbn) - # assert isbn == records['isbn13'], "isbn was mungled!" - canonical['Title'] = records.get('title', u('')) - authors = [a['name'] for a in records['author_data']] - canonical['Authors'] = authors - canonical['Publisher'] = records.get('publisher_name', u('')) - canonical['Year'] = u('') - if 'edition_info' in records: - match = re.search(PATT_YEAR, records['edition_info']) - if match: - canonical['Year'] = str(match.group(0)) - canonical['Language'] = records.get('language', u('')) - except: - raise RecordMappingError(isbn) - # call stdmeta for extra cleanning and validation - return stdmeta(canonical) - - -def _records(isbn, data): - """Classify (canonically) the parsed data.""" - # check status - try: - err = data.get('error', '') - if err: - raise - except: - LOGGER.debug('DataWrongShapeError for %s with status %s', - isbn, err) - raise DataWrongShapeError("error: '%s' for isbn %s" % (err, isbn)) - # put the selected data in records - try: - recs = data['data'][0] - except: # pragma: no cover - LOGGER.debug('NoDataForSelectorError for %s', isbn) - raise NoDataForSelectorError(isbn) - # consistency check (isbn request = isbn response) - if recs: - ids = recs.get('isbn13', '') - if isbn not in repr(ids): # pragma: no cover - LOGGER.debug('ISBNNotConsistentError for %s (%s)', isbn, repr(ids)) - raise ISBNNotConsistentError("%s not in %s" % (isbn, repr(ids))) - # map canonical <- records - return _mapper(isbn, recs) - - -def query(isbn): - """Query the isbndb.org service for metadata.""" - if not apikeys.get('isbndb'): - raise NoAPIKeyError - data = wquery(SERVICE_URL.format(apikey=apikeys['isbndb'], isbn=isbn), - user_agent=UA) - return _records(isbn, data) diff -Nru isbnlib-3.5.6/isbnlib/_merge.py isbnlib-3.9.3/isbnlib/_merge.py --- isbnlib-3.5.6/isbnlib/_merge.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_merge.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -# -*- coding: utf-8 -*- -"""Provide metadata by merging metadata from other providers.""" - -from . import config -from ._goob import query as qgoob -from ._wcat import query as qwcat -from .dev import Metadata, vias - - -def query(isbn, processor=None): - """Query function for the 'merge provider' (waterfall model).""" - if not processor: - processor = config.options.get('VIAS_MERGE', processor).lower() - if not processor: # pragma: no cover - processor = 'serial' - - named_tasks = (('wcat', qwcat), ('goob', qgoob)) - if processor == 'parallel': - results = vias.parallel(named_tasks, isbn) - elif processor == 'serial': - results = vias.serial(named_tasks, isbn) - elif processor == 'multi': - results = vias.multi(named_tasks, isbn) - - rw = results.get('wcat', None) - rg = results.get('goob', None) - - if not rw and not rg: # pragma: no cover - return None - - md = Metadata(rw) if rw else None - - if md and rg: - # Overwrite with Authors and Language from Google - md.merge(rg, overwrite=('Authors')) - return md.value - if not md and rg: # pragma: no cover - md = Metadata(rg) - return md.value - return md.value if not rg and rw else None # pragma: no cover diff -Nru isbnlib-3.5.6/isbnlib/_metadata.py isbnlib-3.9.3/isbnlib/_metadata.py --- isbnlib-3.5.6/isbnlib/_metadata.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_metadata.py 2018-10-05 11:18:35.000000000 +0000 @@ -8,24 +8,26 @@ def query(isbn, service='default', cache='default'): """Query worldcat.org, Google Books (JSON API), ... for metadata.""" - from .registry import metadata_cache # <-- dinamic now! - ean = EAN13(isbn) # <-- XXX maybe this is too strict? + # validate inputs + ean = EAN13(isbn) if not ean: raise NotValidISBNError(isbn) isbn = ean - if cache == 'default': - cache = metadata_cache if service != 'default' and service not in services: # pragma: no cover raise NotRecognizedServiceError(service) - if cache is None: # pragma: no cover + # set cache and get metadata + if cache is None: # pragma: no cover return services[service](isbn) + if cache == 'default': + from .registry import metadata_cache + cache = metadata_cache key = isbn + service try: if cache[key]: return cache[key] - else: # pragma: no cover - raise # <-- IMPORTANT: usually the caches don't return error! - except: + else: # pragma: no cover + raise # <-- IMPORTANT: "caches don't return error"! + except Exception: meta = services[service](isbn) if meta: cache[key] = meta diff -Nru isbnlib-3.5.6/isbnlib/_msk.py isbnlib-3.9.3/isbnlib/_msk.py --- isbnlib-3.5.6/isbnlib/_msk.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_msk.py 2018-10-05 11:18:35.000000000 +0000 @@ -34,13 +34,13 @@ isbn10 = True idx = None - check = ib[-1:] # <-- hack! + check = ib[-1:] # <-- HACK! cur = 3 igi = cur buf = ib[igi:cur + 1] group = ib[0:cur] + '-' + buf - for _ in range(6): # pragma: no cover + for _ in range(6): # pragma: no cover if group in ranges: sevens = ib[cur + 1:cur + 8].ljust(7, '0') for l in ranges[group]: @@ -50,14 +50,14 @@ break cur += 1 buf = ib[igi:cur + 1] - group = group + buf[-1:] # <-- hack! + group = group + buf[-1:] # <-- HACK! if idx: if isbn10: group = group[4:] check = check10 - return separator.join([group, ib[cur + 1:cur + idx + 1], - ib[cur + idx + 1:-1], check]) + return separator.join( + [group, ib[cur + 1:cur + idx + 1], ib[cur + idx + 1:-1], check]) LOGGER.warning('identifier not found! ' 'Please, update the program.') # pragma: no cover - return # pragma: no cover + return None diff -Nru isbnlib-3.5.6/isbnlib/_openled.py isbnlib-3.9.3/isbnlib/_openled.py --- isbnlib-3.5.6/isbnlib/_openled.py 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_openled.py 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +"""Query the Open Library for related ISBNs.""" + +import logging + +from . import get_canonical_isbn, get_isbnlike +from .dev._bouth23 import u +from .dev.webquery import query as wquery + +LOGGER = logging.getLogger(__name__) +UA = 'isbnlib (gzip)' +SERVICE_URL = 'http://openlibrary.org/query.json?type=/type/edition&'\ + '{selectors}' +CODES = 'isbn_13={isbn}&books=' +ISBNS = '{code}&isbn_13=' + + +def query(isbn): + """Query the Open Library for related ISBNs.""" + try: + data = wquery( + SERVICE_URL.format(selectors=CODES.format(isbn=isbn)), + user_agent=UA) + codes = [rec['key'] for rec in data] + isbnlikes = [isbn] + for code in codes: + txt = wquery( + SERVICE_URL.format(selectors=ISBNS.format(code=code)), + user_agent=UA, + parser=None) + isbnlikes.extend(get_isbnlike(txt)) + isbns = [get_canonical_isbn(isbnlike) for isbnlike in isbnlikes] + isbns = sorted(list(set([u(n) for n in isbns if n]))) # qa: py26 + except Exception: # pragma: no cover, qa: FIXME + LOGGER.debug('No data from Open Library for isbn %s', isbn) + return isbns diff -Nru isbnlib-3.5.6/isbnlib/_openl.py isbnlib-3.9.3/isbnlib/_openl.py --- isbnlib-3.5.6/isbnlib/_openl.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_openl.py 2018-10-05 11:18:35.000000000 +0000 @@ -24,17 +24,23 @@ canonical = {} canonical['ISBN-13'] = u(isbn) canonical['Title'] = records.get('title', u('')).replace(' :', ':') - canonical['Authors'] = [a['name'] for a in - records.get('authors', ({'name': u('')},))] - canonical['Publisher'] = records.get('publishers', - [{'name': u('')}, ])[0]['name'] + canonical['Authors'] = [ + a['name'] for a in records.get('authors', ({ + 'name': u(''), + }, )) + ] + canonical['Publisher'] = records.get('publishers', [ + { + 'name': u(''), + }, + ])[0]['name'] canonical['Year'] = u('') strdate = records.get('publish_date', u('')) - if strdate: # pragma: no cover + if strdate: # pragma: no cover match = re.search(r'\d{4}', strdate) if match: canonical['Year'] = match.group(0) - except: # pragma: no cover + except: # pragma: no cover LOGGER.debug("RecordMappingError for %s with data %s", isbn, records) raise RecordMappingError(isbn) # call stdmeta for extra cleanning and validation @@ -46,7 +52,7 @@ try: # put the selected data in records records = data['ISBN:%s' % isbn] - except: # pragma: no cover + except: # pragma: no cover LOGGER.debug('NoDataForSelectorError for %s', isbn) raise NoDataForSelectorError(isbn) diff -Nru isbnlib-3.5.6/isbnlib/registry.py isbnlib-3.9.3/isbnlib/registry.py --- isbnlib-3.5.6/isbnlib/registry.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/registry.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,34 +1,29 @@ # -*- coding: utf-8 -*- - """Registry for metadata services, formatters and cache.""" +from pkg_resources import iter_entry_points from . import _goob as goob -from . import _isbndb as isbndb -from . import _merge as merge from . import _openl as openl -from . import _wcat as wcat from ._imcache import IMCache -from .dev._fmt import fmtbib +from .dev._fmt import _fmtbib # SERVICES -services = {'default': merge.query, - 'wcat': wcat.query, - 'goob': goob.query, - 'merge': merge.query, - 'openl': openl.query, - 'isbndb': isbndb.query - } +services = { + 'default': goob.query, + 'goob': goob.query, + 'openl': openl.query, +} -def setdefaultservice(name): # pragma: no cover +def setdefaultservice(name): # pragma: no cover """Set the default service.""" global services services['default'] = services[name] -def add_service(name, query): # pragma: no cover +def add_service(name, query): # pragma: no cover """Add a new service to services.""" global services services[name] = query @@ -36,52 +31,64 @@ # FORMATTERS -bibformatters = {'default': lambda x: fmtbib('labels', x), - 'labels': lambda x: fmtbib('labels', x), - 'bibtex': lambda x: fmtbib('bibtex', x), - 'endnote': lambda x: fmtbib('endnote', x), - 'refworks': lambda x: fmtbib('refworks', x), - 'msword': lambda x: fmtbib('msword', x), - 'json': lambda x: fmtbib('json', x), - 'opf': lambda x: fmtbib('opf', x)} # pragma: no cover +bibformatters = { + 'default': lambda x: _fmtbib('labels', x), + 'labels': lambda x: _fmtbib('labels', x), + 'bibtex': lambda x: _fmtbib('bibtex', x), + 'csl': lambda x: _fmtbib('csl', x), + 'json': lambda x: _fmtbib('json', x), + 'opf': lambda x: _fmtbib('opf', x), + 'endnote': lambda x: _fmtbib('endnote', x), + 'refworks': lambda x: _fmtbib('refworks', x), + 'msword': lambda x: _fmtbib('msword', x), +} # pragma: no cover -def setdefaultbibformatter(name): # pragma: no cover +def setdefaultbibformatter(name): # pragma: no cover """Set the default formatter.""" global bibformatters bibformatters['default'] = bibformatters[name] -def add_bibformatter(name, formatter): # pragma: no cover +def add_bibformatter(name, formatter): # pragma: no cover """Add a new formatter to formatters.""" global bibformatters bibformatters[name] = formatter -# CACHE -# if you want a persistant cache you could use -# .dev.helpers ShelveCache(pathtofile) +def load_plugins(): # pragma: no cover + """Load plugins with groups: isbnlib.metadata & isbnlib.formatters.""" + # get metadata plugins from entry_points + try: + for entry in iter_entry_points(group='isbnlib.metadata'): + add_service(entry.name, entry.load()) + except: + pass + # get formatters from entry_points + try: + for entry in iter_entry_points(group='isbnlib.formatters'): + add_bibformatter(entry.name, entry.load()) + except: + pass -metadata_cache = IMCache() # should be an instance +# load plugins on import +load_plugins() + +# CACHE +metadata_cache = IMCache() # should be an instance -def set_cache(cache): # pragma: no cover + +def set_cache(cache): # pragma: no cover """Set cache for metadata.""" global metadata_cache metadata_cache = cache -covers_cache = None # should be an instance - - -def set_covers_cache(cache): # pragma: no cover - """Set cache for covers.""" - global covers_cache - covers_cache = cache -custom_cache = None # should be an instance +custom_cache = None # should be an instance -def set_custom_cache(cache): # pragma: no cover +def set_custom_cache(cache): # pragma: no cover """Set a 'spare' cache.""" global custom_cache custom_cache = cache diff -Nru isbnlib-3.5.6/isbnlib/test/data4tests.py isbnlib-3.9.3/isbnlib/test/data4tests.py --- isbnlib-3.5.6/isbnlib/test/data4tests.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/data4tests.py 2018-10-05 11:18:35.000000000 +0000 @@ -81,4 +81,5 @@ ISBN 978-99937-1-056-1 ISBN 978-99965-2-047-1 ''' + # flake8: noqa diff -Nru isbnlib-3.5.6/isbnlib/test/__init__.py isbnlib-3.9.3/isbnlib/test/__init__.py --- isbnlib-3.5.6/isbnlib/test/__init__.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/__init__.py 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1 @@ + diff -Nru isbnlib-3.5.6/isbnlib/test/test_core.py isbnlib-3.9.3/isbnlib/test/test_core.py --- isbnlib-3.5.6/isbnlib/test/test_core.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_core.py 2018-10-05 11:18:35.000000000 +0000 @@ -3,33 +3,34 @@ # pylint: skip-file from nose.tools import assert_equals -from .._core import (_check_digit10, _check_digit13, _check_structure10, - _check_structure13, is_isbn10, is_isbn13, to_isbn10, to_isbn13, - canonical, clean, notisbn, get_isbnlike, get_canonical_isbn, EAN13) +from .._core import (check_digit10, check_digit13, _check_structure10, + _check_structure13, is_isbn10, is_isbn13, to_isbn10, + to_isbn13, canonical, clean, notisbn, get_isbnlike, + get_canonical_isbn, EAN13) from .data4tests import ISBNs - # nose tests -def test__check_digit10(): + +def test_check_digit10(): """Test check digit algo for ISBN-10.""" - assert_equals(_check_digit10('082649752'), '7') - assert_equals(_check_digit10('585270001'), '0') - assert_equals(_check_digit10('08264975X'), None) - assert_equals(_check_digit10('08264975'), None) + assert_equals(check_digit10('082649752'), '7') + assert_equals(check_digit10('585270001'), '0') + assert_equals(check_digit10('08264975X'), None) + assert_equals(check_digit10('08264975'), None) -def test__check_digit13(): +def test_check_digit13(): """Test check digit algo for ISBN-13.""" - assert_equals(_check_digit13('978082649752'), '9') - assert_equals(_check_digit13('97808264975'), None) - assert_equals(_check_digit13('97808264975X'), None) + assert_equals(check_digit13('978082649752'), '9') + assert_equals(check_digit13('97808264975'), None) + assert_equals(check_digit13('97808264975X'), None) def test__check_structure10(): """Test structure detection for ISBN-10.""" assert_equals(_check_structure10('0826497527'), True) - assert_equals(_check_structure10('0826497X27'), True) # isbnlike! + assert_equals(_check_structure10('0826497X27'), True) # isbnlike! assert_equals(_check_structure10('0826497XI7'), False) @@ -62,10 +63,10 @@ """Test transformation of ISBN to ISBN-10.""" assert_equals(to_isbn10('9780826497529'), '0826497527') assert_equals(to_isbn10('0826497527'), '0826497527') - assert_equals(to_isbn10('9780826497520'), None) # ISBN13 not valid + assert_equals(to_isbn10('9780826497520'), None) # ISBN13 not valid assert_equals(to_isbn10('9790826497529'), None) assert_equals(to_isbn10('97808264975X3'), None) - assert_equals(to_isbn10('978-826497'), None) # (bug #14) + assert_equals(to_isbn10('978-826497'), None) # (bug #14) assert_equals(to_isbn10('isbn 0-8264-9752-7'), '0826497527') assert_equals(to_isbn10('isbn 979-10-90636-07-1'), None) assert_equals(to_isbn10('isbn 978-0-8264-9752-9'), '0826497527') @@ -76,11 +77,12 @@ """Test transformation of ISBN to ISBN-13.""" assert_equals(to_isbn13('0826497527'), '9780826497529') assert_equals(to_isbn13('9780826497529'), '9780826497529') - assert_equals(to_isbn13('0826497520'), None) # ISBN10 not valid + assert_equals(to_isbn13('0826497520'), None) # ISBN10 not valid assert_equals(to_isbn13('08X6497527'), None) - assert_equals(to_isbn13('91-43-01019-9'), '9789143010190') # (bug #14) + assert_equals(to_isbn13('91-43-01019-9'), '9789143010190') # (bug #14) assert_equals(to_isbn13('isbn 91-43-01019-9'), '9789143010190') - assert_equals(to_isbn13('asd isbn 979-10-90636-07-1 blabla'), '9791090636071') + assert_equals( + to_isbn13('asd isbn 979-10-90636-07-1 blabla'), '9791090636071') def test_clean(): @@ -118,17 +120,23 @@ def test_get_canonical_isbn(): """Test the extraction of canonical ISBN from ISBN-like string.""" - assert_equals(get_canonical_isbn('0826497527', output='bouth'), - '0826497527') + assert_equals( + get_canonical_isbn( + '0826497527', output='bouth'), '0826497527') assert_equals(get_canonical_isbn('0826497527'), '0826497527') - assert_equals(get_canonical_isbn('0826497527', output='isbn10'), - '0826497527') - assert_equals(get_canonical_isbn('0826497527', output='isbn13'), - '9780826497529') - assert_equals(get_canonical_isbn('ISBN 0826497527', output='isbn13'), - '9780826497529') - assert_equals(get_canonical_isbn('ISBN 0826497527', output='NOOPTION'), - None) + assert_equals( + get_canonical_isbn( + '0826497527', output='isbn10'), '0826497527') + assert_equals( + get_canonical_isbn( + '0826497527', output='isbn13'), '9780826497529') + assert_equals( + get_canonical_isbn( + 'ISBN 0826497527', output='isbn13'), + '9780826497529') + assert_equals( + get_canonical_isbn( + 'ISBN 0826497527', output='NOOPTION'), None) assert_equals(get_canonical_isbn('0826497520'), None) assert_equals(get_canonical_isbn('9780826497529'), '9780826497529') assert_equals(get_canonical_isbn('9780826497520'), None) diff -Nru isbnlib-3.5.6/isbnlib/test/test_data.py isbnlib-3.9.3/isbnlib/test/test_data.py --- isbnlib-3.5.6/isbnlib/test/test_data.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_data.py 2018-10-05 11:18:35.000000000 +0000 @@ -13,52 +13,53 @@ def test_stdmeta(): """Test the transformation of raw records into standard metadata.""" # test stdmeta from data - r={ - 'ISBN-13': u('9780123456789 '), - 'Title': u('Bla. Bla /Title .'), - 'Publisher': u(''), - 'Year': u('2000'), - 'Language': u('en'), - 'Authors': [u('author1. mba'), u('author2 ')] - } - R={ - 'ISBN-13': u('9780123456789'), - 'Title': u('Bla. Bla /Title'), - 'Publisher': u(''), - 'Year': u('2000'), - 'Language': u('en'), - 'Authors': [u('author1. mba'), u('author2')] - } - A={ - 'ISBN-13': u('9780123456789 '), - 'Title': b'Bla. Bla /Title .', - 'Publisher': u(''), - 'Year': b'2000', - 'Language': u('en'), - 'Authors': [u('author1. mba'), u('author2 ')] - } - B={ - 'ISBN-13': u('9780123456789'), - 'Title': u('Bla. Bla /Title .'), - 'Publisher': u(''), - 'Year': u('2000'), - 'Language': u('en'), - 'Authors': u('author1') - } + r = { + 'ISBN-13': u('9780123456789 '), + 'Title': u('Bla. Bla /Title .'), + 'Publisher': u(''), + 'Year': u('2000'), + 'Language': u('en'), + 'Authors': [u('author1. mba'), u('author2 ')] + } + R = { + 'ISBN-13': u('9780123456789'), + 'Title': u('Bla. Bla /Title'), + 'Publisher': u(''), + 'Year': u('2000'), + 'Language': u('en'), + 'Authors': [u('author1. mba'), u('author2')] + } + A = { + 'ISBN-13': u('9780123456789 '), + 'Title': b'Bla. Bla /Title .', + 'Publisher': u(''), + 'Year': b'2000', + 'Language': u('en'), + 'Authors': [u('author1. mba'), u('author2 ')] + } + B = { + 'ISBN-13': u('9780123456789'), + 'Title': u('Bla. Bla /Title .'), + 'Publisher': u(''), + 'Year': u('2000'), + 'Language': u('en'), + 'Authors': u('author1') + } assert_equals(stdmeta(r), R) assert_equals(stdmeta(R), R) assert_raises(Exception, stdmeta, A) assert_raises(Exception, stdmeta, B) + def test_metaclass(): """Test the creation of a Metadata class from raw records.""" - R={ - 'ISBN-13': u('9780123456789'), - 'Title': u('Bla. Bla /Title'), - 'Publisher': u(''), - 'Year': u('2000'), - 'Language': u('en'), - 'Authors': [u('author1. mba'), u('author2')] - } + R = { + 'ISBN-13': u('9780123456789'), + 'Title': u('Bla. Bla /Title'), + 'Publisher': u(''), + 'Year': u('2000'), + 'Language': u('en'), + 'Authors': [u('author1. mba'), u('author2')] + } dt = Metadata(R) assert_equals(dt.value, R) diff -Nru isbnlib-3.5.6/isbnlib/test/test_doi2tex.py isbnlib-3.9.3/isbnlib/test/test_doi2tex.py --- isbnlib-3.5.6/isbnlib/test/test_doi2tex.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_doi2tex.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- # flake8: noqa # pylint: skip-file - """ nose tests """ diff -Nru isbnlib-3.5.6/isbnlib/test/test_editions.py isbnlib-3.9.3/isbnlib/test/test_editions.py --- isbnlib-3.5.6/isbnlib/test/test_editions.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_editions.py 2018-10-05 11:18:35.000000000 +0000 @@ -7,25 +7,37 @@ from .._exceptions import NotRecognizedServiceError, NotValidISBNError from .._ext import editions - # nose tests -def test_editions1(): - """Test the 'editions' service.""" - assert_equals(len(editions('9780156001311', service='wcat')) > 19, True) + +def test_editions_openl(): + """Test the 'openl editions' service.""" + assert_equals(len(editions('9780099536017', service='openl')) > 4, True) + + +def test_editions_thingl(): + """Test the 'thingl editions' service.""" assert_equals(len(editions('9780151446476', service='thingl')) > 19, True) + + +def test_editions_any(): + """Test the 'any editions' service.""" assert_equals(len(editions('9780151446476', service='any')) > 19, True) + + +def test_editions_merge(): + """Test the 'merge editions' service.""" assert_equals(len(editions('9780151446476', service='merge')) > 19, True) @raises(NotValidISBNError) -def test_editions2(): +def test_editions_NotValidISBNError(): """Test the 'editions' service error detection (NotValidISBNError).""" editions('978') @raises(NotRecognizedServiceError) -def test_editions3(): +def test_editions_NotRecognizedServiceError(): """Test the 'editions' service error detection (NotRecognizedServiceError).""" editions('9780156001311', service='xxx') diff -Nru isbnlib-3.5.6/isbnlib/test/test_ext.py isbnlib-3.9.3/isbnlib/test/test_ext.py --- isbnlib-3.5.6/isbnlib/test/test_ext.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_ext.py 2018-10-05 11:18:35.000000000 +0000 @@ -5,7 +5,6 @@ from nose.tools import assert_equals, assert_raises from .._ext import mask, editions, isbn_from_words, doi, desc, cover - # nose tests @@ -29,7 +28,8 @@ assert_equals(mask('9789993075899'), '978-99930-75-89-9') assert_equals(mask('0-330284983'), '0-330-28498-3') assert_equals(mask('9791090636071'), '979-10-90636-07-1') - assert_equals(mask('9786131796364'), '978-613-1-79636-4') # <-- prefix with 1 rule + assert_equals( + mask('9786131796364'), '978-613-1-79636-4') # <-- prefix with 1 rule assert_equals(mask('isbn 979-10-90636-07-1'), '979-10-90636-07-1') assert_raises(Exception, mask, '') assert_raises(Exception, mask, '9786') @@ -56,9 +56,9 @@ def test_cover(): """Test 'cover' command.""" - assert_equals(cover('9780156001311')[1][:13], '9780156001311') # <-- no size 2 (in most areas) but size 1 - assert_equals(cover('9780000000000'), None) # <-- invalid ISBN - assert_equals(cover('9781408835029')[1][:13], '9781408835029') - assert_equals(cover('9789727576807')[1], None) # <-- no image of any size - - + assert_equals(len(repr(cover('9780156001311'))) > 50, True) + assert_equals(cover('9780000000000'), None) # <-- invalid ISBN + assert_equals(len(repr(cover('9781408835029'))) > 50, True) + assert_equals( + len(repr(cover('9789727576807'))) < 50, + True) # <-- no image of any size diff -Nru isbnlib-3.5.6/isbnlib/test/test_files.py isbnlib-3.9.3/isbnlib/test/test_files.py --- isbnlib-3.5.6/isbnlib/test/test_files.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_files.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- # flake8: noqa # pylint: skip-file - """ nose tests """ @@ -17,28 +16,34 @@ TESTFILE = './ç-deleteme.pdf' if WINDOWS else '/tmp/海明威-deleteme.pdf' NEW_BASENAME = 'ç-deleteme-PLEASE.pdf' if WINDOWS else '海明威-deleteme-PLEASE.pdf' else: - print("Your default locale encoding (%s) doesn't allow unicode filenames!" % ENCODING) + print("Your default locale encoding (%s) doesn't allow unicode filenames!" + % ENCODING) TESTFILE = './deleteme.pdf' NEW_BASENAME = 'deleteme-PLEASE.pdf' + def setup_module(): with open(TESTFILE, 'w') as f: - f.write('ooo') + f.write('ooo') os.chdir(os.path.dirname(TESTFILE)) + def teardown_module(): os.remove(os.path.join(os.path.dirname(TESTFILE), NEW_BASENAME)) + def test_isfile(): """Test if a path is a file.""" f = File(TESTFILE) assert f.isfile(TESTFILE) == True + def test_exists(): """Test if a path is a file or a directory.""" f = File(TESTFILE) assert f.exists(TESTFILE) == True + def test_validate(): """Test if a string is a valid filename for 'ren' command.""" f = File(TESTFILE) diff -Nru isbnlib-3.5.6/isbnlib/test/test_fmt.py isbnlib-3.9.3/isbnlib/test/test_fmt.py --- isbnlib-3.5.6/isbnlib/test/test_fmt.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_fmt.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,31 +1,31 @@ # -*- coding: utf-8 -*- # flake8: noqa # pylint: skip-file - """ nose tests """ from nose.tools import assert_equals from ..dev._bouth23 import u -from ..dev._fmt import fmtbib - +from ..dev._fmt import _fmtbib canonical = { - 'ISBN-13': u('9780123456789'), - 'Title': u('A book about nothing'), - 'Publisher': u('No Paper Press'), - 'Year': u('2000'), - 'Language': u('en'), - 'Authors': [u('John Smith'), u('José Silva')] - } + 'ISBN-13': u('9780123456789'), + 'Title': u('A book about nothing'), + 'Publisher': u('No Paper Press'), + 'Year': u('2000'), + 'Language': u('en'), + 'Authors': [u('John Smith'), u('José Silva')] +} + def test_fmtbib(): """Test the formating into several bibliographic formats.""" - assert_equals(len(fmtbib("bibtex", canonical)), 182) - assert_equals(len(fmtbib("labels", canonical)), 158) - assert_equals(len(fmtbib("endnote", canonical)), 103) - assert_equals(len(fmtbib("msword", canonical)), 485) - assert_equals(len(fmtbib("json", canonical)), 229) - assert_equals(len(fmtbib("refworks", canonical)), 130) - assert_equals(len(fmtbib("opf", canonical)), 861) + assert_equals(len(_fmtbib("bibtex", canonical)), 182) + assert_equals(len(_fmtbib("labels", canonical)), 158) + assert_equals(len(_fmtbib("endnote", canonical)), 103) + assert_equals(len(_fmtbib("msword", canonical)), 485) + assert_equals(len(_fmtbib("json", canonical)), 229) + assert_equals(len(_fmtbib("csl", canonical)), 253) + assert_equals(len(_fmtbib("refworks", canonical)), 130) + assert_equals(len(_fmtbib("opf", canonical)), 861) diff -Nru isbnlib-3.5.6/isbnlib/test/test_goom.py isbnlib-3.9.3/isbnlib/test/test_goom.py --- isbnlib-3.5.6/isbnlib/test/test_goom.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_goom.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- # flake8: noqa # pylint: skip-file - """ nose tests """ @@ -12,4 +11,5 @@ def test_goom(): """Test the Google's Multiple Books service.""" - assert_equals(len(repr(goom.query('the old man and the sea'))) > 1000, True) + assert_equals(len(repr(goom.query('the old man and the sea'))) > 1000, + True) diff -Nru isbnlib-3.5.6/isbnlib/test/test_helpers.py isbnlib-3.9.3/isbnlib/test/test_helpers.py --- isbnlib-3.5.6/isbnlib/test/test_helpers.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_helpers.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- # flake8: noqa # pylint: skip-file - """ nose tests """ @@ -12,9 +11,15 @@ def test_last_first(): """Test the parsing of author's name into (Surname, First Name).""" - assert_equals(last_first("Surname, First Name"), {"last": "Surname", "first": "First Name"}) - assert_equals(last_first("First Name Surname"), {"last": "Surname", "first": "First Name"}) - assert_equals(last_first("Surname1, First1 and Sur2, First2"), {"last": "Surname1", "first": "First1 and Sur2, First2"}) + assert_equals(last_first("Surname, First Name"), + {"last": "Surname", + "first": "First Name"}) + assert_equals(last_first("First Name Surname"), + {"last": "Surname", + "first": "First Name"}) + assert_equals(last_first("Surname1, First1 and Sur2, First2"), + {"last": "Surname1", + "first": "First1 and Sur2, First2"}) def test_cutoff_tokens(): @@ -24,14 +29,29 @@ def test_parse_placeholders(): """Test the parsing of placeholders.""" - assert_equals(parse_placeholders('{isbn}_akaj_{name}'), ['{isbn}', '{name}']) + assert_equals(parse_placeholders('{isbn}_akaj_{name}'), ['{isbn}', '{name}' + ]) def test_fake_isbn(): """Test the 'fake_isbn' function.""" - assert_equals(fake_isbn(' Hello?? Wer, ! ksDf: asdf. ; '), '1111006407537') - assert_equals(fake_isbn(' Hello?? Wer, ! ksDf: asdf. ; ', author=''), '1108449680873') - assert_equals(fake_isbn(' Hello?? Wer, ! ksDf: asdf. ; ', author=' '), '1108449680873') - assert_equals(fake_isbn(' Hello?? Wer, ! ksDf: asdf. ; ', author='', publisher=''), '1181593982422') - assert_equals(fake_isbn(' Hello?? Wer, ! ksDf: asdf. ; ', author='a', publisher='K'), '1895031085488') - assert_equals(fake_isbn(' Hello?? Wer, ! ksDf: asdf. ; ', author='A', publisher='k'), '1895031085488') + assert_equals(fake_isbn(' Hello?? Wer, ! ksDf: asdf. ; '), + '1111006407537') + assert_equals(fake_isbn(' Hello?? Wer, ! ksDf: asdf. ; ', + author=''), + '1108449680873') + assert_equals(fake_isbn(' Hello?? Wer, ! ksDf: asdf. ; ', + author=' '), + '1108449680873') + assert_equals(fake_isbn(' Hello?? Wer, ! ksDf: asdf. ; ', + author='', + publisher=''), + '1181593982422') + assert_equals(fake_isbn(' Hello?? Wer, ! ksDf: asdf. ; ', + author='a', + publisher='K'), + '1895031085488') + assert_equals(fake_isbn(' Hello?? Wer, ! ksDf: asdf. ; ', + author='A', + publisher='k'), + '1895031085488') diff -Nru isbnlib-3.5.6/isbnlib/test/test_info.py isbnlib-3.9.3/isbnlib/test/test_info.py --- isbnlib-3.5.6/isbnlib/test/test_info.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_info.py 2018-10-05 11:18:35.000000000 +0000 @@ -2,7 +2,6 @@ # flake8: noqa # pylint: skip-file - from .._infogroup import infogroup from .._ext import info from nose.tools import assert_equals, assert_raises @@ -16,16 +15,15 @@ assert_equals(infogroup('7500117019'), "China, People's Republic") assert_equals(infogroup('7-5001-1701-9'), "China, People's Republic") assert_equals(infogroup('9524712946'), 'Finland') - assert_equals(infogroup('0330284983'), - 'English language') - assert_equals(infogroup('3796519008'), - 'German language') + assert_equals(infogroup('0330284983'), 'English language') + assert_equals(infogroup('3796519008'), 'German language') assert_raises(Exception, infogroup, '92xxxxxxxxxxx') assert_raises(Exception, infogroup, '') assert_equals(infogroup('9791090636071'), 'France') assert_equals(infogroup('9786131796364'), 'Mauritius') assert_equals(infogroup('9789992158104'), 'Qatar') + def test_ext_info(): """Test 'info' language/country function.""" assert_equals(info('9524712946'), 'Finland') diff -Nru isbnlib-3.5.6/isbnlib/test/test_metadata.py isbnlib-3.9.3/isbnlib/test/test_metadata.py --- isbnlib-3.5.6/isbnlib/test/test_metadata.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_metadata.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- # flake8: noqa # pylint: skip-file - """nose tests for metadata.""" from random import randrange @@ -14,24 +13,21 @@ """Test the query of metadata with 'low level' queries.""" # test query from metadata assert_raises(Exception, query, '9781849692341', 'goog') - assert_raises(Exception, query, '9781849692342', 'goob') - assert_raises(Exception, query, '9781849692341', 'wcat') - assert_equals(len(repr(query('9780321534965', 'wcat'))) > 150, True) - assert_equals(len(repr(query('9780321534965'))) > 150, True) - assert_equals(len(repr(query('9780321534965', 'merge'))) > 150, True) - assert_equals(len(repr(query('9780321534965', 'goob'))) > 150, True) - assert_equals(len(repr(query('9789934015960'))) > 150, True) - assert_equals(len(repr(query(u'9781118241257'))) > 149, True) - assert_raises(Exception, query, '9780000000', 'wcat', None) - assert_raises(Exception, query, randrange(0, 1000000), 'wcat') + assert_raises(Exception, query, '9781849692343', 'goob') + assert_raises(Exception, query, '9789934015960', 'goob') + assert_equals(len(repr(query('9780321534965'))) > 100, True) + assert_equals(len(repr(query('9780321534965', 'goob'))) > 100, True) + #assert_equals(len(repr(query('9789934015960'))) > 100, True) + assert_equals(len(repr(query(u'9781118241257'))) > 100, True) + assert_raises(Exception, query, '9780000000', 'goob', None) + assert_raises(Exception, query, randrange(0, 1000000), 'goob') def test_ext_meta(): """Test the query of metadata with 'high level' meta function.""" # test meta from core - assert_equals(len(repr(meta('9780321534965', 'wcat'))) > 150, True) - assert_equals(len(repr(meta('9780321534965', 'merge'))) > 150, True) - assert_equals(len(repr(meta('9780321534965'))) > 150, True) - assert_raises(Exception, meta, '9780000000', 'wcat', None) - assert_raises(Exception, meta, randrange(0, 1000000), 'wcat') - assert_raises(Exception, meta, '9781849692342', 'goob', None) + assert_equals(len(repr(meta('9780321534965', 'goob'))) > 100, True) + assert_equals(len(repr(meta('9780321534965'))) > 100, True) + assert_raises(Exception, meta, '9780000000', 'goob', None) + assert_raises(Exception, meta, randrange(0, 1000000), 'goob') + assert_raises(Exception, meta, '9781849692343', 'goob', None) diff -Nru isbnlib-3.5.6/isbnlib/test/test_openl.py isbnlib-3.9.3/isbnlib/test/test_openl.py --- isbnlib-3.5.6/isbnlib/test/test_openl.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_openl.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- # flake8: noqa # pylint: skip-file - - """ nose tests """ diff -Nru isbnlib-3.5.6/isbnlib/test/test_rename.py isbnlib-3.9.3/isbnlib/test/test_rename.py --- isbnlib-3.5.6/isbnlib/test/test_rename.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_rename.py 2018-10-05 11:18:35.000000000 +0000 @@ -8,7 +8,6 @@ from .._ext import ren from ..dev._bouth23 import b2u3, u from ..dev.helpers import File, cwdfiles - """ nose tests """ @@ -16,7 +15,8 @@ WINDOWS = os.name == 'nt' ENCODING = locale.getpreferredencoding() if ENCODING != 'UTF-8': - print("Your default locale encoding (%s) doesn't allow unicode filenames!" % ENCODING) + print("Your default locale encoding (%s) doesn't allow unicode filenames!" + % ENCODING) print("=> Some tests could fail.") TESTFILE_1 = './ç-deleteme.pdf' if WINDOWS else '/tmp/ç-deleteme.pdf' @@ -48,7 +48,8 @@ with open(fn, 'w') as f: f.write(b2u3('ooo') + b2u3(fn)) except UnicodeEncodeError: - print("Your default locale (%s) doesn't allow non-ascii filenames!" % locale.CODESET) + print("Your default locale (%s) doesn't allow non-ascii filenames!" + % locale.CODESET) def delete_files(fnpatt): @@ -60,7 +61,8 @@ def setup_module(): # create_files([u(TESTFILE_1), u(TESTFILE_2)]) os.chdir(os.path.dirname(TESTFILE_1)) - create_files(FISBN+[F11]) + #create_files(FISBN + [F11]) + create_files([F1]) def teardown_module(): @@ -70,8 +72,8 @@ def test_ren(): """Test 'high level' ren function.""" ren(F1) - assert_equals('Knuth2008_The Art Of Computer Programming_9780321534965.pdf' in cwdfiles("*.pdf"), True) + assert_equals('Knuth2008_The Art Of Computer Programming_9780321534965.pdf' + in cwdfiles("*.pdf"), True) # create_files([F5]) # ren(F5) # assert_equals('Campos2011_Emergências obstétricas_9789727576807.pdf' in cwdfiles("*.pdf"), True) - diff -Nru isbnlib-3.5.6/isbnlib/test/test_unicode_to_utf8tex.py isbnlib-3.9.3/isbnlib/test/test_unicode_to_utf8tex.py --- isbnlib-3.5.6/isbnlib/test/test_unicode_to_utf8tex.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_unicode_to_utf8tex.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- # flake8: noqa # pylint: skip-file - """ nose tests """ @@ -13,4 +12,5 @@ def test_unicode_to_utf8tex(): """Test 'unicode_to_utf8tex' identity transformation.""" assert_equals(unicode_to_utf8tex(u"\u00E2 \u00F5"), b"\^{a}\space \~{o}") - assert_equals(unicode_to_utf8tex(u"\u00E2 \u00F5", (b"\\space ",)), b"\^{a} \~{o}") + assert_equals(unicode_to_utf8tex(u"\u00E2 \u00F5", + (b"\\space ", )), b"\^{a} \~{o}") diff -Nru isbnlib-3.5.6/isbnlib/test/test_vias.py isbnlib-3.9.3/isbnlib/test/test_vias.py --- isbnlib-3.5.6/isbnlib/test/test_vias.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_vias.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- -# flake8: noqa -# pylint: skip-file - -""" -nose tests -""" - -import os - -from .. import _merge as merge -from nose.tools import assert_equals - - -WINDOWS = os.name == 'nt' - - -def test_vias_modes(): - """Test 'vias' several modes of operation.""" - if WINDOWS: - # appveyor doesn't allow! - return - assert_equals(len(repr(merge.query('9780321534965', 'parallel'))) > 170, True) - assert_equals(len(repr(merge.query('9780321534965', 'multi'))) > 170, True) - assert_equals(len(repr(merge.query('9780321534965', 'serial'))) > 170, True) - -def test_vias_cache_cleanning(): - """Test 'vias' cache cleanning for serial.""" - # test if the secondary cache (cache in vias) does clears... sequentially - assert_equals(len(repr(merge.query('9781484206546', 'serial'))) < 20, True) # NO METADATA - assert_equals(len(repr(merge.query('9780321534965', 'serial'))) > 170, True) - assert_equals(len(repr(merge.query('9781484206546', 'serial'))) < 20, True) # NO METADATA diff -Nru isbnlib-3.5.6/isbnlib/test/test_webservice.py isbnlib-3.9.3/isbnlib/test/test_webservice.py --- isbnlib-3.5.6/isbnlib/test/test_webservice.py 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_webservice.py 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# flake8: noqa +# pylint: skip-file +""" +nose tests +""" + +from ..dev.webservice import query as wsquery +from nose.tools import assert_equals + + +def test_webservice(): + """Test that values can be passed to a WebService query.""" + assert_equals(len(repr(wsquery("http://example.org", values={'some': 'values'}))) > 0, + True) diff -Nru isbnlib-3.5.6/isbnlib/test/test_words.py isbnlib-3.9.3/isbnlib/test/test_words.py --- isbnlib-3.5.6/isbnlib/test/test_words.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/test/test_words.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- # flake8: noqa # pylint: skip-file - """ nose tests """ @@ -13,4 +12,5 @@ def test_words(): """Test 'isbn_from_words' function.""" assert_equals(len(words.goos('the old man and the sea')), 13) + assert_equals(len(words.goos('Camões Lusíadas')), 13) # assert_equals(words.goos('-ISBN -isbn') in ('9781364200329', None), True) diff -Nru isbnlib-3.5.6/isbnlib/_thinged.py isbnlib-3.9.3/isbnlib/_thinged.py --- isbnlib-3.5.6/isbnlib/_thinged.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_thinged.py 2018-10-05 11:18:35.000000000 +0000 @@ -29,10 +29,9 @@ def query(isbn): - """Query the worldcat.org service for related ISBNs.""" - data = wquery(SERVICE_URL.format(isbn=isbn), - user_agent=UA, - parser=parser_thinged) - if not data: # pragma: no cover + """Query the ThingISBN service for related ISBNs.""" + data = wquery( + SERVICE_URL.format(isbn=isbn), user_agent=UA, parser=parser_thinged) + if not data: # pragma: no cover LOGGER.debug('No data from ThingISBN for isbn %s', isbn) return data diff -Nru isbnlib-3.5.6/isbnlib/_wcated.py isbnlib-3.9.3/isbnlib/_wcated.py --- isbnlib-3.5.6/isbnlib/_wcated.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_wcated.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -"""Query the worldcat.org xID service for related ISBNs.""" - -import logging -from ast import literal_eval - -from .dev._exceptions import DataWrongShapeError, NoDataForSelectorError -from .dev.webquery import query as wquery - -LOGGER = logging.getLogger(__name__) -UA = 'isbnlib (gzip)' -SERVICE_URL = 'http://xisbn.worldcat.org/webservices/xid/isbn/{isbn}?'\ - 'method=getEditions&format=python' - - -def _editions(isbn, data): - """Return the records from the parsed response.""" - # check status - try: - status = data['stat'] - if status != 'ok': - raise # pragma: no cover - except: # pragma: no cover - LOGGER.debug('DataWrongShapeError for %s with status %s', - isbn, status) - raise DataWrongShapeError("status: '%s' for isbn %s" % (status, isbn)) - # put the selected data in records - try: - recs = [ib['isbn'][0] for ib in data['list']] - except: # pragma: no cover - LOGGER.debug('NoDataForSelectorError for %s', isbn) - raise NoDataForSelectorError(isbn) - return recs - - -def query(isbn): - """Query the worldcat.org service for related ISBNs.""" - data = wquery(SERVICE_URL.format(isbn=isbn), - user_agent=UA, - parser=literal_eval) - return _editions(isbn, data) diff -Nru isbnlib-3.5.6/isbnlib/_wcat.py isbnlib-3.9.3/isbnlib/_wcat.py --- isbnlib-3.5.6/isbnlib/_wcat.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/isbnlib/_wcat.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -# -*- coding: utf-8 -*- -"""Query the worldcat.org xID service for metadata.""" - -import logging - -from .dev import stdmeta -from .dev._bouth23 import u -from .dev._exceptions import (DataWrongShapeError, ISBNNotConsistentError, - NoDataForSelectorError, RecordMappingError) -from .dev.webquery import query as wquery - -UA = 'isbnlib (gzip)' -SERVICE_URL = 'http://xisbn.worldcat.org/webservices/xid/isbn/{isbn}?'\ - 'method=getMetadata&format=json&fl=title,author,year,publisher,lang' -LOGGER = logging.getLogger(__name__) - - -def _mapper(isbn, records): - """Mapp: canonical <- records.""" - # canonical: ISBN-13, Title, Authors, Publisher, Year, Language - try: - canonical = {} - canonical['ISBN-13'] = u(isbn) - canonical['Title'] = records.get('title', u('')).replace(' :', ':') - buf = records.get('author', u('')) - canonical['Authors'] = [x.strip('. ') for x in buf.split(';')] - canonical['Publisher'] = records.get('publisher', u('')) - canonical['Year'] = records.get('year', u('')) - canonical['Language'] = records.get('lang', u('')) - except: # pragma: no cover - LOGGER.debug("RecordMappingError for %s with data %s", isbn, records) - raise RecordMappingError(isbn) - # call stdmeta for extra cleanning and validation - return stdmeta(canonical) - - -def _records(isbn, data): - """Classify (canonically) the parsed data.""" - # check status - try: - status = data['stat'] - if status != 'ok': - raise - except: - LOGGER.debug('DataWrongShapeError for %s with status %s', - isbn, status) - raise DataWrongShapeError("status: '%s' for isbn %s" % (status, isbn)) - # put the selected data in records - try: - recs = data['list'][0] - except: # pragma: no cover - LOGGER.debug('NoDataForSelectorError for %s', isbn) - raise NoDataForSelectorError(isbn) - # consistency check (isbn request = isbn response) - if recs: - ids = recs.get('isbn', '') - if isbn not in repr(ids): # pragma: no cover - LOGGER.debug('ISBNNotConsistentError for %s (%s)', isbn, repr(ids)) - raise ISBNNotConsistentError("%s not in %s" % (isbn, repr(ids))) - # map canonical <- records - return _mapper(isbn, recs) - - -def query(isbn): - """Query the worldcat.org service for metadata.""" - data = wquery(SERVICE_URL.format(isbn=isbn), user_agent=UA) - return _records(isbn, data) diff -Nru isbnlib-3.5.6/LICENSE isbnlib-3.9.3/LICENSE --- isbnlib-3.5.6/LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/LICENSE 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff -Nru isbnlib-3.5.6/LICENSE-LGPL.txt isbnlib-3.9.3/LICENSE-LGPL.txt --- isbnlib-3.5.6/LICENSE-LGPL.txt 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/LICENSE-LGPL.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff -Nru isbnlib-3.5.6/MANIFEST.in isbnlib-3.9.3/MANIFEST.in --- isbnlib-3.5.6/MANIFEST.in 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/MANIFEST.in 2018-10-05 11:18:35.000000000 +0000 @@ -1,2 +1,3 @@ include *.txt include *.rst +include *.coveragerc diff -Nru isbnlib-3.5.6/.mention-bot isbnlib-3.9.3/.mention-bot --- isbnlib-3.5.6/.mention-bot 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/.mention-bot 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,3 @@ +{ + "maxReviewers": 1 +} diff -Nru isbnlib-3.5.6/.noserc isbnlib-3.9.3/.noserc --- isbnlib-3.5.6/.noserc 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/.noserc 2018-10-05 11:18:35.000000000 +0000 @@ -1,2 +1,6 @@ [nosetests] verbosity=1 +with-coverage=1 +cover-package=isbnlib +cover-branches=1 +cover-min-percentage=99 diff -Nru isbnlib-3.5.6/.pep257 isbnlib-3.9.3/.pep257 --- isbnlib-3.5.6/.pep257 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/.pep257 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,2 @@ +[pep257] +ignore=D203 Binary files /tmp/tmpu7yK9M/RpOPkkJAZP/isbnlib-3.5.6/PLUGIN.zip and /tmp/tmpu7yK9M/uGP3_Ilz_V/isbnlib-3.9.3/PLUGIN.zip differ diff -Nru isbnlib-3.5.6/.pylintrc isbnlib-3.9.3/.pylintrc --- isbnlib-3.5.6/.pylintrc 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/.pylintrc 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,379 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS,_data,test + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Use multiple processes to speed up Pylint. +jobs=1 + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Allow optimization of some AST trees. This will activate a peephole AST +# optimizer, which will apply various small optimizations. For instance, it can +# be used to obtain the result of joining multiple strings with the addition +# operator. Joining a lot of strings can lead to a maximum recursion error in +# Pylint and this flag can prevent that. It has one side effect, the resulting +# AST will be different than the one from reality. +optimize-ast=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=cmp-method,round-builtin,suppressed-message,old-division,hex-method,coerce-builtin,import-star-module-level,long-builtin,cmp-builtin,backtick,setslice-method,raw_input-builtin,unichr-builtin,no-absolute-import,standarderror-builtin,file-builtin,next-method-called,getslice-method,reduce-builtin,indexing-exception,xrange-builtin,buffer-builtin,dict-view-method,reload-builtin,coerce-method,print-statement,basestring-builtin,nonzero-method,input-builtin,range-builtin-not-iterating,useless-suppression,old-ne-operator,long-suffix,parameter-unpacking,raising-string,unpacking-in-except,map-builtin-not-iterating,apply-builtin,unicode-builtin,delslice-method,filter-builtin-not-iterating,zip-builtin-not-iterating,intern-builtin,using-cmp-argument,metaclass-assignment,oct-method,old-octal-literal,dict-iter-method,execfile-builtin,old-raise-syntax,global-statement,file-ignored,invalid-name + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +reports=yes + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_$|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_,_cb + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + + +[SPELLING] + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[BASIC] + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# Regular expression matching correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for argument names +argument-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for function names +function-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for method names +method-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for attribute names +attr-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Naming hint for class names +class-name-hint=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression matching correct inline iteration names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Naming hint for inline iteration names +inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ + +# Regular expression matching correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for variable names +variable-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct class attribute names +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Naming hint for class attribute names +class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Regular expression matching correct constant names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Naming hint for constant names +const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression matching correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Naming hint for module names +module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + + +[ELIF] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=100 + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma,dict-separator + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). This supports can work +# with qualified names. +ignored-classes= + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of boolean expressions in a if statement +max-bool-expr=5 + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict,_fields,_replace,_source,_make + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=optparse + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception diff -Nru isbnlib-3.5.6/README.rst isbnlib-3.9.3/README.rst --- isbnlib-3.5.6/README.rst 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/README.rst 2018-10-05 11:18:35.000000000 +0000 @@ -1,25 +1,32 @@ -.. image:: https://sourcegraph.com/api/repos/github.com/xlcnd/isbnlib/.badges/status.svg +.. image:: https://img.shields.io/badge/Sourcegraph-Status-blue.svg :target: https://sourcegraph.com/github.com/xlcnd/isbnlib :alt: Graph .. image:: https://readthedocs.org/projects/isbnlib/badge/?version=latest - :target: http://isbnlib.readthedocs.org/en/latest/ + :target: https://isbnlib.readthedocs.org/en/latest/ :alt: Documentation Status -.. image:: https://coveralls.io/repos/xlcnd/isbnlib/badge.svg?branch=v3.5.6 - :target: https://coveralls.io/r/xlcnd/isbnlib?branch=v3.5.6 - :alt: Coverage +.. image:: https://coveralls.io/repos/github/xlcnd/isbnlib/badge.svg?branch=v3.9.3 + :target: https://coveralls.io/github/xlcnd/isbnlib?branch=v3.9.3 + :alt: Coverage Status -.. image:: https://travis-ci.org/xlcnd/isbnlib.svg?branch=v3.5.6 +.. image:: https://travis-ci.org/xlcnd/isbnlib.svg?branch=v3.9.3 :target: https://travis-ci.org/xlcnd/isbnlib :alt: Built Status -.. image:: https://ci.appveyor.com/api/projects/status/github/xlcnd/isbnlib?branch=v3.5.6&svg=true +.. image:: https://ci.appveyor.com/api/projects/status/github/xlcnd/isbnlib?branch=v3.9.3&svg=true :target: https://ci.appveyor.com/project/xlcnd/isbnlib :alt: Windows Built Status +Warning +======= + + The service xISBN was decommissioned (see issue 51_)! + + + Info ==== @@ -30,23 +37,23 @@ This short version, is suitable to be include as a dependency in other projects. Has a straightforward setup and a very easy programmatic api. +Runs on py27, py34, py35, py36 and py37. Typical usage (as library): .. code-block:: python - #!/usr/bin/env python import isbnlib ... -Note +ISBN ---- The official form of an ISBN is something like ``ISBN 979-10-90636-07-1``. However for most applications only the numbers are important, you can always 'masked' them if you need (see below). - This library works mainly with 'striped' ISBNs (only numbers and X) like '0826497527'. You can + This library works mainly with 'striped' ISBNs (only digits and X) like '0826497527'. You can strip an ISBN-like string by using ``canonical(isbnlike)``. You can 'mask' the ISBN by using ``mask(isbn)``. So in the examples below, when you see 'isbn' in the argument, it is a 'striped' ISBN, when the argument is an 'isbnlike' it is a string @@ -61,8 +68,8 @@ (because '9786610326266' follows the rules of an ISBN). But the situation is even murkier, try ``meta('9786610326266')`` and you will see that this ISBN was already used! - If possible, work with ISBNs in the isbn-13 format (since 2007, only are issued ISBNs in the isbn-13 - format). You can always convert isbn-10 to isbn-13, but **not** the reverse. + If possible, work with ISBNs in the isbn-13 format (since 2007, only are issued ISBNs + in the isbn-13 format). You can always convert isbn-10 to isbn-13, but **not** the reverse. Read more about ISBN at isbn-international.org_ or wikipedia_. @@ -71,84 +78,82 @@ -------------- ``is_isbn10(isbn10like)`` - Validates as ISBN-10. + Validates as ISBN-10. ``is_isbn13(isbn13like)`` - Validates as ISBN-13. + Validates as ISBN-13. ``to_isbn10(isbn13)`` - Transforms isbn-13 to isbn-10. + Transforms isbn-13 to isbn-10. ``to_isbn13(isbn10)`` - Transforms isbn-10 to isbn-13. + Transforms isbn-10 to isbn-13. ``canonical(isbnlike)`` - Keeps only numbers and X. You will get strings like `9780321534965` and `954430603X`. + Keeps only digits and X. You will get strings like `9780321534965` and `954430603X`. ``clean(isbnlike)`` - Cleans ISBN (only legal characters). + Cleans ISBN (only legal characters). ``notisbn(isbnlike, level='strict')`` - Check with the goal to invalidate isbn-like. + Check with the goal to invalidate isbn-like. ``get_isbnlike(text, level='normal')`` - Extracts all substrings that seem like ISBNs (very useful for scraping). + Extracts all substrings that seem like ISBNs (very useful for scraping). ``get_canonical_isbn(isbnlike, output='bouth')`` - Extracts ISBNs and transform them to the canonical form. + Extracts ISBNs and transform them to the canonical form. ``EAN13(isbnlike)`` - Transforms an `isbnlike` string into an EAN13 number (validated canonical ISBN-13). + Transforms an `isbnlike` string into an EAN13 number (validated canonical ISBN-13). ``info(isbn)`` - Gets the language or country assigned to this ISBN. + Gets the language or country assigned to this ISBN. ``mask(isbn, separator='-')`` - `Mask` (hyphenate) a canonical ISBN. + `Mask` (hyphenate) a canonical ISBN. ``meta(isbn, service='default', cache='default')`` Gives you the main metadata associated with the ISBN. As `service` parameter you can use: - ``'wcat'`` uses **worldcat.org** - (**no key is needed**), ``'goob'`` uses the **Google Books service** (**no key is needed**), - ``'isbndb'`` uses the **isbndb.com** service (**an api key is needed**), - ``'openl'`` uses the **OpenLibrary.org** api (**no key is needed**), ``merge`` uses - a merged record of ``wcat`` and ``goob`` records (**no key is needed**) and - **is the default option**. - You can get an API key for the *isbndb.com service* here_. You can enter API keys - with ``config.add_apikey(service, apikey)``. - The output can be formatted as ``bibtex``, ``msword``, ``endnote``, ``refworks``, + ``'goob'`` uses the **Google Books service** (**no key is needed**) and + **is the default option**, + ``'openl'`` uses the **OpenLibrary.org** api (**no key is needed**). + You can enter API keys + with ``config.add_apikey(service, apikey)`` (see example below). + The output can be formatted as ``bibtex``, ``csl`` (CSL-JSON), ``msword``, ``endnote``, ``refworks``, ``opf`` or ``json`` (BibJSON) bibliographic formats with ``isbnlib.registry.bibformatters``. ``cache`` only allows two values: 'default' or None. You can change the kind of cache by using ``isbnlib.registry.set_cache`` (see below). + Now, you can extend the functionality of this function by adding pluggins, more metadata + providers or new bibliographic formatters (check_ for available pluggins). -``editions(isbn, service='wcat')`` +``editions(isbn, service='merge')`` Returns the list of ISBNs of editions related with this ISBN. By default - uses 'wcat', but other providers are available: 'thingl' (uses the - service ThingISBN from **LibraryThing**), 'merge' (merges 'wcat' with 'thingl') - and 'any' (first tries 'wcat', if no data, tries 'thingl'). + uses 'merge' (merges 'openl' and 'thingl'), but other providers are available: + 'openl' users **Open Library**, 'thingl' (uses the service ThingISBN from **LibraryThing**) + and 'any' (first tries 'openl', if no data, then 'thingl'). ``isbn_from_words(words)`` - Returns the most probable ISBN from a list of words (for your geographic area). + Returns the most probable ISBN from a list of words (for your geographic area). ``goom(words)`` - Returns a list of references from **Google Books multiple references**. + Returns a list of references from **Google Books multiple references**. ``doi(isbn)`` - Returns a DOI's ISBN-A from a ISBN-13. + Returns a DOI's ISBN-A from a ISBN-13. ``doi2tex(DOI)`` - Returns metadata formated as BibTeX for a given DOI. + Returns metadata formated as BibTeX for a given DOI. ``ren(filename)`` - Renames a file using metadata from an ISBN in his filename. + Renames a file using metadata from an ISBN in his filename. ``desc(isbn)`` - **BETA** Returns a small description of the book. + Returns a small description of the book. *Almost all data available are for US books!* ``cover(isbn)`` - **BETA** Downloads an image of the cover of the book or, with - `cover(isbn, mode='url')`, returns an url of the image. + Returns a dictionary with the url for cover. *Almost all data available are for US books!* @@ -173,6 +178,11 @@ $ easy_install isbnlib +If you use linux systems, you can install using your distribution package +manager (all major distributions have packages ``python-isbnlib`` +and ``python3-isbnlib``), however (usually) are **very old and don't work well anymore**! + + For Devs ======== @@ -213,17 +223,13 @@ * ``vias`` exposes several functions to put calls to services, just by passing the name and a pointer to the service's ``query`` function. - ``vias.parallel`` allows to put threaded calls. + ``vias.parallel`` allows to put threaded calls. You can use ``vias.serial`` to make serial calls and ``vias.multi`` to use several cores. The default is ``vias.serial``. -* ``bouth23`` (**DEPRECATED**) a small module to make it possible the code to run - in **bouth** python 2 and python 3. **It will disappear in the next major version!**. - See python-future.org_ for a built-in alternative to ``bouth23``. - The exceptions raised by these methods can all be catched using ``ISBNLibDevException``. You **should't raise** this exception in your code, only raise the specific exceptions -exposed in ``isbnlib.dev`` whose name end in Error. +exposed in ``isbnlib.dev`` whose name ends in Error. In ``isbnlib.dev.helpers`` you can find several methods, that we found very useful, some of then @@ -239,36 +245,57 @@ Finally, from ``isbnlib.config`` you can read and set configuration options: -change timeouts with ``setsocketstimeout`` and ``setthreadstimeout``, +change timeouts with ``seturlopentimeout`` and ``setthreadstimeout``, access api keys with ``apikeys`` and add new one with ``add_apikey`` and access and set generic and user-defined options with ``options`` and ``set_option``. +Let us concretize the last point with a small example. + +Suppose you want a small script to get metadata using ``Open Library`` formated in BibTeX. + +A minimal script would be: + + +.. code-block:: python + + from isbnlib import meta + from isbnlib.registry import bibformatters + + SERVICE = 'openl' + + # now you can use the service + isbn = '9780446310789' + bibtex = bibformatters['bibtex'] + print(bibtex(meta(isbn, SERVICE))) + + + +Plugins +------- + +You can extend the functionality of the library by adding plugins (for now, just +new metadata providers or new bibliographic formatters). + +For available plugins check_ here. + +After install, your plugin will blend transparently in ``isbnlib`` (you will have more options in ``meta`` and ``bibformatters``). + +If you want to develop a plugin, start with this template_ and follow the instructions there. For inspiration take a look +at goob_. + + +Remember that plugins **must** support python 2.7 and python 3.4+ (see python-future.org_). -Merge Metadata --------------- -The original quality of metadata, at the several services, is not very good! -If you need high quality metadata in your app, the only solution is to use -*polling & merge* of several providers **and** a **lot** of cleaning and standardization -for fields like ``Authors`` and ``Publisher``. - -A *merge* provider is now the default in ``meta``. -It gives priority to ``wcat`` but overwrites the ``Authors`` field with the value from ``goob``. -Uses the ``merge`` method of ``Metadata`` and *serial* calls to services -by default (faster for one-call to services through fast internet connections). -You can change that by using ``vias``'s other methods -(e.g. ``isbnlib.config.set_option('VIAS_MERGE', 'multi')``. Caveats ------- -1. These classes are optimized for one-call to services and not for batch calls. However, - is very easy to produce an high volume processing system using these classes - (use ``vias.multi``) and Redis. +1. These classes are optimized for one-call to services and not for batch calls. 2. If you inspect the library, you will see that there are a lot of private modules (their name starts with '_'). These modules **should not** be accessed directly since, @@ -276,14 +303,37 @@ +Projects using *isbnlib* +------------------------ + +**isbntools** https://github.com/xlcnd/isbntools + +**Spreads** https://github.com/DIYBookScanner/spreads + +**BiblioManager** https://github.com/Phyks/BMC/ + +**libBMC** https://github.com/Phyks/libbmc/ + +**Alessandria** https://gitlab.com/openlabmatera/alessandria + +**Comic Collector** https://github.com/wengole/comiccollector + +**Abelujo** http://www.abelujo.cc/ + +**BibLib** https://pypi.python.org/pypi/biblib + + + + Help -____ +---- If you need help, please take a look at github_ or post a question on stackoverflow_ (with tag **isbnlib**) + ---------------------------------------------------------------------------------------------- .. class:: center @@ -297,8 +347,6 @@ .. _range: https://www.isbn-international.org/range_file_generation -.. _here: http://isbndb.com/api/v2/docs - .. _isbntools: https://pypi.python.org/pypi/isbntools .. _sourcegraph: http://bit.ly/ISBNLib_srcgraph @@ -316,3 +364,19 @@ .. _wikipedia: http://en.wikipedia.org/wiki/International_Standard_Book_Number .. _python-future.org: http://python-future.org/compatible_idioms.html + +.. _issue: https://github.com/xlcnd/isbnlib/issues/28 + +.. _check: https://pypi.python.org/pypi?%3Aaction=search&term=isbnlib_&submit=search + +.. _template: https://github.com/xlcnd/isbnlib/blob/dev/PLUGIN.zip + + +.. _goob: https://github.com/xlcnd/isbnlib/blob/dev/isbnlib/_goob.py + + +.. _search: https://pypi.python.org/pypi?%3Aaction=search&term=isbnlib&submit=search + +.. _51: https://github.com/xlcnd/isbnlib/issues/51 + + diff -Nru isbnlib-3.5.6/requirements-appveyor.txt isbnlib-3.9.3/requirements-appveyor.txt --- isbnlib-3.5.6/requirements-appveyor.txt 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/requirements-appveyor.txt 2018-10-05 11:18:35.000000000 +0000 @@ -1,6 +1,6 @@ -coverage==3.7.1 -flake8==2.1.0 -nose==1.3.4 -tox==1.7.1 -setuptools==12.0.4 -wheel==0.23.0 +coverage==4.4.2 +flake8==3.5.0 +nose==1.3.7 +setuptools==38.4.0 +tox==2.9.1 +wheel==0.30.0 diff -Nru isbnlib-3.5.6/requirements-dev.txt isbnlib-3.9.3/requirements-dev.txt --- isbnlib-3.5.6/requirements-dev.txt 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/requirements-dev.txt 2018-10-05 11:18:35.000000000 +0000 @@ -1,13 +1,13 @@ -coverage==3.7.1 -flake8==2.1.0 -mccabe==0.2.1 -mock==1.0.1 -nose==1.3.4 -pep8==1.5.7 -pep8-naming==0.2.2 -pep257==0.3.2 -pyflakes==0.8.1 -pylint==1.2.1 -tox==1.7.1 -virtualenv==12.0.5 -wheel==0.23.0 +coverage==4.4.2 +flake8==3.5.0 +flake8-bugbear==18.2.0 +flake8-commas==1.0.0 +flake8-docstrings==1.3.0 +flake8-import-order==0.17.1 +isort==4.3.4 +nose==1.3.7 +pep8-naming==0.5.0 +setuptools==38.4.0 +tox==2.9.1 +wheel==0.30.0 +yapf==0.20.2 diff -Nru isbnlib-3.5.6/setup.cfg isbnlib-3.9.3/setup.cfg --- isbnlib-3.5.6/setup.cfg 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/setup.cfg 2018-10-05 11:18:35.000000000 +0000 @@ -1,6 +1,29 @@ +[metadata] +license_file = LICENSE + + [bdist_wheel] universal=1 + [nosetests] verbosity=1 +with-coverage=1 +cover-package=isbnlib +cover-branches=1 +cover-min-percentage=90 + + +[pep257] +ignore=D203 + + +[flake8] +ignore=N806,E721,W503 +exclude=*/test/*,*/_data/* +max-complexity=13 + +[doc8] +max-line-length=120 +verbose=1 diff -Nru isbnlib-3.5.6/setup.py isbnlib-3.9.3/setup.py --- isbnlib-3.5.6/setup.py 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/setup.py 2018-10-05 11:18:35.000000000 +0000 @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- +# flake8: noqa +# isort:skip_file -# isbnlib - tools for extracting, cleaning and transforming ISBNs -# Copyright (C) 2014 Alexandre Lima Conde +# isbnlib -- tools for extracting, cleaning and transforming ISBNs +# Copyright (C) 2014-2018 Alexandre Lima Conde # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by @@ -27,7 +29,7 @@ author='xlcnd', author_email='xlcnd@outlook.com', url='https://github.com/xlcnd/isbnlib', - download_url='https://github.com/xlcnd/isbnlib/archive/v3.5.6.zip', + download_url='https://github.com/xlcnd/isbnlib/archive/v3.9.3.zip', packages=['isbnlib', 'isbnlib/dev', 'isbnlib/_data', @@ -36,15 +38,16 @@ license='LGPL v3', description='Extract, clean, transform, hyphenate and metadata for ISBNs (International Standard Book Number).', long_description=open('README.rst').read(), - keywords='ISBN, validate, transform, hyphenate, metadata, World Catalogue, Google Books, Open Library, isbndb.com, BibTeX, EndNote, RefWorks, MSWord, opf, BibJSON, ISBN-A, doi, EAN13', + keywords='ISBN metadata World_Catalogue Google_Books Open_Library BibTeX EndNote RefWorks MSWord opf BibJSON', classifiers=[ 'Programming Language :: Python', 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)', 'Operating System :: OS Independent', 'Development Status :: 5 - Production/Stable', @@ -52,6 +55,6 @@ 'Topic :: Text Processing :: General', 'Topic :: Software Development :: Libraries :: Python Modules', ], - tests_require=['nose'], + tests_require=['nose', 'coverage'], test_suite='nose.collector', ) diff -Nru isbnlib-3.5.6/.style.yapf isbnlib-3.9.3/.style.yapf --- isbnlib-3.5.6/.style.yapf 1970-01-01 00:00:00.000000000 +0000 +++ isbnlib-3.9.3/.style.yapf 2018-10-05 11:18:35.000000000 +0000 @@ -0,0 +1,2 @@ +[style] +based_on_style = pep8 diff -Nru isbnlib-3.5.6/tox.ini isbnlib-3.9.3/tox.ini --- isbnlib-3.5.6/tox.ini 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/tox.ini 2018-10-05 11:18:35.000000000 +0000 @@ -1,17 +1,24 @@ [flake8] -ignore=N806,E721 +ignore=N806,I100,I101,I201,N802,C901,E722,E741 exclude=*/test/*,*/_data/* max-complexity=13 +[pep257] +ignore=D203 + +[doc8] +max-line-length=120 +verbose=1 + [tox] -envlist=py26,py27,py33,py34,checkers +envlist=py27,py34,py35,py36,nightly,checkers [testenv] deps= nose coverage commands= - nosetests -v --with-coverage --cover-package=isbnlib + nosetests -v --with-coverage --cover-package=isbnlib --cover-min-percentage=90 [testenv:checkers] basepython=python diff -Nru isbnlib-3.5.6/.travis.yml isbnlib-3.9.3/.travis.yml --- isbnlib-3.5.6/.travis.yml 2015-06-03 10:51:03.000000000 +0000 +++ isbnlib-3.9.3/.travis.yml 2018-10-05 11:18:35.000000000 +0000 @@ -1,41 +1,45 @@ sudo: false language: python -os: -- linux -- osx branches: only: - - v3.5.6 - - none + - v3.9.3 matrix: include: + - os: osx + language: generic + env: TOXENV=py37 - python: "2.7" env: TOXENV=py27 + - python: "3.6" + env: TOXENV=py36 + - python: "3.5" + env: TOXENV=py35 - python: "3.4" env: TOXENV=py34 - - python: "3.3" - env: TOXENV=py33 - - python: "2.6" - env: TOXENV=py26 - - python: "pypy" - env: TOXENV=pypy + - python: "nightly" + env: TOXENV=nightly - python: "2.7" env: TOXENV=checkers - python: "2.7" env: DOC=sphinx allow_failures: - - env: TOXENV=pypy + - env: TOXENV=nightly + - env: TOXENV=py34 - env: TOXENV=checkers install: -- if [[ ! -z $TOXENV ]]; then pip install tox; fi -- if [[ ! -z $TOXENV ]]; then pip install flake8; fi -- if [[ ! -z $TOXENV ]]; then pip install pep8-naming; fi -- if [[ $TOXENV == 'py27' ]]; then pip install coveralls; fi +- if [[ $TRAVIS_OS_NAME == 'osx' ]]; then brew upgrade python && python --version; fi +- if [[ $TRAVIS_OS_NAME == 'osx' ]]; then pip3 install tox; fi +- if [[ $TRAVIS_OS_NAME == 'linux' ]]; then pip install tox; fi +- if [[ $TOXENV == 'checkers' ]]; then pip install flake8; fi +- if [[ $TOXENV == 'checkers' ]]; then pip install pep8-naming; fi +- if [[ $TOXENV == 'py27' ]]; then pip install coveralls; fi - if [[ $DOC == 'sphinx' ]]; then pip install sphinx; fi +- if [[ $TRAVIS_PULL_REQUEST != 'false' ]]; then pip install yapf; fi script: +- if [[ $TRAVIS_PULL_REQUEST != 'false' ]] && [[ $TOXENV == 'checkers' ]]; then yapf -i isbnlib; fi - if [[ ! -z $TOXENV ]]; then tox -e $TOXENV; fi - if [[ $DOC == 'sphinx' ]]; then cd docs; sphinx-build -n -b html -d _build/.doctrees . _build/html; fi after_success: - if [[ $TOXENV == 'py27' ]]; then coveralls; fi notifications: - email: false + email: false