Skip to content

Commit 2e40243

Browse files
authored
Merge pull request #106 from ComplexData-MILA/94-bug-add-update-member
bug fix
2 parents 9c66a46 + 902da0c commit 2e40243

2 files changed

Lines changed: 79 additions & 9 deletions

File tree

src/python/__init__.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
from pathlib import Path
33
import re
4+
from urllib.error import HTTPError, URLError
45
from urllib.request import urlopen, urlretrieve
56
from collections import OrderedDict
67

@@ -50,15 +51,24 @@ def parse_issue_body(body):
5051

5152
def find_urls(text):
5253
"""
53-
1. Find all urls using regex: https://stackoverflow.com/a/840110/13837091
54-
2. Remove the trailing ")"
55-
3. Get unique URLs only (set comprehension -> list)
54+
Find URLs in markdown links/images, HTML tags, and plain text.
55+
Return unique URLs while preserving order.
5656
"""
57-
return list(
58-
OrderedDict.fromkeys(
59-
[s for s in re.findall("(?P<url>https?://[^\s)]+)", text)]
60-
)
61-
)
57+
if not text:
58+
return []
59+
60+
patterns = [
61+
r"\((https?://[^\s)]+)\)",
62+
r"(?:src|href)=[\"'](https?://[^\"']+)[\"']",
63+
r"https?://[^\s<>)\"']+",
64+
]
65+
66+
urls = []
67+
for pattern in patterns:
68+
urls.extend(re.findall(pattern, text))
69+
70+
cleaned_urls = [url.rstrip('.,;:!?"\'') for url in urls]
71+
return list(OrderedDict.fromkeys(cleaned_urls))
6272

6373
def get_non_alpha(text):
6474
for ch in text:
@@ -125,7 +135,11 @@ def save_url_image(
125135
file_path = image_dir / f"{fname}"
126136

127137
image_dir.mkdir(parents=True, exist_ok=True)
128-
urlretrieve(url, str(file_path))
138+
try:
139+
urlretrieve(url, str(file_path))
140+
except (HTTPError, URLError, ValueError) as e:
141+
print(f"Could not download {url} due to error: {e}")
142+
continue
129143

130144
if ext in ["svg", "gif"]:
131145
return "/" + str(file_path)

tests/test_add_update_member.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
import os
44
import shutil
55
from pathlib import Path
6+
from urllib.error import HTTPError
7+
from unittest.mock import patch
68
from ruamel.yaml import YAML
79

810
import src.python.add_update_member as mod
11+
import src.python as core
912

1013

1114
class TestAddUpdateMember(unittest.TestCase):
@@ -73,5 +76,58 @@ def test_update_member(self):
7376

7477
self.assertEqual(output, expected, error_message)
7578

79+
def test_find_urls_handles_markdown_html_and_plain_text(self):
80+
text = (
81+
'![avatar](https://example.com/image.png) '
82+
'<img src="https://bucket.example.com/photos/profile.jpg?download=1"> '
83+
'https://plain.example.org/pic.webp'
84+
)
85+
86+
urls = core.find_urls(text)
87+
88+
self.assertEqual(
89+
urls,
90+
[
91+
"https://example.com/image.png",
92+
"https://bucket.example.com/photos/profile.jpg?download=1",
93+
"https://plain.example.org/pic.webp",
94+
],
95+
)
96+
97+
@patch("src.python.Image.open")
98+
@patch("src.python.urlretrieve")
99+
def test_save_url_image_skips_failed_downloads(self, mock_urlretrieve, mock_image_open):
100+
class DummyImage:
101+
def thumbnail(self, *_):
102+
return None
103+
104+
def save(self, *_args, **_kwargs):
105+
return None
106+
107+
mock_image_open.return_value = DummyImage()
108+
mock_urlretrieve.side_effect = [
109+
HTTPError("https://example.com/missing.jpg", 404, "Not Found", None, None),
110+
None,
111+
]
112+
113+
profile = {
114+
"avatar": (
115+
"![bad](https://example.com/missing.jpg) "
116+
"![ok](https://example.com/found.png)"
117+
)
118+
}
119+
120+
saved_path = core.save_url_image(
121+
fname="john-doe",
122+
profile=profile,
123+
key="avatar",
124+
image_dir="tests/scratch/assets/images/bio/",
125+
crop_center=False,
126+
size=(300, 300),
127+
)
128+
129+
self.assertEqual(saved_path, "/tests/scratch/assets/images/bio/john-doe.png")
130+
self.assertEqual(mock_urlretrieve.call_count, 2)
131+
76132

77133

0 commit comments

Comments
 (0)