dissolve-python 0.3.0

A tool to dissolve deprecated calls in Python codebases
Documentation
#[cfg(test)]
#[cfg(feature = "concurrent-lsp")]
mod concurrent_lsp_tests {
    use crate::concurrent_lsp::ConcurrentTypeIntrospectionContext;
    use crate::types::TypeIntrospectionMethod;
    use std::fs;
    use tempfile::TempDir;

    #[tokio::test]
    async fn test_concurrent_pyright_basic() {
        // Create a simple Python file for testing
        let temp_dir = TempDir::new().unwrap();
        let file_path = temp_dir.path().join("test.py");
        let content = "x: int = 42\ny = x + 1\n";
        fs::write(&file_path, content).unwrap();

        // Create concurrent type introspection context
        let ctx =
            ConcurrentTypeIntrospectionContext::new(TypeIntrospectionMethod::PyrightLsp).await;

        if ctx.is_err() {
            // Skip test if pyright-langserver is not available
            println!("Skipping concurrent LSP test - pyright-langserver not available");
            return;
        }

        let ctx = ctx.unwrap();

        // Query type information
        let result = ctx
            .query_type_concurrent(
                &file_path.to_string_lossy(),
                content,
                1, // Line 1 (x: int = 42)
                0, // Column 0 (the 'x')
            )
            .await;

        match result {
            Ok(Some(type_info)) => {
                println!("Type info: {}", type_info);
                assert!(type_info.contains("int") || type_info.contains("Variable"));
            }
            Ok(None) => {
                println!(
                    "No type information returned - this might be expected for some LSP setups"
                );
            }
            Err(e) => {
                println!("Type query failed: {} - this might be expected if pyright is not properly configured", e);
            }
        }

        // Test shutdown
        ctx.shutdown().await.unwrap();
    }

    #[tokio::test]
    async fn test_concurrent_mypy_basic() {
        // Create a simple Python file for testing
        let temp_dir = TempDir::new().unwrap();
        let file_path = temp_dir.path().join("test.py");
        let content = "x: int = 42\ny = x + 1\n";
        fs::write(&file_path, content).unwrap();

        // Create concurrent type introspection context
        let ctx =
            ConcurrentTypeIntrospectionContext::new(TypeIntrospectionMethod::MypyDaemon).await;

        if ctx.is_err() {
            // Skip test if dmypy is not available
            println!("Skipping concurrent mypy test - dmypy not available");
            return;
        }

        let ctx = ctx.unwrap();

        // Query type information
        let result = ctx
            .query_type_concurrent(
                &file_path.to_string_lossy(),
                content,
                1, // Line 1 (x: int = 42)
                0, // Column 0 (the 'x')
            )
            .await;

        match result {
            Ok(Some(type_info)) => {
                println!("Mypy type info: {}", type_info);
                assert!(type_info.contains("int"));
            }
            Ok(None) => {
                println!("No type information returned from mypy - this might be expected");
            }
            Err(e) => {
                println!(
                    "Mypy query failed: {} - this might be expected if dmypy is not available",
                    e
                );
            }
        }

        // Test shutdown
        ctx.shutdown().await.unwrap();
    }

    #[tokio::test]
    async fn test_concurrent_multiple_requests() {
        // Create a simple Python file for testing
        let temp_dir = TempDir::new().unwrap();
        let file_path = temp_dir.path().join("test.py");
        let content = r#"
x: int = 42
y: str = "hello" 
z: float = 3.14
"#;
        fs::write(&file_path, content).unwrap();

        // Create concurrent type introspection context
        let ctx =
            ConcurrentTypeIntrospectionContext::new(TypeIntrospectionMethod::PyrightLsp).await;

        if ctx.is_err() {
            // Skip test if pyright-langserver is not available
            println!(
                "Skipping concurrent multiple requests test - pyright-langserver not available"
            );
            return;
        }

        let ctx = ctx.unwrap();
        let file_path_str = file_path.to_string_lossy().to_string();

        // Send multiple concurrent requests - this is the key test!
        let futures = vec![
            ctx.query_type_concurrent(&file_path_str, content, 2, 0), // x
            ctx.query_type_concurrent(&file_path_str, content, 3, 0), // y
            ctx.query_type_concurrent(&file_path_str, content, 4, 0), // z
        ];

        // All should complete concurrently
        let results = futures::future::join_all(futures).await;

        for (i, result) in results.into_iter().enumerate() {
            match result {
                Ok(Some(type_info)) => {
                    println!("Concurrent request {} result: {}", i, type_info);
                }
                Ok(None) => {
                    println!("Concurrent request {} returned no type info", i);
                }
                Err(e) => {
                    println!("Concurrent request {} failed: {}", i, e);
                }
            }
        }

        // Test shutdown
        ctx.shutdown().await.unwrap();
    }
}