Refactoring work to make this a real program

This commit is contained in:
bspeice 2016-05-17 10:40:23 -04:00
parent 5853c86a2d
commit fcc280b96c
13 changed files with 215 additions and 174 deletions

View File

@ -13,23 +13,7 @@
<ConfirmationsSetting value="0" id="Add" /> <ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" /> <ConfirmationsSetting value="0" id="Remove" />
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="Python 3.5.1 (C:\Users\Bradlee Speice\Anaconda3\python.exe)" project-jdk-type="Python SDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" default="false" assert-keyword="true" jdk-15="true" project-jdk-name="Python 3.5.1 (C:\Users\Bradlee Speice\Anaconda3\python.exe)" project-jdk-type="Python SDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
<component name="masterDetails">
<states>
<state key="ProjectJDKs.UI">
<settings>
<last-edited>Python 3.5.1 (C:\Users\Bradlee Speice\Anaconda3\python.exe)</last-edited>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
</states>
</component>
</project> </project>

View File

@ -1,12 +1,15 @@
# Format: (all args are passed to __init__ as kwargs # Format (all args are passed to __init__ as kwargs:
# #
# <mountpoint>: # <mountpoint>:
# class: <feed_class> # class: <feed_class>
# args: # args:
# key: value # key: value
subfactory-show: server:
package: bassdrive port: 10000
class: BassdriveFeed
podcasts:
subfactory-show:
class: podcasters.BassdriveFeed
args: args:
url: http://archives.bassdrivearchive.com/1%20-%20Monday/Subfactory%20Show%20-%20DJ%20Spim/ url: http://archives.bassdrivearchive.com/1%20-%20Monday/Subfactory%20Show%20-%20DJ%20Spim/
logo: http://www.bassdrive.com/img/radio_schedule_entries/image/original/subfactory-web-add-56.jpg logo: http://www.bassdrive.com/img/radio_schedule_entries/image/original/subfactory-web-add-56.jpg

View File

@ -2,7 +2,9 @@
<module type="PYTHON_MODULE" version="4"> <module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true"> <component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>

View File

@ -1,30 +0,0 @@
"""
Given a configuration file, set up everything needed to kick
off the server.
"""
from importlib import import_module
import yaml
from pyramid.config import Configurator
from os.path import expanduser, join
# Needed for import_module call
# noinspection PyUnresolvedReferences
import modules
def build_configuration(conf=None) -> Configurator:
if conf is None:
conf = join(expanduser('~'), '.repodrc')
with open(conf) as conf_file:
conf_dict = yaml.load(conf_file)
server_conf = Configurator()
for mountpoint, feed in conf_dict.items():
feed_package = import_module('modules.' + feed['package'])
feed_class = getattr(feed_package, feed['class'])
feed_instance = feed_class(**feed['args'])
server_conf.add_route(mountpoint, '/' + mountpoint + '/')
server_conf.add_view(feed_instance.view, route_name=mountpoint)
return server_conf

View File

@ -1,10 +0,0 @@
from wsgiref.simple_server import make_server
from conf_parser import build_configuration
def start_server():
app = build_configuration().make_wsgi_app()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
if __name__ == '__main__':
start_server()

38
src/conf_parser.py Normal file
View File

@ -0,0 +1,38 @@
"""
Given a configuration file, set up everything needed to kick
off the server.
"""
from importlib import import_module
import yaml
from pyramid.config import Configurator
def build_configurator(podcasts: dict) -> Configurator:
server_conf = Configurator()
for mountpoint, feed in podcasts:
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'])
server_conf.add_route(mountpoint, '/' + mountpoint + '/')
server_conf.add_view(feed_instance.view, route_name=mountpoint)
def build_configuration_text(file_str: str) -> (dict, Configurator):
conf_dict = yaml.load(file_str)
server_opts = conf_dict.get('server', None)
podcasts = build_configurator(conf_dict['podcasts'])
return server_opts, podcasts
def build_configuration(file_name) -> (dict, Configurator):
try:
with open(file_name) as conf_file:
return build_configuration_text(conf_file.read())
except FileNotFoundError:
print("Could not locate configuration file " +
"(does {} exist?)".format(file_name))
raise

View File

@ -11,6 +11,7 @@ class BasePodcast():
"Return a list of all episodes, in descending date order" "Return a list of all episodes, in descending date order"
pass pass
# noinspection PyUnusedLocal
def view(self, request): def view(self, request):
fg = self.build_feed() fg = self.build_feed()
response = Response(fg.rss_str(pretty=True)) response = Response(fg.rss_str(pretty=True))

View File

@ -1,22 +1,26 @@
""" """
Podcast provider for the Bassdrive Archives Podcast provider for the Bassdrive Archives
""" """
from datetime import datetime
from html.parser import HTMLParser from html.parser import HTMLParser
from urllib.parse import unquote from urllib.parse import unquote
import requests import requests
from feedgen.feed import FeedGenerator from feedgen.feed import FeedGenerator
from podcast import BasePodcast
from datetime import datetime
from pytz import UTC from pytz import UTC
from podcasters.base import BasePodcast
class BassdriveParser(HTMLParser): class BassdriveParser(HTMLParser):
def error(self, message):
return super().error(message)
record_link_text = False record_link_text = False
link_url = '' link_url = ''
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
# noinspection PyArgumentList
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.links = [] self.links = []
@ -62,7 +66,6 @@ class BassdriveFeed(BasePodcast):
# And turn them into something usable # And turn them into something usable
fg = FeedGenerator() fg = FeedGenerator()
#fg.load_extension('podcast')
fg.id(self.url) fg.id(self.url)
fg.title(self.title) fg.title(self.title)
fg.description(self.title) fg.description(self.title)
@ -79,8 +82,8 @@ class BassdriveFeed(BasePodcast):
fe.enclosure(self.url + link[1], 0, 'audio/mpeg') fe.enclosure(self.url + link[1], 0, 'audio/mpeg')
# Bassdrive always uses date strings of # Bassdrive always uses date strings of
# [yyyy.mm.dd] with 0 padding, so that # [yyyy.mm.dd] with 0 padding on days and months,
# makes our lives easy # so that makes our lives easy
date_start = link[0].find('[') date_start = link[0].find('[')
date_str = link[0][date_start:date_start+12] date_str = link[0][date_start:date_start+12]
published = datetime.strptime(date_str, '[%Y.%m.%d]') published = datetime.strptime(date_str, '[%Y.%m.%d]')

38
src/server.py Normal file
View File

@ -0,0 +1,38 @@
import argparse
from wsgiref.simple_server import make_server
from conf_parser import build_configuration
from os.path import expanduser, join
# noinspection PyUnresolvedReferences
def start_server(cmd_args: dict):
try:
server_conf, configurator = build_configuration(cmd_args.configuration)
app = configurator.make_wsgi_app()
server = make_server(cmd_args.host, cmd_args.port, app)
server.serve_forever()
except FileNotFoundError:
print("Unable to find configuration file. Does {} exist?"
.format(cmd_args.configuration))
except AttributeError:
print("Unable to parse configuration file. Is {} a valid YML file?"
.format(cmd_args.configuration))
except KeyError:
print('Unable to parse configuration file. Is there a `podcasts`'
'section?')
if __name__ == '__main__':
default_rc = join(expanduser('~'), '.repodrc')
parser = argparse.ArgumentParser()
parser.add_argument('--verbose', 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',
help='Host address to start the server')
parser.add_argument('--configuration', type=str, default=default_rc,
help='Configuration file to start the server')
args = parser.parse_args()
start_server(args)

0
src/tests/__init__.py Normal file
View File

View File

@ -0,0 +1,12 @@
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