Skip to content

Commit 7b9a5ea

Browse files
authored
Merge pull request #34 from stevenhua0320/load-image-fix
Fix: fix loadimage function to robustly load image
2 parents f789f24 + c8b83e5 commit 7b9a5ea

File tree

6 files changed

+142
-34
lines changed

6 files changed

+142
-34
lines changed
File renamed without changes.

news/load-image-fix.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
**Added:**
2+
3+
* <news item>
4+
5+
**Changed:**
6+
7+
* <news item>
8+
9+
**Deprecated:**
10+
11+
* <news item>
12+
13+
**Removed:**
14+
15+
* <news item>
16+
17+
**Fixed:**
18+
19+
* `load_image()` function correctly finds files when passed a relative path.
20+
21+
**Security:**
22+
23+
* <news item>

src/diffpy/srxplanar/loadimage.py

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import fnmatch
1717
import os
1818
import time
19+
from pathlib import Path
1920

2021
import numpy as np
2122

@@ -24,14 +25,14 @@
2425
try:
2526
import fabio
2627

27-
def openImage(im):
28+
def open_image(im):
2829
rv = fabio.openimage.openimage(im)
2930
return rv.data
3031

3132
except ImportError:
3233
import tifffile
3334

34-
def openImage(im):
35+
def open_image(im):
3536
rv = tifffile.imread(im)
3637
return rv
3738

@@ -53,7 +54,7 @@ def __init__(self, p):
5354
self.config = p
5455
return
5556

56-
def flipImage(self, pic):
57+
def flip_image(self, pic):
5758
"""Flip image if configured in config.
5859
5960
:param pic: 2d array, image array
@@ -65,32 +66,41 @@ def flipImage(self, pic):
6566
pic = np.array(pic[::-1, :])
6667
return pic
6768

68-
def loadImage(self, filename):
69-
"""Load image file, if failed (for example loading an incomplete
70-
file), then it will keep trying loading file for 5s.
69+
def load_image(self, filename):
70+
"""Load image file. If loading fails (e.g. incomplete file),
71+
retry for 5 seconds (10×0.5s).
7172
72-
:param filename: str, image file name
73-
:return: 2d ndarray, 2d image array (flipped)
73+
:param filename: str or Path, image file name or path
74+
:return: 2D ndarray, flipped image array
7475
"""
75-
if os.path.exists(filename):
76+
filename = Path(
77+
filename
78+
).expanduser() # handle "~", make it a Path object
79+
if filename.exists():
7680
filenamefull = filename
7781
else:
78-
filenamefull = os.path.join(self.opendirectory, filename)
79-
image = np.zeros(10000).reshape(100, 100)
80-
if os.path.exists(filenamefull):
81-
i = 0
82-
while i < 10:
83-
try:
84-
if os.path.splitext(filenamefull)[-1] == ".npy":
85-
image = np.load(filenamefull)
86-
else:
87-
image = openImage(filenamefull)
88-
i = 10
89-
except FileNotFoundError:
90-
i = i + 1
91-
time.sleep(0.5)
92-
image = self.flipImage(image)
93-
image[image < 0] = 0
82+
found_files = list(Path.home().rglob(filename.name))
83+
filenamefull = found_files[0] if found_files else None
84+
85+
if filenamefull is None or not filenamefull.exists():
86+
raise FileNotFoundError(
87+
f"Error: file not found: {filename}, "
88+
f"Please rerun specifying a valid filename."
89+
)
90+
return np.zeros((100, 100))
91+
92+
image = np.zeros((100, 100))
93+
for _ in range(10): # retry 10 times (5 seconds total)
94+
try:
95+
if filenamefull.suffix == ".npy":
96+
image = np.load(filenamefull)
97+
else:
98+
image = open_image(filenamefull)
99+
break
100+
except FileNotFoundError:
101+
time.sleep(0.5)
102+
image = self.flip_image(image)
103+
image[image < 0] = 0
94104
return image
95105

96106
def genFileList(

src/diffpy/srxplanar/srxplanar.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ def _getPic(self, image, flip=None, correction=None):
155155
rv += self._getPic(imagefile)
156156
rv /= len(image)
157157
elif isinstance(image, str):
158-
rv = self.loadimage.loadImage(image)
158+
rv = self.loadimage.load_image(image)
159159
if correction is None or correction is True:
160160
ce = self.config.cropedges
161161
rv[ce[2] : -ce[3], ce[0] : -ce[1]] = (
@@ -165,7 +165,7 @@ def _getPic(self, image, flip=None, correction=None):
165165
else:
166166
rv = image
167167
if flip is True:
168-
rv = self.loadimage.flipImage(rv)
168+
rv = self.loadimage.flip_image(rv)
169169
if correction is True:
170170
# rv *= self.correction
171171
ce = self.config.cropedges
@@ -339,13 +339,13 @@ def createMask(self, filename=None, pic=None, addmask=None):
339339
pic = self.pic
340340
else:
341341
pic = (
342-
self.loadimage.loadImage(filelist[0])
342+
self.loadimage.load_image(filelist[0])
343343
if len(filelist) > 0
344344
else None
345345
)
346346
else:
347347
pic = (
348-
self.loadimage.loadImage(filelist[0])
348+
self.loadimage.load_image(filelist[0])
349349
if len(filelist) > 0
350350
else None
351351
)

tests/conftest.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,22 @@
77
@pytest.fixture
88
def user_filesystem(tmp_path):
99
base_dir = Path(tmp_path)
10-
home_dir = base_dir / "home_dir"
11-
home_dir.mkdir(parents=True, exist_ok=True)
1210
cwd_dir = base_dir / "cwd_dir"
13-
cwd_dir.mkdir(parents=True, exist_ok=True)
11+
home_dir = base_dir / "home_dir"
12+
test_dir = base_dir / "test_dir"
13+
for dir in (cwd_dir, home_dir, test_dir):
14+
dir.mkdir(parents=True, exist_ok=True)
1415

15-
home_config_data = {"username": "home_username", "email": "home@email.com"}
16+
home_config_data = {
17+
"username": "home_username",
18+
"email": "home@email.com",
19+
}
1620
with open(home_dir / "diffpyconfig.json", "w") as f:
1721
json.dump(home_config_data, f)
1822

19-
yield tmp_path
23+
yield {
24+
"base": base_dir,
25+
"cwd": cwd_dir,
26+
"home": home_dir,
27+
"test": test_dir,
28+
}

tests/test_load_image.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import os
2+
import shutil
3+
from pathlib import Path
4+
from types import SimpleNamespace
5+
6+
import pytest
7+
8+
from diffpy.srxplanar.loadimage import LoadImage
9+
10+
PROJECT_ROOT = Path(__file__).resolve().parents[1]
11+
12+
load_image_param = [
13+
# case 1: just filename of file in current directory.
14+
# expect function loads tiff file from cwd
15+
(["KFe2As2-00838.tif", False, False], [0, 26, 173]),
16+
# case 2: absolute file path to file in another directory.
17+
# expect file is found and correctly read.
18+
(
19+
["home_dir/KFe2As2-00838.tif", True, False],
20+
[102, 57, 136],
21+
),
22+
# case 3: relative file path to file in another directory.
23+
# expect file is found and correctly read
24+
(["./KFe2As2-00838.tif", False, True], [39, 7, 0]),
25+
# case 4: non-existent file that incurred by mistype.
26+
(
27+
["nonexistent_file.tif", False, False],
28+
FileNotFoundError,
29+
),
30+
# case 5: relative file path to file in another directory.
31+
# expect file to be flip both horizontally and vertically
32+
# and correctly read
33+
(["./KFe2As2-00838.tif", True, True], [0, 53, 21]),
34+
]
35+
36+
37+
@pytest.mark.parametrize("inputs, expected", load_image_param)
38+
def test_load_image(inputs, expected, user_filesystem):
39+
home_dir = user_filesystem["home"]
40+
cwd_dir = user_filesystem["cwd"]
41+
os.chdir(cwd_dir)
42+
43+
expected_mean = 2595.7087
44+
expected_shape = (2048, 2048)
45+
46+
# locate source example file inside project docs
47+
source_file = (
48+
PROJECT_ROOT / "docs" / "examples" / "data" / "KFe2As2-00838.tif"
49+
)
50+
shutil.copy(source_file, cwd_dir / "KFe2As2-00838.tif")
51+
shutil.copy(source_file, home_dir / "KFe2As2-00838.tif")
52+
config = SimpleNamespace(fliphorizontal=inputs[1], flipvertical=inputs[2])
53+
try:
54+
loader = LoadImage(config)
55+
actual = loader.load_image(inputs[0])
56+
assert actual.shape == expected_shape
57+
assert actual.mean() == expected_mean
58+
assert actual[1][0] == expected[0]
59+
assert actual[1][1] == expected[1]
60+
assert actual[2][5] == expected[2]
61+
except FileNotFoundError:
62+
pytest.raises(
63+
FileNotFoundError,
64+
match=r"file not found:"
65+
r" .*Please rerun specifying a valid filename\.",
66+
)

0 commit comments

Comments
 (0)