Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Commit a10faf2

Browse files
committed
Moved Cloudant argument messages to _messages.py
- Updated error messages in _messages.py and test cases for consistency - Added CloudantViewException to error.py - Moved view exception messages to _messages.py
1 parent b8594c1 commit a10faf2

File tree

15 files changed

+188
-164
lines changed

15 files changed

+188
-164
lines changed

src/cloudant/_common_util.py

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -174,33 +174,21 @@ def py_to_couch_validate(key, val):
174174
Validates the individual parameter key and value.
175175
"""
176176
if key not in RESULT_ARG_TYPES:
177-
msg = 'Invalid argument {0}'.format(key)
178-
raise CloudantArgumentError(msg)
177+
raise CloudantArgumentError(116, key)
179178
# pylint: disable=unidiomatic-typecheck
180179
# Validate argument values and ensure that a boolean is not passed in
181180
# if an integer is expected
182181
if (not isinstance(val, RESULT_ARG_TYPES[key]) or
183182
(type(val) is bool and int in RESULT_ARG_TYPES[key])):
184-
msg = 'Argument {0} not instance of expected type: {1}'.format(
185-
key,
186-
RESULT_ARG_TYPES[key]
187-
)
188-
raise CloudantArgumentError(msg)
183+
raise CloudantArgumentError(117, key, RESULT_ARG_TYPES[key])
189184
if key == 'keys':
190185
for key_list_val in val:
191186
if (not isinstance(key_list_val, RESULT_ARG_TYPES['key']) or
192187
type(key_list_val) is bool):
193-
msg = 'Key list element not of expected type: {0}'.format(
194-
RESULT_ARG_TYPES['key']
195-
)
196-
raise CloudantArgumentError(msg)
188+
raise CloudantArgumentError(134, RESULT_ARG_TYPES['key'])
197189
if key == 'stale':
198190
if val not in ('ok', 'update_after'):
199-
msg = (
200-
'Invalid value for stale option {0} '
201-
'must be ok or update_after'
202-
).format(val)
203-
raise CloudantArgumentError(msg)
191+
raise CloudantArgumentError(135, val)
204192

205193
def _py_to_couch_translate(key, val):
206194
"""
@@ -216,8 +204,7 @@ def _py_to_couch_translate(key, val):
216204
arg_converter = TYPE_CONVERTERS.get(type(val))
217205
return {key: arg_converter(val)}
218206
except Exception as ex:
219-
msg = 'Error converting argument {0}: {1}'.format(key, ex)
220-
raise CloudantArgumentError(msg)
207+
raise CloudantArgumentError(136, key, ex)
221208

222209
def type_or_none(typerefs, value):
223210
"""

src/cloudant/_messages.py

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,71 @@
1616
Module that contains exception messages for the Cloudant Python client
1717
library.
1818
"""
19+
ARGUMENT_ERROR = {
20+
100: 'A general Cloudant argument error was raised.',
21+
# Client
22+
101: 'Invalid year and/or month supplied. Found: year - {0}, month - {1}',
23+
# Database
24+
102: 'Invalid role(s) provided: {0}. Valid roles are: {1}',
25+
103: 'Invalid index type: {0}. Index type must be '
26+
'either \"json\" or \"text\".',
27+
104: 'A single query/q parameter is required. Found: {0}',
28+
105: 'Invalid argument: {0}',
29+
106: 'Argument {0} is not an instance of expected type: {1}',
30+
# Design document
31+
107: 'View {0} already exists in this design doc.',
32+
108: 'An index with name {0} already exists in this design doc.',
33+
109: 'A list with name {0} already exists in this design doc.',
34+
110: 'A show function with name {0} already exists in this design doc.',
35+
111: 'View {0} does not exist in this design doc.',
36+
112: 'An index with name {0} does not exist in this design doc.',
37+
113: 'A list with name {0} does not exist in this design doc.',
38+
114: 'A show function with name {0} does not exist in this design doc.',
39+
# Feed
40+
115: 'Error converting argument {0}: {1}',
41+
116: 'Invalid argument {0}',
42+
117: 'Argument {0} not instance of expected type: {1}',
43+
118: 'Argument {0} must be > 0. Found: {1}',
44+
119: 'Invalid value ({0}) for feed option. Must be one of {1}',
45+
120: 'Invalid value ({0}) for style option. Must be main_only, '
46+
'or all_docs.',
47+
121: 'Invalid infinite feed option: {0}. Must be set to continuous.',
48+
# Index
49+
122: 'The design document id: {0} is not a string.',
50+
123: 'The index name: {0} is not a string.',
51+
124: '{0} provided as argument(s). A JSON index requires that '
52+
'only a \'fields\' argument is provided.',
53+
125: 'Deleting an index requires a design document id be provided.',
54+
126: 'Deleting an index requires an index name be provided.',
55+
127: 'Invalid argument: {0}',
56+
128: 'Argument {0} is not an instance of expected type: {1}',
57+
# Query
58+
129: 'Invalid argument: {0}',
59+
130: 'Argument {0} is not an instance of expected type: {1}',
60+
131: 'No selector in the query or the selector was empty. '
61+
'Add a selector to define the query and retry.',
62+
# View
63+
132: 'The map property must be a dictionary.',
64+
133: 'The reduce property must be a string.',
65+
# Common_util
66+
134: 'Key list element not of expected type: {0}',
67+
135: 'Invalid value for stale option {0} must be ok or update_after.',
68+
136: 'Error converting argument {0}: {1}'
69+
}
70+
1971
CLIENT = {
2072
100: 'A general Cloudant client exception was raised.',
21-
101: 'Value must be set to a Database object. Found type: {0}.',
73+
101: 'Value must be set to a Database object. Found type: {0}',
2274
102: 'You must provide a url or an account.',
2375
404: 'Database {0} does not exist. Verify that the client is valid and try again.',
2476
409: 'Database {0} already exists.'
2577
}
2678

2779
DATABASE = {
2880
100: 'A general Cloudant database exception was raised.',
29-
101: 'Unexpected index type. Found: {0}.',
81+
101: 'Unexpected index type. Found: {0}',
3082
400: 'Invalid database name during creation. Found: {0}',
31-
401: 'Unauthorized to create database {0}.',
83+
401: 'Unauthorized to create database {0}',
3284
409: 'Document with id {0} already exists.'
3385
}
3486

@@ -74,7 +126,16 @@
74126
RESULT = {
75127
100: 'A general result exception was raised.',
76128
101: 'Failed to interpret the argument {0} as a valid key value or as a valid slice.',
77-
102: 'Cannot use {0} when performing key access or key slicing. Found {1}.',
78-
103: 'Cannot use {0} for iteration. Found {1}.',
129+
102: 'Cannot use {0} when performing key access or key slicing. Found {1}',
130+
103: 'Cannot use {0} for iteration. Found {1}',
79131
104: 'Invalid page_size: {0}'
80132
}
133+
134+
VIEW = {
135+
100: 'A general view exception was raised.',
136+
101: 'A QueryIndexView is not callable. If you wish to execute a query '
137+
'use the database \'get_query_result\' convenience method.',
138+
102: 'Cannot create a custom result context manager using a '
139+
'QueryIndexView. If you wish to execute a query use the '
140+
'database \'get_query_result\' convenience method instead.'
141+
}

src/cloudant/client.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -549,9 +549,7 @@ def _usage_endpoint(self, endpoint, year=None, month=None):
549549
err = True
550550

551551
if err:
552-
msg = ('Invalid year and/or month supplied. '
553-
'Found: year - {0}, month - {1}').format(year, month)
554-
raise CloudantArgumentError(msg)
552+
raise CloudantArgumentError(101, year, month)
555553
else:
556554
resp.raise_for_status()
557555
return resp.json()

src/cloudant/database.py

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -986,10 +986,7 @@ def share_database(self, username, roles=None):
986986
perms = list(set(roles))
987987

988988
if not perms:
989-
msg = (
990-
'Invalid role(s) provided: {0}. Valid roles are: {1}.'
991-
).format(roles, valid_roles)
992-
raise CloudantArgumentError(msg)
989+
raise CloudantArgumentError(102, roles, valid_roles)
993990

994991
data[username] = perms
995992
doc['cloudant'] = data
@@ -1131,11 +1128,7 @@ def create_query_index(
11311128
elif index_type == TEXT_INDEX_TYPE:
11321129
index = TextIndex(self, design_document_id, index_name, **kwargs)
11331130
else:
1134-
msg = (
1135-
'Invalid index type: {0}. '
1136-
'Index type must be either \"json\" or \"text\"'
1137-
).format(index_type)
1138-
raise CloudantArgumentError(msg)
1131+
raise CloudantArgumentError(103, index_type)
11391132
index.create()
11401133
return index
11411134

@@ -1155,11 +1148,7 @@ def delete_query_index(self, design_document_id, index_type, index_name):
11551148
elif index_type == TEXT_INDEX_TYPE:
11561149
index = TextIndex(self, design_document_id, index_name)
11571150
else:
1158-
msg = (
1159-
'Invalid index type: {0}. '
1160-
'Index type must be either \"json\" or \"text\"'
1161-
).format(index_type)
1162-
raise CloudantArgumentError(msg)
1151+
raise CloudantArgumentError(103, index_type)
11631152
index.delete()
11641153

11651154
def get_query_result(self, selector, fields=None, raw_result=False,
@@ -1346,20 +1335,14 @@ def get_search_result(self, ddoc_id, index_name, **query_params):
13461335
param_query = query_params.get('query')
13471336
# Either q or query parameter is required
13481337
if bool(param_q) == bool(param_query):
1349-
raise CloudantArgumentError(
1350-
'A single query/q parameter is required. '
1351-
'Found: {0}'.format(query_params))
1338+
raise CloudantArgumentError(104, query_params)
13521339

13531340
# Validate query arguments and values
13541341
for key, val in iteritems_(query_params):
13551342
if key not in list(SEARCH_INDEX_ARGS.keys()):
1356-
msg = 'Invalid argument: {0}'.format(key)
1357-
raise CloudantArgumentError(msg)
1343+
raise CloudantArgumentError(105, key)
13581344
if not isinstance(val, SEARCH_INDEX_ARGS[key]):
1359-
msg = (
1360-
'Argument {0} is not an instance of expected type: {1}'
1361-
).format(key, SEARCH_INDEX_ARGS[key])
1362-
raise CloudantArgumentError(msg)
1345+
raise CloudantArgumentError(106, key, SEARCH_INDEX_ARGS[key])
13631346
# Execute query search
13641347
headers = {'Content-Type': 'application/json'}
13651348
ddoc = DesignDocument(self, ddoc_id)

src/cloudant/design_document.py

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,7 @@ def add_view(self, view_name, map_func, reduce_func=None, **kwargs):
282282
:param str reduce_func: Optional Javascript reduce function.
283283
"""
284284
if self.get_view(view_name) is not None:
285-
msg = "View {0} already exists in this design doc".format(view_name)
286-
raise CloudantArgumentError(msg)
285+
raise CloudantArgumentError(107, view_name)
287286
if self.get('language', None) == QUERY_LANGUAGE:
288287
raise CloudantDesignDocumentException(101)
289288

@@ -300,9 +299,7 @@ def add_search_index(self, index_name, search_func, analyzer=None):
300299
:param analyzer: Optional analyzer for this search index.
301300
"""
302301
if self.get_index(index_name) is not None:
303-
msg = ('An index with name {0} already exists in this design doc'
304-
.format(index_name))
305-
raise CloudantArgumentError(msg)
302+
raise CloudantArgumentError(108, index_name)
306303
if analyzer is not None:
307304
search = {'index': codify(search_func), 'analyzer': analyzer}
308305
else:
@@ -319,9 +316,7 @@ def add_list_function(self, list_name, list_func):
319316
:param str list_func: Javascript list function.
320317
"""
321318
if self.get_list_function(list_name) is not None:
322-
msg = ('A list with name {0} already exists in this design doc'
323-
.format(list_name))
324-
raise CloudantArgumentError(msg)
319+
raise CloudantArgumentError(109, list_name)
325320

326321
self.lists.__setitem__(list_name, codify(list_func))
327322

@@ -334,9 +329,7 @@ def add_show_function(self, show_name, show_func):
334329
:param show_func: Javascript show function.
335330
"""
336331
if self.get_show_function(show_name) is not None:
337-
msg = ('A show function with name {0} already exists in this design doc'
338-
.format(show_name))
339-
raise CloudantArgumentError(msg)
332+
raise CloudantArgumentError(110, show_name)
340333

341334
self.shows.__setitem__(show_name, show_func)
342335

@@ -356,8 +349,7 @@ def update_view(self, view_name, map_func, reduce_func=None, **kwargs):
356349
"""
357350
view = self.get_view(view_name)
358351
if view is None:
359-
msg = "View {0} does not exist in this design doc".format(view_name)
360-
raise CloudantArgumentError(msg)
352+
raise CloudantArgumentError(111, view_name)
361353
if isinstance(view, QueryIndexView):
362354
raise CloudantDesignDocumentException(102)
363355

@@ -375,9 +367,7 @@ def update_search_index(self, index_name, search_func, analyzer=None):
375367
"""
376368
search = self.get_index(index_name)
377369
if search is None:
378-
msg = ('An index with name {0} does not exist in this design doc'
379-
.format(index_name))
380-
raise CloudantArgumentError(msg)
370+
raise CloudantArgumentError(112, index_name)
381371
if analyzer is not None:
382372
search = {'index': codify(search_func), 'analyzer': analyzer}
383373
else:
@@ -394,9 +384,7 @@ def update_list_function(self, list_name, list_func):
394384
:param str list_func: Javascript list function.
395385
"""
396386
if self.get_list_function(list_name) is None:
397-
msg = ('A list with name {0} does not exist in this design doc'
398-
.format(list_name))
399-
raise CloudantArgumentError(msg)
387+
raise CloudantArgumentError(113, list_name)
400388

401389
self.lists.__setitem__(list_name, codify(list_func))
402390

@@ -409,9 +397,7 @@ def update_show_function(self, show_name, show_func):
409397
:param show_func: Javascript show function.
410398
"""
411399
if self.get_show_function(show_name) is None:
412-
msg = ('A show function with name {0} does not exist in this design doc'
413-
.format(show_name))
414-
raise CloudantArgumentError(msg)
400+
raise CloudantArgumentError(114, show_name)
415401

416402
self.shows.__setitem__(show_name, show_func)
417403

src/cloudant/error.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@
1717
library.
1818
"""
1919
from cloudant._messages import (
20+
ARGUMENT_ERROR,
2021
CLIENT,
2122
DATABASE,
2223
DESIGN_DOCUMENT,
2324
DOCUMENT,
2425
FEED,
2526
INDEX,
2627
REPLICATOR,
27-
RESULT
28-
)
28+
RESULT,
29+
VIEW)
2930

3031
class CloudantException(Exception):
3132
"""
@@ -46,18 +47,21 @@ def __init__(self, msg, code=None):
4647
class CloudantArgumentError(CloudantException):
4748
"""
4849
Provides a way to issue Cloudant Python client library specific exceptions
49-
that pertain to invalid argument errors. A CloudantArgumentError object is
50-
instantiated with a message and optional code where the code defaults to
51-
400.
50+
that pertain to invalid argument errors.
5251
5352
Note: The intended use for this class is internal to the Cloudant Python
5453
client library.
5554
56-
:param str msg: A message that describes the exception.
5755
:param int code: An optional code value used to identify the exception.
58-
Defaults to 400.
56+
Defaults to 100.
57+
:param args: A list of arguments used to format the exception message.
5958
"""
60-
def __init__(self, msg, code=400):
59+
def __init__(self, code=100, *args):
60+
try:
61+
msg = ARGUMENT_ERROR[code].format(*args)
62+
except (KeyError, IndexError):
63+
code = 100
64+
msg = ARGUMENT_ERROR[code]
6165
super(CloudantArgumentError, self).__init__(msg, code)
6266

6367
class ResultException(CloudantException):
@@ -183,3 +187,18 @@ def __init__(self, code=100, *args):
183187
code = 100
184188
msg = REPLICATOR[code]
185189
super(CloudantReplicatorException, self).__init__(msg, code)
190+
191+
class CloudantViewException(CloudantException):
192+
"""
193+
Provides a way to issue Cloudant library view specific exceptions.
194+
195+
:param int code: A code value used to identify the view exception.
196+
:param args: A list of arguments used to format the exception message.
197+
"""
198+
def __init__(self, code=100, *args):
199+
try:
200+
msg = VIEW[code].format(*args)
201+
except (KeyError, IndexError):
202+
code = 100
203+
msg = VIEW[code]
204+
super(CloudantViewException, self).__init__(msg, code)

0 commit comments

Comments
 (0)