blob: e56c633256240fb38b1f102a5288a7f74b649fd1 [file] [log] [blame]
Ilya Menkovad234032019-10-22 13:43:54 +04001#
2# TestRail API binding for Python 3.x (API v2, available since
3# TestRail 3.0)
4# Compatible with TestRail 3.0 and later.
5#
6# Learn more:
7#
8# http://docs.gurock.com/testrail-api2/start
9# http://docs.gurock.com/testrail-api2/accessing
10#
11# Copyright Gurock Software GmbH. See license.md for details.
12#
13
Ilya Menkovad234032019-10-22 13:43:54 +040014import base64
stavrovska28772bc2024-05-22 09:33:50 +020015import json
16
17import requests
Ilya Menkovad234032019-10-22 13:43:54 +040018
19
20class APIClient:
21 def __init__(self, base_url):
stavrovska28772bc2024-05-22 09:33:50 +020022 self.user = ""
23 self.password = ""
24 if not base_url.endswith("/"):
25 base_url += "/"
26 self.__url = base_url + "index.php?/api/v2/"
Ilya Menkovad234032019-10-22 13:43:54 +040027
28 #
29 # Send Get
30 #
31 # Issues a GET request (read) against the API and returns the result
32 # (as Python dict) or filepath if successful file download
33 #
34 # Arguments:
35 #
36 # uri The API method to call including parameters
37 # (e.g. get_case/1)
38 #
39 # filepath The path and file name for attachment download
40 # Used only for 'get_attachment/:attachment_id'
41 #
42 def send_get(self, uri, filepath=None):
stavrovska28772bc2024-05-22 09:33:50 +020043 return self.__send_request("GET", uri, filepath)
Ilya Menkovad234032019-10-22 13:43:54 +040044
45 #
46 # Send POST
47 #
48 # Issues a POST request (write) against the API and returns the result
49 # (as Python dict).
50 #
51 # Arguments:
52 #
53 # uri The API method to call including parameters
54 # (e.g. add_case/1)
55 # data The data to submit as part of the request (as
56 # Python dict, strings must be UTF-8 encoded)
57 # If adding an attachment, must be the path
58 # to the file
59 #
60 def send_post(self, uri, data):
stavrovska28772bc2024-05-22 09:33:50 +020061 return self.__send_request("POST", uri, data)
Ilya Menkovad234032019-10-22 13:43:54 +040062
63 def __send_request(self, method, uri, data):
64 url = self.__url + uri
65
66 auth = str(
67 base64.b64encode(
stavrovska28772bc2024-05-22 09:33:50 +020068 bytes("%s:%s" % (self.user, self.password), "utf-8")
Ilya Menkovad234032019-10-22 13:43:54 +040069 ),
stavrovska28772bc2024-05-22 09:33:50 +020070 "ascii",
Ilya Menkovad234032019-10-22 13:43:54 +040071 ).strip()
stavrovska28772bc2024-05-22 09:33:50 +020072 headers = {"Authorization": "Basic " + auth}
Ilya Menkovad234032019-10-22 13:43:54 +040073
stavrovska28772bc2024-05-22 09:33:50 +020074 if method == "POST":
75 if uri[:14] == "add_attachment": # add_attachment API method
76 files = {"attachment": (open(data, "rb"))}
Ilya Menkovad234032019-10-22 13:43:54 +040077 response = requests.post(url, headers=headers, files=files)
stavrovska28772bc2024-05-22 09:33:50 +020078 files["attachment"].close()
Ilya Menkovad234032019-10-22 13:43:54 +040079 else:
stavrovska28772bc2024-05-22 09:33:50 +020080 headers["Content-Type"] = "application/json"
81 payload = bytes(json.dumps(data), "utf-8")
Ilya Menkovad234032019-10-22 13:43:54 +040082 response = requests.post(url, headers=headers, data=payload)
83 else:
stavrovska28772bc2024-05-22 09:33:50 +020084 headers["Content-Type"] = "application/json"
Ilya Menkovad234032019-10-22 13:43:54 +040085 response = requests.get(url, headers=headers)
86
87 if response.status_code > 201:
88 try:
89 error = response.json()
stavrovska28772bc2024-05-22 09:33:50 +020090 except Exception: # response.content not formatted as JSON
Ilya Menkovad234032019-10-22 13:43:54 +040091 error = str(response.content)
stavrovska28772bc2024-05-22 09:33:50 +020092 raise APIError(
93 "TestRail API returned HTTP %s (%s)"
94 % (response.status_code, error)
95 )
Ilya Menkovad234032019-10-22 13:43:54 +040096 else:
stavrovska28772bc2024-05-22 09:33:50 +020097 if uri[:15] == "get_attachment/": # Expecting file, not JSON
Ilya Menkovad234032019-10-22 13:43:54 +040098 try:
stavrovska28772bc2024-05-22 09:33:50 +020099 open(data, "wb").write(response.content)
100 return data
101 except Exception:
102 return "Error saving attachment."
Ilya Menkovad234032019-10-22 13:43:54 +0400103 else:
104 return response.json()
105
106
107class APIError(Exception):
stavrovska28772bc2024-05-22 09:33:50 +0200108 pass