Ejemplo n.º 1
0
    def test_new_instance_every_time(self):
        """
        Every time a registered class is invoked, a new instance is
        returned.
        """
        registry = ClassRegistry(attr_name='element')
        registry.register(Wartortle)

        self.assertIsNot(registry['water'], registry['water'])
Ejemplo n.º 2
0
    def test_register_function(self):
        """
        Functions can be registered as well (so long as they walk, talk
        and quack like a class).
        """
        registry = ClassRegistry()

        @registry.register('fire')
        def pokemon_factory(name=None):
            return Charmeleon(name=name)

        poke = registry.get('fire', name='trogdor')

        self.assertIsInstance(poke, Charmeleon)
        self.assertEqual(poke.name, 'trogdor')
Ejemplo n.º 3
0
    def test_register_error_empty_key(self):
        """
        Attempting to register a class with an empty key.
        """
        registry = ClassRegistry('element')

        with self.assertRaises(ValueError):
            # noinspection PyUnusedLocal
            @registry.register(None)
            class Ponyta(Pokemon):
                element = 'fire'

        with self.assertRaises(ValueError):
            # noinspection PyUnusedLocal
            @registry.register('')
            class Rapidash(Pokemon):
                element = 'fire'

        with self.assertRaises(ValueError):
            # noinspection PyUnusedLocal
            @registry.register
            class Mew(Pokemon):
                element = None

        with self.assertRaises(ValueError):
            # noinspection PyUnusedLocal
            @registry.register
            class Mewtwo(Pokemon):
                element = ''
Ejemplo n.º 4
0
    def test_register_detect_keys(self):
        """
        If an attribute name is passed to ClassRegistry's constructor,
        it will automatically check for this attribute when
        registering classes.
        """
        registry = ClassRegistry(attr_name='element')

        @registry.register
        class Charizard(Pokemon):
            element = 'fire'

        @registry.register
        class Blastoise(Pokemon):
            element = 'water'

        # You can still override the registry key if you want.
        @registry.register('poison')
        class Venusaur(Pokemon):
            element = 'grass'

        self.assertIsInstance(registry['fire'], Charizard)
        self.assertIsInstance(registry['water'], Blastoise)
        self.assertIsInstance(registry['poison'], Venusaur)

        # We overrode the registry key for this class.
        with self.assertRaises(RegistryKeyError):
            # noinspection PyStatementEffect
            registry['grass']
Ejemplo n.º 5
0
    def test_register_manual_keys(self):
        """
        Registers a few classes with manually-assigned identifiers and
        verifies that the factory returns them correctly.
        """
        registry = ClassRegistry()

        @registry.register('fire')
        class Charizard(Pokemon):
            pass

        @registry.register('water')
        class Blastoise(Pokemon):
            pass

        # By default, you have to specify a registry key when
        # registering new classes.  We'll see how to assign
        # registry keys automatically in the next test.
        with self.assertRaises(ValueError):
            # noinspection PyUnusedLocal
            @registry.register
            class Venusaur(Pokemon):
                pass

        self.assertIsInstance(registry['fire'], Charizard)
        self.assertIsInstance(registry['water'], Blastoise)
Ejemplo n.º 6
0
    def test_contains_when_class_init_requires_arguments(self):
        """
        Special case when checking if a class is registered, and that class'
        initializer requires arguments.
        """
        registry = ClassRegistry(attr_name='element')

        @registry.register
        class Butterfree(Pokemon):
            element = 'bug'

            def __init__(self, name):
                super(Butterfree, self).__init__(name)

        self.assertTrue('bug' in registry)
Ejemplo n.º 7
0
    def test_unique_keys(self):
        """
        Specifying ``unique=True`` when creating the registry requires
        all keys to be unique.
        """
        registry = ClassRegistry(attr_name='element', unique=True)

        # We can register any class like normal...
        # noinspection PyUnusedLocal
        registry.register(Charmander)

        # ... but if we try to register a second class with the same
        # key, we get an error.
        with self.assertRaises(RegistryKeyError):
            registry.register(Charmeleon)
Ejemplo n.º 8
0
    def test_constructor_params(self):
        """
        Params can be passed to the registered class' constructor.
        """
        registry = ClassRegistry(attr_name='element')
        registry.register(Bulbasaur)

        # Goofus uses positional arguments, which are magical and
        # make his code more difficult to read.
        goofus  = registry.get('grass', 'goofus')

        # Gallant uses keyword arguments, producing self-documenting
        # code and being courteous to his fellow developers.
        # He still names his pokémon after himself, though. Narcissist.
        gallant = registry.get('grass', name='gallant')

        self.assertIsInstance(goofus, Bulbasaur)
        self.assertEqual(goofus.name, 'goofus')

        self.assertIsInstance(gallant, Bulbasaur)
        self.assertEqual(gallant.name, 'gallant')
Ejemplo n.º 9
0
    def setUp(self):
        super(ClassRegistryInstanceCacheTestCase, self).setUp()

        self.registry = ClassRegistry(attr_name='element')
        self.cache = ClassRegistryInstanceCache(self.registry)
Ejemplo n.º 10
0
class ClassRegistryInstanceCacheTestCase(TestCase):
    def setUp(self):
        super(ClassRegistryInstanceCacheTestCase, self).setUp()

        self.registry = ClassRegistry(attr_name='element')
        self.cache = ClassRegistryInstanceCache(self.registry)

    def test_get(self):
        """
        When an instance is returned from
        :py:meth:`ClassRegistryInstanceCache.get`, future invocations
        return the same instance.
        """
        # Register a few classes with the ClassRegistry.
        self.registry.register(Bulbasaur)
        self.registry.register(Charmander)
        self.registry.register(Squirtle)

        poke_1 = self.cache['grass']
        self.assertIsInstance(poke_1, Bulbasaur)

        # Same key = exact same instance.
        poke_2 = self.cache['grass']
        self.assertIs(poke_2, poke_1)

        poke_3 = self.cache['water']
        self.assertIsInstance(poke_3, Squirtle)

        # If we pull a class directly from the wrapped registry, we get
        # a new instance.
        poke_4 = self.registry['water']
        self.assertIsInstance(poke_4, Squirtle)
        self.assertIsNot(poke_3, poke_4)

    def test_template_args(self):
        """
        Extra params passed to the cache constructor are passed to the
        template function when creating new instances.
        """
        self.registry.register(Charmeleon)
        self.registry.register(Wartortle)

        # Add an extra init param to the cache.
        cache = ClassRegistryInstanceCache(self.registry, name='Bruce')

        # The cache parameters are automatically applied to the class'
        # initializer.
        poke_1 = cache['fire']
        self.assertIsInstance(poke_1, Charmeleon)
        self.assertEqual(poke_1.name, 'Bruce')

        poke_2 = cache['water']
        self.assertIsInstance(poke_2, Wartortle)
        self.assertEqual(poke_2.name, 'Bruce')

    def test_iterator(self):
        """
        Creating an iterator using :py:func:`iter`.
        """
        self.registry.register(Bulbasaur)
        self.registry.register(Charmander)
        self.registry.register(Squirtle)

        # The cache's iterator only operates over cached instances.
        self.assertListEqual(list(iter(self.cache)), [])

        poke_1 = self.cache['water']
        poke_2 = self.cache['grass']
        poke_3 = self.cache['fire']

        # The order that values are yielded depends on the ordering of
        # the wrapped registry.
        self.assertListEqual(
            list(iter(self.cache)),
            [poke_2, poke_3, poke_1],
        )
Ejemplo n.º 11
0
    def setUp(self):
        super(RegistryPatcherTestCase, self).setUp()

        self.registry = ClassRegistry(attr_name='element', unique=True)
Ejemplo n.º 12
0
class RegistryPatcherTestCase(TestCase):
    def setUp(self):
        super(RegistryPatcherTestCase, self).setUp()

        self.registry = ClassRegistry(attr_name='element', unique=True)

    def test_patch_detect_keys(self):
        """
        Patching a registry in a context, with registry keys detected
        automatically.
        """
        self.registry.register(Charmander)
        self.registry.register(Squirtle)

        with RegistryPatcher(self.registry, Charmeleon, Bulbasaur):
            self.assertIsInstance(self.registry['fire'], Charmeleon)
            self.assertIsInstance(self.registry['water'], Squirtle)

            # Nesting contexts?  You betcha!
            with RegistryPatcher(self.registry, Ivysaur):
                self.assertIsInstance(self.registry['grass'], Ivysaur)

            self.assertIsInstance(self.registry['grass'], Bulbasaur)

        # Save file corrupted.  Restoring previous save...
        self.assertIsInstance(self.registry['fire'], Charmander)
        self.assertIsInstance(self.registry['water'], Squirtle)

        with self.assertRaises(RegistryKeyError):
            self.registry.get('grass')

    def test_patch_manual_keys(self):
        """
        Patching a registry in a context, specifying registry keys
        manually.
        """
        self.registry.register('sparky')(Charmander)
        self.registry.register('chad')(Squirtle)

        with RegistryPatcher(self.registry, sparky=Charmeleon, rex=Bulbasaur):
            self.assertIsInstance(self.registry['sparky'], Charmeleon)
            self.assertIsInstance(self.registry['chad'], Squirtle)

            # Don't worry Chad; your day will come!
            with RegistryPatcher(self.registry, rex=Ivysaur):
                self.assertIsInstance(self.registry['rex'], Ivysaur)

            self.assertIsInstance(self.registry['rex'], Bulbasaur)

        # Save file corrupted.  Restoring previous save...
        self.assertIsInstance(self.registry['sparky'], Charmander)
        self.assertIsInstance(self.registry['chad'], Squirtle)

        with self.assertRaises(RegistryKeyError):
            self.registry.get('jodie')
Ejemplo n.º 13
0
    def test_unregister(self):
        """
        Removing a class from the registry.

        This is not used that often outside of unit tests (e.g., to
        remove artifacts when a test has to add a class to a global
        registry).
        """
        registry = ClassRegistry(attr_name='element')
        registry.register(Charmander)
        registry.register(Squirtle)

        # Don't feel bad Bulbasaur!  Actually, you're my favorite!

        self.assertIs(registry.unregister('fire'), Charmander)

        with self.assertRaises(RegistryKeyError):
            registry.get('fire')

        # Note that you must unregister the KEY, not the CLASS.
        with self.assertRaises(KeyError):
            # noinspection PyTypeChecker
            registry.unregister(Squirtle)

        # If you try to unregister a key that isn't registered, you'll
        # get an error.
        with self.assertRaises(KeyError):
            registry.unregister('fire')