almaapitk 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. almaapitk-0.3.1/LICENSE +21 -0
  2. almaapitk-0.3.1/PKG-INFO +266 -0
  3. almaapitk-0.3.1/README.md +231 -0
  4. almaapitk-0.3.1/docs/releases/0.3.1.md +38 -0
  5. almaapitk-0.3.1/pyproject.toml +77 -0
  6. almaapitk-0.3.1/src/almaapitk/__init__.py +112 -0
  7. almaapitk-0.3.1/src/almaapitk/_internal/__init__.py +39 -0
  8. almaapitk-0.3.1/src/almaapitk/_internal/client.py +9 -0
  9. almaapitk-0.3.1/src/almaapitk/_internal/domains.py +29 -0
  10. almaapitk-0.3.1/src/almaapitk/_internal/exceptions.py +9 -0
  11. almaapitk-0.3.1/src/almaapitk/_internal/response.py +9 -0
  12. almaapitk-0.3.1/src/almaapitk/alma_logging/__init__.py +58 -0
  13. almaapitk-0.3.1/src/almaapitk/alma_logging/config.py +245 -0
  14. almaapitk-0.3.1/src/almaapitk/alma_logging/formatters.py +230 -0
  15. almaapitk-0.3.1/src/almaapitk/alma_logging/handlers.py +165 -0
  16. almaapitk-0.3.1/src/almaapitk/alma_logging/logger.py +286 -0
  17. almaapitk-0.3.1/src/almaapitk/client/AlmaAPIClient.py +480 -0
  18. almaapitk-0.3.1/src/almaapitk/client/__init__.py +6 -0
  19. almaapitk-0.3.1/src/almaapitk/domains/__init__.py +18 -0
  20. almaapitk-0.3.1/src/almaapitk/domains/acquisition.py +2372 -0
  21. almaapitk-0.3.1/src/almaapitk/domains/admin.py +760 -0
  22. almaapitk-0.3.1/src/almaapitk/domains/analytics.py +300 -0
  23. almaapitk-0.3.1/src/almaapitk/domains/bibs.py +825 -0
  24. almaapitk-0.3.1/src/almaapitk/domains/resource_sharing.py +631 -0
  25. almaapitk-0.3.1/src/almaapitk/domains/users.py +693 -0
  26. almaapitk-0.3.1/src/almaapitk/utils/__init__.py +0 -0
  27. almaapitk-0.3.1/src/almaapitk/utils/citation_metadata.py +517 -0
  28. almaapitk-0.3.1/src/almaapitk/utils/tsv_generator.py +438 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Hagay Bar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,266 @@
1
+ Metadata-Version: 2.3
2
+ Name: almaapitk
3
+ Version: 0.3.1
4
+ Summary: Python toolkit for the Ex Libris Alma ILS API
5
+ License: MIT
6
+ Keywords: alma,ils,library,api,ex-libris,acquisitions,cataloging,resource-sharing
7
+ Author: Hagay Bar
8
+ Author-email: hagaybar@gmail.com
9
+ Requires-Python: >=3.12
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Information Technology
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
20
+ Classifier: Typing :: Typed
21
+ Requires-Dist: beautifulsoup4 (>=4.14.3,<5.0.0)
22
+ Requires-Dist: boto3 (>=1.35.0,<2.0.0)
23
+ Requires-Dist: lxml (>=6.0.2,<7.0.0)
24
+ Requires-Dist: openpyxl (>=3.1.0,<4.0.0)
25
+ Requires-Dist: pandas (>=2.0.0,<3.0.0)
26
+ Requires-Dist: pypdf2 (>=3.0.0,<4.0.0)
27
+ Requires-Dist: pyyaml (>=6.0.3,<7.0.0)
28
+ Requires-Dist: requests (>=2.32.0,<3.0.0)
29
+ Project-URL: Documentation, https://github.com/hagaybar/AlmaAPITK#readme
30
+ Project-URL: Homepage, https://github.com/hagaybar/AlmaAPITK
31
+ Project-URL: Issues, https://github.com/hagaybar/AlmaAPITK/issues
32
+ Project-URL: Repository, https://github.com/hagaybar/AlmaAPITK
33
+ Description-Content-Type: text/markdown
34
+
35
+ # almaapitk
36
+
37
+ A Python toolkit for interacting with the Ex Libris Alma ILS (Integrated Library System) API.
38
+
39
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
40
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
41
+
42
+ ## Features
43
+
44
+ - **Simple API Client**: Easy-to-use HTTP client with automatic authentication and error handling
45
+ - **Domain Classes**: High-level abstractions for common Alma operations
46
+ - `Acquisitions` - POL operations, invoicing, item receiving
47
+ - `Analytics` - Analytics reports with pagination support
48
+ - `Users` - User management, email updates
49
+ - `BibliographicRecords` - Bib records, holdings, items
50
+ - `Admin` - Sets management (BIB_MMS, USER)
51
+ - `ResourceSharing` - Lending/borrowing via Partners API
52
+ - **Environment Support**: Seamless switching between Sandbox and Production
53
+ - **Response Wrapper**: Consistent response handling with `AlmaResponse`
54
+ - **Comprehensive Logging**: Built-in logging with automatic API key redaction
55
+
56
+ ## Installation
57
+
58
+ ```bash
59
+ pip install almaapitk
60
+ ```
61
+
62
+ Or with Poetry:
63
+
64
+ ```bash
65
+ poetry add almaapitk
66
+ ```
67
+
68
+ ## Quick Start
69
+
70
+ ### Setup
71
+
72
+ Set your Alma API keys as environment variables:
73
+
74
+ ```bash
75
+ export ALMA_SB_API_KEY="your-sandbox-api-key"
76
+ export ALMA_PROD_API_KEY="your-production-api-key"
77
+ ```
78
+
79
+ ### Basic Usage
80
+
81
+ ```python
82
+ from almaapitk import AlmaAPIClient, AlmaAPIError
83
+
84
+ # Initialize client (uses ALMA_SB_API_KEY)
85
+ client = AlmaAPIClient('SANDBOX')
86
+
87
+ # Make API calls
88
+ try:
89
+ response = client.get('almaws/v1/conf/libraries')
90
+ if response.success:
91
+ libraries = response.json()
92
+ for lib in libraries.get('library', []):
93
+ print(f"Library: {lib['name']}")
94
+ except AlmaAPIError as e:
95
+ print(f"API error: {e} (status: {e.status_code})")
96
+ ```
97
+
98
+ ### Using Domain Classes
99
+
100
+ ```python
101
+ from almaapitk import AlmaAPIClient, Acquisitions, Users
102
+
103
+ client = AlmaAPIClient('SANDBOX')
104
+
105
+ # Acquisitions operations
106
+ acq = Acquisitions(client)
107
+ # Note: Acquisitions.get_pol returns a plain dict directly
108
+ pol = acq.get_pol("POL-12345")
109
+ print(f"POL Status: {pol['status']['value']}")
110
+
111
+ # User operations
112
+ # Note: get_user takes a primary ID (NOT email) and returns an AlmaResponse
113
+ users = Users(client)
114
+ user_response = users.get_user("PRIMARY_ID_12345")
115
+ user_data = user_response.json()
116
+ print(f"User: {user_data['full_name']}")
117
+ ```
118
+
119
+ ### Working with Bibliographic Records
120
+
121
+ ```python
122
+ from almaapitk import AlmaAPIClient, BibliographicRecords
123
+
124
+ client = AlmaAPIClient('SANDBOX')
125
+ bibs = BibliographicRecords(client)
126
+
127
+ # Get a bib record (signature: get_record(mms_id, view="full", expand=None))
128
+ record = bibs.get_record("99123456789")
129
+
130
+ # Get holdings for a bib
131
+ holdings = bibs.get_holdings("99123456789")
132
+ ```
133
+
134
+ ### Resource Sharing
135
+
136
+ ```python
137
+ from almaapitk import AlmaAPIClient, ResourceSharing
138
+
139
+ client = AlmaAPIClient('SANDBOX')
140
+ rs = ResourceSharing(client)
141
+
142
+ # Create a lending request
143
+ # Mandatory: partner_code, external_id, owner, format_type, title
144
+ # (citation_type is required unless mms_id is supplied)
145
+ result = rs.create_lending_request(
146
+ partner_code="PARTNER_CODE",
147
+ external_id="EXT-2025-001",
148
+ owner="MAIN", # resource sharing library code
149
+ format_type="PHYSICAL",
150
+ title="Introduction to Python",
151
+ citation_type="BOOK",
152
+ author="Smith, John",
153
+ )
154
+ ```
155
+
156
+ ### Analytics Reports
157
+
158
+ ```python
159
+ from almaapitk import AlmaAPIClient, Analytics
160
+
161
+ # Analytics API only works with PRODUCTION
162
+ client = AlmaAPIClient('PRODUCTION')
163
+ analytics = Analytics(client)
164
+
165
+ # Get column headers for a report
166
+ report_path = "/shared/University/Reports/MyReport"
167
+ headers = analytics.get_report_headers(report_path)
168
+ print(f"Columns: {headers}")
169
+
170
+ # Fetch rows with pagination (limit must be 25-1000)
171
+ rows = analytics.fetch_report_rows(report_path, limit=100, max_rows=500)
172
+ for row in rows:
173
+ print(row) # Dict with Column0, Column1, etc.
174
+
175
+ # Optional: pass a progress_callback to track progress for large reports.
176
+ # The callback receives one argument: the cumulative row count fetched so far.
177
+ def show_progress(rows_so_far: int) -> None:
178
+ print(f" fetched {rows_so_far} rows...")
179
+
180
+ rows = analytics.fetch_report_rows(
181
+ report_path,
182
+ limit=100,
183
+ max_rows=500,
184
+ progress_callback=show_progress,
185
+ )
186
+ ```
187
+
188
+ ## API Reference
189
+
190
+ ### Core Classes
191
+
192
+ | Class | Description |
193
+ |-------|-------------|
194
+ | `AlmaAPIClient` | Main HTTP client for Alma API |
195
+ | `AlmaResponse` | Response wrapper with `.data`, `.json()`, `.success`, `.status_code` |
196
+ | `AlmaAPIError` | Base exception for API errors |
197
+ | `AlmaValidationError` | Exception for validation failures |
198
+
199
+ ### Domain Classes
200
+
201
+ | Class | Description |
202
+ |-------|-------------|
203
+ | `Acquisitions` | POL operations, invoicing, item receiving |
204
+ | `Analytics` | Analytics reports with pagination (ResumptionToken) |
205
+ | `Users` | User management, email updates |
206
+ | `BibliographicRecords` | Bib records, holdings, items, scan-in |
207
+ | `Admin` | Sets management (BIB_MMS, USER sets) |
208
+ | `ResourceSharing` | Lending/borrowing via Partners API |
209
+
210
+ ### Utilities
211
+
212
+ | Class | Description |
213
+ |-------|-------------|
214
+ | `TSVGenerator` | TSV file generation utilities |
215
+ | `CitationMetadataError` | Exception for citation metadata errors |
216
+
217
+ ## Environment Configuration
218
+
219
+ See [Quick Start → Setup](#setup) for environment variable setup. The client
220
+ automatically picks `ALMA_SB_API_KEY` for `'SANDBOX'` and `ALMA_PROD_API_KEY`
221
+ for `'PRODUCTION'`.
222
+
223
+ ## Error Handling
224
+
225
+ ```python
226
+ from almaapitk import AlmaAPIClient, AlmaAPIError, AlmaValidationError
227
+
228
+ client = AlmaAPIClient('SANDBOX')
229
+
230
+ try:
231
+ response = client.get('almaws/v1/users/invalid-user')
232
+ except AlmaValidationError as e:
233
+ # Input validation failed
234
+ print(f"Validation error: {e}")
235
+ except AlmaAPIError as e:
236
+ # API returned an error
237
+ print(f"API error: {e}")
238
+ print(f"Status code: {e.status_code}")
239
+ print(f"Response: {e.response}")
240
+ ```
241
+
242
+ ## Requirements
243
+
244
+ - Python 3.12+
245
+ - requests
246
+ - pandas
247
+ - openpyxl
248
+ - boto3
249
+ - pypdf2
250
+ - pyyaml
251
+ - beautifulsoup4
252
+ - lxml
253
+
254
+ ## License
255
+
256
+ MIT License - see [LICENSE](LICENSE) for details.
257
+
258
+ ## Contributing
259
+
260
+ Contributions are welcome! Please feel free to submit a Pull Request.
261
+
262
+ ## Links
263
+
264
+ - [Alma API Documentation](https://developers.exlibrisgroup.com/alma/apis/)
265
+ - [GitHub Repository](https://github.com/hagaybar/AlmaAPITK)
266
+
@@ -0,0 +1,231 @@
1
+ # almaapitk
2
+
3
+ A Python toolkit for interacting with the Ex Libris Alma ILS (Integrated Library System) API.
4
+
5
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Features
9
+
10
+ - **Simple API Client**: Easy-to-use HTTP client with automatic authentication and error handling
11
+ - **Domain Classes**: High-level abstractions for common Alma operations
12
+ - `Acquisitions` - POL operations, invoicing, item receiving
13
+ - `Analytics` - Analytics reports with pagination support
14
+ - `Users` - User management, email updates
15
+ - `BibliographicRecords` - Bib records, holdings, items
16
+ - `Admin` - Sets management (BIB_MMS, USER)
17
+ - `ResourceSharing` - Lending/borrowing via Partners API
18
+ - **Environment Support**: Seamless switching between Sandbox and Production
19
+ - **Response Wrapper**: Consistent response handling with `AlmaResponse`
20
+ - **Comprehensive Logging**: Built-in logging with automatic API key redaction
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ pip install almaapitk
26
+ ```
27
+
28
+ Or with Poetry:
29
+
30
+ ```bash
31
+ poetry add almaapitk
32
+ ```
33
+
34
+ ## Quick Start
35
+
36
+ ### Setup
37
+
38
+ Set your Alma API keys as environment variables:
39
+
40
+ ```bash
41
+ export ALMA_SB_API_KEY="your-sandbox-api-key"
42
+ export ALMA_PROD_API_KEY="your-production-api-key"
43
+ ```
44
+
45
+ ### Basic Usage
46
+
47
+ ```python
48
+ from almaapitk import AlmaAPIClient, AlmaAPIError
49
+
50
+ # Initialize client (uses ALMA_SB_API_KEY)
51
+ client = AlmaAPIClient('SANDBOX')
52
+
53
+ # Make API calls
54
+ try:
55
+ response = client.get('almaws/v1/conf/libraries')
56
+ if response.success:
57
+ libraries = response.json()
58
+ for lib in libraries.get('library', []):
59
+ print(f"Library: {lib['name']}")
60
+ except AlmaAPIError as e:
61
+ print(f"API error: {e} (status: {e.status_code})")
62
+ ```
63
+
64
+ ### Using Domain Classes
65
+
66
+ ```python
67
+ from almaapitk import AlmaAPIClient, Acquisitions, Users
68
+
69
+ client = AlmaAPIClient('SANDBOX')
70
+
71
+ # Acquisitions operations
72
+ acq = Acquisitions(client)
73
+ # Note: Acquisitions.get_pol returns a plain dict directly
74
+ pol = acq.get_pol("POL-12345")
75
+ print(f"POL Status: {pol['status']['value']}")
76
+
77
+ # User operations
78
+ # Note: get_user takes a primary ID (NOT email) and returns an AlmaResponse
79
+ users = Users(client)
80
+ user_response = users.get_user("PRIMARY_ID_12345")
81
+ user_data = user_response.json()
82
+ print(f"User: {user_data['full_name']}")
83
+ ```
84
+
85
+ ### Working with Bibliographic Records
86
+
87
+ ```python
88
+ from almaapitk import AlmaAPIClient, BibliographicRecords
89
+
90
+ client = AlmaAPIClient('SANDBOX')
91
+ bibs = BibliographicRecords(client)
92
+
93
+ # Get a bib record (signature: get_record(mms_id, view="full", expand=None))
94
+ record = bibs.get_record("99123456789")
95
+
96
+ # Get holdings for a bib
97
+ holdings = bibs.get_holdings("99123456789")
98
+ ```
99
+
100
+ ### Resource Sharing
101
+
102
+ ```python
103
+ from almaapitk import AlmaAPIClient, ResourceSharing
104
+
105
+ client = AlmaAPIClient('SANDBOX')
106
+ rs = ResourceSharing(client)
107
+
108
+ # Create a lending request
109
+ # Mandatory: partner_code, external_id, owner, format_type, title
110
+ # (citation_type is required unless mms_id is supplied)
111
+ result = rs.create_lending_request(
112
+ partner_code="PARTNER_CODE",
113
+ external_id="EXT-2025-001",
114
+ owner="MAIN", # resource sharing library code
115
+ format_type="PHYSICAL",
116
+ title="Introduction to Python",
117
+ citation_type="BOOK",
118
+ author="Smith, John",
119
+ )
120
+ ```
121
+
122
+ ### Analytics Reports
123
+
124
+ ```python
125
+ from almaapitk import AlmaAPIClient, Analytics
126
+
127
+ # Analytics API only works with PRODUCTION
128
+ client = AlmaAPIClient('PRODUCTION')
129
+ analytics = Analytics(client)
130
+
131
+ # Get column headers for a report
132
+ report_path = "/shared/University/Reports/MyReport"
133
+ headers = analytics.get_report_headers(report_path)
134
+ print(f"Columns: {headers}")
135
+
136
+ # Fetch rows with pagination (limit must be 25-1000)
137
+ rows = analytics.fetch_report_rows(report_path, limit=100, max_rows=500)
138
+ for row in rows:
139
+ print(row) # Dict with Column0, Column1, etc.
140
+
141
+ # Optional: pass a progress_callback to track progress for large reports.
142
+ # The callback receives one argument: the cumulative row count fetched so far.
143
+ def show_progress(rows_so_far: int) -> None:
144
+ print(f" fetched {rows_so_far} rows...")
145
+
146
+ rows = analytics.fetch_report_rows(
147
+ report_path,
148
+ limit=100,
149
+ max_rows=500,
150
+ progress_callback=show_progress,
151
+ )
152
+ ```
153
+
154
+ ## API Reference
155
+
156
+ ### Core Classes
157
+
158
+ | Class | Description |
159
+ |-------|-------------|
160
+ | `AlmaAPIClient` | Main HTTP client for Alma API |
161
+ | `AlmaResponse` | Response wrapper with `.data`, `.json()`, `.success`, `.status_code` |
162
+ | `AlmaAPIError` | Base exception for API errors |
163
+ | `AlmaValidationError` | Exception for validation failures |
164
+
165
+ ### Domain Classes
166
+
167
+ | Class | Description |
168
+ |-------|-------------|
169
+ | `Acquisitions` | POL operations, invoicing, item receiving |
170
+ | `Analytics` | Analytics reports with pagination (ResumptionToken) |
171
+ | `Users` | User management, email updates |
172
+ | `BibliographicRecords` | Bib records, holdings, items, scan-in |
173
+ | `Admin` | Sets management (BIB_MMS, USER sets) |
174
+ | `ResourceSharing` | Lending/borrowing via Partners API |
175
+
176
+ ### Utilities
177
+
178
+ | Class | Description |
179
+ |-------|-------------|
180
+ | `TSVGenerator` | TSV file generation utilities |
181
+ | `CitationMetadataError` | Exception for citation metadata errors |
182
+
183
+ ## Environment Configuration
184
+
185
+ See [Quick Start → Setup](#setup) for environment variable setup. The client
186
+ automatically picks `ALMA_SB_API_KEY` for `'SANDBOX'` and `ALMA_PROD_API_KEY`
187
+ for `'PRODUCTION'`.
188
+
189
+ ## Error Handling
190
+
191
+ ```python
192
+ from almaapitk import AlmaAPIClient, AlmaAPIError, AlmaValidationError
193
+
194
+ client = AlmaAPIClient('SANDBOX')
195
+
196
+ try:
197
+ response = client.get('almaws/v1/users/invalid-user')
198
+ except AlmaValidationError as e:
199
+ # Input validation failed
200
+ print(f"Validation error: {e}")
201
+ except AlmaAPIError as e:
202
+ # API returned an error
203
+ print(f"API error: {e}")
204
+ print(f"Status code: {e.status_code}")
205
+ print(f"Response: {e.response}")
206
+ ```
207
+
208
+ ## Requirements
209
+
210
+ - Python 3.12+
211
+ - requests
212
+ - pandas
213
+ - openpyxl
214
+ - boto3
215
+ - pypdf2
216
+ - pyyaml
217
+ - beautifulsoup4
218
+ - lxml
219
+
220
+ ## License
221
+
222
+ MIT License - see [LICENSE](LICENSE) for details.
223
+
224
+ ## Contributing
225
+
226
+ Contributions are welcome! Please feel free to submit a Pull Request.
227
+
228
+ ## Links
229
+
230
+ - [Alma API Documentation](https://developers.exlibrisgroup.com/alma/apis/)
231
+ - [GitHub Repository](https://github.com/hagaybar/AlmaAPITK)
@@ -0,0 +1,38 @@
1
+ # almaapitk 0.3.1
2
+
3
+ **Release date:** 2026-04-27
4
+
5
+ First publish of `almaapitk` to PyPI.
6
+
7
+ > **Note:** 0.3.0 was uploaded to TestPyPI during pre-publish verification but
8
+ > never released — README content corrections caught during the TestPyPI gate
9
+ > required a version bump to 0.3.1. There is no 0.3.0 release on PyPI.
10
+
11
+ ## What's new since 0.2.0 (built locally on 2026-03-16, never published)
12
+
13
+ - **`Analytics` domain class.** Supports Alma Analytics reports via `get_report_headers()` and `fetch_report_rows()` with built-in pagination. Note: Alma Analytics is backed by a single shared database accessible only via PRODUCTION credentials; SANDBOX has no analytics endpoint.
14
+ - **`progress_callback` hook on `Analytics.fetch_report_rows()`.** Invoked after each page so callers can display progress for long-running fetches.
15
+ - **Documentation moved out of the package.** Three internal docs files that previously lived in `src/almaapitk/alma_logging/` were moved to `docs/alma_logging/` so the published wheel contains zero non-Python content.
16
+ - **Audit-driven hardening.** `process_users_batch` now documents `max_workers` honestly as a no-op pending a future concurrency feature; all `requests` calls in `AlmaAPIClient` have a generous `timeout=300` to prevent indefinite hangs.
17
+
18
+ ## Public API
19
+
20
+ ```python
21
+ from almaapitk import (
22
+ AlmaAPIClient,
23
+ AlmaResponse,
24
+ AlmaAPIError, AlmaValidationError,
25
+ Admin, Users, BibliographicRecords, Acquisitions, ResourceSharing, Analytics,
26
+ TSVGenerator, CitationMetadataError,
27
+ )
28
+ ```
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ pip install almaapitk
34
+ ```
35
+
36
+ ## Repository
37
+
38
+ `https://github.com/hagaybar/AlmaAPITK`
@@ -0,0 +1,77 @@
1
+ [project]
2
+ name = "almaapitk"
3
+ version = "0.3.1"
4
+ description = "Python toolkit for the Ex Libris Alma ILS API"
5
+ authors = [
6
+ {name = "Hagay Bar", email = "hagaybar@gmail.com"}
7
+ ]
8
+ readme = "README.md"
9
+ license = {text = "MIT"}
10
+ requires-python = ">=3.12"
11
+ keywords = [
12
+ "alma",
13
+ "ils",
14
+ "library",
15
+ "api",
16
+ "ex-libris",
17
+ "acquisitions",
18
+ "cataloging",
19
+ "resource-sharing"
20
+ ]
21
+ classifiers = [
22
+ "Development Status :: 4 - Beta",
23
+ "Intended Audience :: Developers",
24
+ "Intended Audience :: Information Technology",
25
+ "License :: OSI Approved :: MIT License",
26
+ "Operating System :: OS Independent",
27
+ "Programming Language :: Python :: 3",
28
+ "Programming Language :: Python :: 3.12",
29
+ "Programming Language :: Python :: 3.13",
30
+ "Topic :: Software Development :: Libraries :: Python Modules",
31
+ "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
32
+ "Typing :: Typed"
33
+ ]
34
+ dependencies = [
35
+ "requests>=2.32.0,<3.0.0",
36
+ "pandas>=2.0.0,<3.0.0",
37
+ "openpyxl>=3.1.0,<4.0.0",
38
+ "boto3>=1.35.0,<2.0.0",
39
+ "pypdf2>=3.0.0,<4.0.0",
40
+ "pyyaml (>=6.0.3,<7.0.0)",
41
+ "beautifulsoup4 (>=4.14.3,<5.0.0)",
42
+ "lxml (>=6.0.2,<7.0.0)"
43
+ ]
44
+
45
+ [project.urls]
46
+ Homepage = "https://github.com/hagaybar/AlmaAPITK"
47
+ Repository = "https://github.com/hagaybar/AlmaAPITK"
48
+ Documentation = "https://github.com/hagaybar/AlmaAPITK#readme"
49
+ Issues = "https://github.com/hagaybar/AlmaAPITK/issues"
50
+
51
+ [tool.poetry]
52
+ packages = [{ include = "almaapitk", from = "src" }]
53
+ include = [
54
+ { path = "README.md", format = "sdist" },
55
+ { path = "LICENSE", format = "sdist" },
56
+ { path = "docs/releases/0.3.1.md", format = "sdist" },
57
+ ]
58
+ exclude = [
59
+ "tests/**",
60
+ "scripts/**",
61
+ "docs/**",
62
+ "logs/**",
63
+ "backups/**",
64
+ ".a5c/**",
65
+ "config/**",
66
+ "AGENTS.md",
67
+ "CLAUDE.md",
68
+ "CLAUDE_tmp.html",
69
+ "ALMA_DIGITAL_DOCUMENTATION_EVALUATION.md",
70
+ ]
71
+
72
+ [tool.poetry.group.dev.dependencies]
73
+ pytest = "^8.0.0"
74
+
75
+ [build-system]
76
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
77
+ build-backend = "poetry.core.masonry.api"