Skip to content

Commit 8900f3b

Browse files
author
Gonchik Tsymzhitov
committed
Merge branch 'master' of https://github.com/atlassian-api/atlassian-python-api into master
2 parents ebe6794 + a2d1fb8 commit 8900f3b

File tree

7 files changed

+160
-50
lines changed

7 files changed

+160
-50
lines changed

atlassian/bitbucket/cloud/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
class Cloud(BitbucketCloudBase):
9-
def __init__(self, url, *args, **kwargs):
9+
def __init__(self, url="https://api.bitbucket.org/", *args, **kwargs):
1010
kwargs["cloud"] = True
1111
kwargs["api_root"] = None
1212
kwargs["api_version"] = "2.0"

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)

docs/index.rst

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -49,45 +49,10 @@ Add a connection:
4949
username='admin',
5050
password='admin')
5151
52-
Key/Cert Based authentication
53-
-----------------------------
52+
Other authentication methods
53+
----------------------------
5454

55-
Add a connection using key/cert based authentication:
56-
57-
.. code-block:: python
58-
59-
from atlassian import Jira
60-
from atlassian import Confluence
61-
from atlassian import Bitbucket
62-
from atlassian import ServiceDesk
63-
from atlassian import Xray
64-
65-
jira = Jira(
66-
url='http://localhost:8080',
67-
key='/path/to/key',
68-
cert='/path/to/cert')
69-
70-
confluence = Confluence(
71-
url='http://localhost:8090',
72-
key='/path/to/key',
73-
cert='/path/to/cert')
74-
75-
bitbucket = Bitbucket(
76-
url='http://localhost:7990',
77-
key='/path/to/key',
78-
cert='/path/to/cert')
79-
80-
service_desk = ServiceDesk(
81-
url='http://localhost:8080',
82-
key='/path/to/key',
83-
cert='/path/to/cert')
84-
85-
xray = Xray(
86-
url='http://localhost:8080',
87-
key='/path/to/key',
88-
cert='/path/to/cert')
89-
90-
Alternatively OAuth can be used:
55+
Further authentication methods are available. For example OAuth can be used:
9156

9257
.. code-block:: python
9358
@@ -121,7 +86,7 @@ OAuth 2.0 is also supported:
12186

12287
.. code-block:: python
12388
124-
from atlassian.bitbucket.cloud import Cloud
89+
from atlassian.bitbucket import Cloud
12590
12691
# token is a dictionary and must at least contain "access_token"
12792
# and "token_type".
@@ -130,7 +95,6 @@ OAuth 2.0 is also supported:
13095
"token": token}
13196
13297
bitbucket_cloud = Cloud(
133-
url='https://api.bitbucket.org/',
13498
oauth2=oauth2_dict)
13599
136100
# For a detailed example see bitbucket_oauth2.py in
@@ -225,16 +189,14 @@ And to Bitbucket Cloud:
225189
# Log-in with E-Mail and App password not possible.
226190
# Username can be found here: https://bitbucket.org/account/settings/
227191
228-
from atlassian.bitbucket.cloud import Cloud
192+
from atlassian.bitbucket import Cloud
229193
230194
bitbucket = Cloud(
231-
url='https://api.bitbucket.org/',
232195
username=bitbucket_email,
233196
password=bitbucket_password,
234197
cloud=True)
235198
236199
bitbucket_app_pw = Cloud(
237-
url='https://api.bitbucket.org/',
238200
username=bitbucket_username,
239201
password=bitbucket_app_password,
240202
cloud=True)

examples/bitbucket/bitbucket_cloud_oo.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
from textwrap import indent
44

5-
from atlassian.bitbucket.cloud import Cloud
5+
from atlassian.bitbucket import Cloud
66

7-
cloud = Cloud(url="http://localhost:7990", username="admin", password="admin")
7+
cloud = Cloud(url="https://api.bitbucket.org/", username="admin", password="admin")
88

99
index = 0
1010
for w in cloud.workspaces.each():

examples/bitbucket/bitbucket_oauth2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# token and the available workspaces are returned.
55

66
from requests_oauthlib import OAuth2Session
7-
from atlassian.bitbucket.cloud import Cloud
7+
from atlassian.bitbucket import Cloud
88
from flask import Flask, request, redirect, session
99

1010
app = Flask(__name__)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# coding=utf-8
2+
from atlassian import Jira
3+
4+
# This example shoes how to add an additional value to the Labels field
5+
# without loosing the previously defined ones already defined
6+
7+
issue_key = "TST-1"
8+
new_tag = "label_to_add_for_test"
9+
jira = Jira(url="http://localhost:8080", username="admin", password="admin")
10+
11+
12+
def jira_add_label(issue_key, new_tag):
13+
field_name = "labels"
14+
# get value and save
15+
field_value = jira.issue_field_value(issue_key, field_name)
16+
field_value.append(new_tag)
17+
# prepare data like this
18+
# https://developer.atlassian.com/server/jira/platform/jira-rest-api-example-edit-issues-6291632
19+
field_preparation = {field_name: field_value}
20+
# update custom field on destination issue
21+
jira.update_issue_field(issue_key, field_preparation)
22+
23+
24+
jira_add_label(issue_key, new_tag)
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)