Skip to content
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

⚡️ Speed up method LocalStorageService.build_full_path by 37% in src/backend/base/langflow/services/storage/local.py #103

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

codeflash-ai[bot]
Copy link

@codeflash-ai codeflash-ai bot commented Dec 12, 2024

📄 LocalStorageService.build_full_path in src/backend/base/langflow/services/storage/local.py

✨ Performance Summary:

  • Speed Increase: 📈 37% (0.37x faster)
  • Runtime Reduction: ⏱️ From 32.1 milliseconds down to 23.4 milliseconds (best of 40 runs)

📝 Explanation and details

Here's a faster version of the given code. I have optimized the LocalStorageService class initialization to avoid unnecessary path computations and use more efficient methods where applicable.

Explanation

  1. Path Initialization: Using Path from anyio is kept, but concatenation in build_full_path is done using joinpath, which is more efficient and cleaner.
  2. Posix Path: Using as_posix() instead of str() for a more explicit conversion to string representation.

Note: Given the simplicity of the original code, there aren't many changes required to optimize runtime significantly, since the operations performed (i.e., path concatenation) are already quite efficient. This version is focused on making the path operations internally consistent and clear.


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 2043 Passed See below
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Coverage 100.0%

🌀 Generated Regression Tests Details

Click to view details
from unittest.mock import MagicMock

import anyio
# imports
import pytest  # used for our unit tests
from langflow.services.storage.local import LocalStorageService
# function to test
from langflow.services.storage.service import StorageService


# Mock services
class MockSettingsService:
    def __init__(self, config_dir):
        self.settings = MagicMock()
        self.settings.config_dir = config_dir

class MockSessionService:
    pass

# unit tests
@pytest.fixture
def local_storage_service():
    settings_service = MockSettingsService("/mock/config_dir")
    session_service = MockSessionService()
    return LocalStorageService(session_service, settings_service)

def test_basic_functionality(local_storage_service):
    # Test with normal inputs
    codeflash_output = local_storage_service.build_full_path("flow123", "file.txt")
    codeflash_output = local_storage_service.build_full_path("test_flow", "data.json")

def test_edge_cases(local_storage_service):
    # Test with empty strings
    codeflash_output = local_storage_service.build_full_path("", "file.txt")
    codeflash_output = local_storage_service.build_full_path("flow123", "")
    
    # Test with special characters
    codeflash_output = local_storage_service.build_full_path("flow@123", "file!.txt")
    codeflash_output = local_storage_service.build_full_path("flow#123", "file$.json")
    
    # Test with long strings
    long_string = "a" * 255
    codeflash_output = local_storage_service.build_full_path(long_string, "file.txt")
    codeflash_output = local_storage_service.build_full_path("flow123", long_string)

def test_path_traversal(local_storage_service):
    # Test with relative paths
    codeflash_output = local_storage_service.build_full_path("..", "file.txt")
    codeflash_output = local_storage_service.build_full_path("flow123", "../file.txt")
    
    # Test with absolute paths
    codeflash_output = local_storage_service.build_full_path("/absolute/path", "file.txt")
    codeflash_output = local_storage_service.build_full_path("flow123", "/absolute/file.txt")

def test_unicode_characters(local_storage_service):
    # Test with Unicode characters
    codeflash_output = local_storage_service.build_full_path("flow_测试", "file_测试.txt")
    codeflash_output = local_storage_service.build_full_path("flow_ñ", "file_ñ.json")

def test_performance_and_scalability(local_storage_service):
    # Test with large number of calls
    for _ in range(1000):
        codeflash_output = local_storage_service.build_full_path("flow123", "file.txt")
    
    # Test with large data samples
    large_file_name = "a" * 10000
    codeflash_output = local_storage_service.build_full_path("flow123", large_file_name)

def test_invalid_inputs(local_storage_service):
    # Test with None values
    with pytest.raises(TypeError):
        local_storage_service.build_full_path(None, "file.txt")
    with pytest.raises(TypeError):
        local_storage_service.build_full_path("flow123", None)
    
    # Test with non-string types
    with pytest.raises(TypeError):
        local_storage_service.build_full_path(123, "file.txt")
    with pytest.raises(TypeError):
        local_storage_service.build_full_path("flow123", 456)

def test_directory_and_file_name_conflicts(local_storage_service):
    # Test with same name for flow and file
    codeflash_output = local_storage_service.build_full_path("file", "file")
    codeflash_output = local_storage_service.build_full_path("dir", "dir")

def test_case_sensitivity(local_storage_service):
    # Test with mixed case sensitivity
    codeflash_output = local_storage_service.build_full_path("Flow123", "File.txt")
    codeflash_output = local_storage_service.build_full_path("flow123", "file.TXT")

def test_special_path_characters(local_storage_service):
    # Test with dot and double dot
    codeflash_output = local_storage_service.build_full_path(".", "file.txt")
    codeflash_output = local_storage_service.build_full_path("flow123", "..")

def test_environment_specific_paths(local_storage_service):
    # Test with Windows paths
    codeflash_output = local_storage_service.build_full_path("C:\\flow123", "file.txt")
    
    # Test with Unix paths
    codeflash_output = local_storage_service.build_full_path("/usr/local/flow123", "file.txt")
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
import anyio
# imports
import pytest  # used for our unit tests
from langflow.services.storage.local import LocalStorageService
from langflow.services.storage.service import StorageService


# Mock settings and session services for testing
class MockSettingsService:
    class Settings:
        config_dir = "/mock/config/dir"
    settings = Settings()

class MockSessionService:
    pass

@pytest.fixture
def local_storage_service():
    return LocalStorageService(MockSessionService(), MockSettingsService())

# unit tests

def test_basic_valid_inputs(local_storage_service):
    # Test with normal alphanumeric flow_id and file_name
    codeflash_output = local_storage_service.build_full_path("flow123", "file.txt")
    # Test with underscores and hyphens
    codeflash_output = local_storage_service.build_full_path("flow_123", "file-name.txt")

def test_edge_cases_with_special_characters(local_storage_service):
    # Test with spaces
    codeflash_output = local_storage_service.build_full_path("flow 123", "file name.txt")
    # Test with special characters
    codeflash_output = local_storage_service.build_full_path("flow@123", "file#name.txt")

def test_empty_strings(local_storage_service):
    # Test with empty flow_id
    codeflash_output = local_storage_service.build_full_path("", "file.txt")
    # Test with empty file_name
    codeflash_output = local_storage_service.build_full_path("flow123", "")
    # Test with both empty
    codeflash_output = local_storage_service.build_full_path("", "")

def test_long_strings(local_storage_service):
    # Test with very long flow_id
    long_flow_id = "f" * 255
    codeflash_output = local_storage_service.build_full_path(long_flow_id, "file.txt")
    # Test with very long file_name
    long_file_name = "f" * 255 + ".txt"
    codeflash_output = local_storage_service.build_full_path("flow123", long_file_name)

def test_path_traversal_characters(local_storage_service):
    # Test with path traversal in flow_id
    codeflash_output = local_storage_service.build_full_path("../flow123", "file.txt")
    # Test with path traversal in file_name
    codeflash_output = local_storage_service.build_full_path("flow123", "../file.txt")


def test_unicode_characters(local_storage_service):
    # Test with Unicode characters in flow_id
    codeflash_output = local_storage_service.build_full_path("flöw123", "file.txt")
    # Test with Unicode characters in file_name
    codeflash_output = local_storage_service.build_full_path("flow123", "fïle.txt")

def test_combining_multiple_edge_cases(local_storage_service):
    # Test with long flow_id and special characters
    long_special_flow_id = "f" * 100 + "@123"
    codeflash_output = local_storage_service.build_full_path(long_special_flow_id, "file.txt")
    # Test with empty flow_id and special characters in file_name
    codeflash_output = local_storage_service.build_full_path("", "@file.txt")

def test_large_scale_cases(local_storage_service):
    # Test with large number of unique flow_id and file_name pairs
    for i in range(1000):
        flow_id = f"flow{i}"
        file_name = f"file{i}.txt"
        codeflash_output = local_storage_service.build_full_path(flow_id, file_name)
    # Test with extremely deep directory structure
    deep_flow_id = "a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z"
    codeflash_output = local_storage_service.build_full_path(deep_flow_id, "file.txt")
# 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

Here's a faster version of the given code. I have optimized the `LocalStorageService` class initialization to avoid unnecessary path computations and use more efficient methods where applicable.



### Explanation
1. **Path Initialization:** Using `Path` from `anyio` is kept, but concatenation in `build_full_path` is done using `joinpath`, which is more efficient and cleaner.
2. **Posix Path:** Using `as_posix()` instead of `str()` for a more explicit conversion to string representation.

Note: Given the simplicity of the original code, there aren't many changes required to optimize runtime significantly, since the operations performed (i.e., path concatenation) are already quite efficient. This version is focused on making the path operations internally consistent and clear.
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label Dec 12, 2024
@codeflash-ai codeflash-ai bot requested a review from misrasaurabh1 December 12, 2024 20:44
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
Projects
None yet
Development

Successfully merging this pull request may close these issues.

0 participants