or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

backends.mdcore-jsonrpc.mddispatcher.mdexceptions.mdindex.mdrequests-responses.md

dispatcher.mddocs/

0

# Method Dispatching

1

2

Flexible method registration and dispatch system supporting functions, classes, objects, decorators, and context injection. The Dispatcher class provides a dictionary-like interface for mapping method names to callable functions with extensive customization options.

3

4

## Capabilities

5

6

### Core Dispatcher

7

8

Dictionary-like object that maps method names to callable functions, implementing the MutableMapping interface for standard dictionary operations.

9

10

```python { .api }

11

class Dispatcher:

12

def __init__(self, prototype = None):

13

"""

14

Initialize dispatcher with optional prototype.

15

16

Parameters:

17

- prototype: Initial method mapping (dict or object with callable attributes)

18

"""

19

20

# Dictionary interface

21

def __getitem__(self, key: str):

22

"""Get method by name."""

23

24

def __setitem__(self, key: str, value):

25

"""Set method by name."""

26

27

def __delitem__(self, key: str):

28

"""Remove method by name."""

29

30

def __len__(self) -> int:

31

"""Number of registered methods."""

32

33

def __iter__(self):

34

"""Iterate over method names."""

35

36

def __repr__(self) -> str:

37

"""String representation of method mapping."""

38

39

# Properties

40

method_map: dict # Internal method storage

41

context_arg_for_method: dict # Context argument mapping

42

```

43

44

### Method Registration

45

46

Multiple ways to register methods with flexible naming and context injection support.

47

48

```python { .api }

49

def add_method(self, f = None, name: str = None, context_arg: str = None):

50

"""

51

Add a method to the dispatcher.

52

53

Parameters:

54

- f: Callable to register

55

- name: Method name (defaults to function name)

56

- context_arg: Parameter name that will receive context data

57

58

Returns:

59

The original function (for decorator usage)

60

61

Usage:

62

- As method: dispatcher.add_method(func, "name")

63

- As decorator: @dispatcher.add_method

64

- With custom name: @dispatcher.add_method(name="custom")

65

- With context: @dispatcher.add_method(context_arg="ctx")

66

"""

67

```

68

69

### Bulk Registration

70

71

Register multiple methods from classes, objects, or dictionaries with optional prefixing.

72

73

```python { .api }

74

def add_class(self, cls):

75

"""

76

Add all public methods from a class.

77

78

Parameters:

79

- cls: Class to register methods from

80

81

Methods are prefixed with lowercase class name + '.'

82

"""

83

84

def add_object(self, obj):

85

"""

86

Add all public methods from an object instance.

87

88

Parameters:

89

- obj: Object instance to register methods from

90

91

Methods are prefixed with lowercase class name + '.'

92

"""

93

94

def add_dict(self, dict: dict, prefix: str = ''):

95

"""

96

Add methods from dictionary.

97

98

Parameters:

99

- dict: Dictionary of name -> callable mappings

100

- prefix: Optional prefix for method names

101

"""

102

103

def build_method_map(self, prototype, prefix: str = ''):

104

"""

105

Build method map from prototype object or dictionary.

106

107

Parameters:

108

- prototype: Object or dict to extract methods from

109

- prefix: Optional prefix for method names

110

"""

111

```

112

113

### Global Dispatcher Instance

114

115

Pre-created dispatcher instance available for immediate use.

116

117

```python { .api }

118

# Global dispatcher instance

119

dispatcher: Dispatcher

120

```

121

122

## Usage Examples

123

124

### Basic Method Registration

125

126

```python

127

from jsonrpc import dispatcher, JSONRPCResponseManager

128

129

# Method 1: Using decorator

130

@dispatcher.add_method

131

def add(a, b):

132

"""Add two numbers."""

133

return a + b

134

135

@dispatcher.add_method

136

def multiply(x, y):

137

"""Multiply two numbers."""

138

return x * y

139

140

# Method 2: Direct registration

141

def subtract(a, b):

142

return a - b

143

144

dispatcher.add_method(subtract)

145

146

# Method 3: Dictionary-style assignment

147

dispatcher["divide"] = lambda a, b: a / b

148

149

# Test the methods

150

request = '{"jsonrpc": "2.0", "method": "add", "params": [5, 3], "id": 1}'

151

response = JSONRPCResponseManager.handle(request, dispatcher)

152

print(response.json)

153

# {"jsonrpc": "2.0", "result": 8, "id": 1}

154

```

155

156

### Custom Method Names

157

158

```python

159

from jsonrpc import Dispatcher

160

161

dispatcher = Dispatcher()

162

163

# Custom name with decorator

164

@dispatcher.add_method(name="math.add")

165

def addition(a, b):

166

return a + b

167

168

# Custom name with method call

169

def multiplication(a, b):

170

return a * b

171

172

dispatcher.add_method(multiplication, name="math.multiply")

173

174

# Dictionary-style with custom name

175

dispatcher["math.power"] = lambda base, exp: base ** exp

176

177

# Usage

178

request = '{"jsonrpc": "2.0", "method": "math.add", "params": [2, 3], "id": 1}'

179

response = JSONRPCResponseManager.handle(request, dispatcher)

180

print(response.json)

181

# {"jsonrpc": "2.0", "result": 5, "id": 1}

182

```

183

184

### Context Injection

185

186

```python

187

from jsonrpc import Dispatcher, JSONRPCResponseManager

188

189

dispatcher = Dispatcher()

190

191

# Method that receives context

192

@dispatcher.add_method(context_arg="context")

193

def get_request_info(context):

194

"""Return information about the current request."""

195

request = context.get("request")

196

return {

197

"request_id": request._id if request else None,

198

"method": request.method if request else None,

199

"user": context.get("user", "anonymous")

200

}

201

202

@dispatcher.add_method(context_arg="ctx")

203

def calculate_with_audit(a, b, operation, ctx):

204

"""Perform calculation with audit logging."""

205

result = a + b if operation == "add" else a * b

206

207

# Access context data

208

user = ctx.get("user", "unknown")

209

timestamp = ctx.get("timestamp")

210

211

return {

212

"result": result,

213

"calculated_by": user,

214

"timestamp": timestamp

215

}

216

217

# Handle request with context

218

context = {

219

"user": "alice",

220

"timestamp": "2023-01-01T12:00:00Z",

221

"session_id": "abc123"

222

}

223

224

request = '{"jsonrpc": "2.0", "method": "get_request_info", "id": 1}'

225

response = JSONRPCResponseManager.handle(request, dispatcher, context)

226

print(response.json)

227

# {"jsonrpc": "2.0", "result": {"request_id": 1, "method": "get_request_info", "user": "alice"}, "id": 1}

228

```

229

230

### Class and Object Registration

231

232

```python

233

from jsonrpc import Dispatcher

234

235

# Example service class

236

class MathService:

237

def add(self, a, b):

238

return a + b

239

240

def subtract(self, a, b):

241

return a - b

242

243

def _private_method(self):

244

# Private methods (starting with _) are not registered

245

return "private"

246

247

class StringService:

248

def __init__(self, prefix=""):

249

self.prefix = prefix

250

251

def upper(self, text):

252

return (self.prefix + text).upper()

253

254

def lower(self, text):

255

return (self.prefix + text).lower()

256

257

dispatcher = Dispatcher()

258

259

# Register all public methods from class (creates new instance)

260

dispatcher.add_class(MathService)

261

262

# Register methods from specific object instance

263

string_service = StringService("Hello ")

264

dispatcher.add_object(string_service)

265

266

# Methods are prefixed with class name

267

print(list(dispatcher.method_map.keys()))

268

# ['mathservice.add', 'mathservice.subtract', 'stringservice.upper', 'stringservice.lower']

269

270

# Usage

271

request = '{"jsonrpc": "2.0", "method": "mathservice.add", "params": [10, 5], "id": 1}'

272

response = JSONRPCResponseManager.handle(request, dispatcher)

273

print(response.json)

274

# {"jsonrpc": "2.0", "result": 15, "id": 1}

275

```

276

277

### Dictionary Registration

278

279

```python

280

from jsonrpc import Dispatcher

281

282

# Create method dictionary

283

math_methods = {

284

"add": lambda a, b: a + b,

285

"multiply": lambda a, b: a * b,

286

"power": lambda base, exp: base ** exp

287

}

288

289

string_methods = {

290

"upper": str.upper,

291

"lower": str.lower,

292

"capitalize": str.capitalize

293

}

294

295

dispatcher = Dispatcher()

296

297

# Register with prefix

298

dispatcher.add_dict(math_methods, prefix="math")

299

dispatcher.add_dict(string_methods, prefix="string")

300

301

print(list(dispatcher.method_map.keys()))

302

# ['math.add', 'math.multiply', 'math.power', 'string.upper', 'string.lower', 'string.capitalize']

303

304

# Usage

305

request = '{"jsonrpc": "2.0", "method": "string.upper", "params": ["hello world"], "id": 1}'

306

response = JSONRPCResponseManager.handle(request, dispatcher)

307

print(response.json)

308

# {"jsonrpc": "2.0", "result": "HELLO WORLD", "id": 1}

309

```

310

311

### Prototype Initialization

312

313

```python

314

from jsonrpc import Dispatcher

315

316

# Initialize with function dictionary

317

initial_methods = {

318

"ping": lambda: "pong",

319

"echo": lambda msg: msg,

320

"add": lambda a, b: a + b

321

}

322

323

dispatcher = Dispatcher(prototype=initial_methods)

324

325

# Initialize with object

326

class APIService:

327

def status(self):

328

return "running"

329

330

def version(self):

331

return "1.0.0"

332

333

api_dispatcher = Dispatcher(prototype=APIService())

334

335

print(list(api_dispatcher.method_map.keys()))

336

# ['status', 'version']

337

338

# Add more methods later

339

@api_dispatcher.add_method

340

def shutdown():

341

return "shutting down"

342

```

343

344

### Method Removal and Management

345

346

```python

347

from jsonrpc import Dispatcher

348

349

dispatcher = Dispatcher()

350

351

# Add methods

352

dispatcher["add"] = lambda a, b: a + b

353

dispatcher["subtract"] = lambda a, b: a - b

354

dispatcher["multiply"] = lambda a, b: a * b

355

356

print(len(dispatcher)) # 3

357

print("add" in dispatcher) # True

358

359

# Remove method

360

del dispatcher["subtract"]

361

print(len(dispatcher)) # 2

362

363

# Clear all methods

364

dispatcher.method_map.clear()

365

print(len(dispatcher)) # 0

366

367

# Check available methods

368

@dispatcher.add_method

369

def test():

370

return "test"

371

372

print(list(dispatcher)) # ['test']

373

print(repr(dispatcher)) # {'test': <function test at 0x...>}

374

```