ultralytics 8.3.4__py3-none-any.whl → 8.3.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ultralytics might be problematic. Click here for more details.

@@ -1,243 +1,131 @@
1
1
  # Ultralytics YOLO 🚀, AGPL-3.0 license
2
2
 
3
- from collections import defaultdict
3
+ from shapely.geometry import LineString, Point
4
4
 
5
- import cv2
6
-
7
- from ultralytics.utils.checks import check_imshow, check_requirements
5
+ from ultralytics.solutions.solutions import BaseSolution # Import a parent class
8
6
  from ultralytics.utils.plotting import Annotator, colors
9
7
 
10
- check_requirements("shapely>=2.0.0")
11
8
 
12
- from shapely.geometry import LineString, Point, Polygon
9
+ class ObjectCounter(BaseSolution):
10
+ """A class to manage the counting of objects in a real-time video stream based on their tracks."""
13
11
 
12
+ def __init__(self, **kwargs):
13
+ """Initialization function for Count class, a child class of BaseSolution class, can be used for counting the
14
+ objects.
15
+ """
16
+ super().__init__(**kwargs)
14
17
 
15
- class ObjectCounter:
16
- """A class to manage the counting of objects in a real-time video stream based on their tracks."""
18
+ self.in_count = 0 # Counter for objects moving inward
19
+ self.out_count = 0 # Counter for objects moving outward
20
+ self.counted_ids = [] # List of IDs of objects that have been counted
21
+ self.classwise_counts = {} # Dictionary for counts, categorized by object class
22
+ self.region_initialized = False # Bool variable for region initialization
17
23
 
18
- def __init__(
19
- self,
20
- names,
21
- reg_pts=None,
22
- line_thickness=2,
23
- view_img=False,
24
- view_in_counts=True,
25
- view_out_counts=True,
26
- draw_tracks=False,
27
- ):
24
+ self.show_in = self.CFG["show_in"]
25
+ self.show_out = self.CFG["show_out"]
26
+
27
+ def count_objects(self, track_line, box, track_id, prev_position, cls):
28
28
  """
29
- Initializes the ObjectCounter with various tracking and counting parameters.
29
+ Helper function to count objects within a polygonal region.
30
30
 
31
31
  Args:
32
- names (dict): Dictionary of class names.
33
- reg_pts (list): List of points defining the counting region.
34
- line_thickness (int): Line thickness for bounding boxes.
35
- view_img (bool): Flag to control whether to display the video stream.
36
- view_in_counts (bool): Flag to control whether to display the in counts on the video stream.
37
- view_out_counts (bool): Flag to control whether to display the out counts on the video stream.
38
- draw_tracks (bool): Flag to control whether to draw the object tracks.
32
+ track_line (dict): last 30 frame track record
33
+ box (list): Bounding box data for specific track in current frame
34
+ track_id (int): track ID of the object
35
+ prev_position (tuple): last frame position coordinates of the track
36
+ cls (int): Class index for classwise count updates
39
37
  """
40
- # Mouse events
41
- self.is_drawing = False
42
- self.selected_point = None
43
-
44
- # Region & Line Information
45
- self.reg_pts = [(20, 400), (1260, 400)] if reg_pts is None else reg_pts
46
- self.counting_region = None
47
-
48
- # Image and annotation Information
49
- self.im0 = None
50
- self.tf = line_thickness
51
- self.view_img = view_img
52
- self.view_in_counts = view_in_counts
53
- self.view_out_counts = view_out_counts
54
-
55
- self.names = names # Classes names
56
- self.window_name = "Ultralytics YOLOv8 Object Counter"
57
-
58
- # Object counting Information
59
- self.in_counts = 0
60
- self.out_counts = 0
61
- self.count_ids = []
62
- self.class_wise_count = {}
63
-
64
- # Tracks info
65
- self.track_history = defaultdict(list)
66
- self.draw_tracks = draw_tracks
67
-
68
- # Check if environment supports imshow
69
- self.env_check = check_imshow(warn=True)
70
-
71
- # Initialize counting region
72
- if len(self.reg_pts) == 2:
73
- print("Line Counter Initiated.")
74
- self.counting_region = LineString(self.reg_pts)
75
- elif len(self.reg_pts) >= 3:
76
- print("Polygon Counter Initiated.")
77
- self.counting_region = Polygon(self.reg_pts)
78
- else:
79
- print("Invalid Region points provided, region_points must be 2 for lines or >= 3 for polygons.")
80
- print("Using Line Counter Now")
81
- self.counting_region = LineString(self.reg_pts)
82
-
83
- # Define the counting line segment
84
- self.counting_line_segment = LineString(
85
- [
86
- (self.reg_pts[0][0], self.reg_pts[0][1]),
87
- (self.reg_pts[1][0], self.reg_pts[1][1]),
88
- ]
89
- )
90
-
91
- def mouse_event_for_region(self, event, x, y, flags, params):
38
+ if prev_position is None or track_id in self.counted_ids:
39
+ return
40
+
41
+ centroid = self.r_s.centroid
42
+ dx = (box[0] - prev_position[0]) * (centroid.x - prev_position[0])
43
+ dy = (box[1] - prev_position[1]) * (centroid.y - prev_position[1])
44
+
45
+ if len(self.region) >= 3 and self.r_s.contains(Point(track_line[-1])):
46
+ self.counted_ids.append(track_id)
47
+ # For polygon region
48
+ if dx > 0:
49
+ self.in_count += 1
50
+ self.classwise_counts[self.names[cls]]["IN"] += 1
51
+ else:
52
+ self.out_count += 1
53
+ self.classwise_counts[self.names[cls]]["OUT"] += 1
54
+
55
+ elif len(self.region) < 3 and LineString([prev_position, box[:2]]).intersects(self.l_s):
56
+ self.counted_ids.append(track_id)
57
+ # For linear region
58
+ if dx > 0 and dy > 0:
59
+ self.in_count += 1
60
+ self.classwise_counts[self.names[cls]]["IN"] += 1
61
+ else:
62
+ self.out_count += 1
63
+ self.classwise_counts[self.names[cls]]["OUT"] += 1
64
+
65
+ def store_classwise_counts(self, cls):
92
66
  """
93
- Handles mouse events for defining and moving the counting region in a real-time video stream.
67
+ Initialize class-wise counts if not already present.
94
68
 
95
69
  Args:
96
- event (int): The type of mouse event (e.g., cv2.EVENT_MOUSEMOVE, cv2.EVENT_LBUTTONDOWN, etc.).
97
- x (int): The x-coordinate of the mouse pointer.
98
- y (int): The y-coordinate of the mouse pointer.
99
- flags (int): Any associated event flags (e.g., cv2.EVENT_FLAG_CTRLKEY, cv2.EVENT_FLAG_SHIFTKEY, etc.).
100
- params (dict): Additional parameters for the function.
70
+ cls (int): Class index for classwise count updates
71
+ """
72
+ if self.names[cls] not in self.classwise_counts:
73
+ self.classwise_counts[self.names[cls]] = {"IN": 0, "OUT": 0}
74
+
75
+ def display_counts(self, im0):
101
76
  """
102
- if event == cv2.EVENT_LBUTTONDOWN:
103
- for i, point in enumerate(self.reg_pts):
104
- if (
105
- isinstance(point, (tuple, list))
106
- and len(point) >= 2
107
- and (abs(x - point[0]) < 10 and abs(y - point[1]) < 10)
108
- ):
109
- self.selected_point = i
110
- self.is_drawing = True
111
- break
112
-
113
- elif event == cv2.EVENT_MOUSEMOVE:
114
- if self.is_drawing and self.selected_point is not None:
115
- self.reg_pts[self.selected_point] = (x, y)
116
- self.counting_region = Polygon(self.reg_pts)
117
-
118
- elif event == cv2.EVENT_LBUTTONUP:
119
- self.is_drawing = False
120
- self.selected_point = None
121
-
122
- def extract_and_process_tracks(self, tracks):
123
- """Extracts and processes tracks for object counting in a video stream."""
124
- # Annotator Init and region drawing
125
- annotator = Annotator(self.im0, self.tf, self.names)
126
-
127
- # Draw region or line
128
- annotator.draw_region(reg_pts=self.reg_pts, color=(104, 0, 123), thickness=self.tf * 2)
129
-
130
- # Extract tracks for OBB or object detection
131
- track_data = tracks[0].obb or tracks[0].boxes
132
-
133
- if track_data and track_data.id is not None:
134
- boxes = track_data.xyxy.cpu()
135
- clss = track_data.cls.cpu().tolist()
136
- track_ids = track_data.id.int().cpu().tolist()
137
-
138
- # Extract tracks
139
- for box, track_id, cls in zip(boxes, track_ids, clss):
140
- # Draw bounding box
141
- annotator.box_label(box, label=self.names[cls], color=colors(int(track_id), True))
142
-
143
- # Store class info
144
- if self.names[cls] not in self.class_wise_count:
145
- self.class_wise_count[self.names[cls]] = {"IN": 0, "OUT": 0}
146
-
147
- # Draw Tracks
148
- track_line = self.track_history[track_id]
149
- track_line.append((float((box[0] + box[2]) / 2), float((box[1] + box[3]) / 2)))
150
- if len(track_line) > 30:
151
- track_line.pop(0)
152
-
153
- # Draw track trails
154
- if self.draw_tracks:
155
- annotator.draw_centroid_and_tracks(
156
- track_line,
157
- color=colors(int(track_id), True),
158
- track_thickness=self.tf,
159
- )
160
-
161
- prev_position = self.track_history[track_id][-2] if len(self.track_history[track_id]) > 1 else None
162
-
163
- # Count objects in any polygon
164
- if len(self.reg_pts) >= 3:
165
- is_inside = self.counting_region.contains(Point(track_line[-1]))
166
-
167
- if prev_position is not None and is_inside and track_id not in self.count_ids:
168
- self.count_ids.append(track_id)
169
-
170
- if (box[0] - prev_position[0]) * (self.counting_region.centroid.x - prev_position[0]) > 0:
171
- self.in_counts += 1
172
- self.class_wise_count[self.names[cls]]["IN"] += 1
173
- else:
174
- self.out_counts += 1
175
- self.class_wise_count[self.names[cls]]["OUT"] += 1
176
-
177
- # Count objects using line
178
- elif len(self.reg_pts) == 2:
179
- if (
180
- prev_position is not None
181
- and track_id not in self.count_ids
182
- and LineString([(prev_position[0], prev_position[1]), (box[0], box[1])]).intersects(
183
- self.counting_line_segment
184
- )
185
- ):
186
- self.count_ids.append(track_id)
187
-
188
- # Determine the direction of movement (IN or OUT)
189
- dx = (box[0] - prev_position[0]) * (self.counting_region.centroid.x - prev_position[0])
190
- dy = (box[1] - prev_position[1]) * (self.counting_region.centroid.y - prev_position[1])
191
- if dx > 0 and dy > 0:
192
- self.in_counts += 1
193
- self.class_wise_count[self.names[cls]]["IN"] += 1
194
- else:
195
- self.out_counts += 1
196
- self.class_wise_count[self.names[cls]]["OUT"] += 1
197
-
198
- labels_dict = {}
199
-
200
- for key, value in self.class_wise_count.items():
201
- if value["IN"] != 0 or value["OUT"] != 0:
202
- if not self.view_in_counts and not self.view_out_counts:
203
- continue
204
- elif not self.view_in_counts:
205
- labels_dict[str.capitalize(key)] = f"OUT {value['OUT']}"
206
- elif not self.view_out_counts:
207
- labels_dict[str.capitalize(key)] = f"IN {value['IN']}"
208
- else:
209
- labels_dict[str.capitalize(key)] = f"IN {value['IN']} OUT {value['OUT']}"
77
+ Helper function to display object counts on the frame.
78
+
79
+ Args:
80
+ im0 (ndarray): The input image or frame
81
+ """
82
+ labels_dict = {
83
+ str.capitalize(key): f"{'IN ' + str(value['IN']) if self.show_in else ''} "
84
+ f"{'OUT ' + str(value['OUT']) if self.show_out else ''}".strip()
85
+ for key, value in self.classwise_counts.items()
86
+ if value["IN"] != 0 or value["OUT"] != 0
87
+ }
210
88
 
211
89
  if labels_dict:
212
- annotator.display_analytics(self.im0, labels_dict, (104, 31, 17), (255, 255, 255), 10)
213
-
214
- def display_frames(self):
215
- """Displays the current frame with annotations and regions in a window."""
216
- if self.env_check:
217
- cv2.namedWindow(self.window_name)
218
- if len(self.reg_pts) == 4: # only add mouse event If user drawn region
219
- cv2.setMouseCallback(self.window_name, self.mouse_event_for_region, {"region_points": self.reg_pts})
220
- cv2.imshow(self.window_name, self.im0)
221
- # Break Window
222
- if cv2.waitKey(1) & 0xFF == ord("q"):
223
- return
224
-
225
- def start_counting(self, im0, tracks):
90
+ self.annotator.display_analytics(im0, labels_dict, (104, 31, 17), (255, 255, 255), 10)
91
+
92
+ def count(self, im0):
226
93
  """
227
- Main function to start the object counting process.
94
+ Processes input data (frames or object tracks) and updates counts.
228
95
 
229
96
  Args:
230
- im0 (ndarray): Current frame from the video stream.
231
- tracks (list): List of tracks obtained from the object tracking process.
97
+ im0 (ndarray): The input image that will be used for processing
98
+ Returns
99
+ im0 (ndarray): The processed image for more usage
232
100
  """
233
- self.im0 = im0 # store image
234
- self.extract_and_process_tracks(tracks) # draw region even if no objects
101
+ if not self.region_initialized:
102
+ self.initialize_region()
103
+ self.region_initialized = True
104
+
105
+ self.annotator = Annotator(im0, line_width=self.line_width) # Initialize annotator
106
+ self.extract_tracks(im0) # Extract tracks
107
+
108
+ self.annotator.draw_region(
109
+ reg_pts=self.region, color=(104, 0, 123), thickness=self.line_width * 2
110
+ ) # Draw region
111
+
112
+ # Iterate over bounding boxes, track ids and classes index
113
+ for box, track_id, cls in zip(self.boxes, self.track_ids, self.clss):
114
+ # Draw bounding box and counting region
115
+ self.annotator.box_label(box, label=self.names[cls], color=colors(track_id, True))
116
+ self.store_tracking_history(track_id, box) # Store track history
117
+ self.store_classwise_counts(cls) # store classwise counts in dict
118
+
119
+ # Draw centroid of objects
120
+ self.annotator.draw_centroid_and_tracks(
121
+ self.track_line, color=colors(int(track_id), True), track_thickness=self.line_width
122
+ )
235
123
 
236
- if self.view_img:
237
- self.display_frames()
238
- return self.im0
124
+ # store previous position of track for object counting
125
+ prev_position = self.track_history[track_id][-2] if len(self.track_history[track_id]) > 1 else None
126
+ self.count_objects(self.track_line, box, track_id, prev_position, cls) # Perform object counting
239
127
 
128
+ self.display_counts(im0) # Display the counts on the frame
129
+ self.display_output(im0) # display output with base class function
240
130
 
241
- if __name__ == "__main__":
242
- classes_names = {0: "person", 1: "car"} # example class names
243
- ObjectCounter(classes_names)
131
+ return im0 # return output image for more usage
@@ -0,0 +1,93 @@
1
+ # Ultralytics YOLO 🚀, AGPL-3.0 license
2
+
3
+ from collections import defaultdict
4
+ from pathlib import Path
5
+
6
+ import cv2
7
+
8
+ from ultralytics import YOLO
9
+ from ultralytics.utils import LOGGER, yaml_load
10
+ from ultralytics.utils.checks import check_imshow, check_requirements
11
+
12
+ check_requirements("shapely>=2.0.0")
13
+ from shapely.geometry import LineString, Polygon
14
+
15
+ DEFAULT_SOL_CFG_PATH = Path(__file__).resolve().parents[1] / "cfg/solutions/default.yaml"
16
+
17
+
18
+ class BaseSolution:
19
+ """A class to manage all the Ultralytics Solutions: https://docs.ultralytics.com/solutions/."""
20
+
21
+ def __init__(self, **kwargs):
22
+ """
23
+ Base initializer for all solutions.
24
+
25
+ Child classes should call this with necessary parameters.
26
+ """
27
+ # Load config and update with args
28
+ self.CFG = yaml_load(DEFAULT_SOL_CFG_PATH)
29
+ self.CFG.update(kwargs)
30
+ LOGGER.info(f"Ultralytics Solutions: ✅ {self.CFG}")
31
+
32
+ self.region = self.CFG["region"] # Store region data for other classes usage
33
+ self.line_width = self.CFG["line_width"] # Store line_width for usage
34
+
35
+ # Load Model and store classes names
36
+ self.model = YOLO(self.CFG["model"])
37
+ self.names = self.model.names
38
+
39
+ # Initialize environment and region setup
40
+ self.env_check = check_imshow(warn=True)
41
+ self.track_history = defaultdict(list)
42
+
43
+ def extract_tracks(self, im0):
44
+ """
45
+ Apply object tracking and extract tracks.
46
+
47
+ Args:
48
+ im0 (ndarray): The input image or frame
49
+ """
50
+ self.tracks = self.model.track(source=im0, persist=True, classes=self.CFG["classes"])
51
+
52
+ # Extract tracks for OBB or object detection
53
+ self.track_data = self.tracks[0].obb or self.tracks[0].boxes
54
+
55
+ if self.track_data and self.track_data.id is not None:
56
+ self.boxes = self.track_data.xyxy.cpu()
57
+ self.clss = self.track_data.cls.cpu().tolist()
58
+ self.track_ids = self.track_data.id.int().cpu().tolist()
59
+ else:
60
+ LOGGER.warning("WARNING ⚠️ no tracks found!")
61
+ self.boxes, self.clss, self.track_ids = [], [], []
62
+
63
+ def store_tracking_history(self, track_id, box):
64
+ """
65
+ Store object tracking history.
66
+
67
+ Args:
68
+ track_id (int): The track ID of the object
69
+ box (list): Bounding box coordinates of the object
70
+ """
71
+ # Store tracking history
72
+ self.track_line = self.track_history[track_id]
73
+ self.track_line.append(((box[0] + box[2]) / 2, (box[1] + box[3]) / 2))
74
+ if len(self.track_line) > 30:
75
+ self.track_line.pop(0)
76
+
77
+ def initialize_region(self):
78
+ """Initialize the counting region and line segment based on config."""
79
+ self.region = [(20, 400), (1260, 400)] if self.region is None else self.region
80
+ self.r_s = Polygon(self.region) if len(self.region) >= 3 else LineString(self.region)
81
+ self.l_s = LineString([(self.region[0][0], self.region[0][1]), (self.region[1][0], self.region[1][1])])
82
+
83
+ def display_output(self, im0):
84
+ """
85
+ Display the results of the processing, which could involve showing frames, printing counts, or saving results.
86
+
87
+ Args:
88
+ im0 (ndarray): The input image or frame
89
+ """
90
+ if self.CFG.get("show") and self.env_check:
91
+ cv2.imshow("Ultralytics Solutions", im0)
92
+ if cv2.waitKey(1) & 0xFF == ord("q"):
93
+ return
@@ -61,8 +61,8 @@ HELP_MSG = """
61
61
  from ultralytics import YOLO
62
62
 
63
63
  # Load a model
64
- model = YOLO("yolov8n.yaml") # build a new model from scratch
65
- model = YOLO("yolov8n.pt") # load a pretrained model (recommended for training)
64
+ model = YOLO("yolo11n.yaml") # build a new model from scratch
65
+ model = YOLO("yolo11n.pt") # load a pretrained model (recommended for training)
66
66
 
67
67
  # Use the model
68
68
  results = model.train(data="coco8.yaml", epochs=3) # train the model
@@ -77,21 +77,21 @@ HELP_MSG = """
77
77
  yolo TASK MODE ARGS
78
78
 
79
79
  Where TASK (optional) is one of [detect, segment, classify, pose, obb]
80
- MODE (required) is one of [train, val, predict, export, benchmark]
80
+ MODE (required) is one of [train, val, predict, export, track, benchmark]
81
81
  ARGS (optional) are any number of custom "arg=value" pairs like "imgsz=320" that override defaults.
82
82
  See all ARGS at https://docs.ultralytics.com/usage/cfg or with "yolo cfg"
83
83
 
84
84
  - Train a detection model for 10 epochs with an initial learning_rate of 0.01
85
- yolo detect train data=coco8.yaml model=yolov8n.pt epochs=10 lr0=0.01
85
+ yolo detect train data=coco8.yaml model=yolo11n.pt epochs=10 lr0=0.01
86
86
 
87
87
  - Predict a YouTube video using a pretrained segmentation model at image size 320:
88
- yolo segment predict model=yolov8n-seg.pt source='https://youtu.be/LNwODJXcvt4' imgsz=320
88
+ yolo segment predict model=yolo11n-seg.pt source='https://youtu.be/LNwODJXcvt4' imgsz=320
89
89
 
90
90
  - Val a pretrained detection model at batch-size 1 and image size 640:
91
- yolo detect val model=yolov8n.pt data=coco8.yaml batch=1 imgsz=640
91
+ yolo detect val model=yolo11n.pt data=coco8.yaml batch=1 imgsz=640
92
92
 
93
- - Export a YOLOv8n classification model to ONNX format at image size 224 by 128 (no TASK required)
94
- yolo export model=yolov8n-cls.pt format=onnx imgsz=224,128
93
+ - Export a YOLO11n classification model to ONNX format at image size 224 by 128 (no TASK required)
94
+ yolo export model=yolo11n-cls.pt format=onnx imgsz=224,128
95
95
 
96
96
  - Run special commands:
97
97
  yolo help
@@ -989,55 +989,56 @@ def set_sentry():
989
989
  Additionally, the function sets custom tags and user information for Sentry events.
990
990
  """
991
991
  if (
992
- SETTINGS["sync"]
993
- and RANK in {-1, 0}
994
- and Path(ARGV[0]).name == "yolo"
995
- and not TESTS_RUNNING
996
- and ONLINE
997
- and IS_PIP_PACKAGE
998
- and not IS_GIT_DIR
992
+ not SETTINGS["sync"]
993
+ or RANK not in {-1, 0}
994
+ or Path(ARGV[0]).name != "yolo"
995
+ or TESTS_RUNNING
996
+ or not ONLINE
997
+ or not IS_PIP_PACKAGE
998
+ or IS_GIT_DIR
999
999
  ):
1000
- # If sentry_sdk package is not installed then return and do not use Sentry
1001
- try:
1002
- import sentry_sdk # noqa
1003
- except ImportError:
1004
- return
1005
-
1006
- def before_send(event, hint):
1007
- """
1008
- Modify the event before sending it to Sentry based on specific exception types and messages.
1000
+ return
1001
+ # If sentry_sdk package is not installed then return and do not use Sentry
1002
+ try:
1003
+ import sentry_sdk # noqa
1004
+ except ImportError:
1005
+ return
1006
+
1007
+ def before_send(event, hint):
1008
+ """
1009
+ Modify the event before sending it to Sentry based on specific exception types and messages.
1009
1010
 
1010
- Args:
1011
- event (dict): The event dictionary containing information about the error.
1012
- hint (dict): A dictionary containing additional information about the error.
1011
+ Args:
1012
+ event (dict): The event dictionary containing information about the error.
1013
+ hint (dict): A dictionary containing additional information about the error.
1013
1014
 
1014
- Returns:
1015
- dict: The modified event or None if the event should not be sent to Sentry.
1016
- """
1017
- if "exc_info" in hint:
1018
- exc_type, exc_value, _ = hint["exc_info"]
1019
- if exc_type in {KeyboardInterrupt, FileNotFoundError} or "out of memory" in str(exc_value):
1020
- return None # do not send event
1021
-
1022
- event["tags"] = {
1023
- "sys_argv": ARGV[0],
1024
- "sys_argv_name": Path(ARGV[0]).name,
1025
- "install": "git" if IS_GIT_DIR else "pip" if IS_PIP_PACKAGE else "other",
1026
- "os": ENVIRONMENT,
1027
- }
1028
- return event
1029
-
1030
- sentry_sdk.init(
1031
- dsn="https://888e5a0778212e1d0314c37d4b9aae5d@o4504521589325824.ingest.us.sentry.io/4504521592406016",
1032
- debug=False,
1033
- auto_enabling_integrations=False,
1034
- traces_sample_rate=1.0,
1035
- release=__version__,
1036
- environment="production", # 'dev' or 'production'
1037
- before_send=before_send,
1038
- ignore_errors=[KeyboardInterrupt, FileNotFoundError],
1039
- )
1040
- sentry_sdk.set_user({"id": SETTINGS["uuid"]}) # SHA-256 anonymized UUID hash
1015
+ Returns:
1016
+ dict: The modified event or None if the event should not be sent to Sentry.
1017
+ """
1018
+ if "exc_info" in hint:
1019
+ exc_type, exc_value, _ = hint["exc_info"]
1020
+ if exc_type in {KeyboardInterrupt, FileNotFoundError} or "out of memory" in str(exc_value):
1021
+ return None # do not send event
1022
+
1023
+ event["tags"] = {
1024
+ "sys_argv": ARGV[0],
1025
+ "sys_argv_name": Path(ARGV[0]).name,
1026
+ "install": "git" if IS_GIT_DIR else "pip" if IS_PIP_PACKAGE else "other",
1027
+ "os": ENVIRONMENT,
1028
+ }
1029
+ return event
1030
+
1031
+ sentry_sdk.init(
1032
+ dsn="https://888e5a0778212e1d0314c37d4b9aae5d@o4504521589325824.ingest.us.sentry.io/4504521592406016",
1033
+ debug=False,
1034
+ auto_enabling_integrations=False,
1035
+ traces_sample_rate=1.0,
1036
+ release=__version__,
1037
+ environment="production", # 'dev' or 'production'
1038
+ before_send=before_send,
1039
+ ignore_errors=[KeyboardInterrupt, FileNotFoundError],
1040
+ )
1041
+ sentry_sdk.set_user({"id": SETTINGS["uuid"]}) # SHA-256 anonymized UUID hash
1041
1042
 
1042
1043
 
1043
1044
  class JSONDict(dict):