diff --git a/mopidy/core/playback.py b/mopidy/core/playback.py index 300a6a89..45e1b4ba 100644 --- a/mopidy/core/playback.py +++ b/mopidy/core/playback.py @@ -217,6 +217,7 @@ class PlaybackController(object): if self._pending_tl_track: self._set_current_tl_track(self._pending_tl_track) self._pending_tl_track = None + self.set_state(PlaybackState.PLAYING) self._trigger_track_playback_started() def _on_about_to_finish_callback(self): @@ -233,6 +234,9 @@ class PlaybackController(object): }) def _on_about_to_finish(self): + if self._state == PlaybackState.STOPPED: + return + # TODO: check that we always have a current track original_tl_track = self.get_current_tl_track() next_tl_track = self.core.tracklist.eot_track(original_tl_track) @@ -328,10 +332,6 @@ class PlaybackController(object): current = self._pending_tl_track or self._current_tl_track pending = tl_track or current or self.core.tracklist.next_track(None) - if pending: - # TODO: remove? - self.set_state(PlaybackState.PLAYING) - while pending: # TODO: should we consume unplayable tracks in this loop? if self._change(pending, PlaybackState.PLAYING): diff --git a/tests/core/test_playback.py b/tests/core/test_playback.py index b5796827..4ae3b4ef 100644 --- a/tests/core/test_playback.py +++ b/tests/core/test_playback.py @@ -314,6 +314,8 @@ class TestCurrentAndPendingTlTrack(BaseTest): 'mopidy.core.playback.listener.CoreListener', spec=core.CoreListener) class EventEmissionTest(BaseTest): + maxDiff = None + def test_play_when_stopped_emits_events(self, listener_mock): tl_tracks = self.core.tracklist.get_tl_tracks() @@ -321,14 +323,14 @@ class EventEmissionTest(BaseTest): self.replay_events() self.assertListEqual( - listener_mock.send.mock_calls, [ mock.call( 'playback_state_changed', old_state='stopped', new_state='playing'), mock.call( 'track_playback_started', tl_track=tl_tracks[0]), - ]) + ], + listener_mock.send.mock_calls) def test_play_when_paused_emits_events(self, listener_mock): tl_tracks = self.core.tracklist.get_tl_tracks() @@ -344,17 +346,17 @@ class EventEmissionTest(BaseTest): self.replay_events() self.assertListEqual( - listener_mock.send.mock_calls, [ - mock.call( - 'playback_state_changed', - old_state='paused', new_state='playing'), mock.call( 'track_playback_ended', tl_track=tl_tracks[0], time_position=mock.ANY), + mock.call( + 'playback_state_changed', + old_state='paused', new_state='playing'), mock.call( 'track_playback_started', tl_track=tl_tracks[1]), - ]) + ], + listener_mock.send.mock_calls) def test_play_when_playing_emits_events(self, listener_mock): tl_tracks = self.core.tracklist.get_tl_tracks() @@ -366,19 +368,18 @@ class EventEmissionTest(BaseTest): self.core.playback.play(tl_tracks[2]) self.replay_events() - # TODO: Do we want to emit playing->playing for this case? self.assertListEqual( - listener_mock.send.mock_calls, [ - mock.call( - 'playback_state_changed', old_state='playing', - new_state='playing'), mock.call( 'track_playback_ended', tl_track=tl_tracks[0], time_position=mock.ANY), + mock.call( + 'playback_state_changed', old_state='playing', + new_state='playing'), mock.call( 'track_playback_started', tl_track=tl_tracks[2]), - ]) + ], + listener_mock.send.mock_calls) def test_pause_emits_events(self, listener_mock): tl_tracks = self.core.tracklist.get_tl_tracks() @@ -392,7 +393,6 @@ class EventEmissionTest(BaseTest): self.core.playback.pause() self.assertListEqual( - listener_mock.send.mock_calls, [ mock.call( 'playback_state_changed', @@ -400,7 +400,8 @@ class EventEmissionTest(BaseTest): mock.call( 'track_playback_paused', tl_track=tl_tracks[0], time_position=1000), - ]) + ], + listener_mock.send.mock_calls) def test_resume_emits_events(self, listener_mock): tl_tracks = self.core.tracklist.get_tl_tracks() @@ -415,7 +416,6 @@ class EventEmissionTest(BaseTest): self.core.playback.resume() self.assertListEqual( - listener_mock.send.mock_calls, [ mock.call( 'playback_state_changed', @@ -423,7 +423,8 @@ class EventEmissionTest(BaseTest): mock.call( 'track_playback_resumed', tl_track=tl_tracks[0], time_position=1000), - ]) + ], + listener_mock.send.mock_calls) def test_stop_emits_events(self, listener_mock): tl_tracks = self.core.tracklist.get_tl_tracks() @@ -437,7 +438,6 @@ class EventEmissionTest(BaseTest): self.replay_events() self.assertListEqual( - listener_mock.send.mock_calls, [ mock.call( 'playback_state_changed', @@ -445,7 +445,8 @@ class EventEmissionTest(BaseTest): mock.call( 'track_playback_ended', tl_track=tl_tracks[0], time_position=1000), - ]) + ], + listener_mock.send.mock_calls) def test_next_emits_events(self, listener_mock): tl_tracks = self.core.tracklist.get_tl_tracks() @@ -458,18 +459,20 @@ class EventEmissionTest(BaseTest): self.core.playback.next() self.replay_events() - # TODO: should we be emitting playing -> playing? self.assertListEqual( - listener_mock.send.mock_calls, [ mock.call( 'track_playback_ended', tl_track=tl_tracks[0], time_position=mock.ANY), + mock.call( + 'playback_state_changed', + old_state='playing', new_state='playing'), mock.call( 'track_playback_started', tl_track=tl_tracks[1]), - ]) + ], + listener_mock.send.mock_calls) - def test_on_end_of_track_emits_events(self, listener_mock): + def test_gapless_track_change_emits_events(self, listener_mock): tl_tracks = self.core.tracklist.get_tl_tracks() self.core.playback.play(tl_tracks[0]) @@ -479,14 +482,17 @@ class EventEmissionTest(BaseTest): self.trigger_about_to_finish() self.assertListEqual( - listener_mock.send.mock_calls, [ mock.call( 'track_playback_ended', tl_track=tl_tracks[0], time_position=mock.ANY), + mock.call( + 'playback_state_changed', + old_state='playing', new_state='playing'), mock.call( 'track_playback_started', tl_track=tl_tracks[1]), - ]) + ], + listener_mock.send.mock_calls) def test_seek_emits_seeked_event(self, listener_mock): tl_tracks = self.core.tracklist.get_tl_tracks() @@ -511,14 +517,17 @@ class EventEmissionTest(BaseTest): self.replay_events() self.assertListEqual( - listener_mock.send.mock_calls, [ mock.call( 'track_playback_ended', tl_track=tl_tracks[0], time_position=mock.ANY), + mock.call( + 'playback_state_changed', + old_state='playing', new_state='playing'), mock.call( 'track_playback_started', tl_track=tl_tracks[1]), - ]) + ], + listener_mock.send.mock_calls) def test_previous_emits_events(self, listener_mock): tl_tracks = self.core.tracklist.get_tl_tracks() @@ -531,14 +540,17 @@ class EventEmissionTest(BaseTest): self.replay_events() self.assertListEqual( - listener_mock.send.mock_calls, [ mock.call( 'track_playback_ended', tl_track=tl_tracks[1], time_position=mock.ANY), + mock.call( + 'playback_state_changed', + old_state='playing', new_state='playing'), mock.call( 'track_playback_started', tl_track=tl_tracks[0]), - ]) + ], + listener_mock.send.mock_calls) class UnplayableURITest(BaseTest): @@ -612,6 +624,8 @@ class SeekTest(BaseTest): tl_tracks = self.core.tracklist.get_tl_tracks() self.core.playback.play(tl_tracks[0]) + self.replay_events() + self.core.playback.pause() self.replay_events() diff --git a/tests/local/test_playback.py b/tests/local/test_playback.py index 92fbe5b9..f0dcf20b 100644 --- a/tests/local/test_playback.py +++ b/tests/local/test_playback.py @@ -998,7 +998,7 @@ class LocalPlaybackProviderTest(unittest.TestCase): self.playback.next().get() self.assert_next_tl_track_is_not(None) self.assert_state_is(PlaybackState.STOPPED) - self.playback.play() + self.playback.play().get() self.assert_state_is(PlaybackState.PLAYING) @populate_tracklist diff --git a/tests/local/test_tracklist.py b/tests/local/test_tracklist.py index b7ed7dcb..6c9532e8 100644 --- a/tests/local/test_tracklist.py +++ b/tests/local/test_tracklist.py @@ -38,7 +38,9 @@ class LocalTracklistProviderTest(unittest.TestCase): self.audio = dummy_audio.create_proxy() self.backend = actor.LocalBackend.start( config=self.config, audio=self.audio).proxy() - self.core = core.Core(self.config, mixer=None, backends=[self.backend]) + self.core = core.Core.start(audio=self.audio, + backends=[self.backend], + config=self.config).proxy() self.controller = self.core.tracklist self.playback = self.core.playback @@ -47,216 +49,254 @@ class LocalTracklistProviderTest(unittest.TestCase): def tearDown(self): # noqa: N802 pykka.ActorRegistry.stop_all() + def assert_state_is(self, state): + self.assertEqual(self.playback.get_state().get(), state) + + def assert_current_track_is(self, track): + self.assertEqual(self.playback.get_current_track().get(), track) + def test_length(self): - self.assertEqual(0, len(self.controller.tl_tracks)) - self.assertEqual(0, self.controller.length) + self.assertEqual(0, len(self.controller.get_tl_tracks().get())) + self.assertEqual(0, self.controller.get_length().get()) self.controller.add(self.tracks) - self.assertEqual(3, len(self.controller.tl_tracks)) - self.assertEqual(3, self.controller.length) + self.assertEqual(3, len(self.controller.get_tl_tracks().get())) + self.assertEqual(3, self.controller.get_length().get()) def test_add(self): for track in self.tracks: - tl_tracks = self.controller.add([track]) - self.assertEqual(track, self.controller.tracks[-1]) - self.assertEqual(tl_tracks[0], self.controller.tl_tracks[-1]) - self.assertEqual(track, tl_tracks[0].track) + added = self.controller.add([track]).get() + tracks = self.controller.get_tracks().get() + tl_tracks = self.controller.get_tl_tracks().get() + + self.assertEqual(track, tracks[-1]) + self.assertEqual(added[0], tl_tracks[-1]) + self.assertEqual(track, added[0].track) def test_add_at_position(self): for track in self.tracks[:-1]: - tl_tracks = self.controller.add([track], 0) - self.assertEqual(track, self.controller.tracks[0]) - self.assertEqual(tl_tracks[0], self.controller.tl_tracks[0]) - self.assertEqual(track, tl_tracks[0].track) + added = self.controller.add([track], 0).get() + tracks = self.controller.get_tracks().get() + tl_tracks = self.controller.get_tl_tracks().get() + + self.assertEqual(track, tracks[0]) + self.assertEqual(added[0], tl_tracks[0]) + self.assertEqual(track, added[0].track) @populate_tracklist def test_add_at_position_outside_of_playlist(self): for track in self.tracks: - tl_tracks = self.controller.add([track], len(self.tracks) + 2) - self.assertEqual(track, self.controller.tracks[-1]) - self.assertEqual(tl_tracks[0], self.controller.tl_tracks[-1]) - self.assertEqual(track, tl_tracks[0].track) + added = self.controller.add([track], len(self.tracks) + 2).get() + tracks = self.controller.get_tracks().get() + tl_tracks = self.controller.get_tl_tracks().get() + + self.assertEqual(track, tracks[-1]) + self.assertEqual(added[0], tl_tracks[-1]) + self.assertEqual(track, added[0].track) @populate_tracklist def test_filter_by_tlid(self): - tl_track = self.controller.tl_tracks[1] - self.assertEqual( - [tl_track], self.controller.filter({'tlid': [tl_track.tlid]})) + tl_track = self.controller.get_tl_tracks().get()[1] + result = self.controller.filter({'tlid': [tl_track.tlid]}).get() + self.assertEqual([tl_track], result) @populate_tracklist def test_filter_by_uri(self): - tl_track = self.controller.tl_tracks[1] - self.assertEqual( - [tl_track], self.controller.filter({'uri': [tl_track.track.uri]})) + tl_track = self.controller.get_tl_tracks().get()[1] + result = self.controller.filter({'uri': [tl_track.track.uri]}).get() + self.assertEqual([tl_track], result) @populate_tracklist def test_filter_by_uri_returns_nothing_for_invalid_uri(self): - self.assertEqual([], self.controller.filter({'uri': ['foobar']})) + self.assertEqual([], self.controller.filter({'uri': ['foobar']}).get()) def test_filter_by_uri_returns_single_match(self): t = Track(uri='a') self.controller.add([Track(uri='z'), t, Track(uri='y')]) - self.assertEqual(t, self.controller.filter({'uri': ['a']})[0].track) + + result = self.controller.filter({'uri': ['a']}).get() + self.assertEqual(t, result[0].track) def test_filter_by_uri_returns_multiple_matches(self): track = Track(uri='a') self.controller.add([Track(uri='z'), track, track]) - tl_tracks = self.controller.filter({'uri': ['a']}) + tl_tracks = self.controller.filter({'uri': ['a']}).get() self.assertEqual(track, tl_tracks[0].track) self.assertEqual(track, tl_tracks[1].track) def test_filter_by_uri_returns_nothing_if_no_match(self): self.controller.playlist = Playlist( tracks=[Track(uri='z'), Track(uri='y')]) - self.assertEqual([], self.controller.filter({'uri': ['a']})) + self.assertEqual([], self.controller.filter({'uri': ['a']}).get()) def test_filter_by_multiple_criteria_returns_elements_matching_all(self): t1 = Track(uri='a', name='x') t2 = Track(uri='b', name='x') t3 = Track(uri='b', name='y') self.controller.add([t1, t2, t3]) - self.assertEqual( - t1, self.controller.filter({'uri': ['a'], 'name': ['x']})[0].track) - self.assertEqual( - t2, self.controller.filter({'uri': ['b'], 'name': ['x']})[0].track) - self.assertEqual( - t3, self.controller.filter({'uri': ['b'], 'name': ['y']})[0].track) + + result1 = self.controller.filter({'uri': ['a'], 'name': ['x']}).get() + self.assertEqual(t1, result1[0].track) + + result2 = self.controller.filter({'uri': ['b'], 'name': ['x']}).get() + self.assertEqual(t2, result2[0].track) + + result3 = self.controller.filter({'uri': ['b'], 'name': ['y']}).get() + self.assertEqual(t3, result3[0].track) def test_filter_by_criteria_that_is_not_present_in_all_elements(self): track1 = Track() track2 = Track(uri='b') track3 = Track() + self.controller.add([track1, track2, track3]) - self.assertEqual( - track2, self.controller.filter({'uri': ['b']})[0].track) + result = self.controller.filter({'uri': ['b']}).get() + self.assertEqual(track2, result[0].track) @populate_tracklist def test_clear(self): - self.controller.clear() - self.assertEqual(len(self.controller.tracks), 0) + self.controller.clear().get() + self.assertEqual(len(self.controller.get_tracks().get()), 0) def test_clear_empty_playlist(self): - self.controller.clear() - self.assertEqual(len(self.controller.tracks), 0) + self.controller.clear().get() + self.assertEqual(len(self.controller.get_tracks().get()), 0) @populate_tracklist def test_clear_when_playing(self): - self.playback.play() - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - self.controller.clear() - self.assertEqual(self.playback.state, PlaybackState.STOPPED) + self.playback.play().get() + self.assert_state_is(PlaybackState.PLAYING) + self.controller.clear().get() + self.assert_state_is(PlaybackState.STOPPED) def test_add_appends_to_the_tracklist(self): self.controller.add([Track(uri='a'), Track(uri='b')]) - self.assertEqual(len(self.controller.tracks), 2) + + tracks = self.controller.get_tracks().get() + self.assertEqual(len(tracks), 2) + self.controller.add([Track(uri='c'), Track(uri='d')]) - self.assertEqual(len(self.controller.tracks), 4) - self.assertEqual(self.controller.tracks[0].uri, 'a') - self.assertEqual(self.controller.tracks[1].uri, 'b') - self.assertEqual(self.controller.tracks[2].uri, 'c') - self.assertEqual(self.controller.tracks[3].uri, 'd') + + tracks = self.controller.get_tracks().get() + self.assertEqual(len(tracks), 4) + self.assertEqual(tracks[0].uri, 'a') + self.assertEqual(tracks[1].uri, 'b') + self.assertEqual(tracks[2].uri, 'c') + self.assertEqual(tracks[3].uri, 'd') def test_add_does_not_reset_version(self): - version = self.controller.version + version = self.controller.get_version().get() self.controller.add([]) - self.assertEqual(self.controller.version, version) + self.assertEqual(self.controller.get_version().get(), version) @populate_tracklist def test_add_preserves_playing_state(self): - self.playback.play() - track = self.playback.current_track - self.controller.add(self.controller.tracks[1:2]) - self.assertEqual(self.playback.state, PlaybackState.PLAYING) - self.assertEqual(self.playback.current_track, track) + self.playback.play().get() + + track = self.playback.get_current_track().get() + tracks = self.controller.get_tracks().get() + self.controller.add(tracks[1:2]).get() + + self.assert_state_is(PlaybackState.PLAYING) + self.assert_current_track_is(track) @populate_tracklist def test_add_preserves_stopped_state(self): - self.controller.add(self.controller.tracks[1:2]) - self.assertEqual(self.playback.state, PlaybackState.STOPPED) - self.assertEqual(self.playback.current_track, None) + tracks = self.controller.get_tracks().get() + self.controller.add(tracks[1:2]).get() + + self.assert_state_is(PlaybackState.STOPPED) + self.assert_current_track_is(None) @populate_tracklist def test_add_returns_the_tl_tracks_that_was_added(self): - tl_tracks = self.controller.add(self.controller.tracks[1:2]) - self.assertEqual(tl_tracks[0].track, self.controller.tracks[1]) + tracks = self.controller.get_tracks().get() + + added = self.controller.add(tracks[1:2]).get() + tracks = self.controller.get_tracks().get() + self.assertEqual(added[0].track, tracks[1]) @populate_tracklist def test_move_single(self): self.controller.move(0, 0, 2) - tracks = self.controller.tracks + tracks = self.controller.get_tracks().get() self.assertEqual(tracks[2], self.tracks[0]) @populate_tracklist def test_move_group(self): self.controller.move(0, 2, 1) - tracks = self.controller.tracks + tracks = self.controller.get_tracks().get() self.assertEqual(tracks[1], self.tracks[0]) self.assertEqual(tracks[2], self.tracks[1]) @populate_tracklist def test_moving_track_outside_of_playlist(self): - tracks = len(self.controller.tracks) + num_tracks = len(self.controller.get_tracks().get()) with self.assertRaises(AssertionError): - self.controller.move(0, 0, tracks + 5) + self.controller.move(0, 0, num_tracks + 5).get() @populate_tracklist def test_move_group_outside_of_playlist(self): - tracks = len(self.controller.tracks) + num_tracks = len(self.controller.get_tracks().get()) with self.assertRaises(AssertionError): - self.controller.move(0, 2, tracks + 5) + self.controller.move(0, 2, num_tracks + 5).get() @populate_tracklist def test_move_group_out_of_range(self): - tracks = len(self.controller.tracks) + num_tracks = len(self.controller.get_tracks().get()) with self.assertRaises(AssertionError): - self.controller.move(tracks + 2, tracks + 3, 0) + self.controller.move(num_tracks + 2, num_tracks + 3, 0).get() @populate_tracklist def test_move_group_invalid_group(self): with self.assertRaises(AssertionError): - self.controller.move(2, 1, 0) + self.controller.move(2, 1, 0).get() def test_tracks_attribute_is_immutable(self): - tracks1 = self.controller.tracks - tracks2 = self.controller.tracks + tracks1 = self.controller.tracks.get() + tracks2 = self.controller.tracks.get() self.assertNotEqual(id(tracks1), id(tracks2)) @populate_tracklist def test_remove(self): - track1 = self.controller.tracks[1] - track2 = self.controller.tracks[2] - version = self.controller.version + track1 = self.controller.get_tracks().get()[1] + track2 = self.controller.get_tracks().get()[2] + version = self.controller.get_version().get() self.controller.remove({'uri': [track1.uri]}) - self.assertLess(version, self.controller.version) - self.assertNotIn(track1, self.controller.tracks) - self.assertEqual(track2, self.controller.tracks[1]) + self.assertLess(version, self.controller.get_version().get()) + self.assertNotIn(track1, self.controller.get_tracks().get()) + self.assertEqual(track2, self.controller.get_tracks().get()[1]) @populate_tracklist def test_removing_track_that_does_not_exist_does_nothing(self): - self.controller.remove({'uri': ['/nonexistant']}) + self.controller.remove({'uri': ['/nonexistant']}).get() def test_removing_from_empty_playlist_does_nothing(self): - self.controller.remove({'uri': ['/nonexistant']}) + self.controller.remove({'uri': ['/nonexistant']}).get() @populate_tracklist def test_remove_lists(self): - track0 = self.controller.tracks[0] - track1 = self.controller.tracks[1] - track2 = self.controller.tracks[2] - version = self.controller.version + version = self.controller.get_version().get() + tracks = self.controller.get_tracks().get() + track0 = tracks[0] + track1 = tracks[1] + track2 = tracks[2] + self.controller.remove({'uri': [track0.uri, track2.uri]}) - self.assertLess(version, self.controller.version) - self.assertNotIn(track0, self.controller.tracks) - self.assertNotIn(track2, self.controller.tracks) - self.assertEqual(track1, self.controller.tracks[0]) + + tracks = self.controller.get_tracks().get() + self.assertLess(version, self.controller.get_version().get()) + self.assertNotIn(track0, tracks) + self.assertNotIn(track2, tracks) + self.assertEqual(track1, tracks[0]) @populate_tracklist def test_shuffle(self): random.seed(1) self.controller.shuffle() - shuffled_tracks = self.controller.tracks + shuffled_tracks = self.controller.get_tracks().get() self.assertNotEqual(self.tracks, shuffled_tracks) self.assertEqual(set(self.tracks), set(shuffled_tracks)) @@ -266,7 +306,7 @@ class LocalTracklistProviderTest(unittest.TestCase): random.seed(1) self.controller.shuffle(1, 3) - shuffled_tracks = self.controller.tracks + shuffled_tracks = self.controller.get_tracks().get() self.assertNotEqual(self.tracks, shuffled_tracks) self.assertEqual(self.tracks[0], shuffled_tracks[0]) @@ -275,20 +315,20 @@ class LocalTracklistProviderTest(unittest.TestCase): @populate_tracklist def test_shuffle_invalid_subset(self): with self.assertRaises(AssertionError): - self.controller.shuffle(3, 1) + self.controller.shuffle(3, 1).get() @populate_tracklist def test_shuffle_superset(self): - tracks = len(self.controller.tracks) + num_tracks = len(self.controller.get_tracks().get()) with self.assertRaises(AssertionError): - self.controller.shuffle(1, tracks + 5) + self.controller.shuffle(1, num_tracks + 5).get() @populate_tracklist def test_shuffle_open_subset(self): random.seed(1) self.controller.shuffle(1) - shuffled_tracks = self.controller.tracks + shuffled_tracks = self.controller.get_tracks().get() self.assertNotEqual(self.tracks, shuffled_tracks) self.assertEqual(self.tracks[0], shuffled_tracks[0]) @@ -296,22 +336,22 @@ class LocalTracklistProviderTest(unittest.TestCase): @populate_tracklist def test_slice_returns_a_subset_of_tracks(self): - track_slice = self.controller.slice(1, 3) + track_slice = self.controller.slice(1, 3).get() self.assertEqual(2, len(track_slice)) self.assertEqual(self.tracks[1], track_slice[0].track) self.assertEqual(self.tracks[2], track_slice[1].track) @populate_tracklist def test_slice_returns_empty_list_if_indexes_outside_tracks_list(self): - self.assertEqual(0, len(self.controller.slice(7, 8))) - self.assertEqual(0, len(self.controller.slice(-1, 1))) + self.assertEqual(0, len(self.controller.slice(7, 8).get())) + self.assertEqual(0, len(self.controller.slice(-1, 1).get())) def test_version_does_not_change_when_adding_nothing(self): - version = self.controller.version + version = self.controller.get_version().get() self.controller.add([]) - self.assertEqual(version, self.controller.version) + self.assertEqual(version, self.controller.get_version().get()) def test_version_increases_when_adding_something(self): - version = self.controller.version + version = self.controller.get_version().get() self.controller.add([Track()]) - self.assertLess(version, self.controller.version) + self.assertLess(version, self.controller.get_version().get())