clarity-api-sdk-python 0.1.0__tar.gz → 0.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clarity-api-sdk-python
3
- Version: 0.1.0
4
- Summary: A Python SDK to connect to the CTI API server.
3
+ Version: 0.1.4
4
+ Summary: A Python SDK to connect to the CTI Clarity API server.
5
5
  Author-email: "Chesapeake Technology Inc." <support@chesapeaketech.com>
6
6
  Project-URL: Homepage, https://github.com/chesapeake-tech/clarity-api-sdk-python
7
7
  Classifier: Programming Language :: Python :: 3
@@ -9,7 +9,16 @@ Classifier: License :: OSI Approved :: MIT License
9
9
  Classifier: Operating System :: OS Independent
10
10
  Requires-Python: >=3.12
11
11
  Description-Content-Type: text/markdown
12
+ Requires-Dist: httpx>=0.28.1
13
+ Requires-Dist: brotli
14
+ Requires-Dist: h2
15
+ Requires-Dist: httpx_auth>=0.23.1
16
+ Requires-Dist: httpx-retries>=0.4.5
12
17
  Requires-Dist: structlog
18
+ Provides-Extra: brotli
19
+ Requires-Dist: httpx[brotli]>=0.28.1; extra == "brotli"
20
+ Provides-Extra: http2
21
+ Requires-Dist: httpx[http2]>=0.28.1; extra == "http2"
13
22
 
14
23
  # Clarity API SDK for Python
15
24
 
@@ -5,11 +5,11 @@ build-backend = "setuptools.build_meta"
5
5
 
6
6
  [project]
7
7
  name = "clarity-api-sdk-python"
8
- version = "0.1.0"
8
+ version = "0.1.4"
9
9
  authors = [
10
10
  { name="Chesapeake Technology Inc.", email="support@chesapeaketech.com" },
11
11
  ]
12
- description = "A Python SDK to connect to the CTI API server."
12
+ description = "A Python SDK to connect to the CTI Clarity API server."
13
13
  readme = "README.md"
14
14
  requires-python = ">=3.12"
15
15
  classifiers = [
@@ -18,9 +18,18 @@ classifiers = [
18
18
  "Operating System :: OS Independent",
19
19
  ]
20
20
  dependencies = [
21
+ "httpx>=0.28.1",
22
+ "brotli",
23
+ "h2",
24
+ "httpx_auth>=0.23.1",
25
+ "httpx-retries>=0.4.5",
21
26
  "structlog",
22
27
  ]
23
28
 
29
+ [project.optional-dependencies]
30
+ brotli = ["httpx[brotli]>=0.28.1"]
31
+ http2 = ["httpx[http2]>=0.28.1"]
32
+
24
33
  [project.urls]
25
34
  "Homepage" = "https://github.com/chesapeake-tech/clarity-api-sdk-python"
26
35
 
@@ -0,0 +1,3 @@
1
+ """API client"""
2
+
3
+ from .client import ClarityApiClient
@@ -0,0 +1,124 @@
1
+ """client for clarity API"""
2
+
3
+ import os
4
+ import uuid
5
+
6
+ from httpx import Client, HTTPStatusError, RequestError, Response, URL
7
+ from httpx_auth import OAuth2ClientCredentials, OAuth2, TokenMemoryCache
8
+ from httpx_retries import Retry, RetryTransport
9
+
10
+ from logger import get_logger
11
+
12
+ logger = get_logger(__name__)
13
+ OAuth2.token_cache = TokenMemoryCache()
14
+
15
+
16
+ class ClarityApiClient(Client):
17
+ """Client for Clarity API configured with OAuth2 authentication, retry mechanism
18
+ and other defaults to connect to the clarity server.
19
+
20
+ Reuse this client instance for multiple requests for faster performance.
21
+ """
22
+
23
+ def __init__(self):
24
+
25
+ # credentials for Clarity API
26
+ cti_credentials = OAuth2ClientCredentials(
27
+ token_url=(
28
+ f'{os.environ.get("KEYCLOAK_SERVER_URL", "missing KEYCLOAK_SERVER_URL")}/realms/'
29
+ f'{os.environ.get("KEYCLOAK_REALM", "missing KEYCLOAK_REALM")}'
30
+ "/protocol/openid-connect/token"
31
+ ),
32
+ client_id=os.environ.get(
33
+ "KEYCLOAK_CLIENT_ID", "missing KEYCLOAK_CLIENT_ID"
34
+ ),
35
+ client_secret=os.environ.get(
36
+ "KEYCLOAK_CLIENT_SECRET", "missing KEYCLOAK_CLIENT_SECRET"
37
+ ),
38
+ )
39
+
40
+ # retry mechanism for API requests
41
+ retry = Retry(total=12, backoff_factor=0.5)
42
+ transport = RetryTransport(retry=retry)
43
+
44
+ super().__init__(
45
+ base_url=os.environ.get("CLARITY_API_URL", "missing Clarity_API_URL"),
46
+ auth=cti_credentials,
47
+ timeout=60,
48
+ transport=transport,
49
+ http2=True,
50
+ headers={"Accept": "application/json"},
51
+ )
52
+
53
+ def request(self, method: str, url: URL | str, **kwargs) -> Response:
54
+ """Make a request to the Clarity API and handle exceptions.
55
+
56
+ The exceptions are caught and logged, and then re-raised.
57
+
58
+ Args:
59
+ method: HTTP method (GET, POST, PUT, DELETE, etc.)
60
+ url: relative URL for the request, eg: "/api/v1/projects/12345"
61
+ kwargs: additional keyword arguments to be passed to the request
62
+
63
+ Returns:
64
+ httpx.Response: Response from the API
65
+
66
+ Raises:
67
+ RequestError: If there was an issue with the request
68
+ HTTPStatusError: If the response status code is not in the 2xx range
69
+ Exception: For any other uncaught exception
70
+ """
71
+ try:
72
+ request_id = str(uuid.uuid4())
73
+ if "headers" not in kwargs or kwargs["headers"] is None:
74
+ kwargs["headers"] = {}
75
+ # append x-request-id header to the kwargs "headers"
76
+ kwargs["headers"].update({"x-request-id": request_id})
77
+ logger.info(
78
+ "request",
79
+ extra={"url": url, "request_id": request_id},
80
+ )
81
+ # make the actual request and return the response
82
+ response = super().request(method, url, **kwargs)
83
+ # raise an exception if the response status is not in the 2xx range
84
+ response.raise_for_status()
85
+ logger.info(
86
+ "response",
87
+ extra={
88
+ "request_id": request_id,
89
+ "response": {"status_code": response.status_code},
90
+ },
91
+ )
92
+ return response
93
+ except HTTPStatusError as e:
94
+ logger.error(
95
+ "http",
96
+ extra={
97
+ "request": {
98
+ "method": e.request.method,
99
+ "url": str(e.request.url),
100
+ "headers": dict(e.request.headers),
101
+ },
102
+ "error": {
103
+ "message": str(e.response.content),
104
+ "status_code": e.response.status_code,
105
+ "headers": dict(e.response.headers),
106
+ },
107
+ },
108
+ )
109
+ raise e
110
+ except RequestError as e:
111
+ logger.error(
112
+ "request",
113
+ extra={
114
+ "request": {
115
+ "method": e.request.method,
116
+ "url": str(e.request.url),
117
+ "headers": dict(e.request.headers),
118
+ },
119
+ "error": {
120
+ "message": str(e),
121
+ },
122
+ },
123
+ )
124
+ raise e
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clarity-api-sdk-python
3
- Version: 0.1.0
4
- Summary: A Python SDK to connect to the CTI API server.
3
+ Version: 0.1.4
4
+ Summary: A Python SDK to connect to the CTI Clarity API server.
5
5
  Author-email: "Chesapeake Technology Inc." <support@chesapeaketech.com>
6
6
  Project-URL: Homepage, https://github.com/chesapeake-tech/clarity-api-sdk-python
7
7
  Classifier: Programming Language :: Python :: 3
@@ -9,7 +9,16 @@ Classifier: License :: OSI Approved :: MIT License
9
9
  Classifier: Operating System :: OS Independent
10
10
  Requires-Python: >=3.12
11
11
  Description-Content-Type: text/markdown
12
+ Requires-Dist: httpx>=0.28.1
13
+ Requires-Dist: brotli
14
+ Requires-Dist: h2
15
+ Requires-Dist: httpx_auth>=0.23.1
16
+ Requires-Dist: httpx-retries>=0.4.5
12
17
  Requires-Dist: structlog
18
+ Provides-Extra: brotli
19
+ Requires-Dist: httpx[brotli]>=0.28.1; extra == "brotli"
20
+ Provides-Extra: http2
21
+ Requires-Dist: httpx[http2]>=0.28.1; extra == "http2"
13
22
 
14
23
  # Clarity API SDK for Python
15
24
 
@@ -1,5 +1,7 @@
1
1
  README.md
2
2
  pyproject.toml
3
+ src/api/__init__.py
4
+ src/api/client.py
3
5
  src/clarity_api_sdk_python.egg-info/PKG-INFO
4
6
  src/clarity_api_sdk_python.egg-info/SOURCES.txt
5
7
  src/clarity_api_sdk_python.egg-info/dependency_links.txt
@@ -0,0 +1,12 @@
1
+ httpx>=0.28.1
2
+ brotli
3
+ h2
4
+ httpx_auth>=0.23.1
5
+ httpx-retries>=0.4.5
6
+ structlog
7
+
8
+ [brotli]
9
+ httpx[brotli]>=0.28.1
10
+
11
+ [http2]
12
+ httpx[http2]>=0.28.1
@@ -0,0 +1,3 @@
1
+ """import modules"""
2
+
3
+ from .logger import get_logger, initialize_logger, ExternalLoggerConfig # noqa
@@ -5,7 +5,6 @@ from dataclasses import dataclass
5
5
  import logging
6
6
  import socket
7
7
  import sys
8
- from typing import Optional
9
8
  import urllib.error
10
9
  import urllib.request
11
10
 
@@ -167,8 +166,8 @@ def _secret_redaction_processor(_, __, event_dict):
167
166
 
168
167
 
169
168
  def initialize_logger(
170
- initial_context: Optional[dict] = None,
171
- external_logger_configurations: Optional[list[ExternalLoggerConfig]] = None,
169
+ initial_context: dict | None = None,
170
+ external_logger_configurations: list[ExternalLoggerConfig] | None = None,
172
171
  ) -> None:
173
172
  """Configures logging for the application using structlog.
174
173
 
@@ -1,3 +0,0 @@
1
- """import modules"""
2
-
3
- from .logger import get_logger, initialize_logger # noqa