diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..7ca7387 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: python +python: + - "3.2" + - "3.3" + - "3.4" + - "3.5" + +script: nosetests --with-doctest \ No newline at end of file diff --git a/Requirements b/requirements.txt similarity index 100% rename from Requirements rename to requirements.txt diff --git a/src/conf_parser.py b/src/conf_parser.py index 5f75322..9233940 100644 --- a/src/conf_parser.py +++ b/src/conf_parser.py @@ -10,15 +10,17 @@ from pyramid.config import Configurator def build_configurator(podcasts: dict) -> Configurator: server_conf = Configurator() - for mountpoint, feed in podcasts: + for mountpoint, feed in podcasts.items(): package, class_name = feed['class'].rsplit('.', 1) feed_package = import_module(package) feed_class = getattr(feed_package, class_name) - feed_instance = feed_class(**feed['args']) + feed_instance = feed_class(**feed) server_conf.add_route(mountpoint, '/' + mountpoint + '/') server_conf.add_view(feed_instance.view, route_name=mountpoint) + return server_conf + def build_configuration_text(file_str: str) -> (dict, Configurator): conf_dict = yaml.load(file_str) diff --git a/src/podcasters/bassdrive.py b/src/podcasters/bassdrive.py index 2672b0c..e2cf28a 100644 --- a/src/podcasters/bassdrive.py +++ b/src/podcasters/bassdrive.py @@ -25,6 +25,17 @@ class BassdriveParser(HTMLParser): self.links = [] def handle_starttag(self, tag, attrs): + """ + If we find an 'a' tag, make sure that we record + the next link we come across + + >>> b = BassdriveParser() + >>> b.handle_starttag('a', (('href', 'something.mp3'),)) + >>> b.record_link_text + True + >>> b.link_url + 'something.mp3' + """ href = '' for attr, val in attrs: if attr == 'href': @@ -35,6 +46,20 @@ class BassdriveParser(HTMLParser): self.link_url = href def handle_data(self, data): + """ + If we receive a new link, record it if we're inside an `a` tag + + >>> b = BassdriveParser() + >>> not b.get_links() + True + >>> b.handle_data("some_link") + >>> not b.get_links() + True + >>> b.handle_starttag('a', [['href', 'something.mp3']]) + >>> b.handle_data("some text") + >>> len(b.get_links()) == 1 + True + """ if self.record_link_text: self.links.append((data, self.link_url)) self.record_link_text = False @@ -44,13 +69,27 @@ class BassdriveParser(HTMLParser): return self.links def clear_links(self): + """ + For whatever reason, creating a new parser doesn't + clear out the old links. + + >>> import requests + >>> b = BassdriveParser() + >>> b.feed(str(requests.get('http://archives.bassdrivearchive.com/' +\ + '1%20-%20Monday/Subfactory%20Show%20-%20DJ%20Spim').content)) + >>> len(b.get_links()) > 0 + True + >>> b.clear_links() + >>> len(b.get_links()) == 0 + True + """ self.links = [] class BassdriveFeed(BasePodcast): def __init__(self, *args, **kwargs): self.url = kwargs['url'] - self.logo = kwargs['logo'] + self.logo = kwargs.get('logo', '') # Get the title and DJ while handling trailing slash url_pretty = unquote(self.url) elems = filter(lambda x: x, url_pretty.split('/')) @@ -90,5 +129,4 @@ class BassdriveFeed(BasePodcast): fe.pubdate(UTC.localize(published)) fe.guid((link[0])) - parser.clear_links() return fg diff --git a/src/server.py b/src/server.py index 377cf7a..823c9b9 100644 --- a/src/server.py +++ b/src/server.py @@ -1,32 +1,47 @@ import argparse -from wsgiref.simple_server import make_server -from conf_parser import build_configuration +import traceback from os.path import expanduser, join +from wsgiref.simple_server import make_server + +from pyramid.config import Configurator + +from conf_parser import build_configuration # noinspection PyUnresolvedReferences -def start_server(cmd_args: dict): +def start_server(server_conf: dict, configurator: Configurator) -> None: try: - server_conf, configurator = build_configuration(cmd_args.configuration) app = configurator.make_wsgi_app() - server = make_server(cmd_args.host, cmd_args.port, app) + port = server_conf['port'] if 'port' in server_conf else cmd_args.port + host = server_conf['host'] if 'host' in server_conf else cmd_args.host + server = make_server(host, port, app) + + if cmd_args.verbose: + print("Starting server {}:{}".format(host, port)) server.serve_forever() except FileNotFoundError: print("Unable to find configuration file. Does {} exist?" .format(cmd_args.configuration)) + if cmd_args.verbose: + print(traceback.format_exc()) except AttributeError: print("Unable to parse configuration file. Is {} a valid YML file?" .format(cmd_args.configuration)) + if cmd_args.verbose: + print(traceback.format_exc()) except KeyError: - print('Unable to parse configuration file. Is there a `podcasts`' + print('Unable to parse configuration file. Is there a `podcasts` ' 'section?') + if cmd_args.verbose: + print(traceback.format_exc()) if __name__ == '__main__': default_rc = join(expanduser('~'), '.repodrc') parser = argparse.ArgumentParser() - parser.add_argument('--verbose', help='Run server in verbose mode') + parser.add_argument('--verbose', action='store_true', + help='Run server in verbose mode') parser.add_argument('--port', type=int, default=10000, help='Port to use when starting the server') parser.add_argument('--host', type=str, default='0.0.0.0', @@ -35,4 +50,5 @@ if __name__ == '__main__': help='Configuration file to start the server') args = parser.parse_args() - start_server(args) + server_conf, configurator = build_configuration(args.configuration) + start_server(server_conf, configurator) diff --git a/src/tests/test_build_configurator.py b/src/tests/test_build_configurator.py deleted file mode 100644 index ca8e45e..0000000 --- a/src/tests/test_build_configurator.py +++ /dev/null @@ -1,12 +0,0 @@ -from unittest import TestCase -import conf_parser - - -class TestBuild_configurator(TestCase): - def test_build_configurator(self): - try: - # noinspection PyTypeChecker - conf_parser.build_configurator(None) - self.fail("Must have dictionary to set up configurator") - except TypeError: - pass \ No newline at end of file