Skip to content

Only compute normalized decimal places if necessary in decimal_places_validator #11281

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

misrasaurabh1
Copy link
Contributor

📄 decimal_places_validator in pydantic/_internal/_validators.py

✨ Performance Summary:

  • Speed Increase: 📈 24% (0.24x faster)
  • Runtime Reduction: ⏱️ From 182 microseconds down to 147 microseconds (best of 159 runs)

📝 Explanation and details

Here are the changes made to the code for optimization.

  1. Calling _extract_decimal_digits_info function isn't required when (decimal_places_ > decimal_places) does not hold true.

Correctness verification

The new optimized code was tested for correctness. The results are listed below:

Test Status Details
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 23 Passed See below
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 1 Passed
📊 Coverage 100.00%

🌀 Generated Regression Tests Details

Click to view details
from decimal import Decimal
from typing import Any

# imports
import pytest  # used for our unit tests
from pydantic._internal._validators import decimal_places_validator
from pydantic_core._pydantic_core import PydanticKnownError

# unit tests

# Basic Test Cases
def test_valid_decimal_exact_places():
    codeflash_output = decimal_places_validator(Decimal('1.23'), 2)
    codeflash_output = decimal_places_validator(Decimal('0.123'), 3)

def test_valid_decimal_less_places():
    codeflash_output = decimal_places_validator(Decimal('1.2'), 2)
    codeflash_output = decimal_places_validator(Decimal('0.1'), 3)

def test_invalid_decimal_more_places():
    with pytest.raises(PydanticKnownError):
        decimal_places_validator(Decimal('1.234'), 2)
    with pytest.raises(PydanticKnownError):
        decimal_places_validator(Decimal('0.1234'), 3)

# Edge Test Cases
def test_non_normalized_input():
    codeflash_output = decimal_places_validator(Decimal('1.2300'), 3)
    codeflash_output = decimal_places_validator(Decimal('0.1230'), 3)


def test_zero_value():
    codeflash_output = decimal_places_validator(Decimal('0'), 0)
    codeflash_output = decimal_places_validator(Decimal('0.0'), 1)

def test_negative_values():
    codeflash_output = decimal_places_validator(Decimal('-1.23'), 2)
    codeflash_output = decimal_places_validator(Decimal('-0.123'), 3)

def test_large_numbers():
    codeflash_output = decimal_places_validator(Decimal('123456789.123456789'), 9)
    codeflash_output = decimal_places_validator(Decimal('123456789.1234567890'), 10)

# Invalid Inputs
def test_non_decimal_types():
    with pytest.raises(TypeError):
        decimal_places_validator('1.23', 2)
    with pytest.raises(TypeError):
        decimal_places_validator(1.23, 2)
    with pytest.raises(TypeError):
        decimal_places_validator(None, 2)

# Boundary Conditions
def test_maximum_decimal_places():
    codeflash_output = decimal_places_validator(Decimal('1.' + '0'*28 + '1'), 29)
    with pytest.raises(PydanticKnownError):
        decimal_places_validator(Decimal('1.' + '0'*28 + '1'), 28)

def test_minimum_decimal_places():
    codeflash_output = decimal_places_validator(Decimal('1.0'), 0)
    with pytest.raises(PydanticKnownError):
        decimal_places_validator(Decimal('1.1'), 0)

# Large Scale Test Cases
def test_large_scale():
    codeflash_output = decimal_places_validator(Decimal('1.' + '0'*1000 + '1'), 1001)
    with pytest.raises(PydanticKnownError):
        decimal_places_validator(Decimal('1.' + '0'*1000 + '1'), 1000)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

📣 **Feedback**

If you have any feedback or need assistance, feel free to join our Discord community:

Discord

codeflash-ai bot and others added 2 commits December 3, 2024 23:41
Here are the changes made to the code for optimization.

1. Avoided repeated calls to expensive functions like `len()`.
2. Simplified some logic to minimize computations.
3. Removed the redundant instances of re-extracting decimal info where possible.




Points of optimization.
- Avoided `assert` statement which is typically disabled in optimized mode.
- Simplified the conditional blocks and reduced the number of function calls and length calculations.
@github-actions github-actions bot added the relnotes-fix Used for bugfixes. label Jan 16, 2025
Copy link

codspeed-hq bot commented Jan 16, 2025

CodSpeed Performance Report

Merging #11281 will not alter performance

Comparing misrasaurabh1:codeflash/optimize-decimal_places_validator-2024-12-03T23.41.41 (197ab22) with main (dac74dc)

Summary

✅ 45 untouched benchmarks

Copy link
Contributor

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  pydantic/_internal
  _validators.py
Project Total  

This report was generated by python-coverage-comment-action

@Viicos Viicos changed the title ⚡️ Speed up function decimal_places_validator by 24% [codeflash] Only compute normalized decimal places if necessary in decimal_places_validator Jan 16, 2025
@Viicos Viicos enabled auto-merge (squash) January 16, 2025 11:07
@Viicos Viicos merged commit 46f3075 into pydantic:main Jan 16, 2025
53 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
relnotes-fix Used for bugfixes.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants