diff --git a/picard/album.py b/picard/album.py index 7b8ab4a94..4902fa1e9 100644 --- a/picard/album.py +++ b/picard/album.py @@ -22,7 +22,6 @@ from PyQt4 import QtCore from musicbrainz2.model import Relation from musicbrainz2.utils import extractUuid, extractFragment from musicbrainz2.webservice import Query, WebServiceError, ReleaseIncludes, TrackIncludes -from picard.component import Component, ExtensionPoint from picard.metadata import Metadata, run_album_metadata_processors, run_track_metadata_processors from picard.dataobj import DataObject from picard.track import Track diff --git a/picard/api.py b/picard/api.py deleted file mode 100644 index 7cd83ed13..000000000 --- a/picard/api.py +++ /dev/null @@ -1,50 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Picard, the next-generation MusicBrainz tagger -# Copyright (C) 2006 Lukáš Lalinský -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -from picard.component import Interface - -class OptionsCheckError(Exception): - def __init__(self, title, message): - self.title = title - self.message = message - -class IOptionsPage(Interface): - - def get_page_info(self): - pass - - def get_page(self): - pass - - def check(self): - pass - - def load_options(self): - pass - - def save_options(self): - pass - -class IFileOpener(Interface): - - def get_supported_formats(self): - pass - - def open_file(self, filename): - pass diff --git a/picard/component.py b/picard/component.py deleted file mode 100644 index a54916486..000000000 --- a/picard/component.py +++ /dev/null @@ -1,235 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Picard, the next-generation MusicBrainz tagger -# Copyright (C) 2006 Lukáš Lalinský -# -# This program 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. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2003-2006 Edgewall Software -# Copyright (C) 2003-2004 Jonas Borgström -# Copyright (C) 2004-2005 Christopher Lenz -# All rights reserved. -# -# 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. -# -# Author: Jonas Borgström -# Christopher Lenz - -__all__ = ['Component', 'ExtensionPoint', 'implements', 'Interface'] - -from PyQt4 import QtCore -import sip - - -class Interface(object): - """Marker base class for extension point 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 __repr__(self): - """Return a textual representation of the extension point.""" - return '' % self.interface.__name__ - - -class ComponentMeta(sip.wrappertype): - """Meta class for components. - - Takes care of component and extension point registration. - """ - _components = [] - _registry = {} - - def __new__(cls, name, bases, d): - """Create the component class.""" - - new_class = sip.wrappertype.__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): - QtCore.QObject.__init__(self) - 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) - - return new_class - - -def implements(*interfaces): - """ - Can be used in the class definiton of `Component` subclasses to declare - the extension points that are extended. - """ - import sys - - frame = sys._getframe(1) - locals = frame.f_locals - - # Some sanity checks - assert locals is not frame.f_globals and '__module__' in frame.f_locals, \ - 'implements() can only be used in a class definition' - assert not '_implements' in locals, \ - 'implements() can only be used once in a class definition' - - locals['_implements'] = interfaces - - -class Component(QtCore.QObject): - """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 Exception, 'Component "%s" not registered' % cls.__name__ - try: - component = cls(self) - except TypeError, e: - raise Exception, '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/picard/tagger.py b/picard/tagger.py index 0ab8f8d95..39eec6f74 100644 --- a/picard/tagger.py +++ b/picard/tagger.py @@ -49,11 +49,9 @@ import picard.plugins from picard import musicdns from picard.album import Album -from picard.api import IFileOpener from picard.browser.browser import BrowserIntegration from picard.browser.filelookup import FileLookup from picard.cluster import Cluster, ClusterList, UnmatchedFiles -from picard.component import ComponentManager, ExtensionPoint, Component from picard.config import Config from picard.file import File from picard.formats import open as open_file @@ -88,13 +86,10 @@ from musicbrainz2.webservice import ( MUSICDNS_KEY = "80eaa76658f99dbac1c58cc06aa44779" -class Tagger(QtGui.QApplication, ComponentManager, Component): - - file_openers = ExtensionPoint(IFileOpener) +class Tagger(QtGui.QApplication): def __init__(self, localedir): QtGui.QApplication.__init__(self, sys.argv) - ComponentManager.__init__(self) self.config = Config() diff --git a/test/test_script.py b/test/test_script.py index 32f290a93..3a59cd6f3 100644 --- a/test/test_script.py +++ b/test/test_script.py @@ -1,6 +1,5 @@ import unittest from picard.script import ScriptParser -from picard.component import ComponentManager class MiscModelTest(unittest.TestCase):