Skip to content

⚡️ Speed up method Date.transform by 42%#148

Open
codeflash-ai[bot] wants to merge 1 commit into
branch-3.9from
codeflash/optimize-Date.transform-mhwpsmbs
Open

⚡️ Speed up method Date.transform by 42%#148
codeflash-ai[bot] wants to merge 1 commit into
branch-3.9from
codeflash/optimize-Date.transform-mhwpsmbs

Conversation

@codeflash-ai
Copy link
Copy Markdown

@codeflash-ai codeflash-ai Bot commented Nov 13, 2025

📄 42% (0.42x) speedup for Date.transform in src/bokeh/core/property/datetime.py

⏱️ Runtime : 71.9 microseconds 50.7 microseconds (best of 221 runs)

📝 Explanation and details

The optimization removes an unnecessary super().transform(value) call from the Date.transform() method, achieving a 41% speedup by eliminating function call overhead.

Key optimization: The base Property.transform() method simply returns the input value unchanged (return value). By removing the super().transform(value) call in Date.transform(), we eliminate:

  • Function call overhead (~75% of execution time per profiling)
  • Python's super() mechanism overhead
  • An extra variable assignment

Why this works: The line profiler shows the super().transform(value) call took 245,032 nanoseconds (74.7% of total time), while the actual date logic (isinstance check + isoformat) took much less. By inlining the trivial parent behavior, we reduce the optimized version to just 118,163 nanoseconds total.

Test case performance: The optimization is particularly effective for:

  • Non-date inputs (strings, integers, None): 60-100% faster since they skip both the super() call and date conversion
  • Date objects: 15-35% faster, benefiting primarily from removing the super() call overhead
  • Large-scale operations: Consistent speedup across all test scenarios due to the per-call overhead reduction

Behavior preservation: The optimization maintains identical functionality - date objects are still converted to ISO format strings, and all other values pass through unchanged. The transformation logic and type handling remain completely intact.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 270 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
import datetime
# function to test
from typing import Any

# imports
import pytest  # used for our unit tests
from bokeh.core.property.datetime import Date

# unit tests

# -------------------- BASIC TEST CASES --------------------

def test_transform_with_date_object():
    # Basic: Should convert a datetime.date to ISO string
    d = datetime.date(2024, 6, 1)
    codeflash_output = Date().transform(d) # 2.10μs -> 1.66μs (27.1% faster)

def test_transform_with_iso_string():
    # Basic: Should return ISO string unchanged
    s = "2024-06-01"
    codeflash_output = Date().transform(s) # 919ns -> 422ns (118% faster)

def test_transform_with_non_iso_string():
    # Basic: Should return non-ISO string unchanged
    s = "June 1, 2024"
    codeflash_output = Date().transform(s) # 900ns -> 501ns (79.6% faster)

def test_transform_with_datetime_object():
    # Basic: Should convert datetime.datetime to ISO date string (date part only)
    dt = datetime.datetime(2024, 6, 1, 12, 30, 45)
    # Since datetime.datetime is a subclass of datetime.date, it should convert to date string
    codeflash_output = Date().transform(dt) # 2.78μs -> 2.31μs (20.6% faster)

def test_transform_with_none():
    # Basic: Should return None unchanged
    codeflash_output = Date().transform(None) # 871ns -> 468ns (86.1% faster)

def test_transform_with_integer():
    # Basic: Should return integer unchanged
    codeflash_output = Date().transform(123456) # 871ns -> 505ns (72.5% faster)

def test_transform_with_float():
    # Basic: Should return float unchanged
    codeflash_output = Date().transform(123.456) # 1.03μs -> 630ns (63.3% faster)

def test_transform_with_list():
    # Basic: Should return list unchanged
    codeflash_output = Date().transform([2024, 6, 1]) # 890ns -> 488ns (82.4% faster)

def test_transform_with_dict():
    # Basic: Should return dict unchanged
    codeflash_output = Date().transform({"year": 2024, "month": 6, "day": 1}) # 827ns -> 469ns (76.3% faster)

# -------------------- EDGE TEST CASES --------------------

def test_transform_with_min_date():
    # Edge: Test with minimum possible date
    min_date = datetime.date.min
    codeflash_output = Date().transform(min_date) # 2.12μs -> 1.71μs (23.5% faster)

def test_transform_with_max_date():
    # Edge: Test with maximum possible date
    max_date = datetime.date.max
    codeflash_output = Date().transform(max_date) # 1.84μs -> 1.45μs (27.4% faster)

def test_transform_with_empty_string():
    # Edge: Should return empty string unchanged
    codeflash_output = Date().transform("") # 883ns -> 454ns (94.5% faster)

def test_transform_with_boolean_true():
    # Edge: Should return True unchanged
    codeflash_output = Date().transform(True) # 1.07μs -> 702ns (52.7% faster)

def test_transform_with_boolean_false():
    # Edge: Should return False unchanged
    codeflash_output = Date().transform(False) # 1.04μs -> 590ns (75.9% faster)

def test_transform_with_datetime_subclass():
    # Edge: Should convert subclass of datetime.date
    class MyDate(datetime.date):
        pass
    d = MyDate(2024, 6, 1)
    codeflash_output = Date().transform(d) # 2.33μs -> 1.89μs (23.4% faster)

def test_transform_with_object_with_isoformat():
    # Edge: Should not convert object with isoformat unless it's a datetime.date
    class Dummy:
        def isoformat(self):
            return "not-a-date"
    dummy = Dummy()
    codeflash_output = Date().transform(dummy) # 1.01μs -> 572ns (77.4% faster)

def test_transform_with_bytes():
    # Edge: Should return bytes unchanged
    codeflash_output = Date().transform(b"2024-06-01") # 893ns -> 469ns (90.4% faster)

def test_transform_with_tuple():
    # Edge: Should return tuple unchanged
    codeflash_output = Date().transform((2024, 6, 1)) # 903ns -> 564ns (60.1% faster)

def test_transform_with_set():
    # Edge: Should return set unchanged
    codeflash_output = Date().transform({2024, 6, 1}) # 906ns -> 577ns (57.0% faster)

# -------------------- LARGE SCALE TEST CASES --------------------

def test_transform_with_large_list_of_dates():
    # Large Scale: Transform a large list of datetime.date objects
    dates = [datetime.date(2024, 1, i % 28 + 1) for i in range(1000)]
    transformed = [Date().transform(d) for d in dates]
    expected = [d.isoformat() for d in dates]

def test_transform_with_large_list_of_iso_strings():
    # Large Scale: Transform a large list of ISO strings (should be unchanged)
    iso_dates = [f"2024-01-{str(i % 28 + 1).zfill(2)}" for i in range(1000)]
    transformed = [Date().transform(s) for s in iso_dates]

def test_transform_with_large_mixed_list():
    # Large Scale: Mixed types in a large list
    items = []
    expected = []
    for i in range(500):
        d = datetime.date(2024, 1, i % 28 + 1)
        s = d.isoformat()
        items.append(d)
        items.append(s)
        expected.append(s)
        expected.append(s)
    transformed = [Date().transform(x) for x in items]

def test_transform_with_large_list_of_integers():
    # Large Scale: Should return list of integers unchanged
    ints = list(range(1000))
    transformed = [Date().transform(i) for i in ints]

def test_transform_with_large_list_of_none():
    # Large Scale: Should return list of None unchanged
    none_list = [None] * 1000
    transformed = [Date().transform(n) for n in none_list]

# -------------------- SPECIAL CASES --------------------

def test_transform_with_datetime_with_time():
    # Special: Should convert datetime.datetime to ISO string including time
    dt = datetime.datetime(2024, 6, 1, 15, 45, 30)
    codeflash_output = Date().transform(dt) # 4.42μs -> 3.28μs (34.7% faster)

def test_transform_with_leap_year_date():
    # Special: Should handle leap year date
    d = datetime.date(2024, 2, 29)
    codeflash_output = Date().transform(d) # 2.24μs -> 1.75μs (28.1% faster)

def test_transform_with_non_gregorian_date_string():
    # Special: Should return non-Gregorian date string unchanged
    s = "2024-13-01"  # Invalid month
    codeflash_output = Date().transform(s) # 969ns -> 540ns (79.4% faster)

def test_transform_with_object_without_isoformat():
    # Special: Should return object unchanged if not a datetime.date
    class NoIso:
        pass
    obj = NoIso()
    codeflash_output = Date().transform(obj) # 1.13μs -> 703ns (60.2% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
import datetime
# function to test (from bokeh/core/property/datetime.py)
from typing import Any

# imports
import pytest
from bokeh.core.property.datetime import Date

# unit tests

# ---------------------------
# 1. Basic Test Cases
# ---------------------------

def test_transform_with_date_object():
    # Should convert a datetime.date object to ISO string
    d = datetime.date(2024, 6, 14)
    codeflash_output = Date().transform(d); result = codeflash_output # 2.25μs -> 1.72μs (31.0% faster)

def test_transform_with_iso_string():
    # Should return ISO string unchanged
    s = "2024-06-14"
    codeflash_output = Date().transform(s); result = codeflash_output # 960ns -> 515ns (86.4% faster)

def test_transform_with_non_iso_string():
    # Should return non-ISO string unchanged
    s = "14/06/2024"
    codeflash_output = Date().transform(s); result = codeflash_output # 890ns -> 478ns (86.2% faster)

def test_transform_with_none():
    # Should return None unchanged
    codeflash_output = Date().transform(None); result = codeflash_output # 880ns -> 536ns (64.2% faster)

def test_transform_with_integer():
    # Should return integer unchanged
    codeflash_output = Date().transform(20240614); result = codeflash_output # 858ns -> 464ns (84.9% faster)

def test_transform_with_datetime_object():
    # Should return datetime.datetime unchanged (not converted to string)
    dt = datetime.datetime(2024, 6, 14, 12, 30)
    codeflash_output = Date().transform(dt); result = codeflash_output # 3.05μs -> 2.57μs (18.6% faster)

# ---------------------------
# 2. Edge Test Cases
# ---------------------------

def test_transform_with_min_date():
    # Should handle the minimum valid date
    d = datetime.date.min
    codeflash_output = Date().transform(d); result = codeflash_output # 1.92μs -> 1.50μs (27.3% faster)

def test_transform_with_max_date():
    # Should handle the maximum valid date
    d = datetime.date.max
    codeflash_output = Date().transform(d); result = codeflash_output # 1.80μs -> 1.36μs (32.1% faster)

def test_transform_with_empty_string():
    # Should return empty string unchanged
    codeflash_output = Date().transform(""); result = codeflash_output # 865ns -> 500ns (73.0% faster)

def test_transform_with_object():
    # Should return arbitrary object unchanged
    class Dummy:
        pass
    obj = Dummy()
    codeflash_output = Date().transform(obj); result = codeflash_output # 1.10μs -> 605ns (81.3% faster)

def test_transform_with_bool():
    # Should return boolean unchanged
    codeflash_output = Date().transform(True); result_true = codeflash_output # 1.06μs -> 662ns (59.7% faster)
    codeflash_output = Date().transform(False); result_false = codeflash_output # 565ns -> 335ns (68.7% faster)

def test_transform_with_float():
    # Should return float unchanged
    codeflash_output = Date().transform(3.14159); result = codeflash_output # 970ns -> 613ns (58.2% faster)

def test_transform_with_bytes():
    # Should return bytes unchanged
    b = b"2024-06-14"
    codeflash_output = Date().transform(b); result = codeflash_output # 809ns -> 438ns (84.7% faster)

def test_transform_with_datetime_subclass():
    # Should not convert subclasses of datetime.datetime
    class MyDateTime(datetime.datetime):
        pass
    dt = MyDateTime(2024, 6, 14, 12, 0)
    codeflash_output = Date().transform(dt); result = codeflash_output # 3.21μs -> 2.77μs (15.7% faster)

def test_transform_with_date_subclass():
    # Should convert subclasses of datetime.date to ISO string
    class MyDate(datetime.date):
        pass
    d = MyDate(2024, 6, 14)
    codeflash_output = Date().transform(d); result = codeflash_output # 2.18μs -> 1.77μs (23.2% faster)

def test_transform_with_list_of_dates():
    # Should return list unchanged (not recursive)
    dates = [datetime.date(2024, 6, 14), datetime.date(2024, 6, 15)]
    codeflash_output = Date().transform(dates); result = codeflash_output # 768ns -> 428ns (79.4% faster)

def test_transform_with_tuple_of_dates():
    # Should return tuple unchanged
    dates = (datetime.date(2024, 6, 14), datetime.date(2024, 6, 15))
    codeflash_output = Date().transform(dates); result = codeflash_output # 869ns -> 520ns (67.1% faster)

def test_transform_with_dict_of_dates():
    # Should return dict unchanged
    dates = {"a": datetime.date(2024, 6, 14), "b": datetime.date(2024, 6, 15)}
    codeflash_output = Date().transform(dates); result = codeflash_output # 735ns -> 423ns (73.8% faster)

# ---------------------------
# 3. Large Scale Test Cases
# ---------------------------

def test_transform_large_list_of_dates():
    # Should efficiently handle a large list of date objects (not recursive)
    large_list = [datetime.date(2024, 6, 14) for _ in range(1000)]
    codeflash_output = Date().transform(large_list); result = codeflash_output # 774ns -> 415ns (86.5% faster)

def test_transform_large_list_of_strings():
    # Should efficiently handle a large list of strings (not recursive)
    large_list = ["2024-06-14" for _ in range(1000)]
    codeflash_output = Date().transform(large_list); result = codeflash_output # 925ns -> 462ns (100% faster)

def test_transform_large_list_of_mixed_types():
    # Should efficiently handle a large list of mixed types (not recursive)
    large_list = [datetime.date(2024, 6, 14) if i % 2 == 0 else "2024-06-14" for i in range(1000)]
    codeflash_output = Date().transform(large_list); result = codeflash_output # 761ns -> 490ns (55.3% faster)

def test_transform_large_dict_of_dates():
    # Should efficiently handle a large dict of date objects (not recursive)
    large_dict = {str(i): datetime.date(2024, 6, 14) for i in range(1000)}
    codeflash_output = Date().transform(large_dict); result = codeflash_output # 787ns -> 475ns (65.7% faster)

def test_transform_large_string():
    # Should efficiently handle a large string (not a date)
    large_str = "a" * 1000
    codeflash_output = Date().transform(large_str); result = codeflash_output # 996ns -> 542ns (83.8% faster)

def test_transform_large_bytes():
    # Should efficiently handle a large bytes object
    large_bytes = b"a" * 1000
    codeflash_output = Date().transform(large_bytes); result = codeflash_output # 952ns -> 486ns (95.9% faster)

# ---------------------------
# 4. Mutation-sensitive tests
# ---------------------------

def test_transform_with_datetime_date_and_datetime_datetime():
    # Should only convert datetime.date, not datetime.datetime
    d = datetime.date(2024, 6, 14)
    dt = datetime.datetime(2024, 6, 14, 12, 30)
    codeflash_output = Date().transform(d) # 2.45μs -> 2.11μs (16.1% faster)
    codeflash_output = Date().transform(dt) # 1.84μs -> 1.68μs (9.70% faster)

def test_transform_with_date_subclass_and_datetime_subclass():
    # Should convert date subclass, not datetime subclass
    class MyDate(datetime.date):
        pass
    class MyDateTime(datetime.datetime):
        pass
    d = MyDate(2024, 6, 14)
    dt = MyDateTime(2024, 6, 14, 12, 30)
    codeflash_output = Date().transform(d) # 2.03μs -> 1.64μs (23.9% faster)
    codeflash_output = Date().transform(dt) # 1.68μs -> 1.53μs (9.80% 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-Date.transform-mhwpsmbs and push.

Codeflash Static Badge

The optimization removes an unnecessary `super().transform(value)` call from the `Date.transform()` method, achieving a **41% speedup** by eliminating function call overhead.

**Key optimization**: The base `Property.transform()` method simply returns the input value unchanged (`return value`). By removing the `super().transform(value)` call in `Date.transform()`, we eliminate:
- Function call overhead (~75% of execution time per profiling)
- Python's `super()` mechanism overhead
- An extra variable assignment

**Why this works**: The line profiler shows the `super().transform(value)` call took 245,032 nanoseconds (74.7% of total time), while the actual date logic (isinstance check + isoformat) took much less. By inlining the trivial parent behavior, we reduce the optimized version to just 118,163 nanoseconds total.

**Test case performance**: The optimization is particularly effective for:
- **Non-date inputs** (strings, integers, None): 60-100% faster since they skip both the super() call and date conversion
- **Date objects**: 15-35% faster, benefiting primarily from removing the super() call overhead
- **Large-scale operations**: Consistent speedup across all test scenarios due to the per-call overhead reduction

**Behavior preservation**: The optimization maintains identical functionality - date objects are still converted to ISO format strings, and all other values pass through unchanged. The transformation logic and type handling remain completely intact.
@codeflash-ai codeflash-ai Bot requested a review from mashraf-222 November 13, 2025 00:52
@codeflash-ai codeflash-ai Bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Nov 13, 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.

0 participants