Upgrading to ClassRegistry v5

ClassRegistry v5 introduces some changes that can break code that was previously using ClassRegistry v4. If you are upgrading from ClassRegistry v4 to ClassRegistry v5, you’ll need to make the following changes:

Type Parameters

I thought I’d start this off with some good news 😺

If a ClassRegistry always returns objects derived from a particular base class, you can now provide a type parameter to help with type checking, autocomplete, etc.:

# Add type parameter ``[Pokemon]``:
pokedex = ClassRegistry[Pokemon]()

# Your IDE will automatically infer that ``fighter1`` is a ``Pokemon``.
fighter1 = pokedex['fire']

ClassRegistryInstanceCache now inherits the type parameter from the ClassRegistry that it wraps in order to help with type checking, autocompletion, etc.:

# Add type parameter ``[Pokemon]``:
registry = ClassRegistry[Pokemon]()

# The ``ClassRegistryInstanceCache`` inherits the type parameters from the
# ``ClassRegistry`` that it wraps.
pokedex = ClassRegistryInstanceCache(registry)

# Your IDE will automatically infer that ``fire_fighter`` is a ``Pokemon``.
fire_fighter = pokedex['fire']

Alternatively, you can apply the type parameter to the ClassRegistryInstanceCache directly:

pokedex = ClassRegistryInstanceCache[Pokemon](registry)

Imports

Now for the tricky parts.

In ClassRegistry v5 many symbols were removed from the top-level class_registry namespace. The table below shows how to import each symbol in ClassRegistry v5 in your code:

Symbol

How to Import in ClassRegistry v5

AutoRegister()

from class_registry.base import AutoRegister

ClassRegistry

from class_registry import Classregistry (unchanged)

ClassRegistryInstanceCache

from class_registry.cache import ClassRegistryInstanceCache

EntryPointClassRegistry

from class_registry.entry_points import EntryPointClassRegistry

RegistryKeyError

from class_registry import RegistryKeyError (unchanged)

RegistryPatcher

from class_registry.patcher import RegistryPatcher

SortedClassRegistry

from class_registry.registry import SortedClassRegistry

AutoRegister

In ClassRegistry v5, AutoRegister() now returns a base class instead of a metaclass. The example below shows how to update classes that use AutoRegister():

ClassRegistry v4:

from class_registry import AutoRegister

class MyBaseClass(metaclass=AutoRegister(my_registry)):
    ...

ClassRegistry v5:

from abc import ABC
from class_registry.base import AutoRegister

class MyBaseClass(AutoRegister(my_registry), ABC):
    ...

Note

If this is a non-trivial change for your code, you can continue to use the (deprecated) metaclass version of AutoRegister() which is located at class_registry.auto_register.AutoRegister.

The metaclass version of AutoRegister() will be removed in a future version of ClassRegistry, so it’s recommended that you update your code. If you need help, post in the ClassRegistry issue tracker, and I’ll have a look πŸ™‚

Other Changes

BaseRegistry

Important

BaseRegistry no longer implements typing.Mapping due to violations of the Liskov Substitutability Principle:

>>> isinstance(ClassRegistry(), typing.Mapping)
False

If your code relies on the previous behaviour, post in the ClassRegistry issue tracker, so that we can find an alternative solution.

Additionally, the following methods have been deprecated and will be removed in a future version:

  • BaseRegistry.items() is deprecated. If you still need this functionality, use the following workaround:

    ClassRegistry v4:

    registry.items()
    

    ClassRegistry v5:

    zip(registry.keys(), registry.classes())
    
  • BaseRegistry.values() is now renamed to BaseRegistry.classes():

    ClassRegistry v4:

    registry.values()
    

    ClassRegistry v5:

    registry.classes()
    

BaseMutableRegistry

Important

BaseMutableRegistry no longer implements typing.MutableMapping due to violations of the Liskov Substitutability Principle:

>>> isinstance(ClassRegistry(), typing.MutableMapping)
False

If your code relies on the previous behaviour, post in the ClassRegistry issue tracker, so that we can find an alternative solution.

  • BaseMutableRegistry.__delitem__() method has been removed. Use the unregister() method instead:

    ClassRegistry v4:

    del registry["fire"]
    

    ClassRegistry v5:

    registry.unregister("fire")
    
  • BaseMutableRegistry.__setitem__() method has been removed. Use the register() method instead:

    ClassRegistry v4:

    registry["fire"] = Charizard
    

    ClassRegistry v5:

    registry.register("fire")(Charizard)
    

    Note

    If you initialised the ClassRegistry with unique=True, you will need to unregister() the key first:

    >>> registry = ClassRegistry(unique=True)
    >>> registry.register(Charmander)
    
    # Attempting to register over an existing class will fail.
    >>> registry.register("fire")(Charizard)
    RegistryKeyError: <class Charmander>
    
    # Instead, unregister the current class and then register the new one.
    >>> registry.unregister("fire")
    >>> registry.register("fire")(Charizard)
    

New Methods

The following methods have been added:

  • BaseRegistry.__dir__() method returns the list of registered keys as strings.

  • BaseRegistry.__len__() method returns the number of registered symbols.