* cleanup

* fix & cleanup

* make testable

* please add the install log
This commit is contained in:
Nachtzuster
2025-11-09 19:39:29 +01:00
committed by GitHub
parent b5352ef038
commit edd5c62447
4 changed files with 162 additions and 134 deletions
+1
View File
@@ -31,6 +31,7 @@ Add any other context about the problem or your installation here.
The hardware on which BirdNET-Pi is running goes here. The hardware on which BirdNET-Pi is running goes here.
**Code or log snippets** **Code or log snippets**
The installation creates a log in `~/`, please include it where applicable.
<details> <details>
<summary>log or code</summary> <summary>log or code</summary>
+1 -1
View File
@@ -1,4 +1,4 @@
tflite_runtime-2.6.0-cp39-none-linux_aarch64.whl tflite_runtime
librosa librosa
pytz pytz
tzlocal tzlocal
+4 -4
View File
@@ -146,14 +146,14 @@ def sendAppriseNotifications(species, confidence, confidencepct, path,
def get_todays_count_for(db_path, sci_name): def get_todays_count_for(db_path, sci_name):
today = datetime.now().strftime("%Y-%m-%d") today = datetime.now().strftime("%Y-%m-%d")
select_sql = f"SELECT COUNT(*) FROM detections WHERE Date = DATE('{today}') AND Sci_name = '{sci_name}'" select_sql = f"SELECT COUNT(*) FROM detections WHERE Date = DATE('{today}') AND Sci_Name = '{sci_name}'"
records = get_records(db_path, select_sql) records = get_records(db_path, select_sql)
return records[0][0] if records else 0 return records[0][0] if records else 0
def get_this_weeks_count_for(db_path, sci_name): def get_this_weeks_count_for(db_path, sci_name):
today = datetime.now().strftime("%Y-%m-%d") today = datetime.now().strftime("%Y-%m-%d")
select_sql = f"SELECT COUNT(*) FROM detections WHERE Date >= DATE('{today}', '-7 day') AND Sci_name = '{sci_name}'" select_sql = f"SELECT COUNT(*) FROM detections WHERE Date >= DATE('{today}', '-7 day') AND Sci_Name = '{sci_name}'"
records = get_records(db_path, select_sql) records = get_records(db_path, select_sql)
return records[0][0] if records else 0 return records[0][0] if records else 0
@@ -165,8 +165,8 @@ def get_records(db_path, select_sql):
cur.execute(select_sql) cur.execute(select_sql)
records = cur.fetchall() records = cur.fetchall()
con.close() con.close()
except sqlite3.Error: except sqlite3.Error as e:
print("Database busy") print(f"Database busy: {e}")
timeim.sleep(2) timeim.sleep(2)
records = [] records = []
return records return records
+65 -38
View File
@@ -1,29 +1,40 @@
import os import os
import sqlite3 import sqlite3
import pytest
from scripts.utils.notifications import sendAppriseNotifications
from datetime import datetime from datetime import datetime
import unittest
from unittest.mock import patch
from scripts.utils import notifications
from scripts.utils.notifications import sendAppriseNotifications
def create_test_db(db_file): class TestAppriseNotifications(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.db_file = "test.db"
cls.apprise_body_file = "test_apprise_body"
cls.apprise_config_file = "test_apprise_config"
def create_test_db(self):
""" create a database connection to a SQLite database """ """ create a database connection to a SQLite database """
conn = None conn = None
try: try:
conn = sqlite3.connect(db_file) conn = sqlite3.connect(self.db_file)
sql_create_detections_table = """ CREATE TABLE IF NOT EXISTS detections ( sql_create_detections_table = """ CREATE TABLE IF NOT EXISTS detections (
id integer PRIMARY KEY, id integer PRIMARY KEY,
Sci_Name text NOT NULL,
Com_Name text NOT NULL, Com_Name text NOT NULL,
Date date NULL, Date date NOT NULL,
Time time NULL Time time NULL
); """ ); """
cur = conn.cursor() cur = conn.cursor()
cur.execute(sql_create_detections_table) cur.execute(sql_create_detections_table)
sql = ''' INSERT INTO detections(Com_Name, Date) sql = ''' INSERT INTO detections(Sci_Name, Com_Name, Date)
VALUES(?,?) ''' VALUES(?,?,?) '''
cur = conn.cursor()
today = datetime.now().strftime("%Y-%m-%d") # SQLite stores date as YYYY-MM-DD today = datetime.now().strftime("%Y-%m-%d") # SQLite stores date as YYYY-MM-DD
cur.execute(sql, ["Great Crested Flycatcher", today]) cur.execute(sql, ["Myiarchus crinitus", "Great Crested Flycatcher", today])
conn.commit() conn.commit()
except Exception as e: except Exception as e:
@@ -32,22 +43,32 @@ def create_test_db(db_file):
if conn: if conn:
conn.close() conn.close()
def create_apprise_config(self):
with open(self.apprise_body_file, 'w') as f:
f.write('A $comname ($sciname) was just detected with a confidence of $confidencepct ($reason)')
with open(self.apprise_config_file, 'w') as f:
f.write('a dummy config')
notifications.APPRISE_BODY = self.apprise_body_file
notifications.APPRISE_CONFIG = self.apprise_config_file
@pytest.fixture(autouse=True) def tearDown(self):
def clean_up_after_each_test(): if os.path.exists(self.db_file):
yield os.remove(self.db_file)
os.remove("test.db") if os.path.exists(self.apprise_body_file):
os.remove(self.apprise_body_file)
if os.path.exists(self.apprise_config_file):
os.remove(self.apprise_config_file)
@patch('scripts.utils.notifications.notify')
def test_notifications(mocker): def test_notifications(self, mock_notify):
notify_call = mocker.patch('scripts.utils.notifications.notify') self.create_test_db()
create_test_db("test.db") self.create_apprise_config()
settings_dict = { settings_dict = {
"APPRISE_NOTIFICATION_TITLE": "New backyard bird!", "APPRISE_NOTIFICATION_TITLE": "New backyard bird!",
"APPRISE_NOTIFICATION_BODY": "A $comname ($sciname) was just detected with a confidence of $confidence",
"APPRISE_NOTIFY_EACH_DETECTION": "0", "APPRISE_NOTIFY_EACH_DETECTION": "0",
"APPRISE_NOTIFY_NEW_SPECIES": "0", "APPRISE_NOTIFY_NEW_SPECIES": "0",
"APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY": "0" "APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY": "0",
"APPRISE_MINIMUM_SECONDS_BETWEEN_NOTIFICATIONS_PER_SPECIES": "0"
} }
sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher",
"0.91", "0.91",
@@ -62,13 +83,13 @@ def test_notifications(mocker):
"1.25", "1.25",
"0.0", "0.0",
settings_dict, settings_dict,
"test.db") self.db_file)
# No active apprise notifcations configured. Confirm no notifications. # No active apprise notifications configured. Confirm no notifications.
assert (notify_call.call_count == 0) # No notification should be sent. self.assertEqual(mock_notify.call_count, 0)
# Add daily notification. # Add daily notification.
notify_call.reset_mock() mock_notify.reset_mock()
settings_dict["APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY"] = "1" settings_dict["APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY"] = "1"
sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher",
"0.91", "0.91",
@@ -83,15 +104,16 @@ def test_notifications(mocker):
"1.25", "1.25",
"0.0", "0.0",
settings_dict, settings_dict,
"test.db") self.db_file)
assert (notify_call.call_count == 1) self.assertEqual(mock_notify.call_count, 1)
assert ( self.assertEqual(
notify_call.call_args_list[0][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (first time today)" mock_notify.call_args_list[0][0][0],
"A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (first time today)"
) )
# Add new species notification. # Add new species notification.
notify_call.reset_mock() mock_notify.reset_mock()
settings_dict["APPRISE_NOTIFY_NEW_SPECIES"] = "1" settings_dict["APPRISE_NOTIFY_NEW_SPECIES"] = "1"
sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher",
"0.91", "0.91",
@@ -106,19 +128,20 @@ def test_notifications(mocker):
"1.25", "1.25",
"0.0", "0.0",
settings_dict, settings_dict,
"test.db") self.db_file)
assert (notify_call.call_count == 2) self.assertEqual(mock_notify.call_count, 2)
assert ( self.assertEqual(
notify_call.call_args_list[0][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (first time today)" mock_notify.call_args_list[0][0][0],
"A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (first time today)"
) )
assert ( self.assertEqual(
notify_call.call_args_list[1][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence \ mock_notify.call_args_list[1][0][0],
of 91 (only seen 1 times in last 7d)" "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (only seen 1 times in last 7d)"
) )
# Add each species notification. # Add each species notification.
notify_call.reset_mock() mock_notify.reset_mock()
settings_dict["APPRISE_NOTIFY_EACH_DETECTION"] = "1" settings_dict["APPRISE_NOTIFY_EACH_DETECTION"] = "1"
sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher",
"0.91", "0.91",
@@ -133,6 +156,10 @@ def test_notifications(mocker):
"1.25", "1.25",
"0.0", "0.0",
settings_dict, settings_dict,
"test.db") self.db_file)
assert (notify_call.call_count == 3) self.assertEqual(mock_notify.call_count, 3)
if __name__ == '__main__':
unittest.main()