or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

basic-mocking.mdindex.mdmatchers.mdrecording.mdregistries.mdrequests-mock.mdresponse-types.md

registries.mddocs/

0

# Response Registries

1

2

Registry systems that control how responses are matched and selected when multiple responses could potentially match a request. Different registry types provide different strategies for response selection, enabling complex testing scenarios with precise control over response ordering and reuse.

3

4

## Capabilities

5

6

### FirstMatchRegistry

7

8

The default registry that returns the first response that matches a request. Responses remain available for subsequent matching unless explicitly removed.

9

10

```python { .api }

11

class FirstMatchRegistry:

12

def __init__(self):

13

"""

14

Create a FirstMatchRegistry instance.

15

16

This is the default registry used by responses. When a request

17

is made, it searches through registered responses in order and

18

returns the first one that matches. The response remains in

19

the registry for future matching.

20

"""

21

22

@property

23

def registered(self):

24

"""

25

List of all registered responses.

26

27

Returns:

28

List of BaseResponse objects currently in the registry

29

"""

30

31

def find(self, request):

32

"""

33

Find the first response that matches the request.

34

35

Parameters:

36

- request: PreparedRequest object to match against

37

38

Returns:

39

Tuple of (BaseResponse or None, List[str])

40

- First element: Matching response or None if no match

41

- Second element: List of reasons why other responses didn't match

42

43

The matching response is NOT removed from the registry and can

44

match future requests.

45

"""

46

47

def add(self, response):

48

"""

49

Add a response to the registry.

50

51

Parameters:

52

- response: BaseResponse object to register

53

54

Returns:

55

BaseResponse object that was added (may be a deep copy)

56

57

If the same response instance is added multiple times,

58

it will be deep copied to prevent shared state issues.

59

"""

60

61

def remove(self, response):

62

"""

63

Remove all instances of a response from the registry.

64

65

Parameters:

66

- response: BaseResponse object to remove

67

68

Returns:

69

List of BaseResponse objects that were removed

70

71

Removes all responses that match the given response object.

72

"""

73

74

def replace(self, response):

75

"""

76

Replace an existing response in the registry.

77

78

Parameters:

79

- response: BaseResponse object that should replace existing

80

81

Returns:

82

BaseResponse object representing the replacement

83

84

Raises:

85

ValueError if no matching response is found to replace

86

"""

87

88

def reset(self):

89

"""Clear all registered responses from the registry."""

90

```

91

92

**Usage Example:**

93

94

```python

95

from responses.registries import FirstMatchRegistry

96

97

@responses.activate

98

def test_first_match_behavior():

99

# Multiple responses for same URL

100

responses.add(responses.GET, "http://api.example.com/data", json={"version": 1})

101

responses.add(responses.GET, "http://api.example.com/data", json={"version": 2})

102

103

# First response is always returned

104

resp1 = requests.get("http://api.example.com/data")

105

resp2 = requests.get("http://api.example.com/data")

106

resp3 = requests.get("http://api.example.com/data")

107

108

# All return the first registered response

109

assert resp1.json()["version"] == 1

110

assert resp2.json()["version"] == 1

111

assert resp3.json()["version"] == 1

112

```

113

114

### OrderedRegistry

115

116

A registry that enforces strict ordering where responses must be consumed in the order they were registered. Each response is removed after first use.

117

118

```python { .api }

119

class OrderedRegistry(FirstMatchRegistry):

120

def __init__(self):

121

"""

122

Create an OrderedRegistry instance.

123

124

Responses are consumed in first-in-first-out (FIFO) order.

125

Each response can only be used once and is removed from the

126

registry after matching a request.

127

"""

128

129

def find(self, request):

130

"""

131

Find and remove the next response in order.

132

133

Parameters:

134

- request: PreparedRequest object to match against

135

136

Returns:

137

Tuple of (BaseResponse or None, List[str])

138

- First element: Next response in order if it matches, None otherwise

139

- Second element: List with error message if no match

140

141

The matching response is REMOVED from the registry and cannot

142

match future requests. If the next response doesn't match the

143

request, an error is returned and the registry is reset.

144

145

This enforces that requests must be made in the exact order

146

that responses were registered.

147

"""

148

```

149

150

**Usage Example:**

151

152

```python

153

from responses.registries import OrderedRegistry

154

155

def test_ordered_responses():

156

with responses.RequestsMock() as rsps:

157

# Switch to ordered registry

158

rsps.reset()

159

rsps._set_registry(OrderedRegistry)

160

161

# Register responses in specific order

162

rsps.add(responses.GET, "http://api.example.com/step1", json={"step": 1})

163

rsps.add(responses.POST, "http://api.example.com/step2", json={"step": 2})

164

rsps.add(responses.PUT, "http://api.example.com/step3", json={"step": 3})

165

166

# Requests must be made in exact order

167

step1 = requests.get("http://api.example.com/step1") # Uses first response

168

step2 = requests.post("http://api.example.com/step2") # Uses second response

169

step3 = requests.put("http://api.example.com/step3") # Uses third response

170

171

assert step1.json()["step"] == 1

172

assert step2.json()["step"] == 2

173

assert step3.json()["step"] == 3

174

175

# Registry is now empty - no more responses available

176

with pytest.raises(ConnectionError):

177

requests.get("http://api.example.com/step1") # Would fail

178

```

179

180

### Registry Usage Patterns

181

182

#### Simulating API Sequences

183

184

OrderedRegistry is useful for testing sequences of API calls that must happen in a specific order:

185

186

```python

187

def test_user_registration_flow():

188

with responses.RequestsMock() as rsps:

189

rsps._set_registry(OrderedRegistry)

190

191

# Step 1: Check email availability

192

rsps.add(

193

responses.GET,

194

"http://api.example.com/users/check-email?email=test@example.com",

195

json={"available": True}

196

)

197

198

# Step 2: Create user

199

rsps.add(

200

responses.POST,

201

"http://api.example.com/users",

202

json={"id": 123, "email": "test@example.com"},

203

status=201

204

)

205

206

# Step 3: Send verification email

207

rsps.add(

208

responses.POST,

209

"http://api.example.com/users/123/send-verification",

210

json={"sent": True}

211

)

212

213

# Run the registration flow

214

availability = requests.get("http://api.example.com/users/check-email?email=test@example.com")

215

assert availability.json()["available"] is True

216

217

user = requests.post("http://api.example.com/users", json={"email": "test@example.com"})

218

assert user.status_code == 201

219

220

verification = requests.post("http://api.example.com/users/123/send-verification")

221

assert verification.json()["sent"] is True

222

```

223

224

#### Simulating Different Response Patterns

225

226

FirstMatchRegistry allows the same endpoint to always return the same response:

227

228

```python

229

def test_stable_api_responses():

230

# Using default FirstMatchRegistry

231

responses.add(

232

responses.GET,

233

"http://api.example.com/config",

234

json={"api_version": "v1", "features": ["feature1", "feature2"]}

235

)

236

237

# Multiple calls to same endpoint return same response

238

config1 = requests.get("http://api.example.com/config")

239

config2 = requests.get("http://api.example.com/config")

240

241

assert config1.json() == config2.json()

242

```

243

244

### Registry Selection and Switching

245

246

Control which registry is used for response matching:

247

248

```python { .api }

249

# Using with RequestsMock constructor

250

mock = RequestsMock(registry=OrderedRegistry)

251

252

# Switching registry on existing mock (must reset first)

253

@responses.activate

254

def test_registry_switching():

255

# Start with default FirstMatchRegistry

256

responses.add(responses.GET, "http://api.example.com/test", json={"registry": "first"})

257

258

# Switch to OrderedRegistry

259

responses.reset() # Clear existing responses

260

responses.mock._set_registry(OrderedRegistry)

261

262

# Add new responses to OrderedRegistry

263

responses.add(responses.GET, "http://api.example.com/test", json={"registry": "ordered"})

264

```

265

266

### Custom Registry Implementation

267

268

Advanced users can implement custom registries by extending FirstMatchRegistry:

269

270

```python

271

class CustomRegistry(FirstMatchRegistry):

272

def find(self, request):

273

# Custom matching logic

274

# Must return (response_or_none, reasons_list)

275

pass

276

277

# Use custom registry

278

mock = RequestsMock(registry=CustomRegistry)

279

```

280

281

## Registry Error Handling

282

283

### OrderedRegistry Errors

284

285

OrderedRegistry raises specific errors when requests don't match the expected order:

286

287

```python

288

def test_order_mismatch_error():

289

with responses.RequestsMock() as rsps:

290

rsps._set_registry(OrderedRegistry)

291

292

rsps.add(responses.GET, "http://api.example.com/first", json={"order": 1})

293

rsps.add(responses.GET, "http://api.example.com/second", json={"order": 2})

294

295

# Skip first response and try second - will fail

296

with pytest.raises(ConnectionError) as exc_info:

297

requests.get("http://api.example.com/second")

298

299

error_message = str(exc_info.value)

300

assert "Next 'Response' in the order doesn't match" in error_message

301

```

302

303

### Registry State Management

304

305

```python { .api }

306

def registered():

307

"""

308

Get all currently registered responses.

309

310

Returns:

311

List of BaseResponse objects in the registry

312

313

Useful for debugging and verifying registry state.

314

"""

315

316

def reset():

317

"""

318

Clear all responses from the registry.

319

320

Resets the registry to empty state. Required before

321

switching registry types with _set_registry().

322

"""

323

```

324

325

**Usage Example:**

326

327

```python

328

@responses.activate

329

def test_registry_state():

330

# Add some responses

331

responses.add(responses.GET, "http://api.example.com/1", json={"id": 1})

332

responses.add(responses.GET, "http://api.example.com/2", json={"id": 2})

333

334

# Check registry state

335

registered_responses = responses.registered()

336

assert len(registered_responses) == 2

337

338

# Clear registry

339

responses.reset()

340

assert len(responses.registered()) == 0

341

```