Skip to content

Commit 0a604a9

Browse files
Python cleanup (#60)
1 parent 6870d9c commit 0a604a9

File tree

8 files changed

+131
-107
lines changed

8 files changed

+131
-107
lines changed

shared/python/apimrequests.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class ApimRequests:
2525
# CONSTRUCTOR
2626
# ------------------------------
2727

28-
def __init__(self, url: str, apimSubscriptionKey: str | None = None):
28+
def __init__(self, url: str, apimSubscriptionKey: str | None = None) -> None:
2929
"""
3030
Initialize the ApimRequests object.
3131
@@ -43,6 +43,10 @@ def __init__(self, url: str, apimSubscriptionKey: str | None = None):
4343

4444
self._headers['Accept'] = 'application/json'
4545

46+
# ------------------------------
47+
# PROPERTIES
48+
# ------------------------------
49+
4650
@property
4751
def headers(self) -> dict[str, str]:
4852
"""
@@ -177,7 +181,7 @@ def _multiRequest(self, method: HTTP_VERB, path: str, runs: int, headers: list[a
177181

178182
return api_runs
179183

180-
def _print_response(self, response):
184+
def _print_response(self, response) -> None:
181185
"""
182186
Print the response headers and body with appropriate formatting.
183187
"""
@@ -194,7 +198,7 @@ def _print_response(self, response):
194198
else:
195199
utils.print_val("Response body", response.text, True)
196200

197-
def _print_response_code(self, response):
201+
def _print_response_code(self, response) -> None:
198202
"""
199203
Print the response status code with color formatting.
200204
"""
@@ -213,7 +217,7 @@ def _print_response_code(self, response):
213217
# PUBLIC METHODS
214218
# ------------------------------
215219

216-
def singleGet(self, path: str, headers = None, msg: str | None = None, printResponse = True) -> Any:
220+
def singleGet(self, path: str, headers = None, msg: str | None = None, printResponse: bool = True) -> Any:
217221
"""
218222
Make a GET request to the Azure API Management service.
219223
@@ -228,7 +232,7 @@ def singleGet(self, path: str, headers = None, msg: str | None = None, printResp
228232

229233
return self._request(method = HTTP_VERB.GET, path = path, headers = headers, msg = msg, printResponse = printResponse)
230234

231-
def singlePost(self, path: str, *, headers = None, data = None, msg: str | None = None, printResponse = True) -> Any:
235+
def singlePost(self, path: str, *, headers = None, data = None, msg: str | None = None, printResponse: bool = True) -> Any:
232236
"""
233237
Make a POST request to the Azure API Management service.
234238
@@ -244,7 +248,7 @@ def singlePost(self, path: str, *, headers = None, data = None, msg: str | None
244248

245249
return self._request(method = HTTP_VERB.POST, path = path, headers = headers, data = data, msg = msg, printResponse = printResponse)
246250

247-
def multiGet(self, path: str, runs: int, headers = None, data = None, msg: str | None = None, printResponse = True, sleepMs: int | None = None) -> list[dict[str, Any]]:
251+
def multiGet(self, path: str, runs: int, headers = None, data = None, msg: str | None = None, printResponse: bool = True, sleepMs: int | None = None) -> list[dict[str, Any]]:
248252
"""
249253
Make multiple GET requests to the Azure API Management service.
250254

shared/python/apimtesting.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,38 @@
11
"""
2-
Rudimentary test "framework" to offload validations from the Jupyter notebooks.
2+
Rudimentary test framework to offload validations from the Jupyter notebooks.
33
"""
44

5+
6+
# ------------------------------
7+
# CLASSES
8+
# ------------------------------
9+
510
class ApimTesting:
6-
def __init__(self, test_suite_name: str = 'APIM Tests'):
11+
"""
12+
A simple test framework for validating APIM deployments and configurations.
13+
"""
14+
15+
# ------------------------------
16+
# CONSTRUCTOR
17+
# ------------------------------
18+
19+
def __init__(self, test_suite_name: str = 'APIM Tests') -> None:
20+
"""
21+
Initialize the ApimTesting instance.
22+
23+
Args:
24+
test_suite_name (str, optional): The name of the test suite. Defaults to 'APIM Tests'.
25+
"""
726
self.test_suite_name = test_suite_name
827
self.tests_passed = 0
928
self.tests_failed = 0
1029
self.total_tests = 0
1130
self.errors = []
31+
32+
33+
# ------------------------------
34+
# PUBLIC METHODS
35+
# ------------------------------
1236

1337
def verify(self, value: any, expected: any) -> bool:
1438
"""
@@ -19,22 +43,23 @@ def verify(self, value: any, expected: any) -> bool:
1943
expected: The expected value to match
2044
2145
Returns:
22-
True, if the assertion passes; otherwise, false.
46+
bool: True, if the assertion passes; otherwise, False.
2347
"""
24-
2548
try:
2649
self.total_tests += 1
2750
assert value == expected, f'Value [{value}] does not match expected [{expected}]'
2851
self.tests_passed += 1
2952
print(f"✅ Test {self.total_tests}: PASS")
53+
3054
return True
3155
except AssertionError as e:
3256
self.tests_failed += 1
3357
self.errors.append(f'{str(e)}')
3458
print(f"❌ Test {self.total_tests}: FAIL - {str(e)}")
59+
3560
return False
3661

37-
def print_summary(self):
62+
def print_summary(self) -> None:
3863
"""
3964
Print a summary of the test results with visual flair and comprehensive details.
4065

shared/python/apimtypes.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
# ------------------------------
13-
# CONSTANTS
13+
# PRIVATE METHODS
1414
# ------------------------------
1515

1616
def _get_project_root() -> Path:
@@ -204,7 +204,7 @@ class APIOperation:
204204
# CONSTRUCTOR
205205
# ------------------------------
206206

207-
def __init__(self, name: str, displayName: str, urlTemplate: str, method: HTTP_VERB, description: str, policyXml: Optional[str] = None, templateParameters: Optional[List[dict[str, Any]]] = None):
207+
def __init__(self, name: str, displayName: str, urlTemplate: str, method: HTTP_VERB, description: str, policyXml: Optional[str] = None, templateParameters: Optional[List[dict[str, Any]]] = None) -> None:
208208
# Validate that method is a valid HTTP_VERB
209209
if not isinstance(method, HTTP_VERB):
210210
try:
@@ -241,6 +241,7 @@ class GET_APIOperation(APIOperation):
241241
"""
242242
Represents a simple GET operation within a parent API.
243243
"""
244+
244245
# ------------------------------
245246
# CONSTRUCTOR
246247
# ------------------------------
@@ -254,11 +255,12 @@ class GET_APIOperation2(APIOperation):
254255
"""
255256
Represents a GET operation within a parent API.
256257
"""
258+
257259
# ------------------------------
258260
# CONSTRUCTOR
259261
# ------------------------------
260262

261-
def __init__(self, name: str, displayName: str, urlTemplate: str, description: str, policyXml: Optional[str] = None, templateParameters: Optional[List[dict[str, Any]]] = None):
263+
def __init__(self, name: str, displayName: str, urlTemplate: str, description: str, policyXml: Optional[str] = None, templateParameters: Optional[List[dict[str, Any]]] = None) -> None:
262264
super().__init__(name, displayName, urlTemplate, HTTP_VERB.GET, description, policyXml, templateParameters)
263265

264266

@@ -267,11 +269,12 @@ class POST_APIOperation(APIOperation):
267269
"""
268270
Represents a simple POST operation within a parent API.
269271
"""
272+
270273
# ------------------------------
271274
# CONSTRUCTOR
272275
# ------------------------------
273276

274-
def __init__(self, description: str, policyXml: Optional[str] = None, templateParameters: Optional[List[dict[str, Any]]] = None):
277+
def __init__(self, description: str, policyXml: Optional[str] = None, templateParameters: Optional[List[dict[str, Any]]] = None) -> None:
275278
super().__init__('POST', 'POST', '/', HTTP_VERB.POST, description, policyXml, templateParameters)
276279

277280

@@ -289,7 +292,7 @@ class NamedValue:
289292
# CONSTRUCTOR
290293
# ------------------------------
291294

292-
def __init__(self, name: str, value: str, isSecret: bool = False):
295+
def __init__(self, name: str, value: str, isSecret: bool = False) -> None:
293296
self.name = name
294297
self.value = value
295298
self.isSecret = isSecret
@@ -307,6 +310,7 @@ def to_dict(self) -> dict:
307310
}
308311

309312
return nv_dict
313+
310314

311315
@dataclass
312316
class PolicyFragment:
@@ -322,7 +326,7 @@ class PolicyFragment:
322326
# CONSTRUCTOR
323327
# ------------------------------
324328

325-
def __init__(self, name: str, policyXml: str, description: str = ''):
329+
def __init__(self, name: str, policyXml: str, description: str = '') -> None:
326330
self.name = name
327331
self.policyXml = policyXml
328332
self.description = description
@@ -362,7 +366,7 @@ class Product:
362366
# CONSTRUCTOR
363367
# ------------------------------
364368

365-
def __init__(self, name: str, displayName: str, description: str, state: str = 'published', subscriptionRequired: bool = True, approvalRequired: bool = False, policyXml: Optional[str] = None):
369+
def __init__(self, name: str, displayName: str, description: str, state: str = 'published', subscriptionRequired: bool = True, approvalRequired: bool = False, policyXml: Optional[str] = None) -> None:
366370
self.name = name
367371
self.displayName = displayName
368372
self.description = description
@@ -391,6 +395,7 @@ def __init__(self, name: str, displayName: str, description: str, state: str = '
391395
</policies>"""
392396
else:
393397
self.policyXml = policyXml
398+
394399
# ------------------------------
395400
# PUBLIC METHODS
396401
# ------------------------------
@@ -408,4 +413,4 @@ def to_dict(self) -> dict:
408413
if self.policyXml is not None:
409414
product_dict["policyXml"] = self.policyXml
410415

411-
return product_dict
416+
return product_dict

shared/python/authfactory.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,33 @@ class JwtPayload:
1818
https://datatracker.ietf.org/doc/html/rfc7519
1919
"""
2020

21+
# ------------------------------
22+
# CONSTANTS
23+
# ------------------------------
24+
2125
DEFAULT_LIFETIME_SECONDS = 3600 * 24 # Default lifetime of 24 hours
2226

27+
28+
# ------------------------------
29+
# CONSTRUCTOR
30+
# ------------------------------
31+
2332
def __init__(self, subject: str, name: str, issued_at: int | None = None, expires: int | None = None, roles: dict[str] | None = None) -> None:
2433
self.sub = subject
2534
self.name = name
2635
self.iat = issued_at if issued_at is not None else int(time.time())
2736
self.exp = expires if expires is not None else self.iat + self.DEFAULT_LIFETIME_SECONDS
2837
self.roles = roles if roles is not None else []
2938

39+
40+
# ------------------------------
41+
# PUBLIC METHODS
42+
# ------------------------------
43+
3044
def to_dict(self) -> dict[str, Any]:
3145
"""
3246
Convert the payload to a dictionary for encoding.
3347
"""
34-
3548
pl: dict[str, Any] = {
3649
"sub": self.sub,
3750
"name": self.name,
@@ -44,13 +57,18 @@ def to_dict(self) -> dict[str, Any]:
4457

4558
return pl
4659

60+
4761
class SymmetricJwtToken:
4862
"""
4963
Represents a JSON Web Token using a symmetric signing algorithm (HS256) for APIM testing.
5064
This is a simple implementation for demonstration purposes as it uses a shared secret key
5165
for the token creation and verification. This is not production-ready code.
5266
"""
5367

68+
# ------------------------------
69+
# CONSTRUCTOR
70+
# ------------------------------
71+
5472
def __init__(self, key: str, payload: JwtPayload) -> None:
5573
"""
5674
Initialize the SymmetricJwtToken with a signing key and payload.
@@ -62,6 +80,11 @@ def __init__(self, key: str, payload: JwtPayload) -> None:
6280
self.key = key
6381
self.payload = payload
6482

83+
84+
# ------------------------------
85+
# PUBLIC METHODS
86+
# ------------------------------
87+
6588
def encode(self) -> str:
6689
"""
6790
Encode the JWT token using the provided key and payload.
@@ -73,12 +96,17 @@ def encode(self) -> str:
7396
The key parameter used for signing must be a regular ASCII string, NOT a base64-encoded string. If you have a base64-encoded key, decode it to its ASCII form before using it here. Passing a base64-encoded string directly will result in signature validation errors in APIM or other JWT consumers.
7497
"""
7598
return jwt.encode(self.payload.to_dict(), self.key, algorithm = "HS256")
99+
76100

77101
class AuthFactory:
78102
"""
79103
Factory class for creating authentication tokens or objects.
80104
"""
81105

106+
# ------------------------------
107+
# PUBLIC METHODS
108+
# ------------------------------
109+
82110
@staticmethod
83111
def create_symmetric_jwt_token_for_user(user: User, jwt_key: str) -> str:
84112
if not user:

shared/python/charts.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,44 @@ class BarChart(object):
2222
Class for creating bar charts with colored bars based on backend indexes.
2323
"""
2424

25-
def __init__(self, title: str, x_label: str, y_label: str, api_results: list[dict], fig_text: str = None):
25+
# ------------------------------
26+
# CONSTRUCTOR
27+
# ------------------------------
28+
29+
def __init__(self, title: str, x_label: str, y_label: str, api_results: list[dict], fig_text: str = None) -> None:
2630
"""
2731
Initialize the BarChart with API results.
2832
2933
Args:
34+
title (str): The title of the chart.
35+
x_label (str): The label for the x-axis.
36+
y_label (str): The label for the y-axis.
3037
api_results (list[dict]): List of API result dictionaries.
38+
fig_text (str, optional): Additional figure text to display. Defaults to None.
3139
"""
32-
3340
self.title = title
3441
self.x_label = x_label
3542
self.y_label = y_label
3643
self.api_results = api_results
3744
self.fig_text = fig_text
3845

39-
def plot(self):
46+
47+
# ------------------------------
48+
# PUBLIC METHODS
49+
# ------------------------------
50+
51+
def plot(self) -> None:
4052
"""
4153
Plot the bar chart based on the provided API results.
4254
"""
4355
self._plot_barchart(self.api_results)
4456

45-
def _plot_barchart(self, api_results: list[dict]):
57+
58+
# ------------------------------
59+
# PRIVATE METHODS
60+
# ------------------------------
61+
62+
def _plot_barchart(self, api_results: list[dict]) -> None:
4663
"""
4764
Internal method to plot the bar chart.
4865

0 commit comments

Comments
 (0)