11"""
2- Defines manager classes .
2+ Defines base Redmine resource manager class and it's infrastructure .
33"""
44
5- from distutils .version import LooseVersion
6-
7- from . import utilities , resources , resultsets , exceptions
5+ from .. import utilities , resultsets , exceptions
86
97
108class ResourceManager (object ):
119 """
12- Manages Redmine resource defined by the resource_name with the help of redmine object.
10+ Manages given Redmine resource class with the help of redmine object.
1311 """
14- def __init__ (self , redmine , resource_name , ** params ):
12+ def __init__ (self , redmine , resource_class ):
1513 """
1614 :param redmine.Redmine redmine: (required). Redmine object.
17- :param string resource_name: (required). Resource name.
18- :param dict params: (optional). Parameters used for resources retrieval.
15+ :param resources.BaseResource resource_class: (required). Resource class.
1916 """
20- resource_name = '' .join (word [0 ].upper () + word [1 :] for word in str (resource_name ).split ('_' ))
21-
22- try :
23- resource_class = resources .registry [resource_name ]['class' ]
24- except KeyError :
25- raise exceptions .ResourceError
26-
27- if redmine .ver is not None and LooseVersion (str (redmine .ver )) < LooseVersion (resource_class .redmine_version ):
28- raise exceptions .ResourceVersionMismatchError
29-
3017 self .url = ''
18+ self .params = {}
3119 self .container = None
32- self .params = params
3320 self .redmine = redmine
3421 self .resource_class = resource_class
3522
36- def request (self , is_bulk , ** params ):
37- """
38- Makes request(s) and additionally checks for resource specific stuff.
39-
40- :param bool is_bulk: (required). Whether this is a bulk or single request.
41- :param dict params: (optional). Parameters used for resource retrieval.
42- """
43- try :
44- if not is_bulk :
45- return self .redmine .engine .request ('get' , self .url , params = params )[self .container ]
46- else :
47- return self .redmine .engine .bulk_request ('get' , self .url , self .container , ** self .params )
48- except exceptions .ResourceNotFoundError as e :
49- # This is the only place we're checking for ResourceRequirementsError
50- # because for some POST/PUT/DELETE requests Redmine may also return 404
51- # status code instead of 405 which can lead us to improper decisions
52- if self .resource_class .requirements :
53- raise exceptions .ResourceRequirementsError (self .resource_class .requirements )
54- raise e
55-
5623 def to_resource (self , resource ):
5724 """
5825 Converts resource data to Resource object.
@@ -83,7 +50,9 @@ def new_manager(self, resource_name, **params):
8350 :param string resource_name: (required). Resource name.
8451 :param dict params: (optional). Parameters used for resources retrieval.
8552 """
86- return ResourceManager (self .redmine , resource_name , ** params )
53+ manager = getattr (self .redmine , resource_name )
54+ manager .params = params
55+ return manager
8756
8857 def get (self , resource_id , ** params ):
8958 """
@@ -109,7 +78,13 @@ def get(self, resource_id, **params):
10978
11079 self .params = self .resource_class .bulk_decode (params , self )
11180 self .container = self .resource_class .container_one
112- return self .to_resource (self .request (False , ** self .params ))
81+
82+ try :
83+ return self .to_resource (self .redmine .engine .request ('get' , self .url , params = self .params )[self .container ])
84+ except exceptions .ResourceNotFoundError as e :
85+ if self .resource_class .requirements :
86+ raise exceptions .ResourceRequirementsError (self .resource_class .requirements )
87+ raise e
11388
11489 def all (self , ** params ):
11590 """
@@ -146,6 +121,22 @@ def filter(self, **filters):
146121 self .params = self .resource_class .bulk_decode (filters , self )
147122 return resultsets .ResourceSet (self )
148123
124+ def _construct_create_url (self , path ):
125+ """
126+ Constructs URL for create method.
127+
128+ :param string path: absolute URL path.
129+ """
130+ return self .redmine .url + path
131+
132+ def _prepare_create_request (self , request ):
133+ """
134+ Makes the necessary preparations for create request data.
135+
136+ :param dict request: Request data.
137+ """
138+ return {self .container : self .resource_class .bulk_decode (request , self )}
139+
149140 def create (self , ** fields ):
150141 """
151142 Creates a new resource in Redmine and returns created Resource object on success.
@@ -161,30 +152,50 @@ def create(self, **fields):
161152 formatter = utilities .MemorizeFormatter ()
162153
163154 try :
164- url = self .redmine .url + formatter .format (self .resource_class .query_create , ** fields )
165- except KeyError as exception :
166- raise exceptions .ValidationError ('{0} field is required' .format (exception ))
167-
168- self .container = self .resource_class .container_create
169- data = {self .resource_class .container_create : self .resource_class .bulk_decode (formatter .unused_kwargs , self )}
170- response = self .redmine .engine .request (self .resource_class .http_method_create , url , data = data )
171-
172- try :
173- resource = self .to_resource (response [self .container ])
174- except TypeError :
175- raise exceptions .ValidationError ('Resource already exists' ) # fix for repeated PUT requests (issue #182)
155+ url = self ._construct_create_url (formatter .format (self .resource_class .query_create , ** fields ))
156+ except KeyError as e :
157+ raise exceptions .ValidationError ('{0} field is required' .format (e ))
176158
177159 self .params = formatter .used_kwargs
160+ self .container = self .resource_class .container_create
161+ request = self ._prepare_create_request (formatter .unused_kwargs )
162+ response = self .redmine .engine .request (self .resource_class .http_method_create , url , data = request )
163+ resource = self ._process_create_response (request , response )
178164 self .url = self .redmine .url + self .resource_class .query_one .format (resource .internal_id , ** fields )
179165 return resource
180166
167+ def _process_create_response (self , request , response ):
168+ """
169+ Processes create response and constructs resource object.
170+
171+ :param dict request: Original request data.
172+ :param any response: Response received from Redmine for this request data.
173+ """
174+ return self .to_resource (response [self .container ])
175+
176+ def _construct_update_url (self , path ):
177+ """
178+ Constructs URL for update method.
179+
180+ :param string path: absolute URL path.
181+ """
182+ return self .redmine .url + path
183+
184+ def _prepare_update_request (self , request ):
185+ """
186+ Makes the necessary preparations for update request data.
187+
188+ :param dict request: Request data.
189+ """
190+ return {self .resource_class .container_update : self .resource_class .bulk_decode (request , self )}
191+
181192 def update (self , resource_id , ** fields ):
182193 """
183194 Updates a Resource object by resource id.
184195
185196 :param resource_id: (required). Resource id.
186197 :type resource_id: int or string
187- :param dict fields: (optional). Fields which will be updated for the resource.
198+ :param dict fields: (optional). Fields that will be updated for the resource.
188199 """
189200 if self .resource_class .query_update is None or self .resource_class .container_update is None :
190201 raise exceptions .ResourceBadMethodError
@@ -196,18 +207,44 @@ def update(self, resource_id, **fields):
196207
197208 try :
198209 query_update = formatter .format (self .resource_class .query_update , resource_id , ** fields )
199- except KeyError as exception :
200- param = exception .args [0 ]
210+ except KeyError as e :
211+ param = e .args [0 ]
201212
202213 if param in self .params :
203214 fields [param ] = self .params [param ]
204215 query_update = formatter .format (self .resource_class .query_update , resource_id , ** fields )
205216 else :
206- raise exceptions .ValidationError ('{0} argument is required' .format (exception ))
217+ raise exceptions .ValidationError ('{0} argument is required' .format (e ))
207218
208- url = self .redmine .url + query_update
209- data = {self .resource_class .container_update : self .resource_class .bulk_decode (formatter .unused_kwargs , self )}
210- return self .redmine .engine .request (self .resource_class .http_method_update , url , data = data )
219+ url = self ._construct_update_url (query_update )
220+ request = self ._prepare_update_request (formatter .unused_kwargs )
221+ response = self .redmine .engine .request (self .resource_class .http_method_update , url , data = request )
222+ return self ._process_update_response (request , response )
223+
224+ def _process_update_response (self , request , response ):
225+ """
226+ Processes update response.
227+
228+ :param dict request: Original request data.
229+ :param any response: Response received from Redmine for this request data.
230+ """
231+ return response
232+
233+ def _construct_delete_url (self , path ):
234+ """
235+ Constructs URL for delete method.
236+
237+ :param string path: absolute URL path.
238+ """
239+ return self .redmine .url + path
240+
241+ def _prepare_delete_request (self , request ):
242+ """
243+ Makes the necessary preparations for delete request data.
244+
245+ :param dict request: Request data.
246+ """
247+ return self .resource_class .bulk_decode (request , self )
211248
212249 def delete (self , resource_id , ** params ):
213250 """
@@ -221,12 +258,22 @@ def delete(self, resource_id, **params):
221258 raise exceptions .ResourceBadMethodError
222259
223260 try :
224- url = self .redmine . url + self .resource_class .query_delete .format (resource_id , ** params )
225- except KeyError as exception :
226- raise exceptions .ValidationError ('{0} argument is required' .format (exception ))
261+ url = self ._construct_delete_url ( self .resource_class .query_delete .format (resource_id , ** params ) )
262+ except KeyError as e :
263+ raise exceptions .ValidationError ('{0} argument is required' .format (e ))
227264
228- return self .redmine .engine .request (
229- self .resource_class .http_method_delete , url , params = self .resource_class .bulk_decode (params , self ))
265+ request = self ._prepare_delete_request (params )
266+ response = self .redmine .engine .request (self .resource_class .http_method_delete , url , params = request )
267+ return self ._process_delete_response (request , response )
268+
269+ def _process_delete_response (self , request , response ):
270+ """
271+ Processes delete response.
272+
273+ :param dict request: Original request data.
274+ :param any response: Response received from Redmine for this request data.
275+ """
276+ return response
230277
231278 def search (self , query , ** options ):
232279 """
@@ -246,5 +293,5 @@ def __repr__(self):
246293 """
247294 Official representation of a ResourceManager object.
248295 """
249- return '<{0}.{1} object for {2 } resource>' .format (
250- self .__class__ .__module__ , self . __class__ . __name__ , self .resource_class .__name__ )
296+ return '<redminelib.managers. {0} object for {1 } resource>' .format (
297+ self .__class__ .__name__ , self .resource_class .__name__ )
0 commit comments