Skip to content

Conversation

@codeflash-ai
Copy link

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

📄 8% (0.08x) speedup for UniversalBaseModel.construct in src/deepgram/core/pydantic_utilities.py

⏱️ Runtime : 128 milliseconds 119 milliseconds (best of 32 runs)

📝 Explanation and details

The optimized code achieves a 7% speedup by introducing cached type introspection functions to eliminate redundant expensive calls to typing_extensions utilities.

Key optimizations:

  1. LRU-cached type introspection helpers: Added @lru_cache(maxsize=128) decorators to _get_origin_cached(), _get_args_cached(), and _is_typeddict_cached() functions. This eliminates repeated expensive type analysis calls that were consuming significant time in the profiler.

  2. Local caching of origin lookups: Introduced clean_type_origin = _get_origin_cached(clean_type) to avoid calling get_origin multiple times for the same type within a single function call.

  3. Tuple unpacking optimization: Changed typing_extensions.get_args(clean_type)[0] patterns to tuple unpacking like (inner_container_type,) = _get_args_cached(clean_type) and key_type, value_type = _get_args_cached(clean_type), reducing indexing overhead.

Why it's faster: The line profiler shows that repeated calls to typing_extensions.get_origin() were major bottlenecks (consuming 1.2-1.6% each). By caching these introspection results, the optimized version reduces the time spent on type analysis from ~39ms to ~35ms in the core function.

Best performance gains are seen in test cases with:

  • Large collections (122% faster for 1000-element lists, 117% faster for 1000-element dicts)
  • Sequence operations (11.6% faster for sequence models)
  • Union types and complex nested structures where type introspection occurs frequently

The caching is particularly effective because the same types are often analyzed repeatedly during recursive traversal of nested data structures.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 23 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 75.0%
🌀 Generated Regression Tests and Runtime
import collections.abc
import datetime as dt
import sys
import typing

import pydantic
# imports
import pytest
import typing_extensions
from deepgram.core.pydantic_utilities import UniversalBaseModel

# --- Function under test and its dependencies (from deepgram/core/pydantic_utilities.py and deepgram/core/serialization.py) ---

# Minimal stub for serialize_datetime to allow UniversalBaseModel to work
def serialize_datetime(dt_obj):
    return dt_obj.isoformat()

# IS_PYDANTIC_V2 logic
IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.")
from deepgram.core.pydantic_utilities import UniversalBaseModel

# 1. BASIC TEST CASES























#------------------------------------------------
import sys
import typing

import pydantic
# imports
import pytest
import typing_extensions
from deepgram.core.pydantic_utilities import UniversalBaseModel


# Helper for TypedDicts with aliases
def make_typed_dict_with_alias():
    class TD(typing_extensions.TypedDict, total=True):
        x: int
        y: typing_extensions.Annotated[int, pydantic.Field(alias="z")]
    return TD

# Helper for Pydantic models with aliases
class AliasModel(UniversalBaseModel):
    x: int
    y: typing_extensions.Annotated[int, pydantic.Field(alias="z")]

class NestedModel(UniversalBaseModel):
    a: int
    b: AliasModel

class ListModel(UniversalBaseModel):
    items: typing.List[int]

class SetModel(UniversalBaseModel):
    items: typing.Set[str]

class DictModel(UniversalBaseModel):
    mapping: typing.Dict[str, int]

class UnionModel(UniversalBaseModel):
    value: typing.Union[int, str]

class OptionalModel(UniversalBaseModel):
    value: typing.Optional[int]

class SequenceModel(UniversalBaseModel):
    seq: typing.Sequence[int]

# Basic Test Cases

def test_construct_basic_pydantic_model():
    # Test basic construction with direct field names
    codeflash_output = AliasModel.construct(x=1, y=2); m = codeflash_output # 132μs -> 130μs (1.17% faster)

def test_construct_basic_pydantic_model_with_alias():
    # Test construction using aliased field
    codeflash_output = AliasModel.construct(x=1, z=3); m = codeflash_output # 112μs -> 111μs (0.186% faster)


def test_construct_list_model():
    # Test construction with list field
    codeflash_output = ListModel.construct(items=[1, 2, 3]); m = codeflash_output # 66.3μs -> 63.1μs (5.07% faster)

def test_construct_set_model():
    # Test construction with set field
    codeflash_output = SetModel.construct(items={"a", "b"}); m = codeflash_output # 58.2μs -> 58.6μs (0.649% slower)

def test_construct_dict_model():
    # Test construction with dict field
    codeflash_output = DictModel.construct(mapping={"foo": 1, "bar": 2}); m = codeflash_output # 64.9μs -> 61.2μs (6.00% faster)

def test_construct_union_model_with_int():
    # Test construction with Union field (int)
    codeflash_output = UnionModel.construct(value=42); m = codeflash_output # 68.3μs -> 64.2μs (6.49% faster)

def test_construct_union_model_with_str():
    # Test construction with Union field (str)
    codeflash_output = UnionModel.construct(value="hello"); m = codeflash_output # 63.6μs -> 61.0μs (4.22% faster)

def test_construct_optional_model_with_value():
    # Test construction with Optional field (value present)
    codeflash_output = OptionalModel.construct(value=5); m = codeflash_output # 64.9μs -> 61.5μs (5.54% faster)

def test_construct_optional_model_none():
    # Test construction with Optional field (None)
    codeflash_output = OptionalModel.construct(value=None); m = codeflash_output # 50.3μs -> 49.8μs (0.954% faster)

def test_construct_sequence_model():
    # Test construction with Sequence field
    codeflash_output = SequenceModel.construct(seq=[1, 2, 3]); m = codeflash_output # 68.1μs -> 61.0μs (11.6% faster)

# Edge Test Cases



def test_construct_extra_field():
    # Test construction with extra field not in model
    codeflash_output = AliasModel.construct(x=1, y=2, extra=99); m = codeflash_output # 143μs -> 140μs (2.06% faster)

def test_construct_with_none_for_non_optional():
    # Test construction with None for non-optional field
    codeflash_output = AliasModel.construct(x=None, y=2); m = codeflash_output # 116μs -> 114μs (1.95% faster)

def test_construct_with_alias_and_field_name():
    # Test construction with both alias and field name; alias should take precedence
    codeflash_output = AliasModel.construct(x=1, y=2, z=99); m = codeflash_output # 113μs -> 110μs (2.24% faster)

def test_construct_typed_dict_with_alias():
    # Test TypedDict with alias, passed to a model
    TD = make_typed_dict_with_alias()
    d = TD(x=10, z=20)
    codeflash_output = AliasModel.construct(**d); m = codeflash_output # 100μs -> 97.4μs (3.22% faster)

def test_construct_nested_dict_with_alias():
    # Test nested dict with alias in inner model
    codeflash_output = NestedModel.construct(a=1, b={"x": 2, "z": 3}); m = codeflash_output # 140μs -> 138μs (1.17% faster)







def test_construct_with_empty_list_and_set():
    # Test construction with empty list and set
    codeflash_output = ListModel.construct(items=[]); m1 = codeflash_output # 54.4μs -> 52.3μs (4.02% faster)
    codeflash_output = SetModel.construct(items=set()); m2 = codeflash_output # 34.0μs -> 34.2μs (0.614% slower)

def test_construct_with_large_int():
    # Test construction with large integer value
    codeflash_output = AliasModel.construct(x=sys.maxsize, y=2); m = codeflash_output # 120μs -> 117μs (2.33% faster)

def test_construct_with_unicode_string():
    # Test construction with unicode string in set
    codeflash_output = SetModel.construct(items={"α", "β"}); m = codeflash_output # 57.0μs -> 56.0μs (1.84% faster)

# Large Scale Test Cases

def test_construct_large_list_model():
    # Test construction with a large list (1000 elements)
    data = list(range(1000))
    codeflash_output = ListModel.construct(items=data); m = codeflash_output # 3.31ms -> 1.49ms (122% faster)

def test_construct_large_set_model():
    # Test construction with a large set (1000 elements)
    data = set(str(i) for i in range(1000))
    codeflash_output = SetModel.construct(items=data); m = codeflash_output # 1.92ms -> 1.25ms (54.3% faster)

def test_construct_large_dict_model():
    # Test construction with a large dict (1000 elements)
    data = {str(i): i for i in range(1000)}
    codeflash_output = DictModel.construct(mapping=data); m = codeflash_output # 3.35ms -> 1.54ms (117% faster)





#------------------------------------------------
from deepgram.core.pydantic_utilities import UniversalBaseModel
import pytest

def test_UniversalBaseModel_construct():
    with pytest.raises(TypeError, match='super\\(type,\\ obj\\):\\ obj\\ must\\ be\\ an\\ instance\\ or\\ subtype\\ of\\ type'):
        UniversalBaseModel.construct(UniversalBaseModel, _fields_set=None)

To edit these changes git checkout codeflash/optimize-UniversalBaseModel.construct-mh2t5zfk and push.

Codeflash

The optimized code achieves a **7% speedup** by introducing **cached type introspection functions** to eliminate redundant expensive calls to `typing_extensions` utilities.

**Key optimizations:**

1. **LRU-cached type introspection helpers**: Added `@lru_cache(maxsize=128)` decorators to `_get_origin_cached()`, `_get_args_cached()`, and `_is_typeddict_cached()` functions. This eliminates repeated expensive type analysis calls that were consuming significant time in the profiler.

2. **Local caching of origin lookups**: Introduced `clean_type_origin = _get_origin_cached(clean_type)` to avoid calling `get_origin` multiple times for the same type within a single function call.

3. **Tuple unpacking optimization**: Changed `typing_extensions.get_args(clean_type)[0]` patterns to tuple unpacking like `(inner_container_type,) = _get_args_cached(clean_type)` and `key_type, value_type = _get_args_cached(clean_type)`, reducing indexing overhead.

**Why it's faster**: The line profiler shows that repeated calls to `typing_extensions.get_origin()` were major bottlenecks (consuming 1.2-1.6% each). By caching these introspection results, the optimized version reduces the time spent on type analysis from ~39ms to ~35ms in the core function.

**Best performance gains** are seen in test cases with:
- Large collections (122% faster for 1000-element lists, 117% faster for 1000-element dicts)
- Sequence operations (11.6% faster for sequence models)
- Union types and complex nested structures where type introspection occurs frequently

The caching is particularly effective because the same types are often analyzed repeatedly during recursive traversal of nested data structures.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 October 23, 2025 02:33
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Oct 23, 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