From 6f39bde566fa32190f724754993494d8e38f203a Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 2 Apr 2013 16:18:15 +0200 Subject: [PATCH] config: Start passing dummy config explicitly to audio/backends/frontends. --- mopidy/__main__.py | 30 ++++++++++--------- mopidy/audio/actor.py | 2 +- mopidy/backends/dummy.py | 6 +++- mopidy/backends/local/actor.py | 2 +- mopidy/backends/spotify/actor.py | 2 +- mopidy/backends/stream/actor.py | 2 +- mopidy/frontends/http/actor.py | 2 +- mopidy/frontends/lastfm/actor.py | 2 +- mopidy/frontends/mpd/actor.py | 2 +- mopidy/frontends/mpris/actor.py | 2 +- mopidy/utils/log.py | 2 +- tests/audio/actor_test.py | 6 ++-- tests/backends/base/events.py | 5 +++- tests/backends/base/library.py | 4 ++- tests/backends/base/playback.py | 4 ++- tests/backends/base/playlists.py | 5 +++- tests/backends/base/tracklist.py | 4 ++- tests/backends/local/events_test.py | 1 + tests/backends/local/library_test.py | 2 +- tests/backends/local/playback_test.py | 1 + tests/backends/local/playlists_test.py | 3 +- tests/backends/local/tracklist_test.py | 1 + tests/core/events_test.py | 2 +- tests/frontends/http/events_test.py | 2 +- tests/frontends/mpd/dispatcher_test.py | 2 +- tests/frontends/mpd/protocol/__init__.py | 2 +- tests/frontends/mpd/status_test.py | 2 +- tests/frontends/mpris/events_test.py | 2 +- .../frontends/mpris/player_interface_test.py | 2 +- .../mpris/playlists_interface_test.py | 2 +- tests/frontends/mpris/root_interface_test.py | 2 +- tests/utils/jsonrpc_test.py | 2 +- 32 files changed, 66 insertions(+), 44 deletions(-) diff --git a/mopidy/__main__.py b/mopidy/__main__.py index 2aeff179..4f531000 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -53,17 +53,18 @@ def main(): loop = gobject.MainLoop() options = parse_options() + config = {} # TODO: replace dummy placeholder try: - log.setup_logging(options.verbosity_level, options.save_debug_log) + log.setup_logging(config, options.verbosity_level, options.save_debug_log) check_old_folders() extensions = load_extensions() load_config(options, extensions) setup_settings(options.interactive) - audio = setup_audio() - backends = setup_backends(extensions, audio) + audio = setup_audio(config) + backends = setup_backends(config, extensions, audio) core = setup_core(audio, backends) - setup_frontends(extensions, core) + setup_frontends(config, extensions, core) loop.run() except exceptions.SettingsError as ex: logger.error(ex.message) @@ -122,6 +123,7 @@ def parse_options(): def check_old_folders(): + # TODO: add old settings and pre extension storage locations? old_settings_folder = os.path.expanduser('~/.mopidy') if not os.path.isdir(old_settings_folder): @@ -138,8 +140,6 @@ def load_extensions(): for entry_point in pkg_resources.iter_entry_points('mopidy.ext'): logger.debug('Loading extension %s', entry_point.name) - # TODO Filter out disabled extensions - try: extension_class = entry_point.load() except pkg_resources.DistributionNotFound as ex: @@ -157,8 +157,6 @@ def load_extensions(): {'ep': entry_point.name, 'ext': extension.ext_name}) continue - # TODO Validate configuration - try: extension.validate_environment() except exceptions.ExtensionError as ex: @@ -166,6 +164,10 @@ def load_extensions(): 'Disabled extension %s: %s', entry_point.name, ex.message) continue + # TODO: due to order we do things in we can't know for sure if we are + # going to use it at this point, should we perhaps just log a single + # line with all extenions we found and then log an enabled line for + # each one after we check configs etc? logger.info( 'Loaded extension %s: %s %s', entry_point.name, extension.dist_name, extension.version) @@ -240,9 +242,9 @@ def setup_settings(interactive): sys.exit(1) -def setup_audio(): +def setup_audio(config): logger.info('Starting Mopidy audio') - return Audio.start().proxy() + return Audio.start(config=config).proxy() def stop_audio(): @@ -250,12 +252,12 @@ def stop_audio(): process.stop_actors_by_class(Audio) -def setup_backends(extensions, audio): +def setup_backends(config, extensions, audio): logger.info('Starting Mopidy backends') backends = [] for extension in extensions: for backend_class in extension.get_backend_classes(): - backend = backend_class.start(audio=audio).proxy() + backend = backend_class.start(config=config, audio=audio).proxy() backends.append(backend) return backends @@ -277,11 +279,11 @@ def stop_core(): process.stop_actors_by_class(Core) -def setup_frontends(extensions, core): +def setup_frontends(config, extensions, core): logger.info('Starting Mopidy frontends') for extension in extensions: for frontend_class in extension.get_frontend_classes(): - frontend_class.start(core=core) + frontend_class.start(config=config, core=core) def stop_frontends(extensions): diff --git a/mopidy/audio/actor.py b/mopidy/audio/actor.py index 11d2741f..42dee084 100644 --- a/mopidy/audio/actor.py +++ b/mopidy/audio/actor.py @@ -38,7 +38,7 @@ class Audio(pykka.ThreadingActor): #: The GStreamer state mapped to :class:`mopidy.audio.PlaybackState` state = PlaybackState.STOPPED - def __init__(self): + def __init__(self, config): super(Audio, self).__init__() self._playbin = None diff --git a/mopidy/backends/dummy.py b/mopidy/backends/dummy.py index dd021445..65477ea2 100644 --- a/mopidy/backends/dummy.py +++ b/mopidy/backends/dummy.py @@ -22,8 +22,12 @@ from mopidy.backends import base from mopidy.models import Playlist, SearchResult +def create_dummy_backend_proxy(config=None, audio=None): + return DummyBackend.start(config=config, audio=audio).proxy() + + class DummyBackend(pykka.ThreadingActor, base.Backend): - def __init__(self, audio): + def __init__(self, config, audio): super(DummyBackend, self).__init__() self.library = DummyLibraryProvider(backend=self) diff --git a/mopidy/backends/local/actor.py b/mopidy/backends/local/actor.py index 75baeab2..abad75ca 100644 --- a/mopidy/backends/local/actor.py +++ b/mopidy/backends/local/actor.py @@ -13,7 +13,7 @@ logger = logging.getLogger('mopidy.backends.local') class LocalBackend(pykka.ThreadingActor, base.Backend): - def __init__(self, audio): + def __init__(self, config, audio): super(LocalBackend, self).__init__() self.library = LocalLibraryProvider(backend=self) diff --git a/mopidy/backends/spotify/actor.py b/mopidy/backends/spotify/actor.py index 5e90205b..67b4acdc 100644 --- a/mopidy/backends/spotify/actor.py +++ b/mopidy/backends/spotify/actor.py @@ -14,7 +14,7 @@ class SpotifyBackend(pykka.ThreadingActor, base.Backend): # Imports inside methods are to prevent loading of __init__.py to fail on # missing spotify dependencies. - def __init__(self, audio): + def __init__(self, config, audio): super(SpotifyBackend, self).__init__() from .library import SpotifyLibraryProvider diff --git a/mopidy/backends/stream/actor.py b/mopidy/backends/stream/actor.py index f80ac7a9..d6eb31d3 100644 --- a/mopidy/backends/stream/actor.py +++ b/mopidy/backends/stream/actor.py @@ -13,7 +13,7 @@ logger = logging.getLogger('mopidy.backends.stream') class StreamBackend(pykka.ThreadingActor, base.Backend): - def __init__(self, audio): + def __init__(self, config, audio): super(StreamBackend, self).__init__() self.library = StreamLibraryProvider(backend=self) diff --git a/mopidy/frontends/http/actor.py b/mopidy/frontends/http/actor.py index 8ad0f026..54085471 100644 --- a/mopidy/frontends/http/actor.py +++ b/mopidy/frontends/http/actor.py @@ -23,7 +23,7 @@ logger = logging.getLogger('mopidy.frontends.http') class HttpFrontend(pykka.ThreadingActor, CoreListener): - def __init__(self, core): + def __init__(self, config, core): super(HttpFrontend, self).__init__() self.core = core self._setup_server() diff --git a/mopidy/frontends/lastfm/actor.py b/mopidy/frontends/lastfm/actor.py index 60a909e0..1e157d4f 100644 --- a/mopidy/frontends/lastfm/actor.py +++ b/mopidy/frontends/lastfm/actor.py @@ -20,7 +20,7 @@ API_SECRET = '94d9a09c0cd5be955c4afaeaffcaefcd' class LastfmFrontend(pykka.ThreadingActor, CoreListener): - def __init__(self, core): + def __init__(self, config, core): super(LastfmFrontend, self).__init__() self.lastfm = None self.last_start_time = None diff --git a/mopidy/frontends/mpd/actor.py b/mopidy/frontends/mpd/actor.py index 8907fe22..e288c24e 100644 --- a/mopidy/frontends/mpd/actor.py +++ b/mopidy/frontends/mpd/actor.py @@ -14,7 +14,7 @@ logger = logging.getLogger('mopidy.frontends.mpd') class MpdFrontend(pykka.ThreadingActor, CoreListener): - def __init__(self, core): + def __init__(self, config, core): super(MpdFrontend, self).__init__() hostname = network.format_hostname(settings.MPD_SERVER_HOSTNAME) port = settings.MPD_SERVER_PORT diff --git a/mopidy/frontends/mpris/actor.py b/mopidy/frontends/mpris/actor.py index 5e171826..11f87922 100644 --- a/mopidy/frontends/mpris/actor.py +++ b/mopidy/frontends/mpris/actor.py @@ -18,7 +18,7 @@ except ImportError as import_error: class MprisFrontend(pykka.ThreadingActor, CoreListener): - def __init__(self, core): + def __init__(self, config, core): super(MprisFrontend, self).__init__() self.core = core self.indicate_server = None diff --git a/mopidy/utils/log.py b/mopidy/utils/log.py index ae4ea0d9..d50f107f 100644 --- a/mopidy/utils/log.py +++ b/mopidy/utils/log.py @@ -7,7 +7,7 @@ from mopidy import settings from . import deps, versioning -def setup_logging(verbosity_level, save_debug_log): +def setup_logging(config, verbosity_level, save_debug_log): setup_root_logger() setup_console_logging(verbosity_level) if save_debug_log: diff --git a/tests/audio/actor_test.py b/tests/audio/actor_test.py index 73c8c165..35503472 100644 --- a/tests/audio/actor_test.py +++ b/tests/audio/actor_test.py @@ -17,7 +17,7 @@ class AudioTest(unittest.TestCase): settings.MIXER = 'fakemixer track_max_volume=65536' settings.OUTPUT = 'fakesink' self.song_uri = path_to_uri(path_to_data_dir('song1.wav')) - self.audio = audio.Audio.start().proxy() + self.audio = audio.Audio.start(None).proxy() def tearDown(self): pykka.ActorRegistry.stop_all() @@ -60,7 +60,7 @@ class AudioTest(unittest.TestCase): def test_set_volume_with_mixer_max_below_100(self): settings.MIXER = 'fakemixer track_max_volume=40' - self.audio = audio.Audio.start().proxy() + self.audio = audio.Audio.start(None).proxy() for value in range(0, 101): self.assertTrue(self.audio.set_volume(value).get()) @@ -81,7 +81,7 @@ class AudioTest(unittest.TestCase): class AudioStateTest(unittest.TestCase): def setUp(self): - self.audio = audio.Audio() + self.audio = audio.Audio(None) def test_state_starts_as_stopped(self): self.assertEqual(audio.PlaybackState.STOPPED, self.audio.state) diff --git a/tests/backends/base/events.py b/tests/backends/base/events.py index 1d31a721..a5d9fa7b 100644 --- a/tests/backends/base/events.py +++ b/tests/backends/base/events.py @@ -9,9 +9,12 @@ from mopidy.backends import listener @mock.patch.object(listener.BackendListener, 'send') class BackendEventsTest(object): + config = {} + def setUp(self): self.audio = audio.DummyAudio.start().proxy() - self.backend = self.backend_class.start(audio=self.audio).proxy() + self.backend = self.backend_class.start( + config=self.config, audio=self.audio).proxy() self.core = core.Core.start(backends=[self.backend]).proxy() def tearDown(self): diff --git a/tests/backends/base/library.py b/tests/backends/base/library.py index c75bec74..8390d2d6 100644 --- a/tests/backends/base/library.py +++ b/tests/backends/base/library.py @@ -23,9 +23,11 @@ class LibraryControllerTest(object): uri='file://' + path_to_data_dir('uri2'), name='track2', artists=artists[1:2], album=albums[1], date='2002', length=4000), Track()] + config = {} def setUp(self): - self.backend = self.backend_class.start(audio=None).proxy() + self.backend = self.backend_class.start( + config=self.config, audio=None).proxy() self.core = core.Core(backends=[self.backend]) self.library = self.core.library diff --git a/tests/backends/base/playback.py b/tests/backends/base/playback.py index e12d54a5..9ce73d31 100644 --- a/tests/backends/base/playback.py +++ b/tests/backends/base/playback.py @@ -18,10 +18,12 @@ from tests.backends.base import populate_tracklist class PlaybackControllerTest(object): tracks = [] + config = {} def setUp(self): self.audio = audio.DummyAudio.start().proxy() - self.backend = self.backend_class.start(audio=self.audio).proxy() + self.backend = self.backend_class.start( + config=self.config, audio=self.audio).proxy() self.core = core.Core(backends=[self.backend]) self.playback = self.core.playback self.tracklist = self.core.tracklist diff --git a/tests/backends/base/playlists.py b/tests/backends/base/playlists.py index 2184168f..00e32a6f 100644 --- a/tests/backends/base/playlists.py +++ b/tests/backends/base/playlists.py @@ -13,13 +13,16 @@ from tests import unittest, path_to_data_dir class PlaylistsControllerTest(object): + config = {} + def setUp(self): settings.LOCAL_PLAYLIST_PATH = tempfile.mkdtemp() settings.LOCAL_TAG_CACHE_FILE = path_to_data_dir('library_tag_cache') settings.LOCAL_MUSIC_PATH = path_to_data_dir('') self.audio = audio.DummyAudio.start().proxy() - self.backend = self.backend_class.start(audio=self.audio).proxy() + self.backend = self.backend_class.start( + config=self.config, audio=self.audio).proxy() self.core = core.Core(backends=[self.backend]) def tearDown(self): diff --git a/tests/backends/base/tracklist.py b/tests/backends/base/tracklist.py index 39fb020d..5140d3aa 100644 --- a/tests/backends/base/tracklist.py +++ b/tests/backends/base/tracklist.py @@ -13,10 +13,12 @@ from tests.backends.base import populate_tracklist class TracklistControllerTest(object): tracks = [] + config = {} def setUp(self): self.audio = audio.DummyAudio.start().proxy() - self.backend = self.backend_class.start(audio=self.audio).proxy() + self.backend = self.backend_class.start( + config=self.config, audio=self.audio).proxy() self.core = core.Core(audio=self.audio, backends=[self.backend]) self.controller = self.core.tracklist self.playback = self.core.playback diff --git a/tests/backends/local/events_test.py b/tests/backends/local/events_test.py index b35fad1a..5ccf0886 100644 --- a/tests/backends/local/events_test.py +++ b/tests/backends/local/events_test.py @@ -7,6 +7,7 @@ from tests.backends.base import events class LocalBackendEventsTest(events.BackendEventsTest, unittest.TestCase): backend_class = actor.LocalBackend + # TODO: setup config def setUp(self): settings.LOCAL_TAG_CACHE_FILE = path_to_data_dir('empty_tag_cache') diff --git a/tests/backends/local/library_test.py b/tests/backends/local/library_test.py index 7bf8d565..ca90e40b 100644 --- a/tests/backends/local/library_test.py +++ b/tests/backends/local/library_test.py @@ -8,8 +8,8 @@ from tests.backends.base.library import LibraryControllerTest class LocalLibraryControllerTest(LibraryControllerTest, unittest.TestCase): - backend_class = actor.LocalBackend + # TODO: setup config def setUp(self): settings.LOCAL_TAG_CACHE_FILE = path_to_data_dir('library_tag_cache') diff --git a/tests/backends/local/playback_test.py b/tests/backends/local/playback_test.py index 8d997d2e..e9b3954c 100644 --- a/tests/backends/local/playback_test.py +++ b/tests/backends/local/playback_test.py @@ -15,6 +15,7 @@ class LocalPlaybackControllerTest(PlaybackControllerTest, unittest.TestCase): backend_class = actor.LocalBackend tracks = [ Track(uri=generate_song(i), length=4464) for i in range(1, 4)] + # TODO: setup config def setUp(self): settings.LOCAL_TAG_CACHE_FILE = path_to_data_dir('empty_tag_cache') diff --git a/tests/backends/local/playlists_test.py b/tests/backends/local/playlists_test.py index f3794cee..3dbc3a2a 100644 --- a/tests/backends/local/playlists_test.py +++ b/tests/backends/local/playlists_test.py @@ -17,6 +17,7 @@ class LocalPlaylistsControllerTest( PlaylistsControllerTest, unittest.TestCase): backend_class = actor.LocalBackend + # TODO: setup config def setUp(self): settings.LOCAL_TAG_CACHE_FILE = path_to_data_dir('empty_tag_cache') @@ -96,7 +97,7 @@ class LocalPlaylistsControllerTest( playlist = playlist.copy(tracks=[track]) playlist = self.core.playlists.save(playlist) - backend = self.backend_class(audio=self.audio) + backend = self.backend_class(config=self.config, audio=self.audio) self.assert_(backend.playlists.playlists) self.assertEqual( diff --git a/tests/backends/local/tracklist_test.py b/tests/backends/local/tracklist_test.py index 0c47a5db..24c400fa 100644 --- a/tests/backends/local/tracklist_test.py +++ b/tests/backends/local/tracklist_test.py @@ -13,6 +13,7 @@ class LocalTracklistControllerTest(TracklistControllerTest, unittest.TestCase): backend_class = actor.LocalBackend tracks = [ Track(uri=generate_song(i), length=4464) for i in range(1, 4)] + # TODO: setup config def setUp(self): settings.LOCAL_TAG_CACHE_FILE = path_to_data_dir('empty_tag_cache') diff --git a/tests/core/events_test.py b/tests/core/events_test.py index 11881db7..7f673b02 100644 --- a/tests/core/events_test.py +++ b/tests/core/events_test.py @@ -13,7 +13,7 @@ from tests import unittest @mock.patch.object(core.CoreListener, 'send') class BackendEventsTest(unittest.TestCase): def setUp(self): - self.backend = dummy.DummyBackend.start(audio=None).proxy() + self.backend = dummy.create_dummy_backend_proxy() self.core = core.Core.start(backends=[self.backend]).proxy() def tearDown(self): diff --git a/tests/frontends/http/events_test.py b/tests/frontends/http/events_test.py index 77438fd4..7661ac6e 100644 --- a/tests/frontends/http/events_test.py +++ b/tests/frontends/http/events_test.py @@ -24,7 +24,7 @@ from tests import unittest @mock.patch('cherrypy.engine.publish') class HttpEventsTest(unittest.TestCase): def setUp(self): - self.http = actor.HttpFrontend(core=mock.Mock()) + self.http = actor.HttpFrontend(config=None, core=mock.Mock()) def test_track_playback_paused_is_broadcasted(self, publish): publish.reset_mock() diff --git a/tests/frontends/mpd/dispatcher_test.py b/tests/frontends/mpd/dispatcher_test.py index 3404db95..3c32cd32 100644 --- a/tests/frontends/mpd/dispatcher_test.py +++ b/tests/frontends/mpd/dispatcher_test.py @@ -13,7 +13,7 @@ from tests import unittest class MpdDispatcherTest(unittest.TestCase): def setUp(self): - self.backend = dummy.DummyBackend.start(audio=None).proxy() + self.backend = dummy.create_dummy_backend_proxy() self.core = core.Core.start(backends=[self.backend]).proxy() self.dispatcher = MpdDispatcher() diff --git a/tests/frontends/mpd/protocol/__init__.py b/tests/frontends/mpd/protocol/__init__.py index 00594206..9d24c3fa 100644 --- a/tests/frontends/mpd/protocol/__init__.py +++ b/tests/frontends/mpd/protocol/__init__.py @@ -24,7 +24,7 @@ class MockConnection(mock.Mock): class BaseTestCase(unittest.TestCase): def setUp(self): - self.backend = dummy.DummyBackend.start(audio=None).proxy() + self.backend = dummy.create_dummy_backend_proxy() self.core = core.Core.start(backends=[self.backend]).proxy() self.connection = MockConnection() diff --git a/tests/frontends/mpd/status_test.py b/tests/frontends/mpd/status_test.py index d508cbf0..8868eef7 100644 --- a/tests/frontends/mpd/status_test.py +++ b/tests/frontends/mpd/status_test.py @@ -22,7 +22,7 @@ STOPPED = PlaybackState.STOPPED class StatusHandlerTest(unittest.TestCase): def setUp(self): - self.backend = dummy.DummyBackend.start(audio=None).proxy() + self.backend = dummy.create_dummy_backend_proxy() self.core = core.Core.start(backends=[self.backend]).proxy() self.dispatcher = dispatcher.MpdDispatcher(core=self.core) self.context = self.dispatcher.context diff --git a/tests/frontends/mpris/events_test.py b/tests/frontends/mpris/events_test.py index 78e40071..f79202c0 100644 --- a/tests/frontends/mpris/events_test.py +++ b/tests/frontends/mpris/events_test.py @@ -19,7 +19,7 @@ from tests import unittest class BackendEventsTest(unittest.TestCase): def setUp(self): # As a plain class, not an actor: - self.mpris_frontend = actor.MprisFrontend(core=None) + self.mpris_frontend = actor.MprisFrontend(config=None, core=None) self.mpris_object = mock.Mock(spec=objects.MprisObject) self.mpris_frontend.mpris_object = self.mpris_object diff --git a/tests/frontends/mpris/player_interface_test.py b/tests/frontends/mpris/player_interface_test.py index 0c477dc8..ec4a17a9 100644 --- a/tests/frontends/mpris/player_interface_test.py +++ b/tests/frontends/mpris/player_interface_test.py @@ -26,7 +26,7 @@ STOPPED = PlaybackState.STOPPED class PlayerInterfaceTest(unittest.TestCase): def setUp(self): objects.MprisObject._connect_to_dbus = mock.Mock() - self.backend = dummy.DummyBackend.start(audio=None).proxy() + self.backend = dummy.create_dummy_backend_proxy() self.core = core.Core.start(backends=[self.backend]).proxy() self.mpris = objects.MprisObject(core=self.core) diff --git a/tests/frontends/mpris/playlists_interface_test.py b/tests/frontends/mpris/playlists_interface_test.py index 2adffaf3..745a858c 100644 --- a/tests/frontends/mpris/playlists_interface_test.py +++ b/tests/frontends/mpris/playlists_interface_test.py @@ -23,7 +23,7 @@ from tests import unittest class PlayerInterfaceTest(unittest.TestCase): def setUp(self): objects.MprisObject._connect_to_dbus = mock.Mock() - self.backend = dummy.DummyBackend.start(audio=None).proxy() + self.backend = dummy.create_dummy_backend_proxy() self.core = core.Core.start(backends=[self.backend]).proxy() self.mpris = objects.MprisObject(core=self.core) diff --git a/tests/frontends/mpris/root_interface_test.py b/tests/frontends/mpris/root_interface_test.py index 722fd2cd..36d689a2 100644 --- a/tests/frontends/mpris/root_interface_test.py +++ b/tests/frontends/mpris/root_interface_test.py @@ -21,7 +21,7 @@ class RootInterfaceTest(unittest.TestCase): def setUp(self): objects.exit_process = mock.Mock() objects.MprisObject._connect_to_dbus = mock.Mock() - self.backend = dummy.DummyBackend.start(audio=None).proxy() + self.backend = dummy.create_dummy_backend_proxy() self.core = core.Core.start(backends=[self.backend]).proxy() self.mpris = objects.MprisObject(core=self.core) diff --git a/tests/utils/jsonrpc_test.py b/tests/utils/jsonrpc_test.py index 226d4614..7fb8a55e 100644 --- a/tests/utils/jsonrpc_test.py +++ b/tests/utils/jsonrpc_test.py @@ -38,7 +38,7 @@ class Calculator(object): class JsonRpcTestBase(unittest.TestCase): def setUp(self): - self.backend = dummy.DummyBackend.start(audio=None).proxy() + self.backend = dummy.create_dummy_backend_proxy() self.core = core.Core.start(backends=[self.backend]).proxy() self.jrw = jsonrpc.JsonRpcWrapper(