0
# Cookies and Exceptions
1
2
Specialized cookie jar implementations for privacy and session management, plus custom exception classes for better error handling and debugging in HTTP operations.
3
4
## Capabilities
5
6
### Cookie Management
7
8
Specialized cookie jar that forgets cookies after use for enhanced privacy.
9
10
```python { .api }
11
class ForgetfulCookieJar(RequestsCookieJar):
12
"""
13
Cookie jar that refuses to store cookies.
14
15
Inherits from requests.cookies.RequestsCookieJar but overrides set_cookie
16
to prevent any cookies from being stored.
17
"""
18
def set_cookie(self, *args, **kwargs):
19
"""Override to prevent cookies from being stored."""
20
```
21
22
#### Usage Examples
23
24
```python
25
import requests
26
from requests_toolbelt.cookies.forgetful import ForgetfulCookieJar
27
28
# Session with forgetful cookies
29
session = requests.Session()
30
session.cookies = ForgetfulCookieJar()
31
32
# Requests try to set cookies but they are not stored
33
response1 = session.get('https://httpbin.org/cookies/set/session_id/abc123')
34
print(f"Cookies after first request: {dict(session.cookies)}") # Empty
35
36
# Subsequent requests have no cookies
37
response2 = session.get('https://httpbin.org/cookies')
38
print(f"Cookies after second request: {dict(session.cookies)}") # Empty
39
40
# Regular cookie jar comparison
41
regular_session = requests.Session()
42
regular_session.get('https://httpbin.org/cookies/set/session_id/xyz789')
43
print(f"Regular cookies persist: {dict(regular_session.cookies)}") # Has cookies
44
45
# ForgetfulCookieJar ensures no cookies are ever stored
46
session = requests.Session()
47
session.cookies = ForgetfulCookieJar()
48
49
# Multiple requests with different cookie-setting responses
50
session.get('https://httpbin.org/cookies/set/session_id/abc123')
51
session.get('https://httpbin.org/cookies/set/auth_token/xyz789')
52
session.get('https://httpbin.org/cookies/set/user_pref/dark_mode')
53
54
print(f"All cookies ignored: {dict(session.cookies)}") # Always empty
55
```
56
57
### Exception Classes
58
59
Custom exceptions for better error handling and debugging of HTTP operations.
60
61
```python { .api }
62
class StreamingError(Exception):
63
"""
64
Exception raised during streaming operations.
65
66
Used in requests_toolbelt.downloadutils.stream when there are errors
67
in streaming uploads, downloads, or other data transfer operations.
68
"""
69
70
class VersionMismatchError(Exception):
71
"""
72
Exception raised when there's a version compatibility issue.
73
74
Used to indicate a version mismatch in the version of requests required.
75
The feature in use requires a newer version of Requests to function
76
appropriately but the version installed is not sufficient.
77
"""
78
79
class RequestsVersionTooOld(Warning):
80
"""
81
Warning issued when requests version is too old.
82
83
Used to indicate that the Requests version is too old. If the version
84
of Requests is too old to support a feature, this warning is issued.
85
"""
86
```
87
88
#### Usage Examples
89
90
```python
91
import requests
92
from requests_toolbelt import StreamingIterator
93
from requests_toolbelt.exceptions import StreamingError, VersionMismatchError
94
import warnings
95
96
def safe_streaming_upload(url, data_iterator, total_size):
97
"""Upload with proper error handling."""
98
try:
99
stream = StreamingIterator(total_size, data_iterator)
100
101
response = requests.post(
102
url,
103
data=stream,
104
headers={'Content-Length': str(total_size)}
105
)
106
107
if response.status_code != 200:
108
raise StreamingError(
109
f"Upload failed with status {response.status_code}",
110
response=response
111
)
112
113
return response
114
115
except Exception as e:
116
if isinstance(e, StreamingError):
117
print(f"Streaming error: {e}")
118
if e.response:
119
print(f"Response status: {e.response.status_code}")
120
print(f"Response text: {e.response.text}")
121
else:
122
raise StreamingError(f"Unexpected error during streaming: {e}")
123
124
# Version checking
125
def check_requests_version():
126
"""Check if requests version is compatible."""
127
import requests
128
from packaging import version
129
130
current_version = version.parse(requests.__version__)
131
minimum_version = version.parse("2.0.1")
132
133
if current_version < minimum_version:
134
raise VersionMismatchError(
135
expected="requests>=2.0.1",
136
actual=f"requests=={requests.__version__}"
137
)
138
139
# Issue warning for very old versions
140
old_version = version.parse("2.10.0")
141
if current_version < old_version:
142
warnings.warn(
143
f"requests version {requests.__version__} is very old. "
144
"Some features may not work correctly.",
145
RequestsVersionTooOld
146
)
147
148
# Usage with error handling
149
try:
150
check_requests_version()
151
152
def data_generator():
153
for i in range(100):
154
yield f"Data chunk {i}\\n".encode('utf-8')
155
156
# Calculate total size
157
total = sum(len(f"Data chunk {i}\\n".encode('utf-8')) for i in range(100))
158
159
response = safe_streaming_upload(
160
'https://upload.example.com/data',
161
data_generator(),
162
total
163
)
164
165
print("Upload successful!")
166
167
except VersionMismatchError as e:
168
print(f"Version compatibility error: {e}")
169
print("Please upgrade requests: pip install --upgrade requests")
170
171
except StreamingError as e:
172
print(f"Upload failed: {e}")
173
174
except Exception as e:
175
print(f"Unexpected error: {e}")
176
177
# Warning handling
178
warnings.simplefilter('always', RequestsVersionTooOld)
179
180
try:
181
check_requests_version()
182
except VersionMismatchError:
183
print("Critical version mismatch - cannot continue")
184
```
185
186
### Privacy-Focused Cookie Patterns
187
188
```python
189
import requests
190
from requests_toolbelt.cookies.forgetful import ForgetfulCookieJar
191
192
class PrivacySession(requests.Session):
193
"""Session with enhanced privacy features."""
194
195
def __init__(self):
196
super().__init__()
197
198
# Use forgetful cookie jar
199
self.cookies = ForgetfulCookieJar()
200
201
# Privacy-focused headers
202
self.headers.update({
203
'DNT': '1', # Do Not Track
204
'User-Agent': 'Privacy-Focused-Client/1.0',
205
})
206
207
def request(self, method, url, **kwargs):
208
"""Override to add privacy protections."""
209
210
# Remove referer header for privacy
211
if 'headers' not in kwargs:
212
kwargs['headers'] = {}
213
kwargs['headers'].pop('Referer', None)
214
215
response = super().request(method, url, **kwargs)
216
217
# Clear sensitive cookies after each request
218
self.cookies.clear()
219
220
return response
221
222
# Usage
223
privacy_session = PrivacySession()
224
225
# Each request is independent - no cookie persistence
226
response1 = privacy_session.get('https://example.com/login')
227
response2 = privacy_session.get('https://example.com/profile') # No login cookies
228
229
# Temporary authentication session
230
class TemporaryAuthSession(requests.Session):
231
"""Session that maintains auth only for the current operation."""
232
233
def __init__(self):
234
super().__init__()
235
self.cookies = ForgetfulCookieJar()
236
237
def authenticated_request(self, method, url, auth_cookies=None, **kwargs):
238
"""Make request with temporary authentication."""
239
240
# Set auth cookies temporarily
241
if auth_cookies:
242
for name, value in auth_cookies.items():
243
self.cookies.set(name, value)
244
245
try:
246
response = self.request(method, url, **kwargs)
247
return response
248
finally:
249
# Always clear auth cookies after request
250
self.cookies.clear()
251
252
# Usage
253
temp_session = TemporaryAuthSession()
254
255
auth_cookies = {'session_token': 'abc123', 'csrf_token': 'xyz789'}
256
257
# Each authenticated request is isolated
258
response = temp_session.authenticated_request(
259
'POST',
260
'https://api.example.com/secure-endpoint',
261
auth_cookies=auth_cookies,
262
json={'data': 'sensitive'}
263
)
264
265
# No cookies persist after the operation
266
print(f"Cookies after request: {dict(temp_session.cookies)}") # Empty
267
```
268
269
### Exception Handling Patterns
270
271
```python
272
from requests_toolbelt.exceptions import StreamingError, VersionMismatchError
273
import requests
274
import logging
275
276
# Configure logging for better error tracking
277
logging.basicConfig(level=logging.INFO)
278
logger = logging.getLogger(__name__)
279
280
class RobustHTTPClient:
281
"""HTTP client with comprehensive error handling."""
282
283
def __init__(self):
284
self.session = requests.Session()
285
286
def upload_with_retry(self, url, data, max_retries=3):
287
"""Upload with automatic retry on streaming errors."""
288
289
for attempt in range(max_retries):
290
try:
291
response = self.session.post(url, data=data)
292
293
if response.status_code >= 500:
294
raise StreamingError(
295
f"Server error: {response.status_code}",
296
response=response
297
)
298
299
return response
300
301
except StreamingError as e:
302
logger.warning(f"Attempt {attempt + 1} failed: {e}")
303
304
if attempt == max_retries - 1:
305
logger.error("All retry attempts exhausted")
306
raise
307
308
# Wait before retry
309
import time
310
time.sleep(2 ** attempt) # Exponential backoff
311
312
def safe_operation(self, operation_func, *args, **kwargs):
313
"""Wrap operations with comprehensive error handling."""
314
try:
315
return operation_func(*args, **kwargs)
316
317
except VersionMismatchError as e:
318
logger.error(f"Version compatibility issue: {e}")
319
raise
320
321
except StreamingError as e:
322
logger.error(f"Streaming operation failed: {e}")
323
if e.response:
324
logger.error(f"Response details: {e.response.status_code} - {e.response.text[:100]}")
325
raise
326
327
except Exception as e:
328
logger.exception("Unexpected error in HTTP operation")
329
raise StreamingError(f"Operation failed: {e}")
330
331
# Usage
332
client = RobustHTTPClient()
333
334
try:
335
# Robust upload operation
336
with open('important_data.json', 'rb') as f:
337
response = client.upload_with_retry(
338
'https://backup.example.com/upload',
339
f
340
)
341
342
print("Upload completed successfully")
343
344
except StreamingError as e:
345
print(f"Upload failed permanently: {e}")
346
# Implement fallback strategy
347
348
except VersionMismatchError as e:
349
print(f"System compatibility issue: {e}")
350
# Prompt user to update dependencies
351
```