示例#1
0
def load(obj, timeout=None):
    """Block until the object's data is loaded.

    The ``obj`` must at least have the :attr:`is_loaded` attribute. If it also
    has an :meth:`error` method, it will be checked for errors to raise.

    After ``timeout`` seconds with no results :exc:`~spotify.Timeout` is
    raised.

    If unspecified, the ``timeout`` defaults to 10s. Any timeout is better than
    no timeout, since no timeout would cause programs to potentially hang
    forever without any information to help debug the issue.

    The method returns ``self`` to allow for chaining of calls.
    """
    if spotify.session_instance is None:
        raise RuntimeError('Session must be initialized to load objects')
    if spotify.session_instance.user is None:
        raise RuntimeError('Session must be logged in to load objects')
    if timeout is None:
        timeout = 10
    deadline = time.time() + timeout
    while not obj.is_loaded:
        # TODO Consider sleeping for the time returned by process_events()
        # instead of making a tight loop.
        spotify.session_instance.process_events()
        spotify.Error.maybe_raise(getattr(obj, 'error', 0),
                                  ignores=[spotify.ErrorType.IS_LOADING])
        if time.time() > deadline:
            raise spotify.Timeout(timeout)
        time.sleep(0.001)
    spotify.Error.maybe_raise(getattr(obj, 'error', 0),
                              ignores=[spotify.ErrorType.IS_LOADING])
    return obj
示例#2
0
def load(session, obj, timeout=None):
    """Block until the object's data is loaded.

    If the session isn't logged in, a :exc:`spotify.Error` is raised as Spotify
    objects cannot be loaded without being online and logged in.

    The ``obj`` must at least have the :attr:`is_loaded` attribute. If it also
    has an :meth:`error` method, it will be checked for errors to raise.

    After ``timeout`` seconds with no results :exc:`~spotify.Timeout` is
    raised.

    If unspecified, the ``timeout`` defaults to 10s. Any timeout is better than
    no timeout, since no timeout would cause programs to potentially hang
    forever without any information to help debug the issue.

    The method returns ``self`` to allow for chaining of calls.
    """
    _check_error(obj)
    if obj.is_loaded:
        return obj

    if session.connection.state is not spotify.ConnectionState.LOGGED_IN:
        raise spotify.Error(
            'Session must be logged in and online to load objects: %r'
            % session.connection.state)

    if timeout is None:
        timeout = 10
    deadline = time.time() + timeout

    while not obj.is_loaded:
        session.process_events()
        _check_error(obj)
        if obj.is_loaded:
            return obj
        if time.time() > deadline:
            raise spotify.Timeout(timeout)

        # Instead of sleeping for a very short time and making a tight loop
        # here, one might be tempted to sleep for the time returned by the
        # session.process_events() call above. If no event loop is running,
        # that could lead to very long waits (up to a minute or so) since no
        # one is doing anything on "notify_main_thread" session callbacks,
        # which is intended to interrupt the sleep interval prescribed by
        # session.process_events(). Thus, it is better to make this loop tight.
        time.sleep(0.001)

    _check_error(obj)
    return obj
示例#3
0
 def test_has_useful_repr(self):
     error = spotify.Timeout(0.5)
     self.assertIn('Operation did not complete in 0.500s', repr(error))
示例#4
0
 def test_has_useful_string_representation(self):
     error = spotify.Timeout(0.5)
     self.assertEqual('%s' % error, 'Operation did not complete in 0.500s')
     self.assertIsInstance('%s' % error, utils.text_type)
示例#5
0
 def test_is_an_error(self):
     error = spotify.Timeout(0.5)
     self.assertIsInstance(error, spotify.Error)