diff --git a/README.md b/README.md index 2d9b3ce..6e69373 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ A simple python script to fetch cricket scores and send notifications. * beautifulSoup4 * requests * python2 only +* mock ## Installation ## ``sudo python setup.py install`` diff --git a/scorer/app.py b/scorer/app.py index 77b4fb2..3d20ede 100644 --- a/scorer/app.py +++ b/scorer/app.py @@ -1,33 +1,22 @@ -import logging from time import sleep - +import scorer.logger as logger import scorer.fetch_scores as fs import scorer.notification as notify from scorer.system import exitApp from scorer.ui import getUserInput +from scorer import config_reader -logger = logging.getLogger("scorer.app") -logger.setLevel(logging.DEBUG) -fh = logging.FileHandler("scorer.log") -fh.setLevel(logging.DEBUG) -ch = logging.StreamHandler() -ch.setLevel(logging.ERROR) -formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -\ - %(message)s') -fh.setFormatter(formatter) -ch.setFormatter(formatter) -logger.addHandler(fh) -logger.addHandler(ch) +logger = logger.get_logger('cricket-scores-api') -NO_LIVE_MATCHES = "No Match in progress" -SLEEP_INTERVAL = 60 +no_live_matches = config_reader.NO_LIVE_MATCHES +sleep_interval = config_reader.SLEEP_INTERVAL def main(): while True: logger.debug("Getting the xml and matches list") xml, matches = fs.findMatchesAvailable() - if matches[0] == NO_LIVE_MATCHES: + if matches[0] == no_live_matches: print "No Live matches are available now:" exitApp() matches.append("Quit the scorer app") @@ -50,7 +39,7 @@ def main(): logger.debug("Sending notification for: title:{} score:\ {}".format(title, score)) notify.popUpMessage(title, score) - sleep(SLEEP_INTERVAL) + sleep(sleep_interval) except KeyboardInterrupt: break diff --git a/scorer/config.json b/scorer/config.json new file mode 100644 index 0000000..88a23dd --- /dev/null +++ b/scorer/config.json @@ -0,0 +1,5 @@ +{ + "NO_LIVE_MATCHES": "No Match in progress", + "SLEEP_INTERVAL": 60, + "WON_STATUS": "won by" +} \ No newline at end of file diff --git a/scorer/config_reader.py b/scorer/config_reader.py new file mode 100644 index 0000000..84fc7ff --- /dev/null +++ b/scorer/config_reader.py @@ -0,0 +1,21 @@ +import json +import scorer.logger as logger +from scorer.system import exitApp + +logger = logger.get_logger("config-reader") + + +def read_json(file_path): + try: + with open(file_path.lower()) as json_data: + data = json.load(json_data) + return data + except FileNotFoundError as e: + logger.error("config file not found!!") + exitApp() + + +config_data = read_json("../scorer/config.json") +NO_LIVE_MATCHES = config_data["NO_LIVE_MATCHES"] +SLEEP_INTERVAL = config_data["SLEEP_INTERVAL"] +WON_STATUS = config_data["WON_STATUS"] diff --git a/scorer/fetch_scores.py b/scorer/fetch_scores.py index bbb2e4b..30233f8 100644 --- a/scorer/fetch_scores.py +++ b/scorer/fetch_scores.py @@ -1,12 +1,13 @@ -import logging +import scorer.logger as logger import re - import requests from bs4 import BeautifulSoup +from scorer.system import exitApp +from scorer import config_reader -logger = logging.getLogger('scorer.fetch_scores') +logger = logger.get_logger('scorer.fetch_scores') -WON_STATUS = "won by" +won_status = config_reader.WON_STATUS def getJsonURL(matchId): @@ -30,30 +31,40 @@ def getPlayingTeamNames(jsonurl): :return: teams playing """ logger.info("Url to get the json from {}".format(jsonurl)) - r = requests.get(jsonurl) + try: + r = requests.get(jsonurl) + except: + logger.error("not able to reach the site to get the match info!!") + exitApp() + jsonData = r.json() playingTeams = {team.get("team_id"): team.get("team_name\ ") for team in jsonData.get("team")} - logging.debug("playingTeams: {}".format(playingTeams)) + logger.debug("playingTeams: {}".format(playingTeams)) return playingTeams def getLastestScore(jsonurl, playingTeams): logger.info("Entry Point for getLastestScore") - logger.debug("Url to get the latest json is: {}" . format(jsonurl)) - r = requests.get(jsonurl) + logger.debug("Url to get the latest json is: {}".format(jsonurl)) + try: + r = requests.get(jsonurl) + except: + logger.error("not able to reach the site to get the match info!!") + exitApp() + jsonData = r.json() matchStatus = jsonData.get("live").get("status") logger.info("matchStatus: {}".format(matchStatus)) titleToDisplay = matchStatus scoreToDisplay = "" # Check if match Started - if(not jsonData.get("live").get("innings")): + if (not jsonData.get("live").get("innings")): logger.info("Match not started") return (titleToDisplay, scoreToDisplay) # Check if match over - if(WON_STATUS in matchStatus): + if (won_status in matchStatus): logger.info("Match over") return (titleToDisplay, scoreToDisplay) innings = jsonData.get("live").get("innings") @@ -105,9 +116,14 @@ def findMatchesAvailable(url="http://static.cricinfo.com/rss/livescores.xml"): :return: a tuple of xml and matches. """ logger.info("Entry point for findMatchesAvailable") - r = requests.get(url) + try: + r = requests.get(url) + except: + logger.error("not able to reach the site to get the match info!!") + exitApp() + soup = BeautifulSoup(r.text) xml = soup.find_all("item") matches = map(lambda item: re.sub(r'\s+', " ", re.sub('\ - [^A-Za-z ]+', '', item.title.text)), xml) + [^A-Za-z ]+', '', item.title.text)), xml) return (xml, matches) diff --git a/scorer/logger.py b/scorer/logger.py new file mode 100644 index 0000000..2e7953f --- /dev/null +++ b/scorer/logger.py @@ -0,0 +1,15 @@ +import sys +import logging + +def get_logger(name, level=logging.INFO): + logger = logging.getLogger(name) + logger.setLevel(level) + if logger.handlers: + pass + else: + ch = logging.StreamHandler(sys.stderr) + ch.setLevel(level) + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + ch.setFormatter(formatter) + logger.addHandler(ch) + return logger \ No newline at end of file diff --git a/scorer/notification.py b/scorer/notification.py index 362d99f..9674178 100644 --- a/scorer/notification.py +++ b/scorer/notification.py @@ -1,20 +1,16 @@ -import logging - -import pynotify - +import scorer.logger as logger +from sys import version_info from scorer.system import exitApp +import subprocess as sp -logger = logging.getLogger('scorer.notification') +logger = logger.get_logger('scorer.notification') def popUpMessage(title, message): - logger.info("Initializing pynotify") try: - pynotify.init("Scorer") - pynotify.Notification(title, message, "dialog-information").show() + command = ['notify-send', title, message] + pipe = sp.call(command) + logger.info("pop up message sent!!") except Exception as e: - logger.error("Error initializing pynotify") logger.debug(e) - logger.info("Unable to initialize pynotify: Connection Refused") - logger.info("Quitting the app") exitApp() diff --git a/scorer/ui.py b/scorer/ui.py index 82f8bdf..3390dff 100644 --- a/scorer/ui.py +++ b/scorer/ui.py @@ -1,8 +1,8 @@ from curses import wrapper import curses -import logging +import scorer.logger as logger -logger = logging.getLogger('scorer.ui') +logger = logger.get_logger('scorer.ui') def printGames(stdscr, matches, selected): @@ -26,15 +26,15 @@ def main(stdscr, matches): printGames(stdscr, matches, selected) event = stdscr.getch() if event == ord("\n"): - logging.info("Enter key pressed") + logger.info("Enter key pressed") return selected elif event == curses.KEY_UP: - logging.info("Up key pressed") + logger.info("Up key pressed") if selected != 0: selected -= 1 printGames(stdscr, matches, selected) elif event == curses.KEY_DOWN: - logging.info("Down key pressed") + logger.info("Down key pressed") if selected != len(matches) - 1: selected += 1 printGames(stdscr, matches, selected) diff --git a/setup.py b/setup.py index 39f223f..4a346f3 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ def readme(): install_requires=[ 'requests', 'beautifulsoup4', - 'pynotify' + 'mock' ], entry_points={ 'console_scripts': [ diff --git a/test/test_config_reader.py b/test/test_config_reader.py new file mode 100644 index 0000000..92ef0fb --- /dev/null +++ b/test/test_config_reader.py @@ -0,0 +1,25 @@ +# export the PYTHONPATH till the project folder as I added another folder test for writing the test cases and Python +# wouldn't be able to recognize the other packages. +# export PYTHONPATH=$PYTHONPATH:/Users/hmandadi/Documents/harsh/scorer.py/ +# Run test case from scorer/ folder +# python -m unittest discover ../test/ + +import unittest +from mock import MagicMock +import scorer.config_reader as config_reader + + +class ConfigReaderTestCases(unittest.TestCase): + + def test_wrong_json_path(self): + config_reader.read_json = MagicMock(return_value=str('No such file or directory')) + self.assertEqual(config_reader.read_json('/path/not/found/'), 'No such file or directory') + + def test_json_file_unable_to_open(self): + config_reader.read_json = MagicMock(return_value=str('No JSON object could be decoded')) + self.assertEqual(config_reader.read_json('/filenotabletoberead/sample-template.abc'), + 'No JSON object could be decoded') + + +if __name__ == '__main__': + unittest.main()