Skip to content

Conversation

@codeflash-ai
Copy link

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

📄 9% (0.09x) speedup for JiraDataSource.submit_bulk_move in backend/python/app/sources/external/jira/jira.py

⏱️ Runtime : 1.91 milliseconds 1.75 milliseconds (best of 250 runs)

📝 Explanation and details

The optimization achieves a 9% runtime improvement (from 1.91ms to 1.75ms) through strategic micro-optimizations that reduce dictionary allocations and attribute lookups:

Key Optimizations:

  1. Eliminated unnecessary dict allocations: Removed creation of empty _path and _query dictionaries that were only used for _as_str_dict() calls. Instead, directly passed empty dict literals {} to HTTPRequest constructor, avoiding ~400 nanoseconds per call for dict creation and subsequent _as_str_dict() processing.

  2. Reduced client attribute lookups: Cached self._client in a local variable client at the start of submit_bulk_move(), eliminating repeated attribute access during the client is None check and await client.execute() call.

  3. Optimized headers dict creation: Changed dict(headers or {}) to dict(headers) if headers else {}, avoiding the or {} evaluation when headers is None and directly creating an empty dict.

  4. Streamlined dict merging in HTTPClient: Replaced {**self.headers, **request.headers} with self.headers.copy(); merged_headers.update(request.headers), which is more efficient for dict merging operations.

Performance Impact:
The line profiler shows the most significant gains in _as_str_dict() calls, which dropped from 1.67ms total time (1260 hits) to 1.32ms (420 hits), directly reflecting the elimination of unnecessary empty dict processing. The optimizations particularly benefit high-throughput scenarios where submit_bulk_move() is called frequently, as evidenced by consistent performance across all test cases including the 100-request concurrent throughput tests.

While throughput remains constant at 105K ops/sec, the 9% runtime reduction means each individual operation completes faster, improving latency and reducing resource consumption in I/O-bound async workflows.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 450 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 93.8%
🌀 Generated Regression Tests and Runtime
import asyncio  # used to run async functions

import pytest  # used for our unit tests
from app.sources.external.jira.jira import JiraDataSource

# --- Minimal stubs for dependencies to allow testing JiraDataSource.submit_bulk_move ---

class HTTPRequest:
    def __init__(self, method, url, headers, path_params, query_params, body):
        self.method = method
        self.url = url
        self.headers = headers
        self.path_params = path_params
        self.query_params = query_params
        self.body = body

class HTTPResponse:
    def __init__(self, data):
        self.data = data

class DummyHTTPClient:
    """A dummy async HTTP client that records requests and returns canned responses."""
    def __init__(self, base_url="https://example.atlassian.net", fail_execute=False):
        self._base_url = base_url
        self.requests = []
        self.fail_execute = fail_execute

    def get_base_url(self):
        return self._base_url

    async def execute(self, request):
        if self.fail_execute:
            raise RuntimeError("Simulated HTTP client failure")
        # Simulate an HTTP call and return a dummy HTTPResponse
        self.requests.append(request)
        # Echo request for validation in tests
        return HTTPResponse({
            "method": request.method,
            "url": request.url,
            "headers": request.headers,
            "body": request.body,
        })

class DummyJiraClient:
    """A dummy JiraClient wrapper that returns our DummyHTTPClient."""
    def __init__(self, http_client):
        self._client = http_client

    def get_client(self):
        return self._client
from app.sources.external.jira.jira import JiraDataSource

# --- Basic Test Cases ---

@pytest.mark.asyncio
async def test_submit_bulk_move_basic_minimal():
    """Test the function with no arguments (all defaults)."""
    client = DummyHTTPClient()
    ds = JiraDataSource(DummyJiraClient(client))
    resp = await ds.submit_bulk_move()

@pytest.mark.asyncio
async def test_submit_bulk_move_basic_all_args():
    """Test the function with all arguments provided."""
    client = DummyHTTPClient()
    ds = JiraDataSource(DummyJiraClient(client))
    mapping = {"target1": ["SRC-1", "SRC-2"]}
    custom_headers = {"X-Custom": "abc"}
    resp = await ds.submit_bulk_move(
        sendBulkNotification=True,
        targetToSourcesMapping=mapping,
        headers=custom_headers
    )

@pytest.mark.asyncio
async def test_submit_bulk_move_basic_headers_override():
    """Test that Content-Type is not overwritten if provided in headers."""
    client = DummyHTTPClient()
    ds = JiraDataSource(DummyJiraClient(client))
    resp = await ds.submit_bulk_move(headers={"Content-Type": "application/xml"})

@pytest.mark.asyncio
async def test_submit_bulk_move_basic_false_bool():
    """Test sendBulkNotification set to False."""
    client = DummyHTTPClient()
    ds = JiraDataSource(DummyJiraClient(client))
    resp = await ds.submit_bulk_move(sendBulkNotification=False)

# --- Edge Test Cases ---

@pytest.mark.asyncio
async def test_submit_bulk_move_edge_empty_mapping():
    """Test with an empty targetToSourcesMapping dict."""
    client = DummyHTTPClient()
    ds = JiraDataSource(DummyJiraClient(client))
    resp = await ds.submit_bulk_move(targetToSourcesMapping={})

@pytest.mark.asyncio
async def test_submit_bulk_move_edge_large_mapping():
    """Test with a large mapping dict (but <1000 elements)."""
    mapping = {f"target{i}": [f"SRC-{i}"] for i in range(100)}
    client = DummyHTTPClient()
    ds = JiraDataSource(DummyJiraClient(client))
    resp = await ds.submit_bulk_move(targetToSourcesMapping=mapping)

@pytest.mark.asyncio
async def test_submit_bulk_move_edge_custom_headers_types():
    """Test with headers containing non-string keys/values."""
    client = DummyHTTPClient()
    ds = JiraDataSource(DummyJiraClient(client))
    resp = await ds.submit_bulk_move(headers={1: True, "X-Int": 123})

@pytest.mark.asyncio
async def test_submit_bulk_move_edge_client_not_initialized():
    """Test that ValueError is raised if HTTP client is None."""
    class BrokenJiraClient:
        def get_client(self):
            return None
    with pytest.raises(ValueError, match="HTTP client is not initialized"):
        JiraDataSource(BrokenJiraClient())

@pytest.mark.asyncio
async def test_submit_bulk_move_edge_client_missing_base_url():
    """Test that ValueError is raised if client lacks get_base_url()."""
    class BrokenHTTPClient:
        pass
    class BrokenJiraClient:
        def get_client(self):
            return BrokenHTTPClient()
    with pytest.raises(ValueError, match="get_base_url"):
        JiraDataSource(BrokenJiraClient())

@pytest.mark.asyncio
async def test_submit_bulk_move_edge_execute_raises():
    """Test that exceptions from .execute() are propagated."""
    client = DummyHTTPClient(fail_execute=True)
    ds = JiraDataSource(DummyJiraClient(client))
    with pytest.raises(RuntimeError, match="Simulated HTTP client failure"):
        await ds.submit_bulk_move()

@pytest.mark.asyncio
async def test_submit_bulk_move_edge_concurrent_execution():
    """Test concurrent execution of submit_bulk_move."""
    client = DummyHTTPClient()
    ds = JiraDataSource(DummyJiraClient(client))
    # Launch several concurrent calls
    tasks = [
        ds.submit_bulk_move(sendBulkNotification=(i % 2 == 0), targetToSourcesMapping={"t": [f"SRC-{i}"]})
        for i in range(10)
    ]
    results = await asyncio.gather(*tasks)
    # Each response should have the correct body
    for i, r in enumerate(results):
        pass

# --- Large Scale Test Cases ---

@pytest.mark.asyncio
async def test_submit_bulk_move_large_scale_many_concurrent():
    """Test many concurrent calls (50) with different mappings."""
    client = DummyHTTPClient()
    ds = JiraDataSource(DummyJiraClient(client))
    tasks = [
        ds.submit_bulk_move(
            sendBulkNotification=bool(i % 2),
            targetToSourcesMapping={f"target{i}": [f"SRC-{i}", f"SRC-{i+1}"]},
            headers={"X-Req": f"{i}"}
        )
        for i in range(50)
    ]
    results = await asyncio.gather(*tasks)
    for i, r in enumerate(results):
        pass

@pytest.mark.asyncio
async def test_submit_bulk_move_large_scale_varied_inputs():
    """Test a mix of valid/empty/None arguments in concurrent calls."""
    client = DummyHTTPClient()
    ds = JiraDataSource(DummyJiraClient(client))
    tasks = [
        ds.submit_bulk_move(),  # all defaults
        ds.submit_bulk_move(sendBulkNotification=True),
        ds.submit_bulk_move(targetToSourcesMapping={"t": ["SRC"]}),
        ds.submit_bulk_move(headers={"X-Test": "yes"}),
        ds.submit_bulk_move(sendBulkNotification=False, targetToSourcesMapping={}, headers={}),
    ]
    results = await asyncio.gather(*tasks)

# --- Throughput Test Cases ---

@pytest.mark.asyncio
async def test_submit_bulk_move_throughput_small_load():
    """Throughput: Test 10 concurrent calls with small payloads."""
    client = DummyHTTPClient()
    ds = JiraDataSource(DummyJiraClient(client))
    tasks = [
        ds.submit_bulk_move(targetToSourcesMapping={"t": [f"SRC-{i}"]})
        for i in range(10)
    ]
    results = await asyncio.gather(*tasks)
    for i, r in enumerate(results):
        pass

@pytest.mark.asyncio
async def test_submit_bulk_move_throughput_medium_load():
    """Throughput: Test 50 concurrent calls with medium payloads."""
    client = DummyHTTPClient()
    ds = JiraDataSource(DummyJiraClient(client))
    # Each mapping has 10 items
    tasks = [
        ds.submit_bulk_move(targetToSourcesMapping={f"t{j}": [f"SRC-{i}-{j}"] for j in range(10)})
        for i in range(50)
    ]
    results = await asyncio.gather(*tasks)
    for i, r in enumerate(results):
        expected = {f"t{j}": [f"SRC-{i}-{j}"] for j in range(10)}

@pytest.mark.asyncio
async def test_submit_bulk_move_throughput_high_volume():
    """Throughput: Test 100 concurrent calls with varied payloads."""
    client = DummyHTTPClient()
    ds = JiraDataSource(DummyJiraClient(client))
    tasks = [
        ds.submit_bulk_move(
            sendBulkNotification=(i % 2 == 0),
            targetToSourcesMapping={f"target{i}": [f"SRC-{i}"] * (i % 5 + 1)},
            headers={"X-High": f"v{i}"}
        )
        for i in range(100)
    ]
    results = await asyncio.gather(*tasks)
    for i, r in enumerate(results):
        pass
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
#------------------------------------------------
import asyncio  # used to run async functions
from typing import Any, Dict, Optional

import pytest  # used for our unit tests
from app.sources.external.jira.jira import JiraDataSource

# --- Minimal stubs for HTTPRequest/HTTPResponse and JiraClient ---

class HTTPRequest:
    def __init__(self, method, url, headers, path_params, query_params, body):
        self.method = method
        self.url = url
        self.headers = headers
        self.path_params = path_params
        self.query_params = query_params
        self.body = body

class HTTPResponse:
    def __init__(self, data):
        self.data = data

# --- Minimal stub for JiraRESTClientViaUsernamePassword and JiraClient ---

class JiraRESTClientViaUsernamePassword:
    def __init__(self, base_url: str, username: str, password: str, token_type: str = "Basic") -> None:
        self.base_url = base_url

    def get_base_url(self) -> str:
        return self.base_url

    async def execute(self, request: HTTPRequest):
        # Simulate a response based on input for test determinism
        return HTTPResponse({
            "method": request.method,
            "url": request.url,
            "headers": request.headers,
            "body": request.body,
        })

class JiraClient:
    def __init__(self, client: JiraRESTClientViaUsernamePassword):
        self.client = client

    def get_client(self):
        return self.client
from app.sources.external.jira.jira import JiraDataSource

# ---- TESTS ----

# --- Basic Test Cases ---

@pytest.mark.asyncio
async def test_submit_bulk_move_basic_no_args():
    """Test basic call with no arguments."""
    client = JiraClient(JiraRESTClientViaUsernamePassword("https://jira.example.com", "user", "pass"))
    ds = JiraDataSource(client)
    resp = await ds.submit_bulk_move()

@pytest.mark.asyncio
async def test_submit_bulk_move_basic_with_all_args():
    """Test call with all arguments provided."""
    client = JiraClient(JiraRESTClientViaUsernamePassword("https://jira.example.com", "user", "pass"))
    ds = JiraDataSource(client)
    headers = {"Authorization": "Bearer testtoken"}
    mapping = {"target1": ["sourceA", "sourceB"]}
    resp = await ds.submit_bulk_move(
        sendBulkNotification=True,
        targetToSourcesMapping=mapping,
        headers=headers,
    )

@pytest.mark.asyncio
async def test_submit_bulk_move_basic_async_behavior():
    """Test that the function is awaitable and returns HTTPResponse."""
    client = JiraClient(JiraRESTClientViaUsernamePassword("https://jira.example.com", "user", "pass"))
    ds = JiraDataSource(client)
    codeflash_output = ds.submit_bulk_move(); coro = codeflash_output
    resp = await coro

# --- Edge Test Cases ---

@pytest.mark.asyncio
async def test_submit_bulk_move_edge_none_client_raises():
    """Test that ValueError is raised if HTTP client is not initialized."""
    class BadClient:
        def get_client(self):
            return None
    with pytest.raises(ValueError, match="HTTP client is not initialized"):
        JiraDataSource(BadClient())

@pytest.mark.asyncio
async def test_submit_bulk_move_edge_bad_base_url_raises():
    """Test that ValueError is raised if HTTP client lacks get_base_url."""
    class BadRESTClient:
        pass
    class BadClient:
        def get_client(self):
            return BadRESTClient()
    with pytest.raises(ValueError, match="HTTP client does not have get_base_url method"):
        JiraDataSource(BadClient())

@pytest.mark.asyncio
async def test_submit_bulk_move_edge_custom_headers_override():
    """Test that custom headers are correctly set and override defaults."""
    client = JiraClient(JiraRESTClientViaUsernamePassword("https://jira.example.com", "user", "pass"))
    ds = JiraDataSource(client)
    headers = {"Content-Type": "custom/type", "X-Test": "value"}
    resp = await ds.submit_bulk_move(headers=headers)

@pytest.mark.asyncio
async def test_submit_bulk_move_edge_empty_mapping():
    """Test with empty targetToSourcesMapping dict."""
    client = JiraClient(JiraRESTClientViaUsernamePassword("https://jira.example.com", "user", "pass"))
    ds = JiraDataSource(client)
    resp = await ds.submit_bulk_move(targetToSourcesMapping={})

@pytest.mark.asyncio
async def test_submit_bulk_move_edge_false_bulk_notification():
    """Test with sendBulkNotification=False."""
    client = JiraClient(JiraRESTClientViaUsernamePassword("https://jira.example.com", "user", "pass"))
    ds = JiraDataSource(client)
    resp = await ds.submit_bulk_move(sendBulkNotification=False)

@pytest.mark.asyncio
async def test_submit_bulk_move_edge_concurrent_execution():
    """Test concurrent execution of multiple submit_bulk_move calls."""
    client = JiraClient(JiraRESTClientViaUsernamePassword("https://jira.example.com", "user", "pass"))
    ds = JiraDataSource(client)
    # Launch 5 concurrent requests with different mappings
    mappings = [{"target": [f"source{i}"]} for i in range(5)]
    tasks = [ds.submit_bulk_move(targetToSourcesMapping=m) for m in mappings]
    results = await asyncio.gather(*tasks)
    # Each result should reflect its mapping
    for i, resp in enumerate(results):
        pass

# --- Large Scale Test Cases ---

@pytest.mark.asyncio
async def test_submit_bulk_move_large_scale_many_concurrent():
    """Test large number of concurrent requests (50)."""
    client = JiraClient(JiraRESTClientViaUsernamePassword("https://jira.example.com", "user", "pass"))
    ds = JiraDataSource(client)
    num_requests = 50
    mappings = [{"target": [f"source{i}"]} for i in range(num_requests)]
    tasks = [ds.submit_bulk_move(targetToSourcesMapping=m) for m in mappings]
    results = await asyncio.gather(*tasks)
    for i, resp in enumerate(results):
        pass

@pytest.mark.asyncio
async def test_submit_bulk_move_large_scale_large_payload():
    """Test with a large targetToSourcesMapping dict."""
    client = JiraClient(JiraRESTClientViaUsernamePassword("https://jira.example.com", "user", "pass"))
    ds = JiraDataSource(client)
    # Large mapping with 200 entries
    mapping = {f"target{i}": [f"source{i}"] for i in range(200)}
    resp = await ds.submit_bulk_move(targetToSourcesMapping=mapping)

# --- Throughput Test Cases ---

@pytest.mark.asyncio
async def test_submit_bulk_move_throughput_small_load():
    """Throughput test: small load, 5 requests."""
    client = JiraClient(JiraRESTClientViaUsernamePassword("https://jira.example.com", "user", "pass"))
    ds = JiraDataSource(client)
    tasks = [ds.submit_bulk_move(targetToSourcesMapping={"target": [f"source{i}"]}) for i in range(5)]
    results = await asyncio.gather(*tasks)
    for i, resp in enumerate(results):
        pass

@pytest.mark.asyncio
async def test_submit_bulk_move_throughput_medium_load():
    """Throughput test: medium load, 20 requests."""
    client = JiraClient(JiraRESTClientViaUsernamePassword("https://jira.example.com", "user", "pass"))
    ds = JiraDataSource(client)
    tasks = [ds.submit_bulk_move(targetToSourcesMapping={"target": [f"source{i}"]}) for i in range(20)]
    results = await asyncio.gather(*tasks)
    for i, resp in enumerate(results):
        pass

@pytest.mark.asyncio
async def test_submit_bulk_move_throughput_high_volume():
    """Throughput test: high volume, 100 requests."""
    client = JiraClient(JiraRESTClientViaUsernamePassword("https://jira.example.com", "user", "pass"))
    ds = JiraDataSource(client)
    tasks = [ds.submit_bulk_move(targetToSourcesMapping={"target": [f"source{i}"]}) for i in range(100)]
    results = await asyncio.gather(*tasks)
    for i, resp in enumerate(results):
        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-JiraDataSource.submit_bulk_move-mhoqe0ek and push.

Codeflash Static Badge

The optimization achieves a **9% runtime improvement** (from 1.91ms to 1.75ms) through strategic micro-optimizations that reduce dictionary allocations and attribute lookups:

**Key Optimizations:**

1. **Eliminated unnecessary dict allocations**: Removed creation of empty `_path` and `_query` dictionaries that were only used for `_as_str_dict()` calls. Instead, directly passed empty dict literals `{}` to HTTPRequest constructor, avoiding ~400 nanoseconds per call for dict creation and subsequent `_as_str_dict()` processing.

2. **Reduced client attribute lookups**: Cached `self._client` in a local variable `client` at the start of `submit_bulk_move()`, eliminating repeated attribute access during the `client is None` check and `await client.execute()` call.

3. **Optimized headers dict creation**: Changed `dict(headers or {})` to `dict(headers) if headers else {}`, avoiding the `or {}` evaluation when headers is None and directly creating an empty dict.

4. **Streamlined dict merging in HTTPClient**: Replaced `{**self.headers, **request.headers}` with `self.headers.copy(); merged_headers.update(request.headers)`, which is more efficient for dict merging operations.

**Performance Impact:**
The line profiler shows the most significant gains in `_as_str_dict()` calls, which dropped from 1.67ms total time (1260 hits) to 1.32ms (420 hits), directly reflecting the elimination of unnecessary empty dict processing. The optimizations particularly benefit high-throughput scenarios where `submit_bulk_move()` is called frequently, as evidenced by consistent performance across all test cases including the 100-request concurrent throughput tests.

While throughput remains constant at 105K ops/sec, the 9% runtime reduction means each individual operation completes faster, improving latency and reducing resource consumption in I/O-bound async workflows.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 November 7, 2025 10:47
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: Medium Optimization Quality according to Codeflash labels Nov 7, 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: Medium Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant