๐Ÿ’ป Exercise: Exercise: A tool registry

๐Ÿ“ Instructions

Implement a ToolRegistry class with four methods. register(name, fn) stores a function under a name and raises ValueError on a duplicate name. has(name) returns a bool. names() returns the registered names as a sorted list. call(name, **kwargs) runs the registered function, raising KeyError for an unknown name. The registry is the lookup table that turns a parsed tool name into an actual callable. Standard library only.

๐Ÿงช Initial Code / Tests

๐Ÿ“„ evaluate.py
from unittest import TestCase
from exercise import ToolRegistry


class Evaluate(TestCase):
    def test_register_then_call(self):
        reg = ToolRegistry(); reg.register('add', lambda a, b: a + b)
        self.assertEqual(reg.call('add', a=2, b=3), 5)

    def test_names_are_sorted(self):
        reg = ToolRegistry(); reg.register('b', lambda: 1); reg.register('a', lambda: 2)
        self.assertEqual(reg.names(), ['a', 'b'])

    def test_duplicate_registration_raises(self):
        reg = ToolRegistry(); reg.register('x', lambda: 1)
        self.assertRaises(ValueError, reg.register, 'x', lambda: 2)

    def test_unknown_call_raises_keyerror(self):
        reg = ToolRegistry()
        self.assertRaises(KeyError, reg.call, 'ghost')

โœ… Solutions

๐Ÿ“„ exercise.py
class ToolRegistry:
    def __init__(self):
        self._tools = {}

    def register(self, name, fn):
        if name in self._tools:
            raise ValueError('already registered: ' + name)
        self._tools[name] = fn

    def has(self, name):
        return name in self._tools

    def names(self):
        return sorted(self._tools)

    def call(self, name, **kwargs):
        if name not in self._tools:
            raise KeyError(name)
        return self._tools[name](**kwargs)