patternpythonMinor
Simple CodeReview Questions Notifications for OSX
Viewed 0 times
simpleosxcodereviewquestionsnotificationsfor
Problem
Some days ago, I figured out that I'd like to get a notification every time a new question is asked here. So, I've made a really simple Python script, which uses
I'd like to get some feedback regarding anything that comes to your mind, including good practices. That's not a complicated piece of code, but I'd like some feedback on it anyway.
pync (only OSX compatible) to do that for me.I'd like to get some feedback regarding anything that comes to your mind, including good practices. That's not a complicated piece of code, but I'd like some feedback on it anyway.
import stackexchange
import time
from pync import Notifier
def get_notifications():
"""This method uses the SE API and pops up a notification everytime a new question is asked on CR"""
cr = stackexchange.Site(stackexchange.CodeReview)
old = []
while True:
questions = cr.recent_questions(filter='_b')
for question in questions[:1]:
if question.title not in old:
old.append(question.title)
Notifier.notify('Votes: {0} | Answers: {1} | Views: {2}'.format(
question.score, len(question.answers), question.view_count),
title='CodeReview: {0}'.format(question.title),
subtitle='Tags: {0}'.format(', '.join(question.tags)),
sound='default',
open=question.url)
else:
continue
time.sleep(2)
if __name__ == '__main__':
get_notifications()Solution
Nitpicks
Reusability
As it stand, I can't use this script because it is too much tied to your OSX only notifier. I'd rather
Something like:
Should be enough. Note that I import modules each time a new question appears, which is not ideal, but at least it let you easily deal with modules that are not present on the system. And the few extra time spent realizing the module is already loaded is negligible compared to your
On the reusability side, it could also be good to be able to parametrize the generator with the site the user whish to fetch:
Better usage of the
The
will be a direct call to the SE API on questions.
From there, two things worth noting:
Sorting results
The advantage of using
Asking for questions asked after a given date
The
Proposed improvements
```
import stackexchange
import datetime
import time
def pync_notify(question):
from pync import Notifier
Notifier.notify('Votes: {0} | Answers: {1} | Views: {2}'.format(
question.score, len(question.answers), question.view_count),
title='CodeReview: {0}'.format(question.title),
subtitle='Tags: {0}'.format(', '.join(question.tags)),
sound='default', open=question.url)
def gtk_notify(question):
from gi.repository import Notify
Notify.init('stackexchange')
notification = Notify.Notification.new(
'CodeReview: {}'.format(question.title),
'Votes: {} | Answers: {} | Views: {}'.format(
question.score, len(question.answers), question.view_count),
'dialog-information')
notification.show()
def now():
"""Return the current timestamp"""
date = datetime.datetime.now()
return int(date.timestamp())
def get_questions(site=stackexchange.CodeReview, query_delay=2):
"""Fetch recent questions from the Stack Exchange network
This function uses the SE API and yield each
new question that is asked on the given site.
"""
se = site()
last_query = now()
while True:
fromdate, last_query = last_query, now()
questions = se.questions(fromdate=fromdate, sort='creation')
yield from questions
time.sleep(query_delay)
if __name__ == '__main__':
for question in get_q
- Maximum line length should be 72 characters for docstrings.
- For your
oldvariable, you may wan to use asetinstead of alistto check for existence (not in) as it will be \$O(1)\$ instead of \$O(n)\$.
Reusability
As it stand, I can't use this script because it is too much tied to your OSX only notifier. I'd rather
yield questions from get_notifications (which will not be greatly named after that) and format them elsewhere, letting other users handle it with other notifications systems (or even email, for that matter).Something like:
import stackexchange
import time
def pync_notify(question):
from pync import Notifier
Notifier.notify('Votes: {0} | Answers: {1} | Views: {2}'.format(
question.score, len(question.answers), question.view_count),
title='CodeReview: {0}'.format(question.title),
subtitle='Tags: {0}'.format(', '.join(question.tags)),
sound='default', open=question.url)
def gtk_notify(question):
from gi.repository import Notify
Notify.init('stackexchange')
notification = Notify.Notification.new(
'CodeReview: {}'.format(question.title),
'Votes: {} | Answers: {} | Views: {}'.format(
question.score, len(question.answers), question.view_count),
'dialog-information')
notification.show()
def get_questions():
"""Fetch recent questions from CodeReview
This function uses the SE API and yield each
new question that is asked on CR.
"""
cr = stackexchange.Site(stackexchange.CodeReview)
old = {}
while True:
questions = cr.recent_questions(filter='_b')
for question in questions[:1]:
if question.title not in old:
old.add(question.title)
yield question
time.sleep(2)
if __name__ == '__main__':
for question in get_questions():
pync_notify(question)Should be enough. Note that I import modules each time a new question appears, which is not ideal, but at least it let you easily deal with modules that are not present on the system. And the few extra time spent realizing the module is already loaded is negligible compared to your
time.sleep(2) anyway. You may want to use classes with a __call__ method if you really want to import and initialize only once.On the reusability side, it could also be good to be able to parametrize the generator with the site the user whish to fetch:
def get_questions(site=stackexchange.CodeReview):
se = stackexchange.Site(site)
…Better usage of the
stackexchange APIThe
stackexchange module let you directly query information using "site classes" (such as stackexchange.CodeReview) without necessarily relying on a stackexchange.Site object. So:CR = stackexchange.CodeReview()
CR.questions()will be a direct call to the SE API on questions.
From there, two things worth noting:
- The sort method;
- The fromdate parameter.
Sorting results
The advantage of using
sort='creation' in the query parameters is that you only need to store the last asked question in your old variable. You can then iterate over the result of the query and stop when q.title == old.title without storing previous questions anymore.Asking for questions asked after a given date
The
fromdate parameter takes a timestamp and make the query returns only questions asked after that point in time. There is no real need for sorting anymore, all you need to remember is the date at when the last query was made.Proposed improvements
```
import stackexchange
import datetime
import time
def pync_notify(question):
from pync import Notifier
Notifier.notify('Votes: {0} | Answers: {1} | Views: {2}'.format(
question.score, len(question.answers), question.view_count),
title='CodeReview: {0}'.format(question.title),
subtitle='Tags: {0}'.format(', '.join(question.tags)),
sound='default', open=question.url)
def gtk_notify(question):
from gi.repository import Notify
Notify.init('stackexchange')
notification = Notify.Notification.new(
'CodeReview: {}'.format(question.title),
'Votes: {} | Answers: {} | Views: {}'.format(
question.score, len(question.answers), question.view_count),
'dialog-information')
notification.show()
def now():
"""Return the current timestamp"""
date = datetime.datetime.now()
return int(date.timestamp())
def get_questions(site=stackexchange.CodeReview, query_delay=2):
"""Fetch recent questions from the Stack Exchange network
This function uses the SE API and yield each
new question that is asked on the given site.
"""
se = site()
last_query = now()
while True:
fromdate, last_query = last_query, now()
questions = se.questions(fromdate=fromdate, sort='creation')
yield from questions
time.sleep(query_delay)
if __name__ == '__main__':
for question in get_q
Code Snippets
import stackexchange
import time
def pync_notify(question):
from pync import Notifier
Notifier.notify('Votes: {0} | Answers: {1} | Views: {2}'.format(
question.score, len(question.answers), question.view_count),
title='CodeReview: {0}'.format(question.title),
subtitle='Tags: {0}'.format(', '.join(question.tags)),
sound='default', open=question.url)
def gtk_notify(question):
from gi.repository import Notify
Notify.init('stackexchange')
notification = Notify.Notification.new(
'CodeReview: {}'.format(question.title),
'Votes: {} | Answers: {} | Views: {}'.format(
question.score, len(question.answers), question.view_count),
'dialog-information')
notification.show()
def get_questions():
"""Fetch recent questions from CodeReview
This function uses the SE API and yield each
new question that is asked on CR.
"""
cr = stackexchange.Site(stackexchange.CodeReview)
old = {}
while True:
questions = cr.recent_questions(filter='_b')
for question in questions[:1]:
if question.title not in old:
old.add(question.title)
yield question
time.sleep(2)
if __name__ == '__main__':
for question in get_questions():
pync_notify(question)def get_questions(site=stackexchange.CodeReview):
se = stackexchange.Site(site)
…CR = stackexchange.CodeReview()
CR.questions()import stackexchange
import datetime
import time
def pync_notify(question):
from pync import Notifier
Notifier.notify('Votes: {0} | Answers: {1} | Views: {2}'.format(
question.score, len(question.answers), question.view_count),
title='CodeReview: {0}'.format(question.title),
subtitle='Tags: {0}'.format(', '.join(question.tags)),
sound='default', open=question.url)
def gtk_notify(question):
from gi.repository import Notify
Notify.init('stackexchange')
notification = Notify.Notification.new(
'CodeReview: {}'.format(question.title),
'Votes: {} | Answers: {} | Views: {}'.format(
question.score, len(question.answers), question.view_count),
'dialog-information')
notification.show()
def now():
"""Return the current timestamp"""
date = datetime.datetime.now()
return int(date.timestamp())
def get_questions(site=stackexchange.CodeReview, query_delay=2):
"""Fetch recent questions from the Stack Exchange network
This function uses the SE API and yield each
new question that is asked on the given site.
"""
se = site()
last_query = now()
while True:
fromdate, last_query = last_query, now()
questions = se.questions(fromdate=fromdate, sort='creation')
yield from questions
time.sleep(query_delay)
if __name__ == '__main__':
for question in get_questions():
pync_notify(question)Context
StackExchange Code Review Q#142538, answer score: 8
Revisions (0)
No revisions yet.