Skip to content

@patch breaks on iterable classes (e.g. Enums)@patch breaks on iterable classes (e.g. Enums) #825

Description

@ncoop57

Patching a method onto an Enum subclass fails:

from enum import Enum
from fastcore.basics import patch

class Color(Enum):
    RED = 1
    GREEN = 2

@patch(cls_method=True)
def from_name(cls: Color, s): return cls[s.upper()]
# AttributeError: 'Color' object has no attribute '__name__'

The cause is in patch_to, which calls tuplify(cls). An Enum class is
iterable, so instead of wrapping the class in a one-element tuple, tuplify
iterates it and returns its members. The loop body then runs against an enum
member instead of the class, and the member has no __name__.

This affects any class whose metaclass makes instances iterable, not just Enums.

A few shapes a fix could take:

  1. In patch_to, wrap the class directly instead of tuplifying it:
    classes = (cls,) if isinstance(cls, type) else tuplify(cls). This keeps
    list and union handling intact, since patch already converts unions to
    tuples via union2tuple.

  2. Same idea, but guard on tuples instead of types:
    classes = cls if isinstance(cls, tuple) else (cls,). Relies on unions
    always arriving as tuples, which holds for the patch path but not for
    direct patch_to calls with a bare union.

  3. Change tuplify (or listify) to not iterate types. Broader blast radius,
    since those are used widely.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions