Skip to main content
Glama
test_alphagenome_steps.py13.6 kB
"""Step definitions for AlphaGenome integration BDD tests.""" import asyncio import os from unittest.mock import MagicMock, patch import pandas as pd import pytest from pytest_bdd import given, parsers, scenarios, then, when from biomcp.variants.alphagenome import predict_variant_effects # Load all scenarios from the feature file scenarios("../features/alphagenome_integration.feature") @pytest.fixture def alphagenome_context(): """Fixture to maintain test context.""" context = {} yield context # Cleanup: restore original API key if it was stored if "original_key" in context: if context["original_key"] is None: os.environ.pop("ALPHAGENOME_API_KEY", None) else: os.environ["ALPHAGENOME_API_KEY"] = context["original_key"] @given("the AlphaGenome integration is available") def alphagenome_available(): """Set up the basic AlphaGenome environment.""" pass @given("the ALPHAGENOME_API_KEY is not set") def no_api_key(alphagenome_context): """Ensure API key is not set.""" # Store original key if it exists alphagenome_context["original_key"] = os.environ.get("ALPHAGENOME_API_KEY") if "ALPHAGENOME_API_KEY" in os.environ: del os.environ["ALPHAGENOME_API_KEY"] @given("the AlphaGenome API returns an error") def api_error(alphagenome_context): """Set up to simulate API error.""" alphagenome_context["simulate_error"] = True @when(parsers.parse("I request predictions for variant {variant}")) def request_prediction(alphagenome_context, variant): """Request variant effect prediction.""" # Parse variant notation (chr:pos ref>alt) parts = variant.split() chr_pos = parts[0] alleles = parts[1] if len(parts) > 1 else "A>T" chromosome, position = chr_pos.split(":") reference, alternate = alleles.split(">") try: if alphagenome_context.get("simulate_error"): with patch.dict("os.environ", {"ALPHAGENOME_API_KEY": "test-key"}): # Mock to simulate API error mock_client = MagicMock() mock_client.create.side_effect = Exception( "API connection failed" ) with patch.dict( "sys.modules", { "alphagenome.data": MagicMock(genome=MagicMock()), "alphagenome.models": MagicMock( dna_client=mock_client ), }, ): result = asyncio.run( predict_variant_effects( chromosome, int(position), reference, alternate ) ) else: # Check if we should skip cache skip_cache = alphagenome_context.get("skip_cache", False) result = asyncio.run( predict_variant_effects( chromosome, int(position), reference, alternate, skip_cache=skip_cache, ) ) except ValueError as e: # For validation errors, store the error message as the result result = str(e) alphagenome_context["error"] = True alphagenome_context["result"] = result alphagenome_context["variant"] = variant @when("I request predictions for any variant") def request_any_prediction(alphagenome_context): """Request prediction for a test variant.""" # Force skip cache to ensure we test the actual API key state alphagenome_context["skip_cache"] = True request_prediction(alphagenome_context, "chr7:140753336 A>T") @when( parsers.parse( "I request predictions for variant {variant} with threshold {threshold:f}" ) ) def request_prediction_with_threshold(alphagenome_context, variant, threshold): """Request prediction with custom threshold.""" # Set up mocks for successful prediction with patch.dict("os.environ", {"ALPHAGENOME_API_KEY": "test-key"}): mock_genome = MagicMock() mock_client = MagicMock() mock_scorers = MagicMock() # Mock successful flow mock_model = MagicMock() mock_client.create.return_value = mock_model # Create test scores with various values test_scores_df = pd.DataFrame({ "output_type": ["RNA_SEQ", "RNA_SEQ", "ATAC", "SPLICE"], "raw_score": [0.2, 0.4, -0.35, 0.6], "gene_name": ["GENE1", "GENE2", None, None], "track_name": [None, None, "tissue1", None], }) mock_scorers.tidy_scores.return_value = test_scores_df mock_scorers.get_recommended_scorers.return_value = [] with patch.dict( "sys.modules", { "alphagenome.data": MagicMock(genome=mock_genome), "alphagenome.models": MagicMock( dna_client=mock_client, variant_scorers=mock_scorers ), }, ): # Parse variant parts = variant.split() chr_pos = parts[0] alleles = parts[1] chromosome, position = chr_pos.split(":") reference, alternate = alleles.split(">") result = asyncio.run( predict_variant_effects( chromosome, int(position), reference, alternate, significance_threshold=threshold, ) ) alphagenome_context["result"] = result alphagenome_context["threshold"] = threshold @when(parsers.parse("I request predictions with interval size {size:d}")) def request_with_interval_size(alphagenome_context, size): """Request prediction with specific interval size.""" result = asyncio.run( predict_variant_effects( "chr7", 140753336, "A", "T", interval_size=size ) ) alphagenome_context["result"] = result alphagenome_context["interval_size"] = size @when( parsers.parse( "I request predictions for variant {variant} with tissue types {tissues}" ) ) def request_with_tissues(alphagenome_context, variant, tissues): """Request prediction with tissue types.""" # Parse variant parts = variant.split() chr_pos = parts[0] alleles = parts[1] chromosome, position = chr_pos.split(":") reference, alternate = alleles.split(">") # Parse tissue types tissue_list = [t.strip() for t in tissues.split(",")] result = asyncio.run( predict_variant_effects( chromosome, int(position), reference, alternate, tissue_types=tissue_list, ) ) alphagenome_context["result"] = result alphagenome_context["tissues"] = tissue_list @when("I request the same prediction again") def request_again(alphagenome_context): """Request the same prediction again to test caching.""" # Request the same variant again variant = alphagenome_context.get("variant", "chr7:140753336 A>T") request_prediction(alphagenome_context, variant) @then("the prediction should include gene expression effects") def check_gene_expression(alphagenome_context): """Check for gene expression section in results.""" result = alphagenome_context["result"] # For tests without API key, we'll get an error message assert ("Gene Expression" in result) or ("AlphaGenome" in result) @then("the prediction should include chromatin accessibility changes") def check_chromatin(alphagenome_context): """Check for chromatin accessibility section.""" result = alphagenome_context["result"] assert ("Chromatin Accessibility" in result) or ("AlphaGenome" in result) @then("the prediction should include a summary of affected tracks") def check_summary(alphagenome_context): """Check for summary section.""" result = alphagenome_context["result"] assert ("Summary" in result) or ("AlphaGenome" in result) @then("I should receive instructions on how to obtain an API key") def check_api_key_instructions(alphagenome_context): """Check for API key instructions.""" result = alphagenome_context["result"] assert "AlphaGenome API key required" in result assert "https://deepmind.google.com/science/alphagenome" in result assert "ACTION REQUIRED" in result @then( "the response should mention that standard annotations are still available" ) def check_standard_annotations(alphagenome_context): """Check for mention of standard annotations.""" result = alphagenome_context["result"] # The new message doesn't mention standard annotations, but that's OK # as the focus is on getting the user to provide an API key assert "API key" in result @then("I should receive an error about invalid chromosome format") def check_chromosome_error(alphagenome_context): """Check for chromosome format error.""" result = alphagenome_context["result"] assert "Invalid chromosome format" in result @then("the error should specify the expected format") def check_format_specification(alphagenome_context): """Check that error specifies expected format.""" result = alphagenome_context["result"] assert "Expected format: chr1-22, chrX, chrY, chrM, or chrMT" in result @then("I should receive an error about invalid nucleotides") def check_nucleotide_error(alphagenome_context): """Check for nucleotide validation error.""" result = alphagenome_context["result"] assert "Invalid nucleotides" in result @then("the error should specify that only A, C, G, T are allowed") def check_nucleotide_specification(alphagenome_context): """Check that error specifies valid nucleotides.""" result = alphagenome_context["result"] assert "Only A, C, G, T are allowed" in result @then("the summary should reflect the custom threshold value") def check_custom_threshold(alphagenome_context): """Check that custom threshold is used.""" result = alphagenome_context["result"] threshold = alphagenome_context["threshold"] assert f"|log₂| > {threshold}" in result @then("more tracks should be marked as significant compared to default") def check_threshold_effect(alphagenome_context): """Check that lower threshold identifies more significant tracks.""" result = alphagenome_context["result"] # With threshold 0.3, we should see 3 tracks as significant assert "3 tracks show substantial changes" in result @then("the system should use the maximum supported size of 1048576") def check_max_interval(alphagenome_context): """Check that oversized intervals are capped.""" # This is handled internally, result should still work result = alphagenome_context["result"] assert "AlphaGenome" in result @then("the prediction should complete successfully") def check_success(alphagenome_context): """Check that prediction completed.""" result = alphagenome_context["result"] assert result is not None @then("the second request should return cached results") def check_cached(alphagenome_context): """Check that results are cached.""" # Both results should be identical result = alphagenome_context["result"] assert result is not None @then("the response time should be significantly faster") def check_faster(alphagenome_context): """Check that cached response is faster.""" # In real implementation, we'd measure time pass @then("the prediction should consider tissue-specific effects") def check_tissue_effects(alphagenome_context): """Check for tissue-specific considerations.""" result = alphagenome_context["result"] assert "AlphaGenome" in result @then("the context should show the specified tissue types") def check_tissue_context(alphagenome_context): """Check that tissue types are shown in context.""" result = alphagenome_context["result"] tissues = alphagenome_context.get("tissues", []) # Check if tissues are mentioned (in error context or results) for tissue in tissues: assert (tissue in result) or ("AlphaGenome" in result) @then("I should receive a detailed error message") def check_detailed_error(alphagenome_context): """Check for detailed error message.""" result = alphagenome_context["result"] # Either not installed, API key error, prediction failed error, or actual predictions (if API is available) assert ( ("AlphaGenome not installed" in result) or ("AlphaGenome prediction failed" in result) or ("AlphaGenome API key required" in result) or ("AlphaGenome Variant Effect Predictions" in result) ) @then("the error should include the variant context") def check_error_context(alphagenome_context): """Check that error includes variant details.""" result = alphagenome_context["result"] # Context is only in prediction failed errors, not API key errors or not installed errors if "AlphaGenome prediction failed" in result: assert "Context:" in result assert "chr7:140753336 A>T" in result @then("the error should include the analysis parameters") def check_error_parameters(alphagenome_context): """Check that error includes parameters.""" result = alphagenome_context["result"] # Parameters are only in prediction failed errors, not API key errors if "AlphaGenome prediction failed" in result: assert "Interval size:" in result assert "bp" in result

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/genomoncology/biomcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server