Skip to content

Commit f32e6cc

Browse files
northwestwitchChiara Rasidnil
authored
Error message when requests to Ensembl (liftover) fail (#5322)
* Warning message when requests to Ensembl (liftover) fail * Some fixes * Update CHANGELOG.md Co-authored-by: Daniel Nilsson <[email protected]> * Remove debug message * Displayed as error anyway, which is fine * Fix changelog * Update tests/utils/test_ensembl_rest_clients.py Co-authored-by: Daniel Nilsson <[email protected]> * Update tests/utils/test_ensembl_rest_clients.py Co-authored-by: Daniel Nilsson <[email protected]> * Remove as err in the client code * Add referece to the PRs on changelog items --------- Co-authored-by: Chiara Rasi <[email protected]> Co-authored-by: Daniel Nilsson <[email protected]>
1 parent 28914aa commit f32e6cc

File tree

3 files changed

+63
-57
lines changed

3 files changed

+63
-57
lines changed

CHANGELOG.md

+13-13
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ About changelog [here](https://keepachangelog.com/en/1.0.0/)
66

77
## [unreleased]
88
### Added
9-
- De novo assembly alignment file load and display
10-
- Paraphase bam-let alignment file load and display
11-
- Parsing and showing ClinVar somatic oncogenicity anontations, when available
12-
### Changed
13-
- Allow ACMG criteria strength modification to Very strong/Stand-alone
14-
- Mocked the Ensembl liftover service in igv tracks tests
15-
### Fixed
16-
- Re-enable display of case and individual specific tracks (pre-computed coverage, UPD, zygosity)
17-
- Disable 2-color mode in IGV.js by default, since it obscures variant proportion of reads. Can be manually enabled.
18-
- Institute settings reset
19-
- Updated color scheme for variant assessment badges that were hard to see in light mode, notably Risk Factor
20-
- Avoid page timeout by skipping HGVS validations in ClinVar multistep submission for non-MANE transcripts from variants in build 38
21-
9+
- De novo assembly alignment file load and display (#5284)
10+
- Paraphase bam-let alignment file load and display (#5284)
11+
- Parsing and showing ClinVar somatic oncogenicity anontations, when available (#5304)
12+
### Changed
13+
- Allow ACMG criteria strength modification to Very strong/Stand-alone (#5297)
14+
- Mocked the Ensembl liftover service in igv tracks tests (#5319)
15+
### Fixed
16+
- Re-enable display of case and individual specific tracks (pre-computed coverage, UPD, zygosity) (#5300)
17+
- Disable 2-color mode in IGV.js by default, since it obscures variant proportion of reads. Can be manually enabled (#5311)
18+
- Institute settings reset (#5309)
19+
- Updated color scheme for variant assessment badges that were hard to see in light mode, notably Risk Factor (#5318)
20+
- Avoid page timeout by skipping HGVS validations in ClinVar multistep submission for non-MANE transcripts from variants in build 38 (#5302)
21+
- Sashimi view page displaying an error message when Ensembl REST API (LiftOver) is not available (#5322)
2222

2323
## [4.98]
2424
### Added

scout/utils/ensembl_rest_clients.py

+17-12
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
"""Code for talking to ensembl rest API"""
22

33
import logging
4+
from typing import Optional
45
from urllib.parse import urlencode
56

67
import requests
8+
from flask import flash
79

810
LOG = logging.getLogger(__name__)
911

@@ -34,7 +36,7 @@ def build_url(self, endpoint, params=None):
3436
return "".join([self.server, endpoint])
3537

3638
@staticmethod
37-
def send_request(url):
39+
def send_request(url) -> Optional[dict]:
3840
"""Sends the actual request to the server and returns the response
3941
4042
Accepts:
@@ -43,19 +45,22 @@ def send_request(url):
4345
Returns:
4446
data(dict): dictionary from json response
4547
"""
46-
data = {}
48+
error = None
49+
data = None
4750
try:
4851
response = requests.get(url, headers=HEADERS)
49-
if response.status_code == 404:
50-
LOG.info("Request failed for url %s\n", url)
51-
response.raise_for_status()
52-
data = response.json()
53-
except requests.exceptions.MissingSchema as err:
54-
LOG.info("Request failed for url %s: Error: %s\n", url, err)
55-
data = err
56-
except requests.exceptions.HTTPError as err:
57-
LOG.info("Request failed for url %s: Error: %s\n", url, err)
58-
data = err
52+
if response.status_code not in [404, 500]:
53+
54+
data = response.json()
55+
else:
56+
error = f"Ensembl request failed with code:{response.status_code} for url {url}"
57+
except requests.exceptions.MissingSchema:
58+
error = f"Ensembl request failed with MissingSchema error for url {url}"
59+
except requests.exceptions.HTTPError:
60+
error = f"Ensembl request failed with HTTPError error for url {url}"
61+
62+
if error:
63+
flash(error)
5964
return data
6065

6166
def liftover(self, build, chrom, start, end=None):
+33-32
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
"""Tests for ensembl rest api"""
22

33
import responses
4-
from requests.exceptions import HTTPError, MissingSchema
4+
from requests.exceptions import MissingSchema
5+
from requests.models import Response
56

6-
REST_CLIENT_37_URL = "https://grch37.rest.ensembl.org"
7+
from scout.utils.ensembl_rest_clients import RESTAPI_37
78

89

910
@responses.activate
1011
def test_liftover(ensembl_rest_client_37, ensembl_liftover_response):
1112
"""Test send request for coordinates liftover"""
1213
# GIVEN a patched response from Ensembl
13-
url = f"{REST_CLIENT_37_URL}/map/human/GRCh37/X:1000000..1000100/GRCh38?content-type=application/json"
14+
url = f"{RESTAPI_37}/map/human/GRCh37/X:1000000..1000100/GRCh38?content-type=application/json"
1415
responses.add(
1516
responses.GET,
1617
url,
@@ -26,7 +27,7 @@ def test_liftover(ensembl_rest_client_37, ensembl_liftover_response):
2627
@responses.activate
2728
def test_send_gene_request(ensembl_gene_response, ensembl_rest_client_37):
2829
"""Test send request with correct params and endpoint"""
29-
url = f"{REST_CLIENT_37_URL}/overlap/id/ENSG00000103591?feature=gene"
30+
url = f"{RESTAPI_37}/overlap/id/ENSG00000103591?feature=gene"
3031
client = ensembl_rest_client_37
3132
responses.add(
3233
responses.GET,
@@ -43,37 +44,37 @@ def test_send_gene_request(ensembl_gene_response, ensembl_rest_client_37):
4344
assert data[0]["end"]
4445

4546

46-
@responses.activate
47-
def test_send_request_fakey_url(ensembl_rest_client_37):
48-
"""Successful requests are tested by other tests in this file.
49-
This test will trigger errors instead.
50-
"""
47+
def test_send_request_fakey_url(mock_app, ensembl_rest_client_37, mocker):
48+
"""Test the Ensembl REST client with an URL that is raising missing schema error."""
49+
5150
# GIVEN a completely invalid URL
5251
url = "fakeyurl"
53-
# GIVEN a client
52+
# GIVEN a patched Ensembl client
5453
client = ensembl_rest_client_37
55-
responses.add(
56-
responses.GET,
57-
url,
58-
body=MissingSchema(),
59-
status=404,
60-
)
61-
data = client.send_request(url)
62-
assert isinstance(data, MissingSchema)
54+
mocker.patch("requests.get", side_effect=MissingSchema("Invalid URL"))
6355

56+
# THEN the client should return no content
57+
with mock_app.test_request_context():
58+
data = client.send_request(url)
59+
assert data is None
6460

65-
@responses.activate
66-
def test_send_request_wrong_url(ensembl_rest_client_37):
67-
"""Successful requests are tested by other tests in this file.
68-
This test will trigger errors instead.
69-
"""
70-
url = f"{REST_CLIENT_37_URL}/fakeyurl"
61+
62+
def test_send_request_unavaailable(mock_app, ensembl_rest_client_37, mocker):
63+
"""Test the Ensembl REST client with an URL that is not available (500 error)."""
64+
65+
url = f"{RESTAPI_37}/fakeyurl"
66+
# GIVEN a patched Ensembl client
7167
client = ensembl_rest_client_37
72-
responses.add(
73-
responses.GET,
74-
url,
75-
body=HTTPError(),
76-
status=404,
77-
)
78-
data = client.send_request(url)
79-
assert isinstance(data, HTTPError)
68+
69+
# GIVEN a mocked 550 response from Ensembl
70+
mock_response = Response()
71+
mock_response.status_code = 500 # Simulate 500 Internal Server Error
72+
mock_response._content = b"Internal Server Error" # Optional: Set error content
73+
74+
# Mock `requests.get` to return the mock response
75+
mocker.patch("scout.utils.ensembl_rest_clients.requests.get", return_value=mock_response)
76+
77+
with mock_app.test_request_context():
78+
# THEN the client should return no content
79+
data = client.send_request(url)
80+
assert data is None

0 commit comments

Comments
 (0)