Skip to content

Commit 8110874

Browse files
committed
add options to skip response processing
1 parent 703e770 commit 8110874

8 files changed

Lines changed: 87 additions & 3 deletions

File tree

CHANGELOG.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ Changelog
1212
for GUI like behaviour or iterable of elements with "all_gui" string and additional columns to export
1313
- Added support for special characters in WikiPage titles (`Issue #222 <https://github.com/maxtepkeev/python-redmine/
1414
issues/222>`__) (thanks to `Radek Czajka <https://github.com/rczajka>`__)
15+
- Added ``return_response`` and ``ignore_response`` parameters to engine which allow to skip response processing
16+
and speed up the create/update/delete operation in case response body isn't needed (see
17+
`docs <https://python-redmine.com/advanced/request_engines.html#session>`__ for details)
1518

1619
**Changes**:
1720

@@ -26,6 +29,7 @@ Changelog
2629

2730
**Documentation**:
2831

32+
- Introduced detailed parameter list for ``redmine.session``
2933
- Mentioned support for ``admin`` in User's resource create/update
3034

3135
2.2.1 (2019-02-28)

docs/advanced/request_engines.rst

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,17 @@ Session
6666

6767
Sometimes there is a need to change engine/connection options only for one or few requests.
6868
Python-Redmine provides a convenient ``session()`` context manager for that. Options that can
69-
be redefined are all keyword arguments accepted by ``Redmine`` class:
69+
be redefined are as follows:
70+
71+
* **key**. API key used for authentication.
72+
* **username**. Username used for authentication.
73+
* **password**. Password used for authentication.
74+
* **requests**. Connection options.
75+
* **impersonate**. Username to impersonate.
76+
* **ignore_response**. If True no response processing will be done at all.
77+
* **return_response**. Whether to return response or None.
78+
* **return_raw_response**. Whether to return raw or json encoded response.
79+
* **workers**. How many workers to use. *Available only in Pro Edition*.
7080

7181
.. code-block:: python
7282

docs/introduction.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,25 @@ a request to Redmine will be made to actually save the resource and finally a ``
9696
will be executed to run post create tasks if any. You can use any method you like, though it is
9797
recommended to use a ``new()`` method as the most advanced one.
9898
99+
.. hint::
100+
101+
If there's no need to process response, one can use a ``redmine.session`` with either a ``return_response=False``
102+
which doesn't return any response in a form of Resource object, but still validates it in case there were any
103+
errors and raises an exception if needed or a ``ignore_response=True`` which totally ignores response even
104+
if there were any errors. These attributes can save quite some processing time and if a response isn't needed
105+
one is highly encouraged to use on of them:
106+
107+
.. code-block:: python
108+
109+
with redmine.session(return_response=False):
110+
redmine.issue.create(project_id=123, subject='Vacation')
111+
112+
with redmine.session(return_response=False):
113+
issue = redmine.issue.new()
114+
issue.project_id = 123
115+
issue.subject = 'Vacation'
116+
issue.save()
117+
99118
read
100119
++++
101120

redminelib/engines/base.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,18 @@ def __init__(self, **options):
1717
:param string password: (optional). Password used for authentication.
1818
:param dict requests: (optional). Connection options.
1919
:param string impersonate: (optional). Username to impersonate.
20+
:param bool ignore_response (optional). If True no response processing will be done at all.
21+
:param bool return_response (optional). Whether to return response or None.
2022
:param bool return_raw_response (optional). Whether to return raw or json encoded responses.
2123
"""
24+
self.ignore_response = options.pop('ignore_response', False)
25+
self.return_response = options.pop('return_response', True)
2226
self.return_raw_response = options.pop('return_raw_response', False)
2327
self.requests = dict(dict(headers={}, params={}, data={}), **options.get('requests', {}))
2428

29+
if self.ignore_response:
30+
self.requests['stream'] = True
31+
2532
if options.get('impersonate') is not None:
2633
self.requests['headers']['X-Redmine-Switch-User'] = options['impersonate']
2734

@@ -132,6 +139,9 @@ def process_response(self, response):
132139
133140
:param obj response: (required). Response object with response details.
134141
"""
142+
if self.ignore_response:
143+
return None
144+
135145
if response.history:
136146
r = response.history[0]
137147
if r.is_redirect and r.request.url.startswith('http://') and response.request.url.startswith('https://'):
@@ -140,7 +150,9 @@ def process_response(self, response):
140150
status_code = response.status_code
141151

142152
if status_code in (200, 201, 204):
143-
if self.return_raw_response:
153+
if not self.return_response:
154+
return None
155+
elif self.return_raw_response:
144156
return response
145157
elif not response.content.strip():
146158
return True

redminelib/managers/base.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ def create(self, **fields):
158158
self.container = self.resource_class.container_create
159159
request = self._prepare_create_request(self.resource_class.query_create.formatter.unused_kwargs)
160160
response = self.redmine.engine.request(self.resource_class.http_method_create, url, data=request)
161+
162+
if response is None:
163+
return None
164+
161165
resource = self._process_create_response(request, response)
162166
self.url = self.redmine.url + self.resource_class.query_one.format(resource.internal_id, **fields)
163167
return resource
@@ -215,6 +219,10 @@ def update(self, resource_id, **fields):
215219
url = self._construct_update_url(query_update)
216220
request = self._prepare_update_request(self.resource_class.query_update.formatter.unused_kwargs)
217221
response = self.redmine.engine.request(self.resource_class.http_method_update, url, data=request)
222+
223+
if response is None:
224+
return None
225+
218226
return self._process_update_response(request, response)
219227

220228
def _process_update_response(self, request, response):
@@ -260,6 +268,10 @@ def delete(self, resource_id, **params):
260268

261269
request = self._prepare_delete_request(params)
262270
response = self.redmine.engine.request(self.resource_class.http_method_delete, url, params=request)
271+
272+
if response is None:
273+
return None
274+
263275
return self._process_delete_response(request, response)
264276

265277
def _process_delete_response(self, request, response):

redminelib/resources/base.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,11 @@ def save(self, **attrs):
384384
self.post_update()
385385
else:
386386
self.pre_create()
387-
self._decoded_attrs = self.manager.create(**self._changes).raw()
387+
resource = self.manager.create(**self._changes)
388+
389+
if resource is not None:
390+
self._decoded_attrs = resource.raw()
391+
388392
self.post_create()
389393

390394
self._changes = {}

tests/test_engines.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ def test_successful_response_via_put_method(self):
2929
self.response.content = ''
3030
self.assertEqual(self.redmine.engine.request('put', self.url), True)
3131

32+
def test_returns_none_with_ignore_response_true(self):
33+
with self.redmine.session(ignore_response=True):
34+
self.assertEqual(self.redmine.engine.ignore_response, True)
35+
self.assertEqual(self.redmine.engine.requests['stream'], True)
36+
self.assertEqual(self.redmine.engine.request('post', self.url), None)
37+
38+
def test_returns_none_with_return_response_false(self):
39+
with self.redmine.session(return_response=False):
40+
self.assertEqual(self.redmine.engine.return_response, False)
41+
self.assertEqual(self.redmine.engine.request('post', self.url), None)
42+
3243
def test_session_not_implemented_exception(self):
3344
self.assertRaises(NotImplementedError, lambda: engines.BaseEngine())
3445

tests/test_managers.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ def test_create_empty_resource(self):
136136
self.assertEqual(project._decoded_attrs, defaults)
137137
self.assertEqual(repr(project), '<redminelib.resources.Project #0 "">')
138138

139+
def test_create_resource_returns_none(self):
140+
with self.redmine.session(return_response=False):
141+
self.assertEqual(self.redmine.user.create(firstname='John', lastname='Smith'), None)
142+
139143
def test_update_resource(self):
140144
self.response.content = ''
141145
manager = self.redmine.wiki_page
@@ -165,6 +169,10 @@ def test_update_resource_with_stream_uploads(self):
165169
self.assertEquals(len(w), 1)
166170
self.assertIs(w[0].category, exceptions.PerformanceWarning)
167171

172+
def test_update_resource_returns_none(self):
173+
with self.redmine.session(return_response=False):
174+
self.assertEqual(self.redmine.issue.update(1, subject='Bar'), None)
175+
168176
def test_delete_resource(self):
169177
self.response.content = ''
170178
self.assertEqual(self.redmine.wiki_page.delete(b'\xcf\x86oo'.decode('utf-8'), project_id=1), True)
@@ -174,6 +182,10 @@ def test_delete_resource_returns_204(self):
174182
self.response.content = ''
175183
self.assertEqual(self.redmine.wiki_page.delete(b'\xcf\x86oo'.decode('utf-8'), project_id=1), True)
176184

185+
def test_delete_resource_returns_none(self):
186+
with self.redmine.session(return_response=False):
187+
self.assertEqual(self.redmine.user.delete(1), None)
188+
177189
def test_resource_get_method_unsupported_exception(self):
178190
self.assertRaises(exceptions.ResourceBadMethodError, lambda: self.redmine.issue_journal.get(1))
179191

0 commit comments

Comments
 (0)