Coverage for src/evutils/_checker.py: 77%

30 statements  

« prev     ^ index     » next       coverage.py v7.15.1, created at 2026-07-18 05:24 +0000

1"""Module providing utilities to check the validity of event arrays.""" 

2 

3import numpy as np 

4from .types import EventArray 

5 

6class EventsChecker(): 

7 """Class to check if events are valid. 

8  

9 Parameters 

10 ---------- 

11 events : np.ndarray 

12 Array of events to check. 

13 

14 """ 

15 

16 def __init__(self, events: 'np.ndarray | EventArray'): 

17 from .types import Event_dtype, SoaArray 

18 if isinstance(events, SoaArray): 

19 if events._aos_dtype != Event_dtype: 

20 raise ValueError("events must be of type Events") 

21 else: 

22 if not hasattr(events, 'dtype'): 

23 raise TypeError("events must be a NumPy array or SoaArray") 

24 if events.dtype != Event_dtype: 

25 raise ValueError("events must be of type Events") 

26 

27 self.events = events 

28 

29 def is_sorted(self) -> bool: 

30 """Check if events are sorted by timestamp. 

31  

32 Returns 

33 ------- 

34 bool 

35 True if events are sorted in non-decreasing order of timestamps. 

36 

37 """ 

38 return bool(np.all(np.diff(self.events['t']) >= 0)) 

39 

40 def has_valid_polarity(self) -> bool: 

41 """Check if events have valid polarity (0 or 1). 

42  

43 Returns 

44 ------- 

45 bool 

46 True if all events have polarity 0 or 1. 

47 

48 """ 

49 return bool(np.all((self.events['p'] <= 1) & (self.events['p'] >= 0))) 

50 

51 def has_valid_x(self, width: int) -> bool: 

52 """Check if events have valid x coordinates. 

53  

54 Parameters 

55 ---------- 

56 width : int 

57 Maximum valid width (exclusive). 

58  

59 Returns 

60 ------- 

61 bool 

62 True if all events have x coordinates in [0, width). 

63 

64 """ 

65 return bool(np.all((self.events['x'] >= 0) & (self.events['x'] < width))) 

66 

67 def has_valid_y(self, height: int) -> bool: 

68 """Check if events have valid y coordinates. 

69  

70 Parameters 

71 ---------- 

72 height : int 

73 Maximum valid height (exclusive). 

74  

75 Returns 

76 ------- 

77 bool 

78 True if all events have y coordinates in [0, height). 

79 

80 """ 

81 return bool(np.all((self.events['y'] >= 0) & (self.events['y'] < height))) 

82 

83 def is_valid(self, width: int | None = None, height: int | None = None) -> bool: 

84 """Check if all events are valid (sorted, valid polarity, and valid coordinates). 

85  

86 Parameters 

87 ---------- 

88 width : int, optional 

89 Maximum valid width. If None, x coordinates are not checked. 

90 height : int, optional 

91 Maximum valid height. If None, y coordinates are not checked. 

92  

93 Returns 

94 ------- 

95 bool 

96 True if all checks pass. 

97 

98 """ 

99 valid = self.is_sorted() and self.has_valid_polarity() 

100 if width is not None: 

101 valid = valid and self.has_valid_x(width) 

102 if height is not None: 

103 valid = valid and self.has_valid_y(height) 

104 return valid 

105 

106 def __repr__(self) -> str: 

107 """Return string representation of the EventsChecker. 

108  

109 Returns 

110 ------- 

111 str 

112 String representation indicating the EventsChecker and number of events. 

113 

114 """ 

115 return f"EventsChecker(events={len(self.events)})"