Skip to content

Commit f1f8223

Browse files
Spacetowngonchik
andauthored
[Bitbucket] Unify Server and Cloud implementation. (#672)
- Add links to API documentation - Add update to cloud repository. - Remove checks for "error" in response because an exception is thrown on HTTP errors. Co-authored-by: Gonchik Tsymzhitov <[email protected]>
1 parent 546720a commit f1f8223

File tree

29 files changed

+1016
-744
lines changed

29 files changed

+1016
-744
lines changed

atlassian/bitbucket/__init__.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2538,7 +2538,6 @@ def delete_issue(self, workspace, repository_slug, id):
25382538
.repositories.get(repository_slug)
25392539
.issues.get(id)
25402540
.delete()
2541-
.data
25422541
)
25432542

25442543
@deprecated(
@@ -2647,7 +2646,6 @@ def delete_branch_restriction(self, workspace, repository_slug, id):
26472646
.repositories.get(repository_slug)
26482647
.branch_restrictions.get(id)
26492648
.delete()
2650-
.data
26512649
)
26522650

26532651
@deprecated(
@@ -2734,5 +2732,4 @@ def delete_default_reviewer(self, workspace, repository_slug, user):
27342732
.repositories.get(repository_slug)
27352733
.default_reviewers.get(user)
27362734
.delete()
2737-
.data
27382735
)

atlassian/bitbucket/base.py

Lines changed: 90 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
# coding=utf-8
22

3+
import copy
34
import re
45
import sys
56

67
from datetime import datetime
8+
from pprint import PrettyPrinter
79
from ..rest_client import AtlassianRestAPI
810

911

@@ -17,27 +19,37 @@ class BitbucketBase(AtlassianRestAPI):
1719
def __init__(self, url, *args, **kwargs):
1820
"""
1921
Init the rest api wrapper
20-
:param url: The base url used for the rest api.
21-
:param *args: The fixed arguments for the AtlassianRestApi.
22-
:param **kwargs: The fixed arguments for the AtlassianRestApi.
22+
23+
:param url: string: The base url used for the rest api.
24+
:param *args: list: The fixed arguments for the AtlassianRestApi.
25+
:param **kwargs: dict: The keyword arguments for the AtlassianRestApi.
2326
2427
:return: nothing
2528
"""
29+
self._update_data(kwargs.pop("data", {}))
30+
if url is None:
31+
url = self.get_link("self")
32+
if isinstance(url, list): # Server has a list of links
33+
url = url[0]
2634
self.timeformat_lambda = kwargs.pop("timeformat_lambda", lambda x: self._default_timeformat_lambda(x))
2735
self._check_timeformat_lambda()
2836
super(BitbucketBase, self).__init__(url, *args, **kwargs)
2937

38+
def __str__(self):
39+
return PrettyPrinter(indent=4).pformat(self.__data if self.__data else self)
40+
3041
def _get_paged(self, url, params=None, data=None, flags=None, trailing=None, absolute=False):
3142
"""
3243
Used to get the paged data
33-
:param url: The url to retrieve.
34-
:param params: The parameters (optional).
35-
:param data: The data (optional).
36-
:param flags: The flags (optional).
37-
:param trailing: If True, a trailing slash is added to the url (optional).
38-
:param absolute: If True, the url is used absolute and not relative to the root (optional).
3944
40-
:return: A generator for the project objects
45+
:param url: string: The url to retrieve
46+
:param params: dict (default is None): The parameters
47+
:param data: dict (default is None): The data
48+
:param flags: string[] (default is None): The flags
49+
:param trailing: bool (default is None): If True, a trailing slash is added to the url
50+
:param absolute: bool (default is False): If True, the url is used absolute and not relative to the root
51+
52+
:return: A generator object for the data elements
4153
"""
4254

4355
if params is None:
@@ -64,7 +76,21 @@ def _get_paged(self, url, params=None, data=None, flags=None, trailing=None, abs
6476

6577
return
6678

79+
@staticmethod
80+
def _default_timeformat_lambda(timestamp):
81+
"""
82+
Default time format function.
83+
84+
:param timestamp: datetime str: The datetime object of the parsed string or the raw value if parsing failed
85+
86+
:return: timestamp if it was a datetime object, else None
87+
"""
88+
return timestamp if isinstance(timestamp, datetime) else None
89+
6790
def _check_timeformat_lambda(self):
91+
"""
92+
Check the lambda for for the time format. Raise an exception if the the value is wrong
93+
"""
6894
LAMBDA = lambda: 0 # noqa: E731
6995
if self.timeformat_lambda is None or (
7096
isinstance(self.timeformat_lambda, type(LAMBDA)) and self.timeformat_lambda.__name__ == LAMBDA.__name__
@@ -73,11 +99,45 @@ def _check_timeformat_lambda(self):
7399
else:
74100
ValueError("Expected [None] or [lambda function] for argument [timeformat_func]")
75101

76-
@staticmethod
77-
def _default_timeformat_lambda(timestamp):
78-
return timestamp if isinstance(timestamp, datetime) else None
102+
def _sub_url(self, url):
103+
"""
104+
Get the full url from a relative one.
105+
106+
:param url: string: The sub url
107+
108+
:return: The absolute url
109+
"""
110+
return self.url_joiner(self.url, url)
111+
112+
@property
113+
def data(self):
114+
"""
115+
Get the internal cached data. For data integrity a deep copy is returned.
116+
117+
:return: A copy of the data cache
118+
"""
119+
return copy.copy(self.__data)
120+
121+
def get_data(self, id, default=None):
122+
"""
123+
Get a data element from the internal data cache. For data integrity a deep copy is returned.
124+
If data isn't present, the default value is returned.
125+
126+
:param id: string: The data element to return
127+
:param default: any (default is None): The value to return if id is not present
128+
129+
:return: The requested data element
130+
"""
131+
return copy.copy(self.__data[id]) if id in self.__data else default
79132

80133
def get_time(self, id):
134+
"""
135+
Return the time value with the expected format.
136+
137+
:param id: string: The id for the time data
138+
139+
:return: The time with the configured format, see timeformat_lambda.
140+
"""
81141
value_str = self.get_data(id)
82142
if self.timeformat_lambda is None:
83143
return value_str
@@ -92,8 +152,25 @@ def get_time(self, id):
92152

93153
return self.timeformat_lambda(value)
94154

155+
def _update_data(self, data):
156+
"""
157+
Internal function to update the data.
158+
159+
:param data: dict: The new data.
160+
161+
:return: The updated object
162+
"""
163+
self.__data = data
164+
165+
return self
166+
95167
@property
96168
def _new_session_args(self):
169+
"""
170+
Get the kwargs for new objects (session, root, version,...).
171+
172+
:return: A dict with the kwargs for new objects
173+
"""
97174
return dict(
98175
session=self._session,
99176
cloud=self.cloud,

atlassian/bitbucket/cloud/base.py

Lines changed: 29 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,49 @@
11
# coding=utf-8
2-
import copy
3-
from pprint import PrettyPrinter
42

53
from ..base import BitbucketBase
64

75

86
class BitbucketCloudBase(BitbucketBase):
9-
def __init__(self, url, link="self", *args, **kwargs):
7+
def __init__(self, url, *args, **kwargs):
108
"""
119
Init the rest api wrapper
12-
:param url: The base url used for the rest api.
13-
:param link: Attribute to resolve a url based on input data.
14-
If None, no tries to receive an url from input data
15-
:param *args: The fixed arguments for the AtlassianRestApi.
16-
:param **kwargs: The keyword arguments for the AtlassianRestApi.
10+
11+
:param url: string: The base url used for the rest api.
12+
:param *args: list: The fixed arguments for the AtlassianRestApi.
13+
:param **kwargs: dict: The keyword arguments for the AtlassianRestApi.
1714
1815
:return: nothing
1916
"""
20-
if "data" in kwargs:
21-
self.__data = kwargs.pop("data")
22-
expected_type = kwargs.pop("expected_type")
23-
if not self.get_data("type") == expected_type:
24-
raise ValueError(
25-
"Expected type of data is [{}], got [{}].".format(expected_type, self.get_data("type"))
26-
)
27-
if url is None and link is not None:
28-
url = self.get_link(link)
29-
17+
expected_type = kwargs.pop("expected_type", None)
3018
super(BitbucketCloudBase, self).__init__(url, *args, **kwargs)
19+
if expected_type is not None and not expected_type == self.get_data("type"):
20+
raise ValueError("Expected type of data is [{}], got [{}].".format(expected_type, self.get_data("type")))
21+
22+
def get_link(self, link):
23+
"""
24+
Get a link from the data.
25+
26+
:param link: string: The link identifier
3127
32-
def __str__(self):
33-
return PrettyPrinter(indent=4).pformat(self.__data)
28+
:return: The requested link or None if it isn't present
29+
"""
30+
links = self.get_data("links")
31+
if links is None or link not in links:
32+
return None
33+
return links[link]["href"]
3434

3535
def _get_paged(self, url, params=None, data=None, flags=None, trailing=None, absolute=False):
3636
"""
3737
Used to get the paged data
38-
:param url: The url to retrieve.
39-
:param params: The parameters (optional).
40-
:param data: The data (optional).
41-
:param flags: The flags (optional).
42-
:param trailing: If True, a trailing slash is added to the url (optional).
43-
:param absolute: If True, the url is used absolute and not relative to the root (optional).
44-
45-
:return: A generator for the project objects
38+
39+
:param url: string: The url to retrieve
40+
:param params: dict (default is None): The parameters
41+
:param data: dict (default is None): The data
42+
:param flags: string[] (default is None): The flags
43+
:param trailing: bool (default is None): If True, a trailing slash is added to the url
44+
:param absolute: bool (default is False): If True, the url is used absolute and not relative to the root
45+
46+
:return: A generator object for the data elements
4647
"""
4748

4849
if params is None:
@@ -70,20 +71,3 @@ def _get_paged(self, url, params=None, data=None, flags=None, trailing=None, abs
7071
absolute = True
7172

7273
return
73-
74-
def update(self, **kwargs):
75-
"""
76-
Fields not present in the request body are ignored.
77-
"""
78-
self.__data = super(BitbucketBase, self).put(None, data=kwargs)
79-
return self
80-
81-
@property
82-
def data(self):
83-
return copy.copy(self.__data)
84-
85-
def get_data(self, id, default=None):
86-
return copy.copy(self.__data[id]) if id in self.__data else default
87-
88-
def get_link(self, link):
89-
return self.__data["links"][link]["href"]

0 commit comments

Comments
 (0)