Skip to content

Commit ea58d83

Browse files
authored
Accept filename and relative path as well as absolute path (#758)
2 parents 2c0eb37 + b56c63b commit ea58d83

2 files changed

Lines changed: 40 additions & 24 deletions

File tree

scopesim/tests/test_utils_functions.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
"""Unit tests for module scopesim.utils"""
22

3+
from unittest.mock import patch
4+
from pathlib import Path
5+
36
import pytest
47
from pytest import approx
5-
from unittest.mock import patch
68

79
import numpy as np
810
from astropy import wcs
@@ -15,6 +17,16 @@
1517
from scopesim import load_example_optical_train, OpticalTrain
1618
from scopesim.utils import from_currsys
1719

20+
# pylint: disable=missing-function-docstring, missing-class-docstring
21+
22+
23+
@pytest.fixture(name="temp_file")
24+
def fixture_temp_file():
25+
filename = "th1s_is_an_impossibly_named-temporaaree_fi1111e.dingens"
26+
Path(filename).touch()
27+
yield filename
28+
Path(filename).unlink()
29+
1830

1931
class TestFindFile:
2032
"""Tests of function scopesim.utils.find_file"""
@@ -25,7 +37,10 @@ def test_fails_if_filename_not_a_string(self):
2537
with pytest.raises((TypeError, AttributeError)):
2638
utils.find_file(1.2, rc.__search_path__)
2739

28-
def test_passes_if_file_exists(self):
40+
def test_passes_if_file_exists_in_cwd(self, temp_file):
41+
assert utils.find_file(temp_file, [])
42+
43+
def test_passes_if_file_exists_in_search_path(self):
2944
filename = "utils.py"
3045
assert utils.find_file(filename, rc.__search_path__)
3146

@@ -35,7 +50,7 @@ def test_throws_error_if_file_doesnt_exist(self, throw_error):
3550
with patch.dict("scopesim.rc.__currsys__", patched):
3651
filename = "utils987654.pz"
3752
if throw_error:
38-
with pytest.raises(ValueError):
53+
with pytest.raises(FileNotFoundError):
3954
utils.find_file(filename, rc.__search_path__)
4055
else:
4156
assert utils.find_file(filename, rc.__search_path__) is None

scopesim/utils.py

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -229,51 +229,54 @@ def log_bug_report(level=logging.DEBUG) -> None:
229229
bug_logger.log(level, str_stream.getvalue())
230230

231231

232-
def find_file(filename, path=None, silent=False):
232+
def find_file(
233+
filename: str,
234+
path: Iterable[Path | str] | None = None,
235+
silent: bool = False,
236+
) -> str | None:
233237
"""Find a file in search path.
234238
239+
First check whether `filename` exists as (relative) path. In
240+
particular, this finds files that are present in the user's current
241+
working directory. If `filename` is not found in this way it is looked
242+
for in the search path, `rc.__search_path__`.
243+
235244
Parameters
236245
----------
237246
filename : str
238247
name of a file to look for
239248
path : list
240-
list of directories to search (default: ['./'])
249+
list of directories to search (default: `rc.__search_path__`)
241250
silent : bool
242251
if True, remain silent when file is not found
243252
244253
Returns
245254
-------
246-
Absolute path of the file
255+
Absolute path of the file (str) or None
247256
"""
248257
if filename is None or filename.lower() == "none":
249258
return None
250259

251260
if filename.startswith("!"):
252-
raise ValueError(f"!-string filename should be resolved upstream: "
261+
raise ValueError("!-string filename should be resolved upstream: "
253262
f"{filename}")
254-
# filename = from_currsys(filename)
263+
255264
# Turn into pathlib.Path object for better manipulation afterwards
256265
filename = Path(filename)
257266

267+
if filename.exists():
268+
# file exists; assume user wants to override search path
269+
return str(filename)
270+
258271
if path is None:
259272
path = rc.__search_path__
260273

261-
if filename.is_absolute():
262-
# absolute path: only path to try
263-
trynames = [filename]
264-
else:
265-
# try to find the file in a search path
266-
trynames = [Path(trydir, filename)
267-
for trydir in path if trydir is not None]
274+
# try to find the file in a search path
275+
trynames = [Path(trydir, filename)
276+
for trydir in path if trydir is not None]
268277

269278
for fname in trynames:
270279
if fname.exists(): # success
271-
# strip leading ./
272-
# Path should take care of this automatically!
273-
# while fname[:2] == './':
274-
# fname = fname[2:]
275-
# Nevertheless, make sure this is actually the case...
276-
assert not str(fname).startswith("./")
277280
# HACK: Turn Path object back into string, because not everything
278281
# that depends on this function can handle Path objects (yet)
279282
return str(fname)
@@ -282,10 +285,8 @@ def find_file(filename, path=None, silent=False):
282285
msg = f"File cannot be found: {filename}"
283286
if not silent:
284287
logger.error(msg)
285-
286-
# TODO: Not sure what to do here
287288
if from_currsys("!SIM.file.error_on_missing_file"):
288-
raise ValueError(msg)
289+
raise FileNotFoundError(msg)
289290

290291
return None
291292

0 commit comments

Comments
 (0)