Spaces:
Sleeping
Sleeping
rmm
commited on
Commit
·
dca913f
1
Parent(s):
95f4dd2
test: for setters and for to_dict method of InputObservation
Browse files- the last test here puts appropriate data into an InputObservation,
mimicks going through all the classification stages, and then
generates the dict that will be transmitted to the dataset/HF server
- tests/test_input_observation.py +157 -0
tests/test_input_observation.py
CHANGED
|
@@ -38,6 +38,7 @@ class MockUploadedFile(BytesIO):
|
|
| 38 |
|
| 39 |
self._file_urls = [None,]
|
| 40 |
|
|
|
|
| 41 |
@pytest.fixture
|
| 42 |
def mock_uploadedFile():
|
| 43 |
class MockGUIClass(MagicMock):
|
|
@@ -198,6 +199,7 @@ def test_input_observation_invalid(key, error_type, mock_uploadedFile):
|
|
| 198 |
inputs[key] = None
|
| 199 |
with pytest.raises(error_type):
|
| 200 |
obs = InputObservation(**inputs)
|
|
|
|
| 201 |
|
| 202 |
# we can take a similar approach to test equality.
|
| 203 |
# here, construct two dicts, each with valid inputs but all elements different.
|
|
@@ -263,3 +265,158 @@ def test_input_observation_equality(key, expect_equality, mock_uploadedFile):
|
|
| 263 |
assert obs1 != obs2
|
| 264 |
|
| 265 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
self._file_urls = [None,]
|
| 40 |
|
| 41 |
+
|
| 42 |
@pytest.fixture
|
| 43 |
def mock_uploadedFile():
|
| 44 |
class MockGUIClass(MagicMock):
|
|
|
|
| 199 |
inputs[key] = None
|
| 200 |
with pytest.raises(error_type):
|
| 201 |
obs = InputObservation(**inputs)
|
| 202 |
+
|
| 203 |
|
| 204 |
# we can take a similar approach to test equality.
|
| 205 |
# here, construct two dicts, each with valid inputs but all elements different.
|
|
|
|
| 265 |
assert obs1 != obs2
|
| 266 |
|
| 267 |
|
| 268 |
+
# now let's test the setter methods (set_top_predictions, set_selected_class, set_class_overriden)
|
| 269 |
+
# ideally we get a fixture that produces a good / valid InputObservation object
|
| 270 |
+
# and from there, just test the setters + their expected changes / side effects
|
| 271 |
+
|
| 272 |
+
@pytest.fixture
|
| 273 |
+
def good_datadict_for_input_observation(mock_uploadedFile) -> dict:
|
| 274 |
+
# set up the good and bad inputs
|
| 275 |
+
_date="2023-10-10"
|
| 276 |
+
_time="10:10:10"
|
| 277 |
+
image_datetime_raw = _date + " " + _time
|
| 278 |
+
fname = "test_image.jpg"
|
| 279 |
+
image = np.random.randint(0, 255, (100, 100, 3), dtype=np.uint8)
|
| 280 |
+
|
| 281 |
+
dt_ok = datetime.datetime.strptime(image_datetime_raw, "%Y-%m-%d %H:%M:%S")
|
| 282 |
+
valid_inputs = {
|
| 283 |
+
"author_email": "test@example.com",
|
| 284 |
+
"uploaded_file": mock_uploadedFile(name=fname).get_data(),
|
| 285 |
+
"date": dt_ok.date(),
|
| 286 |
+
"time": dt_ok.time(),
|
| 287 |
+
"image": image,
|
| 288 |
+
"image_md5": 'd1d2515e6f6ac4c5ca6dd739d5143cd4', # 32 hex chars.
|
| 289 |
+
"image_datetime_raw": image_datetime_raw,
|
| 290 |
+
"latitude": 12.34,
|
| 291 |
+
"longitude": 56.78,
|
| 292 |
+
|
| 293 |
+
}
|
| 294 |
+
return valid_inputs
|
| 295 |
+
|
| 296 |
+
|
| 297 |
+
@pytest.fixture
|
| 298 |
+
def good_input_observation(good_datadict_for_input_observation) -> InputObservation:
|
| 299 |
+
observation = InputObservation(**good_datadict_for_input_observation)
|
| 300 |
+
|
| 301 |
+
return observation
|
| 302 |
+
|
| 303 |
+
|
| 304 |
+
#
|
| 305 |
+
def test_input_observation__set_top_predictions_populated(good_input_observation):
|
| 306 |
+
obs = good_input_observation
|
| 307 |
+
|
| 308 |
+
# before setting, expect empty list
|
| 309 |
+
assert obs.top_predictions == []
|
| 310 |
+
assert obs.selected_class == None
|
| 311 |
+
|
| 312 |
+
# set >0,
|
| 313 |
+
# - expect to find the same list in the property/attribute
|
| 314 |
+
# - expect to find the first element in the selected_class
|
| 315 |
+
top_predictions = ["beluga", "blue_whale", "common_dolphin"]
|
| 316 |
+
obs.set_top_predictions(top_predictions)
|
| 317 |
+
|
| 318 |
+
assert len(obs.top_predictions) == 3
|
| 319 |
+
assert obs.top_predictions == top_predictions
|
| 320 |
+
assert obs.selected_class == "beluga"
|
| 321 |
+
|
| 322 |
+
def test_input_observation__set_top_predictions_unpopulated(good_input_observation):
|
| 323 |
+
obs = good_input_observation
|
| 324 |
+
|
| 325 |
+
# before setting, expect empty list
|
| 326 |
+
assert obs.top_predictions == []
|
| 327 |
+
assert obs.selected_class == None
|
| 328 |
+
|
| 329 |
+
# set to empty list,
|
| 330 |
+
# - expect to find the same list in the property/attribute
|
| 331 |
+
# - expect to find selected_class to be None
|
| 332 |
+
top_predictions = []
|
| 333 |
+
obs.set_top_predictions(top_predictions)
|
| 334 |
+
|
| 335 |
+
assert len(obs.top_predictions) == 0
|
| 336 |
+
assert obs.top_predictions == []
|
| 337 |
+
assert obs.selected_class == None
|
| 338 |
+
|
| 339 |
+
def test_input_observation__set_selected_class_default(good_input_observation):
|
| 340 |
+
obs = good_input_observation
|
| 341 |
+
|
| 342 |
+
# before setting, expect empty list
|
| 343 |
+
assert obs.top_predictions == []
|
| 344 |
+
assert obs.selected_class == None
|
| 345 |
+
assert obs.class_overriden == False
|
| 346 |
+
|
| 347 |
+
# set >0, and then set_selected_class to the first element
|
| 348 |
+
# - expect to find the same list in the property/attribute
|
| 349 |
+
# - expect to find the first element in the selected_class
|
| 350 |
+
# - expect class_overriden to be False
|
| 351 |
+
top_predictions = ["beluga", "blue_whale", "common_dolphin"]
|
| 352 |
+
obs.set_top_predictions(top_predictions)
|
| 353 |
+
obs.set_selected_class(top_predictions[0])
|
| 354 |
+
|
| 355 |
+
assert len(obs.top_predictions) == 3
|
| 356 |
+
assert obs.top_predictions == top_predictions
|
| 357 |
+
assert obs.selected_class == "beluga"
|
| 358 |
+
|
| 359 |
+
def test_input_observation__set_selected_class_override(good_input_observation):
|
| 360 |
+
obs = good_input_observation
|
| 361 |
+
|
| 362 |
+
# before setting, expect empty list
|
| 363 |
+
assert obs.top_predictions == []
|
| 364 |
+
assert obs.selected_class == None
|
| 365 |
+
assert obs.class_overriden == False
|
| 366 |
+
|
| 367 |
+
# set >0, and then set_selected_class to something out of list
|
| 368 |
+
# - expect to find the same list in the property/attribute
|
| 369 |
+
# - expect to find the first element in the selected_class
|
| 370 |
+
# - expect class_overriden to be False
|
| 371 |
+
top_predictions = ["beluga", "blue_whale", "common_dolphin"]
|
| 372 |
+
obs.set_top_predictions(top_predictions)
|
| 373 |
+
obs.set_selected_class("brydes_whale")
|
| 374 |
+
|
| 375 |
+
assert len(obs.top_predictions) == 3
|
| 376 |
+
assert obs.top_predictions == top_predictions
|
| 377 |
+
assert obs.selected_class == "brydes_whale"
|
| 378 |
+
assert obs.class_overriden == True
|
| 379 |
+
|
| 380 |
+
|
| 381 |
+
# now we want to test to_dict, make sure it is compliant with the data to be
|
| 382 |
+
# transmitted to the dataset/server
|
| 383 |
+
|
| 384 |
+
def test_input_observation_to_dict(good_datadict_for_input_observation):
|
| 385 |
+
obs = InputObservation(**good_datadict_for_input_observation)
|
| 386 |
+
|
| 387 |
+
# set >0, and then set_selected_class to something out of list
|
| 388 |
+
# - expect to find the same list in the property/attribute
|
| 389 |
+
# - expect to find the first element in the selected_class
|
| 390 |
+
# - expect class_overriden to be False
|
| 391 |
+
top_predictions = ["beluga", "blue_whale", "common_dolphin"]
|
| 392 |
+
selected = "brydes_whale"
|
| 393 |
+
obs.set_top_predictions(top_predictions)
|
| 394 |
+
obs.set_selected_class(selected)
|
| 395 |
+
|
| 396 |
+
# as a first point, we expect the dict to be like the input dict...
|
| 397 |
+
expected_output = good_datadict_for_input_observation.copy()
|
| 398 |
+
# ... with a few changes
|
| 399 |
+
# - date and time get converted to str(date) str(time)
|
| 400 |
+
expected_output["date"] = str(expected_output["date"])
|
| 401 |
+
expected_output["time"] = str(expected_output["time"])
|
| 402 |
+
# - image_filename comes from uploaded_file.name
|
| 403 |
+
expected_output["image_filename"] = expected_output["uploaded_file"].name
|
| 404 |
+
# - uploaded_file and image are not in the transmitted data
|
| 405 |
+
del expected_output["uploaded_file"]
|
| 406 |
+
del expected_output["image"]
|
| 407 |
+
# - the classification results should be as set above
|
| 408 |
+
expected_output["top_prediction"] = top_predictions[0]
|
| 409 |
+
expected_output["selected_class"] = selected
|
| 410 |
+
expected_output["class_overriden"] = True
|
| 411 |
+
|
| 412 |
+
print(obs.to_dict())
|
| 413 |
+
assert obs.to_dict() == expected_output
|
| 414 |
+
|
| 415 |
+
# expected = {
|
| 416 |
+
# 'image_filename': 'test_image.jpg', 'image_md5':
|
| 417 |
+
# 'd1d2515e6f6ac4c5ca6dd739d5143cd4', 'latitude': 12.34, 'longitude':
|
| 418 |
+
# 56.78, 'author_email': 'test@example.com', 'image_datetime_raw':
|
| 419 |
+
# '2023-10-10 10:10:10', 'date': '2023-10-10', 'time': '10:10:10',
|
| 420 |
+
# 'selected_class': 'brydes_whale', 'top_prediction': 'beluga',
|
| 421 |
+
# 'class_overriden': True
|
| 422 |
+
# }
|