Skip to content

Commit 41be4e5

Browse files
aleetmorrell
authored andcommitted
feat: add 422 Error and status_code attribute to DataCiteError-s
- add 422 Unprocessable Entity error class, resolves #89 - minor refactoring to use a defaultdict data structure to map status codes to error classes instead of an if/elif conditional chain. - future status codes can be supported by adding a new DataCiteError subtype and an entry to the DataCiteErrorFactory.ERROR_CLASSES dictionary - includes the status code in the Error class so client code can retrieve the status code from the raised Exception, resolves #98 defaults to DataCiteServerError for any unhandled status_code >= 500 and DataCiteRequestError if there is not an exact match
1 parent eb31d24 commit 41be4e5

1 file changed

Lines changed: 59 additions & 17 deletions

File tree

datacite/errors.py

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
# This file is part of DataCite.
44
#
55
# Copyright (C) 2015 CERN.
6+
# Copyright (C) 2024 Arizona State University.
67
#
78
# DataCite is free software; you can redistribute it and/or modify it
89
# under the terms of the Revised BSD License; see LICENSE file for
910
# more details.
1011

12+
from collections import defaultdict
13+
1114
"""Errors for the DataCite API.
1215
1316
MDS error responses will be converted into an exception from this module.
@@ -32,27 +35,21 @@ class DataCiteError(Exception):
3235
* 403 Forbidden
3336
* 404 Not Found
3437
* 410 Gone (deleted)
38+
* 412 Precondition Failed
39+
* 422 Unprocessable Entity
3540
"""
3641

42+
status_code = 400
43+
44+
def __init__(self, *args, status_code=500):
45+
"""Initialize this exception with an http status code error."""
46+
super().__init__(*args)
47+
self.status_code = status_code
48+
3749
@staticmethod
38-
def factory(err_code, *args):
50+
def factory(status_code, *args):
3951
"""Create exceptions through a Factory based on the HTTP error code."""
40-
if err_code == 204:
41-
return DataCiteNoContentError(*args)
42-
elif err_code == 400:
43-
return DataCiteBadRequestError(*args)
44-
elif err_code == 401:
45-
return DataCiteUnauthorizedError(*args)
46-
elif err_code == 403:
47-
return DataCiteForbiddenError(*args)
48-
elif err_code == 404:
49-
return DataCiteNotFoundError(*args)
50-
elif err_code == 410:
51-
return DataCiteGoneError(*args)
52-
elif err_code == 412:
53-
return DataCitePreconditionError(*args)
54-
else:
55-
return DataCiteServerError(*args)
52+
return DataCiteErrorFactory.create(status_code, *args)
5653

5754

5855
class DataCiteServerError(DataCiteError):
@@ -104,3 +101,48 @@ class DataCiteGoneError(DataCiteRequestError):
104101

105102
class DataCitePreconditionError(DataCiteRequestError):
106103
"""Metadata must be uploaded first."""
104+
105+
106+
class DataCiteUnprocessableEntityError(DataCiteRequestError):
107+
"""Invalid metadata format or content."""
108+
109+
110+
class DataCiteErrorFactory:
111+
"""
112+
Factory class to create specific DataCiteError instances based on the HTTP status code
113+
114+
Attributes:
115+
ERROR_CLASSES (defaultdict): A dictionary mapping HTTP status codes to corresponding DataCiteError classes.
116+
"""
117+
118+
ERROR_CLASSES = defaultdict(
119+
lambda status_code: (
120+
DataCiteServerError if status_code >= 500 else DataCiteRequestError
121+
),
122+
{
123+
204: DataCiteNoContentError,
124+
400: DataCiteBadRequestError,
125+
401: DataCiteUnauthorizedError,
126+
403: DataCiteForbiddenError,
127+
404: DataCiteNotFoundError,
128+
410: DataCiteGoneError,
129+
412: DataCitePreconditionError,
130+
422: DataCiteUnprocessableEntityError,
131+
},
132+
)
133+
134+
@staticmethod
135+
def create(status_code, *args):
136+
"""
137+
Create a specific DataCiteError instance based on the provided error code.
138+
139+
Args:
140+
status_code (int): The HTTP status code representing the error.
141+
args: Additional arguments to be passed to the DataCiteError constructor.
142+
143+
Returns:
144+
DataCiteError: An instance of the appropriate DataCiteError subclass.
145+
146+
"""
147+
DataCiteErrorClass = DataCiteErrorFactory.ERROR_CLASSES[status_code]
148+
return DataCiteErrorClass(*args, status_code=status_code)

0 commit comments

Comments
 (0)