Skip to content

Conversation

@codeflash-ai
Copy link

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

📄 9% (0.09x) speedup for Bundle.from_bokeh in panel/io/resources.py

⏱️ Runtime : 129 microseconds 119 microseconds (best of 282 runs)

📝 Explanation and details

The optimized code replaces inefficient kwargs.pop() operations with direct dictionary key checks and deletions in the __init__ method.

Key optimization: Instead of using kwargs.pop("key", default) which performs a dictionary lookup, retrieval, and deletion even when the key doesn't exist, the optimized version uses "key" in kwargs checks followed by direct access and deletion only when needed.

Why this is faster: The original pop() method has overhead from:

  1. Dictionary key lookup
  2. Default value handling logic
  3. Key deletion attempt even for non-existent keys

The optimized approach eliminates unnecessary operations when keys are missing (which appears common based on test results), and uses more efficient direct dictionary operations when keys are present.

Performance characteristics: The optimization shows consistent 8-18% speedup across most test cases, with particularly good gains on:

  • Empty/minimal bundles (18.8% faster) where keys are frequently missing
  • Basic scenarios with partial fields (10-15% faster)
  • Large-scale tests still benefit (4-9% faster) despite the optimization being relatively small compared to data processing overhead

The from_bokeh method remains unchanged, so the gains come purely from more efficient kwargs processing during Bundle initialization.

Correctness verification report:

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

# imports
import pytest
from panel.io.resources import Bundle


# --- Helper class to simulate bokeh.embed.bundle.Bundle for testing ---
class DummyBkBundle:
    def __init__(
        self,
        js_files=None,
        js_raw=None,
        css_files=None,
        css_raw=None,
        hashes=None
    ):
        self.js_files = js_files if js_files is not None else []
        self.js_raw = js_raw if js_raw is not None else []
        self.css_files = css_files if css_files is not None else []
        self.css_raw = css_raw if css_raw is not None else []
        self.hashes = hashes if hashes is not None else {}

# --- Basic Test Cases ---
def test_basic_all_fields_populated():
    # Test with all fields populated with simple values
    bk_bundle = DummyBkBundle(
        js_files=["file1.js", "file2.js"],
        js_raw=["console.log('hello');"],
        css_files=["style1.css"],
        css_raw=["body {color: red;}"],
        hashes={"file1.js": "abc123", "style1.css": "def456"}
    )
    codeflash_output = Bundle.from_bokeh(bk_bundle, notebook=True); result = codeflash_output # 4.51μs -> 4.16μs (8.34% faster)

def test_basic_empty_fields():
    # Test with all fields empty
    bk_bundle = DummyBkBundle()
    codeflash_output = Bundle.from_bokeh(bk_bundle); result = codeflash_output # 4.22μs -> 3.55μs (18.8% faster)

def test_basic_partial_fields():
    # Test with only some fields populated
    bk_bundle = DummyBkBundle(
        js_files=["main.js"],
        css_files=["main.css"]
    )
    codeflash_output = Bundle.from_bokeh(bk_bundle); result = codeflash_output # 4.06μs -> 3.68μs (10.4% faster)

# --- Edge Test Cases ---
def test_edge_none_fields():
    # Test with all fields set to None explicitly
    bk_bundle = DummyBkBundle(
        js_files=None,
        js_raw=None,
        css_files=None,
        css_raw=None,
        hashes=None
    )
    codeflash_output = Bundle.from_bokeh(bk_bundle); result = codeflash_output # 4.01μs -> 3.48μs (15.3% faster)

def test_edge_unusual_types():
    # Test with fields containing unusual types (should pass through as-is)
    bk_bundle = DummyBkBundle(
        js_files=[None, 123, "js.js"],
        js_raw=[b"bytes", True],
        css_files=[False, "css.css"],
        css_raw=[None],
        hashes={"weird": None, 123: "456"}
    )
    codeflash_output = Bundle.from_bokeh(bk_bundle); result = codeflash_output # 4.01μs -> 3.56μs (12.5% faster)

def test_edge_missing_attribute():
    # Test with missing attributes on bk_bundle (should raise AttributeError)
    class IncompleteBkBundle:
        pass
    with pytest.raises(AttributeError):
        Bundle.from_bokeh(IncompleteBkBundle()) # 1.36μs -> 1.44μs (5.70% slower)

def test_edge_extra_kwargs():
    # Test that extra kwargs passed to Bundle.__init__ do not interfere with from_bokeh
    # (from_bokeh should only pass expected arguments)
    bk_bundle = DummyBkBundle(
        js_files=["a.js"],
        js_raw=["a"],
        css_files=["b.css"],
        css_raw=["b"],
        hashes={"a.js": "h"}
    )
    # Simulate extra kwargs in Bundle.__init__ via subclass
    class CustomBundle(Bundle):
        def __init__(self, notebook=False, **kwargs):
            self.custom_value = kwargs.pop("custom_value", "default")
            super().__init__(notebook=notebook, **kwargs)
    codeflash_output = CustomBundle.from_bokeh(bk_bundle, notebook=True); result = codeflash_output # 7.49μs -> 7.24μs (3.45% faster)

def test_edge_notebook_flag_false():
    # Test with notebook flag explicitly set to False
    bk_bundle = DummyBkBundle(js_files=["f.js"])
    codeflash_output = Bundle.from_bokeh(bk_bundle, notebook=False); result = codeflash_output # 4.42μs -> 3.79μs (16.5% faster)

def test_edge_notebook_flag_true():
    # Test with notebook flag explicitly set to True
    bk_bundle = DummyBkBundle(js_files=["f.js"])
    codeflash_output = Bundle.from_bokeh(bk_bundle, notebook=True); result = codeflash_output # 4.19μs -> 3.65μs (15.0% faster)

# --- Large Scale Test Cases ---
def test_large_scale_max_elements():
    # Test with large lists (but <1000 elements)
    N = 999
    js_files = [f"file_{i}.js" for i in range(N)]
    js_raw = [f"console.log({i});" for i in range(N)]
    css_files = [f"style_{i}.css" for i in range(N)]
    css_raw = [f"body {{color: #{i:03x};}}" for i in range(N)]
    hashes = {f"file_{i}.js": f"hash_{i}" for i in range(N)}
    bk_bundle = DummyBkBundle(
        js_files=js_files,
        js_raw=js_raw,
        css_files=css_files,
        css_raw=css_raw,
        hashes=hashes
    )
    codeflash_output = Bundle.from_bokeh(bk_bundle); result = codeflash_output # 13.3μs -> 12.8μs (3.89% faster)

def test_large_scale_empty_strings():
    # Test with large lists of empty strings
    N = 500
    bk_bundle = DummyBkBundle(
        js_files=[""] * N,
        js_raw=[""] * N,
        css_files=[""] * N,
        css_raw=[""] * N,
        hashes={str(i): "" for i in range(N)}
    )
    codeflash_output = Bundle.from_bokeh(bk_bundle); result = codeflash_output # 7.50μs -> 6.87μs (9.17% faster)

def test_large_scale_mixed_types():
    # Test with large lists of mixed types
    N = 300
    js_files = [i if i % 2 == 0 else f"file_{i}.js" for i in range(N)]
    js_raw = [None if i % 3 == 0 else f"raw_{i}" for i in range(N)]
    css_files = [f"css_{i}.css" if i % 5 else False for i in range(N)]
    css_raw = [True if i % 7 == 0 else f"cssraw_{i}" for i in range(N)]
    hashes = {i: f"h_{i}" for i in range(N)}
    bk_bundle = DummyBkBundle(
        js_files=js_files,
        js_raw=js_raw,
        css_files=css_files,
        css_raw=css_raw,
        hashes=hashes
    )
    codeflash_output = Bundle.from_bokeh(bk_bundle); result = codeflash_output # 6.43μs -> 5.89μs (9.20% faster)

# --- Mutation sensitivity: ensure all fields are copied correctly ---
def test_mutation_sensitivity_fields():
    # If from_bokeh omits any field, this test will fail
    bk_bundle = DummyBkBundle(
        js_files=["a.js"],
        js_raw=["raw"],
        css_files=["b.css"],
        css_raw=["cssraw"],
        hashes={"a.js": "h"}
    )
    codeflash_output = Bundle.from_bokeh(bk_bundle); result = codeflash_output # 4.13μs -> 3.62μs (14.0% faster)
    # Changing any field in result should not affect bk_bundle (deep copy semantics not enforced, but we check for reference equality)
    result.js_files.append("extra.js")

# --- Determinism test ---
def test_determinism():
    # The same input should always produce the same output
    bk_bundle = DummyBkBundle(
        js_files=["a.js", "b.js"],
        js_raw=["raw1", "raw2"],
        css_files=["c.css", "d.css"],
        css_raw=["cssraw1", "cssraw2"],
        hashes={"a.js": "h1", "b.js": "h2"}
    )
    codeflash_output = Bundle.from_bokeh(bk_bundle); result1 = codeflash_output # 4.10μs -> 3.61μs (13.6% faster)
    codeflash_output = Bundle.from_bokeh(bk_bundle); result2 = codeflash_output # 1.82μs -> 1.75μs (4.13% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
#------------------------------------------------
import pytest  # used for our unit tests
from panel.io.resources import Bundle


# Minimal stubs for bokeh.embed.bundle.Bundle to allow testing
class BkBundle:
    def __init__(self, js_files=None, js_raw=None, css_files=None, css_raw=None, hashes=None):
        self.js_files = js_files if js_files is not None else []
        self.js_raw = js_raw if js_raw is not None else []
        self.css_files = css_files if css_files is not None else []
        self.css_raw = css_raw if css_raw is not None else []
        self.hashes = hashes if hashes is not None else {}
from panel.io.resources import Bundle

# unit tests

# --- Basic Test Cases ---

def test_basic_copy_all_fields():
    # Test that all fields are copied correctly from a typical BkBundle
    bk = BkBundle(
        js_files=['a.js', 'b.js'],
        js_raw=['alert("hi");'],
        css_files=['a.css'],
        css_raw=['body { color: red; }'],
        hashes={'a.js': 'abc123'}
    )
    codeflash_output = Bundle.from_bokeh(bk); bundle = codeflash_output # 3.68μs -> 3.43μs (7.26% faster)

def test_basic_notebook_flag_true():
    # Test that the notebook flag is set correctly
    bk = BkBundle()
    codeflash_output = Bundle.from_bokeh(bk, notebook=True); bundle = codeflash_output # 4.07μs -> 3.60μs (13.2% faster)

def test_basic_empty_bundle():
    # Test with all fields empty
    bk = BkBundle()
    codeflash_output = Bundle.from_bokeh(bk); bundle = codeflash_output # 3.83μs -> 3.47μs (10.6% faster)

# --- Edge Test Cases ---

def test_edge_none_fields():
    # Test with all fields set explicitly to None
    bk = BkBundle(
        js_files=None,
        js_raw=None,
        css_files=None,
        css_raw=None,
        hashes=None
    )
    codeflash_output = Bundle.from_bokeh(bk); bundle = codeflash_output # 3.75μs -> 3.52μs (6.44% faster)

def test_edge_empty_strings():
    # Test with fields containing empty strings
    bk = BkBundle(
        js_files=[''],
        js_raw=[''],
        css_files=[''],
        css_raw=[''],
        hashes={'': ''}
    )
    codeflash_output = Bundle.from_bokeh(bk); bundle = codeflash_output # 3.85μs -> 3.62μs (6.52% faster)

def test_edge_unusual_types_in_fields():
    # Test with fields containing unusual types (e.g. numbers, dicts)
    bk = BkBundle(
        js_files=[123, None, {'foo': 'bar'}],
        js_raw=[True, False],
        css_files=[[], ()],
        css_raw=[set(), frozenset()],
        hashes={42: [1,2,3]}
    )
    codeflash_output = Bundle.from_bokeh(bk); bundle = codeflash_output # 3.83μs -> 3.55μs (7.94% faster)

def test_edge_mutation_does_not_affect_original():
    # Test that mutating the returned Bundle does not affect the original BkBundle
    bk = BkBundle(js_files=['a.js'])
    codeflash_output = Bundle.from_bokeh(bk); bundle = codeflash_output # 3.92μs -> 3.49μs (12.4% faster)
    bundle.js_files.append('b.js')

def test_edge_missing_attributes():
    # Test with a bk_bundle missing some expected attributes
    class IncompleteBkBundle:
        def __init__(self):
            self.js_files = ['a.js']
            # css_files is missing
            self.js_raw = []
            self.css_raw = []
            self.hashes = {}
    bk = IncompleteBkBundle()
    # Should raise AttributeError because css_files is missing
    with pytest.raises(AttributeError):
        Bundle.from_bokeh(bk) # 1.50μs -> 1.48μs (1.15% faster)

# --- Large Scale Test Cases ---

def test_large_scale_many_files():
    # Test with a large number of files
    n = 1000
    js_files = [f'file_{i}.js' for i in range(n)]
    css_files = [f'file_{i}.css' for i in range(n)]
    js_raw = [f'console.log({i});' for i in range(n)]
    css_raw = [f'body {{ color: #{i:03x}; }}' for i in range(n)]
    hashes = {f'file_{i}.js': f'hash_{i}' for i in range(n)}
    bk = BkBundle(
        js_files=js_files,
        js_raw=js_raw,
        css_files=css_files,
        css_raw=css_raw,
        hashes=hashes
    )
    codeflash_output = Bundle.from_bokeh(bk); bundle = codeflash_output # 13.7μs -> 13.1μs (4.89% faster)

def test_large_scale_large_hash_dict():
    # Test with a large hashes dictionary only
    n = 1000
    hashes = {f'file_{i}.js': f'hash_{i}' for i in range(n)}
    bk = BkBundle(hashes=hashes)
    codeflash_output = Bundle.from_bokeh(bk); bundle = codeflash_output # 7.42μs -> 6.88μs (7.79% faster)

def test_large_scale_large_raw_strings():
    # Test with very large raw strings
    big_js = 'console.log("x");' * 1000
    big_css = 'body { color: red; }' * 1000
    bk = BkBundle(js_raw=[big_js], css_raw=[big_css])
    codeflash_output = Bundle.from_bokeh(bk); bundle = codeflash_output # 4.26μs -> 3.85μs (10.5% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-Bundle.from_bokeh-mh9xo1yw and push.

Codeflash

The optimized code replaces inefficient `kwargs.pop()` operations with direct dictionary key checks and deletions in the `__init__` method. 

**Key optimization:** Instead of using `kwargs.pop("key", default)` which performs a dictionary lookup, retrieval, and deletion even when the key doesn't exist, the optimized version uses `"key" in kwargs` checks followed by direct access and deletion only when needed.

**Why this is faster:** The original `pop()` method has overhead from:
1. Dictionary key lookup 
2. Default value handling logic
3. Key deletion attempt even for non-existent keys

The optimized approach eliminates unnecessary operations when keys are missing (which appears common based on test results), and uses more efficient direct dictionary operations when keys are present.

**Performance characteristics:** The optimization shows consistent 8-18% speedup across most test cases, with particularly good gains on:
- Empty/minimal bundles (18.8% faster) where keys are frequently missing
- Basic scenarios with partial fields (10-15% faster)
- Large-scale tests still benefit (4-9% faster) despite the optimization being relatively small compared to data processing overhead

The `from_bokeh` method remains unchanged, so the gains come purely from more efficient kwargs processing during Bundle initialization.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 October 28, 2025 02:14
@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