]> git.parisson.com Git - timeside.git/commitdiff
replace the core with the new core:
authorOlivier Guilyardi <olivier@samalyse.com>
Thu, 26 Nov 2009 20:36:58 +0000 (20:36 +0000)
committerOlivier Guilyardi <olivier@samalyse.com>
Thu, 26 Nov 2009 20:36:58 +0000 (20:36 +0000)
- requires absolutely no change in the encode, decode, analyze and graph code
- the test scripts needed a few changes

core.py
newcore.py [deleted file]
tests/test.py
tests/testnewcore.py

diff --git a/core.py b/core.py
index 96b1347fc46f19cc5fc2097cace9bdf18df5f99f..9b91d97164f832012b925f301a9736e6fc55fdfc 100644 (file)
--- a/core.py
+++ b/core.py
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) 2007 Samalyse SARL
-# Copyright (C) 2003-2005 Edgewall Software
-# Copyright (C) 2003-2004 Jonas Borgström <jonas@edgewall.com>
-# Copyright (C) 2004-2005 Christopher Lenz <cmlenz@gmx.de>
-# All rights reserved.
+# Copyright (c) 2009 Olivier Guilyardi <olivier@samalyse.com>
 #
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in
-#    the documentation and/or other materials provided with the
-#    distribution.
-#3. The name of the author may not be used to endorse or promote
-#   products derived from this software without specific prior
-#   written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
-#OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-#ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-#DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-#DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
-#GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-#IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-#OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-#IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# This file is part of TimeSide.
 
-# Author: Jonas Borgström <jonas@edgewall.com>
-#         Christopher Lenz <cmlenz@gmx.de>
-#         Olivier Guilyardi <olivier@samalyse.com>
+# TimeSide is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
 
+# TimeSide is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
 
-__all__ = ['Component', 'ExtensionPoint', 'implements', 'Interface',
-           'TimeSideError']
+# You should have received a copy of the GNU General Public License
+# along with TimeSide.  If not, see <http://www.gnu.org/licenses/>.
 
 
+
+# This file defines an object interface mechanism and a way to determine
+# which components implements a given interface
+#
+# For example, the following defines the Music class as implementing the
+# listenable interface.
+#
+# class Listenable(Interface):
+#     pass
+#
+# class Music(Component):
+#    implements(Listenable)
+#
+# Several class can implements a such interface, and it is possible to 
+# discover which class implements it with implementations():
+#
+# list_of_classes = implementations(Listenable)
+#
+# This mechanism support inheritance of both interfaces and components:
+#
+# - all descendants of a class implementing a given interface are also considered
+#   to implement this interface
+# - a class implementing a given interface is also considered to implement all
+#   the ascendants of this interface
+
+__all__ = ['Component', 'implements', 'Interface', 'implementations', 'TimeSideError']
+
 class TimeSideError(Exception):
     """Exception base class for errors in TimeSide."""
     # FIXME: is this redundant with Django's error handling ?
-
-#    def __init__(self, message, title=None, show_traceback=False):
-#        Exception.__init__(self, message)
-#        self.message = message
-#        self.title = title
-#        self.show_traceback = show_traceback
-
+    # FIXME: this class doesn't belong to the core
 
 class Interface(object):
-    """Marker base class for extension point interfaces."""
-
+    """Marker base class for interfaces."""
 
-class ExtensionPoint(property):
-    """Marker class for extension points in components."""
-
-    def __init__(self, interface):
-        """Create the extension point.
-        
-        @param interface: the `Interface` subclass that defines the protocol
-            for the extension point
-        """
-        property.__init__(self, self.extensions)
-        self.interface = interface
-        self.__doc__ = 'List of components that implement `%s`' % \
-                       self.interface.__name__
-
-    def extensions(self, component):
-        """Return a list of components that declare to implement the extension
-        point interface."""
-        extensions = ComponentMeta._registry.get(self.interface, [])
-        return filter(None, [component.compmgr[cls] for cls in extensions])
+def implements(*interfaces):
+    _implements.extend(interfaces)
 
-    def __repr__(self):
-        """Return a textual representation of the extension point."""
-        return '<ExtensionPoint %s>' % self.interface.__name__
+def implementations(interface):
+    result = []
+    find_implementations(interface, result)
+    return result
 
+_implementations = []
+_implements = []
 
 class ComponentMeta(type):
-    """Meta class for components.
-    
-    Takes care of component and extension point registration.
-    """
-    _components = []
-    _registry = {}
 
     def __new__(cls, name, bases, d):
-        """Create the component class."""
-
-        d['_implements'] = _implements[:]
-        del _implements[:]
-
         new_class = type.__new__(cls, name, bases, d)
-        if name == 'Component':
-            # Don't put the Component base class in the registry
-            return new_class
-
-        # Only override __init__ for Components not inheriting ComponentManager
-        if True not in [issubclass(x, ComponentManager) for x in bases]:
-            # Allow components to have a no-argument initializer so that
-            # they don't need to worry about accepting the component manager
-            # as argument and invoking the super-class initializer
-            init = d.get('__init__')
-            if not init:
-                # Because we're replacing the initializer, we need to make sure
-                # that any inherited initializers are also called.
-                for init in [b.__init__._original for b in new_class.mro()
-                             if issubclass(b, Component)
-                             and '__init__' in b.__dict__]:
-                    break
-            def maybe_init(self, compmgr, init=init, cls=new_class):
-                if cls not in compmgr.components:
-                    compmgr.components[cls] = self
-                    if init:
-                        init(self)
-            maybe_init._original = init
-            new_class.__init__ = maybe_init
-
-        if d.get('abstract'):
-            # Don't put abstract component classes in the registry
-            return new_class
-
-        ComponentMeta._components.append(new_class)
-        for interface in d.get('_implements', []):
-            ComponentMeta._registry.setdefault(interface, []).append(new_class)
-        for base in [base for base in bases if hasattr(base, '_implements')]:
-            for interface in base._implements:
-                ComponentMeta._registry.setdefault(interface, []).append(new_class)
-
+        if _implements:
+            for i in _implements:
+                _implementations.append((i, new_class))
+        del _implements[:]
         return new_class
 
+class Component(object):
+    __metaclass__ = ComponentMeta 
 
-_implements = []
+def extend_unique(list1, list2):
+    for item in list2:
+        if item not in list1:
+            list1.append(item)
 
-def implements(*interfaces):
-    """Can be used in the class definiton of `Component` subclasses to declare
-    the extension points that are extended.
-    """
-    _implements.extend(interfaces)
+def find_implementations(interface, result):
+    for i, cls in _implementations:
+        if (i == interface):
+            extend_unique(result, [cls])
+            extend_unique(result, cls.__subclasses__())
 
+    subinterfaces = interface.__subclasses__()
+    if subinterfaces:
+        for i in subinterfaces:
+            find_implementations(i, result)
 
-class Component(object):
-    """Base class for components.
-
-    Every component can declare what extension points it provides, as well as
-    what extension points of other components it extends.
-    """
-    __metaclass__ = ComponentMeta
-
-    def __new__(cls, *args, **kwargs):
-        """Return an existing instance of the component if it has already been
-        activated, otherwise create a new instance.
-        """
-        # If this component is also the component manager, just invoke that
-        if issubclass(cls, ComponentManager):
-            self = super(Component, cls).__new__(cls)
-            self.compmgr = self
-            return self
-
-        # The normal case where the component is not also the component manager
-        compmgr = args[0]
-        self = compmgr.components.get(cls)
-        if self is None:
-            self = super(Component, cls).__new__(cls)
-            self.compmgr = compmgr
-            compmgr.component_activated(self)
-        return self
-
-
-class ComponentManager(object):
-    """The component manager keeps a pool of active components."""
-
-    def __init__(self):
-        """Initialize the component manager."""
-        self.components = {}
-        self.enabled = {}
-        if isinstance(self, Component):
-            self.components[self.__class__] = self
-
-    def __contains__(self, cls):
-        """Return wether the given class is in the list of active components."""
-        return cls in self.components
-
-    def __getitem__(self, cls):
-        """Activate the component instance for the given class, or return the
-        existing the instance if the component has already been activated."""
-        if cls not in self.enabled:
-            self.enabled[cls] = self.is_component_enabled(cls)
-        if not self.enabled[cls]:
-            return None
-        component = self.components.get(cls)
-        if not component:
-            if cls not in ComponentMeta._components:
-                raise TimeSideError, 'Component "%s" not registered' % cls.__name__
-            try:
-                component = cls(self)
-            except TypeError, e:
-                raise TimeSideError, 'Unable to instantiate component %r (%s)' \
-                                 % (cls, e)
-        return component
-
-    def component_activated(self, component):
-        """Can be overridden by sub-classes so that special initialization for
-        components can be provided.
-        """
-
-    def is_component_enabled(self, cls):
-        """Can be overridden by sub-classes to veto the activation of a
-        component.
-
-        If this method returns False, the component with the given class will
-        not be available.
-        """
-        return True
diff --git a/newcore.py b/newcore.py
deleted file mode 100644 (file)
index 9b91d97..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2009 Olivier Guilyardi <olivier@samalyse.com>
-#
-# This file is part of TimeSide.
-
-# TimeSide is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 2 of the License, or
-# (at your option) any later version.
-
-# TimeSide is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-
-
-# This file defines an object interface mechanism and a way to determine
-# which components implements a given interface
-#
-# For example, the following defines the Music class as implementing the
-# listenable interface.
-#
-# class Listenable(Interface):
-#     pass
-#
-# class Music(Component):
-#    implements(Listenable)
-#
-# Several class can implements a such interface, and it is possible to 
-# discover which class implements it with implementations():
-#
-# list_of_classes = implementations(Listenable)
-#
-# This mechanism support inheritance of both interfaces and components:
-#
-# - all descendants of a class implementing a given interface are also considered
-#   to implement this interface
-# - a class implementing a given interface is also considered to implement all
-#   the ascendants of this interface
-
-__all__ = ['Component', 'implements', 'Interface', 'implementations', 'TimeSideError']
-
-class TimeSideError(Exception):
-    """Exception base class for errors in TimeSide."""
-    # FIXME: is this redundant with Django's error handling ?
-    # FIXME: this class doesn't belong to the core
-
-class Interface(object):
-    """Marker base class for interfaces."""
-
-def implements(*interfaces):
-    _implements.extend(interfaces)
-
-def implementations(interface):
-    result = []
-    find_implementations(interface, result)
-    return result
-
-_implementations = []
-_implements = []
-
-class ComponentMeta(type):
-
-    def __new__(cls, name, bases, d):
-        new_class = type.__new__(cls, name, bases, d)
-        if _implements:
-            for i in _implements:
-                _implementations.append((i, new_class))
-        del _implements[:]
-        return new_class
-
-class Component(object):
-    __metaclass__ = ComponentMeta 
-
-def extend_unique(list1, list2):
-    for item in list2:
-        if item not in list1:
-            list1.append(item)
-
-def find_implementations(interface, result):
-    for i, cls in _implementations:
-        if (i == interface):
-            extend_unique(result, [cls])
-            extend_unique(result, cls.__subclasses__())
-
-    subinterfaces = interface.__subclasses__()
-    if subinterfaces:
-        for i in subinterfaces:
-            find_implementations(i, result)
-
index e52723be67367d0af041f016b04959d6363f7188..8698e2d34e4d0aed2c60106cf43a6a6bee92292c 100755 (executable)
@@ -4,15 +4,21 @@
 import os
 import timeside
 import magic
-from timeside.core import Component, ExtensionPoint, ComponentManager
+from timeside.core import *
 
 
 class TestAnalyzers(Component):
-    analyzers = ExtensionPoint(timeside.analyze.IAnalyzer)
+    analyzers = implementations(timeside.analyze.IAnalyzer)
 
     def list(self):
         analyzers = []
-        for analyzer in self.analyzers:
+        for analyzer_class in self.analyzers:
+            # FIXME: should access the name, id and unit member statically
+            # there should be no need to instantiate analyzer_class
+            # eg: access directly analyzer_class.name, etc...
+            #
+            # This remark is true at many places in this file
+            analyzer = analyzer_class()
             analyzers.append({'name':analyzer.name(),
                             'id':analyzer.id(),
                             'unit':analyzer.unit(),
@@ -21,18 +27,20 @@ class TestAnalyzers(Component):
 
     def run(self, media):
         print '\n=== Analyzer testing ===\n'
-        for analyzer in self.analyzers:
+        for analyzer_class in self.analyzers:
+            analyzer = analyzer_class()
             id = analyzer.id()
             value = analyzer.render(media)
             print id + ' = ' + str(value) + ' ' + analyzer.unit()
 
 
 class TestDecoders(Component):
-    decoders = ExtensionPoint(timeside.decode.IDecoder)
+    decoders = implementations(timeside.decode.IDecoder)
 
     def list(self):
         decoders_list = []
-        for decoder in self.decoders:
+        for decoder_class in self.decoders:
+            decoder = decoder_class()
             decoders_list.append({'format': decoder.format(),
                             'mime_type': decoder.mime_type(),
                             'file_extension': decoder.file_extension(),
@@ -40,7 +48,8 @@ class TestDecoders(Component):
         print decoders_list
 
     def get_decoder(self, mime_type):
-        for decoder in self.decoders:
+        for decoder_class in self.decoders:
+            decoder = decoder_class()
             if decoder.mime_type() == mime_type:
                 return decoder
 
@@ -63,27 +72,30 @@ class TestDecoders(Component):
                 f.close()
 
 class TestEncoders(Component):
-    encoders = ExtensionPoint(timeside.encode.IEncoder)
+    encoders = implementations(timeside.encode.IEncoder)
 
     def list(self):
         encoders = []
-        for encoder in self.encoders:
+        for encoder_class in self.encoders:
+            encoder = encoder_class()
             encoders.append({'format': encoder.format(),
                             'mime_type': encoder.mime_type(),
                             })
         print encoders
 
     def get_encoder(self, mime_type):
-        for encoder in self.encoders:
+        for encoder_class in self.encoders:
+            encoder = encoder_class()
             if encoder.mime_type() == mime_type:
                 return encoder
 
     def run(self, source, metadata):
         print '\n=== Encoder testing ===\n'
-        for encoder in self.encoders:
+        for encoder_class in self.encoders:
+            encoder = encoder_class()
             mime = mimetype(source)
             format = encoder.format()
-            decoders = TestDecoders(comp_mgr)
+            decoders = TestDecoders()
             decoder = decoders.get_decoder(mime)
             decoded = decoder.process(source)
             ext = encoder.file_extension()
@@ -97,11 +109,12 @@ class TestEncoders(Component):
 
 
 class TestGraphers(Component):
-    graphers = ExtensionPoint(timeside.graph.IGrapher)
+    graphers = implementations(timeside.graph.IGrapher)
 
     def list(self):
         graphers = []
-        for grapher in self.graphers:
+        for grapher_class in self.graphers:
+            grapher = grapher_class()
             graphers.append({'id':grapher.id(),
                             'name':grapher.name(),
                             })
@@ -109,7 +122,8 @@ class TestGraphers(Component):
 
     def run(self, media):
         print '\n=== Grapher testing ===\n'
-        for grapher in self.graphers:
+        for grapher_class in self.graphers:
+            grapher = grapher_class()
             id = grapher.id()
             image = grapher.render(media)
             file_path = 'results/'+id+'.png'
@@ -136,11 +150,10 @@ def mimetype(path):
 if __name__ == '__main__':
     sample = 'samples/sweep_source.wav'
     metadata = (('creator', 'yomguy'), ('date', '2009'), ('name', 'test'))
-    comp_mgr = ComponentManager()
-    a = TestAnalyzers(comp_mgr)
-    d = TestDecoders(comp_mgr)
-    e = TestEncoders(comp_mgr)
-    g = TestGraphers(comp_mgr)
+    a = TestAnalyzers()
+    d = TestDecoders()
+    e = TestEncoders()
+    g = TestGraphers()
     a.list()
     d.list()
     e.list()
index ccbf003b8a7d5ecd0bf15fd72f2d5258b2f10128..6cf370f9ea1e4eff7a53af4115a32f2545a4c4c0 100644 (file)
@@ -1,5 +1,5 @@
 
-from timeside.newcore import *
+from timeside.core import *
 from sys import stdout
 
 class I1(Interface):