trcli
Advanced tools
+1
-1
| Metadata-Version: 2.4 | ||
| Name: trcli | ||
| Version: 1.12.3 | ||
| Version: 1.12.4 | ||
| License-File: LICENSE.md | ||
@@ -5,0 +5,0 @@ Requires-Dist: click<8.2.2,>=8.1.0 |
+4
-4
@@ -36,3 +36,3 @@  | ||
| ``` | ||
| TestRail CLI v1.12.3 | ||
| TestRail CLI v1.12.4 | ||
| Copyright 2025 Gurock Software GmbH - www.gurock.com | ||
@@ -51,3 +51,3 @@ Supported and loaded modules: | ||
| $ trcli --help | ||
| TestRail CLI v1.12.3 | ||
| TestRail CLI v1.12.4 | ||
| Copyright 2025 Gurock Software GmbH - www.gurock.com | ||
@@ -1099,3 +1099,3 @@ Usage: trcli [OPTIONS] COMMAND [ARGS]... | ||
| $ trcli add_run --help | ||
| TestRail CLI v1.12.3 | ||
| TestRail CLI v1.12.4 | ||
| Copyright 2025 Gurock Software GmbH - www.gurock.com | ||
@@ -1224,3 +1224,3 @@ Usage: trcli add_run [OPTIONS] | ||
| $ trcli parse_openapi --help | ||
| TestRail CLI v1.12.3 | ||
| TestRail CLI v1.12.4 | ||
| Copyright 2025 Gurock Software GmbH - www.gurock.com | ||
@@ -1227,0 +1227,0 @@ Usage: trcli parse_openapi [OPTIONS] |
@@ -422,1 +422,37 @@ import pytest | ||
| assert headers.get("Content-Type") != "application/json" | ||
| @pytest.mark.api_client | ||
| def test_empty_response_is_valid(self, api_resources_maker, requests_mock): | ||
| """Test that empty response body with HTTP 200 is treated as valid (e.g., for DELETE operations).""" | ||
| api_client = api_resources_maker() | ||
| api_client.uploader_metadata = "test_metadata_value" | ||
| # DELETE operations may return empty body with HTTP 200 | ||
| requests_mock.post(create_url("delete_section/123"), status_code=200, content=b"") | ||
| response = api_client.send_post("delete_section/123") | ||
| # Verify that the request was made only once (no retry) | ||
| assert requests_mock.call_count == 1 | ||
| # Verify successful response with empty dict | ||
| check_response(200, {}, "", response) | ||
| @pytest.mark.api_client | ||
| def test_metadata_header_sent_when_enabled(self, api_resources_maker, requests_mock): | ||
| """Test that X-Uploader-Metadata header is sent when enabled.""" | ||
| api_client = api_resources_maker() | ||
| test_metadata = "test_metadata_value" | ||
| api_client.uploader_metadata = test_metadata | ||
| requests_mock.get(create_url("get_projects"), json=FAKE_PROJECT_DATA) | ||
| response = api_client.send_get("get_projects") | ||
| # Check that metadata header was sent | ||
| request_headers = requests_mock.last_request.headers | ||
| assert "X-Uploader-Metadata" in request_headers | ||
| assert request_headers["X-Uploader-Metadata"] == test_metadata | ||
| # Verify successful response | ||
| check_response(200, FAKE_PROJECT_DATA, "", response) |
| Metadata-Version: 2.4 | ||
| Name: trcli | ||
| Version: 1.12.3 | ||
| Version: 1.12.4 | ||
| License-File: LICENSE.md | ||
@@ -5,0 +5,0 @@ Requires-Dist: click<8.2.2,>=8.1.0 |
@@ -1,1 +0,1 @@ | ||
| __version__ = "1.12.3" | ||
| __version__ = "1.12.4" |
+44
-47
@@ -53,3 +53,3 @@ import json | ||
| verify: bool = True, | ||
| proxy: str = None, #added proxy params | ||
| proxy: str = None, # added proxy params | ||
| proxy_user: str = None, | ||
@@ -70,5 +70,5 @@ noproxy: str = None, | ||
| self.proxy_user = proxy_user | ||
| self.noproxy = noproxy.split(',') if noproxy else [] | ||
| self.uploader_metadata = uploader_metadata | ||
| self.noproxy = noproxy.split(",") if noproxy else [] | ||
| self.uploader_metadata = uploader_metadata | ||
| if not host_name.endswith("/"): | ||
@@ -90,3 +90,5 @@ host_name = host_name + "/" | ||
| def send_post(self, uri: str, payload: dict = None, files: Dict[str, Path] = None, as_form_data: bool = False) -> APIClientResult: | ||
| def send_post( | ||
| self, uri: str, payload: dict = None, files: Dict[str, Path] = None, as_form_data: bool = False | ||
| ) -> APIClientResult: | ||
| """ | ||
@@ -101,3 +103,5 @@ Sends POST request to host specified by host_name. | ||
| def __send_request(self, method: str, uri: str, payload: dict, files: Dict[str, Path] = None, as_form_data: bool = False) -> APIClientResult: | ||
| def __send_request( | ||
| self, method: str, uri: str, payload: dict, files: Dict[str, Path] = None, as_form_data: bool = False | ||
| ) -> APIClientResult: | ||
| status_code = -1 | ||
@@ -124,8 +128,8 @@ response_text = "" | ||
| request_kwargs = { | ||
| 'url': url, | ||
| 'auth': auth, | ||
| 'headers': headers, | ||
| 'timeout': self.timeout, | ||
| 'verify': self.verify, | ||
| 'proxies': proxies | ||
| "url": url, | ||
| "auth": auth, | ||
| "headers": headers, | ||
| "timeout": self.timeout, | ||
| "verify": self.verify, | ||
| "proxies": proxies, | ||
| } | ||
@@ -139,13 +143,13 @@ if files: | ||
| request_kwargs["json"] = payload | ||
| response = requests.post(**request_kwargs) | ||
| else: | ||
| response = requests.get( | ||
| url=url, | ||
| auth=auth, | ||
| json=payload, | ||
| timeout=self.timeout, | ||
| verify=self.verify, | ||
| url=url, | ||
| auth=auth, | ||
| json=payload, | ||
| timeout=self.timeout, | ||
| verify=self.verify, | ||
| headers=headers, | ||
| proxies=proxies | ||
| proxies=proxies, | ||
| ) | ||
@@ -173,5 +177,3 @@ except InvalidProxyURL: | ||
| except RequestException as e: | ||
| error_message = FAULT_MAPPING[ | ||
| "unexpected_error_during_request_send" | ||
| ].format(request=e.request) | ||
| error_message = FAULT_MAPPING["unexpected_error_during_request_send"].format(request=e.request) | ||
| self.verbose_logging_function(verbose_log_message) | ||
@@ -193,15 +195,16 @@ break | ||
| except (JSONDecodeError, ValueError): | ||
| response_preview = response.content[:200].decode('utf-8', errors='ignore') | ||
| response_text = str(response.content) | ||
| error_message = FAULT_MAPPING["invalid_json_response"].format( | ||
| status_code=status_code, | ||
| response_preview=response_preview | ||
| ) | ||
| if len(response.content) == 0: | ||
| # Empty response with HTTP 200 is valid for certain operations like delete | ||
| response_text = {} | ||
| error_message = "" | ||
| else: | ||
| response_preview = response.content[:200].decode("utf-8", errors="ignore") | ||
| response_text = str(response.content) | ||
| error_message = FAULT_MAPPING["invalid_json_response"].format( | ||
| status_code=status_code, response_preview=response_preview | ||
| ) | ||
| except AttributeError: | ||
| error_message = "" | ||
| verbose_log_message = ( | ||
| verbose_log_message | ||
| + APIClient.format_response_for_vlog( | ||
| response.status_code, response_text | ||
| ) | ||
| verbose_log_message = verbose_log_message + APIClient.format_response_for_vlog( | ||
| response.status_code, response_text | ||
| ) | ||
@@ -222,3 +225,3 @@ if verbose_log_message: | ||
| if self.proxy_user: | ||
| user_pass_encoded = b64encode(self.proxy_user.encode('utf-8')).decode('utf-8') | ||
| user_pass_encoded = b64encode(self.proxy_user.encode("utf-8")).decode("utf-8") | ||
@@ -255,5 +258,5 @@ # Add Proxy-Authorization header | ||
| if self.noproxy: | ||
| # Ensure noproxy is a list or tuple | ||
| # Ensure noproxy is a list or tuple | ||
| if isinstance(self.noproxy, str): | ||
| self.noproxy = self.noproxy.split(',') | ||
| self.noproxy = self.noproxy.split(",") | ||
| if host in self.noproxy: | ||
@@ -267,3 +270,3 @@ print(f"Bypassing proxy for host: {host}") | ||
| #print(f"Parsed URL: {url}, Proxy: {self.proxy} , NoProxy: {self.noproxy}") | ||
| # print(f"Parsed URL: {url}, Proxy: {self.proxy} , NoProxy: {self.noproxy}") | ||
@@ -277,11 +280,9 @@ # Define the proxy dictionary | ||
| "http": self.proxy, # Use HTTP proxy for HTTP traffic | ||
| "https": self.proxy # Also use HTTP proxy for HTTPS traffic | ||
| "https": self.proxy, # Also use HTTP proxy for HTTPS traffic | ||
| } | ||
| else: | ||
| # If the proxy is HTTPS, route accordingly | ||
| proxy_dict = { | ||
| scheme: self.proxy # Match the proxy scheme with the target URL scheme | ||
| } | ||
| proxy_dict = {scheme: self.proxy} # Match the proxy scheme with the target URL scheme | ||
| #print(f"Using proxy: {proxy_dict}") | ||
| # print(f"Using proxy: {proxy_dict}") | ||
| return proxy_dict | ||
@@ -331,7 +332,3 @@ | ||
| def format_request_for_vlog(method: str, url: str, payload: dict, headers: dict = None): | ||
| log_message = ( | ||
| f"\n**** API Call\n" | ||
| f"method: {method}\n" | ||
| f"url: {url}\n" | ||
| ) | ||
| log_message = f"\n**** API Call\n" f"method: {method}\n" f"url: {url}\n" | ||
| if headers: | ||
@@ -338,0 +335,0 @@ log_message += "headers:\n" |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
616972
0.26%11363
0.2%