Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Oct 28, 2025

📄 1,539% (15.39x) speedup for _ext_use_tables in src/bokeh/embed/bundle.py

⏱️ Runtime : 57.8 milliseconds 3.53 milliseconds (best of 215 runs)

📝 Explanation and details

The optimization reduces algorithmic complexity by eliminating redundant work in the nested loop structure.

Key changes:

  1. Combined conditional check: if name == "bokeh" or name in names: reduces duplicate name lookups
  2. Pre-grouping models by module prefix: Instead of checking every model against every extension name (O(N×M)), models are grouped once by their module prefix, then only relevant models are checked for each extension

Performance impact:
The original code performed ~955,000 model.__module__.startswith(name) checks across all models for each extension name. The optimized version groups models upfront, reducing this to only checking models that actually belong to each extension's module prefix.

Test case benefits:

  • Large-scale tests show dramatic improvements (5000-7000% faster) when many objects/models are involved
  • Smaller test cases show modest slowdowns (20-40%) due to the overhead of pre-grouping, but this is vastly outweighed by the gains in realistic scenarios with substantial model collections
  • The optimization particularly excels when HasProps.model_class_reverse_map contains many models, as it avoids the expensive nested iteration that dominated the original runtime profile (98.7% of execution time)

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 37 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 1 Passed
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
from __future__ import annotations

from typing import Callable

# imports
import pytest
from bokeh.embed.bundle import _ext_use_tables


# Minimal HasProps stub for testing
class HasProps:
    # Simulate Bokeh's model_class_reverse_map
    model_class_reverse_map = {}

    def __init__(self, view_module: str, implementation: bool = False):
        self.__view_module__ = view_module
        if implementation:
            self.__implementation__ = True

# Minimal TableWidget stub for testing
class TableWidget(HasProps):
    pass

# Minimal other widget stub for testing
class OtherWidget(HasProps):
    pass

# Simulate the reverse map as used by _query_extensions
def setup_model_class_reverse_map(models):
    HasProps.model_class_reverse_map = {i: m for i, m in enumerate(models)}
from bokeh.embed.bundle import _ext_use_tables

# ------------------------------
# Unit tests for _ext_use_tables
# ------------------------------

# Basic Test Cases

def test_no_objects_returns_false():
    """Test that an empty set returns False."""
    setup_model_class_reverse_map([TableWidget, OtherWidget])
    codeflash_output = _ext_use_tables(set()) # 4.35μs -> 4.56μs (4.50% slower)

def test_only_bokeh_objects_returns_false():
    """Test that objects from 'bokeh' module are ignored."""
    obj = HasProps(view_module="bokeh.models.widgets")
    setup_model_class_reverse_map([TableWidget, OtherWidget])
    codeflash_output = _ext_use_tables({obj}) # 4.85μs -> 5.01μs (3.33% slower)

def test_object_with_implementation_returns_false():
    """Test that objects with __implementation__ are ignored."""
    obj = HasProps(view_module="custom.models.widgets", implementation=True)
    setup_model_class_reverse_map([TableWidget, OtherWidget])
    codeflash_output = _ext_use_tables({obj}) # 4.28μs -> 4.16μs (2.89% faster)

def test_non_tablewidget_objects_returns_false():
    """Test that non-TableWidget objects do not trigger True."""
    obj = HasProps(view_module="custom.models.widgets")
    # Only OtherWidget in reverse map, not TableWidget
    setup_model_class_reverse_map([OtherWidget])
    codeflash_output = _ext_use_tables({obj}) # 71.8μs -> 96.4μs (25.5% slower)

def test_single_tablewidget_object_returns_true():
    """Test that a TableWidget subclass triggers True."""
    obj = HasProps(view_module="custom.models.widgets")
    # TableWidget in reverse map, module startswith 'custom'
    TableWidget.__module__ = "custom.models.widgets"
    setup_model_class_reverse_map([TableWidget])
    codeflash_output = _ext_use_tables({obj}) # 63.3μs -> 87.3μs (27.4% slower)

def test_multiple_objects_one_tablewidget_returns_true():
    """Test that True is returned if any object matches TableWidget."""
    obj1 = HasProps(view_module="custom.models.widgets")
    obj2 = HasProps(view_module="another.models.widgets")
    TableWidget.__module__ = "custom.models.widgets"
    OtherWidget.__module__ = "another.models.widgets"
    setup_model_class_reverse_map([TableWidget, OtherWidget])
    codeflash_output = _ext_use_tables({obj1, obj2}) # 90.6μs -> 86.1μs (5.24% faster)

def test_multiple_objects_none_tablewidget_returns_false():
    """Test that False is returned if no objects match TableWidget."""
    obj1 = HasProps(view_module="custom.models.widgets")
    obj2 = HasProps(view_module="another.models.widgets")
    OtherWidget.__module__ = "custom.models.widgets"
    setup_model_class_reverse_map([OtherWidget])
    codeflash_output = _ext_use_tables({obj1, obj2}) # 86.9μs -> 82.0μs (6.07% faster)

# Edge Test Cases

def test_duplicate_module_names_only_checked_once():
    """Test that duplicate module names are only checked once."""
    obj1 = HasProps(view_module="custom.models.widgets")
    obj2 = HasProps(view_module="custom.models.widgets")
    TableWidget.__module__ = "custom.models.widgets"
    setup_model_class_reverse_map([TableWidget])
    codeflash_output = _ext_use_tables({obj1, obj2}) # 55.8μs -> 84.1μs (33.6% slower)

def test_module_name_with_dot_and_tablewidget():
    """Test that module names with dots are parsed correctly."""
    obj = HasProps(view_module="custom.widgets.submodule")
    TableWidget.__module__ = "custom.widgets.submodule"
    setup_model_class_reverse_map([TableWidget])
    codeflash_output = _ext_use_tables({obj}) # 60.1μs -> 87.1μs (31.0% slower)

def test_module_name_with_dot_and_no_tablewidget():
    """Test that module names with dots are parsed correctly when no TableWidget."""
    obj = HasProps(view_module="custom.widgets.submodule")
    OtherWidget.__module__ = "custom.widgets.submodule"
    setup_model_class_reverse_map([OtherWidget])
    codeflash_output = _ext_use_tables({obj}) # 51.8μs -> 87.6μs (40.8% slower)

def test_object_with_empty_view_module():
    """Test that objects with an empty view_module do not crash."""
    obj = HasProps(view_module="")
    TableWidget.__module__ = ""
    setup_model_class_reverse_map([TableWidget])
    codeflash_output = _ext_use_tables({obj}) # 106μs -> 84.5μs (26.0% faster)

def test_object_with_non_string_view_module():
    """Test that objects with non-string view_module raise AttributeError."""
    obj = HasProps(view_module=123)
    TableWidget.__module__ = "123"
    setup_model_class_reverse_map([TableWidget])
    with pytest.raises(AttributeError):
        _ext_use_tables({obj}) # 5.56μs -> 5.90μs (5.68% slower)

def test_reverse_map_empty_returns_false():
    """Test that an empty model_class_reverse_map returns False."""
    obj = HasProps(view_module="custom.models.widgets")
    HasProps.model_class_reverse_map = {}
    codeflash_output = _ext_use_tables({obj}) # 70.2μs -> 95.0μs (26.1% slower)

def test_reverse_map_with_non_matching_module_returns_false():
    """Test that reverse map models with non-matching modules do not trigger True."""
    obj = HasProps(view_module="custom.models.widgets")
    TableWidget.__module__ = "other.models.widgets"
    setup_model_class_reverse_map([TableWidget])
    codeflash_output = _ext_use_tables({obj}) # 60.4μs -> 87.0μs (30.5% slower)

# Large Scale Test Cases

def test_many_objects_one_tablewidget_returns_true():
    """Test with 500 objects, one matching TableWidget."""
    objs = {HasProps(view_module=f"mod{i}.widgets") for i in range(500)}
    TableWidget.__module__ = "mod123.widgets"
    setup_model_class_reverse_map([TableWidget])
    codeflash_output = _ext_use_tables(objs) # 13.8ms -> 246μs (5492% faster)

def test_many_objects_no_tablewidget_returns_false():
    """Test with 500 objects, none matching TableWidget."""
    objs = {HasProps(view_module=f"mod{i}.widgets") for i in range(500)}
    OtherWidget.__module__ = "mod0.widgets"
    setup_model_class_reverse_map([OtherWidget])
    codeflash_output = _ext_use_tables(objs) # 13.8ms -> 243μs (5581% faster)

def test_many_models_one_tablewidget_returns_true():
    """Test with 500 models in reverse map, one is TableWidget and matches."""
    objs = {HasProps(view_module="bigmod.widgets")}
    models = []
    for i in range(499):
        cls = type(f"DummyWidget{i}", (HasProps,), {})
        cls.__module__ = "bigmod.widgets"
        models.append(cls)
    TableWidget.__module__ = "bigmod.widgets"
    models.append(TableWidget)
    setup_model_class_reverse_map(models)
    codeflash_output = _ext_use_tables(objs) # 79.1μs -> 104μs (24.3% slower)

def test_many_models_none_tablewidget_returns_false():
    """Test with 500 models in reverse map, none are TableWidget."""
    objs = {HasProps(view_module="bigmod.widgets")}
    models = []
    for i in range(500):
        cls = type(f"DummyWidget{i}", (HasProps,), {})
        cls.__module__ = "bigmod.widgets"
        models.append(cls)
    setup_model_class_reverse_map(models)
    codeflash_output = _ext_use_tables(objs) # 78.9μs -> 105μs (24.9% slower)

def test_performance_many_objects_and_models():
    """Test performance with 1000 objects and 1000 models, with one TableWidget."""
    objs = {HasProps(view_module=f"mod{i}.widgets") for i in range(1000)}
    models = []
    for i in range(999):
        cls = type(f"DummyWidget{i}", (HasProps,), {})
        cls.__module__ = f"mod{i}.widgets"
        models.append(cls)
    TableWidget.__module__ = "mod999.widgets"
    models.append(TableWidget)
    setup_model_class_reverse_map(models)
    codeflash_output = _ext_use_tables(objs) # 27.6ms -> 373μs (7291% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
#------------------------------------------------
from __future__ import annotations

from typing import Callable

# imports
import pytest
from bokeh.embed.bundle import _ext_use_tables


# Minimal stand-ins for bokeh.core.has_props.HasProps and model_class_reverse_map
class HasProps:
    # Simulate the Bokeh HasProps base class
    __view_module__ = "bokeh.models"
    # This will be set up in the test setup
    model_class_reverse_map = {}

# Simulate TableWidget base class
class TableWidget(HasProps):
    __view_module__ = "bokeh.models.widgets"

# Simulate a custom extension widget
class MyExtensionWidget(HasProps):
    __view_module__ = "myext.widgets"

# Simulate a custom extension table widget
class MyExtensionTableWidget(TableWidget):
    __view_module__ = "myext.widgets"

# Simulate another extension widget, not a TableWidget
class MyOtherExtensionWidget(HasProps):
    __view_module__ = "otherext.widgets"

# Simulate an object with __implementation__ (should be skipped)
class ExtensionWithImplementation(HasProps):
    __view_module__ = "myext.widgets"
    __implementation__ = "something"

# Simulate a bokeh widget that is a TableWidget
class BokehTableWidget(TableWidget):
    __view_module__ = "bokeh.models.widgets"

# Simulate a bokeh widget that is not a TableWidget
class BokehRegularWidget(HasProps):
    __view_module__ = "bokeh.models.widgets"
from bokeh.embed.bundle import _ext_use_tables

# -------------------------
# Unit Tests
# -------------------------

# 1. Basic Test Cases

def test_empty_set_returns_false():
    """Test that an empty set returns False."""
    codeflash_output = _ext_use_tables(set()) # 4.96μs -> 4.85μs (2.31% faster)

def test_only_bokeh_widgets_returns_false():
    """Test that only bokeh widgets (including TableWidget) returns False."""
    objs = {BokehTableWidget(), BokehRegularWidget()}
    codeflash_output = _ext_use_tables(objs) # 5.21μs -> 5.12μs (1.78% faster)

def test_extension_widget_not_tablewidget_returns_false():
    """Test that extension widgets not subclassing TableWidget return False."""
    objs = {MyExtensionWidget(), MyOtherExtensionWidget()}
    codeflash_output = _ext_use_tables(objs) # 100μs -> 100μs (0.152% slower)

def test_extension_tablewidget_returns_true():
    """Test that an extension widget subclassing TableWidget returns True."""
    objs = {MyExtensionTableWidget()}
    codeflash_output = _ext_use_tables(objs) # 46.3μs -> 78.4μs (40.9% slower)

def test_mixed_bokeh_and_extension_tablewidget_returns_true():
    """Test that a mix of bokeh and extension TableWidget returns True if extension present."""
    objs = {BokehTableWidget(), MyExtensionTableWidget()}
    codeflash_output = _ext_use_tables(objs) # 48.3μs -> 76.4μs (36.8% slower)

def test_multiple_extension_widgets_one_tablewidget_returns_true():
    """Test that multiple extension widgets, with one TableWidget subclass, returns True."""
    objs = {MyExtensionWidget(), MyOtherExtensionWidget(), MyExtensionTableWidget()}
    codeflash_output = _ext_use_tables(objs) # 74.4μs -> 76.9μs (3.25% slower)

def test_multiple_extension_widgets_none_tablewidget_returns_false():
    """Test that multiple extension widgets, none TableWidget subclass, returns False."""
    objs = {MyExtensionWidget(), MyOtherExtensionWidget()}
    codeflash_output = _ext_use_tables(objs) # 72.0μs -> 75.8μs (4.89% slower)

# 2. Edge Test Cases

def test_object_with_implementation_is_skipped():
    """Test that objects with __implementation__ are skipped."""
    objs = {ExtensionWithImplementation(), MyExtensionTableWidget()}
    # Should still return True because MyExtensionTableWidget triggers True
    codeflash_output = _ext_use_tables(objs) # 45.4μs -> 74.9μs (39.3% slower)

def test_object_with_implementation_only_returns_false():
    """Test that if all objects have __implementation__, returns False."""
    objs = {ExtensionWithImplementation()}
    codeflash_output = _ext_use_tables(objs) # 3.55μs -> 4.05μs (12.3% slower)

def test_duplicate_extension_names_only_checked_once():
    """Test that duplicate extension names are only checked once."""
    # Two objects from the same extension, only one TableWidget subclass
    class MyExtWidgetA(HasProps):
        __view_module__ = "dupeext.widgets"
    class MyExtTableWidgetA(TableWidget):
        __view_module__ = "dupeext.widgets"
    # Add to model_class_reverse_map for testing
    HasProps.model_class_reverse_map["MyExtWidgetA"] = MyExtWidgetA
    HasProps.model_class_reverse_map["MyExtTableWidgetA"] = MyExtTableWidgetA
    objs = {MyExtWidgetA(), MyExtTableWidgetA()}
    codeflash_output = _ext_use_tables(objs) # 55.7μs -> 82.5μs (32.5% slower)

def test_nonstandard_view_module_format():
    """Test that a nonstandard __view_module__ format is handled gracefully."""
    class OddModuleWidget(TableWidget):
        __view_module__ = "oddformat"
    HasProps.model_class_reverse_map["OddModuleWidget"] = OddModuleWidget
    objs = {OddModuleWidget()}
    # Should not raise, and should return True
    codeflash_output = _ext_use_tables(objs) # 49.9μs -> 77.5μs (35.7% slower)

def test_extension_tablewidget_with_similar_bokeh_name():
    """Test that an extension with name starting with 'bokeh' but not equal is not skipped."""
    class BokehXTableWidget(TableWidget):
        __view_module__ = "bokehx.widgets"
    HasProps.model_class_reverse_map["BokehXTableWidget"] = BokehXTableWidget
    objs = {BokehXTableWidget()}
    codeflash_output = _ext_use_tables(objs) # 49.8μs -> 76.8μs (35.1% slower)

def test_extension_with_no_models_in_reverse_map():
    """Test that if no models in reverse map from extension, returns False."""
    # Remove all models from 'ghostext'
    class GhostExtWidget(HasProps):
        __view_module__ = "ghostext.widgets"
    objs = {GhostExtWidget()}
    # No model in reverse map with module starting with 'ghostext'
    codeflash_output = _ext_use_tables(objs) # 48.5μs -> 75.1μs (35.4% slower)

def test_tablewidget_subclass_but_not_in_reverse_map():
    """Test that if a TableWidget subclass is not in reverse map, returns False."""
    class NotInMapTableWidget(TableWidget):
        __view_module__ = "notinmap.widgets"
    objs = {NotInMapTableWidget()}
    # Remove from reverse map if present
    HasProps.model_class_reverse_map.pop("NotInMapTableWidget", None)
    codeflash_output = _ext_use_tables(objs) # 48.6μs -> 74.8μs (35.0% slower)

# 3. Large Scale Test Cases

def test_large_number_of_non_tablewidget_extension_objects():
    """Test with many extension objects, none subclass TableWidget."""
    class ExtWidgetN(HasProps):
        __view_module__ = "extn.widgets"
    # Add to reverse map
    for i in range(500):
        name = f"ExtWidgetN{i}"
        widget = type(name, (HasProps,), {"__view_module__": "extn.widgets"})
        HasProps.model_class_reverse_map[name] = widget
    objs = {HasProps.model_class_reverse_map[f"ExtWidgetN{i}"]() for i in range(500)}
    codeflash_output = _ext_use_tables(objs) # 158μs -> 188μs (16.1% slower)

def test_large_number_of_mixed_extension_objects_with_one_tablewidget():
    """Test with many extension objects, one is a TableWidget subclass."""
    class BigTableWidget(TableWidget):
        __view_module__ = "bigext.widgets"
    HasProps.model_class_reverse_map["BigTableWidget"] = BigTableWidget
    # Add 999 non-TableWidget objects, 1 TableWidget object
    objs = set()
    for i in range(999):
        name = f"BigExtWidget{i}"
        widget = type(name, (HasProps,), {"__view_module__": "bigext.widgets"})
        HasProps.model_class_reverse_map[name] = widget
        objs.add(widget())
    objs.add(BigTableWidget())
    codeflash_output = _ext_use_tables(objs) # 268μs -> 294μs (8.84% slower)

def test_many_extensions_some_with_tablewidget():
    """Test with many extensions, some with TableWidget subclass, should return True."""
    for i in range(10):
        extname = f"ext{i}"
        # Add non-tablewidget
        widget = type(f"Widget{i}", (HasProps,), {"__view_module__": f"{extname}.widgets"})
        HasProps.model_class_reverse_map[f"Widget{i}"] = widget
        # Add tablewidget
        tablewidget = type(f"TableWidget{i}", (TableWidget,), {"__view_module__": f"{extname}.widgets"})
        HasProps.model_class_reverse_map[f"TableWidget{i}"] = tablewidget
    # Add one instance of each TableWidget subclass
    objs = set()
    for i in range(10):
        objs.add(HasProps.model_class_reverse_map[f"TableWidget{i}"]())
    codeflash_output = _ext_use_tables(objs) # 329μs -> 100μs (227% faster)

def test_many_extensions_none_with_tablewidget():
    """Test with many extensions, none with TableWidget subclass, should return False."""
    for i in range(10, 20):
        extname = f"ext{i}"
        widget = type(f"Widget{i}", (HasProps,), {"__view_module__": f"{extname}.widgets"})
        HasProps.model_class_reverse_map[f"Widget{i}"] = widget
    objs = set()
    for i in range(10, 20):
        objs.add(HasProps.model_class_reverse_map[f"Widget{i}"]())
    codeflash_output = _ext_use_tables(objs) # 294μs -> 86.9μs (239% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
#------------------------------------------------
from bokeh.embed.bundle import _ext_use_tables

def test__ext_use_tables():
    _ext_use_tables(set())
🔎 Concolic Coverage Tests and Runtime
Test File::Test Function Original ⏱️ Optimized ⏱️ Speedup
codeflash_concolic_cthbg6_3/tmph2982e0k/test_concolic_coverage.py::test__ext_use_tables 4.11μs 4.08μs 0.711%✅

To edit these changes git checkout codeflash/optimize-_ext_use_tables-mhb7a7hi and push.

Codeflash

The optimization reduces algorithmic complexity by eliminating redundant work in the nested loop structure. 

**Key changes:**
1. **Combined conditional check**: `if name == "bokeh" or name in names:` reduces duplicate name lookups
2. **Pre-grouping models by module prefix**: Instead of checking every model against every extension name (O(N×M)), models are grouped once by their module prefix, then only relevant models are checked for each extension

**Performance impact:**
The original code performed ~955,000 `model.__module__.startswith(name)` checks across all models for each extension name. The optimized version groups models upfront, reducing this to only checking models that actually belong to each extension's module prefix.

**Test case benefits:**
- Large-scale tests show dramatic improvements (5000-7000% faster) when many objects/models are involved
- Smaller test cases show modest slowdowns (20-40%) due to the overhead of pre-grouping, but this is vastly outweighed by the gains in realistic scenarios with substantial model collections
- The optimization particularly excels when `HasProps.model_class_reverse_map` contains many models, as it avoids the expensive nested iteration that dominated the original runtime profile (98.7% of execution time)
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 October 28, 2025 23:31
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Oct 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant