Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Nov 22, 2025

📄 12% (0.12x) speedup for deselect_by_keyword in src/_pytest/mark/__init__.py

⏱️ Runtime : 30.0 milliseconds 26.7 milliseconds (best of 129 runs)

📝 Explanation and details

The optimization achieves a 12% speedup by eliminating repeated attribute lookups and reducing function call overhead in hot paths. Here are the key improvements:

In KeywordMatcher.from_item (the main bottleneck):

  • Cached class references: Session = pytest.Session and Directory = pytest.Directory outside the loop eliminates repeated pytest. attribute lookups
  • Faster type checks: Replaced isinstance(node, pytest.Session) with type(node) is Session, which is faster for exact type matching
  • Reduced set operations: Split marker name gathering and extra keyword processing into separate operations to avoid redundant intermediate collections

In deselect_by_keyword:

  • Method caching: Pre-cached remaining.append and deselected.append as local variables to avoid repeated attribute lookups in the tight loop over items

Why this matters for pytest workloads:
From the function references, this code is called in pytest_collection_modifyitems, which processes every test item during collection. The performance gains scale linearly with test suite size - the larger test suites show 12-13% improvements in the annotated tests.

Best performance gains observed in:

  • Large test suites (1000+ items): 12-13% faster
  • Tests with complex parent hierarchies: Up to 22% faster
  • Cases with many markers/extra keywords: 7-13% faster

The optimizations are particularly effective because KeywordMatcher.from_item is called once per test item, making even small per-call improvements compound significantly across large test suites.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 58 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
# imports
from _pytest.mark.__init__ import deselect_by_keyword


# --- Minimal stubs for pytest internals to enable isolated testing ---


class DummyMark:
    def __init__(self, name):
        self.name = name


class DummyFunction:
    pass


class DummyItem:
    """Minimal pytest Item stub for deselect_by_keyword testing."""

    def __init__(
        self, name, parent=None, extra_keywords=None, function=None, markers=None
    ):
        self.name = name
        self.parent = parent
        self.extra_keyword_matches = set(extra_keywords) if extra_keywords else set()
        self.function = function
        self._markers = [DummyMark(m) for m in (markers or [])]
        self._listchain = None  # for custom chain override

    def listchain(self):
        # Return chain from root to self (simulate pytest's chain)
        chain = []
        node = self
        while node:
            chain.append(node)
            node = getattr(node, "parent", None)
        chain.reverse()
        return chain

    def listextrakeywords(self):
        # Aggregate extra keywords from self and parents
        keywords = set()
        for node in self.listchain():
            keywords.update(getattr(node, "extra_keyword_matches", set()))
        return keywords

    def iter_markers(self):
        return iter(self._markers)


class DummyConfigOption:
    def __init__(self, keyword):
        self.keyword = keyword


class DummyConfig:
    def __init__(self, keyword):
        self.option = DummyConfigOption(keyword)
        self.hook = DummyHook()


class DummyHook:
    def __init__(self):
        self.deselected_items = []

    def pytest_deselected(self, items):
        self.deselected_items.extend(items)


# --- Unit tests ---

# --- Basic Test Cases ---


def test_no_keyword_keeps_all_items():
    """No keyword: all items remain."""
    items = [DummyItem("test_one"), DummyItem("test_two")]
    config = DummyConfig(keyword="")
    deselect_by_keyword(items, config)  # 633ns -> 766ns (17.4% slower)


def test_simple_keyword_match():
    """Simple keyword matches one item."""
    items = [DummyItem("test_foo"), DummyItem("test_bar")]
    config = DummyConfig(keyword="foo")
    deselect_by_keyword(items, config)  # 48.2μs -> 46.6μs (3.48% faster)


def test_simple_keyword_case_insensitive():
    """Keyword matching is case-insensitive."""
    items = [DummyItem("Test_Foo"), DummyItem("test_bar")]
    config = DummyConfig(keyword="FOO")
    deselect_by_keyword(items, config)  # 42.9μs -> 40.3μs (6.51% faster)


def test_keyword_substring_matching():
    """Keyword matches substrings."""
    items = [DummyItem("test_foobar"), DummyItem("test_barfoo"), DummyItem("baz")]
    config = DummyConfig(keyword="foo")
    deselect_by_keyword(items, config)  # 43.0μs -> 41.7μs (3.08% faster)


def test_and_or_not_keywords():
    """Test boolean logic in keyword expression."""
    items = [DummyItem("test_foo"), DummyItem("test_bar"), DummyItem("test_baz")]
    config = DummyConfig(keyword="foo or bar")
    deselect_by_keyword(items, config)  # 61.9μs -> 58.2μs (6.50% faster)

    items = [DummyItem("test_foo"), DummyItem("test_bar"), DummyItem("test_baz")]
    config = DummyConfig(keyword="foo and bar")
    deselect_by_keyword(items, config)  # 37.7μs -> 35.4μs (6.51% faster)

    items = [DummyItem("test_foo"), DummyItem("test_bar"), DummyItem("test_baz")]
    config = DummyConfig(keyword="not foo")
    deselect_by_keyword(items, config)  # 30.9μs -> 30.2μs (2.39% faster)


def test_extra_keywords_matching():
    """Extra keywords from item and parent are matched."""
    parent = DummyItem("parent", extra_keywords=["parent_kw"])
    items = [
        DummyItem("child1", parent=parent, extra_keywords=["child_kw"]),
        DummyItem("child2", parent=parent),
    ]
    config = DummyConfig(keyword="parent_kw")
    deselect_by_keyword(items, config)  # 39.6μs -> 37.6μs (5.09% faster)

    config = DummyConfig(keyword="child_kw")
    items = [
        DummyItem("child1", parent=parent, extra_keywords=["child_kw"]),
        DummyItem("child2", parent=parent),
    ]
    deselect_by_keyword(items, config)  # 24.8μs -> 24.6μs (0.714% faster)


def test_marker_matching():
    """Test marker names are matched."""
    items = [
        DummyItem("test_one", markers=["slow"]),
        DummyItem("test_two", markers=["fast"]),
        DummyItem("test_three", markers=[]),
    ]
    config = DummyConfig(keyword="slow")
    deselect_by_keyword(items, config)  # 40.9μs -> 38.0μs (7.58% faster)


def test_function_dict_matching():
    """Test function __dict__ keys are matched."""
    func = DummyFunction()
    func.custom_key = True
    items = [DummyItem("test_func", function=func), DummyItem("test_other")]
    config = DummyConfig(keyword="custom_key")
    deselect_by_keyword(items, config)  # 39.7μs -> 36.6μs (8.60% faster)


# --- Edge Test Cases ---


def test_empty_items_list():
    """Empty items list: nothing happens."""
    items = []
    config = DummyConfig(keyword="foo")
    deselect_by_keyword(items, config)  # 25.7μs -> 25.1μs (2.60% faster)


def test_keyword_not_found():
    """Keyword not found: all items deselected."""
    items = [DummyItem("test_one"), DummyItem("test_two")]
    config = DummyConfig(keyword="notfound")
    deselect_by_keyword(items, config)  # 40.6μs -> 37.4μs (8.76% faster)


def test_multiple_keywords_no_match():
    """Multiple keywords with 'and' that do not match any item."""
    items = [DummyItem("foo"), DummyItem("bar")]
    config = DummyConfig(keyword="foo and bar")
    deselect_by_keyword(items, config)  # 57.4μs -> 55.9μs (2.73% faster)


def test_multiple_keywords_some_match():
    """Multiple keywords with 'or' that match some items."""
    items = [DummyItem("foo"), DummyItem("bar"), DummyItem("baz")]
    config = DummyConfig(keyword="foo or baz")
    deselect_by_keyword(items, config)  # 59.4μs -> 57.6μs (3.13% faster)


def test_keyword_with_spaces():
    """Keyword with leading/trailing spaces."""
    items = [DummyItem("foo"), DummyItem("bar")]
    config = DummyConfig(keyword="  foo  ")
    deselect_by_keyword(items, config)  # 39.4μs -> 38.2μs (3.31% faster)


def test_keyword_empty_string():
    """Keyword is an empty string: all items remain."""
    items = [DummyItem("foo"), DummyItem("bar")]
    config = DummyConfig(keyword="")
    deselect_by_keyword(items, config)  # 560ns -> 618ns (9.39% slower)


def test_keyword_all_match():
    """Keyword matches all items."""
    items = [DummyItem("foo"), DummyItem("foobar"), DummyItem("barfoo")]
    config = DummyConfig(keyword="foo")
    deselect_by_keyword(items, config)  # 44.2μs -> 43.1μs (2.58% faster)


def test_keyword_none_match():
    """Keyword matches none of the items."""
    items = [DummyItem("foo"), DummyItem("bar")]
    config = DummyConfig(keyword="baz")
    deselect_by_keyword(items, config)  # 41.0μs -> 38.4μs (6.92% faster)


def test_nested_parent_chain_keywords():
    """Keywords in parents propagate to children."""
    grandparent = DummyItem("grandparent", extra_keywords=["gpkw"])
    parent = DummyItem("parent", parent=grandparent, extra_keywords=["pkw"])
    child = DummyItem("child", parent=parent)
    items = [child]
    config = DummyConfig(keyword="gpkw")
    deselect_by_keyword(items, config)  # 38.5μs -> 36.8μs (4.56% faster)
    config = DummyConfig(keyword="pkw")
    items = [DummyItem("child", parent=parent)]
    deselect_by_keyword(items, config)  # 23.0μs -> 22.0μs (4.67% faster)


def test_marker_and_extra_keyword_disjoint():
    """Marker and extra keyword are disjoint; test correct matching."""
    item = DummyItem("foo", extra_keywords=["extra"], markers=["marker"])
    items = [item]
    config = DummyConfig(keyword="marker")
    deselect_by_keyword(items, config)  # 33.9μs -> 33.6μs (0.835% faster)
    config = DummyConfig(keyword="extra")
    items = [DummyItem("foo", extra_keywords=["extra"], markers=["marker"])]
    deselect_by_keyword(items, config)  # 21.2μs -> 20.9μs (1.61% faster)


# --- Large Scale Test Cases ---


def test_large_number_of_items_single_keyword():
    """Test performance/scalability with many items."""
    items = [DummyItem(f"test_{i}") for i in range(1000)]
    config = DummyConfig(keyword="test_999")
    deselect_by_keyword(items, config)  # 2.28ms -> 2.01ms (13.4% faster)


def test_large_number_of_items_all_match():
    """All items match the keyword."""
    items = [DummyItem(f"item_{i}") for i in range(1000)]
    config = DummyConfig(keyword="item")
    deselect_by_keyword(items, config)  # 2.34ms -> 2.08ms (12.4% faster)


def test_large_number_of_items_none_match():
    """No items match the keyword."""
    items = [DummyItem(f"item_{i}") for i in range(1000)]
    config = DummyConfig(keyword="notfound")
    deselect_by_keyword(items, config)  # 2.28ms -> 2.03ms (12.6% faster)


def test_large_number_of_items_some_match():
    """Some items match, some do not."""
    items = [
        DummyItem(f"foo_{i}") if i % 2 == 0 else DummyItem(f"bar_{i}")
        for i in range(1000)
    ]
    config = DummyConfig(keyword="foo")
    deselect_by_keyword(items, config)  # 2.31ms -> 2.07ms (11.6% faster)


def test_large_parent_chain_inheritance():
    """Large parent chain: ensure extra keywords propagate."""
    parent = DummyItem("parent", extra_keywords=["pkw"])
    for i in range(10):
        parent = DummyItem(f"parent_{i}", parent=parent, extra_keywords=[f"kw_{i}"])
    child = DummyItem("child", parent=parent)
    items = [child]
    config = DummyConfig(keyword="kw_9")
    deselect_by_keyword(items, config)  # 53.5μs -> 47.7μs (12.2% faster)
    config = DummyConfig(keyword="pkw")
    items = [DummyItem("child", parent=parent)]
    deselect_by_keyword(items, config)  # 29.5μs -> 27.3μs (8.09% faster)


# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
from _pytest.mark.__init__ import deselect_by_keyword
import pytest


# Minimal stubs to simulate pytest internals for testing
class DummyMark:
    def __init__(self, name):
        self.name = name


class DummyFunction:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)


class DummyItem:
    def __init__(
        self, name, parent=None, extra_keywords=None, function_attrs=None, markers=None
    ):
        self.name = name
        self.parent = parent
        self.extra_keyword_matches = set(extra_keywords or [])
        self.function = (
            DummyFunction(**(function_attrs or {})) if function_attrs else None
        )
        self.own_markers = [DummyMark(m) for m in (markers or [])]
        self._listchain = None  # will be set later

    def listchain(self):
        # Returns the chain from root to self
        chain = []
        node = self
        while node is not None:
            chain.append(node)
            node = getattr(node, "parent", None)
        chain.reverse()
        return chain

    def listextrakeywords(self):
        # Returns all extra keywords from self and parents
        keywords = set()
        for node in self.listchain():
            keywords.update(getattr(node, "extra_keyword_matches", set()))
        return keywords

    def iter_markers(self):
        # Returns all markers attached to this node
        return iter(self.own_markers)


class DummyConfigOption:
    def __init__(self, keyword):
        self.keyword = keyword


class DummyConfig:
    def __init__(self, keyword):
        self.option = DummyConfigOption(keyword)
        self.hook = DummyHook()


class DummyHook:
    def __init__(self):
        self.deselected = []

    def pytest_deselected(self, items):
        self.deselected.extend(items)


# ------------------- UNIT TESTS -------------------

# Basic Test Cases


def test_basic_single_match():
    # Only one item, keyword matches its name
    item = DummyItem("test_foo")
    items = [item]
    config = DummyConfig("foo")
    deselect_by_keyword(items, config)  # 35.9μs -> 34.0μs (5.44% faster)


def test_basic_single_no_match():
    # Only one item, keyword does not match
    item = DummyItem("test_bar")
    items = [item]
    config = DummyConfig("foo")
    deselect_by_keyword(items, config)  # 36.0μs -> 32.7μs (9.90% faster)


def test_basic_multiple_items_some_match():
    # Multiple items, some match keyword
    item1 = DummyItem("test_foo")
    item2 = DummyItem("test_bar")
    item3 = DummyItem("test_baz")
    items = [item1, item2, item3]
    config = DummyConfig("bar")
    deselect_by_keyword(items, config)  # 44.0μs -> 41.1μs (6.97% faster)


def test_basic_multiple_items_all_match():
    # All items match keyword
    item1 = DummyItem("foo_test")
    item2 = DummyItem("barfoo")
    items = [item1, item2]
    config = DummyConfig("foo")
    deselect_by_keyword(items, config)  # 39.3μs -> 36.9μs (6.42% faster)


def test_basic_multiple_items_none_match():
    # No items match keyword
    item1 = DummyItem("alpha")
    item2 = DummyItem("beta")
    items = [item1, item2]
    config = DummyConfig("gamma")
    deselect_by_keyword(items, config)  # 40.0μs -> 37.7μs (6.33% faster)


def test_basic_keyword_case_insensitive():
    # Keyword matching should be case-insensitive
    item = DummyItem("TestFoo")
    items = [item]
    config = DummyConfig("foo")
    deselect_by_keyword(items, config)  # 35.6μs -> 33.4μs (6.86% faster)


# Edge Test Cases


def test_edge_empty_items():
    # No items to deselect
    items = []
    config = DummyConfig("foo")
    deselect_by_keyword(items, config)  # 26.3μs -> 25.9μs (1.68% faster)


def test_edge_empty_keyword():
    # Empty keyword means no deselection
    item1 = DummyItem("foo")
    item2 = DummyItem("bar")
    items = [item1, item2]
    config = DummyConfig("")
    deselect_by_keyword(items, config)  # 590ns -> 639ns (7.67% slower)


def test_edge_whitespace_keyword():
    # Whitespace keyword should be stripped and treated as empty
    item1 = DummyItem("foo")
    items = [item1]
    config = DummyConfig("   ")
    deselect_by_keyword(items, config)  # 686ns -> 707ns (2.97% slower)


def test_edge_keyword_in_parent_name():
    # Keyword matches parent's name
    parent = DummyItem("parent_foo")
    item = DummyItem("child", parent=parent)
    items = [item]
    config = DummyConfig("foo")
    deselect_by_keyword(items, config)  # 42.5μs -> 40.9μs (3.94% faster)


def test_edge_keyword_in_extra_keywords():
    # Keyword matches extra_keyword_matches
    item = DummyItem("test", extra_keywords=["special"])
    items = [item]
    config = DummyConfig("special")
    deselect_by_keyword(items, config)  # 38.1μs -> 37.0μs (2.98% faster)


def test_edge_keyword_in_function_attributes():
    # Keyword matches attribute attached to function
    item = DummyItem("test", function_attrs={"custom_tag": "mytag"})
    items = [item]
    config = DummyConfig("mytag")
    deselect_by_keyword(items, config)  # 37.5μs -> 36.1μs (3.90% faster)


def test_edge_keyword_in_marker_name():
    # Keyword matches marker name
    item = DummyItem("test", markers=["slow"])
    items = [item]
    config = DummyConfig("slow")
    deselect_by_keyword(items, config)  # 37.2μs -> 35.4μs (5.03% faster)


def test_edge_multiple_keywords_and():
    # Keyword expression: 'foo and bar'
    item1 = DummyItem("foo_bar")
    item2 = DummyItem("foo")
    item3 = DummyItem("bar")
    items = [item1, item2, item3]
    config = DummyConfig("foo and bar")
    deselect_by_keyword(items, config)  # 61.6μs -> 59.5μs (3.48% faster)


def test_edge_multiple_keywords_or():
    # Keyword expression: 'foo or bar'
    item1 = DummyItem("foo_test")
    item2 = DummyItem("bar_test")
    item3 = DummyItem("baz_test")
    items = [item1, item2, item3]
    config = DummyConfig("foo or bar")
    deselect_by_keyword(items, config)  # 60.1μs -> 57.4μs (4.66% faster)


def test_edge_not_keyword():
    # Keyword expression: 'not foo'
    item1 = DummyItem("foo_test")
    item2 = DummyItem("bar_test")
    items = [item1, item2]
    config = DummyConfig("not foo")
    deselect_by_keyword(items, config)  # 47.9μs -> 45.7μs (4.93% faster)


def test_edge_parent_and_extra_keywords():
    # Keyword matches in parent and extra_keyword_matches
    parent = DummyItem("parent")
    item = DummyItem("child", parent=parent, extra_keywords=["special"])
    items = [item]
    config = DummyConfig("parent and special")
    deselect_by_keyword(items, config)  # 52.5μs -> 50.6μs (3.83% faster)


def test_edge_parent_and_marker():
    # Keyword matches in parent and marker
    parent = DummyItem("parent")
    item = DummyItem("child", parent=parent, markers=["slow"])
    items = [item]
    config = DummyConfig("parent and slow")
    deselect_by_keyword(items, config)  # 51.8μs -> 49.9μs (3.64% faster)


def test_edge_invalid_expression():
    # Invalid keyword expression should raise
    item = DummyItem("foo")
    items = [item]
    config = DummyConfig("foo and or")
    with pytest.raises(Exception):
        deselect_by_keyword(items, config)  # 23.7μs -> 23.1μs (2.39% faster)


def test_edge_keyword_substring():
    # Keyword matches as substring
    item = DummyItem("foobar")
    items = [item]
    config = DummyConfig("oba")
    deselect_by_keyword(items, config)  # 39.9μs -> 37.2μs (7.28% faster)


def test_edge_keyword_multiple_sources():
    # Keyword matches in name, extra, function, marker
    parent = DummyItem("parent")
    item = DummyItem(
        "child",
        parent=parent,
        extra_keywords=["extra"],
        function_attrs={"tag": "functiontag"},
        markers=["marker"],
    )
    items = [item]
    config = DummyConfig("parent and extra and functiontag and marker")
    deselect_by_keyword(items, config)  # 78.9μs -> 75.8μs (4.13% faster)


# Large Scale Test Cases


def test_large_scale_all_match():
    # 1000 items, all match keyword
    items = [DummyItem(f"item_{i}_foo") for i in range(1000)]
    config = DummyConfig("foo")
    deselect_by_keyword(items, config)  # 2.36ms -> 2.10ms (12.7% faster)


def test_large_scale_none_match():
    # 1000 items, none match keyword
    items = [DummyItem(f"item_{i}_bar") for i in range(1000)]
    config = DummyConfig("foo")
    deselect_by_keyword(items, config)  # 2.27ms -> 2.01ms (13.2% faster)


def test_large_scale_half_match():
    # 1000 items, half match keyword
    items = [
        DummyItem(f"item_{i}_foo" if i % 2 == 0 else f"item_{i}_bar")
        for i in range(1000)
    ]
    config = DummyConfig("foo")
    deselect_by_keyword(items, config)  # 2.36ms -> 2.08ms (13.2% faster)
    for item in items:
        pass
    for item in config.hook.deselected:
        pass


def test_large_scale_complex_expression():
    # 1000 items, complex keyword expression
    items = []
    for i in range(1000):
        # Every 3rd item has 'foo', every 5th has 'bar'
        name = ""
        if i % 3 == 0:
            name += "foo"
        if i % 5 == 0:
            name += "bar"
        if not name:
            name = f"item_{i}"
        items.append(DummyItem(name))
    config = DummyConfig("foo or bar")
    deselect_by_keyword(items, config)  # 2.66ms -> 2.36ms (12.6% faster)
    # All items divisible by 3 or 5 should remain
    expected = [item for item in items if ("foo" in item.name or "bar" in item.name)]


def test_large_scale_extra_keywords():
    # 1000 items, some have extra keywords
    items = []
    for i in range(1000):
        extra = ["special"] if i % 10 == 0 else []
        items.append(DummyItem(f"item_{i}", extra_keywords=extra))
    config = DummyConfig("special")
    deselect_by_keyword(items, config)  # 2.33ms -> 2.05ms (13.4% faster)
    for item in items:
        pass


def test_large_scale_marker_keywords():
    # 1000 items, some have marker 'slow'
    items = []
    for i in range(1000):
        markers = ["slow"] if i % 15 == 0 else []
        items.append(DummyItem(f"item_{i}", markers=markers))
    config = DummyConfig("slow")
    deselect_by_keyword(items, config)  # 2.23ms -> 2.04ms (9.35% faster)
    for item in items:
        pass


def test_large_scale_parent_chain_keyword():
    # 1000 items, half have parent with keyword
    parent = DummyItem("parent_foo")
    items = []
    for i in range(1000):
        p = parent if i % 2 == 0 else None
        items.append(DummyItem(f"item_{i}", parent=p))
    config = DummyConfig("foo")
    deselect_by_keyword(items, config)  # 2.65ms -> 2.17ms (22.1% faster)
    for item in items:
        pass


def test_large_scale_function_attribute_keyword():
    # 1000 items, some have function attribute 'special'
    items = []
    for i in range(1000):
        attrs = {"special": "yes"} if i % 20 == 0 else {}
        items.append(DummyItem(f"item_{i}", function_attrs=attrs))
    config = DummyConfig("special")
    deselect_by_keyword(items, config)  # 2.21ms -> 2.06ms (7.16% faster)
    for item in items:
        pass


# 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-deselect_by_keyword-mi9wz167 and push.

Codeflash Static Badge

The optimization achieves a **12% speedup** by eliminating repeated attribute lookups and reducing function call overhead in hot paths. Here are the key improvements:

**In `KeywordMatcher.from_item` (the main bottleneck):**
- **Cached class references**: `Session = pytest.Session` and `Directory = pytest.Directory` outside the loop eliminates repeated `pytest.` attribute lookups
- **Faster type checks**: Replaced `isinstance(node, pytest.Session)` with `type(node) is Session`, which is faster for exact type matching
- **Reduced set operations**: Split marker name gathering and extra keyword processing into separate operations to avoid redundant intermediate collections

**In `deselect_by_keyword`:**
- **Method caching**: Pre-cached `remaining.append` and `deselected.append` as local variables to avoid repeated attribute lookups in the tight loop over items

**Why this matters for pytest workloads:**
From the function references, this code is called in `pytest_collection_modifyitems`, which processes every test item during collection. The performance gains scale linearly with test suite size - the larger test suites show 12-13% improvements in the annotated tests.

**Best performance gains observed in:**
- Large test suites (1000+ items): 12-13% faster
- Tests with complex parent hierarchies: Up to 22% faster 
- Cases with many markers/extra keywords: 7-13% faster

The optimizations are particularly effective because `KeywordMatcher.from_item` is called once per test item, making even small per-call improvements compound significantly across large test suites.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 November 22, 2025 06:34
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Nov 22, 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