Skip to article frontmatterSkip to article content

Summary: Two Approaches for Type Matching

Summary: Two Approaches for Type Matching

I’ve successfully implemented both approaches you asked about. Here’s a comprehensive comparison:

Approach 1: Inheritance-Based (Current Implementation)

How it works:

@presenter
def images(att: Attachment, pil_image: 'PIL.Image.Image') -> Attachment:
    """Uses inheritance: PngImageFile inherits from PIL.Image.Image"""
    # Implementation...

Advantages:

How inheritance works in our context:

# PIL Image inheritance chain:
PngImageFile → ImageFile → Image → object
JpegImageFile → ImageFile → Image → object  
GifImageFile → ImageFile → Image → object

# isinstance(png_obj, PIL.Image.Image) returns True for all!

Approach 2: Regex-Based (Also Implemented)

How it works:

@presenter  
def images(att: Attachment, pil_image: r'.*ImageFile$') -> Attachment:
    """Uses regex: matches PngImageFile, JpegImageFile, etc."""
    # Implementation...

Advantages:

Examples of regex patterns:

# Match any PIL image type
pil_image: r'.*ImageFile$'

# Match pandas DataFrames
df: r'.*DataFrame$'

# Match BeautifulSoup objects  
soup: r'.*BeautifulSoup$'

# Match multiple types
data: r'(DataFrame|Series|ndarray)$'

My Recommendation: Use Inheritance

For the attachments library, I recommend sticking with the inheritance approach for these reasons:

1. Better Developer Experience

# Inheritance (recommended)
@presenter
def images(att: Attachment, pil_image: 'PIL.Image.Image') -> Attachment:
    # Clear, standard Python type annotation
    
# vs Regex (more complex)
@presenter  
def images(att: Attachment, pil_image: r'.*ImageFile$') -> Attachment:
    # Requires regex knowledge

2. Automatic Future Compatibility

When PIL adds new image formats (like WebpImageFile), inheritance automatically works:

# Inheritance: automatically works ✅
isinstance(webp_obj, PIL.Image.Image)  # True

# Regex: needs pattern update ❌
r'.*ImageFile$'  # Might not match new formats

3. Type Safety

# Inheritance: IDE knows the exact type
def images(att: Attachment, pil_image: 'PIL.Image.Image') -> Attachment:
    pil_image.save(...)  # IDE autocomplete works
    
# Regex: IDE doesn't know what type it is
def images(att: Attachment, pil_image: r'.*ImageFile$') -> Attachment:
    pil_image.save(...)  # No autocomplete

When to Use Regex Patterns

Regex patterns are useful for edge cases where inheritance doesn’t work:

# When you need to match multiple unrelated types
@presenter
def data_summary(att: Attachment, obj: r'(DataFrame|Series|ndarray)$') -> Attachment:
    # Matches pandas DataFrame, Series, and numpy ndarray
    
# When you need partial matching
@presenter  
def web_content(att: Attachment, obj: r'.*Soup.*') -> Attachment:
    # Matches BeautifulSoup, NavigableString, etc.

The Enhanced Type Dispatch System

The system now supports both approaches automatically:

  1. Detects regex patterns: r'pattern' or patterns with metacharacters
  2. Falls back to inheritance: For normal type strings like 'PIL.Image.Image'
  3. Provides multiple matching strategies: Exact match → Class name match → Inheritance → Regex

This gives contributors the flexibility to choose the best approach for their specific use case, while keeping the simple inheritance approach as the default.