adding tests

This commit is contained in:
David Bures
2024-06-26 11:27:25 -07:00
parent 2bf14a7346
commit 4d8d33967e
7 changed files with 159 additions and 87 deletions
+11
View File
@@ -0,0 +1,11 @@
{
"python.testing.unittestArgs": [
"-v",
"-s",
".",
"-p",
"*test.py"
],
"python.testing.pytestEnabled": false,
"python.testing.unittestEnabled": true
}
+97 -85
View File
@@ -1,6 +1,7 @@
# helper functions to use location data
# K7MHI Kelly Keeton 2024
import json
from geopy.geocoders import Nominatim # pip install geopy
import maidenhead as mh # pip install maidenhead
import requests # pip install requests
@@ -8,11 +9,14 @@ import bs4 as bs # pip install beautifulsoup4
URL_TIMEOUT = 10 # wait time for URL requests
DAYS_OF_WEATHER = 4 # weather forecast days, the first two rows are today and tonight
# unified error messages to be able to test them from tests
NO_DATA_NOGPS = "no location data: does your device have GPS?"
ERROR_FETCHING_DATA = "error fetching data"
def where_am_i(lat=0, lon=0):
whereIam = ""
if float(lat) == 0 and float(lon) == 0:
return "no location data: does your device have GPS?"
return NO_DATA_NOGPS
# initialize Nominatim API
geolocator = Nominatim(user_agent="mesh-bot")
@@ -28,100 +32,108 @@ def where_am_i(lat=0, lon=0):
def get_tide(lat=0, lon=0):
station_id = ""
if float(lat) == 0 and float(lon) == 0:
return "no location data: does your device have GPS?"
return NO_DATA_NOGPS
station_lookup_url = "https://api.tidesandcurrents.noaa.gov/mdapi/prod/webapi/tidepredstations.json?lat=" + str(lat) + "&lon=" + str(lon) + "&radius=50"
station_data = requests.get(station_lookup_url, timeout=URL_TIMEOUT)
if(station_data.ok):
station_json = station_data.json()
# get first station id in 50 mile radius
station_id = station_json['stationList'][0]['stationId']
else:
return "error fetching station data"
try:
station_data = requests.get(station_lookup_url, timeout=URL_TIMEOUT)
if station_data.ok:
station_json = station_data.json()
else:
return ERROR_FETCHING_DATA
except (requests.exceptions.RequestException, json.JSONDecodeError):
return ERROR_FETCHING_DATA
station_id = station_json['stationList'][0]['stationId']
station_url = "https://tidesandcurrents.noaa.gov/noaatidepredictions.html?id=" + station_id
station_data = requests.get(station_url, timeout=URL_TIMEOUT)
if(station_data.ok):
# extract table class="table table-condensed"
soup = bs.BeautifulSoup(station_data.text, 'html.parser')
table = soup.find('table', class_='table table-condensed')
# extract rows
rows = table.find_all('tr')
# extract data from rows
tide_data = []
for row in rows:
row_text = ""
cols = row.find_all('td')
for col in cols:
row_text += col.text + " "
tide_data.append(row_text)
# format tide data into a string
tide_string = ""
for data in tide_data:
tide_string += data + "\n"
# trim off last newline
tide_string = tide_string[:-1]
return tide_string
else:
return "error fetching tide data"
try:
station_data = requests.get(station_url, timeout=URL_TIMEOUT)
if not station_data.ok:
return ERROR_FETCHING_DATA
except (requests.exceptions.RequestException):
return ERROR_FETCHING_DATA
# extract table class="table table-condensed"
soup = bs.BeautifulSoup(station_data.text, 'html.parser')
table = soup.find('table', class_='table table-condensed')
# extract rows
rows = table.find_all('tr')
# extract data from rows
tide_data = []
for row in rows:
row_text = ""
cols = row.find_all('td')
for col in cols:
row_text += col.text + " "
tide_data.append(row_text)
# format tide data into a string
tide_string = ""
for data in tide_data:
tide_string += data + "\n"
# trim off last newline
tide_string = tide_string[:-1]
return tide_string
def get_weather(lat=0, lon=0):
weather = ""
if float(lat) == 0 and float(lon) == 0:
return "no location data: does your device have GPS?"
return NO_DATA_NOGPS
weather_url = "https://forecast.weather.gov/MapClick.php?FcstType=text&lat=" + str(lat) + "&lon=" + str(lon)
weather_data = requests.get(weather_url, timeout=URL_TIMEOUT)
if(weather_data.ok):
soup = bs.BeautifulSoup(weather_data.text, 'html.parser')
table = soup.find('div', id="detailed-forecast-body")
if table is None:
return "no weather data found on NOAA for your location"
else:
# get rows
rows = table.find_all('div', class_="row")
# extract data from rows
for row in rows:
# shrink the text
line = row.text.replace("Monday", "Mon ") \
.replace("Tuesday", "Tue ") \
.replace("Wednesday", "Wed ") \
.replace("Thursday", "Thu ") \
.replace("Friday", "Fri ") \
.replace("Saturday", "Sat ") \
.replace("Today", "Today ") \
.replace("Tonight", "Tonight ") \
.replace("Tomorrow", "Tomorrow ") \
.replace("This Afternoon", "Afternoon ") \
.replace("northwest", "NW") \
.replace("northeast", "NE") \
.replace("southwest", "SW") \
.replace("southeast", "SE") \
.replace("north", "N") \
.replace("south", "S") \
.replace("east", "E") \
.replace("west", "W") \
.replace("Northwest", "NW") \
.replace("Northeast", "NE") \
.replace("Southwest", "SW") \
.replace("Southeast", "SE") \
.replace("North", "N") \
.replace("South", "S") \
.replace("East", "E") \
.replace("West", "W") \
.replace("precipitation", "precip") \
.replace("showers", "shwrs") \
.replace("thunderstorms", "t-storms")
# only grab a few days of weather
if len(weather.split("\n")) < DAYS_OF_WEATHER:
weather += line + "\n"
# trim off last newline
weather = weather[:-1]
try:
weather_data = requests.get(weather_url, timeout=TIMEOUT_DURATION)
if not weather_data.ok:
return ERROR_FETCHING_DATA
except (requests.exceptions.RequestException):
return ERROR_FETCHING_DATA
return weather
soup = bs.BeautifulSoup(weather_data.text, 'html.parser')
table = soup.find('div', id="detailed-forecast-body")
if table is None:
return "no weather data found on NOAA for your location"
else:
return "error fetching weather data"
# get rows
rows = table.find_all('div', class_="row")
# extract data from rows
for row in rows:
# shrink the text
line = row.text.replace("Monday", "Mon ") \
.replace("Tuesday", "Tue ") \
.replace("Wednesday", "Wed ") \
.replace("Thursday", "Thu ") \
.replace("Friday", "Fri ") \
.replace("Saturday", "Sat ") \
.replace("Today", "Today ") \
.replace("Tonight", "Tonight ") \
.replace("Tomorrow", "Tomorrow ") \
.replace("This Afternoon", "Afternoon ") \
.replace("northwest", "NW") \
.replace("northeast", "NE") \
.replace("southwest", "SW") \
.replace("southeast", "SE") \
.replace("north", "N") \
.replace("south", "S") \
.replace("east", "E") \
.replace("west", "W") \
.replace("Northwest", "NW") \
.replace("Northeast", "NE") \
.replace("Southwest", "SW") \
.replace("Southeast", "SE") \
.replace("North", "N") \
.replace("South", "S") \
.replace("East", "E") \
.replace("West", "W") \
.replace("precipitation", "precip") \
.replace("showers", "shwrs") \
.replace("thunderstorms", "t-storms")
# only grab a few days of weather
if len(weather.split("\n")) < DAYS_OF_WEATHER:
weather += line + "\n"
# trim off last newline
weather = weather[:-1]
return weather
+44
View File
@@ -0,0 +1,44 @@
import unittest
from locationdata import *
class TestGetWeather(unittest.TestCase):
def test_get_weather_with_valid_coordinates(self):
# Test with valid coordinates
lat = "37.7749"
lon = "-122.4194"
weather = get_weather(lat, lon)
print(f"weather: {weather}")
self.assertNotEqual(weather, NO_DATA_NOGPS)
self.assertNotEqual(weather, ERROR_FETCHING_DATA)
def test_get_weather_with_invalid_coordinates(self):
# Test with invalid coordinates
lat = 0
lon = 0
weather = get_weather(lat, lon)
print(f"weather: {weather}")
self.assertEqual(weather, NO_DATA_NOGPS)
def test_where_am_i_with_valid_coordinates(self):
# Test with invalid coordinates
lat = "37.7749"
lon = "-122.4194"
location = where_am_i(lat, lon)
print(f"location: {location}")
self.assertEqual(location, "South Van Ness Avenue San Francisco California 94103 United States Grid: CM87ss")
self.assertNotEqual(location, NO_DATA_NOGPS)
self.assertNotEqual(location, ERROR_FETCHING_DATA)
def test_get_tide_with_valid_coordinates(self):
# Test with valid coordinates
lat = "37.7749"
lon = "-122.4194"
tide = get_tide(lat, lon)
print(f"tide: {tide}")
self.assertNotEqual(tide, NO_DATA_NOGPS)
self.assertNotEqual(tide, ERROR_FETCHING_DATA)
if __name__ == '__main__':
unittest.main()
+6 -2
View File
@@ -1,16 +1,20 @@
# /etc/systemd/system/meshbot.service
# sudo systemctl daemon-reload
# sudo systemctl start meshbot.service
[Unit]
Description=MESH-BOT
After=network.target
[Service]
ExecStart=/usr/bin/python /usr/local/meshing-around/mesh-bot.py
ExecStart=/usr/bin/python /usr/local/meshing-around/mesh_bot.py
# Disable Python's buffering of STDOUT and STDERR, so that output from the
# service shows up immediately in systemd's logs
Environment=PYTHONUNBUFFERED=1
Restart=on-failure
Type=notify
Type=notify #try simple if any problems
[Install]
WantedBy=default.target
Executable → Regular
View File
Executable → Regular
View File
+1
View File
@@ -7,3 +7,4 @@ geopy
maidenhead
beautifulsoup4
dadjokes
mock