Skip to content
This repository was archived by the owner on Feb 27, 2023. It is now read-only.

Commit d84e46d

Browse files
committed
#21 Split Bintray class
Signed-off-by: Uilian Ries <uilianries@gmail.com>
1 parent 9045593 commit d84e46d

9 files changed

Lines changed: 213 additions & 149 deletions

bintray/bintray.py

Lines changed: 20 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
#!/usr/bin/env python
21
# -*- coding: utf-8 -*-
32
""" Python Wrapper for Bintray API
43
54
https://bintray.com/docs/api
65
"""
76
import os
8-
import logging
9-
import requests
10-
from requests.auth import HTTPBasicAuth
7+
8+
from bintray.requester import Requester
9+
from bintray.logger import Logger
10+
from bintray.utils import bool_to_number
1111

1212

1313
__version__ = "0.1.1"
@@ -31,51 +31,8 @@ def __init__(self, username=None, api_key=None):
3131
"""
3232
self._username = username or os.getenv("BINTRAY_USERNAME")
3333
self._password = api_key or os.getenv("BINTRAY_API_KEY")
34-
35-
self._logger = logging.getLogger(__file__)
36-
self._logger.setLevel(logging.INFO)
37-
formatter = logging.Formatter('%(asctime)s:%(levelname)s: %(message)s')
38-
ch = logging.StreamHandler()
39-
level = int(os.getenv("BINTRAY_LOGGING_LEVEL", logging.INFO))
40-
ch.setLevel(level)
41-
ch.setFormatter(formatter)
42-
self._logger.addHandler(ch)
43-
44-
def _get_authentication(self):
45-
""" Retrieve Basic HTTP Authentication based on username and API key
46-
47-
:return: Basic Authentication handler
48-
"""
49-
if not self._username or not self._password:
50-
return None
51-
return HTTPBasicAuth(self._username, self._password)
52-
53-
def _add_status_code(self, response):
54-
""" Update JSON result with error and status code
55-
56-
:param response: Requests response
57-
:return: Response JSON
58-
"""
59-
json_data = response.json()
60-
if isinstance(json_data, list):
61-
json_data.append({"statusCode": response.status_code, "error": not response.ok})
62-
else:
63-
json_data.update({"statusCode": response.status_code, "error": not response.ok})
64-
return json_data
65-
66-
def _bool_to_number(self, value):
67-
""" Convert boolean result into numeric string
68-
69-
:param value: Any boolean value
70-
:return: "1" when True. Otherwise, "0"
71-
"""
72-
return "1" if value else "0"
73-
74-
def _raise_error(self, message, response):
75-
try:
76-
response.raise_for_status()
77-
except Exception as error:
78-
raise Exception("{} ({}): {}".format(message, response.status_code, str(error)))
34+
self._requester = Requester(self._username, self._password)
35+
self._logger = Logger().logger
7936

8037
# Files
8138

@@ -90,16 +47,13 @@ def get_package_files(self, subject, repo, package, include_unpublished=False):
9047
:param include_unpublished: Show not published files
9148
:return: List with all files
9249
"""
93-
parameters = {"include_unpublished": self._bool_to_number(include_unpublished)}
50+
parameters = {"include_unpublished": bool_to_number(include_unpublished)}
9451
url = "{}/packages/{}/{}/{}/files?include_unpublished={}".format(Bintray.BINTRAY_URL,
9552
subject,
9653
repo,
9754
package,
9855
include_unpublished)
99-
response = requests.get(url, auth=self._get_authentication(), params=parameters)
100-
if not response.ok:
101-
self._raise_error("Could not list package files", response)
102-
return self._add_status_code(response)
56+
return self._requester.get(url, parameters)
10357

10458
# Content Uploading & Publishing
10559

@@ -121,17 +75,15 @@ def upload_content(self, subject, repo, package, version, remote_file_path, loca
12175
"""
12276
url = "{}/content/{}/{}/{}/{}/{}".format(Bintray.BINTRAY_URL, subject, repo, package,
12377
version, remote_file_path)
124-
parameters = {"publish": self._bool_to_number(publish),
125-
"override": self._bool_to_number(override),
126-
"explode": self._bool_to_number(explode)}
78+
parameters = {"publish": bool_to_number(publish),
79+
"override": bool_to_number(override),
80+
"explode": bool_to_number(explode)}
12781

12882
with open(local_file_path, 'rb') as file_content:
129-
response = requests.put(url, auth=self._get_authentication(), params=parameters,
130-
data=file_content)
131-
if response.status_code != 201:
132-
self._raise_error("Could not upload", response)
83+
response = self._requester.put(url, params=parameters, data=file_content)
84+
13385
self._logger.info("Upload successfully: {}".format(url))
134-
return self._add_status_code(response)
86+
return response
13587

13688
# Content Downloading
13789

@@ -145,13 +97,13 @@ def download_content(self, subject, repo, remote_file_path, local_file_path):
14597
"""
14698
download_base_url = "https://dl.bintray.com"
14799
url = "{}/{}/{}/{}".format(download_base_url, subject, repo, remote_file_path)
148-
response = requests.get(url, auth=self._get_authentication())
149-
if not response.ok:
150-
self._raise_error("Could not download file content", response)
100+
response, content = self._requester.download(url)
101+
151102
with open(local_file_path, 'wb') as local_fd:
152-
local_fd.write(response.content)
103+
local_fd.write(content)
104+
153105
self._logger.info("Download successfully: {}".format(url))
154-
return self._add_status_code(response)
106+
return response
155107

156108
# Licenses
157109

@@ -161,8 +113,4 @@ def get_oss_licenses(self):
161113
:return: List with OSS licenses
162114
"""
163115
url = "{}/licenses/oss_licenses".format(Bintray.BINTRAY_URL)
164-
response = requests.get(url, auth=self._get_authentication())
165-
if not response.ok:
166-
self._raise_error("Could not get OSS licenses", response)
167-
return self._add_status_code(response)
168-
116+
return self._requester.get(url)

bintray/logger.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import logging
4+
import os
5+
6+
7+
class Logger(object):
8+
9+
def __init__(self):
10+
self._logger = logging.getLogger("bintray")
11+
self._logger.setLevel(logging.INFO)
12+
formatter = logging.Formatter('%(asctime)s:%(levelname)s: %(message)s')
13+
ch = logging.StreamHandler()
14+
level = int(os.getenv("BINTRAY_LOGGING_LEVEL", logging.INFO))
15+
ch.setLevel(level)
16+
ch.setFormatter(formatter)
17+
self._logger.addHandler(ch)
18+
19+
@property
20+
def logger(self):
21+
return self._logger

bintray/requester.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import requests
4+
5+
from requests.auth import HTTPBasicAuth
6+
7+
8+
class Requester(object):
9+
10+
def __init__(self, username=None, api_key=None):
11+
""" Initialize arguments for login
12+
13+
:param username: Bintray username
14+
:param api_key: Bintray API Key
15+
"""
16+
self._username = username
17+
self._password = api_key
18+
19+
def _get_authentication(self):
20+
""" Retrieve Basic HTTP Authentication based on username and API key
21+
22+
:return: Basic Authentication handler
23+
"""
24+
if not self._username or not self._password:
25+
return None
26+
return HTTPBasicAuth(self._username, self._password)
27+
28+
def _add_status_code(self, response):
29+
""" Update JSON result with error and status code
30+
31+
:param response: Requests response
32+
:return: Response JSON
33+
"""
34+
json_data = response.json()
35+
if isinstance(json_data, list):
36+
json_data.append({"statusCode": response.status_code, "error": not response.ok})
37+
else:
38+
json_data.update({"statusCode": response.status_code, "error": not response.ok})
39+
return json_data
40+
41+
def _raise_error(self, message, response):
42+
try:
43+
response.raise_for_status()
44+
except Exception as error:
45+
raise Exception("{} ({}): {}".format(message, response.status_code, str(error)))
46+
47+
def get(self, url, params=None):
48+
""" Forward GET method
49+
50+
:param url: Web address
51+
:param params: URL params
52+
:return: JSON answer
53+
"""
54+
response, _ = self.download(url, params)
55+
return response
56+
57+
def download(self, url, params=None):
58+
""" Just like GET method, but with content
59+
60+
:param url: URL Address
61+
:param params: URL parameters
62+
:return: JSON response and content
63+
"""
64+
response = requests.get(url, auth=self._get_authentication(), params=params)
65+
if not response.ok:
66+
self._raise_error("Could not GET", response)
67+
return self._add_status_code(response), response.content
68+
69+
def put(self, url, params=None, data=None):
70+
""" Forward PUT method
71+
72+
:param url: URL address
73+
:param params: URL params
74+
:param data: Data content
75+
:return: JSON
76+
"""
77+
response = requests.put(url, auth=self._get_authentication(), params=params, data=data)
78+
if not response.ok:
79+
self._raise_error("Could not PUT", response)
80+
return self._add_status_code(response)

bintray/utils.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# -*- coding: utf-8 -*-
2+
3+
4+
def bool_to_number(value):
5+
""" Convert boolean result into numeric string
6+
7+
:param value: Any boolean value
8+
:return: "1" when True. Otherwise, "0"
9+
"""
10+
return "1" if value else "0"

tests/test_bintray_python.py

Lines changed: 0 additions & 75 deletions
This file was deleted.

tests/test_content_downloading.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import os
4+
from bintray.bintray import Bintray
5+
6+
7+
def test_download_content():
8+
json_file = "packages.json"
9+
bintray = Bintray()
10+
response = bintray.download_content("uilianries", "generic", json_file, json_file)
11+
assert os.path.exists(json_file)
12+
assert False == response["error"]
13+
14+
15+
def test_bad_credentials_for_download_content():
16+
json_file = "packages.json"
17+
bintray = Bintray("foobar", "85abc6aece02515e8bd87b9754a18af697527d88")
18+
error_message = ""
19+
try:
20+
bintray.download_content("uilianries", "generic", json_file, json_file)
21+
except Exception as error:
22+
error_message = str(error)
23+
assert "Could not GET (401): 401 Client Error: Unauthorized for url: "\
24+
"https://dl.bintray.com/uilianries/generic/packages.json" == error_message

tests/test_files.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from bintray.bintray import Bintray
4+
5+
6+
def test_get_package_files():
7+
bintray = Bintray()
8+
response = bintray.get_package_files("uilianries", "generic", "statistics")
9+
assert {'error': False, 'statusCode': 200} in response
10+
assert {'created': '2019-07-01T20:51:42.879Z',
11+
'name': 'packages.json',
12+
'owner': 'uilianries',
13+
'package': 'statistics',
14+
'path': 'packages.json',
15+
'repo': 'generic',
16+
'sha1': '85abc6aece02515e8bd87b9754a18af697527d88',
17+
'sha256': '9537027db06c520b6eeb3b8317cef5c994ab93e5ad4b17fac3567fba7089b165',
18+
'size': 1967,
19+
'version': '20190701'} in response
20+
21+
22+
def test_bad_credentials_for_get_package_files():
23+
bintray = Bintray("foobar", "85abc6aece02515e8bd87b9754a18af697527d88")
24+
error_message = ""
25+
try:
26+
bintray.get_package_files("uilianries", "generic", "statistics")
27+
except Exception as error:
28+
error_message = str(error)
29+
assert "Could not GET (401): 401 Client Error: Unauthorized for url: " \
30+
"https://api.bintray.com/packages/uilianries/generic/statistics/files?" \
31+
"include_unpublished=False&include_unpublished=0" == error_message

0 commit comments

Comments
 (0)