cleared up a lot of boilerplate with lazy properties
This commit is contained in:
parent
206027073c
commit
6b9cf85fc5
|
@ -3,6 +3,7 @@ import os
|
||||||
import mutagen
|
import mutagen
|
||||||
import abc
|
import abc
|
||||||
from media.monitor.exceptions import BadSongFile
|
from media.monitor.exceptions import BadSongFile
|
||||||
|
from media.monitor.pure import LazyProperty
|
||||||
|
|
||||||
class PathChannel(object):
|
class PathChannel(object):
|
||||||
"""a dumb struct; python has no record types"""
|
"""a dumb struct; python has no record types"""
|
||||||
|
@ -18,32 +19,21 @@ class HasMetaData(object):
|
||||||
__metaclass__ = abc.ABCMeta
|
__metaclass__ = abc.ABCMeta
|
||||||
# doing weird bullshit here because python constructors only
|
# doing weird bullshit here because python constructors only
|
||||||
# call the constructor of the leftmost superclass.
|
# call the constructor of the leftmost superclass.
|
||||||
@property
|
@LazyProperty
|
||||||
def metadata(self):
|
def metadata(self):
|
||||||
# Normally this would go in init but we don't like
|
# Normally this would go in init but we don't like
|
||||||
# relying on consumers of this behaviour to have to call
|
# relying on consumers of this behaviour to have to call
|
||||||
# the constructor
|
# the constructor
|
||||||
if not hasattr(self,"_loaded"): self._loaded = False
|
|
||||||
if self._loaded: return self._metadata
|
|
||||||
else:
|
|
||||||
f = None
|
|
||||||
try: f = mutagen.File(self.path, easy=True)
|
try: f = mutagen.File(self.path, easy=True)
|
||||||
except Exception: raise BadSongFile(self.path)
|
except Exception: raise BadSongFile(self.path)
|
||||||
# value returned by mutagen only acts like a dictionary.
|
metadata = {}
|
||||||
# in fact it comes with a nice surprise for you if you try
|
|
||||||
# to add elements to it
|
|
||||||
self._metadata = {}
|
|
||||||
for k,v in f:
|
for k,v in f:
|
||||||
|
# Special handling of attributes here
|
||||||
if isinstance(v, list):
|
if isinstance(v, list):
|
||||||
if len(v) == 1:
|
if len(v) == 1: metadata[k] = v[0]
|
||||||
self._metadata[k] = v[0]
|
else: raise Exception("Weird mutagen %s:%s" % (k,str(v)))
|
||||||
else:
|
else: metadata[k] = v
|
||||||
raise Exception("Weird mutagen %s:%s" % (k,str(v)))
|
return metadata
|
||||||
else:
|
|
||||||
self._metadata[k] = v
|
|
||||||
self._loaded = True
|
|
||||||
return self.metadata
|
|
||||||
|
|
||||||
|
|
||||||
class BaseEvent(object):
|
class BaseEvent(object):
|
||||||
__metaclass__ = abc.ABCMeta
|
__metaclass__ = abc.ABCMeta
|
||||||
|
|
|
@ -10,6 +10,12 @@ class Handles(object):
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def handle(self, sender, event, *args, **kwargs): pass
|
def handle(self, sender, event, *args, **kwargs): pass
|
||||||
|
|
||||||
|
|
||||||
|
# TODO : remove the code duplication between ReportHandler and
|
||||||
|
# ProblemFileHandler. Namely the part where both initialize pydispatch
|
||||||
|
# TODO : Investigate whether weak reffing in dispatcher.connect could possibly
|
||||||
|
# cause a memory leak
|
||||||
|
|
||||||
class ReportHandler(Handles):
|
class ReportHandler(Handles):
|
||||||
__metaclass__ = abc.ABCMeta
|
__metaclass__ = abc.ABCMeta
|
||||||
def __init__(self, signal):
|
def __init__(self, signal):
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import logging
|
import logging
|
||||||
import abc
|
import abc
|
||||||
|
from media.monitor.pure import LazyProperty
|
||||||
|
|
||||||
logger = logging.getLogger('mediamonitor2')
|
logger = logging.getLogger('mediamonitor2')
|
||||||
logging.basicConfig(filename='/home/rudi/throwaway/mm2.log', level=logging.DEBUG)
|
logging.basicConfig(filename='/home/rudi/throwaway/mm2.log', level=logging.DEBUG)
|
||||||
|
|
||||||
class Loggable(object):
|
class Loggable(object):
|
||||||
__metaclass__ = abc.ABCMeta
|
__metaclass__ = abc.ABCMeta
|
||||||
@property
|
# TODO : replace this boilerplate with LazyProperty
|
||||||
|
@LazyProperty
|
||||||
def logger(self):
|
def logger(self):
|
||||||
if not hasattr(self,"_logger"): self._logger = logging.getLogger('mediamonitor2')
|
if not hasattr(self,"_logger"): self._logger = logging.getLogger('mediamonitor2')
|
||||||
return self._logger
|
return self._logger
|
||||||
|
|
|
@ -5,6 +5,21 @@ import shutil
|
||||||
supported_extensions = ["mp3", "ogg"]
|
supported_extensions = ["mp3", "ogg"]
|
||||||
unicode_unknown = u'unknown'
|
unicode_unknown = u'unknown'
|
||||||
|
|
||||||
|
class LazyProperty(object):
|
||||||
|
"""
|
||||||
|
meant to be used for lazy evaluation of an object attribute.
|
||||||
|
property should represent non-mutable data, as it replaces itself.
|
||||||
|
"""
|
||||||
|
def __init__(self,fget):
|
||||||
|
self.fget = fget
|
||||||
|
self.func_name = fget.__name__
|
||||||
|
|
||||||
|
def __get__(self,obj,cls):
|
||||||
|
if obj is None: return None
|
||||||
|
value = self.fget(obj)
|
||||||
|
setattr(obj,self.func_name,value)
|
||||||
|
return value
|
||||||
|
|
||||||
class IncludeOnly(object):
|
class IncludeOnly(object):
|
||||||
"""
|
"""
|
||||||
A little decorator to help listeners only be called on extensions they support
|
A little decorator to help listeners only be called on extensions they support
|
||||||
|
|
|
@ -7,7 +7,10 @@ from media.monitor.handler import ReportHandler
|
||||||
from media.monitor.events import NewFile, DeleteFile
|
from media.monitor.events import NewFile, DeleteFile
|
||||||
from media.monitor.log import Loggable
|
from media.monitor.log import Loggable
|
||||||
from media.monitor.exceptions import BadSongFile
|
from media.monitor.exceptions import BadSongFile
|
||||||
from media.monitor.airtime import Request
|
import media.monitor.pure as mmp
|
||||||
|
from media.monitor.pure import LazyProperty
|
||||||
|
|
||||||
|
import api_clients.api_client as ac
|
||||||
|
|
||||||
class RequestSync(threading.Thread,Loggable):
|
class RequestSync(threading.Thread,Loggable):
|
||||||
def __init__(self, watcher, requests):
|
def __init__(self, watcher, requests):
|
||||||
|
@ -15,11 +18,14 @@ class RequestSync(threading.Thread,Loggable):
|
||||||
self.watcher = watcher
|
self.watcher = watcher
|
||||||
self.requests = requests
|
self.requests = requests
|
||||||
|
|
||||||
|
@LazyProperty
|
||||||
|
def apiclient(self):
|
||||||
|
return ac.AirTimeApiClient()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# TODO : implement proper request sending
|
# TODO : implement proper request sending
|
||||||
self.logger.info("launching request with %d items." % len(self.requests))
|
self.logger.info("launching request with %d items." % len(self.requests))
|
||||||
try: Request.serialize(self.requests).send()
|
# self.apiclient.update_media_metadata(self
|
||||||
except: self.logger.info("Failed to send request...")
|
|
||||||
self.watcher.flag_done()
|
self.watcher.flag_done()
|
||||||
|
|
||||||
class TimeoutWatcher(threading.Thread,Loggable):
|
class TimeoutWatcher(threading.Thread,Loggable):
|
||||||
|
@ -55,6 +61,7 @@ class WatchSyncer(ReportHandler,Loggable):
|
||||||
# trying to send the http requests in order
|
# trying to send the http requests in order
|
||||||
self.__requests = []
|
self.__requests = []
|
||||||
self.request_running = False
|
self.request_running = False
|
||||||
|
# we don't actually use this "private" instance variable anywhere
|
||||||
self.__current_thread = None
|
self.__current_thread = None
|
||||||
tc = TimeoutWatcher(self, timeout)
|
tc = TimeoutWatcher(self, timeout)
|
||||||
tc.daemon = True
|
tc.daemon = True
|
||||||
|
|
|
@ -6,8 +6,7 @@ from media.monitor.organizer import Organizer
|
||||||
from media.monitor.events import PathChannel
|
from media.monitor.events import PathChannel
|
||||||
from media.monitor.watchersyncer import WatchSyncer
|
from media.monitor.watchersyncer import WatchSyncer
|
||||||
from media.monitor.handler import ProblemFileHandler
|
from media.monitor.handler import ProblemFileHandler
|
||||||
from media.monitor.bootstrap import Bootstrapper
|
#from media.monitor.bootstrap import Bootstrapper
|
||||||
from media.monitor.airtime import DBDumper, Connection
|
|
||||||
|
|
||||||
channels = {
|
channels = {
|
||||||
# note that org channel still has a 'watch' path because that is the path
|
# note that org channel still has a 'watch' path because that is the path
|
||||||
|
@ -22,11 +21,11 @@ org = Organizer(channel=channels['org'],target_path=channels['watch'].path)
|
||||||
watch = WatchSyncer(channel=channels['watch'])
|
watch = WatchSyncer(channel=channels['watch'])
|
||||||
problem_files = ProblemFileHandler(channel=channels['badfile'])
|
problem_files = ProblemFileHandler(channel=channels['badfile'])
|
||||||
# do the bootstrapping before any listening is going one
|
# do the bootstrapping before any listening is going one
|
||||||
conn = Connection('localhost', 'more', 'shit', 'here')
|
#conn = Connection('localhost', 'more', 'shit', 'here')
|
||||||
db = DBDumper(conn).dump_block()
|
#db = DBDumper(conn).dump_block()
|
||||||
bs = Bootstrapper(db, [channels['org']], [channels['watch']])
|
#bs = Bootstrapper(db, [channels['org']], [channels['watch']])
|
||||||
bs.flush_organize()
|
#bs.flush_organize()
|
||||||
bs.flush_watch()
|
#bs.flush_watch()
|
||||||
|
|
||||||
wm = pyinotify.WatchManager()
|
wm = pyinotify.WatchManager()
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0653ec0b89362921f075af96ee8772538b801a7c
|
Subproject commit 492242f4bb7367afebbf2f096067cb5a5d3c0449
|
Loading…
Reference in New Issue