def to_reader(model, field): flag_attr = 'allow_create_{}_g'.format(field) method_attr = 'create_{}_g'.format(field) flag_g = getattr(model.meta, flag_attr) if flag_g: return SequentialReader.wrap(getattr(model, method_attr)()) value = getattr(model, field, None) if value is None: return RandomSequentialReader.from_list([]) if isinstance(value, (list, tuple)): return RandomSequentialReader.from_list(value) return SequentialReader.wrap(iter(value)) # TypeError if not iterable
def test_sequential_reader(): def g_func(): for i in range(0, 5): yield i g = g_func() reader = SequentialReader.wrap(g) assert len(list(reader)) == 5
def create_songs_g(self): data = self._api.artist_songs(self.identifier, limit=0) count = int(data['total']) def g(): offset = 0 per = 50 while offset < count: data = self._api.artist_songs(self.identifier, offset, per) for song_data in data['songs']: yield _deserialize(song_data, NeteaseSongSchema) # In reality, len(data['songs']) may smaller than per, # which is a bug of netease server side, so we set # offset to `offset + per` here. offset += per per = 100 return SequentialReader(g(), count)
def create_g(func, identifier, schema, list_key='tracks', limit=20): data = func(identifier, page=1, limit=limit).get(list_key, None) total = data.get('trackCount', None) def g(): nonlocal data if data is None: yield from () else: page = 1 while data: for obj_data in data: obj = schema(**obj_data).model yield obj page += 1 data = func(identifier, page=page, limit=limit).get(list_key, None) return SequentialReader(g(), total)
def create_g(func, identifier, schema, list_key='list'): data = func(identifier, page=1).get('data') total = int(data['total']) def g(): nonlocal data if data is None: yield from () else: page = 1 while data[list_key]: obj_data_list = data[list_key] for obj_data in obj_data_list: obj = _deserialize(obj_data, schema, gotten=True) yield obj page += 1 data = func(identifier, page=page).get('data', {}) return SequentialReader(g(), total)
def create_songs_g(self): data = self._api.playlist_detail_v3(self.identifier, limit=0) track_ids = data['trackIds'] # [{'id': 1, 'v': 1}, ...] count = len(track_ids) def g(): offset = 0 per = 50 # speed up first request while offset < count: end = min(offset + per, count) if end <= offset: break ids = [track_id['id'] for track_id in track_ids[offset:end]] tracks_data = self._api.songs_detail_v3(ids) for track_data in tracks_data: yield _deserialize(track_data, NSongSchemaV3) offset += per per = 800 return SequentialReader(g(), count)
def create_g(func, identifier, schema): data = func(identifier, page=1) total = int(data['total']) def g(): nonlocal data if data is None: yield from () else: page = 1 while data['list']: obj_data_list = data['list'] for obj_data in obj_data_list: obj = _deserialize(obj_data, schema, gotten=False) # FIXME: 由于 feeluown 展示歌手的 album 列表时, # 会依次同步的去获取 cover,所以我们这里必须先把 cover 初始化好, # 否则 feeluown 界面会卡住 if schema == _ArtistAlbumSchema: obj.cover = provider.api.get_cover(obj.mid, 2) yield obj page += 1 data = func(identifier, page) return SequentialReader(g(), total)