Skip to content

Commit 1a0e561

Browse files
author
Your Name
committed
Add numpy support and BSON-safe conversion for database operations
1 parent 26c36b6 commit 1a0e561

File tree

1 file changed

+44
-102
lines changed
  • src/autonomy_metrics/autonomy_metrics

1 file changed

+44
-102
lines changed

src/autonomy_metrics/autonomy_metrics/db_mgr.py

Lines changed: 44 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,48 @@
1-
"""
2-
Licensed under the Apache License, Version 2.0 (the "License");
3-
you may not use this file except in compliance with the License.
4-
You may obtain a copy of the License at
5-
6-
http://www.apache.org/licenses/LICENSE-2.0
7-
8-
Unless required by applicable law or agreed to in writing, software
9-
distributed under the License is distributed on an "AS IS" BASIS,
10-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11-
See the License for the specific language governing permissions and
12-
limitations under the License.
13-
14-
15-
Author: Ibrahim Hroob
16-
Email: ibrahim.hroub7@gmail.com
17-
"""
18-
191
from pymongo import MongoClient
202
from datetime import datetime, timezone
213
from bson import ObjectId
224

5+
# NEW
6+
try:
7+
import numpy as np
8+
except Exception:
9+
np = None
10+
11+
2312
class DatabaseMgr:
2413
"""
2514
A class to manage database operations for robot session.
26-
27-
Attributes:
28-
client (MongoClient): The MongoDB client.
29-
db (Database): The MongoDB database.
30-
sessions_collection (Collection): The MongoDB collection for sessions.
31-
session_id (ObjectId): The ID of the current session.
3215
"""
3316

3417
def __init__(self, database_name='robot_incidents', host='localhost', port=27017):
35-
"""
36-
Initializes the DatabaseMgr with a given database name, host, and port.
37-
38-
Args:
39-
database_name (str): The name of the database to connect to.
40-
host (str): The hostname or IP address of the MongoDB server.
41-
port (int): The port of the MongoDB server.
42-
"""
4318
self.client = MongoClient(
4419
f'mongodb://{host}:{port}/',
45-
# serverSelectionTimeoutMS=-1, # Disable server selection timeout
46-
# socketTimeoutMS=-1, # Disable socket timeout
47-
connectTimeoutMS=None # Disable connection timeout
48-
)
20+
connectTimeoutMS=None
21+
)
4922
self.db = self.client[database_name]
5023
self.sessions_collection = self.db['sessions']
5124
self.session_id = None
5225

26+
# NEW
27+
def _bson_safe(self, obj):
28+
"""Recursively convert non-BSON types (notably numpy) into Mongo-friendly types."""
29+
if np is not None:
30+
# numpy arrays -> list
31+
if isinstance(obj, np.ndarray):
32+
return obj.tolist()
33+
# numpy scalar -> python scalar
34+
if isinstance(obj, np.generic):
35+
return obj.item()
36+
37+
if isinstance(obj, dict):
38+
return {k: self._bson_safe(v) for k, v in obj.items()}
39+
40+
if isinstance(obj, (list, tuple)):
41+
return [self._bson_safe(v) for v in obj]
42+
43+
return obj
44+
5345
def init_session(self, env_variables, aoc_repos_info):
54-
"""
55-
Initializes a new session with the given environmental variables.
56-
57-
Args:
58-
**env_variables: Arbitrary keyword arguments containing session information.
59-
Expected keys include 'robot_name', 'farm_name', 'field_name', 'application',
60-
and 'scenario_name'.
61-
"""
6246
session_start = datetime.now(tz=timezone.utc)
6347
session_document = {
6448
"session_start_time": session_start,
@@ -67,107 +51,65 @@ def init_session(self, env_variables, aoc_repos_info):
6751
"field_name": env_variables['field_name'],
6852
"application": env_variables['application'],
6953
"scenario_name": env_variables['scenario_name'],
70-
"aoc_repos_info": aoc_repos_info,
71-
"mdbi": None,
54+
"aoc_repos_info": aoc_repos_info,
55+
"mdbi": None,
7256
"incidents": 0,
7357
"distance": 0,
7458
"autonomous_distance": 0,
75-
"collision_incidents": 0, # NEW
59+
"collision_incidents": 0,
7660
"events": []
7761
}
62+
63+
# NEW: sanitize (in case aoc_repos_info contains numpy types)
64+
session_document = self._bson_safe(session_document)
65+
7866
result = self.sessions_collection.insert_one(session_document)
7967
self.session_id = result.inserted_id
8068

8169
def add_event(self, event):
82-
"""
83-
Adds an event to the current session.
84-
85-
Args:
86-
event (dict): The event to add.
70+
# NEW: sanitize event before writing
71+
event = self._bson_safe(event)
8772

88-
Returns:
89-
bool: True if the event was added successfully, False otherwise.
90-
"""
9173
result = self.sessions_collection.update_one(
9274
{"_id": ObjectId(self.session_id)},
9375
{"$addToSet": {"events": event}}
9476
)
9577
return result.modified_count > 0
9678

9779
def update_incidents(self, incidents):
98-
"""
99-
Updates the incidents value of the current session.
100-
101-
Args:
102-
incidents (int): The new incidents value.
103-
104-
Returns:
105-
bool: True if the incidents was updated successfully, False otherwise.
106-
"""
80+
incidents = self._bson_safe(incidents) # harmless; keeps pattern consistent
10781
result = self.sessions_collection.update_one(
10882
{"_id": ObjectId(self.session_id)},
10983
{"$set": {"incidents": incidents}}
11084
)
11185
return result.modified_count > 0
11286

11387
def update_distance(self, distance):
114-
"""
115-
Updates the distance value of the current session.
116-
117-
Args:
118-
distance (float): The new distance value.
119-
120-
Returns:
121-
bool: True if the distance was updated successfully, False otherwise.
122-
"""
88+
distance = self._bson_safe(distance)
12389
result = self.sessions_collection.update_one(
12490
{"_id": ObjectId(self.session_id)},
12591
{"$set": {"distance": distance}}
12692
)
12793
return result.modified_count > 0
12894

12995
def update_autonomous_distance(self, autonomous_distance):
130-
"""
131-
Updates the autonomous_distance value of the current session.
132-
133-
Args:
134-
autonomous_distance (float): The new autonomous_distance value.
135-
136-
Returns:
137-
bool: True if the autonomous_distance was updated successfully, False otherwise.
138-
"""
96+
autonomous_distance = self._bson_safe(autonomous_distance)
13997
result = self.sessions_collection.update_one(
14098
{"_id": ObjectId(self.session_id)},
14199
{"$set": {"autonomous_distance": autonomous_distance}}
142100
)
143101
return result.modified_count > 0
144-
145-
def update_mdbi(self, mdbi):
146-
"""
147-
Updates the mdbi value of the current session.
148102

149-
Args:
150-
mdbi (float): The new mdbi value.
151-
152-
Returns:
153-
bool: True if the mdbi was updated successfully, False otherwise.
154-
"""
103+
def update_mdbi(self, mdbi):
104+
mdbi = self._bson_safe(mdbi)
155105
result = self.sessions_collection.update_one(
156106
{"_id": ObjectId(self.session_id)},
157107
{"$set": {"mdbi": mdbi}}
158108
)
159109
return result.modified_count > 0
160-
161-
def update_collision_incidents(self, collision_incidents):
162-
"""
163-
Updates the collision_incidents value of the current session.
164-
165-
Args:
166-
collision_incidents (int): The new collision incidents value.
167110

168-
Returns:
169-
bool: True if the value was updated successfully, False otherwise.
170-
"""
111+
def update_collision_incidents(self, collision_incidents):
112+
collision_incidents = self._bson_safe(collision_incidents)
171113
result = self.sessions_collection.update_one(
172114
{"_id": ObjectId(self.session_id)},
173115
{"$set": {"collision_incidents": collision_incidents}}

0 commit comments

Comments
 (0)