Skip to content

Commit 175d1f7

Browse files
authored
[RestClient] Added advanced_mode to POST, PUT, DELETE (atlassian-api#684)
* [RestClient] Added advanced_mode to POST, PUT, DELETE Added boolean switch to post, put and delete methods of RestClient, to make them align with the get implementation. This allows the caller to retrieve raw response for individual calls rather than change the property of the RestClient instance. Added tests that mimic Confluence module behavior that check the type of response Closes atlassian-api#681 * [RestClient] Fixed flake8 errors on the test for advanced_mode
1 parent cf7763b commit 175d1f7

File tree

2 files changed

+127
-3
lines changed

2 files changed

+127
-3
lines changed

atlassian/rest_client.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,12 @@ def post(
305305
params=None,
306306
trailing=None,
307307
absolute=False,
308+
advanced_mode=False,
308309
):
310+
"""
311+
:param advanced_mode: bool, OPTIONAL: Return the raw response
312+
:return: if advanced_mode is not set - returns dictionary. If it is set - returns raw response.
313+
"""
309314
response = self.request(
310315
"POST",
311316
path=path,
@@ -317,7 +322,7 @@ def post(
317322
trailing=trailing,
318323
absolute=absolute,
319324
)
320-
if self.advanced_mode:
325+
if self.advanced_mode or advanced_mode:
321326
return response
322327
return self._response_handler(response)
323328

@@ -330,7 +335,12 @@ def put(
330335
trailing=None,
331336
params=None,
332337
absolute=False,
338+
advanced_mode=False,
333339
):
340+
"""
341+
:param advanced_mode: bool, OPTIONAL: Return the raw response
342+
:return: if advanced_mode is not set - returns dictionary. If it is set - returns raw response.
343+
"""
334344
response = self.request(
335345
"PUT",
336346
path=path,
@@ -341,7 +351,7 @@ def put(
341351
trailing=trailing,
342352
absolute=absolute,
343353
)
344-
if self.advanced_mode:
354+
if self.advanced_mode or advanced_mode:
345355
return response
346356
return self._response_handler(response)
347357

@@ -353,12 +363,15 @@ def delete(
353363
params=None,
354364
trailing=None,
355365
absolute=False,
366+
advanced_mode=False,
356367
):
357368
"""
358369
Deletes resources at given paths.
370+
:param advanced_mode: bool, OPTIONAL: Return the raw response
359371
:rtype: dict
360372
:return: Empty dictionary to have consistent interface.
361373
Some of Atlassian REST resources don't return any content.
374+
If advanced_mode is set - returns raw response.
362375
"""
363376
response = self.request(
364377
"DELETE",
@@ -369,6 +382,6 @@ def delete(
369382
trailing=trailing,
370383
absolute=absolute,
371384
)
372-
if self.advanced_mode:
385+
if self.advanced_mode or advanced_mode:
373386
return response
374387
return self._response_handler(response)
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# coding=utf-8
2+
import json
3+
import os
4+
import unittest
5+
from requests import Response
6+
7+
from atlassian import Confluence
8+
from atlassian.errors import ApiError
9+
10+
11+
@unittest.skipIf(
12+
not os.path.exists("../credentials.secret"),
13+
"credentials.secret missing, skipping test",
14+
)
15+
class TestConfluenceAdvancedModeCalls(unittest.TestCase):
16+
secret_file = "../credentials.secret"
17+
18+
"""
19+
Keep the credentials private, the file is excluded. There is an example for credentials.secret
20+
See also: http://www.blacktechdiva.com/hide-api-keys/
21+
22+
{
23+
"host" : "https://localhost:8080",
24+
"username" : "john_doe",
25+
"password" : "12345678"
26+
}
27+
"""
28+
29+
@classmethod
30+
def setUpClass(cls):
31+
try:
32+
with open(cls.secret_file) as json_file:
33+
credentials = json.load(json_file)
34+
cls.confluence = Confluence(
35+
url=credentials["host"],
36+
username=credentials["username"],
37+
password=credentials["password"],
38+
)
39+
except Exception as err:
40+
raise cls.failureException("[{0}]: {1}".format(cls.secret_file, err))
41+
42+
cls.space = "SAN"
43+
cls.created_pages = set()
44+
45+
def test_confluence_advanced_mode_post(self):
46+
"""Tests the advanced_mode option of AtlassianRestAPI post method by manually creating a page"""
47+
page_title = "Test_confluence_advanced_mode_post"
48+
data = {
49+
"type": "page",
50+
"title": page_title,
51+
"space": {"key": self.space},
52+
"body": {"editor": {"value": "<h1>Created page</h1>", "representation": "editor"}},
53+
}
54+
result = self.confluence.post(
55+
path="rest/api/content",
56+
data=data,
57+
advanced_mode=True,
58+
)
59+
self.assertIsInstance(result, Response)
60+
61+
# For cleanup
62+
page_id = self.confluence.get_page_id(space=self.space, title=page_title)
63+
self.created_pages |= {page_id}
64+
65+
def test_confluence_advanced_mode_put(self):
66+
"""Tests the advanced_mode option of AtlassianRestAPI post method by creating a page using python API, then
67+
directly updating the text through PUT"""
68+
69+
page_title = "Test_confluence_advanced_mode_put"
70+
page_id = self.confluence.create_page(
71+
space=self.space, title=page_title, body="h1. Test content\n", representation="wiki"
72+
)["id"]
73+
self.created_pages |= {page_id}
74+
data = {
75+
"id": page_id,
76+
"type": "page",
77+
"title": page_title,
78+
"version": {"number": 2, "minorEdit": False},
79+
"body": {"editor": {"value": "<h1>Updated page</h1>", "representation": "editor"}},
80+
}
81+
82+
result = self.confluence.put(path="/rest/api/content/{0}".format(page_id), data=data, advanced_mode=True)
83+
self.assertIsInstance(result, Response)
84+
85+
def test_confluence_advanced_mode_delete(self):
86+
"""Tests the advanced_mode option of AtlassianRestAPI post method by creating a page using python API, then
87+
deleting the page through DELETE"""
88+
page_title = "Test_confluence_advanced_mode_delete"
89+
page_id = self.confluence.create_page(
90+
space=self.space, title=page_title, body="h1. Test content\n", representation="wiki"
91+
)["id"]
92+
response = self.confluence.delete(
93+
path="rest/api/content/{page_id}".format(page_id=page_id), params={}, advanced_mode=True
94+
)
95+
self.assertIsInstance(response, Response)
96+
97+
def tearDown(self):
98+
"""Run after every test. Destroys created pages"""
99+
for page_id in self.created_pages:
100+
try:
101+
self.confluence.remove_page(page_id=page_id)
102+
except ApiError as e:
103+
if e.args[0].startswith("There is no content with the given id"):
104+
# Page was probably already deleted
105+
pass
106+
else:
107+
raise e
108+
109+
110+
if __name__ == "__main__":
111+
unittest.main()

0 commit comments

Comments
 (0)