{"record":{"id":"1aea51b45af91809","repo":"python/cpython","slug":"can-only-register-classes","errorCode":null,"errorMessage":"Can only register classes","messagePattern":"Can only register classes","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"Lib/_py_abc.py","lineNumber":60,"sourceCode":"            for name in getattr(base, \"__abstractmethods__\", set()):\n                value = getattr(cls, name, None)\n                if getattr(value, \"__isabstractmethod__\", False):\n                    abstracts.add(name)\n        cls.__abstractmethods__ = frozenset(abstracts)\n        # Set up inheritance registry\n        cls._abc_registry = WeakSet()\n        cls._abc_cache = WeakSet()\n        cls._abc_negative_cache = WeakSet()\n        cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter\n        return cls\n\n    def register(cls, subclass):\n        \"\"\"Register a virtual subclass of an ABC.\n\n        Returns the subclass, to allow usage as a class decorator.\n        \"\"\"\n        if not isinstance(subclass, type):\n            raise TypeError(\"Can only register classes\")\n        if issubclass(subclass, cls):\n            return subclass  # Already a subclass\n        # Subtle: test for cycles *after* testing for \"already a subclass\";\n        # this means we allow X.register(X) and interpret it as a no-op.\n        if issubclass(cls, subclass):\n            # This would create a cycle, which is bad for the algorithm below\n            raise RuntimeError(\"Refusing to create an inheritance cycle\")\n        cls._abc_registry.add(subclass)\n        ABCMeta._abc_invalidation_counter += 1  # Invalidate negative cache\n        return subclass\n\n    def _dump_registry(cls, file=None):\n        \"\"\"Debug helper to print the ABC registry.\"\"\"\n        print(f\"Class: {cls.__module__}.{cls.__qualname__}\", file=file)\n        print(f\"Inv. counter: {get_cache_token()}\", file=file)\n        for name in cls.__dict__:\n            if name.startswith(\"_abc_\"):\n                value = getattr(cls, name)","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_py_abc.py#L42-L78","documentation":"Raised by ABCMeta.register (pure-Python fallback in _py_abc, mirrored by the C _abc implementation) when the argument is not a class. register() exists to register an existing class as a virtual subclass of the ABC; passing an instance, a module, or any non-type object raises TypeError('Can only register classes').","triggerScenarios":"Calling MyABC.register(x) where isinstance(x, type) is false — e.g. registering an instance (MyABC.register(obj)), a function, or a module object instead of its class. Also happens with dynamic objects like mocks or partials passed as 'subclass'.","commonSituations":"Confusing registration of an instance vs its class (register(instance) instead of register(type(instance))); passing a class object stored via __class__ string; test code registering MagicMock; wrapper libraries that accept 'either class or instance' and forward blindly to register().","solutions":["Pass the class object: MyABC.register(type(obj)) or the class name itself","If the target is defined dynamically, ensure you pass the type object created by type()/metaclass calls, not an instance","Guard the call: only register when isinstance(candidate, type)"],"exampleFix":"# before\nfrom abc import ABC\n\nclass Drawable(ABC):\n    pass\n\nd = SomeShape()\nDrawable.register(d)          # TypeError: Can only register classes\n\n# after\nDrawable.register(SomeShape)  # register the class","handlingStrategy":"type-guard","validationCode":"def safe_register(abc, candidate):\n    if not isinstance(candidate, type):\n        raise TypeError(f'expected a class, got {candidate!r}')\n    return abc.register(candidate)","typeGuard":"def is_class(obj) -> bool:\n    return isinstance(obj, type)","tryCatchPattern":"try:\n    MyABC.register(target)\nexcept TypeError as e:\n    if 'Can only register classes' in str(e):\n        target = type(target)  # fall back to the instance's class\n        MyABC.register(target)\n    else:\n        raise","preventionTips":["Always pass the class object to ABC.register, never an instance","In dynamic plugin loaders, gate registration on isinstance(plugin, type)","Prefer structural checks (__subclasshook__/Protocols) when the registrant may not be a class"],"tags":["abc","typing","subclass","runtime"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}