├── pyalma ├── __init__.py └── alma.py ├── test ├── __init__.py ├── loan.dat ├── availability.dat ├── request2.dat ├── request.dat ├── item_loan.dat ├── hold.dat ├── hold2.dat ├── holds.dat ├── item.dat ├── item2.dat ├── items.dat ├── bib.dat ├── bib2.dat ├── bib.dat.xml ├── bib2.dat.xml ├── test_coroutines.py ├── test_alma.py └── mms_holdings_items_with_requests.csv ├── .gitignore ├── requirements.txt ├── .travis.yml ├── setup.py ├── speedtest ├── time_get_bibs.py └── coroutines_speedtest.py └── README.md /pyalma/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python cahce directories 2 | __pycache__/ 3 | *.pyc 4 | 5 | # virtual environment 6 | ENV 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pymarc 2 | requests 3 | responses 4 | asyncio 5 | aiohttp<2.0 6 | ratelimiter 7 | asynctest 8 | aioresponses 9 | -------------------------------------------------------------------------------- /test/loan.dat: -------------------------------------------------------------------------------- 1 | { 2 | "circ_desk": { 3 | "value": "DEFAULT_CIRC_DESK" 4 | }, 5 | "library": { 6 | "value": "MAIN" 7 | } 8 | } -------------------------------------------------------------------------------- /test/availability.dat: -------------------------------------------------------------------------------- 1 | { 2 | "from_time": 1401691527672, 3 | "to_time": 1401691527672, 4 | "user_id": null, 5 | "user_full_name": null, 6 | "reason": null 7 | } -------------------------------------------------------------------------------- /test/request2.dat: -------------------------------------------------------------------------------- 1 | { 2 | "request_type": "HOLD", 3 | "pickup_location": "Burns", 4 | "pickup_location_type": "LIBRARY", 5 | "pickup_location_library": "BURNS", 6 | "comment": "my comment" 7 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - '3.5' 4 | - '3.6' 5 | install: 6 | - pip install -r requirements.txt 7 | - pip install coveralls 8 | notifications: 9 | email: 10 | recipients: 11 | - jgomez@getty.edu 12 | script: 13 | coverage run --source=pyalma setup.py test 14 | after_success: 15 | coveralls 16 | 17 | -------------------------------------------------------------------------------- /test/request.dat: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Test title", 3 | "author": null, 4 | "description": null, 5 | "comment": null, 6 | "request_id": "83013520000121", 7 | "request_type": "HOLD", 8 | "pickup_location": "Burns", 9 | "pickup_location_type": "LIBRARY", 10 | "pickup_location_library": "BURNS", 11 | "material_type": { 12 | "value": "BK", 13 | "desc": "Book" 14 | }, 15 | "request_status": "NOT_STARTED", 16 | "place_in_queue": 1, 17 | "request_date": "2013-11-12Z" 18 | } 19 | -------------------------------------------------------------------------------- /test/item_loan.dat: -------------------------------------------------------------------------------- 1 | { 2 | "circ_desk": { 3 | "value": "DEFAULT_CIRC_DESK", 4 | "desc": "default circ desk" 5 | }, 6 | "loan_id": "1234", 7 | "library": { 8 | "value": "MAIN", 9 | "desc": "Main Library" 10 | }, 11 | "userId": "ID1234", 12 | "itemBarcode": "000237055710000121", 13 | "dueDate": "2014-06-23T14:00:00Z", 14 | "loanStatus": "ACTIVE", 15 | "loanDate": "2014-06-22T11:00:28Z", 16 | "processStatus": "NORMAL", 17 | "title": "History", 18 | "author": null, 19 | "description": "v2", 20 | "publicationYear": null, 21 | "locationCode": { 22 | "value": "Location 1", 23 | "name": "LOC1" 24 | } 25 | } -------------------------------------------------------------------------------- /test/hold.dat: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "holding_id": "22115858660001551", 4 | "created_by": "import", 5 | "created_date": "2013-07-14Z", 6 | "anies": [ 7 | "\n\n 00214cx a22000973 4500\n 398498\n 333281\n 20010412173201.0\n 0104120p 8 4001aueng0000000\n \n 94-B3418\n \n \n GC\n BOOKS:L2\n P93.5\n .T84 1992\n Copy 1\n \n " 8 | ] 9 | 10 | } -------------------------------------------------------------------------------- /test/hold2.dat: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "holding_id": "22115858660001551", 4 | "created_by": "import", 5 | "created_date": "2013-07-14Z", 6 | "anies": [ 7 | "\n\n 00214cx a22000973 4500\n 398498\n 333281\n 20010412173201.0\n 0104120p 8 4001aueng0000000\n \n 94-B3418\n \n \n GC\n BOOKS:L2\n P93.5\n .T84 1992\n Copy 2\n \n " 8 | ] 9 | 10 | } -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name = 'pyalma', 5 | packages = find_packages(), 6 | test_suite="test", 7 | version = '0.0.1', 8 | description = 'Python client for ExLibris Alma', 9 | author = 'Getty Research Institute', 10 | author_email = 'jgomez@getty.edu', 11 | url = 'https://stash.getty.edu/projects/GRIIS/repos/pyalma/browse', 12 | install_requires = ['pymarc', 'requests', 'aiohttp==1.3', 'ratelimiter'], 13 | classifiers = [ 14 | "Programming Language :: Python", 15 | "Programming Language :: Python :: 3", 16 | "License :: OSI Approved :: MIT License", 17 | "Development Status :: pre-Alpha", 18 | "Intended Audience :: Developers", 19 | "Operating System :: OS Independent", 20 | "Topic :: Software Development :: Libraries :: Python Modules", 21 | ] 22 | ) 23 | -------------------------------------------------------------------------------- /test/holds.dat: -------------------------------------------------------------------------------- 1 | { 2 | "holding": [ 3 | { 4 | "library": { 5 | "value": "65144020000121", 6 | "desc": "BURNS" 7 | }, 8 | "location": { 9 | "value": "UNASSIGNED", 10 | "desc": "UNASSIGNED location" 11 | }, 12 | "link": "/almaws/v1/bibs/99100383900121/holdings/2221159990000121", 13 | "holding_id": "2221159990000121" 14 | }, 15 | { 16 | "library": { 17 | "value": "5867020000121", 18 | "desc": "Main Library" 19 | }, 20 | "location": { 21 | "value": "MICR", 22 | "desc": "Microforms" 23 | }, 24 | "link": "/almaws/v1/bibs/99100383900121/holdings/2221410000000121", 25 | "holding_id": "2221410000000121" 26 | } 27 | ], 28 | "bib_data": { 29 | "title": "Data base", 30 | "issn": "0095-0033", 31 | "publisher": "Association for Computing Machinery", 32 | "link": "/almaws/v1/bibs/99100383900121", 33 | "mms_id": 99100383900121, 34 | "place_of_publication": "New York :", 35 | "network_number": [ 36 | "(CONSER) 2011250895", 37 | "(CKB)954926959913", 38 | "(OCoLC)604911177" 39 | ] 40 | }, 41 | "total_record_count": 2 42 | } 43 | -------------------------------------------------------------------------------- /test/item.dat: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "link": "https://api-na.hosted.exlibrisgroup.com/almaws/v1/bibs/9922405930001551/holdings/22115858660001551/items/23115858650001551", 4 | "bib_data": { 5 | "title": "Envisioning information /", 6 | "author": "Tufte, Edward R.,", 7 | "issn": null, 8 | "link": "https://api-na.hosted.exlibrisgroup.com/almaws/v1/bibs/9922405930001551", 9 | "mms_id": 9922405930001552, 10 | "complete_edition": "3rd printing, with revisions.", 11 | "place_of_publication": "Cheshire, Conn. :", 12 | "publisher_const": "Graphics Press", 13 | "network_number": [ 14 | "(CMalG)333281-gettydb-Voyager", 15 | "(OCoLC)28384525", 16 | "333281" 17 | ] 18 | }, 19 | "holding_data": { 20 | "link": "https://api-na.hosted.exlibrisgroup.com/almaws/v1/bibs/9922405930001551/holdings/22115858660001551", 21 | "holding_id": "22115858660001551", 22 | "call_number": "P93.5 .T84 1992", 23 | "temp_library": { 24 | "value": null, 25 | "desc": null 26 | }, 27 | "temp_location": { 28 | "value": null, 29 | "desc": null 30 | } 31 | }, 32 | "item_data": { 33 | "pid": "23115858650001551", 34 | "barcode": "33125006577916", 35 | "description": null, 36 | "library": { 37 | "value": "GC", 38 | "desc": "General Collections" 39 | }, 40 | "location": { 41 | "value": "BOOKS:L2", 42 | "desc": "BOOKS:L2" 43 | }, 44 | "requested": false, 45 | "physical_material_type": { 46 | "value": "BOOK", 47 | "desc": "Book" 48 | }, 49 | "process_type": { 50 | "value": "LOAN", 51 | "desc": "Loan" 52 | } 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /test/item2.dat: -------------------------------------------------------------------------------- 1 | { 2 | "link": "/almaws/v1/bibs/99110223950001021/holdings/22344156400001021/items/23344156380001021", 3 | "bib_data": { 4 | "title": "Visualizing data /", 5 | "author": "Fry, Ben.", 6 | "issn": null, 7 | "isbn": "9780596514556 (pbk.)", 8 | "link": "/almaws/v1/bibs/99110223950001021", 9 | "mms_id": 99110223950001020, 10 | "place_of_publication": "Sebastopol, CA :", 11 | "publisher_const": "O'Reilly Media Inc", 12 | "network_number": [ 13 | "(OCoLC)ocn190865378", 14 | "(Aleph)002401490BCL01" 15 | ] 16 | }, 17 | "holding_data": { 18 | "link": "/almaws/v1/bibs/99110223950001021/holdings/22344156400001021", 19 | "holding_id": "22344156400001021", 20 | "call_number": "T385 .F79 2008", 21 | "accession_number": "", 22 | "copy_id": "", 23 | "in_temp_location": false, 24 | "temp_library": { 25 | "value": null, 26 | "desc": null 27 | }, 28 | "temp_location": { 29 | "value": null, 30 | "desc": null 31 | }, 32 | "temp_call_number_type": { 33 | "value": "", 34 | "desc": null 35 | }, 36 | "temp_call_number": "", 37 | "temp_policy": { 38 | "value": "", 39 | "desc": null 40 | } 41 | }, 42 | "item_data": { 43 | "pid": "23344156380001021", 44 | "barcode": "39031031697261", 45 | "policy": { 46 | "value": "01", 47 | "desc": "01" 48 | }, 49 | "provenance": { 50 | "value": "", 51 | "desc": null 52 | }, 53 | "description": "", 54 | "library": { 55 | "value": "ONL", 56 | "desc": "O'Neill" 57 | }, 58 | "location": { 59 | "value": "STACK", 60 | "desc": "Stacks (STACK)" 61 | }, 62 | "pages": "", 63 | "pieces": "", 64 | "requested": false, 65 | "edition": null, 66 | "imprint": null, 67 | "language": null, 68 | "creation_date": "2012-06-10Z", 69 | "modification_date": "2012-06-10Z", 70 | "base_status": { 71 | "value": "1", 72 | "desc": "Item in place" 73 | }, 74 | "physical_material_type": { 75 | "value": "BOOK", 76 | "desc": "Book" 77 | }, 78 | "po_line": "08-000030003", 79 | "is_magnetic": false, 80 | "year_of_issue": "", 81 | "enumeration_a": "", 82 | "chronology_i": "", 83 | "receiving_operator": "", 84 | "process_type": { 85 | "value": "", 86 | "desc": null 87 | }, 88 | "alternative_call_number": "", 89 | "alternative_call_number_type": { 90 | "value": "", 91 | "desc": null 92 | }, 93 | "storage_location_id": "", 94 | "public_note": "", 95 | "fulfillment_note": "", 96 | "internal_note_1": "", 97 | "internal_note_2": "", 98 | "internal_note_3": "", 99 | "statistics_note_1": "", 100 | "statistics_note_2": "", 101 | "statistics_note_3": "" 102 | } 103 | } -------------------------------------------------------------------------------- /speedtest/time_get_bibs.py: -------------------------------------------------------------------------------- 1 | from pprint import pprint 2 | # first import the library and create an api object 3 | from pyalma.alma import Alma 4 | from datetime import datetime 5 | import csv 6 | 7 | api = Alma(apikey='', region='') 8 | 9 | 10 | # creates a list of ids of number length 11 | # def create_id_list(number): 12 | # ids = [] 13 | # counter = number 14 | # while counter > 0: 15 | # ids.append('9927390750001551') 16 | # counter -= 1 17 | # return ids 18 | 19 | 20 | # def test_normal(mm_ids): 21 | # # creates a datetime object showing how long it took for mm_ids 22 | # # to be retrieved serially 23 | # begin = datetime.now() 24 | # bibs = [] 25 | # for mm_id in mm_ids: 26 | # bib = api.get_bib(mm_id) 27 | # bibs.append(bib) 28 | # # pprint(bib) 29 | # end = datetime.now() 30 | # diff = end - begin 31 | # print('Returned {} normal bibs'.format(len(bibs))) 32 | # return diff 33 | 34 | 35 | def test_coroutines(mms_ids): 36 | # creates a datetime object showing long it took for mm_ids 37 | # to be retrieved async via coroutines 38 | begin = datetime.now() 39 | input_params = [{"ids": {'mms_id': mms_id}, "data": None} for mms_id in mms_ids] 40 | bibs = api.cor_get_bibs(input_params) 41 | end = datetime.now() 42 | diff = end - begin 43 | count = 0 44 | for bib in bibs: 45 | if bib[1] > 200: 46 | count += 1 47 | print('\n\nReturned {} coroutine bibs, with {} errors'.format((len(bibs)-count),count)) 48 | return [diff, bibs] 49 | 50 | 51 | def list_from_csv(csvfile, number): 52 | with open(csvfile, 'rt', encoding='utf8') as handle: 53 | reader = csv.reader(handle) 54 | ids = [] 55 | counter = number 56 | for row in reader: 57 | if counter > 0: 58 | ids.append(row[0]) 59 | counter -= 1 60 | return ids 61 | 62 | 63 | def test_repeat_bibs(): 64 | num = int(input("Enter number of items to test: ")) 65 | ids = create_id_list(num) 66 | t_coroutine = test_coroutines(ids) 67 | print("\n\nTime elapsed for {} ids: \n Coroutines: {} \n ".format(num, t_coroutine[0])) 68 | 69 | 70 | def write_to_csv(coroutines): 71 | with open('bibs_output.csv', 'w') as csvfile: 72 | bibwriter = csv.writer(csvfile) 73 | # bibwriter.writerow(['mms_id', 'status', 'msg']) 74 | bib_list = coroutines 75 | bibwriter.writerow(["ids", "status", "msg"]) 76 | for bib in bib_list: 77 | bibwriter.writerow(bib) 78 | 79 | 80 | def test_from_csv(handle, num): 81 | ids = list_from_csv(handle, num) 82 | t_coroutine = test_coroutines(ids) 83 | print("\n\nTime elapsed for {} ids: \n Coroutines: {} \n ".format(num, t_coroutine[0])) 84 | return t_coroutine[1] 85 | 86 | 87 | if __name__ == '__main__': 88 | num = int(input("Enter number of items to test: ")) 89 | handle = 'bibs.csv' 90 | bib_list = test_from_csv(handle, num) 91 | write_to_csv(bib_list) 92 | -------------------------------------------------------------------------------- /test/items.dat: -------------------------------------------------------------------------------- 1 | { 2 | "item": [ 3 | { 4 | "link": "/almaws/v1/bibs/99100383900121/holdings/2221159990000121/items/2321159970000121", 5 | "bib_data": { 6 | "title": "Data base", 7 | "issn": "0095-0033", 8 | "link": "/almaws/v1/bibs/99100383900121", 9 | "mms_id": 99100383900121, 10 | "place_of_publication": "New York :", 11 | "publisher_const": "Association for Computing Machinery", 12 | "network_number": [ 13 | "(CONSER) 2011250895", 14 | "(CKB)954926959913", 15 | "(OCoLC)604911177" 16 | ] 17 | }, 18 | "holding_data": { 19 | "link": "/almaws/v1/bibs/99100383900121/holdings/2221159990000121", 20 | "holding_id": "2221159990000121", 21 | "temp_library": { 22 | "value": null, 23 | "desc": null 24 | }, 25 | "temp_location": { 26 | "value": null, 27 | "desc": null 28 | } 29 | }, 30 | "item_data": { 31 | "pid": "2321159970000121", 32 | "description": null, 33 | "library": { 34 | "value": "65144020000121", 35 | "desc": "BURNS" 36 | }, 37 | "location": { 38 | "value": "UNASSIGNED", 39 | "desc": "UNASSIGNED location" 40 | }, 41 | "requested": false, 42 | "physical_material_type": { 43 | "value": "ISSUE", 44 | "desc": "journal" 45 | }, 46 | "process_type": { 47 | "value": "ACQ", 48 | "desc": "Acquisition" 49 | }, 50 | "po_line": "POL-67552" 51 | } 52 | }, 53 | { 54 | "link": "/almaws/v1/bibs/99100383900121/holdings/2221159990000121/items/2321159980000121", 55 | "bib_data": { 56 | "title": "Data base", 57 | "issn": "0095-0033", 58 | "link": "/almaws/v1/bibs/99100383900121", 59 | "mms_id": 99100383900121, 60 | "place_of_publication": "New York :", 61 | "publisher_const": "Association for Computing Machinery", 62 | "network_number": [ 63 | "(CONSER) 2011250895", 64 | "(CKB)954926959913", 65 | "(OCoLC)604911177" 66 | ] 67 | }, 68 | "holding_data": { 69 | "link": "/almaws/v1/bibs/99100383900121/holdings/2221159990000121", 70 | "holding_id": "2221159990000121", 71 | "temp_library": { 72 | "value": null, 73 | "desc": null 74 | }, 75 | "temp_location": { 76 | "value": null, 77 | "desc": null 78 | } 79 | }, 80 | "item_data": { 81 | "pid": "2321159980000121", 82 | "description": null, 83 | "library": { 84 | "value": "65144020000121", 85 | "desc": "BURNS" 86 | }, 87 | "location": { 88 | "value": "UNASSIGNED", 89 | "desc": "UNASSIGNED location" 90 | }, 91 | "requested": false, 92 | "physical_material_type": { 93 | "value": "ISSUE", 94 | "desc": "journal" 95 | }, 96 | "process_type": { 97 | "value": "ACQ", 98 | "desc": "Acquisition" 99 | }, 100 | "po_line": "POL-67551" 101 | } 102 | } 103 | ], 104 | "total_record_count": 2 105 | } 106 | -------------------------------------------------------------------------------- /test/bib.dat: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "mms_id": 9922405930001552, 4 | "holdings": { 5 | "value": null, 6 | "link": "https://api-na.hosted.exlibrisgroup.com/almaws/v1/bibs/9922405930001551/holdings" 7 | }, 8 | "created_by": "import", 9 | "created_date": "2013-07-14Z", 10 | "anies": [ 11 | "\n\n 01229cam a2200397 a 4504\n 333281\n 20130704111532.0\n 940217s1992 ctua b 001 0 eng d\n \n 94-B3418\n \n \n 333281\n \n \n (OCoLC)28384525\n \n \n (CMalG)333281-gettydb-Voyager\n \n \n CPaHP\n CPaHP\n CMalG\n \n \n P93.5\n .T84 1992\n \n \n Tufte, Edward R.,\n 1942-\n \n \n Envisioning information /\n Edward R. Tufte.\n \n \n 3rd printing, with revisions.\n \n \n Cheshire, Conn. :\n Graphics Press,\n 1992.\n \n \n 126 p. :\n ill. (some col.) ;\n 28 cm.\n \n \n Includes bibliographical references and index.\n \n \n Visual communication.\n \n \n 1\n 02/17/94 SMT\n MAI\n DZ\n \n \n BKH\n \n \n LCON02\n 48.00\n \n \n pr/48.00,inv#016687,invd940126,inrd940217\n \n \n JRA\n \n \n cica\n \n \n b1336991x\n 12-20-00\n 04-28-95\n cc\n 01-01-95\n a\n \n \n c\n \n \n CONS\n \n \n 1\n 94-B3418-1\n 33125006577916\n 07/28/94 C\n \n \n 33125006577916\n \n \n 0\n \n \n 1\n 07/27/94 CAT\n CONS\n CONS\n 02/17/94 REC\n \n \n 94-B03418\n \n \n Conservation collection (Getty Research Institute)\n \n \n 9116\n CMalG\n MSW\n MSW\n CJPA\n \n " 12 | ], 13 | "link": null 14 | 15 | } -------------------------------------------------------------------------------- /test/bib2.dat: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "mms_id": 9922405930001552, 4 | "holdings": { 5 | "value": null, 6 | "link": "https://api-na.hosted.exlibrisgroup.com/almaws/v1/bibs/9922405930001551/holdings" 7 | }, 8 | "created_by": "import", 9 | "created_date": "2013-07-14Z", 10 | "anies": [ 11 | "\n\n 01229cam a2200397 a 4504\n 333281\n 20130704111532.0\n 940217s1992 ctua b 001 0 eng d\n \n 94-B3418\n \n \n 333281\n \n \n (OCoLC)28384525\n \n \n (CMalG)333281-gettydb-Voyager\n \n \n CPaHP\n CPaHP\n CMalG\n \n \n P93.5\n .T84 1992\n \n \n Tuft, Edward R.,\n 1942-\n \n \n Envisioning information /\n Edward R. Tuft.\n \n \n 3rd printing, with revisions.\n \n \n Cheshire, Conn. :\n Graphics Press,\n 1992.\n \n \n 126 p. :\n ill. (some col.) ;\n 28 cm.\n \n \n Includes bibliographical references and index.\n \n \n Visual communication.\n \n \n 1\n 02/17/94 SMT\n MAI\n DZ\n \n \n BKH\n \n \n LCON02\n 48.00\n \n \n pr/48.00,inv#016687,invd940126,inrd940217\n \n \n JRA\n \n \n cica\n \n \n b1336991x\n 12-20-00\n 04-28-95\n cc\n 01-01-95\n a\n \n \n c\n \n \n CONS\n \n \n 1\n 94-B3418-1\n 33125006577916\n 07/28/94 C\n \n \n 33125006577916\n \n \n 0\n \n \n 1\n 07/27/94 CAT\n CONS\n CONS\n 02/17/94 REC\n \n \n 94-B03418\n \n \n Conservation collection (Getty Research Institute)\n \n \n 9116\n CMalG\n MSW\n MSW\n CJPA\n \n " 12 | ], 13 | "link": null 14 | 15 | } -------------------------------------------------------------------------------- /test/bib.dat.xml: -------------------------------------------------------------------------------- 1 | 9922405930001551import2013-07-14Z 2 | 01229cam a2200397 a 4504 3 | 333281 4 | 20130704111532.0 5 | 940217s1992 ctua b 001 0 eng d 6 | 7 | 94-B3418 8 | 9 | 10 | 333281 11 | 12 | 13 | (OCoLC)28384525 14 | 15 | 16 | (CMalG)333281-gettydb-Voyager 17 | 18 | 19 | CPaHP 20 | CPaHP 21 | CMalG 22 | 23 | 24 | P93.5 25 | .T84 1992 26 | 27 | 28 | Tufte, Edward R., 29 | 1942- 30 | 31 | 32 | Envisioning information / 33 | Edward R. Tufte. 34 | 35 | 36 | 3rd printing, with revisions. 37 | 38 | 39 | Cheshire, Conn. : 40 | Graphics Press, 41 | 1992. 42 | 43 | 44 | 126 p. : 45 | ill. (some col.) ; 46 | 28 cm. 47 | 48 | 49 | Includes bibliographical references and index. 50 | 51 | 52 | Visual communication. 53 | 54 | 55 | 1 56 | 02/17/94 SMT 57 | MAI 58 | DZ 59 | 60 | 61 | BKH 62 | 63 | 64 | LCON02 65 | 48.00 66 | 67 | 68 | pr/48.00,inv#016687,invd940126,inrd940217 69 | 70 | 71 | JRA 72 | 73 | 74 | cica 75 | 76 | 77 | b1336991x 78 | 12-20-00 79 | 04-28-95 80 | cc 81 | 01-01-95 82 | a 83 | 84 | 85 | c 86 | 87 | 88 | CONS 89 | 90 | 91 | 1 92 | 94-B3418-1 93 | 33125006577916 94 | 07/28/94 C 95 | 96 | 97 | 33125006577916 98 | 99 | 100 | 0 101 | 102 | 103 | 1 104 | 07/27/94 CAT 105 | CONS 106 | CONS 107 | 02/17/94 REC 108 | 109 | 110 | 94-B03418 111 | 112 | 113 | Conservation collection (Getty Research Institute) 114 | 115 | 116 | 9116 117 | CMalG 118 | MSW 119 | MSW 120 | CJPA 121 | 122 | -------------------------------------------------------------------------------- /test/bib2.dat.xml: -------------------------------------------------------------------------------- 1 | 9922405930001551import2013-07-14Z 2 | 01229cam a2200397 a 4504 3 | 333281 4 | 20130704111532.0 5 | 940217s1992 ctua b 001 0 eng d 6 | 7 | 94-B3418 8 | 9 | 10 | 333281 11 | 12 | 13 | (OCoLC)28384525 14 | 15 | 16 | (CMalG)333281-gettydb-Voyager 17 | 18 | 19 | CPaHP 20 | CPaHP 21 | CMalG 22 | 23 | 24 | P93.5 25 | .T84 1992 26 | 27 | 28 | Tuft, Edward R., 29 | 1942- 30 | 31 | 32 | Envisioning information / 33 | Edward R. Tuft. 34 | 35 | 36 | 3rd printing, with revisions. 37 | 38 | 39 | Cheshire, Conn. : 40 | Graphics Press, 41 | 1992. 42 | 43 | 44 | 126 p. : 45 | ill. (some col.) ; 46 | 28 cm. 47 | 48 | 49 | Includes bibliographical references and index. 50 | 51 | 52 | Visual communication. 53 | 54 | 55 | 1 56 | 02/17/94 SMT 57 | MAI 58 | DZ 59 | 60 | 61 | BKH 62 | 63 | 64 | LCON02 65 | 48.00 66 | 67 | 68 | pr/48.00,inv#016687,invd940126,inrd940217 69 | 70 | 71 | JRA 72 | 73 | 74 | cica 75 | 76 | 77 | b1336991x 78 | 12-20-00 79 | 04-28-95 80 | cc 81 | 01-01-95 82 | a 83 | 84 | 85 | c 86 | 87 | 88 | CONS 89 | 90 | 91 | 1 92 | 94-B3418-1 93 | 33125006577916 94 | 07/28/94 C 95 | 96 | 97 | 33125006577916 98 | 99 | 100 | 0 101 | 102 | 103 | 1 104 | 07/27/94 CAT 105 | CONS 106 | CONS 107 | 02/17/94 REC 108 | 109 | 110 | 94-B03418 111 | 112 | 113 | Conservation collection (Getty Research Institute) 114 | 115 | 116 | 9116 117 | CMalG 118 | MSW 119 | MSW 120 | CJPA 121 | 122 | -------------------------------------------------------------------------------- /speedtest/coroutines_speedtest.py: -------------------------------------------------------------------------------- 1 | from pyalma import alma 2 | from datetime import datetime 3 | import csv 4 | import ast 5 | 6 | ''' 7 | The following is a series of functional tests that will 8 | allow you to run speed tests on coroutine methods. 9 | To use, set the number of items you want to test in "TEST_NUM" 10 | You can only test one method at a time. 11 | However, the suite is designed to be run sequentially, to generate the 12 | files you need for later tests. 13 | ''' 14 | 15 | 16 | # set the number of items you would like to test 17 | TEST_NUM = 1000 18 | API_KEY = '' 19 | REGION = '' 20 | 21 | api = alma.Alma(API_KEY, REGION) 22 | 23 | 24 | def list_from_csv(csvfile, number): 25 | ''' 26 | Takes a csv file, column headings may be either: 27 | - ids (with each row containin a dictionary of mms_id, 28 | holding_id, item_pid, and/or request_id)and data, 29 | OR 30 | - mms_id, holding_id, item_pid, and or request_id; and data 31 | Returns a list of dictionaries in format required for coroutines: 32 | [{ 33 | 'data': data, 34 | 'ids': { 35 | 'mms_id': mms_id, 36 | 'holding_id': holding_id, 37 | 'item_pid': item_pid, 38 | 'request_id': request_id 39 | } 40 | }, 41 | ... 42 | ] 43 | ''' 44 | with open(csvfile, 'rt') as handle: 45 | reader = csv.DictReader(handle, delimiter=',') 46 | headers = reader.fieldnames 47 | dict_rows = [] 48 | count = number 49 | for row in reader: 50 | dict_row = {} 51 | if 'ids' not in headers: 52 | dict_row['ids'] = {} 53 | if count > 0: 54 | if 'data' not in headers: 55 | dict_row['data'] = None 56 | for header in headers: 57 | if header == 'data': 58 | dict_row[header] = row[header] 59 | elif header == "": 60 | continue 61 | else: 62 | dict_row['ids'][header] = row[header] 63 | dict_rows.append(dict_row) 64 | count -= 1 65 | else: 66 | break 67 | else: 68 | if count > 0: 69 | dict_row['ids'] = ast.literal_eval(row['ids']) 70 | dict_row['data'] = row['data'] 71 | dict_rows.append(dict_row) 72 | count -= 1 73 | else: 74 | break 75 | 76 | return dict_rows 77 | 78 | 79 | def write_to_csv(results, handle): 80 | ''' 81 | Takes a list of results (a list of dictionaries), 82 | Returns a CSV file with the given filename. 83 | ''' 84 | with open(handle, 'w') as csvfile: 85 | linewriter = csv.writer(csvfile) 86 | linewriter.writerow(["ids", "status", "data"]) 87 | for line in results: 88 | linewriter.writerow(line) 89 | 90 | 91 | def test_general(input_file, output_file, test_func): 92 | ''' 93 | Takes a CSV of the data you wish to feed into a function, the filename you 94 | desire for the output, and the name of the function you wish to test. 95 | Returns a list of results (a list of dictionaries). 96 | ''' 97 | begin = datetime.now() 98 | test_input = list_from_csv(input_file, TEST_NUM) 99 | test_output = test_func(test_input) 100 | output_len = len(test_output) 101 | end = datetime.now() 102 | diff = end - begin 103 | errors = 0 104 | for line in test_output: 105 | if line[1] > 200: 106 | errors += 1 107 | print('\n\nReturned {} rows, with {} errors'.format((output_len - errors), errors)) 108 | print("\n\nTime elapsed for {} ids: \n Coroutines: {} \n ".format(output_len, diff)) 109 | write_to_csv(test_output, output_file) 110 | return test_output 111 | 112 | 113 | ''' 114 | Below are tests for each coroutine method. 115 | ''' 116 | 117 | 118 | def test_cor_get_bib(input_file='test/mms.csv', 119 | output_file='test/output_get_bib.csv', content_type='xml', accept='xml'): 120 | print("\n\nTesting cor_get_bib") 121 | test_func = api.cor_get_bib 122 | return test_general(input_file, output_file, test_func) 123 | 124 | 125 | def test_cor_put_bib(input_file="test/output_get_bib.csv", 126 | output_file='test/output_put_bib.csv', content_type='xml', accept='xml'): 127 | print("\n\nTesting cor_put_bib") 128 | test_func = api.cor_put_bib 129 | return test_general(input_file, output_file, test_func) 130 | 131 | 132 | def test_cor_get_holdings(input_file='test/mms_in.csv', 133 | output_file='test/output_get_holdings.csv'): 134 | print("\n\nTesting cor_get_holdings") 135 | test_func = api.cor_get_holdings 136 | test_general(input_file, output_file, test_func) 137 | 138 | 139 | def test_cor_get_holding(input_file='test/mms_holding.csv', 140 | output_file="test/output_get_holding.csv"): 141 | print("\n\nTesting cor_get_holding") 142 | test_func = api.cor_get_holding 143 | test_general(input_file, output_file, test_func) 144 | 145 | 146 | def test_cor_put_holding(input_file='test/output_get_holding.csv', 147 | output_file='test/output_put_holding.csv'): 148 | print("\n\nTesting cor_put_holding") 149 | test_func = api.cor_put_holding 150 | test_general(input_file, output_file, test_func) 151 | 152 | def test_cor_get_items(input_file='test/mms_holding.csv', 153 | output_file='test/output_get_items.csv'): 154 | print("\n\nTesting cor_get_items") 155 | test_func = api.cor_get_items 156 | test_general(input_file, output_file, test_func) 157 | 158 | 159 | def test_cor_get_item(input_file='test/mms_holding_item.csv', 160 | output_file='test/output_get_item.csv'): 161 | print("\n\nTesting cor_get_item") 162 | test_func = api.cor_get_item 163 | test_general(input_file, output_file, test_func) 164 | 165 | 166 | def test_cor_put_item(input_file='test/output_get_item.csv', 167 | output_file='test/output_put_item.csv'): 168 | print("\n\nTesting cor_put_item") 169 | test_func = api.cor_put_item 170 | test_general(input_file, output_file, test_func) 171 | 172 | 173 | def test_cor_post_loan(input_file='test/mms_holding_item_data.csv', 174 | output_file='test/output_post_loan.csv'): 175 | print("\n\nTesting cor_post_loan") 176 | test_func = api.cor_post_loan 177 | test_general(input_file, output_file, test_func) 178 | 179 | 180 | def test_cor_get_bib_requests(input_file='test/mms_in.csv', 181 | output_file='test/output_get_bib_requests.csv'): 182 | print("\n\nTesting cor_get_bib_requests") 183 | test_func = api.cor_get_bib_requests 184 | test_general(input_file, output_file, test_func) 185 | 186 | 187 | def test_cor_get_item_requests(input_file='test/mms_holdings_items_with_requests.csv', 188 | output_file='test/output_get_item_requests.csv'): 189 | print("\n\nTesting cor_get_item_requests") 190 | test_func = api.cor_get_item_requests 191 | test_general(input_file, output_file, test_func) 192 | 193 | 194 | def test_cor_post_bib_request(input_file='test/item_request_objects.csv', 195 | output_file='test/output_post_bib_request.csv'): 196 | print("\n\nTesting cor_post_bib_request") 197 | test_func = api.cor_post_bib_request 198 | test_general(input_file, output_file, test_func) 199 | 200 | 201 | def test_cor_post_item_request(input_file='test/item_request_objects.csv', 202 | output_file='test/output_put_item_request.csv'): 203 | print("\n\nTesting cor_post_item_request") 204 | test_func = api.cor_post_item_request 205 | test_general(input_file, output_file, test_func) 206 | 207 | 208 | def test_cor_put_bib_request(input_file='test/output_get_bib_requests.csv', 209 | output_file='test/output_put_bib_request.csv'): 210 | print("\n\nTesting cor_put_bib_request") 211 | test_func = api.cor_put_bib_request 212 | test_general(input_file, output_file, test_func) 213 | 214 | def test_cor_put_item_request(input_file='test/output_get_item_requests.csv', 215 | output_file='test/output_put_item_request.csv'): 216 | print("\n\nTesting cor_put_item_request") 217 | test_func = api.cor_put_item_request 218 | test_general(input_file, output_file, test_func) 219 | 220 | 221 | def test_cor_del_item_request(input_file='test/item_request_objects.csv', 222 | output_file='test/output_del_item_request.csv'): 223 | print("\n\nTesting cor_del_item_request") 224 | test_func = api.cor_del_item_request 225 | test_general(input_file, output_file, test_func) 226 | 227 | 228 | def test_cor_del_bib_request(input_file='test/item_request_objects.csv', 229 | output_file='test/output_del_bib_request.csv'): 230 | print("\n\nTesting cor_del_bib_request") 231 | test_func = api.cor_del_bib_request 232 | test_general(input_file, output_file, test_func) 233 | 234 | 235 | def test_cor_get_bib_booking_availability(input_file='test/mms.csv', 236 | output_file='test/output_get_bib_booking_availability.csv'): 237 | print("\n\nTesting cor_get_bib_booking_availability") 238 | test_func = api.cor_get_bib_booking_availability 239 | test_general(input_file, output_file, test_func) 240 | 241 | 242 | def test_cor_get_item_booking_availability(input_file='test/mms_holding_item.csv', 243 | output_file='test/output_get_item_booking_availability.csv'): 244 | print("\n\nTesting cor_get_item_booking_availability") 245 | test_func = api.cor_get_item_booking_availability 246 | test_general(input_file, output_file, test_func) 247 | 248 | 249 | if __name__ == '__main__': 250 | 251 | test_cor_get_bib() 252 | # test_cor_put_bib() 253 | 254 | # test_cor_get_holdings() 255 | 256 | # test_cor_get_holding() 257 | # test_cor_put_holding() 258 | 259 | # test_cor_get_items() 260 | 261 | # test_cor_get_item() 262 | # test_cor_put_item() 263 | 264 | # test_cor_get_bib_requests() 265 | # test_cor_get_item_requests() 266 | 267 | 268 | 269 | ''' 270 | Tests below are for not finalized methods: 271 | ''' 272 | 273 | # test_cor_del_bib_request() 274 | # test_cor_del_item_request() 275 | 276 | # test_cor_post_loan() 277 | 278 | # test_cor_post_bib_request() 279 | # test_cor_post_item_request() 280 | 281 | # test_cor_put_bib_request() 282 | # test_cor_put_item_request() 283 | 284 | # test_cor_get_bib_booking_availability() 285 | # test_cor_get_item_booking_availability() 286 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/gri-is/pyalma.svg?branch=master)](https://travis-ci.org/gri-is/pyalma) 2 | 3 | [![Coverage Status](https://coveralls.io/repos/github/gri-is/pyalma/badge.svg?branch=master)](https://coveralls.io/github/gri-is/pyalma?branch=master) 4 | 5 | PyAlma 6 | ====== 7 | 8 | Developer Installation 9 | ---------------------- 10 | 11 | 0. Ensure that Python 3 is installed on your machine (https://www.python.org/downloads/) 12 | 13 | 1. Create a directory for development projects on your machine 14 | 15 | $ mkdir //projects 16 | $ cd //projects 17 | 18 | 2. Clone the repository 19 | 20 | $ git clone https://@stash.getty.edu/scm/griis/pyalma.git 21 | $ cd pyalma 22 | 23 | 3. Create a virtual environment and activate it 24 | 25 | $ pyvenv ENV 26 | $ source ENV/bin/activate 27 | 28 | 4. Install dependencies to the virtual environment 29 | 30 | (ENV)$ pip install -r requirements.txt 31 | 32 | 5. Run the tests to make sure everything works correctly 33 | 34 | (ENV)$ python -m unittest 35 | 36 | Developer Changes 37 | ----------------- 38 | 39 | 6. When working on a new issue, be sure to do so in a new branch 40 | 41 | (ENV)$ git branch 42 | (ENV)$ git checkout 43 | 44 | 7. Run a status check before doing any adds, commits or pushes 45 | 46 | (ENV)$ git status 47 | 48 | 8. Stage edited or newly created files 49 | 50 | (ENV)$ git status 51 | (ENV)$ git add 52 | 53 | 9. Commit the staged changes and ALWAYS explain the changes in a message 54 | 55 | (ENV)$ git status 56 | (ENV)$ git commit -m 57 | 58 | 10. Push the changes to the shared repository, using the same branch name 59 | 60 | (ENV)$ git status 61 | (ENV)$ git push origin 62 | 63 | 11. On the repository website create a pull request from your branch to the master branch 64 | 65 | 12. When your branch has been reviewed, approved, and merged, you can pull the master and delete your issue branch 66 | 67 | (ENV)$ git checkout master 68 | (ENV)$ git status 69 | (ENV)$ git pull origin master 70 | (ENV)$ git branch -d 71 | 72 | 73 | API KEY Configuration 74 | --------------------- 75 | 76 | The Alma API requires a secret API key. You must also point to correct regional endpoint, of which there are three: 77 | 78 | 1. US: https://api-na.hosted.exlibrisgroup.com 79 | 2. EU: https://api-eu.hosted.exlibrisgroup.com 80 | 3. APAC: https://api-ap.hosted.exlibrisgroup.com 81 | 82 | You can pass the key and region directly to the Alma object at the time of creation, like so: 83 | 84 | from pyalma.alma import Alma 85 | api = alma.Alma(apikey='xxxxxxxxxx', region='US') 86 | 87 | Or, you can create environment variables in your operating system and the Python client will find it. On a linux machine you can do this by editing the `/etc/environment` file, like so: 88 | 89 | ALMA_API_KEY=xxxxxxxxx 90 | ALMA_API_REGION=US 91 | 92 | After editing the `/etc/environment` file, be sure to reload it, like so: 93 | 94 | :$ source /etc/environment 95 | 96 | For Mac OSX, this may be slightly different. This document may be of some help: http://www.dowdandassociates.com/blog/content/howto-set-an-environment-variable-in-mac-os-x-terminal-only/ 97 | 98 | PyAlma Usage Example: 99 | --------------------- 100 | 101 | 1. After starting up a Python session, import the library and create an api object: 102 | 103 | >>> from pyalma.alma import Alma 104 | >>> api = Alma() 105 | 106 | Note: you can only do the above if you set your environment as described above. Otherwise you have to pass in your API key and region like so: 107 | 108 | >>> api = alma.Alma(apikey='xxxxxxxxxx', region='US') 109 | 110 | 2. Now go get your record: 111 | 112 | >>> bib = api.get_bib('9927390750001551') 113 | 114 | Note: The bib is in json format by default unless you pass in accept='xml' to the method. 115 | 116 | 3. To see the content of the bib you can print it: 117 | 118 | >>> from pprint import pprint 119 | >>> pprint(bib) 120 | {'anies': ['\n' 121 | '01523cam a2200481 a 4500992739075000155120160713120531.0940411s1992 cs a c 000 0 cze ' 125 | '3375229322573294-B7378337522(CMalG)337522-gettydb-Voyager(OCoLC)29550137DLCDLCCMalGczeengfregeritaspaN6834.5.M8A4 ' 144 | '1992N6834.5.M8A4 1992Kusák, ' 148 | 'Dalibor.Mucha /Dalibor Kusák, Marta ' 151 | 'Kadlečíková.Vyd. ' 153 | '1.Prague :BB/art,1992.1 v. (unpaged) :chiefly col. ill. ;31 ' 159 | 'cm.Text in Czech, English, French, ' 161 | 'German, Italian, and Spanish.Mucha, ' 163 | 'Alphonse,1860-1939Catalogs.Kadlečíková, ' 167 | 'Marta.Mucha, Alphonse,1860-1939.104/11/94 AGRMAIDAWSMLGET02pr/140.00,zc/gdm,inv#2652,invd940307,inrd940411JMEOCLC REC ' 182 | 'TESTb1341286302-20-9704-28-95cc01-01-95acOCLC ' 191 | 'D160706.R807645 20160708MAIN194-B7378-13312500703729004/13/94 ' 197 | 'C331250070372900104/13/94 CATMAINMAIN04/11/94 ' 206 | 'REC94-B073789110CMalGAGRGCSCJPA'], 213 | 'author': 'Kusák, Dalibor.', 214 | 'complete_edition': 'Vyd. 1.', 215 | 'created_by': 'import', 216 | 'created_date': '2013-07-14Z', 217 | 'holdings': {'link': 'https://api-na.hosted.exlibrisgroup.com/almaws/v1/bibs/9927390750001551/holdings', 218 | 'value': None}, 219 | 'isbn': None, 220 | 'issn': None, 221 | 'last_modified_by': 'System', 222 | 'last_modified_date': '2016-07-13Z', 223 | 'link': None, 224 | 'linked_record_id': {'type': None, 'value': None}, 225 | 'mms_id': '9927390750001551', 226 | 'network_number': ['(OCoLC)29550137', 227 | '(CMalG)337522-gettydb-Voyager', 228 | '337522'], 229 | 'originating_system': 'OTHER', 230 | 'originating_system_id': '337522-gettydb', 231 | 'place_of_publication': 'Prague :', 232 | 'publisher_const': 'BB/art', 233 | 'record_format': 'marc21', 234 | 'suppress_from_publishing': 'false', 235 | 'title': 'Mucha /'} 236 | 237 | Note: the MARC data appears as an XML string inside the JSON. 238 | -------------------------------------------------------------------------------- /test/test_coroutines.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | from importlib import reload 4 | 5 | from pyalma import alma 6 | 7 | import asyncio 8 | import aiohttp 9 | import asynctest 10 | from aioresponses import aioresponses 11 | 12 | from datetime import datetime 13 | 14 | 15 | def setUpModule(): 16 | os.environ['ALMA_API_KEY'] = 'my fake key' 17 | os.environ['ALMA_API_REGION'] = 'APAC' 18 | reload(alma) 19 | 20 | 21 | class TestAsyncRequests(asynctest.TestCase): 22 | 23 | maxDiff = None 24 | 25 | def setUp(self): 26 | self.api = alma.Alma(apikey='unreal', region='US') 27 | 28 | def test_cor_run(self): 29 | loop = asyncio.get_event_loop() 30 | ids = {'mms_id': 9922405930001552} 31 | url = self.api.fullurl('bib', ids) 32 | fh = open('test/bib.dat', 'r') 33 | body = fh.read() 34 | fh.close() 35 | # session = aiohttp.ClientSession() 36 | with aioresponses() as m: 37 | m.get(url, 38 | status=200, 39 | content_type='application/json', 40 | body=body) 41 | resp = loop.run_until_complete(self.api.cor_run('GET', 'bib', [{'ids': ids, 'data':None}], accept='json')) 42 | data = resp[0][2] 43 | self.assertEqual(data, json.loads(body)) 44 | 45 | def test_cor_request(self): 46 | loop = asyncio.get_event_loop() 47 | ids = {'mms_id': 9922405930001552} 48 | url = self.api.fullurl('bib', ids) 49 | fh = open('test/bib.dat', 'r') 50 | body = fh.read() 51 | fh.close() 52 | session = aiohttp.ClientSession() 53 | # creating a session outside of a coroutine is not advised 54 | # and throws a warning. 55 | # but I could not figure out another way 56 | with aioresponses() as m: 57 | m.get(url, 58 | status=200, 59 | content_type='application/json', 60 | body=body) 61 | resp = loop.run_until_complete(self.api.cor_request('GET', 'bib', ids, session, accept='json')) 62 | data = resp[2] 63 | self.assertEqual(data, json.loads(body)) 64 | session.close() 65 | 66 | ''' 67 | Below test is not working because searching the long list of 68 | mock objects slows it down so much that the program becomes too slow 69 | to test the semaphore limit 70 | ''' 71 | 72 | # def test_semaphore(self): 73 | # self.api.max_calls = 100000 74 | # self.semaphore_limit = 2 75 | # ids = {'mms_id': 9922405930001552} 76 | # ids_in = {'ids': {'mms_id': 9922405930001552}, 'data': None} 77 | # ids_list = [ids_in] * 100 78 | # url = self.api.fullurl('bib', ids) 79 | # fh = open('test/bib.dat', 'r') 80 | # body = fh.read() 81 | # fh.close() 82 | # with aioresponses() as m: 83 | # for i in enumerate(ids_list): 84 | # m.get(url, 85 | # status=200, 86 | # content_type='application/json', 87 | # body=body) 88 | # begin = datetime.now() 89 | # resp = self.api.cor_get_bib(ids_list) 90 | # end = datetime.now() 91 | # time_to_finish = (end - begin).total_seconds() 92 | # items_finished = len(resp) 93 | # print(self.api.max_calls) 94 | # print(items_finished/time_to_finish) 95 | # self.assertTrue(self.api.max_calls >= items_finished/time_to_finish) 96 | 97 | def test_rate_limit(self): 98 | self.api.max_calls = 20 99 | # self.semaphore_limit = 500 100 | ids = {'mms_id': 9922405930001552} 101 | ids_in = {'ids': {'mms_id': 9922405930001552}, 'data': None} 102 | ids_list = [ids_in] * 40 103 | url = self.api.fullurl('bib', ids) 104 | fh = open('test/bib.dat', 'r') 105 | body = fh.read() 106 | fh.close() 107 | with aioresponses() as m: 108 | for i in enumerate(ids_list): 109 | m.get(url, 110 | status=200, 111 | content_type='application/json', 112 | body=body) 113 | begin = datetime.now() 114 | resp = self.api.cor_get_bib(ids_list) 115 | end = datetime.now() 116 | time_to_finish = (end - begin).total_seconds() 117 | items_finished = len(resp) 118 | self.assertTrue(self.api.max_calls >= items_finished/time_to_finish) 119 | 120 | 121 | def test_cor_get_bib(self): 122 | ids = {'mms_id': 9922405930001552} 123 | url = self.api.fullurl('bib', ids) 124 | fh = open('test/bib.dat', 'r') 125 | body = fh.read() 126 | fh.close() 127 | # session = aiohttp.ClientSession() 128 | with aioresponses() as m: 129 | m.get(url, 130 | status=200, 131 | content_type='application/json', 132 | body=body) 133 | resp = self.api.cor_get_bib([{'ids':ids,'data':None}]) 134 | bib = resp[0][2] 135 | self.assertEqual(bib, json.loads(body)) 136 | 137 | def test_cor_get_holdings(self): 138 | ids = {'mms_id': 99100383900121} 139 | url = self.api.fullurl('holdings', ids) 140 | fh = open('test/holds.dat', 'r') 141 | body = fh.read() 142 | fh.close() 143 | # session = aiohttp.ClientSession() 144 | with aioresponses() as m: 145 | m.get(url, 146 | status=200, 147 | content_type='application/json', 148 | body=body) 149 | resp = self.api.cor_get_holdings([{'ids':ids,'data':None}]) 150 | holdings = resp[0][2] 151 | self.assertEqual(holdings, json.loads(body)) 152 | 153 | def test_cor_get_holding(self): 154 | ids = {'mms_id': 9922405930001552, 'holding_id': 22115858660001551} 155 | url = self.api.fullurl('holding', ids) 156 | fh = open('test/hold.dat', 'r') 157 | body = fh.read() 158 | fh.close() 159 | # session = aiohttp.ClientSession() 160 | with aioresponses() as m: 161 | m.get(url, 162 | status=200, 163 | content_type='application/json', 164 | body=body) 165 | resp = self.api.cor_get_holding([{'ids':ids,'data':None}]) 166 | holding_data = resp[0][2] 167 | self.assertEqual(holding_data, json.loads(body)) 168 | 169 | def test_cor_get_items(self): 170 | ids = {'mms_id': 9922405930001552, 'holding_id': 22115858660001551} 171 | url = self.api.fullurl('items', ids) 172 | fh = open('test/items.dat', 'r') 173 | body = fh.read() 174 | fh.close() 175 | # session = aiohttp.ClientSession() 176 | with aioresponses() as m: 177 | m.get(url, 178 | status=200, 179 | content_type='application/json', 180 | body=body) 181 | resp = self.api.cor_get_items([{'ids': ids, 'data':None}]) 182 | items_data = resp[0][2] 183 | self.assertEqual(items_data, json.loads(body)) 184 | 185 | def test_cor_get_bib_requests(self): 186 | ids = {'mms_id': 9922405930001552} 187 | url = self.api.fullurl('bib_requests', ids) 188 | fh = open('test/request.dat', 'r') 189 | body = fh.read() 190 | fh.close() 191 | # session = aiohttp.ClientSession() 192 | with aioresponses() as m: 193 | m.get(url, 194 | status=200, 195 | content_type='application/json', 196 | body=body) 197 | resp = self.api.cor_get_bib_requests([{'ids': ids, 'data':None}]) 198 | bib_requests_data = resp[0][2] 199 | self.assertEqual(bib_requests_data, json.loads(body)) 200 | 201 | def test_cor_get_item_requests(self): 202 | ids = {'mms_id': 9922405930001552, 'holding_id': 22115858660001551, 'item_pid': 23115858650001551} 203 | url = self.api.fullurl('item_requests', ids) 204 | fh = open('test/request.dat', 'r') 205 | body = fh.read() 206 | fh.close() 207 | # session = aiohttp.ClientSession() 208 | with aioresponses() as m: 209 | m.get(url, 210 | status=200, 211 | content_type='application/json', 212 | body=body) 213 | resp = self.api.cor_get_item_requests([{'ids': ids, 'data':None}]) 214 | item_requests_data = resp[0][2] 215 | self.assertEqual(item_requests_data, json.loads(body)) 216 | 217 | def test_cor_put_bib(self): 218 | ids = {'mms_id': 9922405930001552} 219 | url = self.api.fullurl('bib', ids) 220 | fh = open('test/bib2.dat', 'r') 221 | original_bib = fh.read() 222 | fh.close() 223 | # session = aiohttp.ClientSession() 224 | with aioresponses() as m: 225 | m.put(url, 226 | status=200, 227 | content_type='application/xml', 228 | body=original_bib) 229 | resp = self.api.cor_put_bib([{'ids': ids, 'data': original_bib}]) 230 | returned_bib = resp[0][2] 231 | self.assertEqual(original_bib, returned_bib) 232 | 233 | def test_cor_put_holding(self): 234 | ids = {'mms_id': 9922405930001552, 'holding_id': 22115858660001551} 235 | url = self.api.fullurl('holding', ids) 236 | fh = open('test/hold2.dat', 'r') 237 | original_holding = fh.read() 238 | fh.close() 239 | # session = aiohttp.ClientSession() 240 | with aioresponses() as m: 241 | m.put(url, 242 | status=200, 243 | content_type='application/xml', 244 | body=original_holding) 245 | resp = self.api.cor_put_holding([{'ids': ids, 'data': original_holding}]) 246 | returned_holding = resp[0][2] 247 | self.assertEqual(original_holding, returned_holding) 248 | 249 | def test_cor_put_item(self): 250 | ids = {'mms_id': 99110223950001020, 'holding_id': 22344156400001021, 'item_pid': 23344156380001021} 251 | url = self.api.fullurl('item', ids) 252 | fh = open('test/item2.dat', 'r') 253 | original_item = fh.read() 254 | fh.close() 255 | # session = aiohttp.ClientSession() 256 | with aioresponses() as m: 257 | m.put(url, 258 | status=200, 259 | content_type='application/xml', 260 | body=original_item) 261 | resp = self.api.cor_put_item([{'ids': ids, 'data': original_item}]) 262 | returned_item = resp[0][2] 263 | self.assertEqual(original_item, returned_item) 264 | 265 | def test_cor_del_bib_request(self): 266 | ids = {'mms_id': 9922405930001552, 'request_id': 83013520000121} 267 | url = self.api.fullurl('bib_request', ids) 268 | with aioresponses() as m: 269 | m.delete(url, 270 | status=200, 271 | content_type='application/xml', 272 | body='') 273 | expected = '' 274 | resp = self.api.cor_del_bib_request([{'ids': ids, 'data': None}]) 275 | bib_request_response = resp[0][2] 276 | self.assertEqual(expected, bib_request_response) 277 | 278 | def test_cor_del_item_request(self): 279 | ids = {'mms_id': 9922405930001552, 'holding_id': 22115858660001551, 'item_pid': 23115858650001551, 'request_id': 83013520000121} 280 | url = self.api.fullurl('item_request', ids) 281 | with aioresponses() as m: 282 | m.delete(url, 283 | status=200, 284 | content_type='application/xml', 285 | body='') 286 | expected = '' 287 | resp = self.api.cor_del_item_request([{'ids': ids, 'data': None}]) 288 | item_request_response = resp[0][2] 289 | self.assertEqual(expected, item_request_response) 290 | 291 | if __name__ == '__main__': 292 | asynctest.main() 293 | -------------------------------------------------------------------------------- /test/test_alma.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import re 4 | from importlib import reload 5 | import unittest 6 | 7 | import responses 8 | 9 | from pyalma import alma 10 | 11 | 12 | def setUpModule(): 13 | os.environ['ALMA_API_KEY'] = 'my fake key' 14 | os.environ['ALMA_API_REGION'] = 'APAC' 15 | reload(alma) 16 | 17 | 18 | class TestAlmaSetup(unittest.TestCase): 19 | 20 | def test_init(self): 21 | api = alma.Alma(apikey='unreal', region='EU') 22 | self.assertEqual(api.apikey, 'unreal') 23 | self.assertEqual(api.endpoint, alma.ENDPOINTS['EU']) 24 | 25 | def test_init_errors(self): 26 | self.assertRaises(Exception, alma.Alma, **{'apikey': None}) 27 | self.assertRaises(Exception, alma.Alma, **{'region': None}) 28 | self.assertRaises(Exception, alma.Alma, **{'region': 'XX'}) 29 | 30 | def test_init_env_vars(self): 31 | api = alma.Alma() 32 | self.assertEqual(api.apikey, 'my fake key') 33 | self.assertEqual(api.endpoint, alma.ENDPOINTS['APAC']) 34 | 35 | def test_baseurl(self): 36 | api = alma.Alma() 37 | url = 'https://api-ap.hosted.exlibrisgroup.com/almaws/v1/' 38 | self.assertEqual(api.baseurl, url) 39 | 40 | def test_fullurl(self): 41 | ids = {'mms_id': 7777777, 'holding_id': 55555, 'item_pid': 333} 42 | expect = 'https://api-ap.hosted.exlibrisgroup.com/almaws/v1/' 43 | expect += 'bibs/7777777/holdings/55555/items/333' 44 | url = alma.Alma().fullurl('item', ids) 45 | self.assertEqual(url, expect) 46 | 47 | def test_headers(self): 48 | expect = { 49 | 'User-Agent': 'pyalma/0.1.0', 50 | 'Authorization': 'apikey my fake key', 51 | 'Accept': 'application/json', 52 | 'Content-Type': 'application/xml' 53 | } 54 | headers = alma.Alma().headers(content_type='xml') 55 | self.assertEqual(headers, expect) 56 | 57 | 58 | class TestAlmaGETRequests(unittest.TestCase): 59 | maxDiff = None 60 | 61 | def setUp(self): 62 | self.api = alma.Alma(apikey='unreal', region='EU') 63 | 64 | def buildResponses(self): 65 | # bib mock response 66 | biburl = self.api.baseurl + r'bibs/\d+$' 67 | bib_re = re.compile(biburl) 68 | with open('test/bib.dat', 'r') as b: 69 | responses.add(responses.GET, bib_re, 70 | status=200, 71 | content_type='application/json', 72 | body=b.read()) 73 | 74 | # holdings mock response 75 | holdsurl = self.api.baseurl + r'bibs/\d+/holdings$' 76 | holds_re = re.compile(holdsurl) 77 | with open('test/holds.dat', 'r') as hs: 78 | responses.add(responses.GET, holds_re, 79 | status=200, 80 | content_type='application/json', 81 | body=hs.read()) 82 | 83 | # holding mock response 84 | holdurl = self.api.baseurl + r'bibs/\d+/holdings/\d+$' 85 | hold_re = re.compile(holdurl) 86 | with open('test/hold.dat', 'r') as h: 87 | responses.add(responses.GET, hold_re, 88 | status=200, 89 | content_type='application/json', 90 | body=h.read()) 91 | 92 | #items mock response 93 | itemsurl = self.api.baseurl + r'bibs/\d+/holdings/\d+/items$' 94 | items_re = re.compile(itemsurl) 95 | with open('test/items.dat', 'r') as its: 96 | responses.add(responses.GET, items_re, 97 | status=200, 98 | content_type='application/json', 99 | body=its.read()) 100 | 101 | # item mock response 102 | itemurl = self.api.baseurl + r'bibs/\d+/holdings/\d+/items/\d+$' 103 | item_re = re.compile(itemurl) 104 | with open('test/item.dat', 'r') as i: 105 | responses.add(responses.GET, item_re, 106 | status=200, 107 | content_type='application/json', 108 | body=i.read()) 109 | 110 | # bib_requests mock response 111 | bib_requestsurl = self.api.baseurl + r'bibs/\d+/requests' 112 | bib_requests_re = re.compile(bib_requestsurl) 113 | with open('test/request.dat', 'r') as f: 114 | responses.add(responses.GET, bib_requests_re, 115 | status=200, 116 | content_type='application/json', 117 | body=f.read()) 118 | 119 | # item_requests mock response 120 | item_requestsurl = self.api.baseurl + \ 121 | r'bibs/\d+/holdings/\d+/items/\d+/requests' 122 | item_requests_re = re.compile(item_requestsurl) 123 | with open('test/request.dat', 'r') as f: 124 | responses.add(responses.GET, item_requests_re, 125 | status=200, 126 | content_type='application/json', 127 | body=f.read()) 128 | 129 | # bib_booking_availability mock response 130 | bib_booking_availabilityurl = self.api.baseurl + \ 131 | r'bibs/\d+/booking-availability' 132 | bib_booking_availability_re = re.compile(bib_booking_availabilityurl) 133 | with open('test/availability.dat', 'r') as f: 134 | responses.add(responses.GET, bib_booking_availability_re, 135 | status=200, 136 | content_type='application/json', 137 | body=f.read()) 138 | 139 | # item_booking_availability mock response 140 | item_booking_availabilityurl = self.api.baseurl + \ 141 | r'bibs/\d+/holdings/\d+/items/\d+/booking-availability' 142 | item_booking_availability_re = re.compile(item_booking_availabilityurl) 143 | with open('test/availability.dat', 'r') as f: 144 | responses.add(responses.GET, item_booking_availability_re, 145 | status=200, 146 | content_type='application/json', 147 | body=f.read()) 148 | 149 | 150 | def buildXMLResponses(self): 151 | # bib mock response 152 | biburl = self.api.baseurl + r'bibs/\d+' 153 | bib_re = re.compile(biburl) 154 | with open('test/bib.dat.xml', 'r') as f: 155 | responses.add(responses.GET, bib_re, 156 | status=200, 157 | content_type='application/xml', 158 | body=f.read()) 159 | 160 | @responses.activate 161 | def test_alma_request(self): 162 | self.buildResponses() 163 | resp = self.api.request('GET', 'bib', {'mms_id': 9922405930001552}) 164 | data = resp.json() 165 | self.assertEqual(data['created_date'], '2013-07-14Z') 166 | 167 | @responses.activate 168 | def test_extract_content_xml(self): 169 | self.buildXMLResponses() 170 | resp = self.api.request('GET', 'bib', {'mms_id': 9922405930001552}) 171 | data = self.api.extract_content(resp) 172 | with open('test/bib.dat.xml', 'r') as dat: 173 | self.assertEqual(data, dat.read()) 174 | 175 | @responses.activate 176 | def test_extract_content_json(self): 177 | self.buildResponses() 178 | resp = self.api.request('GET', 'bib', {'mms_id': 9922405930001552}) 179 | data = self.api.extract_content(resp) 180 | with open('test/bib.dat', 'r') as dat: 181 | self.assertEqual(data, json.loads(dat.read())) 182 | 183 | @responses.activate 184 | def test_alma_get_bib(self): 185 | self.buildResponses() 186 | bib_data = self.api.get_bib(9922405930001552) 187 | with open('test/bib.dat', 'r') as dat: 188 | self.assertEqual(bib_data, json.loads(dat.read())) 189 | 190 | @responses.activate 191 | def test_alma_get_holdings(self): 192 | self.buildResponses() 193 | holdings_data = self.api.get_holdings(99100383900121) 194 | with open('test/holds.dat', 'r') as dat: 195 | self.assertEqual(holdings_data, json.loads(dat.read())) 196 | 197 | @responses.activate 198 | def test_alma_get_holding(self): 199 | self.buildResponses() 200 | holding_data = self.api.get_holding( 201 | 9922405930001552, 202 | 22115858660001551) 203 | with open('test/hold.dat', 'r') as dat: 204 | self.assertEqual(holding_data, json.loads(dat.read())) 205 | 206 | @responses.activate 207 | def test_alma_get_items(self): 208 | self.buildResponses() 209 | items_data = self.api.get_items(99100383900121, 2221159990000121) 210 | with open('test/items.dat', 'r') as dat: 211 | self.assertEqual(items_data, json.loads(dat.read())) 212 | 213 | @responses.activate 214 | def test_alma_get_item(self): 215 | self.buildResponses() 216 | item_data = self.api.get_item( 217 | 9922405930001552, 218 | 22115858660001551, 219 | 23115858650001551) 220 | with open('test/item.dat', 'r') as dat: 221 | self.assertEqual(item_data, json.loads(dat.read())) 222 | 223 | @responses.activate 224 | def test_alma_get_bib_requests(self): 225 | self.buildResponses() 226 | bib_requests_data = self.api.get_bib_requests(9922405930001552) 227 | with open('test/request.dat', 'r') as dat: 228 | self.assertEqual(bib_requests_data, json.loads(dat.read())) 229 | 230 | @responses.activate 231 | def test_alma_get_item_requests(self): 232 | self.buildResponses() 233 | item_requests_data = self.api.get_item_requests(9922405930001552, 234 | 22115858660001551, 235 | 23115858650001551) 236 | with open('test/request.dat', 'r') as dat: 237 | self.assertEqual(item_requests_data, json.loads(dat.read())) 238 | 239 | @responses.activate 240 | def test_alma_get_bib_booking_availability(self): 241 | self.buildResponses() 242 | bib_booking_availability_data = self.api.get_bib_booking_availability( 243 | 9922405930001552) 244 | with open('test/availability.dat', 'r') as dat: 245 | self.assertEqual( 246 | bib_booking_availability_data, json.loads(dat.read())) 247 | 248 | @responses.activate 249 | def test_alma_get_item_booking_availability(self): 250 | self.buildResponses() 251 | item_booking_availability_data = \ 252 | self.api.get_item_booking_availability(9922405930001552, 253 | 22115858660001551, 254 | 23115858650001551) 255 | with open('test/availability.dat', 'r') as dat: 256 | self.assertEqual( 257 | item_booking_availability_data, 258 | json.loads( 259 | dat.read())) 260 | 261 | 262 | class TestAlmaPUTRequests(unittest.TestCase): 263 | maxDiff = None 264 | 265 | def setUp(self): 266 | self.api = alma.Alma(apikey='unreal', region='EU') 267 | 268 | def buildResponses(self): 269 | 270 | def echo_body(request): 271 | return (200, {}, request.body) 272 | 273 | # bib mock response 274 | biburl = self.api.baseurl + r'bibs/\d+$' 275 | bib_re = re.compile(biburl) 276 | responses.add_callback( 277 | responses.PUT, bib_re, 278 | callback=echo_body, 279 | content_type='application/json', 280 | ) 281 | 282 | # holding mock response 283 | holdurl = self.api.baseurl + r'bibs/\d+/holdings/\d+$' 284 | hold_re = re.compile(holdurl) 285 | responses.add_callback( 286 | responses.PUT, hold_re, 287 | callback=echo_body, 288 | content_type='application/json', 289 | ) 290 | 291 | # item mock response 292 | itemurl = self.api.baseurl + r'bibs/\d+/holdings/\d+/items/\d+$' 293 | item_re = re.compile(itemurl) 294 | responses.add_callback( 295 | responses.PUT, item_re, 296 | callback=echo_body, 297 | content_type='application/json', 298 | ) 299 | 300 | # bib_request mock response 301 | bib_requesturl = self.api.baseurl + r'bibs/\d+/requests/\d+$' 302 | bib_request_re = re.compile(bib_requesturl) 303 | responses.add_callback( 304 | responses.PUT, bib_request_re, 305 | callback=echo_body, 306 | content_type='application/json' 307 | ) 308 | 309 | # item_request mock response 310 | item_requesturl = self.api.baseurl + r'bibs/\d+/holdings/\d+/items/\d+/requests/\d+$' 311 | item_request_re = re.compile(item_requesturl) 312 | responses.add_callback( 313 | responses.PUT, item_request_re, 314 | callback=echo_body, 315 | content_type='application/json', 316 | ) 317 | 318 | @responses.activate 319 | def test_alma_put_bib(self): 320 | self.buildResponses() 321 | with open('test/bib2.dat', 'r') as dat: 322 | original_bib = dat.read() 323 | returned_bib = self.api.put_bib(9922405930001552, original_bib) 324 | self.assertEqual(len(responses.calls), 1) 325 | self.assertEqual(returned_bib, json.loads(original_bib)) 326 | 327 | @responses.activate 328 | def test_alma_put_holding(self): 329 | self.buildResponses() 330 | with open('test/hold2.dat', 'r') as dat: 331 | original_holding = dat.read() 332 | returned_holding = self.api.put_holding(9922405930001552, 333 | 22115858660001551, 334 | original_holding) 335 | self.assertEqual(len(responses.calls), 1) 336 | self.assertEqual(returned_holding, json.loads(original_holding)) 337 | 338 | @responses.activate 339 | def test_alma_put_item(self): 340 | self.buildResponses() 341 | with open('test/item2.dat', 'r') as dat: 342 | original_item = dat.read() 343 | returned_item = self.api.put_item(99110223950001020, 344 | 22344156400001021, 345 | 23344156380001021, 346 | original_item) 347 | self.assertEqual(len(responses.calls), 1) 348 | self.assertEqual(returned_item, json.loads(original_item)) 349 | 350 | @responses.activate 351 | def test_alma_put_bib_request(self): 352 | self.buildResponses() 353 | with open('test/request.dat', 'r') as dat: 354 | original_bib_request = dat.read() 355 | returned_bib_request = self.api.put_bib_request(9922405930001552, 356 | 83013520000121, 357 | original_bib_request) 358 | self.assertEqual(len(responses.calls), 1) 359 | self.assertEqual(returned_bib_request, json.loads(original_bib_request)) 360 | 361 | @responses.activate 362 | def test_alma_put_item_request(self): 363 | self.buildResponses() 364 | with open('test/request.dat', 'r') as dat: 365 | original_item_request = dat.read() 366 | returned_item_request = self.api.put_item_request(9922405930001552, 367 | 22115858660001551, 368 | 23115858650001551, 369 | 83013520000121, 370 | original_item_request) 371 | self.assertEqual(len(responses.calls), 1) 372 | self.assertEqual(returned_item_request, json.loads(original_item_request)) 373 | 374 | 375 | class TestAlmaPOSTRequests(unittest.TestCase): 376 | maxDiff = None 377 | 378 | def setUp(self): 379 | self.api = alma.Alma(apikey='unreal', region='EU') 380 | 381 | def buildResponses(self): 382 | 383 | def echo_body(request): 384 | return (200, {}, request.body) 385 | 386 | # bib_request mock responses 387 | bib_requesturl = self.api.baseurl + r'bibs/\d+/requests$' 388 | bib_request_re = re.compile(bib_requesturl) 389 | responses.add_callback( 390 | responses.POST, bib_request_re, 391 | callback=echo_body, 392 | content_type='application/json', 393 | ) 394 | 395 | with open('test/request.dat', 'r') as r: 396 | responses.add(responses.POST, bib_request_re, 397 | status=200, 398 | content_type='application/json', 399 | body=r.read()) 400 | 401 | #item_request mock responses 402 | item_requesturl = self.api.baseurl + r'bibs/\d+/holdings/\d+/items/\d+/requests$' 403 | item_request_re = re.compile(item_requesturl) 404 | responses.add_callback( 405 | responses.POST, item_request_re, 406 | callback=echo_body, 407 | content_type='application/json', 408 | ) 409 | 410 | with open('test/request.dat', 'r') as r: 411 | responses.add(responses.POST, item_request_re, 412 | status=200, 413 | content_type='application/json', 414 | body=r.read()) 415 | 416 | #loan mock responses 417 | loanurl = self.api.baseurl + r'bibs/\d+/holdings/\d+/items/\d+/loans' 418 | loan_re = re.compile(loanurl) 419 | responses.add_callback( 420 | responses.POST, loan_re, 421 | callback=echo_body, 422 | content_type='application/json', 423 | ) 424 | 425 | with open('test/item_loan.dat', 'r') as r: 426 | responses.add(responses.POST, loan_re, 427 | status=200, 428 | content_type='application/json', 429 | body=r.read()) 430 | 431 | @responses.activate 432 | def test_alma_post_bib_request(self): 433 | self.buildResponses() 434 | with open ('test/request2.dat', 'r') as dat: 435 | original_bib_request = dat.read() 436 | returned_bib_request = self.api.post_bib_request(9922405930001552, 437 | original_bib_request) 438 | self.assertEqual(len(responses.calls), 1) 439 | self.assertEqual(returned_bib_request, json.loads(original_bib_request)) 440 | 441 | with open('test/request.dat', 'r') as dat: 442 | bib_request_return = dat.read() 443 | bib_request_response = self.api.post_bib_request(9922405930001552, 444 | bib_request_return) 445 | self.assertEqual(bib_request_response, json.loads(bib_request_return)) 446 | 447 | @responses.activate 448 | def test_alma_post_item_request(self): 449 | self.buildResponses() 450 | with open ('test/request2.dat', 'r') as dat: 451 | original_item_request = dat.read() 452 | returned_item_request = self.api.post_item_request(9922405930001552, 453 | 22115858660001551, 454 | 23115858650001551, 455 | original_item_request) 456 | self.assertEqual(len(responses.calls), 1) 457 | self.assertEqual(returned_item_request, json.loads(original_item_request)) 458 | 459 | with open('test/request.dat', 'r') as dat: 460 | item_request_return = dat.read() 461 | item_request_response = self.api.post_item_request(9922405930001552, 462 | 22115858660001551, 463 | 23115858650001551, 464 | item_request_return) 465 | self.assertEqual(item_request_response, json.loads(item_request_return)) 466 | 467 | @responses.activate 468 | def test_alma_post_loan(self): 469 | self.buildResponses() 470 | with open ('test/loan.dat', 'r') as dat: 471 | original_loan = dat.read() 472 | returned_loan = self.api.post_loan(9922405930001552, 473 | 22115858660001551, 474 | 23115858650001551, 475 | original_loan) 476 | self.assertEqual(len(responses.calls), 1) 477 | self.assertEqual(returned_loan, json.loads(original_loan)) 478 | 479 | with open('test/item_loan.dat', 'r') as dat: 480 | loan_return = dat.read() 481 | loan_response = self.api.post_loan(9922405930001552, 482 | 22115858660001551, 483 | 23115858650001551, 484 | loan_return) 485 | self.assertEqual(loan_response, json.loads(loan_return)) 486 | 487 | 488 | class TestAlmaDELETERequests(unittest.TestCase): 489 | maxDiff = None 490 | 491 | def setUp(self): 492 | self.api = alma.Alma(apikey='unreal', region='EU') 493 | 494 | def buildResponses(self): 495 | 496 | # bib_request mock response 497 | bib_requesturl = self.api.baseurl + r'bibs/\d+/requests/\d+$' 498 | bib_request_re = re.compile(bib_requesturl) 499 | responses.add(responses.DELETE, bib_request_re, body='', status=204,) 500 | 501 | #item_request mock response 502 | item_requesturl = self.api.baseurl + r'bibs/\d+/holdings/\d+/items/\d+/requests/\d+$' 503 | item_request_re = re.compile(item_requesturl) 504 | responses.add(responses.DELETE, item_request_re, body='', status=204,) 505 | 506 | @responses.activate 507 | def test_alma_delete_bib_request(self): 508 | self.buildResponses() 509 | expected = '' 510 | bib_request_response = self.api.del_bib_request(9922405930001552, 511 | 83013520000121,) 512 | self.assertEqual(expected, bib_request_response) 513 | 514 | @responses.activate 515 | def test_alma_delete_item_request(self): 516 | self.buildResponses() 517 | expected = '' 518 | item_request_response = self.api.del_item_request(9922405930001552, 519 | 22115858660001551, 520 | 23115858650001551, 521 | 83013520000121,) 522 | self.assertEqual(expected, item_request_response) 523 | 524 | if __name__ == '__main__': 525 | unittest.main() 526 | -------------------------------------------------------------------------------- /pyalma/alma.py: -------------------------------------------------------------------------------- 1 | import os 2 | # external imports 3 | import requests 4 | 5 | # imports for coroutines 6 | import asyncio 7 | import aiohttp 8 | from aiohttp import ClientSession, web, errors 9 | import time 10 | from ratelimiter import RateLimiter 11 | 12 | 13 | __version__ = '0.1.0' 14 | __api_version__ = 'v1' 15 | __apikey__ = os.getenv('ALMA_API_KEY') 16 | __region__ = os.getenv('ALMA_API_REGION') 17 | __circ_desk__ = os.getenv('ALMA_API_CIRC_DESK') 18 | __library__ = os.getenv('ALMA_API_LIBRARY') 19 | 20 | ENDPOINTS = { 21 | 'US': 'https://api-na.hosted.exlibrisgroup.com', 22 | 'EU': 'https://api-eu.hosted.exlibrisgroup.com', 23 | 'APAC': 'https://api-ap.hosted.exlibrisgroup.com' 24 | } 25 | 26 | FORMATS = { 27 | 'json': 'application/json', 28 | 'xml': 'application/xml' 29 | } 30 | 31 | RESOURCES = { 32 | 'bib': 'bibs/{mms_id}', 33 | 'holdings': 'bibs/{mms_id}/holdings', 34 | 'holding': 'bibs/{mms_id}/holdings/{holding_id}', 35 | 'items': 'bibs/{mms_id}/holdings/{holding_id}/items', 36 | 'item': 'bibs/{mms_id}/holdings/{holding_id}/items/{item_pid}', 37 | 'bib_requests': 'bibs/{mms_id}/requests', 38 | 'item_requests': 39 | 'bibs/{mms_id}/holdings/{holding_id}/items/{item_pid}/requests', 40 | 'bib_requests': 'bibs/{mms_id}/requests', 41 | 'bib_request': 'bibs/{mms_id}/requests/{request_id}', 42 | 'item_requests': 'bibs/{mms_id}/holdings/{holding_id}/items/{item_pid}/requests', 43 | 'item_request': 'bibs/{mms_id}/holdings/{holding_id}/items/{item_pid}/requests/{request_id}', 44 | 'bib_booking_availability': 'bibs/{mms_id}/booking-availability', 45 | 'item_booking_availability': 46 | 'bibs/{mms_id}/holdings/{holding_id}/items/' + 47 | '{item_pid}/booking-availability', 48 | 'loan': 'bibs/{mms_id}/holdings/{holding_id}/items/{item_pid}/loans', 49 | 'requested_resources': 'task-lists/requested-resources', 50 | 'users': 'users', 51 | 'user': 'users/{user_id}' 52 | } 53 | 54 | MAX_CALLS_PER_SEC = 25 55 | SEMAPHORE_LIM = 500 56 | 57 | 58 | class Alma(object): 59 | 60 | def __init__(self, apikey=__apikey__, region=__region__): 61 | if apikey is None: 62 | raise Exception("Please supply an API key") 63 | if region not in ENDPOINTS: 64 | msg = 'Invalid Region. Must be one of {}'.format(list(ENDPOINTS)) 65 | raise Exception(msg) 66 | self.apikey = apikey 67 | self.endpoint = ENDPOINTS[region] 68 | self.max_calls = MAX_CALLS_PER_SEC 69 | self.semaphore_limit = SEMAPHORE_LIM 70 | 71 | @property 72 | def baseurl(self): 73 | return '{}/almaws/{}/'.format(self.endpoint, __api_version__) 74 | 75 | def fullurl(self, resource, ids={}): 76 | return self.baseurl + RESOURCES[resource].format(**ids) 77 | 78 | def headers(self, accept='json', content_type=None): 79 | headers = { 80 | "User-Agent": "pyalma/{}".format(__version__), 81 | "Authorization": "apikey {}".format(self.apikey), 82 | "Accept": FORMATS[accept] 83 | } 84 | if content_type is not None: 85 | headers['Content-Type'] = FORMATS[content_type] 86 | return headers 87 | 88 | def request(self, httpmethod, resource, ids={}, params={}, data=None, 89 | accept='json', content_type=None): 90 | response = requests.request( 91 | method=httpmethod, 92 | headers=self.headers(accept=accept, content_type=content_type), 93 | url=self.fullurl(resource, ids), 94 | params=params, 95 | data=data) 96 | try: 97 | response.raise_for_status() 98 | return response 99 | except requests.exceptions.HTTPError: 100 | raise HTTPError(response) 101 | 102 | def extract_content(self, response): 103 | ctype = response.headers['Content-Type'] 104 | if 'json' in ctype: 105 | return response.json() 106 | else: 107 | return response.content.decode('utf-8') 108 | 109 | ''' 110 | Below are convenience methods that call request() and extract_content() and 111 | return the response data in json or xml 112 | ''' 113 | 114 | def get_bib(self, mms_id, accept='xml'): 115 | response = self.request('GET', 'bib', {'mms_id': mms_id}, 116 | accept=accept) 117 | return self.extract_content(response) 118 | 119 | def put_bib(self, mms_id, data, content_type='xml', accept='xml'): 120 | response = self.request('PUT', 'bib', {'mms_id': mms_id}, 121 | data=data, content_type=content_type, accept=accept) 122 | return self.extract_content(response) 123 | 124 | def get_holdings(self, mms_id, accept='json'): 125 | response = self.request('GET', 'holdings', {'mms_id': mms_id}, 126 | accept=accept) 127 | return self.extract_content(response) 128 | 129 | def get_holding(self, mms_id, holding_id, accept='json'): 130 | response = self.request('GET', 'holding', 131 | {'mms_id': mms_id, 'holding_id': holding_id}, 132 | accept=accept) 133 | return self.extract_content(response) 134 | 135 | def put_holding(self, mms_id, holding_id, data, content_type='json', 136 | accept='json'): 137 | response = self.request('PUT', 'holding', 138 | {'mms_id': mms_id, 'holding_id': holding_id}, 139 | data=data, content_type=content_type, accept=accept) 140 | return self.extract_content(response) 141 | 142 | def get_items(self, mms_id, holding_id, accept='json'): 143 | response = self.request('GET', 'items', 144 | {'mms_id': mms_id, 145 | 'holding_id': holding_id}, 146 | accept=accept) 147 | return self.extract_content(response) 148 | 149 | def get_item(self, mms_id, holding_id, item_pid, accept='json'): 150 | response = self.request('GET', 'item', 151 | {'mms_id': mms_id, 152 | 'holding_id': holding_id, 153 | 'item_pid': item_pid}, 154 | accept=accept) 155 | return self.extract_content(response) 156 | 157 | def put_item(self, mms_id, holding_id, item_pid, data, content_type='json', 158 | accept='json'): 159 | response = self.request('PUT', 'item', 160 | {'mms_id': mms_id, 161 | 'holding_id': holding_id, 162 | 'item_pid': item_pid}, 163 | data=data, content_type=content_type, accept=accept) 164 | return self.extract_content(response) 165 | 166 | def del_item(self, mms_id, holding_id, item_pid): 167 | pass 168 | 169 | def post_loan(self, mms_id, holding_id, item_pid, data, 170 | content_type='json', accept='json'): 171 | response = self.request('POST', 'loan', 172 | {'mms_id': mms_id, 173 | 'holding_id': holding_id, 174 | 'item_pid': item_pid}, 175 | data=data, content_type=content_type, accept=accept) 176 | return self.extract_content(response) 177 | 178 | def get_bib_requests(self, mms_id, accept='json'): 179 | response = self.request('GET', 'bib_requests', {'mms_id': mms_id}, 180 | accept=accept) 181 | return self.extract_content(response) 182 | 183 | def get_item_requests(self, mms_id, holding_id, item_pid, accept='json'): 184 | response = self.request('GET', 'item_requests', 185 | {'mms_id': mms_id, 186 | 'holding_id': holding_id, 187 | 'item_pid': item_pid}, 188 | accept=accept) 189 | return self.extract_content(response) 190 | 191 | def post_bib_request(self, mms_id, data, content_type='json', accept='json'): 192 | response = self.request('POST', 'bib_requests', 193 | {'mms_id': mms_id}, 194 | data=data, content_type=content_type, accept=accept) 195 | return self.extract_content(response) 196 | 197 | def post_item_request(self, mms_id, holding_id, item_pid, data, 198 | content_type='json', accept='json'): 199 | response = self.request('POST', 'item_requests', 200 | {'mms_id': mms_id, 201 | 'holding_id': holding_id, 202 | 'item_pid': item_pid}, 203 | data=data, content_type=content_type, accept=accept) 204 | return self.extract_content(response) 205 | 206 | def put_bib_request(self, mms_id, request_id, data, content_type='json', accept='json'): 207 | response = self.request('PUT', 'bib_request', 208 | {'mms_id': mms_id, 209 | 'request_id': request_id}, 210 | data=data, content_type=content_type, accept=accept) 211 | return self.extract_content(response) 212 | 213 | def put_item_request(self, mms_id, holding_id, item_pid, request_id, 214 | data, content_type='json', accept='json'): 215 | response = self.request('PUT', 'item_request', 216 | {'mms_id': mms_id, 217 | 'holding_id': holding_id, 218 | 'item_pid': item_pid, 219 | 'request_id': request_id}, 220 | data=data, content_type=content_type, accept=accept) 221 | return self.extract_content(response) 222 | 223 | def del_item_request(self, mms_id, holding_id, item_pid, request_id): 224 | response = self.request('DELETE', 'item_request', 225 | {'mms_id': mms_id, 226 | 'holding_id': holding_id, 227 | 'item_pid': item_pid, 228 | 'request_id': request_id},) 229 | return self.extract_content(response) 230 | 231 | def del_bib_request(self, mms_id, request_id): 232 | response = self.request('DELETE', 'bib_request', 233 | {'mms_id': mms_id, 234 | 'request_id': request_id},) 235 | return self.extract_content(response) 236 | 237 | def get_bib_booking_availability(self, mms_id, accept='json'): 238 | response = self.request('GET', 'bib_booking_availability', 239 | {'mms_id': mms_id}, accept=accept) 240 | return self.extract_content(response) 241 | 242 | def get_item_booking_availability( 243 | self, mms_id, holding_id, item_pid, accept='json'): 244 | response = self.request('GET', 'item_booking_availability', 245 | {'mms_id': mms_id, 246 | 'holding_id': holding_id, 247 | 'item_pid': item_pid}, 248 | accept=accept) 249 | return self.extract_content(response) 250 | 251 | def get_users(self, accept='json'): 252 | response = self.request('GET', 'users', accept=accept) 253 | return self.extract_content(response) 254 | 255 | def get_user(self, user_id, accept='json'): 256 | response = self.request('GET', 'user', {'user_id': user_id}, 257 | accept=accept) 258 | return self.extract_content(response) 259 | 260 | def put_user(self, user_id, data, content_type='json', 261 | accept='json'): 262 | response = self.request('PUT', 'user', 263 | {'user_id': user_id}, data=data, 264 | content_type=content_type, accept=accept) 265 | return self.extract_content(response) 266 | 267 | def get_digreps(self, mms_id, accept='json'): 268 | pass 269 | 270 | def get_digrep(self, mms_id, rep_id, accept='json'): 271 | pass 272 | 273 | def post_digrep(self, mms_id, data, content_type='json', accept='json'): 274 | pass 275 | 276 | def del_digrep(self, mms_id, rep_id): 277 | pass 278 | 279 | def get_requested_resources(self, library=__library__, 280 | circ_desk=__circ_desk__): 281 | params = {'library': library, 'circ_desk': circ_desk} 282 | response = self.request('GET', 'requested_resources', params=params) 283 | return self.extract_content(response) 284 | 285 | ''' 286 | Below are coroutine methods. 287 | Note that they currently all default to xml input and output, 288 | for ease of use in receiving data in a GET and sending it back as a PUT. 289 | ''' 290 | 291 | async def cor_request(self, httpmethod, resource, ids, session, params={}, 292 | data=None, accept='xml', content_type=None, max_attempts=5): 293 | """ 294 | Asynchronous request method 295 | Uses session.request, an aiohttp method 296 | 297 | To set rate limit: 298 | - max_attempts is the maximum number of times you want to repeat a 299 | call before giving up. 300 | - set maximum calls per second in global variable MAX_CALLS_PER_SEC 301 | """ 302 | attempts_left = max_attempts 303 | rate_limiter = RateLimiter(max_calls=self.max_calls, 304 | period=(6-attempts_left), 305 | callback=self.cor_limited) 306 | 307 | async with session.request(method=httpmethod, 308 | headers=self.headers(accept='xml', content_type='xml'), 309 | url=self.fullurl(resource, ids), 310 | params=params, 311 | data=data) as response: 312 | try: 313 | try: 314 | ctype = response.headers['Content-Type'] 315 | except: 316 | ctype = '' 317 | status = response.status 318 | method = response.method 319 | url = response.url_obj 320 | async with rate_limiter: 321 | response.raise_for_status() 322 | if 'json' in ctype: 323 | body = await response.json() 324 | else: 325 | body = await response.text(encoding='utf-8') 326 | return (ids, status, body) 327 | except aiohttp.errors.HttpProcessingError: 328 | body = await response.text() 329 | msg = "\nError in {} \n HTTP Status: {}\n Method: {}\n URL: {}\n Response: {}".format(ids, status, method, url, body) 330 | 331 | if status == 429: 332 | attempts_left -= 1 333 | if attempts_left < 0: 334 | print(msg) 335 | return (ids, status, msg) 336 | else: 337 | until = time.time() + (rate_limiter.period) 338 | asyncio.ensure_future(self.cor_limited(until)) 339 | await asyncio.sleep(rate_limiter.period) 340 | async with rate_limiter: 341 | result = await self.cor_request(httpmethod, resource, ids, session, params=params, data=data, accept=accept, content_type=content_type, max_attempts=attempts_left) 342 | return result 343 | else: 344 | return (ids, status, msg) 345 | 346 | async def cor_bound_request(self, sem, httpmethod, resource, ids, session, params={}, 347 | data=None, accept='xml', content_type='xml'): 348 | """ 349 | Bounds request, so that no more than x connections can be 350 | open at once (set inside self.cor_run) 351 | """ 352 | async with sem: 353 | request = await self.cor_request(httpmethod, resource, ids, session, data=data, accept=accept, content_type=content_type) 354 | return request 355 | 356 | async def cor_limited(self, until): 357 | """ 358 | Rate limits calls to the server (set in cor_run) 359 | """ 360 | duration = int(round(until - time.time())) 361 | print("Rate limited, sleeping for {:d} seconds".format(duration)) 362 | 363 | async def cor_run(self, httpmethod, resource, input_params, accept='xml', content_type=None): 364 | """ 365 | Takes a list of input_params, makes requests, returns responses 366 | """ 367 | tasks = [] 368 | 369 | # set the simultaneous connection limit here 370 | sem = asyncio.Semaphore(self.semaphore_limit) 371 | 372 | # set the rate limit here 373 | rate_limiter = RateLimiter(max_calls=self.max_calls, 374 | period=1, 375 | callback=self.cor_limited) 376 | 377 | async with ClientSession() as session: 378 | for input_param in input_params: 379 | 380 | task = asyncio.ensure_future(self.cor_bound_request(sem, 381 | httpmethod, 382 | resource, 383 | input_param['ids'], 384 | session, 385 | data=input_param['data'], 386 | accept=accept, 387 | content_type=content_type)) 388 | # create a delay of between calls 389 | # to help prevent API rate errors 390 | await asyncio.sleep(1/self.max_calls) 391 | tasks.append(task) 392 | async with rate_limiter: 393 | responses = await asyncio.gather(*tasks) 394 | return responses 395 | 396 | """ 397 | Each of the below asynchronous methods takes input_params as a variable, 398 | and returns a list of tuples. 399 | 400 | input_params is a list of dictionaries in the following form: 401 | [{ 402 | 'data': data, 403 | 'ids': { 404 | 'mms_id': mms_id, 405 | 'holding_id': holding_id, 406 | 'item_pid': item_pid, 407 | 'request_id': request_id 408 | } 409 | }, 410 | ... 411 | ] 412 | 413 | Returns a list of tuples in form 414 | [(ids, status, response), 415 | ... 416 | ] 417 | """ 418 | 419 | def cor_get_bib(self, input_params, accept='xml'): 420 | # input_params includes mms_id 421 | loop = asyncio.get_event_loop() 422 | try: 423 | responses = loop.run_until_complete(self.cor_run('GET', 424 | 'bib', 425 | input_params, 426 | accept=accept)) 427 | finally: 428 | loop.close() 429 | return responses 430 | 431 | def cor_put_bib(self, input_params, content_type='xml', accept='xml'): 432 | # input_params includes mms_id, data 433 | loop = asyncio.get_event_loop() 434 | try: 435 | responses = loop.run_until_complete(self.cor_run('PUT', 436 | 'bib', 437 | input_params, 438 | content_type=content_type, 439 | accept=accept)) 440 | finally: 441 | loop.close() 442 | return responses 443 | 444 | def cor_get_holdings(self, input_params, accept='xml'): 445 | # input_params includes mms_id 446 | loop = asyncio.get_event_loop() 447 | try: 448 | responses = loop.run_until_complete(self.cor_run('GET', 449 | 'holdings', 450 | input_params, 451 | accept=accept)) 452 | finally: 453 | loop.close() 454 | return responses 455 | 456 | def cor_get_holding(self, input_params, accept='xml'): 457 | # input_params includes mms_id, holding_id 458 | loop = asyncio.get_event_loop() 459 | try: 460 | responses = loop.run_until_complete(self.cor_run('GET', 461 | 'holding', 462 | input_params, 463 | accept=accept)) 464 | finally: 465 | loop.close() 466 | return responses 467 | 468 | def cor_put_holding(self, input_params, content_type='xml', 469 | accept='xml'): 470 | # input_params includes mms_id, holding_id, data 471 | loop = asyncio.get_event_loop() 472 | try: 473 | responses = loop.run_until_complete(self.cor_run('PUT', 474 | 'holding', 475 | input_params, 476 | content_type=content_type, 477 | accept=accept)) 478 | finally: 479 | loop.close() 480 | return responses 481 | 482 | def cor_get_items(self, input_params, accept='xml'): 483 | # input_params includes mms_id, holding_id 484 | loop = asyncio.get_event_loop() 485 | try: 486 | responses = loop.run_until_complete(self.cor_run('GET', 487 | 'items', 488 | input_params, 489 | accept=accept)) 490 | finally: 491 | loop.close() 492 | return responses 493 | 494 | def cor_get_item(self, input_params, accept='xml'): 495 | # input_params includes mms_id, holding_id, item_pid 496 | loop = asyncio.get_event_loop() 497 | try: 498 | responses = loop.run_until_complete(self.cor_run('GET', 499 | 'item', 500 | input_params, 501 | accept=accept)) 502 | finally: 503 | loop.close() 504 | return responses 505 | 506 | def cor_put_item(self, input_params, content_type='xml', 507 | accept='xml'): 508 | # input_params includes mms_id, holding_id, item_pid, data 509 | loop = asyncio.get_event_loop() 510 | try: 511 | responses = loop.run_until_complete(self.cor_run('PUT', 512 | 'item', 513 | input_params, 514 | content_type=content_type, 515 | accept=accept)) 516 | finally: 517 | loop.close() 518 | return responses 519 | 520 | def cor_get_bib_requests(self, input_params, accept='xml'): 521 | # input_params includes mms_id 522 | loop = asyncio.get_event_loop() 523 | try: 524 | responses = loop.run_until_complete(self.cor_run('GET', 525 | 'bib_requests', 526 | input_params, 527 | accept=accept)) 528 | finally: 529 | loop.close() 530 | return responses 531 | 532 | def cor_get_item_requests(self, input_params, accept='xml'): 533 | # input_params includes mms_id, holding_id, item_pid 534 | loop = asyncio.get_event_loop() 535 | try: 536 | responses = loop.run_until_complete(self.cor_run('GET', 537 | 'item_requests', 538 | input_params, 539 | accept=accept)) 540 | finally: 541 | loop.close() 542 | return responses 543 | 544 | def cor_del_item_request(self, input_params): 545 | # input_params includes mms_id, holding_id, item_pid, request_id 546 | loop = asyncio.get_event_loop() 547 | try: 548 | responses = loop.run_until_complete(self.cor_run('DELETE', 549 | 'item_request', 550 | input_params)) 551 | finally: 552 | loop.close() 553 | return responses 554 | 555 | def cor_del_bib_request(self, input_params): 556 | # input_params includes mms_id, request_id 557 | loop = asyncio.get_event_loop() 558 | try: 559 | responses = loop.run_until_complete(self.cor_run('DELETE', 560 | 'bib_request', 561 | input_params)) 562 | finally: 563 | loop.close() 564 | return responses 565 | 566 | ''' 567 | WARNING: below methods have not been fully implemented or 568 | been tested. To be complete, tehse methods will require the 569 | appropriate query strings parameters to be passed into session.request 570 | within self.cor_request, which has not yet been implemented. 571 | ''' 572 | def cor_del_item(self, input_params): 573 | pass 574 | 575 | def cor_post_loan(self, input_params, 576 | content_type='xml', accept='xml'): 577 | # input_params includes mms_id, holding_id, item_pid, data 578 | loop = asyncio.get_event_loop() 579 | try: 580 | responses = loop.run_until_complete(self.cor_run('POST', 581 | 'loan', 582 | input_params, 583 | content_type=content_type, 584 | accept=accept)) 585 | finally: 586 | loop.close() 587 | return responses 588 | 589 | def cor_post_bib_request(self, input_params, 590 | content_type='xml', accept='xml'): 591 | # input_params includes mms_id, data 592 | loop = asyncio.get_event_loop() 593 | try: 594 | responses = loop.run_until_complete(self.cor_run('POST', 595 | 'bib_requests', 596 | input_params, 597 | content_type=content_type, 598 | accept=accept)) 599 | finally: 600 | loop.close() 601 | return responses 602 | 603 | def cor_post_item_request(self, input_params, 604 | content_type='xml', accept='xml'): 605 | # input_params includes mms_id, holding_id, item_pid, data 606 | loop = asyncio.get_event_loop() 607 | try: 608 | responses = loop.run_until_complete(self.cor_run('POST', 609 | 'item_requests', 610 | input_params, 611 | content_type=content_type, 612 | accept=accept)) 613 | finally: 614 | loop.close() 615 | return responses 616 | 617 | def cor_put_bib_request(self, input_params, 618 | content_type='xml', accept='xml'): 619 | # input_params includes mms_id, request_id, data 620 | loop = asyncio.get_event_loop() 621 | try: 622 | responses = loop.run_until_complete(self.cor_run('PUT', 623 | 'bib_request', 624 | input_params, 625 | content_type=content_type, 626 | accept=accept)) 627 | finally: 628 | loop.close() 629 | return responses 630 | 631 | def cor_put_item_request(self, input_params, 632 | content_type='xml', accept='xml'): 633 | # input_params includes mms_id, holding_id, item_pid, request_id, data 634 | loop = asyncio.get_event_loop() 635 | try: 636 | responses = loop.run_until_complete(self.cor_run('PUT', 637 | 'item_request', 638 | input_params, 639 | content_type=content_type, 640 | accept=accept)) 641 | finally: 642 | loop.close() 643 | return responses 644 | 645 | def cor_get_bib_booking_availability(self, input_params, accept='xml'): 646 | # input_params includes mms_id 647 | loop = asyncio.get_event_loop() 648 | try: 649 | responses = loop.run_until_complete(self.cor_run('GET', 650 | 'bib_booking_availability', 651 | input_params, 652 | accept=accept)) 653 | finally: 654 | loop.close() 655 | return responses 656 | 657 | def cor_get_item_booking_availability( 658 | self, input_params, accept='xml'): 659 | # input_params includes mms_id, holding_id, item_pid 660 | loop = asyncio.get_event_loop() 661 | try: 662 | responses = loop.run_until_complete(self.cor_run('GET', 663 | 'item_booking_availability', 664 | input_params, 665 | accept=accept)) 666 | finally: 667 | loop.close() 668 | return responses 669 | 670 | def cor_get_digreps(self, input_params, accept='json'): 671 | pass 672 | 673 | def cor_get_digrep(self, input_params, accept='json'): 674 | pass 675 | 676 | def cor_post_digrep(self, input_params, content_type='json', accept='json'): 677 | pass 678 | 679 | def cor_del_digrep(self, input_params, rep_id): 680 | pass 681 | 682 | 683 | class HTTPError(Exception): 684 | 685 | def __init__(self, response): 686 | super().__init__(self.msg(response)) 687 | 688 | def msg(self, response): 689 | msg = "\n HTTP Status: {}\n Method: {}\n URL: {}\n Response: {}" 690 | return msg.format(response.status_code, response.request.method, 691 | response.url, response.text) 692 | -------------------------------------------------------------------------------- /test/mms_holdings_items_with_requests.csv: -------------------------------------------------------------------------------- 1 | ids,data 2 | "{'item_pid': '23137888170001551', 'mms_id': '9928519370001551', 'holding_id': '22137888180001551'}" 3 | "{'item_pid': '23137867060001551', 'mms_id': '9928503600001551', 'holding_id': '22137867220001551'}" 4 | "{'item_pid': '23137617400001551', 'mms_id': '9928448450001551', 'holding_id': '22137617410001551'}" 5 | "{'item_pid': '23137474520001551', 'mms_id': '9928407390001551', 'holding_id': '22137474560001551'}" 6 | "{'item_pid': '23136958180001551', 'mms_id': '9928241780001551', 'holding_id': '22136958190001551'}" 7 | "{'item_pid': '23136486090001551', 'mms_id': '9928114970001551', 'holding_id': '22136486100001551'}" 8 | "{'item_pid': '23136319210001551', 'mms_id': '9928066790001551', 'holding_id': '22136319220001551'}" 9 | "{'item_pid': '23136091410001551', 'mms_id': '9928007560001551', 'holding_id': '22136091430001551'}" 10 | "{'item_pid': '23135692920001551', 'mms_id': '9927887590001551', 'holding_id': '22135692990001551'}" 11 | "{'item_pid': '23135574960001551', 'mms_id': '9927842310001551', 'holding_id': '22135574970001551'}" 12 | "{'item_pid': '23134060280001551', 'mms_id': '9927432230001551', 'holding_id': '22157819480001551'}" 13 | "{'item_pid': '23151392950001551', 'mms_id': '9927400050001551', 'holding_id': '22151392960001551'}" 14 | "{'item_pid': '23133912040001551', 'mms_id': '9927399090001551', 'holding_id': '22155677470001551'}" 15 | "{'item_pid': '23151555810001551', 'mms_id': '9927374370001551', 'holding_id': '22151555820001551'}" 16 | "{'item_pid': '23133805180001551', 'mms_id': '9927356110001551', 'holding_id': '22133805190001551'}" 17 | "{'item_pid': '23133745410001551', 'mms_id': '9927334950001551', 'holding_id': '22133745420001551'}" 18 | "{'item_pid': '23133674880001551', 'mms_id': '9927316920001551', 'holding_id': '22133674890001551'}" 19 | "{'item_pid': '23133561330001551', 'mms_id': '9927290210001551', 'holding_id': '22133561340001551'}" 20 | "{'item_pid': '23132178580001551', 'mms_id': '9926910530001551', 'holding_id': '22132178610001551'}" 21 | "{'item_pid': '23132167630001551', 'mms_id': '9926892350001551', 'holding_id': '22132167660001551'}" 22 | "{'item_pid': '23131844720001551', 'mms_id': '9926819240001551', 'holding_id': '22157575790001551'}" 23 | "{'item_pid': '23131538790001551', 'mms_id': '9926726440001551', 'holding_id': '22131538800001551'}" 24 | "{'item_pid': '23131418080001551', 'mms_id': '9926700310001551', 'holding_id': '22131418090001551'}" 25 | "{'item_pid': '23131149600001551', 'mms_id': '9926618750001551', 'holding_id': '22131149620001551'}" 26 | "{'item_pid': '23130730590001551', 'mms_id': '9926494000001551', 'holding_id': '22157479830001551'}" 27 | "{'item_pid': '23129957550001551', 'mms_id': '9926273430001551', 'holding_id': '22129957560001551'}" 28 | "{'item_pid': '23129805870001551', 'mms_id': '9926235880001551', 'holding_id': '22129805880001551'}" 29 | "{'item_pid': '23129756310001551', 'mms_id': '9926230760001551', 'holding_id': '22129756330001551'}" 30 | "{'item_pid': '23129564010001551', 'mms_id': '9926167460001551', 'holding_id': '22157360340001551'}" 31 | "{'item_pid': '23129391590001551', 'mms_id': '9926116910001551', 'holding_id': '22129391600001551'}" 32 | "{'item_pid': '23129093920001551', 'mms_id': '9926028600001551', 'holding_id': '22129093930001551'}" 33 | "{'item_pid': '23128485250001551', 'mms_id': '9925845740001551', 'holding_id': '22128485260001551'}" 34 | "{'item_pid': '23128354500001551', 'mms_id': '9925803820001551', 'holding_id': '22128354510001551'}" 35 | "{'item_pid': '23128062760001551', 'mms_id': '9925725310001551', 'holding_id': '22157226090001551'}" 36 | "{'item_pid': '23127554250001551', 'mms_id': '9925563340001551', 'holding_id': '22157177020001551'}" 37 | "{'item_pid': '23127144550001551', 'mms_id': '9925443910001551', 'holding_id': '22159898660001551'}" 38 | "{'item_pid': '23126522880001551', 'mms_id': '9925275630001551', 'holding_id': '22126522890001551'}" 39 | "{'item_pid': '23126339650001551', 'mms_id': '9925214020001551', 'holding_id': '22126339660001551'}" 40 | "{'item_pid': '23126014700001551', 'mms_id': '9925122840001551', 'holding_id': '22126014710001551'}" 41 | "{'item_pid': '23125608330001551', 'mms_id': '9925016030001551', 'holding_id': '22125608340001551'}" 42 | "{'item_pid': '23125525390001551', 'mms_id': '9924998710001551', 'holding_id': '22125525400001551'}" 43 | "{'item_pid': '23125151050001551', 'mms_id': '9924886480001551', 'holding_id': '22125151060001551'}" 44 | "{'item_pid': '23125148070001551', 'mms_id': '9924871610001551', 'holding_id': '22156943040001551'}" 45 | "{'item_pid': '23123691020001551', 'mms_id': '9924491520001551', 'holding_id': '22123691030001551'}" 46 | "{'item_pid': '23123561630001551', 'mms_id': '9924469390001551', 'holding_id': '22123561640001551'}" 47 | "{'item_pid': '23122896620001551', 'mms_id': '9924265730001551', 'holding_id': '22122896630001551'}" 48 | "{'item_pid': '23122556550001551', 'mms_id': '9924178830001551', 'holding_id': '22122556560001551'}" 49 | "{'item_pid': '23122160890001551', 'mms_id': '9924079520001551', 'holding_id': '22122160900001551'}" 50 | "{'item_pid': '23122106430001551', 'mms_id': '9924060560001551', 'holding_id': '22122106440001551'}" 51 | "{'item_pid': '23122113940001551', 'mms_id': '9924056540001551', 'holding_id': '22163633520001551'}" 52 | "{'item_pid': '23121961610001551', 'mms_id': '9924020680001551', 'holding_id': '22156580430001551'}" 53 | "{'item_pid': '23121798850001551', 'mms_id': '9923952350001551', 'holding_id': '22156566150001551'}" 54 | "{'item_pid': '23120522220001551', 'mms_id': '9923700150001551', 'holding_id': '22120522230001551'}" 55 | "{'item_pid': '23120478200001551', 'mms_id': '9923677370001551', 'holding_id': '22156497530001551'}" 56 | "{'item_pid': '23119085500001551', 'mms_id': '9923290030001551', 'holding_id': '22119085510001551'}" 57 | "{'item_pid': '23118932650001551', 'mms_id': '9923249760001551', 'holding_id': '22118932660001551'}" 58 | "{'item_pid': '23118543960001551', 'mms_id': '9923127190001551', 'holding_id': '22118543970001551'}" 59 | "{'item_pid': '23118154530001551', 'mms_id': '9923019460001551', 'holding_id': '22118154540001551'}" 60 | "{'item_pid': '23117447230001551', 'mms_id': '9922806100001551', 'holding_id': '22117447240001551'}" 61 | "{'item_pid': '23116862210001551', 'mms_id': '9922642840001551', 'holding_id': '22116862220001551'}" 62 | "{'item_pid': '23116820400001551', 'mms_id': '9922634750001551', 'holding_id': '22116820420001551'}" 63 | "{'item_pid': '23115776050001551', 'mms_id': '9922389020001551', 'holding_id': '22156065690001551'}" 64 | "{'item_pid': '23115792870001551', 'mms_id': '9922382490001551', 'holding_id': '22115792900001551'}" 65 | "{'item_pid': '23115282890001551', 'mms_id': '9922249960001551', 'holding_id': '22115282900001551'}" 66 | "{'item_pid': '23114985050001551', 'mms_id': '9922169960001551', 'holding_id': '22114985070001551'}" 67 | "{'item_pid': '23114643180001551', 'mms_id': '9922100080001551', 'holding_id': '22114643190001551'}" 68 | "{'item_pid': '23113300420001551', 'mms_id': '9921702180001551', 'holding_id': '22113300450001551'}" 69 | "{'item_pid': '23113116920001551', 'mms_id': '9921658460001551', 'holding_id': '22113116930001551'}" 70 | "{'item_pid': '23113035550001551', 'mms_id': '9921621340001551', 'holding_id': '22155770740001551'}" 71 | "{'item_pid': '23113034570001551', 'mms_id': '9921621090001551', 'holding_id': '22155771250001551'}" 72 | "{'item_pid': '23112750340001551', 'mms_id': '9921542170001551', 'holding_id': '22112750350001551'}" 73 | "{'item_pid': '23163758310001551', 'mms_id': '9933570608001551', 'holding_id': '22163758320001551'}" 74 | "{'item_pid': '23163567800001551', 'mms_id': '9933569403901551', 'holding_id': '22163567810001551'}" 75 | "{'item_pid': '23162619320001551', 'mms_id': '9933563610001551', 'holding_id': '22162619340001551'}" 76 | "{'item_pid': '23162523720001551', 'mms_id': '9933563306001551', 'holding_id': '22162523730001551'}" 77 | "{'item_pid': '23162779650001551', 'mms_id': '9933561061201551', 'holding_id': '22162779640001551'}" 78 | "{'item_pid': '23162246270001551', 'mms_id': '9933559447601551', 'holding_id': '22162246280001551'}" 79 | "{'item_pid': '23161757590001551', 'mms_id': '9933555607001551', 'holding_id': '22161757600001551'}" 80 | "{'item_pid': '23161359480001551', 'mms_id': '9933552311201551', 'holding_id': '22161359490001551'}" 81 | "{'item_pid': '23161223350001551', 'mms_id': '9933551166401551', 'holding_id': '22161223360001551'}" 82 | "{'item_pid': '23161289440001551', 'mms_id': '9933551009101551', 'holding_id': '22161289250001551'}" 83 | "{'item_pid': '23160895920001551', 'mms_id': '9933548302701551', 'holding_id': '22160895930001551'}" 84 | "{'item_pid': '23160765960001551', 'mms_id': '9933547094501551', 'holding_id': '22161697930001551'}" 85 | "{'item_pid': '23160710670001551', 'mms_id': '9933547006601551', 'holding_id': '22160710680001551'}" 86 | "{'item_pid': '23160291860001551', 'mms_id': '9933542891801551', 'holding_id': '22160291870001551'}" 87 | "{'item_pid': '23159949710001551', 'mms_id': '9933539911401551', 'holding_id': '22159949720001551'}" 88 | "{'item_pid': '23159889280001551', 'mms_id': '9933539610601551', 'holding_id': '22159889300001551'}" 89 | "{'item_pid': '23154301240001551', 'mms_id': '9933289140001551', 'holding_id': '22154301250001551'}" 90 | "{'item_pid': '23152712100001551', 'mms_id': '9932669120001551', 'holding_id': '22152712110001551'}" 91 | "{'item_pid': '23152069160001551', 'mms_id': '9931439020001551', 'holding_id': '22152069170001551'}" 92 | "{'item_pid': '23144289730001551', 'mms_id': '9930253150001551', 'holding_id': '22158682840001551'}" 93 | "{'item_pid': '23144200760001551', 'mms_id': '9930233450001551', 'holding_id': '22144200800001551'}" 94 | "{'item_pid': '23142699780001551', 'mms_id': '9929795880001551', 'holding_id': '22142699790001551'}" 95 | "{'item_pid': '23141807490001551', 'mms_id': '9929531830001551', 'holding_id': '22141807500001551'}" 96 | "{'item_pid': '23141536350001551', 'mms_id': '9929453090001551', 'holding_id': '22141536360001551'}" 97 | "{'item_pid': '23141280930001551', 'mms_id': '9929384340001551', 'holding_id': '22141280940001551'}" 98 | "{'item_pid': '23140758790001551', 'mms_id': '9929269220001551', 'holding_id': '22158371000001551'}" 99 | "{'item_pid': '23140571080001551', 'mms_id': '9929212140001551', 'holding_id': '22140571090001551'}" 100 | "{'item_pid': '23140304560001551', 'mms_id': '9929150500001551', 'holding_id': '22158332580001551'}" 101 | "{'item_pid': '23140311770001551', 'mms_id': '9929146490001551', 'holding_id': '22140311780001551'}" 102 | "{'item_pid': '23140326950001551', 'mms_id': '9929144970001551', 'holding_id': '22140326960001551'}" 103 | "{'item_pid': '23140255460001551', 'mms_id': '9929126010001551', 'holding_id': '22140255470001551'}" 104 | "{'item_pid': '23140195370001551', 'mms_id': '9929104290001551', 'holding_id': '22163649950001551'}" 105 | "{'item_pid': '23138801370001551', 'mms_id': '9928693370001551', 'holding_id': '22138801420001551'}" 106 | "{'item_pid': '23138814460001551', 'mms_id': '9928691410001551', 'holding_id': '22138814470001551'}" 107 | "{'item_pid': '23138625930001551', 'mms_id': '9928642410001551', 'holding_id': '22158162630001551'}" 108 | "{'item_pid': '23137640520001551', 'mms_id': '9928458200001551', 'holding_id': '22158092020001551'}" 109 | "{'item_pid': '23134658580001551', 'mms_id': '9927604800001551', 'holding_id': '22157872900001551'}" 110 | "{'item_pid': '23133956010001551', 'mms_id': '9927406220001551', 'holding_id': '22157808320001551'}" 111 | "{'item_pid': '23129863810001551', 'mms_id': '9926257390001551', 'holding_id': '22158853000001551'}" 112 | "{'item_pid': '23128220070001551', 'mms_id': '9925778920001551', 'holding_id': '22157248990001551'}" 113 | "{'item_pid': '23127413250001551', 'mms_id': '9925524500001551', 'holding_id': '22157156700001551'}" 114 | "{'item_pid': '23159569640001551', 'mms_id': '9924228370001551', 'holding_id': '22122733650001551'}" 115 | "{'item_pid': '23160683790001551', 'mms_id': '9924228370001551', 'holding_id': '22122733650001551'}" 116 | "{'item_pid': '23120434030001551', 'mms_id': '9923668600001551', 'holding_id': '22156450850001551'}" 117 | "{'item_pid': '23118549420001551', 'mms_id': '9923128860001551', 'holding_id': '22156297730001551'}" 118 | "{'item_pid': '23118511340001551', 'mms_id': '9923115210001551', 'holding_id': '22156287830001551'}" 119 | "{'item_pid': '23118464730001551', 'mms_id': '9923109780001551', 'holding_id': '22118464740001551'}" 120 | "{'item_pid': '23117702170001551', 'mms_id': '9922872830001551', 'holding_id': '22156227200001551'}" 121 | "{'item_pid': '23117473210001551', 'mms_id': '9922816470001551', 'holding_id': '22156207780001551'}" 122 | "{'item_pid': '23117438810001551', 'mms_id': '9922809380001551', 'holding_id': '22156199350001551'}" 123 | "{'item_pid': '23117325890001551', 'mms_id': '9922780100001551', 'holding_id': '22117325900001551'}" 124 | "{'item_pid': '23117306010001551', 'mms_id': '9922765780001551', 'holding_id': '22117306020001551'}" 125 | "{'item_pid': '23117161990001551', 'mms_id': '9922725450001551', 'holding_id': '22156161380001551'}" 126 | "{'item_pid': '23116141300001551', 'mms_id': '9922488180001551', 'holding_id': '22116141340001551'}" 127 | "{'item_pid': '23116141260001551', 'mms_id': '9922488180001551', 'holding_id': '22116141290001551'}" 128 | "{'item_pid': '23116034220001551', 'mms_id': '9922457670001551', 'holding_id': '22116034230001551'}" 129 | "{'item_pid': '23115926310001551', 'mms_id': '9922423730001551', 'holding_id': '22156088050001551'}" 130 | "{'item_pid': '23144986950001551', 'mms_id': '9930467740001551', 'holding_id': '22158750920001551'}" 131 | "{'item_pid': '23144807200001551', 'mms_id': '9930401080001551', 'holding_id': '22158724210001551'}" 132 | "{'item_pid': '23142148720001551', 'mms_id': '9929634850001551', 'holding_id': '22158497010001551'}" 133 | "{'item_pid': '23140909170001551', 'mms_id': '9929296360001551', 'holding_id': '22159048350001551'}" 134 | "{'item_pid': '23140135880001551', 'mms_id': '9929083490001551', 'holding_id': '22158328820001551'}" 135 | "{'item_pid': '23151886760001551', 'mms_id': '9922920440001551', 'holding_id': '22151886790001551'}" 136 | "{'item_pid': '23155429500001551', 'mms_id': '9922920440001551', 'holding_id': '22151886790001551'}" 137 | "{'item_pid': '23117826680001551', 'mms_id': '9922920440001551', 'holding_id': '22117826700001551'}" 138 | "{'item_pid': '23161883180001551', 'mms_id': '9933556899201551', 'holding_id': '22161883190001551'}" 139 | "{'item_pid': '23162718770001551', 'mms_id': '9933556899201551', 'holding_id': '22161883190001551'}" 140 | "{'item_pid': '23143505570001551', 'mms_id': '9930039030001551', 'holding_id': '22143505590001551'}" 141 | "{'item_pid': '23143420650001551', 'mms_id': '9930001190001551', 'holding_id': '22143420660001551'}" 142 | "{'item_pid': '23139822650001551', 'mms_id': '9928991230001551', 'holding_id': '22139822660001551'}" 143 | "{'item_pid': '23161828960001551', 'mms_id': '9928991230001551', 'holding_id': '22139822660001551'}" 144 | "{'item_pid': '23137872690001551', 'mms_id': '9928520150001551', 'holding_id': '22137872730001551'}" 145 | "{'item_pid': '23137872720001551', 'mms_id': '9928520150001551', 'holding_id': '22137872730001551'}" 146 | "{'item_pid': '23137872610001551', 'mms_id': '9928520150001551', 'holding_id': '22137872680001551'}" 147 | "{'item_pid': '23137872640001551', 'mms_id': '9928520150001551', 'holding_id': '22137872680001551'}" 148 | "{'item_pid': '23137816450001551', 'mms_id': '9928494920001551', 'holding_id': '22158113330001551'}" 149 | "{'item_pid': '23137816470001551', 'mms_id': '9928494920001551', 'holding_id': '22158113700001551'}" 150 | "{'item_pid': '23135592820001551', 'mms_id': '9927856400001551', 'holding_id': '22135592830001551'}" 151 | "{'item_pid': '23135592800001551', 'mms_id': '9927856400001551', 'holding_id': '22135592810001551'}" 152 | "{'item_pid': '23133748040001551', 'mms_id': '9927335780001551', 'holding_id': '22133748050001551'}" 153 | "{'item_pid': '23133748060001551', 'mms_id': '9927335780001551', 'holding_id': '22133748070001551'}" 154 | "{'item_pid': '23132201730001551', 'mms_id': '9926901100001551', 'holding_id': '22132201760001551'}" 155 | "{'item_pid': '23132201700001551', 'mms_id': '9926901100001551', 'holding_id': '22132201710001551'}" 156 | "{'item_pid': '23129211930001551', 'mms_id': '9926052090001551', 'holding_id': '22129211940001551'}" 157 | "{'item_pid': '23129211950001551', 'mms_id': '9926052090001551', 'holding_id': '22129212020001551'}" 158 | "{'item_pid': '23128783700001551', 'mms_id': '9925939220001551', 'holding_id': '22128783710001551'}" 159 | "{'item_pid': '23128783720001551', 'mms_id': '9925939220001551', 'holding_id': '22128783730001551'}" 160 | "{'item_pid': '23126407600001551', 'mms_id': '9925233730001551', 'holding_id': '22126407610001551'}" 161 | "{'item_pid': '23126407620001551', 'mms_id': '9925233730001551', 'holding_id': '22126407630001551'}" 162 | "{'item_pid': '23126128620001551', 'mms_id': '9925152820001551', 'holding_id': '22126128630001551'}" 163 | "{'item_pid': '23126128640001551', 'mms_id': '9925152820001551', 'holding_id': '22126128650001551'}" 164 | "{'item_pid': '23123250570001551', 'mms_id': '9924361390001551', 'holding_id': '22123250580001551'}" 165 | "{'item_pid': '23123250590001551', 'mms_id': '9924361390001551', 'holding_id': '22123250670001551'}" 166 | "{'item_pid': '23122738100001551', 'mms_id': '9924229180001551', 'holding_id': '22122738130001551'}" 167 | "{'item_pid': '23122738140001551', 'mms_id': '9924229180001551', 'holding_id': '22122738170001551'}" 168 | "{'item_pid': '23119011050001551', 'mms_id': '9923267030001551', 'holding_id': '22119011060001551'}" 169 | "{'item_pid': '23119011030001551', 'mms_id': '9923267030001551', 'holding_id': '22119011040001551'}" 170 | "{'item_pid': '23117816770001551', 'mms_id': '9922903400001551', 'holding_id': '22117816780001551'}" 171 | "{'item_pid': '23117816750001551', 'mms_id': '9922903400001551', 'holding_id': '22163649450001551'}" 172 | "{'item_pid': '23116902730001551', 'mms_id': '9922651290001551', 'holding_id': '22116902740001551'}" 173 | "{'item_pid': '23116902760001551', 'mms_id': '9922651290001551', 'holding_id': '22116902780001551'}" 174 | "{'item_pid': '23134046630001551', 'mms_id': '9927440080001551', 'holding_id': '22134046640001551'}" 175 | "{'item_pid': '23134046690001551', 'mms_id': '9927440080001551', 'holding_id': '22134046700001551'}" 176 | "{'item_pid': '23121779040001551', 'mms_id': '9923957970001551', 'holding_id': '22121779080001551'}" 177 | "{'item_pid': '23121779100001551', 'mms_id': '9923957970001551', 'holding_id': '22121779110001551'}" 178 | "{'item_pid': '23144670210001551', 'mms_id': '9930375790001551', 'holding_id': '22144670220001551'}" 179 | "{'item_pid': '23144670230001551', 'mms_id': '9930375790001551', 'holding_id': '22144670240001551'}" 180 | "{'item_pid': '23143712800001551', 'mms_id': '9930094580001551', 'holding_id': '22143712810001551'}" 181 | "{'item_pid': '23143712770001551', 'mms_id': '9930094580001551', 'holding_id': '22143712780001551'}" 182 | "{'item_pid': '23138236720001551', 'mms_id': '9928600050001551', 'holding_id': '22138236750001551'}" 183 | "{'item_pid': '23138236760001551', 'mms_id': '9928600050001551', 'holding_id': '22138236770001551'}" 184 | "{'item_pid': '23138236780001551', 'mms_id': '9928600050001551', 'holding_id': '22138236790001551'}" 185 | "{'item_pid': '23131343430001551', 'mms_id': '9926680180001551', 'holding_id': '22131343440001551'}" 186 | "{'item_pid': '23131343450001551', 'mms_id': '9926680180001551', 'holding_id': '22131343460001551'}" 187 | "{'item_pid': '23131343470001551', 'mms_id': '9926680180001551', 'holding_id': '22131343480001551'}" 188 | "{'item_pid': '23126331770001551', 'mms_id': '9925211970001551', 'holding_id': '22126331780001551'}" 189 | "{'item_pid': '23126331730001551', 'mms_id': '9925211970001551', 'holding_id': '22157065930001551'}" 190 | "{'item_pid': '23126061060001551', 'mms_id': '9925147690001551', 'holding_id': '22157010100001551'}" 191 | "{'item_pid': '23126061090001551', 'mms_id': '9925147690001551', 'holding_id': '22126061120001551'}" 192 | "{'item_pid': '23125920190001551', 'mms_id': '9925106940001551', 'holding_id': '22125920200001551'}" 193 | "{'item_pid': '23125920170001551', 'mms_id': '9925106940001551', 'holding_id': '22157007730001551'}" 194 | "{'item_pid': '23122213640001551', 'mms_id': '9924084050001551', 'holding_id': '22156614870001551'}" 195 | "{'item_pid': '23122213660001551', 'mms_id': '9924084050001551', 'holding_id': '22156614970001551'}" 196 | "{'item_pid': '23120860180001551', 'mms_id': '9923782290001551', 'holding_id': '22156514970001551'}" 197 | "{'item_pid': '23120860160001551', 'mms_id': '9923782290001551', 'holding_id': '22156515430001551'}" 198 | "{'item_pid': '23120006910001551', 'mms_id': '9923531760001551', 'holding_id': '22156422170001551'}" 199 | "{'item_pid': '23120006950001551', 'mms_id': '9923531760001551', 'holding_id': '22156422200001551'}" 200 | "{'item_pid': '23120006930001551', 'mms_id': '9923531760001551', 'holding_id': '22156422290001551'}" 201 | "{'item_pid': '23118255460001551', 'mms_id': '9923049630001551', 'holding_id': '22118255470001551'}" 202 | "{'item_pid': '23118255420001551', 'mms_id': '9923049630001551', 'holding_id': '22118255430001551'}" 203 | "{'item_pid': '23118255440001551', 'mms_id': '9923049630001551', 'holding_id': '22118255450001551'}" 204 | "{'item_pid': '23139585800001551', 'mms_id': '9928924640001551', 'holding_id': '22139585810001551'}" 205 | "{'item_pid': '23139585820001551', 'mms_id': '9928924640001551', 'holding_id': '22158268830001551'}" 206 | "{'item_pid': '23139168610001551', 'mms_id': '9928810200001551', 'holding_id': '22139168640001551'}" 207 | "{'item_pid': '23139168580001551', 'mms_id': '9928810200001551', 'holding_id': '22158227780001551'}" 208 | "{'item_pid': '23116322440001551', 'mms_id': '9922530710001551', 'holding_id': '22116322480001551'}" 209 | "{'item_pid': '23116322450001551', 'mms_id': '9922530710001551', 'holding_id': '22116322480001551'}" 210 | "{'item_pid': '23116322460001551', 'mms_id': '9922530710001551', 'holding_id': '22116322480001551'}" 211 | "{'item_pid': '23116322470001551', 'mms_id': '9922530710001551', 'holding_id': '22116322480001551'}" 212 | "{'item_pid': '23116322490001551', 'mms_id': '9922530710001551', 'holding_id': '22116322500001551'}" 213 | "{'item_pid': '23116322510001551', 'mms_id': '9922530710001551', 'holding_id': '22116322520001551'}" 214 | "{'item_pid': '23116322530001551', 'mms_id': '9922530710001551', 'holding_id': '22116322540001551'}" 215 | "{'item_pid': '23116322420001551', 'mms_id': '9922530710001551', 'holding_id': '22116322430001551'}" 216 | "{'item_pid': '23113619600001551', 'mms_id': '9921798680001551', 'holding_id': '22113619610001551'}" 217 | "{'item_pid': '23113619620001551', 'mms_id': '9921798680001551', 'holding_id': '22113619630001551'}" 218 | "{'item_pid': '23113619560001551', 'mms_id': '9921798680001551', 'holding_id': '22113619570001551'}" 219 | "{'item_pid': '23113619580001551', 'mms_id': '9921798680001551', 'holding_id': '22113619590001551'}" 220 | "{'item_pid': '23142561560001551', 'mms_id': '9929752620001551', 'holding_id': '22142561570001551'}" 221 | "{'item_pid': '23142561580001551', 'mms_id': '9929752620001551', 'holding_id': '22142561590001551'}" 222 | "{'item_pid': '23142561540001551', 'mms_id': '9929752620001551', 'holding_id': '22142561550001551'}" 223 | "{'item_pid': '23141884920001551', 'mms_id': '9929567440001551', 'holding_id': '22141884930001551'}" 224 | "{'item_pid': '23141884880001551', 'mms_id': '9929567440001551', 'holding_id': '22141884890001551'}" 225 | "{'item_pid': '23141884900001551', 'mms_id': '9929567440001551', 'holding_id': '22141884910001551'}" 226 | "{'item_pid': '23121743420001551', 'mms_id': '9923945040001551', 'holding_id': '22121743440001551'}" 227 | "{'item_pid': '23121743430001551', 'mms_id': '9923945040001551', 'holding_id': '22121743440001551'}" 228 | "{'item_pid': '23121743450001551', 'mms_id': '9923945040001551', 'holding_id': '22121743460001551'}" 229 | "{'item_pid': '23121743480001551', 'mms_id': '9923945040001551', 'holding_id': '22121743490001551'}" 230 | "{'item_pid': '23163049460001551', 'mms_id': '9933556805101551', 'holding_id': '22163049470001551'}" 231 | "{'item_pid': '23163748830001551', 'mms_id': '9933556805101551', 'holding_id': '22163748840001551'}" 232 | "{'item_pid': '23161487930001551', 'mms_id': '9933556805101551', 'holding_id': '22161487940001551'}" 233 | "{'item_pid': '23161879080001551', 'mms_id': '9933556805101551', 'holding_id': '22161487940001551'}" 234 | "{'item_pid': '23135432580001551', 'mms_id': '9927820730001551', 'holding_id': '22135432600001551'}" 235 | "{'item_pid': '23135432480001551', 'mms_id': '9927820730001551', 'holding_id': '22135432510001551'}" 236 | "{'item_pid': '23135432520001551', 'mms_id': '9927820730001551', 'holding_id': '22135432530001551'}" 237 | "{'item_pid': '23135432540001551', 'mms_id': '9927820730001551', 'holding_id': '22135432550001551'}" 238 | "{'item_pid': '23135432560001551', 'mms_id': '9927820730001551', 'holding_id': '22135432570001551'}" 239 | "{'item_pid': '23132345050001551', 'mms_id': '9926949460001551', 'holding_id': '22132345220001551'}" 240 | "{'item_pid': '23132345060001551', 'mms_id': '9926949460001551', 'holding_id': '22132345220001551'}" 241 | "{'item_pid': '23132345090001551', 'mms_id': '9926949460001551', 'holding_id': '22132345220001551'}" 242 | "{'item_pid': '23132345100001551', 'mms_id': '9926949460001551', 'holding_id': '22132345220001551'}" 243 | "{'item_pid': '23132345110001551', 'mms_id': '9926949460001551', 'holding_id': '22132345220001551'}" 244 | "{'item_pid': '23132345120001551', 'mms_id': '9926949460001551', 'holding_id': '22132345220001551'}" 245 | "{'item_pid': '23132345130001551', 'mms_id': '9926949460001551', 'holding_id': '22132345220001551'}" 246 | "{'item_pid': '23132345160001551', 'mms_id': '9926949460001551', 'holding_id': '22132345220001551'}" 247 | "{'item_pid': '23132345170001551', 'mms_id': '9926949460001551', 'holding_id': '22132345220001551'}" 248 | "{'item_pid': '23140599780001551', 'mms_id': '9929228680001551', 'holding_id': '22140599800001551'}" 249 | "{'item_pid': '23140599850001551', 'mms_id': '9929228680001551', 'holding_id': '22158906510001551'}" 250 | "{'item_pid': '23140599810001551', 'mms_id': '9929228680001551', 'holding_id': '22158906360001551'}" 251 | "{'item_pid': '23127974320001551', 'mms_id': '9925694500001551', 'holding_id': '22127974340001551'}" 252 | "{'item_pid': '23127974330001551', 'mms_id': '9925694500001551', 'holding_id': '22127974340001551'}" 253 | "{'item_pid': '23127974410001551', 'mms_id': '9925694500001551', 'holding_id': '22127974450001551'}" 254 | "{'item_pid': '23127974440001551', 'mms_id': '9925694500001551', 'holding_id': '22127974450001551'}" 255 | "{'item_pid': '23127974350001551', 'mms_id': '9925694500001551', 'holding_id': '22127974400001551'}" 256 | "{'item_pid': '23127974370001551', 'mms_id': '9925694500001551', 'holding_id': '22127974400001551'}" 257 | "{'item_pid': '23124637980001551', 'mms_id': '9924744740001551', 'holding_id': '22124638020001551'}" 258 | "{'item_pid': '23124638030001551', 'mms_id': '9924744740001551', 'holding_id': '22124638040001551'}" 259 | "{'item_pid': '23124638050001551', 'mms_id': '9924744740001551', 'holding_id': '22124638060001551'}" 260 | "{'item_pid': '23124637960001551', 'mms_id': '9924744740001551', 'holding_id': '22124637970001551'}" 261 | "{'item_pid': '23124637920001551', 'mms_id': '9924744740001551', 'holding_id': '22124637930001551'}" 262 | "{'item_pid': '23124637940001551', 'mms_id': '9924744740001551', 'holding_id': '22124637950001551'}" 263 | "{'item_pid': '23116764900001551', 'mms_id': '9922614830001551', 'holding_id': '22116764920001551'}" 264 | "{'item_pid': '23116764910001551', 'mms_id': '9922614830001551', 'holding_id': '22116764920001551'}" 265 | "{'item_pid': '23116764840001551', 'mms_id': '9922614830001551', 'holding_id': '22116764860001551'}" 266 | "{'item_pid': '23116764850001551', 'mms_id': '9922614830001551', 'holding_id': '22116764860001551'}" 267 | "{'item_pid': '23116764930001551', 'mms_id': '9922614830001551', 'holding_id': '22116764950001551'}" 268 | "{'item_pid': '23116764940001551', 'mms_id': '9922614830001551', 'holding_id': '22116764950001551'}" 269 | "{'item_pid': '23116764870001551', 'mms_id': '9922614830001551', 'holding_id': '22116764890001551'}" 270 | "{'item_pid': '23116764880001551', 'mms_id': '9922614830001551', 'holding_id': '22116764890001551'}" 271 | "{'item_pid': '23130766860001551', 'mms_id': '9926507720001551', 'holding_id': '22130766870001551'}" 272 | "{'item_pid': '23130766880001551', 'mms_id': '9926507720001551', 'holding_id': '22130766970001551'}" 273 | "{'item_pid': '23130766890001551', 'mms_id': '9926507720001551', 'holding_id': '22130766970001551'}" 274 | "{'item_pid': '23130766900001551', 'mms_id': '9926507720001551', 'holding_id': '22130766970001551'}" 275 | "{'item_pid': '23130766910001551', 'mms_id': '9926507720001551', 'holding_id': '22130766970001551'}" 276 | "{'item_pid': '23130766920001551', 'mms_id': '9926507720001551', 'holding_id': '22130766970001551'}" 277 | "{'item_pid': '23130766930001551', 'mms_id': '9926507720001551', 'holding_id': '22130766970001551'}" 278 | "{'item_pid': '23130766940001551', 'mms_id': '9926507720001551', 'holding_id': '22130766970001551'}" 279 | "{'item_pid': '23130766950001551', 'mms_id': '9926507720001551', 'holding_id': '22130766970001551'}" 280 | "{'item_pid': '23130766960001551', 'mms_id': '9926507720001551', 'holding_id': '22130766970001551'}" 281 | "{'item_pid': '23122085390001551', 'mms_id': '9924046600001551', 'holding_id': '22122085480001551'}" 282 | "{'item_pid': '23122085400001551', 'mms_id': '9924046600001551', 'holding_id': '22122085480001551'}" 283 | "{'item_pid': '23122085410001551', 'mms_id': '9924046600001551', 'holding_id': '22122085480001551'}" 284 | "{'item_pid': '23122085420001551', 'mms_id': '9924046600001551', 'holding_id': '22122085480001551'}" 285 | "{'item_pid': '23122085430001551', 'mms_id': '9924046600001551', 'holding_id': '22122085480001551'}" 286 | "{'item_pid': '23122085440001551', 'mms_id': '9924046600001551', 'holding_id': '22122085480001551'}" 287 | "{'item_pid': '23122085450001551', 'mms_id': '9924046600001551', 'holding_id': '22122085480001551'}" 288 | "{'item_pid': '23122085460001551', 'mms_id': '9924046600001551', 'holding_id': '22122085480001551'}" 289 | "{'item_pid': '23154759810001551', 'mms_id': '9924046600001551', 'holding_id': '22122085480001551'}" 290 | "{'item_pid': '23160685100001551', 'mms_id': '9924046600001551', 'holding_id': '22122085480001551'}" 291 | "{'item_pid': '23122085370001551', 'mms_id': '9924046600001551', 'holding_id': '22122085380001551'}" 292 | "{'item_pid': '23142696170001551', 'mms_id': '9929794780001551', 'holding_id': '22142696300001551'}" 293 | "{'item_pid': '23142696180001551', 'mms_id': '9929794780001551', 'holding_id': '22142696300001551'}" 294 | "{'item_pid': '23142696190001551', 'mms_id': '9929794780001551', 'holding_id': '22142696300001551'}" 295 | "{'item_pid': '23142696200001551', 'mms_id': '9929794780001551', 'holding_id': '22142696300001551'}" 296 | "{'item_pid': '23142696210001551', 'mms_id': '9929794780001551', 'holding_id': '22142696300001551'}" 297 | "{'item_pid': '23142696220001551', 'mms_id': '9929794780001551', 'holding_id': '22142696300001551'}" 298 | "{'item_pid': '23142696230001551', 'mms_id': '9929794780001551', 'holding_id': '22142696300001551'}" 299 | "{'item_pid': '23142696240001551', 'mms_id': '9929794780001551', 'holding_id': '22142696300001551'}" 300 | "{'item_pid': '23142696250001551', 'mms_id': '9929794780001551', 'holding_id': '22142696300001551'}" 301 | "{'item_pid': '23142696260001551', 'mms_id': '9929794780001551', 'holding_id': '22142696300001551'}" 302 | "{'item_pid': '23132827080001551', 'mms_id': '9927069540001551', 'holding_id': '22132827350001551'}" 303 | "{'item_pid': '23132827090001551', 'mms_id': '9927069540001551', 'holding_id': '22132827350001551'}" 304 | "{'item_pid': '23132827100001551', 'mms_id': '9927069540001551', 'holding_id': '22132827350001551'}" 305 | "{'item_pid': '23132827110001551', 'mms_id': '9927069540001551', 'holding_id': '22132827350001551'}" 306 | "{'item_pid': '23132827120001551', 'mms_id': '9927069540001551', 'holding_id': '22132827350001551'}" 307 | "{'item_pid': '23132827130001551', 'mms_id': '9927069540001551', 'holding_id': '22132827350001551'}" 308 | "{'item_pid': '23132827140001551', 'mms_id': '9927069540001551', 'holding_id': '22132827350001551'}" 309 | "{'item_pid': '23132827150001551', 'mms_id': '9927069540001551', 'holding_id': '22132827350001551'}" 310 | "{'item_pid': '23132827160001551', 'mms_id': '9927069540001551', 'holding_id': '22132827350001551'}" 311 | "{'item_pid': '23132827170001551', 'mms_id': '9927069540001551', 'holding_id': '22132827350001551'}" 312 | "{'item_pid': '23116460070001551', 'mms_id': '9922551310001551', 'holding_id': '22116460190001551'}" 313 | "{'item_pid': '23116460080001551', 'mms_id': '9922551310001551', 'holding_id': '22116460190001551'}" 314 | "{'item_pid': '23116460090001551', 'mms_id': '9922551310001551', 'holding_id': '22116460190001551'}" 315 | "{'item_pid': '23116460100001551', 'mms_id': '9922551310001551', 'holding_id': '22116460190001551'}" 316 | "{'item_pid': '23116460110001551', 'mms_id': '9922551310001551', 'holding_id': '22116460190001551'}" 317 | "{'item_pid': '23116460120001551', 'mms_id': '9922551310001551', 'holding_id': '22116460190001551'}" 318 | "{'item_pid': '23116460130001551', 'mms_id': '9922551310001551', 'holding_id': '22116460190001551'}" 319 | "{'item_pid': '23116460150001551', 'mms_id': '9922551310001551', 'holding_id': '22116460190001551'}" 320 | "{'item_pid': '23116460010001551', 'mms_id': '9922551310001551', 'holding_id': '22116460040001551'}" 321 | "{'item_pid': '23116460020001551', 'mms_id': '9922551310001551', 'holding_id': '22116460040001551'}" 322 | "{'item_pid': '23116460030001551', 'mms_id': '9922551310001551', 'holding_id': '22116460040001551'}" 323 | "{'item_pid': '23116479750001551', 'mms_id': '9922551310001551', 'holding_id': '22116460040001551'}" 324 | "{'item_pid': '23116479760001551', 'mms_id': '9922551310001551', 'holding_id': '22116460040001551'}" 325 | "{'item_pid': '23116479770001551', 'mms_id': '9922551310001551', 'holding_id': '22116460040001551'}" 326 | "{'item_pid': '23116479780001551', 'mms_id': '9922551310001551', 'holding_id': '22116460040001551'}" 327 | "{'item_pid': '23116479790001551', 'mms_id': '9922551310001551', 'holding_id': '22116460040001551'}" 328 | "{'item_pid': '23116479800001551', 'mms_id': '9922551310001551', 'holding_id': '22116460040001551'}" 329 | "{'item_pid': '23116479810001551', 'mms_id': '9922551310001551', 'holding_id': '22116460040001551'}" 330 | "{'item_pid': '23116460050001551', 'mms_id': '9922551310001551', 'holding_id': '22116460060001551'}" 331 | "{'item_pid': '23124283770001551', 'mms_id': '9924656440001551', 'holding_id': '22124283900001551'}" 332 | "{'item_pid': '23124283780001551', 'mms_id': '9924656440001551', 'holding_id': '22124283900001551'}" 333 | "{'item_pid': '23124283790001551', 'mms_id': '9924656440001551', 'holding_id': '22124283900001551'}" 334 | "{'item_pid': '23124283800001551', 'mms_id': '9924656440001551', 'holding_id': '22124283900001551'}" 335 | "{'item_pid': '23124283810001551', 'mms_id': '9924656440001551', 'holding_id': '22124283900001551'}" 336 | "{'item_pid': '23124283820001551', 'mms_id': '9924656440001551', 'holding_id': '22124283900001551'}" 337 | "{'item_pid': '23124283910001551', 'mms_id': '9924656440001551', 'holding_id': '22124283970001551'}" 338 | "{'item_pid': '23124283920001551', 'mms_id': '9924656440001551', 'holding_id': '22124283970001551'}" 339 | "{'item_pid': '23124283930001551', 'mms_id': '9924656440001551', 'holding_id': '22124283970001551'}" 340 | "{'item_pid': '23124283940001551', 'mms_id': '9924656440001551', 'holding_id': '22124283970001551'}" 341 | "{'item_pid': '23124283950001551', 'mms_id': '9924656440001551', 'holding_id': '22124283970001551'}" 342 | "{'item_pid': '23124283960001551', 'mms_id': '9924656440001551', 'holding_id': '22124283970001551'}" 343 | "{'item_pid': '23124284050001551', 'mms_id': '9924656440001551', 'holding_id': '22124284110001551'}" 344 | "{'item_pid': '23124284060001551', 'mms_id': '9924656440001551', 'holding_id': '22124284110001551'}" 345 | "{'item_pid': '23124284070001551', 'mms_id': '9924656440001551', 'holding_id': '22124284110001551'}" 346 | "{'item_pid': '23124284080001551', 'mms_id': '9924656440001551', 'holding_id': '22124284110001551'}" 347 | "{'item_pid': '23124284090001551', 'mms_id': '9924656440001551', 'holding_id': '22124284110001551'}" 348 | "{'item_pid': '23124284100001551', 'mms_id': '9924656440001551', 'holding_id': '22124284110001551'}" 349 | "{'item_pid': '23124283980001551', 'mms_id': '9924656440001551', 'holding_id': '22124284040001551'}" 350 | "{'item_pid': '23124283990001551', 'mms_id': '9924656440001551', 'holding_id': '22124284040001551'}" 351 | "{'item_pid': '23124284000001551', 'mms_id': '9924656440001551', 'holding_id': '22124284040001551'}" 352 | "{'item_pid': '23124284010001551', 'mms_id': '9924656440001551', 'holding_id': '22124284040001551'}" 353 | "{'item_pid': '23124284020001551', 'mms_id': '9924656440001551', 'holding_id': '22124284040001551'}" 354 | "{'item_pid': '23124284030001551', 'mms_id': '9924656440001551', 'holding_id': '22124284040001551'}" 355 | "{'item_pid': '23119498170001551', 'mms_id': '9923395690001551', 'holding_id': '22119498230001551'}" 356 | "{'item_pid': '23119498180001551', 'mms_id': '9923395690001551', 'holding_id': '22119498230001551'}" 357 | "{'item_pid': '23119498190001551', 'mms_id': '9923395690001551', 'holding_id': '22119498230001551'}" 358 | "{'item_pid': '23119498200001551', 'mms_id': '9923395690001551', 'holding_id': '22119498230001551'}" 359 | "{'item_pid': '23119498210001551', 'mms_id': '9923395690001551', 'holding_id': '22119498230001551'}" 360 | "{'item_pid': '23119498220001551', 'mms_id': '9923395690001551', 'holding_id': '22119498230001551'}" 361 | "{'item_pid': '23119498780001551', 'mms_id': '9923395690001551', 'holding_id': '22119498810001551'}" 362 | "{'item_pid': '23119498790001551', 'mms_id': '9923395690001551', 'holding_id': '22119498810001551'}" 363 | "{'item_pid': '23119498800001551', 'mms_id': '9923395690001551', 'holding_id': '22119498810001551'}" 364 | "{'item_pid': '23119498240001551', 'mms_id': '9923395690001551', 'holding_id': '22119498250001551'}" 365 | "{'item_pid': '23119498280001551', 'mms_id': '9923395690001551', 'holding_id': '22119498750001551'}" 366 | "{'item_pid': '23119498290001551', 'mms_id': '9923395690001551', 'holding_id': '22119498750001551'}" 367 | "{'item_pid': '23119498300001551', 'mms_id': '9923395690001551', 'holding_id': '22119498750001551'}" 368 | "{'item_pid': '23119498310001551', 'mms_id': '9923395690001551', 'holding_id': '22119498750001551'}" 369 | "{'item_pid': '23119498320001551', 'mms_id': '9923395690001551', 'holding_id': '22119498750001551'}" 370 | "{'item_pid': '23119498330001551', 'mms_id': '9923395690001551', 'holding_id': '22119498750001551'}" 371 | "{'item_pid': '23119498370001551', 'mms_id': '9923395690001551', 'holding_id': '22119498750001551'}" 372 | "{'item_pid': '23119498380001551', 'mms_id': '9923395690001551', 'holding_id': '22119498750001551'}" 373 | "{'item_pid': '23119498390001551', 'mms_id': '9923395690001551', 'holding_id': '22119498750001551'}" 374 | "{'item_pid': '23119498400001551', 'mms_id': '9923395690001551', 'holding_id': '22119498750001551'}" 375 | "{'item_pid': '23119498260001551', 'mms_id': '9923395690001551', 'holding_id': '22119498270001551'}" 376 | "{'item_pid': '23119498760001551', 'mms_id': '9923395690001551', 'holding_id': '22119498770001551'}" 377 | "{'item_pid': '23120920010001551', 'mms_id': '9923803820001551', 'holding_id': '22158996320001551'}" 378 | "{'item_pid': '23120920020001551', 'mms_id': '9923803820001551', 'holding_id': '22158996320001551'}" 379 | "{'item_pid': '23120920030001551', 'mms_id': '9923803820001551', 'holding_id': '22158996320001551'}" 380 | "{'item_pid': '23120920040001551', 'mms_id': '9923803820001551', 'holding_id': '22158996320001551'}" 381 | "{'item_pid': '23120920050001551', 'mms_id': '9923803820001551', 'holding_id': '22158996320001551'}" 382 | "{'item_pid': '23120920060001551', 'mms_id': '9923803820001551', 'holding_id': '22158996320001551'}" 383 | "{'item_pid': '23120920070001551', 'mms_id': '9923803820001551', 'holding_id': '22158996320001551'}" 384 | "{'item_pid': '23120920080001551', 'mms_id': '9923803820001551', 'holding_id': '22158996320001551'}" 385 | "{'item_pid': '23120920090001551', 'mms_id': '9923803820001551', 'holding_id': '22158996320001551'}" 386 | "{'item_pid': '23120920100001551', 'mms_id': '9923803820001551', 'holding_id': '22158996320001551'}" 387 | "{'item_pid': '23120939700001551', 'mms_id': '9923803820001551', 'holding_id': '22159127040001551'}" 388 | "{'item_pid': '23142944650001551', 'mms_id': '9929877310001551', 'holding_id': '22142945090001551'}" 389 | "{'item_pid': '23142944660001551', 'mms_id': '9929877310001551', 'holding_id': '22142945090001551'}" 390 | "{'item_pid': '23142944670001551', 'mms_id': '9929877310001551', 'holding_id': '22142945090001551'}" 391 | "{'item_pid': '23142944680001551', 'mms_id': '9929877310001551', 'holding_id': '22142945090001551'}" 392 | "{'item_pid': '23142944690001551', 'mms_id': '9929877310001551', 'holding_id': '22142945090001551'}" 393 | "{'item_pid': '23142944700001551', 'mms_id': '9929877310001551', 'holding_id': '22142945090001551'}" 394 | "{'item_pid': '23142944710001551', 'mms_id': '9929877310001551', 'holding_id': '22142945090001551'}" 395 | "{'item_pid': '23142944720001551', 'mms_id': '9929877310001551', 'holding_id': '22142945090001551'}" 396 | "{'item_pid': '23142944730001551', 'mms_id': '9929877310001551', 'holding_id': '22142945090001551'}" 397 | "{'item_pid': '23142944740001551', 'mms_id': '9929877310001551', 'holding_id': '22142945090001551'}" 398 | "{'item_pid': '23163739290001551', 'mms_id': '9929867770001551', 'holding_id': '22142901070001551'}" 399 | "{'item_pid': '23163739300001551', 'mms_id': '9929867770001551', 'holding_id': '22142901070001551'}" 400 | "{'item_pid': '23163739310001551', 'mms_id': '9929867770001551', 'holding_id': '22142901070001551'}" 401 | "{'item_pid': '23163739320001551', 'mms_id': '9929867770001551', 'holding_id': '22142901070001551'}" 402 | "{'item_pid': '23163739330001551', 'mms_id': '9929867770001551', 'holding_id': '22142901070001551'}" 403 | "{'item_pid': '23163739340001551', 'mms_id': '9929867770001551', 'holding_id': '22142901070001551'}" 404 | "{'item_pid': '23163739350001551', 'mms_id': '9929867770001551', 'holding_id': '22142901070001551'}" 405 | "{'item_pid': '23163739360001551', 'mms_id': '9929867770001551', 'holding_id': '22142901070001551'}" 406 | "{'item_pid': '23163899640001551', 'mms_id': '9929867770001551', 'holding_id': '22142901070001551'}" 407 | "{'item_pid': '23163899650001551', 'mms_id': '9929867770001551', 'holding_id': '22142901070001551'}" 408 | "{'item_pid': '23163899620001551', 'mms_id': '9929867770001551', 'holding_id': '22142901080001551'}" 409 | "{'item_pid': '23163899630001551', 'mms_id': '9929867770001551', 'holding_id': '22142901080001551'}" 410 | "{'item_pid': '23136678840001551', 'mms_id': '9928175590001551', 'holding_id': '22136678860001551'}" 411 | "{'item_pid': '23136678850001551', 'mms_id': '9928175590001551', 'holding_id': '22136678860001551'}" 412 | "{'item_pid': '23136677930001551', 'mms_id': '9928175590001551', 'holding_id': '22136678530001551'}" 413 | "{'item_pid': '23136677940001551', 'mms_id': '9928175590001551', 'holding_id': '22136678530001551'}" 414 | "{'item_pid': '23136677950001551', 'mms_id': '9928175590001551', 'holding_id': '22136678530001551'}" 415 | "{'item_pid': '23136677960001551', 'mms_id': '9928175590001551', 'holding_id': '22136678530001551'}" 416 | "{'item_pid': '23136677970001551', 'mms_id': '9928175590001551', 'holding_id': '22136678530001551'}" 417 | "{'item_pid': '23136677980001551', 'mms_id': '9928175590001551', 'holding_id': '22136678530001551'}" 418 | "{'item_pid': '23136677990001551', 'mms_id': '9928175590001551', 'holding_id': '22136678530001551'}" 419 | "{'item_pid': '23136678000001551', 'mms_id': '9928175590001551', 'holding_id': '22136678530001551'}" 420 | "{'item_pid': '23136678010001551', 'mms_id': '9928175590001551', 'holding_id': '22136678530001551'}" 421 | "{'item_pid': '23136678020001551', 'mms_id': '9928175590001551', 'holding_id': '22136678530001551'}" 422 | "{'item_pid': '23136678890001551', 'mms_id': '9928175590001551', 'holding_id': '22136678900001551'}" 423 | "{'item_pid': '23136678540001551', 'mms_id': '9928175590001551', 'holding_id': '22136678550001551'}" 424 | "{'item_pid': '23136678560001551', 'mms_id': '9928175590001551', 'holding_id': '22136678590001551'}" 425 | "{'item_pid': '23136678570001551', 'mms_id': '9928175590001551', 'holding_id': '22136678590001551'}" 426 | "{'item_pid': '23136678580001551', 'mms_id': '9928175590001551', 'holding_id': '22136678590001551'}" 427 | "{'item_pid': '23136678870001551', 'mms_id': '9928175590001551', 'holding_id': '22136678880001551'}" 428 | "{'item_pid': '23136678600001551', 'mms_id': '9928175590001551', 'holding_id': '22136678830001551'}" 429 | "{'item_pid': '23136678610001551', 'mms_id': '9928175590001551', 'holding_id': '22136678830001551'}" 430 | "{'item_pid': '23136678620001551', 'mms_id': '9928175590001551', 'holding_id': '22136678830001551'}" 431 | "{'item_pid': '23136678630001551', 'mms_id': '9928175590001551', 'holding_id': '22136678830001551'}" 432 | "{'item_pid': '23136678640001551', 'mms_id': '9928175590001551', 'holding_id': '22136678830001551'}" 433 | "{'item_pid': '23136678650001551', 'mms_id': '9928175590001551', 'holding_id': '22136678830001551'}" 434 | "{'item_pid': '23136678660001551', 'mms_id': '9928175590001551', 'holding_id': '22136678830001551'}" 435 | "{'item_pid': '23136678670001551', 'mms_id': '9928175590001551', 'holding_id': '22136678830001551'}" 436 | "{'item_pid': '23136678680001551', 'mms_id': '9928175590001551', 'holding_id': '22136678830001551'}" 437 | "{'item_pid': '23136678690001551', 'mms_id': '9928175590001551', 'holding_id': '22136678830001551'}" 438 | "{'item_pid': '23136236000001551', 'mms_id': '9928049720001551', 'holding_id': '22159036830001551'}" 439 | "{'item_pid': '23136236010001551', 'mms_id': '9928049720001551', 'holding_id': '22159036830001551'}" 440 | "{'item_pid': '23136236020001551', 'mms_id': '9928049720001551', 'holding_id': '22159036830001551'}" 441 | "{'item_pid': '23136236030001551', 'mms_id': '9928049720001551', 'holding_id': '22159036830001551'}" 442 | "{'item_pid': '23136236040001551', 'mms_id': '9928049720001551', 'holding_id': '22159036830001551'}" 443 | "{'item_pid': '23136236050001551', 'mms_id': '9928049720001551', 'holding_id': '22159036830001551'}" 444 | "{'item_pid': '23136236060001551', 'mms_id': '9928049720001551', 'holding_id': '22159036830001551'}" 445 | "{'item_pid': '23136236070001551', 'mms_id': '9928049720001551', 'holding_id': '22159036830001551'}" 446 | "{'item_pid': '23136236080001551', 'mms_id': '9928049720001551', 'holding_id': '22159036830001551'}" 447 | "{'item_pid': '23136236090001551', 'mms_id': '9928049720001551', 'holding_id': '22159036830001551'}" 448 | "{'item_pid': '23117699070001551', 'mms_id': '9922876790001551', 'holding_id': '22117699430001551'}" 449 | "{'item_pid': '23117699080001551', 'mms_id': '9922876790001551', 'holding_id': '22117699430001551'}" 450 | "{'item_pid': '23117699090001551', 'mms_id': '9922876790001551', 'holding_id': '22117699430001551'}" 451 | "{'item_pid': '23117699100001551', 'mms_id': '9922876790001551', 'holding_id': '22117699430001551'}" 452 | "{'item_pid': '23117699110001551', 'mms_id': '9922876790001551', 'holding_id': '22117699430001551'}" 453 | "{'item_pid': '23117699120001551', 'mms_id': '9922876790001551', 'holding_id': '22117699430001551'}" 454 | "{'item_pid': '23117699130001551', 'mms_id': '9922876790001551', 'holding_id': '22117699430001551'}" 455 | "{'item_pid': '23117699140001551', 'mms_id': '9922876790001551', 'holding_id': '22117699430001551'}" 456 | "{'item_pid': '23117699150001551', 'mms_id': '9922876790001551', 'holding_id': '22117699430001551'}" 457 | "{'item_pid': '23117699160001551', 'mms_id': '9922876790001551', 'holding_id': '22117699430001551'}" 458 | "{'item_pid': '23117699440001551', 'mms_id': '9922876790001551', 'holding_id': '22117699450001551'}" 459 | "{'item_pid': '23117680010001551', 'mms_id': '9922876790001551', 'holding_id': '22117681080001551'}" 460 | "{'item_pid': '23117680020001551', 'mms_id': '9922876790001551', 'holding_id': '22117681080001551'}" 461 | "{'item_pid': '23117680030001551', 'mms_id': '9922876790001551', 'holding_id': '22117681080001551'}" 462 | "{'item_pid': '23117680040001551', 'mms_id': '9922876790001551', 'holding_id': '22117681080001551'}" 463 | "{'item_pid': '23117680080001551', 'mms_id': '9922876790001551', 'holding_id': '22117681080001551'}" 464 | "{'item_pid': '23117680090001551', 'mms_id': '9922876790001551', 'holding_id': '22117681080001551'}" 465 | "{'item_pid': '23117680100001551', 'mms_id': '9922876790001551', 'holding_id': '22117681080001551'}" 466 | "{'item_pid': '23117680110001551', 'mms_id': '9922876790001551', 'holding_id': '22117681080001551'}" 467 | "{'item_pid': '23117680120001551', 'mms_id': '9922876790001551', 'holding_id': '22117681080001551'}" 468 | "{'item_pid': '23117680130001551', 'mms_id': '9922876790001551', 'holding_id': '22117681080001551'}" 469 | "{'item_pid': '23117681090001551', 'mms_id': '9922876790001551', 'holding_id': '22117681110001551'}" 470 | "{'item_pid': '23117681100001551', 'mms_id': '9922876790001551', 'holding_id': '22117681110001551'}" 471 | "{'item_pid': '23117699040001551', 'mms_id': '9922876790001551', 'holding_id': '22117699060001551'}" 472 | "{'item_pid': '23117699050001551', 'mms_id': '9922876790001551', 'holding_id': '22117699060001551'}" 473 | "{'item_pid': '23121016890001551', 'mms_id': '9923814820001551', 'holding_id': '22121019270001551'}" 474 | "{'item_pid': '23121016900001551', 'mms_id': '9923814820001551', 'holding_id': '22121019270001551'}" 475 | "{'item_pid': '23121016910001551', 'mms_id': '9923814820001551', 'holding_id': '22121019270001551'}" 476 | "{'item_pid': '23121016920001551', 'mms_id': '9923814820001551', 'holding_id': '22121019270001551'}" 477 | "{'item_pid': '23121016930001551', 'mms_id': '9923814820001551', 'holding_id': '22121019270001551'}" 478 | "{'item_pid': '23121016940001551', 'mms_id': '9923814820001551', 'holding_id': '22121019270001551'}" 479 | "{'item_pid': '23121016950001551', 'mms_id': '9923814820001551', 'holding_id': '22121019270001551'}" 480 | "{'item_pid': '23121016960001551', 'mms_id': '9923814820001551', 'holding_id': '22121019270001551'}" 481 | "{'item_pid': '23121016970001551', 'mms_id': '9923814820001551', 'holding_id': '22121019270001551'}" 482 | "{'item_pid': '23121016980001551', 'mms_id': '9923814820001551', 'holding_id': '22121019270001551'}" 483 | "{'item_pid': '23113523520001551', 'mms_id': '9921761370001551', 'holding_id': '22155049960001551'}" 484 | "{'item_pid': '23113523530001551', 'mms_id': '9921761370001551', 'holding_id': '22155049960001551'}" 485 | "{'item_pid': '23113523840001551', 'mms_id': '9921761370001551', 'holding_id': '22155049960001551'}" 486 | "{'item_pid': '23113523850001551', 'mms_id': '9921761370001551', 'holding_id': '22155049960001551'}" 487 | "{'item_pid': '23113524250001551', 'mms_id': '9921761370001551', 'holding_id': '22155049960001551'}" 488 | "{'item_pid': '23113524650001551', 'mms_id': '9921761370001551', 'holding_id': '22155049960001551'}" 489 | "{'item_pid': '23113524660001551', 'mms_id': '9921761370001551', 'holding_id': '22155049960001551'}" 490 | "{'item_pid': '23155049950001551', 'mms_id': '9921761370001551', 'holding_id': '22155049960001551'}" 491 | "{'item_pid': '23113525240001551', 'mms_id': '9921761370001551', 'holding_id': '22113525310001551'}" 492 | "{'item_pid': '23113525250001551', 'mms_id': '9921761370001551', 'holding_id': '22113525310001551'}" 493 | "{'item_pid': '23113525260001551', 'mms_id': '9921761370001551', 'holding_id': '22113525310001551'}" 494 | "{'item_pid': '23113525270001551', 'mms_id': '9921761370001551', 'holding_id': '22113525310001551'}" 495 | "{'item_pid': '23113525280001551', 'mms_id': '9921761370001551', 'holding_id': '22113525310001551'}" 496 | "{'item_pid': '23113525290001551', 'mms_id': '9921761370001551', 'holding_id': '22113525310001551'}" 497 | "{'item_pid': '23113525300001551', 'mms_id': '9921761370001551', 'holding_id': '22113525310001551'}" 498 | "{'item_pid': '23155049940001551', 'mms_id': '9921761370001551', 'holding_id': '22155028950001551'}" 499 | "{'item_pid': '23155028920001551', 'mms_id': '9921761370001551', 'holding_id': '22155028940001551'}" 500 | "{'item_pid': '23155028930001551', 'mms_id': '9921761370001551', 'holding_id': '22155028940001551'}" 501 | "{'item_pid': '23113523820001551', 'mms_id': '9921761370001551', 'holding_id': '22155029540001551'}" 502 | "{'item_pid': '23155029430001551', 'mms_id': '9921761370001551', 'holding_id': '22155029540001551'}" 503 | "{'item_pid': '23113525210001551', 'mms_id': '9921761370001551', 'holding_id': '22113525230001551'}" 504 | "{'item_pid': '23113525220001551', 'mms_id': '9921761370001551', 'holding_id': '22113525230001551'}" 505 | "{'item_pid': '23113523230001551', 'mms_id': '9921761370001551', 'holding_id': '22113525200001551'}" 506 | "{'item_pid': '23113523240001551', 'mms_id': '9921761370001551', 'holding_id': '22113525200001551'}" 507 | "{'item_pid': '23113523250001551', 'mms_id': '9921761370001551', 'holding_id': '22113525200001551'}" 508 | "{'item_pid': '23113523260001551', 'mms_id': '9921761370001551', 'holding_id': '22113525200001551'}" 509 | "{'item_pid': '23113523270001551', 'mms_id': '9921761370001551', 'holding_id': '22113525200001551'}" 510 | "{'item_pid': '23113523280001551', 'mms_id': '9921761370001551', 'holding_id': '22113525200001551'}" 511 | "{'item_pid': '23113523290001551', 'mms_id': '9921761370001551', 'holding_id': '22113525200001551'}" 512 | "{'item_pid': '23113523300001551', 'mms_id': '9921761370001551', 'holding_id': '22113525200001551'}" 513 | "{'item_pid': '23113523310001551', 'mms_id': '9921761370001551', 'holding_id': '22113525200001551'}" 514 | "{'item_pid': '23113523380001551', 'mms_id': '9921761370001551', 'holding_id': '22113525200001551'}" 515 | "{'item_pid': '23161810010001551', 'mms_id': '9933545407701551', 'holding_id': '22160535940001551'}" 516 | "{'item_pid': '23161810020001551', 'mms_id': '9933545407701551', 'holding_id': '22160535940001551'}" 517 | "{'item_pid': '23161810030001551', 'mms_id': '9933545407701551', 'holding_id': '22160535940001551'}" 518 | "{'item_pid': '23161810040001551', 'mms_id': '9933545407701551', 'holding_id': '22160535940001551'}" 519 | "{'item_pid': '23161810050001551', 'mms_id': '9933545407701551', 'holding_id': '22160535940001551'}" 520 | "{'item_pid': '23161810060001551', 'mms_id': '9933545407701551', 'holding_id': '22160535940001551'}" 521 | "{'item_pid': '23161810070001551', 'mms_id': '9933545407701551', 'holding_id': '22160535940001551'}" 522 | "{'item_pid': '23161810080001551', 'mms_id': '9933545407701551', 'holding_id': '22160535940001551'}" 523 | "{'item_pid': '23161810090001551', 'mms_id': '9933545407701551', 'holding_id': '22160535940001551'}" 524 | "{'item_pid': '23161810100001551', 'mms_id': '9933545407701551', 'holding_id': '22160535940001551'}" 525 | "{'item_pid': '23122228660001551', 'mms_id': '9924083760001551', 'holding_id': '22122228690001551'}" 526 | "{'item_pid': '23122228670001551', 'mms_id': '9924083760001551', 'holding_id': '22122228690001551'}" 527 | "{'item_pid': '23122228680001551', 'mms_id': '9924083760001551', 'holding_id': '22122228690001551'}" 528 | "{'item_pid': '23122229720001551', 'mms_id': '9924083760001551', 'holding_id': '22122229730001551'}" 529 | "{'item_pid': '23122210370001551', 'mms_id': '9924083760001551', 'holding_id': '22122212770001551'}" 530 | "{'item_pid': '23122210380001551', 'mms_id': '9924083760001551', 'holding_id': '22122212770001551'}" 531 | "{'item_pid': '23122210390001551', 'mms_id': '9924083760001551', 'holding_id': '22122212770001551'}" 532 | "{'item_pid': '23122210400001551', 'mms_id': '9924083760001551', 'holding_id': '22122212770001551'}" 533 | "{'item_pid': '23122210410001551', 'mms_id': '9924083760001551', 'holding_id': '22122212770001551'}" 534 | "{'item_pid': '23122210420001551', 'mms_id': '9924083760001551', 'holding_id': '22122212770001551'}" 535 | "{'item_pid': '23122210430001551', 'mms_id': '9924083760001551', 'holding_id': '22122212770001551'}" 536 | "{'item_pid': '23122210440001551', 'mms_id': '9924083760001551', 'holding_id': '22122212770001551'}" 537 | "{'item_pid': '23122210450001551', 'mms_id': '9924083760001551', 'holding_id': '22122212770001551'}" 538 | "{'item_pid': '23122210460001551', 'mms_id': '9924083760001551', 'holding_id': '22122212770001551'}" 539 | "{'item_pid': '23122229230001551', 'mms_id': '9924083760001551', 'holding_id': '22122229710001551'}" 540 | "{'item_pid': '23122229240001551', 'mms_id': '9924083760001551', 'holding_id': '22122229710001551'}" 541 | "{'item_pid': '23122229250001551', 'mms_id': '9924083760001551', 'holding_id': '22122229710001551'}" 542 | "{'item_pid': '23122229260001551', 'mms_id': '9924083760001551', 'holding_id': '22122229710001551'}" 543 | "{'item_pid': '23122229270001551', 'mms_id': '9924083760001551', 'holding_id': '22122229710001551'}" 544 | "{'item_pid': '23122229280001551', 'mms_id': '9924083760001551', 'holding_id': '22122229710001551'}" 545 | "{'item_pid': '23122229290001551', 'mms_id': '9924083760001551', 'holding_id': '22122229710001551'}" 546 | "{'item_pid': '23122229300001551', 'mms_id': '9924083760001551', 'holding_id': '22122229710001551'}" 547 | "{'item_pid': '23122229310001551', 'mms_id': '9924083760001551', 'holding_id': '22122229710001551'}" 548 | "{'item_pid': '23122229320001551', 'mms_id': '9924083760001551', 'holding_id': '22122229710001551'}" 549 | "{'item_pid': '23122228700001551', 'mms_id': '9924083760001551', 'holding_id': '22122229220001551'}" 550 | "{'item_pid': '23122228710001551', 'mms_id': '9924083760001551', 'holding_id': '22122229220001551'}" 551 | "{'item_pid': '23122228720001551', 'mms_id': '9924083760001551', 'holding_id': '22122229220001551'}" 552 | "{'item_pid': '23122228730001551', 'mms_id': '9924083760001551', 'holding_id': '22122229220001551'}" 553 | "{'item_pid': '23122228740001551', 'mms_id': '9924083760001551', 'holding_id': '22122229220001551'}" 554 | "{'item_pid': '23122228750001551', 'mms_id': '9924083760001551', 'holding_id': '22122229220001551'}" 555 | "{'item_pid': '23122228760001551', 'mms_id': '9924083760001551', 'holding_id': '22122229220001551'}" 556 | "{'item_pid': '23122228770001551', 'mms_id': '9924083760001551', 'holding_id': '22122229220001551'}" 557 | "{'item_pid': '23122228780001551', 'mms_id': '9924083760001551', 'holding_id': '22122229220001551'}" 558 | "{'item_pid': '23122228790001551', 'mms_id': '9924083760001551', 'holding_id': '22122229220001551'}" 559 | "{'item_pid': '23122210040001551', 'mms_id': '9924083760001551', 'holding_id': '22122210360001551'}" 560 | "{'item_pid': '23122210050001551', 'mms_id': '9924083760001551', 'holding_id': '22122210360001551'}" 561 | "{'item_pid': '23122210060001551', 'mms_id': '9924083760001551', 'holding_id': '22122210360001551'}" 562 | "{'item_pid': '23122210070001551', 'mms_id': '9924083760001551', 'holding_id': '22122210360001551'}" 563 | "{'item_pid': '23122210080001551', 'mms_id': '9924083760001551', 'holding_id': '22122210360001551'}" 564 | "{'item_pid': '23122210090001551', 'mms_id': '9924083760001551', 'holding_id': '22122210360001551'}" 565 | "{'item_pid': '23122210100001551', 'mms_id': '9924083760001551', 'holding_id': '22122210360001551'}" 566 | "{'item_pid': '23122210110001551', 'mms_id': '9924083760001551', 'holding_id': '22122210360001551'}" 567 | "{'item_pid': '23122210120001551', 'mms_id': '9924083760001551', 'holding_id': '22122210360001551'}" 568 | "{'item_pid': '23122210130001551', 'mms_id': '9924083760001551', 'holding_id': '22122210360001551'}" 569 | "{'item_pid': '23122210010001551', 'mms_id': '9924083760001551', 'holding_id': '22122210030001551'}" 570 | "{'item_pid': '23122210020001551', 'mms_id': '9924083760001551', 'holding_id': '22122210030001551'}" 571 | "{'item_pid': '23122229740001551', 'mms_id': '9924083760001551', 'holding_id': '22122210030001551'}" 572 | "{'item_pid': '23122229750001551', 'mms_id': '9924083760001551', 'holding_id': '22122210030001551'}" 573 | "{'item_pid': '23122229760001551', 'mms_id': '9924083760001551', 'holding_id': '22122210030001551'}" 574 | "{'item_pid': '23122229770001551', 'mms_id': '9924083760001551', 'holding_id': '22122210030001551'}" 575 | "{'item_pid': '23122229780001551', 'mms_id': '9924083760001551', 'holding_id': '22122210030001551'}" 576 | "{'item_pid': '23122229790001551', 'mms_id': '9924083760001551', 'holding_id': '22122210030001551'}" 577 | "{'item_pid': '23122229800001551', 'mms_id': '9924083760001551', 'holding_id': '22122210030001551'}" 578 | "{'item_pid': '23122229810001551', 'mms_id': '9924083760001551', 'holding_id': '22122210030001551'}" 579 | "{'item_pid': '23116116300001551', 'mms_id': '9922475050001551', 'holding_id': '22116116320001551'}" 580 | "{'item_pid': '23116110290001551', 'mms_id': '9922475050001551', 'holding_id': '22116111920001551'}" 581 | "{'item_pid': '23116110300001551', 'mms_id': '9922475050001551', 'holding_id': '22116111920001551'}" 582 | "{'item_pid': '23116110310001551', 'mms_id': '9922475050001551', 'holding_id': '22116111920001551'}" 583 | "{'item_pid': '23116110320001551', 'mms_id': '9922475050001551', 'holding_id': '22116111920001551'}" 584 | "{'item_pid': '23116110330001551', 'mms_id': '9922475050001551', 'holding_id': '22116111920001551'}" 585 | "{'item_pid': '23116110340001551', 'mms_id': '9922475050001551', 'holding_id': '22116111920001551'}" 586 | "{'item_pid': '23116110350001551', 'mms_id': '9922475050001551', 'holding_id': '22116111920001551'}" 587 | "{'item_pid': '23116110360001551', 'mms_id': '9922475050001551', 'holding_id': '22116111920001551'}" 588 | "{'item_pid': '23116110650001551', 'mms_id': '9922475050001551', 'holding_id': '22116111920001551'}" 589 | "{'item_pid': '23116110660001551', 'mms_id': '9922475050001551', 'holding_id': '22116111920001551'}" 590 | "{'item_pid': '23116112060001551', 'mms_id': '9922475050001551', 'holding_id': '22116113070001551'}" 591 | "{'item_pid': '23116112070001551', 'mms_id': '9922475050001551', 'holding_id': '22116113070001551'}" 592 | "{'item_pid': '23116112080001551', 'mms_id': '9922475050001551', 'holding_id': '22116113070001551'}" 593 | "{'item_pid': '23116112090001551', 'mms_id': '9922475050001551', 'holding_id': '22116113070001551'}" 594 | "{'item_pid': '23116112100001551', 'mms_id': '9922475050001551', 'holding_id': '22116113070001551'}" 595 | "{'item_pid': '23116112110001551', 'mms_id': '9922475050001551', 'holding_id': '22116113070001551'}" 596 | "{'item_pid': '23116112270001551', 'mms_id': '9922475050001551', 'holding_id': '22116113070001551'}" 597 | "{'item_pid': '23116112280001551', 'mms_id': '9922475050001551', 'holding_id': '22116113070001551'}" 598 | "{'item_pid': '23116112290001551', 'mms_id': '9922475050001551', 'holding_id': '22116113070001551'}" 599 | "{'item_pid': '23116112300001551', 'mms_id': '9922475050001551', 'holding_id': '22116113070001551'}" 600 | "{'item_pid': '23116113080001551', 'mms_id': '9922475050001551', 'holding_id': '22116113240001551'}" 601 | "{'item_pid': '23116113090001551', 'mms_id': '9922475050001551', 'holding_id': '22116113240001551'}" 602 | "{'item_pid': '23116113100001551', 'mms_id': '9922475050001551', 'holding_id': '22116113240001551'}" 603 | "{'item_pid': '23116113110001551', 'mms_id': '9922475050001551', 'holding_id': '22116113240001551'}" 604 | "{'item_pid': '23116113120001551', 'mms_id': '9922475050001551', 'holding_id': '22116113240001551'}" 605 | "{'item_pid': '23116113130001551', 'mms_id': '9922475050001551', 'holding_id': '22116113240001551'}" 606 | "{'item_pid': '23116113150001551', 'mms_id': '9922475050001551', 'holding_id': '22116113240001551'}" 607 | "{'item_pid': '23116113180001551', 'mms_id': '9922475050001551', 'holding_id': '22116113240001551'}" 608 | "{'item_pid': '23116113190001551', 'mms_id': '9922475050001551', 'holding_id': '22116113240001551'}" 609 | "{'item_pid': '23116113200001551', 'mms_id': '9922475050001551', 'holding_id': '22116113240001551'}" 610 | "{'item_pid': '23116110040001551', 'mms_id': '9922475050001551', 'holding_id': '22116110210001551'}" 611 | "{'item_pid': '23116110050001551', 'mms_id': '9922475050001551', 'holding_id': '22116110210001551'}" 612 | "{'item_pid': '23116110070001551', 'mms_id': '9922475050001551', 'holding_id': '22116110210001551'}" 613 | "{'item_pid': '23116110100001551', 'mms_id': '9922475050001551', 'holding_id': '22116110210001551'}" 614 | "{'item_pid': '23116110110001551', 'mms_id': '9922475050001551', 'holding_id': '22116110210001551'}" 615 | "{'item_pid': '23116110120001551', 'mms_id': '9922475050001551', 'holding_id': '22116110210001551'}" 616 | "{'item_pid': '23116110130001551', 'mms_id': '9922475050001551', 'holding_id': '22116110210001551'}" 617 | "{'item_pid': '23116110140001551', 'mms_id': '9922475050001551', 'holding_id': '22116110210001551'}" 618 | "{'item_pid': '23116110150001551', 'mms_id': '9922475050001551', 'holding_id': '22116110210001551'}" 619 | "{'item_pid': '23116110160001551', 'mms_id': '9922475050001551', 'holding_id': '22116110210001551'}" 620 | "{'item_pid': '23116114160001551', 'mms_id': '9922475050001551', 'holding_id': '22116116180001551'}" 621 | "{'item_pid': '23116114170001551', 'mms_id': '9922475050001551', 'holding_id': '22116116180001551'}" 622 | "{'item_pid': '23116114190001551', 'mms_id': '9922475050001551', 'holding_id': '22116116180001551'}" 623 | "{'item_pid': '23116114210001551', 'mms_id': '9922475050001551', 'holding_id': '22116116180001551'}" 624 | "{'item_pid': '23116114220001551', 'mms_id': '9922475050001551', 'holding_id': '22116116180001551'}" 625 | "{'item_pid': '23116114230001551', 'mms_id': '9922475050001551', 'holding_id': '22116116180001551'}" 626 | "{'item_pid': '23116114320001551', 'mms_id': '9922475050001551', 'holding_id': '22116116180001551'}" 627 | "{'item_pid': '23116114330001551', 'mms_id': '9922475050001551', 'holding_id': '22116116180001551'}" 628 | "{'item_pid': '23116114340001551', 'mms_id': '9922475050001551', 'holding_id': '22116116180001551'}" 629 | "{'item_pid': '23116114350001551', 'mms_id': '9922475050001551', 'holding_id': '22116116180001551'}" 630 | "{'item_pid': '23116113260001551', 'mms_id': '9922475050001551', 'holding_id': '22116113940001551'}" 631 | "{'item_pid': '23116113370001551', 'mms_id': '9922475050001551', 'holding_id': '22116113940001551'}" 632 | "{'item_pid': '23116113380001551', 'mms_id': '9922475050001551', 'holding_id': '22116113940001551'}" 633 | "{'item_pid': '23116113390001551', 'mms_id': '9922475050001551', 'holding_id': '22116113940001551'}" 634 | "{'item_pid': '23116113400001551', 'mms_id': '9922475050001551', 'holding_id': '22116113940001551'}" 635 | "{'item_pid': '23116113410001551', 'mms_id': '9922475050001551', 'holding_id': '22116113940001551'}" 636 | "{'item_pid': '23116113420001551', 'mms_id': '9922475050001551', 'holding_id': '22116113940001551'}" 637 | "{'item_pid': '23116113430001551', 'mms_id': '9922475050001551', 'holding_id': '22116113940001551'}" 638 | "{'item_pid': '23116113440001551', 'mms_id': '9922475050001551', 'holding_id': '22116113940001551'}" 639 | "{'item_pid': '23116113450001551', 'mms_id': '9922475050001551', 'holding_id': '22116113940001551'}" 640 | "{'item_pid': '23116110220001551', 'mms_id': '9922475050001551', 'holding_id': '22116110280001551'}" 641 | "{'item_pid': '23116110230001551', 'mms_id': '9922475050001551', 'holding_id': '22116110280001551'}" 642 | "{'item_pid': '23116110260001551', 'mms_id': '9922475050001551', 'holding_id': '22116110280001551'}" 643 | "{'item_pid': '23116110270001551', 'mms_id': '9922475050001551', 'holding_id': '22116110280001551'}" 644 | "{'item_pid': '23116113280001551', 'mms_id': '9922475050001551', 'holding_id': '22116110280001551'}" 645 | "{'item_pid': '23116111940001551', 'mms_id': '9922475050001551', 'holding_id': '22116112050001551'}" 646 | "{'item_pid': '23116111950001551', 'mms_id': '9922475050001551', 'holding_id': '22116112050001551'}" 647 | "{'item_pid': '23116111990001551', 'mms_id': '9922475050001551', 'holding_id': '22116112050001551'}" 648 | "{'item_pid': '23116112040001551', 'mms_id': '9922475050001551', 'holding_id': '22116112050001551'}" 649 | "{'item_pid': '23116112590001551', 'mms_id': '9922475050001551', 'holding_id': '22116114140001551'}" 650 | "{'item_pid': '23116113950001551', 'mms_id': '9922475050001551', 'holding_id': '22116114140001551'}" 651 | "{'item_pid': '23116113960001551', 'mms_id': '9922475050001551', 'holding_id': '22116114140001551'}" 652 | "{'item_pid': '23116113970001551', 'mms_id': '9922475050001551', 'holding_id': '22116114140001551'}" 653 | "{'item_pid': '23116113980001551', 'mms_id': '9922475050001551', 'holding_id': '22116114140001551'}" 654 | "{'item_pid': '23116113990001551', 'mms_id': '9922475050001551', 'holding_id': '22116114140001551'}" 655 | "{'item_pid': '23116114000001551', 'mms_id': '9922475050001551', 'holding_id': '22116114140001551'}" 656 | "{'item_pid': '23116114010001551', 'mms_id': '9922475050001551', 'holding_id': '22116114140001551'}" 657 | "{'item_pid': '23116114020001551', 'mms_id': '9922475050001551', 'holding_id': '22116114140001551'}" 658 | "{'item_pid': '23116114030001551', 'mms_id': '9922475050001551', 'holding_id': '22116114140001551'}" 659 | "{'item_pid': '23116116260001551', 'mms_id': '9922475050001551', 'holding_id': '22116116290001551'}" 660 | "{'item_pid': '23116116270001551', 'mms_id': '9922475050001551', 'holding_id': '22116116290001551'}" 661 | "{'item_pid': '23116116280001551', 'mms_id': '9922475050001551', 'holding_id': '22116116290001551'}" 662 | "{'item_pid': '23116116190001551', 'mms_id': '9922475050001551', 'holding_id': '22116116250001551'}" 663 | "{'item_pid': '23116116200001551', 'mms_id': '9922475050001551', 'holding_id': '22116116250001551'}" 664 | "{'item_pid': '23116116210001551', 'mms_id': '9922475050001551', 'holding_id': '22116116250001551'}" 665 | "{'item_pid': '23116116220001551', 'mms_id': '9922475050001551', 'holding_id': '22116116250001551'}" 666 | "{'item_pid': '23116116230001551', 'mms_id': '9922475050001551', 'holding_id': '22116116250001551'}" 667 | "{'item_pid': '23116116240001551', 'mms_id': '9922475050001551', 'holding_id': '22116116250001551'}" 668 | "{'item_pid': '23116110010001551', 'mms_id': '9922475050001551', 'holding_id': '22116110030001551'}" 669 | "{'item_pid': '23116110020001551', 'mms_id': '9922475050001551', 'holding_id': '22116110030001551'}" 670 | "{'item_pid': '23116128960001551', 'mms_id': '9922475050001551', 'holding_id': '22116110030001551'}" 671 | "{'item_pid': '23116128970001551', 'mms_id': '9922475050001551', 'holding_id': '22116110030001551'}" 672 | "{'item_pid': '23116128980001551', 'mms_id': '9922475050001551', 'holding_id': '22116110030001551'}" 673 | "{'item_pid': '23116128990001551', 'mms_id': '9922475050001551', 'holding_id': '22116110030001551'}" 674 | "{'item_pid': '23116129000001551', 'mms_id': '9922475050001551', 'holding_id': '22116110030001551'}" 675 | "{'item_pid': '23116129010001551', 'mms_id': '9922475050001551', 'holding_id': '22116110030001551'}" 676 | "{'item_pid': '23116129020001551', 'mms_id': '9922475050001551', 'holding_id': '22116110030001551'}" 677 | "{'item_pid': '23116129030001551', 'mms_id': '9922475050001551', 'holding_id': '22116110030001551'}" 678 | "{'item_pid': '23160230350001551', 'mms_id': '9927990200001551', 'holding_id': '22136024830001551'}" 679 | "{'item_pid': '23160230360001551', 'mms_id': '9927990200001551', 'holding_id': '22136024830001551'}" 680 | "{'item_pid': '23160535700001551', 'mms_id': '9927990200001551', 'holding_id': '22136024830001551'}" 681 | "{'item_pid': '23160535710001551', 'mms_id': '9927990200001551', 'holding_id': '22136024830001551'}" 682 | "{'item_pid': '23160535720001551', 'mms_id': '9927990200001551', 'holding_id': '22136024830001551'}" 683 | "{'item_pid': '23160535730001551', 'mms_id': '9927990200001551', 'holding_id': '22136024830001551'}" 684 | "{'item_pid': '23160535740001551', 'mms_id': '9927990200001551', 'holding_id': '22136024830001551'}" 685 | "{'item_pid': '23160535750001551', 'mms_id': '9927990200001551', 'holding_id': '22136024830001551'}" 686 | "{'item_pid': '23160535760001551', 'mms_id': '9927990200001551', 'holding_id': '22136024830001551'}" 687 | "{'item_pid': '23160535770001551', 'mms_id': '9927990200001551', 'holding_id': '22136024830001551'}" 688 | "{'item_pid': '23160534590001551', 'mms_id': '9927990200001551', 'holding_id': '22160534600001551'}" 689 | "{'item_pid': '23130030010001551', 'mms_id': '9926293280001551', 'holding_id': '22130030940001551'}" 690 | "{'item_pid': '23130030020001551', 'mms_id': '9926293280001551', 'holding_id': '22130030940001551'}" 691 | "{'item_pid': '23130030030001551', 'mms_id': '9926293280001551', 'holding_id': '22130030940001551'}" 692 | "{'item_pid': '23130030040001551', 'mms_id': '9926293280001551', 'holding_id': '22130030940001551'}" 693 | "{'item_pid': '23130030050001551', 'mms_id': '9926293280001551', 'holding_id': '22130030940001551'}" 694 | "{'item_pid': '23130030060001551', 'mms_id': '9926293280001551', 'holding_id': '22130030940001551'}" 695 | "{'item_pid': '23130030070001551', 'mms_id': '9926293280001551', 'holding_id': '22130030940001551'}" 696 | "{'item_pid': '23130030080001551', 'mms_id': '9926293280001551', 'holding_id': '22130030940001551'}" 697 | "{'item_pid': '23130030090001551', 'mms_id': '9926293280001551', 'holding_id': '22130030940001551'}" 698 | "{'item_pid': '23130030100001551', 'mms_id': '9926293280001551', 'holding_id': '22130030940001551'}" 699 | "{'item_pid': '23130030980001551', 'mms_id': '9926293280001551', 'holding_id': '22130031060001551'}" 700 | "{'item_pid': '23130030990001551', 'mms_id': '9926293280001551', 'holding_id': '22130031060001551'}" 701 | "{'item_pid': '23130031000001551', 'mms_id': '9926293280001551', 'holding_id': '22130031060001551'}" 702 | "{'item_pid': '23130031010001551', 'mms_id': '9926293280001551', 'holding_id': '22130031060001551'}" 703 | "{'item_pid': '23130031020001551', 'mms_id': '9926293280001551', 'holding_id': '22130031060001551'}" 704 | "{'item_pid': '23130031030001551', 'mms_id': '9926293280001551', 'holding_id': '22130031060001551'}" 705 | "{'item_pid': '23130031040001551', 'mms_id': '9926293280001551', 'holding_id': '22130031060001551'}" 706 | "{'item_pid': '23130031050001551', 'mms_id': '9926293280001551', 'holding_id': '22130031060001551'}" 707 | "{'item_pid': '23130049260001551', 'mms_id': '9926293280001551', 'holding_id': '22130049270001551'}" 708 | "{'item_pid': '23130031070001551', 'mms_id': '9926293280001551', 'holding_id': '22130031120001551'}" 709 | "{'item_pid': '23130031080001551', 'mms_id': '9926293280001551', 'holding_id': '22130031120001551'}" 710 | "{'item_pid': '23130031090001551', 'mms_id': '9926293280001551', 'holding_id': '22130031120001551'}" 711 | "{'item_pid': '23130031100001551', 'mms_id': '9926293280001551', 'holding_id': '22130031120001551'}" 712 | "{'item_pid': '23130031110001551', 'mms_id': '9926293280001551', 'holding_id': '22130031120001551'}" 713 | "{'item_pid': '23130031130001551', 'mms_id': '9926293280001551', 'holding_id': '22130031620001551'}" 714 | "{'item_pid': '23130031140001551', 'mms_id': '9926293280001551', 'holding_id': '22130031620001551'}" 715 | "{'item_pid': '23130031150001551', 'mms_id': '9926293280001551', 'holding_id': '22130031620001551'}" 716 | "{'item_pid': '23130031160001551', 'mms_id': '9926293280001551', 'holding_id': '22130031620001551'}" 717 | "{'item_pid': '23130031170001551', 'mms_id': '9926293280001551', 'holding_id': '22130031620001551'}" 718 | "{'item_pid': '23130031180001551', 'mms_id': '9926293280001551', 'holding_id': '22130031620001551'}" 719 | "{'item_pid': '23130031200001551', 'mms_id': '9926293280001551', 'holding_id': '22130031620001551'}" 720 | "{'item_pid': '23130031220001551', 'mms_id': '9926293280001551', 'holding_id': '22130031620001551'}" 721 | "{'item_pid': '23130031230001551', 'mms_id': '9926293280001551', 'holding_id': '22130031620001551'}" 722 | "{'item_pid': '23130031240001551', 'mms_id': '9926293280001551', 'holding_id': '22130031620001551'}" 723 | "{'item_pid': '23130020030001551', 'mms_id': '9926293280001551', 'holding_id': '22130028170001551'}" 724 | "{'item_pid': '23130020060001551', 'mms_id': '9926293280001551', 'holding_id': '22130028170001551'}" 725 | "{'item_pid': '23130020070001551', 'mms_id': '9926293280001551', 'holding_id': '22130028170001551'}" 726 | "{'item_pid': '23130020080001551', 'mms_id': '9926293280001551', 'holding_id': '22130028170001551'}" 727 | "{'item_pid': '23130020090001551', 'mms_id': '9926293280001551', 'holding_id': '22130028170001551'}" 728 | "{'item_pid': '23130020100001551', 'mms_id': '9926293280001551', 'holding_id': '22130028170001551'}" 729 | "{'item_pid': '23130020110001551', 'mms_id': '9926293280001551', 'holding_id': '22130028170001551'}" 730 | "{'item_pid': '23130020130001551', 'mms_id': '9926293280001551', 'holding_id': '22130028170001551'}" 731 | "{'item_pid': '23130020160001551', 'mms_id': '9926293280001551', 'holding_id': '22130028170001551'}" 732 | "{'item_pid': '23130020170001551', 'mms_id': '9926293280001551', 'holding_id': '22130028170001551'}" 733 | "{'item_pid': '23130049290001551', 'mms_id': '9926293280001551', 'holding_id': '22130049300001551'}" 734 | "{'item_pid': '23130049280001551', 'mms_id': '9926293280001551', 'holding_id': '22130049320001551'}" 735 | "{'item_pid': '23130049310001551', 'mms_id': '9926293280001551', 'holding_id': '22130049320001551'}" 736 | "{'item_pid': '23128680010001551', 'mms_id': '9925905280001551', 'holding_id': '22128685330001551'}" 737 | "{'item_pid': '23128680040001551', 'mms_id': '9925905280001551', 'holding_id': '22128685330001551'}" 738 | "{'item_pid': '23128680060001551', 'mms_id': '9925905280001551', 'holding_id': '22128685330001551'}" 739 | "{'item_pid': '23128680100001551', 'mms_id': '9925905280001551', 'holding_id': '22128685330001551'}" 740 | "{'item_pid': '23128680110001551', 'mms_id': '9925905280001551', 'holding_id': '22128685330001551'}" 741 | "{'item_pid': '23128680140001551', 'mms_id': '9925905280001551', 'holding_id': '22128685330001551'}" 742 | "{'item_pid': '23128680150001551', 'mms_id': '9925905280001551', 'holding_id': '22128685330001551'}" 743 | "{'item_pid': '23128680160001551', 'mms_id': '9925905280001551', 'holding_id': '22128685330001551'}" 744 | "{'item_pid': '23128680170001551', 'mms_id': '9925905280001551', 'holding_id': '22128685330001551'}" 745 | "{'item_pid': '23128680180001551', 'mms_id': '9925905280001551', 'holding_id': '22128685330001551'}" 746 | "{'item_pid': '23128691450001551', 'mms_id': '9925905280001551', 'holding_id': '22128691740001551'}" 747 | "{'item_pid': '23128691460001551', 'mms_id': '9925905280001551', 'holding_id': '22128691740001551'}" 748 | "{'item_pid': '23128691470001551', 'mms_id': '9925905280001551', 'holding_id': '22128691740001551'}" 749 | "{'item_pid': '23128691480001551', 'mms_id': '9925905280001551', 'holding_id': '22128691740001551'}" 750 | "{'item_pid': '23128691490001551', 'mms_id': '9925905280001551', 'holding_id': '22128691740001551'}" 751 | "{'item_pid': '23128691500001551', 'mms_id': '9925905280001551', 'holding_id': '22128691740001551'}" 752 | "{'item_pid': '23128691720001551', 'mms_id': '9925905280001551', 'holding_id': '22128691740001551'}" 753 | "{'item_pid': '23128691730001551', 'mms_id': '9925905280001551', 'holding_id': '22128691740001551'}" 754 | "{'item_pid': '23151466430001551', 'mms_id': '9925905280001551', 'holding_id': '22128691740001551'}" 755 | "{'item_pid': '23151466460001551', 'mms_id': '9925905280001551', 'holding_id': '22128691740001551'}" 756 | "{'item_pid': '23128692360001551', 'mms_id': '9925905280001551', 'holding_id': '22128694380001551'}" 757 | "{'item_pid': '23128692370001551', 'mms_id': '9925905280001551', 'holding_id': '22128694380001551'}" 758 | "{'item_pid': '23128692380001551', 'mms_id': '9925905280001551', 'holding_id': '22128694380001551'}" 759 | "{'item_pid': '23128692390001551', 'mms_id': '9925905280001551', 'holding_id': '22128694380001551'}" 760 | "{'item_pid': '23128692400001551', 'mms_id': '9925905280001551', 'holding_id': '22128694380001551'}" 761 | "{'item_pid': '23128692410001551', 'mms_id': '9925905280001551', 'holding_id': '22128694380001551'}" 762 | "{'item_pid': '23128692420001551', 'mms_id': '9925905280001551', 'holding_id': '22128694380001551'}" 763 | "{'item_pid': '23128692430001551', 'mms_id': '9925905280001551', 'holding_id': '22128694380001551'}" 764 | "{'item_pid': '23128692440001551', 'mms_id': '9925905280001551', 'holding_id': '22128694380001551'}" 765 | "{'item_pid': '23128692450001551', 'mms_id': '9925905280001551', 'holding_id': '22128694380001551'}" 766 | "{'item_pid': '23128680960001551', 'mms_id': '9925905280001551', 'holding_id': '22128687580001551'}" 767 | "{'item_pid': '23128680970001551', 'mms_id': '9925905280001551', 'holding_id': '22128687580001551'}" 768 | "{'item_pid': '23128685360001551', 'mms_id': '9925905280001551', 'holding_id': '22128687580001551'}" 769 | "{'item_pid': '23128685370001551', 'mms_id': '9925905280001551', 'holding_id': '22128687580001551'}" 770 | "{'item_pid': '23128685380001551', 'mms_id': '9925905280001551', 'holding_id': '22128687580001551'}" 771 | "{'item_pid': '23128685390001551', 'mms_id': '9925905280001551', 'holding_id': '22128687580001551'}" 772 | "{'item_pid': '23128685400001551', 'mms_id': '9925905280001551', 'holding_id': '22128687580001551'}" 773 | "{'item_pid': '23128685410001551', 'mms_id': '9925905280001551', 'holding_id': '22128687580001551'}" 774 | "{'item_pid': '23128685420001551', 'mms_id': '9925905280001551', 'holding_id': '22128687580001551'}" 775 | "{'item_pid': '23128685430001551', 'mms_id': '9925905280001551', 'holding_id': '22128687580001551'}" 776 | "{'item_pid': '23128694390001551', 'mms_id': '9925905280001551', 'holding_id': '22128694400001551'}" 777 | "{'item_pid': '23151979600001551', 'mms_id': '9925905280001551', 'holding_id': '22151979620001551'}" 778 | --------------------------------------------------------------------------------