Skip to content

Conversation

@codeflash-ai
Copy link

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

📄 35% (0.35x) speedup for GoogleFont.stylesheet in gradio/themes/utils/fonts.py

⏱️ Runtime : 257 microseconds 190 microseconds (best of 84 runs)

📝 Explanation and details

The optimization replaces the generator expression str(weight) for weight in self.weights with map(str, self.weights) in the string join operation.

Key Change:

  • Changed ';'.join(str(weight) for weight in self.weights) to ';'.join(map(str, self.weights))

Why This is Faster:
The map() function is implemented in C and operates directly on the iterable without the Python interpreter overhead of a generator expression. Generator expressions require Python bytecode execution for each iteration, while map() handles the conversion at the C level, resulting in significantly less overhead per element.

Performance Impact:
The optimization shows consistent 10-20% improvements across basic test cases and dramatically better performance on large-scale tests:

  • Basic cases: 9-23% faster (e.g., single weight: 16.8% faster, multiple weights: 17% faster)
  • Large-scale cases: Up to 65.9% faster when processing many weights (1000 string weights: 65.9% faster, 999 integer weights: 40.4% faster)

The optimization is particularly effective for cases with many weights since the per-element overhead reduction compounds. Even edge cases like empty weights (23.8% faster) and non-standard iterables benefit from the more efficient C-level iteration.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 66 Passed
⏪ Replay Tests 12 Passed
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
from collections.abc import Iterable

# imports
import pytest  # used for our unit tests
from gradio.themes.utils.fonts import GoogleFont


class Font:
    pass
from gradio.themes.utils.fonts import GoogleFont

# unit tests

# 1. Basic Test Cases

def test_basic_single_weight():
    # Test with a single weight
    font = GoogleFont("Roboto", weights=[400])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.33μs -> 2.00μs (16.8% faster)

def test_basic_multiple_weights():
    # Test with multiple weights
    font = GoogleFont("Open Sans", weights=[400, 700])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.66μs -> 2.27μs (17.0% faster)

def test_basic_default_weights():
    # Test with default weights
    font = GoogleFont("Lato")
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.32μs -> 2.13μs (9.03% faster)

def test_basic_name_with_spaces():
    # Test font name with multiple spaces
    font = GoogleFont("Noto Sans JP", weights=[100, 900])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.49μs -> 2.16μs (15.2% faster)

def test_basic_weights_as_tuple():
    # Test weights as a tuple
    font = GoogleFont("Montserrat", weights=(300, 500))
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.37μs -> 2.02μs (16.8% faster)

# 2. Edge Test Cases

def test_edge_empty_weights():
    # Test with empty weights iterable
    font = GoogleFont("Fira Code", weights=[])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.06μs -> 1.67μs (23.8% faster)

def test_edge_non_integer_weights():
    # Test with non-integer weights (should coerce to string but not fail)
    font = GoogleFont("Arial", weights=["400", "700"])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.19μs -> 1.85μs (18.3% faster)

def test_edge_weights_with_duplicates():
    # Test with duplicate weights
    font = GoogleFont("Poppins", weights=[400, 400, 700])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.56μs -> 2.14μs (19.7% faster)

def test_edge_font_name_special_characters():
    # Test font name with special characters
    font = GoogleFont("Comic+Sans", weights=[400])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.24μs -> 1.86μs (20.7% faster)

def test_edge_font_name_empty_string():
    # Test with empty font name
    font = GoogleFont("", weights=[400])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.15μs -> 1.82μs (18.3% faster)

def test_edge_weights_as_set():
    # Test weights as a set (order may vary!)
    font = GoogleFont("Inter", weights=set([400, 700]))
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.56μs -> 2.21μs (16.0% faster)
    # Since sets are unordered, check for both possible orderings
    url = result["url"]
    weights_part = url.split(":wght@")[1].split("&")[0]
    weights = weights_part.split(";")


def test_edge_weights_with_negative_and_zero():
    # Test with negative and zero weights
    font = GoogleFont("Ubuntu", weights=[0, -100, 400])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.46μs -> 2.18μs (13.2% faster)

def test_edge_weights_with_large_numbers():
    # Test with very large weight numbers
    font = GoogleFont("Oswald", weights=[1000, 2000])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.35μs -> 2.02μs (16.3% faster)

# 3. Large Scale Test Cases

def test_large_scale_many_weights():
    # Test with a large number of weights (up to 1000)
    weights = list(range(100, 1100))  # 1000 weights
    font = GoogleFont("BigFont", weights=weights)
    codeflash_output = font.stylesheet(); result = codeflash_output # 68.5μs -> 47.7μs (43.6% faster)
    # Check that all weights are present and joined correctly
    expected_weights_str = ";".join(str(w) for w in weights)

def test_large_scale_long_font_name():
    # Test with a very long font name
    long_name = "A" * 200
    font = GoogleFont(long_name, weights=[400])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.31μs -> 1.98μs (16.9% faster)
    plus_name = long_name.replace(' ', '+')

def test_large_scale_long_font_name_with_spaces():
    # Test with a very long font name including spaces
    long_name = "Font " * 200  # 1000 characters, 200 words
    font = GoogleFont(long_name, weights=[400])
    plus_name = long_name.replace(' ', '+')
    codeflash_output = font.stylesheet(); result = codeflash_output # 3.21μs -> 2.93μs (9.41% faster)

def test_large_scale_weights_as_strings():
    # Test with 1000 weights as strings
    weights = [str(i) for i in range(100, 1100)]
    font = GoogleFont("StringyFont", weights=weights)
    expected_weights_str = ";".join(weights)
    codeflash_output = font.stylesheet(); result = codeflash_output # 43.6μs -> 26.3μs (65.9% faster)

def test_large_scale_weights_as_iterable():
    # Test with weights as a range object (iterable)
    font = GoogleFont("RangeFont", weights=range(100, 200))
    expected_weights_str = ";".join(str(w) for w in range(100, 200))
    codeflash_output = font.stylesheet(); result = codeflash_output # 8.43μs -> 6.63μs (27.1% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
#------------------------------------------------
from collections.abc import Iterable

# imports
import pytest  # used for our unit tests
from gradio.themes.utils.fonts import GoogleFont


class Font:
    pass  # Minimal stub to allow GoogleFont to inherit
from gradio.themes.utils.fonts import GoogleFont

# unit tests

# Basic Test Cases

def test_basic_single_weight():
    # Test with a single weight
    font = GoogleFont("Roboto", [400])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.22μs -> 2.03μs (9.50% faster)
    expected_url = "https://fonts.googleapis.com/css2?family=Roboto:wght@400&display=swap"

def test_basic_multiple_weights():
    # Test with multiple weights
    font = GoogleFont("Roboto", [400, 700])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.39μs -> 2.14μs (11.8% faster)
    expected_url = "https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap"

def test_basic_default_weights():
    # Test with default weights
    font = GoogleFont("Open Sans")
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.53μs -> 2.21μs (14.7% faster)
    expected_url = "https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600&display=swap"

def test_basic_font_with_spaces():
    # Test font name with multiple spaces
    font = GoogleFont("Noto Sans JP", [400, 900])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.54μs -> 2.25μs (12.6% faster)
    expected_url = "https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;900&display=swap"

# Edge Test Cases

def test_edge_empty_weights():
    # Test with empty weights iterable
    font = GoogleFont("Roboto", [])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.01μs -> 1.79μs (12.1% faster)
    expected_url = "https://fonts.googleapis.com/css2?family=Roboto:wght@&display=swap"

def test_edge_single_weight_as_tuple():
    # Test with a single weight as a tuple
    font = GoogleFont("Lato", (700,))
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.17μs -> 1.96μs (10.4% faster)
    expected_url = "https://fonts.googleapis.com/css2?family=Lato:wght@700&display=swap"

def test_edge_weights_as_set():
    # Test with weights as a set (unordered, but order should be preserved in output as per input)
    font = GoogleFont("Montserrat", {400, 700})
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.48μs -> 2.17μs (14.0% faster)
    # Since sets are unordered, we check both possible outputs
    expected_urls = [
        "https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap",
        "https://fonts.googleapis.com/css2?family=Montserrat:wght@700;400&display=swap"
    ]


def test_edge_font_name_special_characters():
    # Test font name with special characters
    font = GoogleFont("PT Serif Caption", [400])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.33μs -> 2.05μs (14.1% faster)
    expected_url = "https://fonts.googleapis.com/css2?family=PT+Serif+Caption:wght@400&display=swap"

def test_edge_font_name_empty_string():
    # Test with empty string as font name
    font = GoogleFont("", [400])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.18μs -> 1.77μs (22.7% faster)
    expected_url = "https://fonts.googleapis.com/css2?family=:wght@400&display=swap"

def test_edge_weights_with_non_integer_values():
    # Test with non-integer weights (should be converted to string, but not recommended)
    font = GoogleFont("Roboto", [400, "bold"])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.38μs -> 2.06μs (15.7% faster)
    expected_url = "https://fonts.googleapis.com/css2?family=Roboto:wght@400;bold&display=swap"

def test_edge_weights_with_duplicate_values():
    # Test with duplicate weights
    font = GoogleFont("Roboto", [400, 400, 700])
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.55μs -> 2.18μs (17.0% faster)
    expected_url = "https://fonts.googleapis.com/css2?family=Roboto:wght@400;400;700&display=swap"

# Large Scale Test Cases

def test_large_many_weights():
    # Test with a large number of weights
    weights = list(range(100, 1100, 100))  # 100, 200, ..., 1000 (10 elements)
    font = GoogleFont("Inter", weights)
    codeflash_output = font.stylesheet(); result = codeflash_output # 3.23μs -> 2.74μs (17.9% faster)
    expected_weights_str = ";".join(str(w) for w in weights)
    expected_url = f"https://fonts.googleapis.com/css2?family=Inter:wght@{expected_weights_str}&display=swap"

def test_large_long_font_name():
    # Test with a very long font name
    long_name = "A" * 200
    font = GoogleFont(long_name, [400])
    expected_url = f"https://fonts.googleapis.com/css2?family={'A'*200}:wght@400&display=swap"
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.34μs -> 1.99μs (17.9% faster)

def test_large_max_weights():
    # Test with the maximum allowed weights (999 elements)
    weights = list(range(1, 1000))
    font = GoogleFont("MaxWeightFont", weights)
    expected_weights_str = ";".join(str(w) for w in weights)
    expected_url = f"https://fonts.googleapis.com/css2?family=MaxWeightFont:wght@{expected_weights_str}&display=swap"
    codeflash_output = font.stylesheet(); result = codeflash_output # 61.1μs -> 43.5μs (40.4% faster)

def test_large_font_name_with_many_spaces():
    # Test with a font name containing many spaces
    font_name = "Font " * 50  # 50 repetitions
    font = GoogleFont(font_name.strip(), [400])
    expected_url = f"https://fonts.googleapis.com/css2?family={'Font+'*49}Font:wght@400&display=swap"
    codeflash_output = font.stylesheet(); result = codeflash_output # 2.35μs -> 2.19μs (7.29% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
⏪ Replay Tests and Runtime

To edit these changes git checkout codeflash/optimize-GoogleFont.stylesheet-mhe1xqp8 and push.

Codeflash Static Badge

The optimization replaces the generator expression `str(weight) for weight in self.weights` with `map(str, self.weights)` in the string join operation.

**Key Change:**
- Changed `';'.join(str(weight) for weight in self.weights)` to `';'.join(map(str, self.weights))`

**Why This is Faster:**
The `map()` function is implemented in C and operates directly on the iterable without the Python interpreter overhead of a generator expression. Generator expressions require Python bytecode execution for each iteration, while `map()` handles the conversion at the C level, resulting in significantly less overhead per element.

**Performance Impact:**
The optimization shows consistent 10-20% improvements across basic test cases and dramatically better performance on large-scale tests:
- Basic cases: 9-23% faster (e.g., single weight: 16.8% faster, multiple weights: 17% faster)
- Large-scale cases: Up to 65.9% faster when processing many weights (1000 string weights: 65.9% faster, 999 integer weights: 40.4% faster)

The optimization is particularly effective for cases with many weights since the per-element overhead reduction compounds. Even edge cases like empty weights (23.8% faster) and non-standard iterables benefit from the more efficient C-level iteration.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 October 30, 2025 23:24
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Oct 30, 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