Skip to content

Commit 171079c

Browse files
authored
Merge pull request #816 from flairNLP/fix-duplication-error
Fix `bidict.ValueDuplicationError`
2 parents 0b42c07 + 3faf26f commit 171079c

File tree

3 files changed

+105
-2
lines changed

3 files changed

+105
-2
lines changed

src/fundus/scraping/crawler.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ def callback() -> None:
404404
break
405405
finally:
406406
session_handler.close_current_session()
407+
__EVENTS__.reset()
407408
if save_to_file is not None:
408409
if isinstance(save_to_file, str):
409410
save_to_file = Path(save_to_file)

src/fundus/utils/events.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
import threading
23
from collections import defaultdict
34
from typing import Dict, List, Optional, Union
@@ -84,7 +85,8 @@ def __init__(self, default_events: Optional[List[str]] = None):
8485
default_events: A list of event names that are automatically available
8586
for all threads (e.g., ["stop"]).
8687
"""
87-
self._events: Dict[int, ThreadEventDict] = defaultdict(lambda: ThreadEventDict(default_events))
88+
self.default_events = default_events
89+
self._events: Dict[int, ThreadEventDict] = defaultdict(lambda: ThreadEventDict(self.default_events))
8890
self._aliases: bidict[str, int] = bidict()
8991
self._lock = threading.RLock()
9092

@@ -163,7 +165,7 @@ def register_event(self, event: str, key: Union[int, str, None] = None):
163165
with self._lock:
164166
if isinstance(key, str) and key not in self._aliases:
165167
self._alias(key)
166-
if (resolved := self._resolve(key)) not in self._events:
168+
if event not in self._events[(resolved := self._resolve(key))]:
167169
self._events[resolved][event] = threading.Event()
168170
logger.debug(f"Registered event {event!r} for {self._pretty_resolve(key)}")
169171

@@ -287,5 +289,19 @@ def get(self, event: str, key: Optional[Union[int, str, None]] = None) -> thread
287289
with self._lock:
288290
return self._events[self._resolve(key)][event]
289291

292+
def reset(self):
293+
with self._lock:
294+
self._events = defaultdict(lambda: ThreadEventDict(self.default_events))
295+
self._aliases = bidict()
296+
297+
def __str__(self):
298+
def _entry(thread: int) -> str:
299+
alias = self._aliases.inv.get(thread, None)
300+
serialized = json.dumps(self._events[thread], indent=2, ensure_ascii=False, default=lambda o: o.set())
301+
return f"{alias if alias else 'None'} --> {thread}: \n" + serialized
302+
303+
events = [_entry(ident) for ident in self._events]
304+
return "\n".join(events) if events else "Empty Event Dictionary"
305+
290306

291307
__EVENTS__: EventDict = EventDict(default_events=__DEFAULT_EVENTS__)

tests/resources/test_events.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import bidict
2+
import pytest
3+
4+
from fundus.utils.events import EventDict
5+
6+
7+
class TestEvents:
8+
def test_default_events(self):
9+
events = EventDict(default_events=["success"])
10+
11+
events.get("success")
12+
13+
with pytest.raises(KeyError):
14+
events.get("failure")
15+
16+
def test_set_clear(self):
17+
events = EventDict(default_events=["success"])
18+
19+
events.set_event("success")
20+
21+
assert events.is_event_set("success")
22+
23+
events.clear_event("success")
24+
25+
assert events.is_event_set("success") == False
26+
27+
def test_set_clear_all(self):
28+
events = EventDict()
29+
30+
events.register_event("success", 1)
31+
events.register_event("success", 2)
32+
33+
events.set_for_all("success")
34+
35+
assert events.is_event_set("success", 1) == events.is_event_set("success", 2) == True
36+
37+
events.clear_for_all("success")
38+
39+
assert events.is_event_set("success", 1) == events.is_event_set("success", 2) == False
40+
41+
events.register_event("failure", 1)
42+
events.register_event("failure", 2)
43+
44+
events.set_for_all()
45+
46+
assert events.is_event_set("success", 1) == events.is_event_set("success", 2) == True
47+
assert events.is_event_set("failure", 1) == events.is_event_set("failure", 2) == True
48+
49+
events.clear_for_all()
50+
51+
assert events.is_event_set("success", 1) == events.is_event_set("success", 2) == False
52+
assert events.is_event_set("failure", 1) == events.is_event_set("failure", 2) == False
53+
54+
def test_alias(self):
55+
events = EventDict(default_events=["success"])
56+
57+
events.alias("main-thread")
58+
59+
events.set_event("success", "main-thread")
60+
61+
assert events.is_event_set("success", "main-thread") == True
62+
63+
def test_set_all_with_alias(self):
64+
events = EventDict(default_events=["success"])
65+
66+
events.alias("main-thread")
67+
68+
events.set_for_all("success")
69+
70+
assert events.is_event_set("success", "main-thread") == True
71+
72+
events.clear_for_all("success")
73+
74+
assert events.is_event_set("success", "main-thread") == False
75+
76+
def test_duplicate(self):
77+
events = EventDict(default_events=["success"])
78+
79+
events.alias("main-thread", 1)
80+
81+
with pytest.raises(bidict.ValueDuplicationError):
82+
events.alias("new-thread", 1)
83+
84+
events.alias("main-thread", 2)
85+
86+
events.alias("new-thread", 1)

0 commit comments

Comments
 (0)