or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdconfiguration.mdexceptions.mdindex.mdpaging.mdpipeline.mdpolling.mdserialization.mdservice-client.md

paging.mddocs/

0

# Paging

1

2

Iterator-based paging support for REST APIs that return large result sets, providing automatic page traversal, reset capability, and raw response access. The paging system enables efficient handling of paginated API responses with Python iterator protocol.

3

4

## Capabilities

5

6

### Paged Iterator

7

8

Main class for handling paginated REST responses with automatic page traversal.

9

10

```python { .api }

11

class Paged:

12

def __init__(self, command, classes, raw_headers=None, **kwargs):

13

"""

14

Initialize paged response container.

15

16

Parameters:

17

- command: Function to retrieve next page (callable)

18

- classes: Dict of model classes for deserialization

19

- raw_headers: Dict of headers to include in raw responses

20

- kwargs: Additional initialization parameters

21

"""

22

23

next_link: str = ""

24

current_page: list = []

25

26

def __iter__(self):

27

"""Return iterator (self)."""

28

29

def __next__(self):

30

"""Get next item, advancing pages as needed."""

31

32

# Python 2 compatibility

33

next = __next__

34

```

35

36

### Page Navigation

37

38

Control page traversal and iteration state.

39

40

```python { .api }

41

def advance_page(self) -> list:

42

"""

43

Force moving cursor to next page.

44

45

Returns:

46

Current page list

47

48

Raises:

49

StopIteration if no further pages available

50

"""

51

52

def reset(self):

53

"""Reset iterator to first page."""

54

55

def get(self, url: str) -> list:

56

"""

57

Get arbitrary page by URL.

58

59

This resets iterator and consumes it to return specific page.

60

61

Parameters:

62

- url: URL to specific page

63

64

Returns:

65

Page items list

66

"""

67

```

68

69

### Raw Response Access

70

71

Access underlying HTTP response data and headers.

72

73

```python { .api }

74

@property

75

def raw(self):

76

"""

77

Get current page as ClientRawResponse.

78

79

Returns:

80

ClientRawResponse with current page data and response headers

81

"""

82

```

83

84

### Async Support

85

86

For Python 3.5+, async paging support is available through AsyncPagedMixin.

87

88

```python { .api }

89

class AsyncPagedMixin:

90

"""Mixin providing async iterator support for paging."""

91

92

async def __aiter__(self):

93

"""Return async iterator."""

94

95

async def __anext__(self):

96

"""Get next item asynchronously."""

97

```

98

99

## Usage Examples

100

101

### Basic Paging

102

103

```python

104

from msrest.paging import Paged

105

from msrest import ServiceClient, Configuration

106

107

# Assuming you have a function that gets the next page

108

def get_next_page(next_link):

109

"""Function to fetch next page from API."""

110

if not next_link:

111

# First page

112

request = client.get('/users')

113

else:

114

# Subsequent pages

115

request = client.get(next_link)

116

117

response = client.send(request)

118

return response

119

120

# Create configuration and client

121

config = Configuration(base_url='https://api.example.com')

122

client = ServiceClient(None, config)

123

124

# Create paged iterator

125

model_classes = {'User': User} # Your model classes

126

users_paged = Paged(get_next_page, model_classes)

127

128

# Iterate through all pages automatically

129

for user in users_paged:

130

print(f"User: {user.name} ({user.email})")

131

```

132

133

### Manual Page Control

134

135

```python

136

from msrest.paging import Paged

137

138

# Create paged iterator

139

users_paged = Paged(get_next_page, model_classes)

140

141

# Get first page manually

142

first_page = users_paged.advance_page()

143

print(f"First page has {len(first_page)} users")

144

145

# Check if more pages available

146

if users_paged.next_link:

147

second_page = users_paged.advance_page()

148

print(f"Second page has {len(second_page)} users")

149

150

# Reset to beginning

151

users_paged.reset()

152

153

# Start iteration from beginning again

154

for user in users_paged:

155

print(user.name)

156

break # Just get first user

157

```

158

159

### Direct Page Access

160

161

```python

162

from msrest.paging import Paged

163

164

users_paged = Paged(get_next_page, model_classes)

165

166

# Get specific page by URL

167

specific_page_url = 'https://api.example.com/users?page=5'

168

page_5_users = users_paged.get(specific_page_url)

169

170

print(f"Page 5 has {len(page_5_users)} users")

171

for user in page_5_users:

172

print(f" - {user.name}")

173

```

174

175

### Raw Response Access

176

177

```python

178

from msrest.paging import Paged

179

180

# Include headers in raw responses

181

headers_to_capture = {'X-Total-Count': 'str', 'X-Page-Count': 'str'}

182

users_paged = Paged(get_next_page, model_classes, raw_headers=headers_to_capture)

183

184

# Get first page

185

users_paged.advance_page()

186

187

# Access raw response data

188

raw_response = users_paged.raw

189

print(f"Response status: {raw_response.response.status_code}")

190

print(f"Total count: {raw_response.headers.get('X-Total-Count')}")

191

print(f"Page count: {raw_response.headers.get('X-Page-Count')}")

192

print(f"Current page items: {len(raw_response.output)}")

193

```

194

195

### Custom Page Retrieval Function

196

197

```python

198

import json

199

from msrest.paging import Paged

200

201

def custom_page_fetcher(next_link):

202

"""Custom function to handle specific API pagination format."""

203

204

if not next_link:

205

# First request

206

url = '/api/data'

207

params = {'page': 1, 'per_page': 50}

208

else:

209

# Parse next_link to get page info

210

from urllib.parse import urlparse, parse_qs

211

parsed = urlparse(next_link)

212

query_params = parse_qs(parsed.query)

213

214

url = parsed.path

215

params = {k: v[0] for k, v in query_params.items()}

216

217

# Make request

218

request = client.get(url, params=params)

219

response = client.send(request)

220

221

# Parse response to extract items and next link

222

data = json.loads(response.text)

223

224

# Assuming API returns: {"items": [...], "next_page": "url"}

225

# Transform to msrest format

226

response_with_items = type('Response', (), {

227

'text': json.dumps(data['items']),

228

'headers': response.headers,

229

'status_code': response.status_code

230

})()

231

232

# Set next link for paging

233

if 'next_page' in data:

234

response_with_items.next_link = data['next_page']

235

else:

236

response_with_items.next_link = None

237

238

return response_with_items

239

240

# Use custom fetcher

241

data_paged = Paged(custom_page_fetcher, {'DataItem': DataItem})

242

243

# Iterate through all pages

244

for item in data_paged:

245

print(f"Item: {item.id}")

246

```

247

248

### Async Paging (Python 3.5+)

249

250

```python

251

import asyncio

252

from msrest.paging import Paged

253

254

async def async_page_fetcher(next_link):

255

"""Async function to fetch pages."""

256

# Use async HTTP client here

257

# This is a simplified example

258

259

if not next_link:

260

url = '/async/data'

261

else:

262

url = next_link

263

264

# Async request (pseudo-code)

265

async_response = await async_client.get(url)

266

return async_response

267

268

# For Python 3.5+

269

class AsyncPaged(Paged):

270

"""Async version of Paged iterator."""

271

272

async def __aiter__(self):

273

return self

274

275

async def __anext__(self):

276

if self.current_page and self._current_page_iter_index < len(self.current_page):

277

response = self.current_page[self._current_page_iter_index]

278

self._current_page_iter_index += 1

279

return response

280

else:

281

await self.advance_page_async()

282

return await self.__anext__()

283

284

async def advance_page_async(self):

285

if self.next_link is None:

286

raise StopAsyncIteration("End of paging")

287

288

self._current_page_iter_index = 0

289

self._response = await self._get_next(self.next_link)

290

self._derserializer(self, self._response)

291

return self.current_page

292

293

# Usage

294

async def process_async_pages():

295

async_paged = AsyncPaged(async_page_fetcher, model_classes)

296

297

async for item in async_paged:

298

print(f"Async item: {item.name}")

299

300

# Process only first 10 items

301

if some_condition:

302

break

303

304

# Run async function

305

asyncio.run(process_async_pages())

306

```

307

308

### Error Handling with Paging

309

310

```python

311

from msrest.paging import Paged

312

from msrest.exceptions import HttpOperationError

313

314

def robust_page_fetcher(next_link):

315

"""Page fetcher with error handling."""

316

try:

317

if not next_link:

318

request = client.get('/data')

319

else:

320

request = client.get(next_link)

321

322

response = client.send(request)

323

return response

324

325

except HttpOperationError as e:

326

if e.response.status_code == 404:

327

# No more pages

328

return None

329

else:

330

# Re-raise other errors

331

raise

332

333

data_paged = Paged(robust_page_fetcher, model_classes)

334

335

try:

336

for item in data_paged:

337

print(f"Item: {item.id}")

338

339

except StopIteration:

340

print("Finished processing all pages")

341

except HttpOperationError as e:

342

print(f"API error during paging: {e}")

343

```

344

345

### Paging with Authentication

346

347

```python

348

from msrest import ServiceClient, Configuration

349

from msrest.authentication import ApiKeyCredentials

350

from msrest.paging import Paged

351

352

# Setup authenticated client

353

config = Configuration(base_url='https://api.example.com')

354

config.credentials = ApiKeyCredentials(in_headers={'Authorization': 'Bearer your-token'})

355

356

with ServiceClient(None, config) as client:

357

def auth_page_fetcher(next_link):

358

"""Authenticated page fetcher."""

359

if not next_link:

360

request = client.get('/protected/data')

361

else:

362

request = client.get(next_link)

363

364

# Authentication is automatically handled by the client

365

return client.send(request)

366

367

# Create paged iterator with authenticated fetcher

368

protected_data = Paged(auth_page_fetcher, model_classes)

369

370

# Iterate through protected resources

371

for item in protected_data:

372

print(f"Protected item: {item.name}")

373

```

374

375

## Integration with Deserializer

376

377

The Paged class works closely with the Deserializer to convert raw response data into Python objects:

378

379

```python

380

from msrest.serialization import Deserializer

381

from msrest.paging import Paged

382

383

# The Paged class internally uses a deserializer

384

# You provide the model classes during initialization

385

model_classes = {

386

'User': User,

387

'Address': Address,

388

'Organization': Organization

389

}

390

391

# Paged creates internal deserializer: Deserializer(model_classes)

392

users_paged = Paged(get_next_page, model_classes)

393

394

# Each page response is automatically deserialized using the appropriate model class

395

for user in users_paged:

396

# user is already a User model instance

397

print(f"User: {user.name}")

398

if hasattr(user, 'address'):

399

print(f" Address: {user.address.city}")

400

```