⚡️ Speed up function _get_request_param by 21%
#138
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
📄 21% (0.21x) speedup for
_get_request_paraminmlflow/server/auth/__init__.py⏱️ Runtime :
10.1 milliseconds→8.28 milliseconds(best of11runs)📝 Explanation and details
The optimization achieves a 21% speedup by eliminating unnecessary dictionary operations when
request.view_argsis empty, which happens frequently in practice.Key optimization: The original code unconditionally performs
args | (request.view_args or {}), creating an empty dictionary{}and executing a dictionary merge operation even whenview_argsisNone. The optimized version adds a conditional check to only perform the merge whenview_argsis truthy.Performance impact by the numbers:
if view_args:) adds minimal overhead at just 33K nanosecondsWhy this works: Dictionary merging with the
|operator involves creating new dictionary objects and copying key-value pairs. Whenview_argsisNone(common case), the original code still creates an empty dict and performs the merge. The optimization completely skips this work in the common case where no view arguments exist.Test case benefits: The optimization shows strongest gains in scenarios with no view args (49.4% faster in
test_view_args_is_none) and moderate gains in typical usage patterns (17-49% faster across basic test cases). The performance improvement is consistent across different HTTP methods (GET, POST, DELETE) and scales well with parameter count.This optimization is particularly valuable since parameter extraction likely occurs on every HTTP request in MLflow's authentication layer, making even small per-request savings meaningful at scale.
✅ Correctness verification report:
🌀 Generated Regression Tests and Runtime
import pytest
from flask import Flask, request
from mlflow.server.auth.init import _get_request_param
from werkzeug.exceptions import BadRequest
Simulate the relevant MLflow exception and error codes for testing
class MlflowException(Exception):
def init(self, message, error_code):
super().init(message)
self.error_code = error_code
BAD_REQUEST = 400
INVALID_PARAMETER_VALUE = 422
unit tests
Create a Flask app for testing
app = Flask(name)
----------------------------- BASIC TEST CASES -----------------------------
def test_run_id_special_case():
# Test that missing 'run_id' falls back to 'run_uuid'
with app.test_request_context('/?run_uuid=uuidval', method='GET'):
codeflash_output = _get_request_param('run_id') # 30.4μs -> 20.3μs (49.6% faster)
def test_param_value_is_empty_string():
# Test that param value can be empty string and is returned
with app.test_request_context('/?foo=', method='GET'):
codeflash_output = _get_request_param('foo') # 24.1μs -> 17.1μs (41.1% faster)
def test_view_args_is_none():
# Test that view_args being None does not break merging
with app.test_request_context('/?foo=bar', method='GET'):
request.view_args = None
codeflash_output = _get_request_param('foo') # 21.5μs -> 14.4μs (49.4% faster)
def test_args_and_view_args_merge_with_overlap():
# Test that merging works with overlapping keys, view_args wins
with app.test_request_context('/?foo=argval&bar=argbar', method='GET'):
request.view_args = {'foo': 'viewval', 'baz': 'viewbaz'}
# 'foo' in both, view_args wins
codeflash_output = _get_request_param('foo') # 25.6μs -> 26.5μs (3.40% slower)
# 'bar' only in args
codeflash_output = _get_request_param('bar')
# 'baz' only in view_args
codeflash_output = _get_request_param('baz') # 8.54μs -> 7.83μs (9.00% faster)
def test_args_and_view_args_merge_no_overlap():
# Test that merging works with no overlapping keys
with app.test_request_context('/?foo=argval', method='GET'):
request.view_args = {'bar': 'viewbar'}
codeflash_output = _get_request_param('foo') # 23.1μs -> 22.8μs (1.19% faster)
codeflash_output = _get_request_param('bar')
def test_param_is_int_value():
# Test that integer values are returned as is
with app.test_request_context('/', method='POST', json={'foo': 123}):
codeflash_output = _get_request_param('foo') # 43.6μs -> 43.4μs (0.574% faster)
def test_param_is_none_value():
# Test that None value is returned as is
with app.test_request_context('/', method='POST', json={'foo': None}):
codeflash_output = _get_request_param('foo') # 42.7μs -> 42.2μs (1.11% faster)
-------------------------- LARGE SCALE TEST CASES --------------------------
def test_large_number_of_params_in_args():
# Test with many parameters in GET args
params = {f'key{i}': f'value{i}' for i in range(1000)}
query = '&'.join(f'{k}={v}' for k, v in params.items())
with app.test_request_context(f'/?{query}', method='GET'):
for i in range(0, 1000, 100): # Test every 100th param
codeflash_output = _get_request_param(f'key{i}')
def test_large_number_of_params_in_json():
# Test with many parameters in POST JSON
params = {f'key{i}': f'value{i}' for i in range(1000)}
with app.test_request_context('/', method='POST', json=params):
for i in range(0, 1000, 100): # Test every 100th param
codeflash_output = _get_request_param(f'key{i}')
def test_large_number_of_params_in_view_args():
# Test with many parameters in view_args
params = {f'key{i}': f'value{i}' for i in range(1000)}
with app.test_request_context('/'):
request.view_args = params
for i in range(0, 1000, 100): # Test every 100th param
codeflash_output = _get_request_param(f'key{i}')
def test_large_merge_args_and_view_args():
# Test merging large args and view_args, view_args should override
args = {f'key{i}': f'arg{i}' for i in range(500)}
view_args = {f'key{i}': f'view{i}' for i in range(500)}
query = '&'.join(f'{k}={v}' for k, v in args.items())
with app.test_request_context(f'/?{query}', method='GET'):
request.view_args = view_args
for i in range(0, 500, 50):
codeflash_output = _get_request_param(f'key{i}')
#------------------------------------------------
from types import SimpleNamespace
imports
import pytest
from mlflow.server.auth.init import _get_request_param
--- Begin function to test ---
class MlflowException(Exception):
def init(self, message, error_code):
super().init(message)
self.error_code = error_code
BAD_REQUEST = 400
INVALID_PARAMETER_VALUE = 100
Simulate Flask's request object for testing
class FakeRequest:
def init(self, method, args=None, json=None, is_json=False, view_args=None):
self.method = method
self.args = args or {}
self.json = json
self.is_json = is_json
self.view_args = view_args
Patchable global 'request' for tests
request = None
--- 1. Basic Test Cases ---
To edit these changes
git checkout codeflash/optimize-_get_request_param-mhunmtbxand push.