Skip to content

Commit 2e7a641

Browse files
committed
remove default storage from init
- supports AP-677 - see justification comment https://ucblib.atlassian.net/browse/AP-677?focusedCommentId=410330
1 parent 6757e7b commit 2e7a641

5 files changed

Lines changed: 31 additions & 27 deletions

File tree

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased - proposed 1.0.0?]
9+
10+
### Added
11+
- `output_dir` parameter to `write_search_results_to_file`, defaulting to `./tmp`
12+
- `fetch_file` now defaults `output_dir` to `./tmp` when not supplied
13+
14+
### Removed
15+
- **BREAKING**: `default_storage_dir` constructor parameter removed from `TINDClient`; pass `output_dir` directly to `fetch_file` and `write_search_results_to_file` instead
16+
817
## [0.2.2]
918

1019
### Changed

README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ Create a `TINDClient` with optional configuration values:
2727

2828
- `api_key` (optional): Your TIND API token. Falls back to the `TIND_API_KEY` environment variable.
2929
- `api_url` (optional): Base URL of the TIND instance (e.g. `https://tind.example.edu`). Falls back to the `TIND_API_URL` environment variable.
30-
- `default_storage_dir` (optional): Default output directory for downloaded files. Defaults to `./tmp`.
3130

3231
## Usage
3332

@@ -43,7 +42,6 @@ from tind_client import TINDClient
4342
client = TINDClient(
4443
api_key="your-token",
4544
api_url="https://tind.example.edu",
46-
default_storage_dir="/tmp",
4745
)
4846
```
4947

@@ -79,8 +77,8 @@ records = client.fetch_search_metadata("collection:'Disabled Students Program Ph
7977
xml_results = client.search("collection:'Disabled Students Program Photos'", result_format="xml")
8078
pymarc_results = client.search("collection:'Disabled Students Program Photos'", result_format="pymarc")
8179

82-
# search Tind with a query and write results to an XML file in the default storage directory
83-
records_written = client.write_search_results_to_file("Old Emperor Norton", "full_norton_results.xml")
80+
# search Tind with a query and write results to an XML file
81+
records_written = client.write_search_results_to_file("Old Emperor Norton", "full_norton_results.xml", output_dir="/data")
8482
```
8583

8684
## Running tests

tests/conftest.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ def tind_env(monkeypatch: pytest.MonkeyPatch) -> None:
2424
"""Set required TIND environment variables for a test."""
2525
monkeypatch.setenv("TIND_API_KEY", "test-api-key")
2626
monkeypatch.setenv("TIND_API_URL", "https://tind.example.edu")
27-
monkeypatch.setenv("DEFAULT_STORAGE_DIR", "/tmp")
2827

2928

3029
@pytest.fixture
@@ -39,5 +38,4 @@ def client() -> TINDClient:
3938
return TINDClient(
4039
api_key="test-api-key",
4140
api_url="https://tind.example.edu",
42-
default_storage_dir="/tmp",
4341
)

tests/test_fetch.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,12 @@ def test_write_search_results_to_file_zero_hits(
186186
tmp_path: Path,
187187
) -> None:
188188
"""write_search_results_to_file returns 0 immediately when the query has no hits."""
189-
client.default_storage_dir = str(tmp_path)
190189
requests_mock.get(
191190
f"{BASE_URL}/search",
192191
text=json.dumps({"hits": []}),
193192
status_code=200,
194193
)
195-
assert client.write_search_results_to_file("collection:'empty'") == 0
194+
assert client.write_search_results_to_file("collection:'empty'", output_dir=str(tmp_path)) == 0
196195
assert not (tmp_path / "tind.xml").exists()
197196

198197

@@ -202,7 +201,6 @@ def test_write_search_results_to_file_success(
202201
tmp_path: Path,
203202
) -> None:
204203
"""write_search_results_to_file writes 3 records and returns 3."""
205-
client.default_storage_dir = str(tmp_path)
206204
requests_mock.get(
207205
f"{BASE_URL}/search",
208206
response_list=[
@@ -214,7 +212,9 @@ def test_write_search_results_to_file_success(
214212
{"text": (FIXTURES / "end-of-batch-tind-response.xml").read_text(), "status_code": 200},
215213
],
216214
)
217-
count = client.write_search_results_to_file("collection:'test'", "out.xml")
215+
count = client.write_search_results_to_file(
216+
"collection:'test'", "out.xml", output_dir=str(tmp_path)
217+
)
218218
assert count == 3
219219

220220
marc21_ns = "http://www.loc.gov/MARC21/slim"
@@ -233,7 +233,6 @@ def test_write_search_results_to_file_matched_but_no_records_returned(
233233
tmp_path: Path,
234234
) -> None:
235235
"""write_search_results_to_file raises TINDError when API returns no records for matched IDs"""
236-
client.default_storage_dir = str(tmp_path)
237236
requests_mock.get(
238237
f"{BASE_URL}/search",
239238
response_list=[
@@ -244,7 +243,9 @@ def test_write_search_results_to_file_matched_but_no_records_returned(
244243
],
245244
)
246245
with pytest.raises(TINDError, match="API did not return any."):
247-
client.write_search_results_to_file("collection:'test'", "mismatch.xml")
246+
client.write_search_results_to_file(
247+
"collection:'test'", "mismatch.xml", output_dir=str(tmp_path)
248+
)
248249

249250

250251
def test_write_search_results_to_file_matched_but_api_mismatch(
@@ -253,7 +254,6 @@ def test_write_search_results_to_file_matched_but_api_mismatch(
253254
tmp_path: Path,
254255
) -> None:
255256
"""write_search_results_to_file raises TINDError when streamed record count != ID count."""
256-
client.default_storage_dir = str(tmp_path)
257257
requests_mock.get(
258258
f"{BASE_URL}/search",
259259
response_list=[
@@ -269,7 +269,9 @@ def test_write_search_results_to_file_matched_but_api_mismatch(
269269
],
270270
)
271271
with pytest.raises(TINDError, match="Expected 4 records"):
272-
client.write_search_results_to_file("collection:'test'", "mismatch.xml")
272+
client.write_search_results_to_file(
273+
"collection:'test'", "mismatch.xml", output_dir=str(tmp_path)
274+
)
273275

274276

275277
def test_write_search_results_to_file_malformed_xml_response(
@@ -278,7 +280,6 @@ def test_write_search_results_to_file_malformed_xml_response(
278280
tmp_path: Path,
279281
) -> None:
280282
"""write_search_results_to_file raises TINDError when the API returns malformed XML."""
281-
client.default_storage_dir = str(tmp_path)
282283
requests_mock.get(
283284
f"{BASE_URL}/search",
284285
response_list=[
@@ -287,4 +288,6 @@ def test_write_search_results_to_file_malformed_xml_response(
287288
],
288289
)
289290
with pytest.raises(TINDError, match="Failed to parse"):
290-
client.write_search_results_to_file("collection:'test'", "malformed.xml")
291+
client.write_search_results_to_file(
292+
"collection:'test'", "malformed.xml", output_dir=str(tmp_path)
293+
)

tind_client/client.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,15 @@ class TINDClient:
2929
3030
:param str api_key: Your TIND API token.
3131
:param str api_url: Base URL of the TIND instance, e.g. ``https://tind.example.edu``.
32-
:param str default_storage_dir: Default directory used by :meth:`fetch_file`
33-
when no ``output_dir`` is supplied.
3432
"""
3533

3634
def __init__(
3735
self,
3836
api_key: str = "",
3937
api_url: str = "",
40-
default_storage_dir: str = "./tmp",
4138
) -> None:
4239
self.api_key = api_key or os.environ.get("TIND_API_KEY", "")
4340
self.api_url = api_url or os.environ.get("TIND_API_URL", "")
44-
self.default_storage_dir = default_storage_dir
4541

4642
def fetch_metadata(self, record: str) -> Record:
4743
"""Fetch the MARC XML metadata for a given record.
@@ -69,12 +65,12 @@ def fetch_metadata(self, record: str) -> Record:
6965

7066
return records[0]
7167

72-
def fetch_file(self, file_url: str, output_dir: str = "") -> str:
68+
def fetch_file(self, file_url: str, output_dir: str = "./tmp") -> str:
7369
"""Download a file from TIND and save it locally.
7470
7571
:param str file_url: The TIND file download URL.
7672
:param str output_dir: Directory in which to save the file.
77-
Falls back to ``default_storage_dir`` when empty.
73+
Defaults to ``./tmp``.
7874
:raises AuthorizationError: When the TIND API key is invalid or the file is restricted.
7975
:raises ValueError: When ``file_url`` is not a valid TIND file download URL.
8076
:raises RecordNotFoundError: When the file is invalid or not found.
@@ -83,8 +79,7 @@ def fetch_file(self, file_url: str, output_dir: str = "") -> str:
8379
if not re.match(r"^http.*/download(/)?(\?version=\d+)?$", file_url):
8480
raise ValueError("URL is not a valid TIND file download URL.")
8581

86-
output_target = output_dir or self.default_storage_dir
87-
(status, saved_to) = tind_download(file_url, output_dir=output_target, api_key=self.api_key)
82+
(status, saved_to) = tind_download(file_url, output_dir=output_dir, api_key=self.api_key)
8883

8984
if status != 200:
9085
raise RecordNotFoundError("Referenced file could not be downloaded.")
@@ -178,12 +173,13 @@ def search(self, query: str, result_format: str = "xml") -> list[Any]:
178173
return recs
179174

180175
def write_search_results_to_file(
181-
self, query: str = "", output_file_name: str = "tind.xml"
176+
self, query: str = "", output_file_name: str = "tind.xml", output_dir: str = "./tmp"
182177
) -> int:
183178
"""Search TIND and stream results to an XML file.
184179
185180
:param str query: A TIND search query string.
186181
:param str output_file_name: filename for the output XML file.
182+
:param str output_dir: Directory in which to save the file. Defaults to ``./tmp``.
187183
:returns int: The number of records written to the file.
188184
"""
189185

@@ -192,7 +188,7 @@ def write_search_results_to_file(
192188
return 0
193189

194190
recs_written = 0
195-
output_path = os.path.join(self.default_storage_dir, output_file_name)
191+
output_path = Path(output_dir) / output_file_name
196192
try:
197193
with open(output_path, "w", encoding="utf-8") as f:
198194
f.write(f'<?xml version="1.0" encoding="UTF-8"?>\n<collection xmlns="{NS}">\n')
@@ -206,7 +202,7 @@ def write_search_results_to_file(
206202
raise TINDError(f"Matched {total_hits} tind ids, but API did not return any.")
207203
f.write("</collection>\n")
208204
except Exception:
209-
Path(output_path).unlink(missing_ok=True)
205+
output_path.unlink(missing_ok=True)
210206
raise
211207

212208
if recs_written != total_hits:

0 commit comments

Comments
 (0)