Skip to content

Commit f9d720b

Browse files
committed
parses api errors with correct message
1 parent 18b8f97 commit f9d720b

4 files changed

Lines changed: 42 additions & 10 deletions

File tree

openml/_api_calls.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
import requests
44
import arff
55
import warnings
6+
import xmltodict
67

78
from . import config
8-
from .exceptions import OpenMLServerError
9+
from .exceptions import OpenMLServerError, OpenMLServerException
910

1011

1112
def _perform_api_call(call, data=None, file_dictionary=None,
@@ -80,7 +81,7 @@ def _read_url_files(url, data=None, file_dictionary=None, file_elements=None):
8081
# 'gzip,deflate'
8182
response = requests.post(url, data=data, files=file_elements)
8283
if response.status_code != 200:
83-
raise OpenMLServerError(('Status code: %d\n' % response.status_code) + response.text)
84+
raise _parse_server_exception(response)
8485
if 'Content-Encoding' not in response.headers or \
8586
response.headers['Content-Encoding'] != 'gzip':
8687
warnings.warn('Received uncompressed content from OpenML for %s.' % url)
@@ -97,8 +98,23 @@ def _read_url(url, data=None):
9798
response = requests.post(url, data=data)
9899

99100
if response.status_code != 200:
100-
raise OpenMLServerError(('Status code: %d\n' % response.status_code) + response.text)
101+
raise _parse_server_exception(response)
101102
if 'Content-Encoding' not in response.headers or \
102103
response.headers['Content-Encoding'] != 'gzip':
103104
warnings.warn('Received uncompressed content from OpenML for %s.' % url)
104105
return response.text
106+
107+
def _parse_server_exception(response):
108+
# OpenML has a sopisticated error system
109+
# where information about failures is provided. try to parse this
110+
try:
111+
server_exception = xmltodict.parse(response.text)
112+
except:
113+
raise OpenMLServerError(('Status code: %d\n' % response.status_code) + response.text)
114+
115+
code = int(server_exception['oml:error']['oml:code'])
116+
message = server_exception['oml:error']['oml:message']
117+
additional = None
118+
if 'oml:additional_information' in server_exception['oml:error']:
119+
additional = server_exception['oml:error']['oml:additional_information']
120+
return OpenMLServerException(code, message, additional)

openml/exceptions.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,22 @@ class PyOpenMLError(Exception):
22
def __init__(self, message):
33
super(PyOpenMLError, self).__init__(message)
44

5-
5+
# class for when something is really wrong on the server (result did not parse to dict)
66
class OpenMLServerError(PyOpenMLError):
7-
"""Server didn't respond 200."""
7+
"""Server didn't respond 200, contains unparsed error."""
88
def __init__(self, message):
99
message = "OpenML Server error: " + message
1010
super(OpenMLServerError, self).__init__(message)
1111

12+
# class for when the result of the server was not 200 (e.g., listing call w/o results)
13+
class OpenMLServerException(OpenMLServerError):
14+
"""Server didn't respond 200."""
15+
def __init__(self, code, message, additional=None):
16+
self.code = code
17+
self.additional = additional
18+
message = "OpenML Server exception: " + message
19+
super(OpenMLServerException, self).__init__(message)
20+
1221

1322
class OpenMLCacheException(PyOpenMLError):
1423
"""Dataset / task etc not found in cache"""

openml/runs/functions.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from .. import config
1111
from ..flows import sklearn_to_flow, get_flow
1212
from ..setups import setup_exists
13-
from ..exceptions import OpenMLCacheException
13+
from ..exceptions import OpenMLCacheException, OpenMLServerException
1414
from ..util import URLError
1515
from ..tasks.functions import _create_task_from_xml
1616
from .._api_calls import _perform_api_call
@@ -89,13 +89,19 @@ def _run_exists(task_id, setup_id):
8989
# openml setups are in range 1-inf
9090
return False
9191

92-
result = list_runs(task=[task_id], setup=[setup_id])
93-
if len(result) > 0:
94-
return set(result.keys())
95-
else:
92+
try:
93+
result = list_runs(task=[task_id], setup=[setup_id])
94+
if len(result) > 0:
95+
return set(result.keys())
96+
else:
97+
return False
98+
except OpenMLServerException as exception:
99+
# error code 512 implies no results. This means the run does not exist yet
100+
assert(exception.code == 512)
96101
return False
97102

98103

104+
99105
def _prediction_to_row(rep_no, fold_no, row_id, correct_label, predicted_label, predicted_probabilities, class_labels, model_classes_mapping):
100106
"""Complicated util function that turns probability estimates of a classifier for a given instance into the right arff format to upload to openml.
101107

openml/testing.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def setUp(self):
4545
self.production_server = openml.config.server
4646
self.test_server = "https://test.openml.org/api/v1/xml"
4747
openml.config.server = self.test_server
48+
openml.config.avoid_duplicate_runs = False
4849

4950
openml.config.set_cache_directory(self.workdir)
5051

0 commit comments

Comments
 (0)