Skip to content

Commit

Permalink
Releases/v1.0.0 (#92)
Browse files Browse the repository at this point in the history
* move cov & pytest config to pyproject.toml

* remove temp file

* remove pytest-recording

* add py311

* dependencies updates

* drop py3.7

* copy main config

* drop py3.7

* add requests to dev dependencies

* fix missing dependencies

* dependencies final update

* version bump to 1.0.0

* adds all dependencies

* add py3.12

* typing cleanup & tests refactoring

* Authentication updates (#69)

* ingnore E501 in tests

* add types-requests to dev dependencies

* scopes as str

* scopes as str & types cleanup

* dev dependencies moved to tool.poetry.group.dev.dependencies section

* token_expires_at as datetime obj

* token_expires_at as datetime

* changed utcnow to now(timezone.utc) (#71)

* Ocn-parsing-refactor (#72)

* prep_oclc_numbe_strr refactor

* oclcNumber stripped

* verification refactor

* utc fixes (#73)

* fixed datetime type errors

* moved datetime edits to _hasten_expiration_time

* Errors-refactor (#74)

* removed WorldcatSessionError

* incorrect AttributeError replaced with TypeError

* replaces WorldcatAuthorizationError with TypeError and ValueError for configuration

* removed unused WorldcatAuthorizationError import

* removed unused WorldcatRequestError import

* added safe decoding for bytes-str

* ignore F401

* None type added to possible timeout types

* added type ingnore

* removed unused InvalidOclcNumber import & typing fixes

* changed endpoints in metadata api 2.0 (#77)

* changed endpoints in metadata api 2.0

* fixed tests with typos

* changed response_format default in get_full_bib

* Changed search endpoints (#78)

* changed search endpoints in metadata api 2.0

* fixed types

* fixed spacing and indentation

* type hint fixes and refactored test

* Removed principalID and principalIDNS from token requests (#79)

* removed unnecessary params from token requests

* fixed docstring

* MetadataSession cleanup (#80)

* reordered methods in MetadataSession

* removed obsolete 409 error handling from query.py

* simplified changes

* added new api endpoints (#81)

* added new api endpoints

* added tests

* added test

* added to doc string, fixed typos (#82)

@charlottekostelic This is something that should be brought to users attention in the documentation. Will create an issue as a reminder.
Besides that, looks good. Thanks!

* Query updates (#84)

* work in progress

* added retries to query

* removed test with stale token

* added stale token test back in

* added stale token test back in

* moved retries to _session module, added tests

* added retry status_forcelist tests

* added custom adapter test

* changed default retry behavior

* added another test

* more testing

* Reordered metadata methods (#85)

* renamed/reordered metadata_api methods

* fixed optional/required args, added to doc strings

* fixed default values to match API defaults

* fixed error in live test

* dev status update to 5, removes py3.7 & adds py3.11 & py3.12 (#87)

* Update docs (#88)

* reorganized docs, added mkdocs-material theme

* added css for NYPL colors

* reorganized docs, added examples

* changed structure of docs, added to docs

* changed snake case to camel case in args

* typo fixes

* added contributing.md, python versions for black

* added 1.0 to changelog, migration section in docs

* Added migration section to README

* typo fixes, link fixes

* added py.typed file

* fixed links, made edits per PR 88

* added mkdocstrings, removed mkapi, doc edits (#91)

* edited changelog

* pyproject.toml edits

* update unit-tests.yaml

* fixed unit-tests.yaml

* unit-tests.yaml indentation issues

---------

Co-authored-by: klinga <klingaroo@gmail.com>
  • Loading branch information
charlottekostelic and klinga authored Mar 26, 2024
1 parent 6ec9049 commit 6a865bb
Show file tree
Hide file tree
Showing 44 changed files with 6,115 additions and 3,069 deletions.
3 changes: 0 additions & 3 deletions .coveragerc

This file was deleted.

3 changes: 3 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[flake8]
per-file-ignores =
tests/*:E501, W503
15 changes: 12 additions & 3 deletions .github/workflows/unit-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- name: Set up Python
- name: Set up Python ${{ matrix.python-version}}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version}}
Expand All @@ -29,4 +29,13 @@ jobs:
- name: Send report to Coveralls
uses: AndreMiras/coveralls-python-action@develop
with:
github-token: ${{ secrets.GITHUB_TOKEN}}
parallel: true
github-token: ${{ secrets.GITHUB_TOKEN}}
finish:
needs: test
runs-on: ubuntu-latest
steps:
- name: Coveralls Finished
uses: AndreMiras/coveralls-python-action@develop
with:
parallel-finished: true
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,6 @@ temp/
1.0/
venv-activate.sh
venvcmd.sh

# OSX
.DS_Store
232 changes: 114 additions & 118 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
[![Build Status](https://github.com/BookOps-CAT/bookops-marc/actions/workflows/unit-tests.yaml/badge.svg?branch=main)](https://github.com/BookOps-CAT/bookops-worldcat/actions) [![Coverage Status](https://coveralls.io/repos/github/BookOps-CAT/bookops-worldcat/badge.svg?branch=main)](https://coveralls.io/github/BookOps-CAT/bookops-worldcat?branch=main) [![PyPI version](https://badge.fury.io/py/bookops-worldcat.svg)](https://badge.fury.io/py/bookops-worldcat) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/bookops-worldcat) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

# bookops-worldcat
**Early ALPHA version**

BookOps-Worldcat provides a Python interface for the WorldCat Metadata API. This wrapper simplifies requests to OCLC web services making them more accessible to OCLC member libraries.

BookOps-Worldcat provides a Python interface for the WorldCat Metadata API.
This wrapper simplifies requests to OCLC web services making them ideally more accessible to OCLC member libraries.

Due to major changes introduced by OCLC in May 2020, the version 0.3.0 of the wrapper dropped functionality related to WorldCat Search API. New search endopoints of the Metadata API supported in the 0.3.0 version should fill that gap. While WorldCat Metadata API is our primary focus, we plan in the future to expand wrapper's functionality to other related OCLC web services, including the now dropped Search API.
Bookops-Worldcat version 1.0 supports changes released in version 2.0 (May 2023) of the OCLC Metadata API.

## Installation

Expand All @@ -21,146 +18,145 @@ For full documentation please see https://bookops-cat.github.io/bookops-worldcat

## Features

This package takes advantage of the functionality of the popular [Requests library](https://requests.readthedocs.io/en/master/). Interactions with [OCLC](https://www.oclc.org/en/home.html)'s services are built around 'Requests' sessions. Authorizing a web service session simply requires passing an access token to `MetadataSession`. Opening a session allows the user to call specific methods to facilitate communication between the user's script/client and particular endpoint of OCLC API service. Many of the hurdles related to making valid requests are hidden under the hood of this package, making it as simple as possible.
Please note, not all endpoints of the Metadata API are implemented at the moment. This tool was primarily built for the specific needs of BookOps but we are open to collaboration to expand and improve this package.

At the moment, BookOps-Worldcat supports requests to following OCLC's web services:

+ [Authentication via Client Credential Grant](https://www.oclc.org/developer/develop/authentication/oauth/client-credentials-grant.en.html)
+ [Worldcat Metadata API](https://www.oclc.org/developer/develop/web-services/worldcat-metadata-api.en.html)
+ [Metadata API Search Functionality](https://developer.api.oclc.org/wc-metadata-v1-1)
+ member shared print holdings
+ member general holdings
+ searching bibliographic resources:
+ search brief bibs
+ retrieve specific brief bib
+ retrieve other editions related to a specific bibliographic resource
+ [Metadata API](https://developer.api.oclc.org/wc-metadata)
+ bibliographic records
+ retrieve full bib
+ find current OCLC number
+ holdings
+ set institution holding for a single resource
+ unset institution holding for a single resource
+ retrieve holding status of a single resource
+ set institution holdings for a batch of resources
+ unset institution holdings for a batch of resouces
+ set holdings for a single resource for multiple institutions
+ unset holdings for a single resource for multiple institutions


#### Basic usage:

Obtaining access token
Bookops-Worldcat takes advantage of the functionality of the popular [Requests library](https://requests.readthedocs.io/) and interactions with OCLC's services are built around 'Requests' sessions. `MetadataSession` inherits all `requests.Session` properties. Server responses are `requests.Response` objects with [all of their properties and methods](https://requests.readthedocs.io/en/latest/user/quickstart/).

Authorizing a web service session simply requires passing an access token to `MetadataSession`. Opening a session allows the user to call specific methods to facilitate communication between the user's script/client and a particular endpoint of the Metadata API. Many of the hurdles related to making valid requests are hidden under the hood of this package, making it as simple as possible.

BookOps-Worldcat supports requests to all endpoints of the WorldCat Metadata API 2.0 and Authentication using the [Client Credential Grant](https://www.oclc.org/developer/api/keys/oauth/client-credentials-grant.en.html) flow:

+ [Authentication via Client Credential Grant](https://www.oclc.org/developer/api/keys/oauth/client-credentials-grant.en.html)
+ [Worldcat Metadata API](https://www.oclc.org/developer/api/oclc-apis/worldcat-metadata-api.en.html)
+ Manage Bibliographic Records
+ Manage Institution Holdings
+ Manage Local Bibliographic Data
+ Manage Local Holdings Records
+ Search Member Shared Print Holdings
+ Search Member General Holdings
+ Search Bibliographic Resources
+ Search Local Holdings Resources
+ Search Local Bibliographic Resources

### Basic usage:

Authorizing a MetadataSession
```python
>>> from bookops_worldcat import WorldcatAccessToken
>>> token = WorldcatAccessToken(
key="my_WSkey",
secret="my_WSsecret",
scopes="selected_scope",
principal_id="my_principalID",
principal_idns="my_principalIDNS",
agent="my_client"
)
>>> print(token.token_str)
"tk_Yebz4BpEp9dAsghA7KpWx6dYD1OZKWBlHjqW"
from bookops_worldcat import WorldcatAccessToken
token = WorldcatAccessToken(
key="my_WSKey",
secret="my_secret",
scopes="WorldCatMetadataAPI",
)
print(token)
#>"access_token: 'tk_Yebz4BpEp9dAsghA7KpWx6dYD1OZKWBlHjqW', expires_at: '2024-01-01 12:00:00Z'"
print(token.is_expired())
#>False
```

Metadata API
Search for brief bibliographic resources
```python
>>> from bookops_worldcat import MetadataSession
>>> session = MetadataSession(authorization=token)
>>> result = session.get_brief_bib(oclcNumber=1143317889)
>>> print(result)
<Response [200]>
>>> print(result.json())
with MetadataSession(authorization=token) as session:
response = session.brief_bibs_search(q="ti:The Power Broker AND au: Caro, Robert")
print(response.json())
```
```json
{
"oclcNumber": "1143317889",
"title": "Blueprint : the evolutionary origins of a good society",
"creator": "Nicholas A. Christakis",
"date": "2020",
"language": "eng",
"generalFormat": "Book",
"specificFormat": "PrintBook",
"edition": "First Little, Brown Spark trade paperback edition.",
"publisher": "Little, Brown Spark",
"catalogingInfo": {
"catalogingAgency": "NYP",
"transcribingAgency": "NYP"
}
"numberOfRecords": 89,
"briefRecords": [
{
"oclcNumber": "1631862",
"title": "The power broker : Robert Moses and the fall of New York",
"creator": "Robert A. Caro",
"date": "1975",
"machineReadableDate": "1975",
"language": "eng",
"generalFormat": "Book",
"specificFormat": "PrintBook",
"edition": "Vintage Books edition",
"publisher": "Vintage Books",
"catalogingInfo": {
"catalogingAgency": "DLC",
"catalogingLanguage": "eng",
"levelOfCataloging": " ",
"transcribingAgency": "DLC"
}
}
]
}
```

Using a context manager:
MetadataSession as Context Manager:
```python
with MetadataSession(authorization=token) as session:
results = session.get_full_bib(1143317889)
print(results.text)
result = session.bib_get("1631862")
print(result.text)
```
```xml
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
<content type="application/xml">
<response xmlns="http://worldcat.org/rb" mimeType="application/vnd.oclc.marc21+xml">
<record xmlns="http://www.loc.gov/MARC21/slim">
<leader>00000cam a2200000 i 4500</leader>
<controlfield tag="001">on1143317889</controlfield>
<controlfield tag="003">OCoLC</controlfield>
<controlfield tag="005">20200328101446.1</controlfield>
<controlfield tag="008">200305t20202019nyuabf b 001 0 eng c</controlfield>
<datafield tag="010" ind1=" " ind2=" ">
<subfield code="a"> 2018957420</subfield>
<?xml version='1.0' encoding='UTF-8'?>
<record xmlns="http://www.loc.gov/MARC21/slim">
<leader>00000cam a2200000 i 4500</leader>
<controlfield tag="001">ocm01631862</controlfield>
<controlfield tag="003">OCoLC</controlfield>
<controlfield tag="005">20240201163642.4</controlfield>
<controlfield tag="008">750320t19751974nyuabf b 001 0beng </controlfield>
<datafield tag="010" ind1=" " ind2=" ">
<subfield code="a"> 75009557 </subfield>
</datafield>
<datafield tag="040" ind1=" " ind2=" ">
<subfield code="a">NYP</subfield>
<subfield code="b">eng</subfield>
<subfield code="e">rda</subfield>
<subfield code="c">NYP</subfield>
<!--...-->
<datafield tag="020" ind1=" " ind2=" ">
<subfield code="a">9780316230049</subfield>
<subfield code="q">(pbk.)</subfield>
<datafield tag="020" ind1=" " ind2=" ">
<subfield code="a">9780394720241</subfield>
<subfield code="q">(paperback)</subfield>
<!--...-->
<datafield tag="100" ind1="1" ind2=" ">
<subfield code="a">Christakis, Nicholas A.,</subfield>
<subfield code="e">author.</subfield>
<datafield tag="100" ind1="1" ind2=" ">
<subfield code="a">Caro, Robert A.,</subfield>
<subfield code="e">author.</subfield>
</datafield>
<datafield tag="245" ind1="1" ind2="0">
<subfield code="a">Blueprint :</subfield>
<subfield code="b">the evolutionary origins of a good society /</subfield>
<subfield code="c">Nicholas A. Christakis.</subfield>
<datafield tag="245" ind1="1" ind2="4">
<subfield code="a">The power broker :</subfield>
<subfield code="b">Robert Moses and the fall of New York /</subfield>
<subfield code="c">by Robert A. Caro.</subfield>
</datafield>
<datafield tag="250" ind1=" " ind2=" ">
<subfield code="a">First Little, Brown Spark trade paperback edition.</subfield>
<datafield tag="246" ind1="3" ind2="0">
<subfield code="a">Robert Moses and the fall of New York</subfield>
</datafield>
<datafield tag="264" ind1=" " ind2="1">
<subfield code="a">New York, NY :</subfield>
<subfield code="b">Little, Brown Spark,</subfield>
<subfield code="c">2020</subfield>
<datafield tag="250" ind1=" " ind2=" ">
<subfield code="a">Vintage Books edition.</subfield>
</datafield>
<datafield tag="264" ind1=" " ind2="1">
<subfield code="a">New York :</subfield>
<subfield code="b">Vintage Books,</subfield>
<subfield code="c">1975.</subfield>
</datafield>
<!--...-->
</record>
</response>
</content>
<id>http://worldcat.org/oclc/1143317889</id>
<link href="http://worldcat.org/oclc/1143317889"></link>
</entry>
</record>
```

## Changes in Version 1.0

New functionality available in version 1.0:

+ Send requests to all endpoints of WorldCat Metadata API
+ Match bib records and retrieve bib classification
+ Create, update, and validate bib records
+ Create, retrieve, update, and delete local bib and holdings records
+ Add automatic retries to failed requests
+ Authenticate and authorize for multiple institutions within `MetadataSession`
+ Support for Python 3.11 and 3.12
+ Dropped support for Python 3.7

### Migration Information
Bookops-Worldcat 1.0 introduces many breaking changes for users of previous versions. Due to a complete refactor of the Metadata API, the methods from Bookops-Worldcat 0.5.0 have been rewritten. Most of the functionality from previous versions of the Metadata API is still available in Version 2.0. For a comparison of the functionality available in Versions 1.0, 1.1, and 2.0 of the Metadata API, see [OCLC's documentation](https://www.oclc.org/developer/api/oclc-apis/worldcat-metadata-api.en.html) and their [functionality comparison table](https://www.oclc.org/content/dam/developer-network/worldcat-metadata-api/worldcat-metadata-api-functionality-comparison.pdf).

Versions 1.0 and 1.1 of the Metadata API will be sunset after April 30, 2024 at which point tools that rely on Bookops-Worldcat 0.5 will no longer be able to query the Metadata API.

For more information on changes made in Version 1.0, see [Features in Version 1.0](https://bookops-cat.github.io/bookops-worldcat/latest/#features-in-version-1.0) in the docs.

## Changelog

Consult the [Changelog page](https://bookops-cat.github.io/bookops-worldcat/latest/changelog/) for fixes and enhancements of each version.
Consult the [Changelog page](https://bookops-cat.github.io/bookops-worldcat/latest/changelog/) for a full list of fixes and enhancements for each version.

## Bugs/Requests

Please use [Github issue tracker](https://github.com/BookOps-CAT/bookops-worldcat/issues) to submit bugs or request features.
Please use the [Github issue tracker](https://github.com/BookOps-CAT/bookops-worldcat/issues) to submit bugs or request features.

## Todo
## Contributing

+ Metadata API:
+ support for local holdings resources endpoints of the search functionality of the Metadata API
+ support for local bibliographic data endpoints
+ record validation endpoints
+ methods to create and update bibliographic records
See [Contribution Guidelines](https://bookops-cat.github.io/bookops-worldcat/latest/contributing) for information on how to contribute to bookops-worldcat.
6 changes: 3 additions & 3 deletions bookops_worldcat/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .__version__ import __title__, __version__
from .__version__ import __title__, __version__ # noqa: F401

from .authorize import WorldcatAccessToken
from .metadata_api import MetadataSession
from .authorize import WorldcatAccessToken # noqa: F401
from .metadata_api import MetadataSession # noqa: F401
2 changes: 1 addition & 1 deletion bookops_worldcat/__version__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__title__ = "bookops-worldcat"
__version__ = "0.5.0"
__version__ = "1.0.0"
__author__ = "Tomasz Kalata"
__author_email__ = "klingaroo@gmail.com"
Loading

0 comments on commit 6a865bb

Please sign in to comment.