stabilize 0.9.2__py3-none-any.whl

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.
Files changed (61) hide show
  1. stabilize/__init__.py +29 -0
  2. stabilize/cli.py +1193 -0
  3. stabilize/context/__init__.py +7 -0
  4. stabilize/context/stage_context.py +170 -0
  5. stabilize/dag/__init__.py +15 -0
  6. stabilize/dag/graph.py +215 -0
  7. stabilize/dag/topological.py +199 -0
  8. stabilize/examples/__init__.py +1 -0
  9. stabilize/examples/docker-example.py +759 -0
  10. stabilize/examples/golden-standard-expected-result.txt +1 -0
  11. stabilize/examples/golden-standard.py +488 -0
  12. stabilize/examples/http-example.py +606 -0
  13. stabilize/examples/llama-example.py +662 -0
  14. stabilize/examples/python-example.py +731 -0
  15. stabilize/examples/shell-example.py +399 -0
  16. stabilize/examples/ssh-example.py +603 -0
  17. stabilize/handlers/__init__.py +53 -0
  18. stabilize/handlers/base.py +226 -0
  19. stabilize/handlers/complete_stage.py +209 -0
  20. stabilize/handlers/complete_task.py +75 -0
  21. stabilize/handlers/complete_workflow.py +150 -0
  22. stabilize/handlers/run_task.py +369 -0
  23. stabilize/handlers/start_stage.py +262 -0
  24. stabilize/handlers/start_task.py +74 -0
  25. stabilize/handlers/start_workflow.py +136 -0
  26. stabilize/launcher.py +307 -0
  27. stabilize/migrations/01KDQ4N9QPJ6Q4MCV3V9GHWPV4_initial_schema.sql +97 -0
  28. stabilize/migrations/01KDRK3TXW4R2GERC1WBCQYJGG_rag_embeddings.sql +25 -0
  29. stabilize/migrations/__init__.py +1 -0
  30. stabilize/models/__init__.py +15 -0
  31. stabilize/models/stage.py +389 -0
  32. stabilize/models/status.py +146 -0
  33. stabilize/models/task.py +125 -0
  34. stabilize/models/workflow.py +317 -0
  35. stabilize/orchestrator.py +113 -0
  36. stabilize/persistence/__init__.py +28 -0
  37. stabilize/persistence/connection.py +185 -0
  38. stabilize/persistence/factory.py +136 -0
  39. stabilize/persistence/memory.py +214 -0
  40. stabilize/persistence/postgres.py +655 -0
  41. stabilize/persistence/sqlite.py +674 -0
  42. stabilize/persistence/store.py +235 -0
  43. stabilize/queue/__init__.py +59 -0
  44. stabilize/queue/messages.py +377 -0
  45. stabilize/queue/processor.py +312 -0
  46. stabilize/queue/queue.py +526 -0
  47. stabilize/queue/sqlite_queue.py +354 -0
  48. stabilize/rag/__init__.py +19 -0
  49. stabilize/rag/assistant.py +459 -0
  50. stabilize/rag/cache.py +294 -0
  51. stabilize/stages/__init__.py +11 -0
  52. stabilize/stages/builder.py +253 -0
  53. stabilize/tasks/__init__.py +19 -0
  54. stabilize/tasks/interface.py +335 -0
  55. stabilize/tasks/registry.py +255 -0
  56. stabilize/tasks/result.py +283 -0
  57. stabilize-0.9.2.dist-info/METADATA +301 -0
  58. stabilize-0.9.2.dist-info/RECORD +61 -0
  59. stabilize-0.9.2.dist-info/WHEEL +4 -0
  60. stabilize-0.9.2.dist-info/entry_points.txt +2 -0
  61. stabilize-0.9.2.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,606 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ HTTP Example - Demonstrates making HTTP requests with Stabilize.
4
+
5
+ This example shows how to:
6
+ 1. Create a custom Task that makes HTTP requests
7
+ 2. Support all HTTP methods (GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH)
8
+ 3. Build workflows with API interactions
9
+
10
+ Requirements:
11
+ None (uses urllib from standard library)
12
+
13
+ Run with:
14
+ python examples/http-example.py
15
+ """
16
+
17
+ import json
18
+ import logging
19
+ import ssl
20
+ import time
21
+ import urllib.error
22
+ import urllib.request
23
+ from typing import Any
24
+
25
+ logging.basicConfig(level=logging.ERROR)
26
+
27
+ from stabilize import StageExecution, TaskExecution, Workflow
28
+ from stabilize.handlers.complete_stage import CompleteStageHandler
29
+ from stabilize.handlers.complete_task import CompleteTaskHandler
30
+ from stabilize.handlers.complete_workflow import CompleteWorkflowHandler
31
+ from stabilize.handlers.run_task import RunTaskHandler
32
+ from stabilize.handlers.start_stage import StartStageHandler
33
+ from stabilize.handlers.start_task import StartTaskHandler
34
+ from stabilize.handlers.start_workflow import StartWorkflowHandler
35
+ from stabilize.orchestrator import Orchestrator
36
+ from stabilize.persistence.sqlite import SqliteWorkflowStore
37
+ from stabilize.persistence.store import WorkflowStore
38
+ from stabilize.queue.processor import QueueProcessor
39
+ from stabilize.queue.queue import Queue
40
+ from stabilize.queue.sqlite_queue import SqliteQueue
41
+ from stabilize.tasks.interface import Task
42
+ from stabilize.tasks.registry import TaskRegistry
43
+ from stabilize.tasks.result import TaskResult
44
+
45
+ # =============================================================================
46
+ # Custom Task: HTTPTask
47
+ # =============================================================================
48
+
49
+
50
+ class HTTPTask(Task):
51
+ """
52
+ Make HTTP requests.
53
+
54
+ Context Parameters:
55
+ url: Request URL (required)
56
+ method: HTTP method - GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH (default: GET)
57
+ headers: Request headers as dict (optional)
58
+ body: Request body as string (optional)
59
+ json_body: Request body as dict, auto-serialized to JSON (optional)
60
+ timeout: Request timeout in seconds (default: 30)
61
+ verify_ssl: Verify SSL certificates (default: True)
62
+ expected_status: Expected status code, fails if mismatch (optional)
63
+
64
+ Outputs:
65
+ status_code: HTTP status code
66
+ headers: Response headers as dict
67
+ body: Response body as string
68
+ elapsed_ms: Request duration in milliseconds
69
+ url: Final URL (after redirects)
70
+ """
71
+
72
+ SUPPORTED_METHODS = {"GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"}
73
+
74
+ def execute(self, stage: StageExecution) -> TaskResult:
75
+ url = stage.context.get("url")
76
+ method = stage.context.get("method", "GET").upper()
77
+ headers = stage.context.get("headers", {})
78
+ body = stage.context.get("body")
79
+ json_body = stage.context.get("json_body")
80
+ timeout = stage.context.get("timeout", 30)
81
+ verify_ssl = stage.context.get("verify_ssl", True)
82
+ expected_status = stage.context.get("expected_status")
83
+
84
+ if not url:
85
+ return TaskResult.terminal(error="No 'url' specified in context")
86
+
87
+ if method not in self.SUPPORTED_METHODS:
88
+ return TaskResult.terminal(error=f"Unsupported method '{method}'. Supported: {self.SUPPORTED_METHODS}")
89
+
90
+ # Handle JSON body
91
+ if json_body is not None:
92
+ body = json.dumps(json_body)
93
+ headers.setdefault("Content-Type", "application/json")
94
+
95
+ # Encode body if present
96
+ data = body.encode("utf-8") if body else None
97
+
98
+ # Build request
99
+ request = urllib.request.Request(url, data=data, headers=headers, method=method)
100
+
101
+ # SSL context
102
+ ssl_context = None
103
+ if not verify_ssl:
104
+ ssl_context = ssl.create_default_context()
105
+ ssl_context.check_hostname = False
106
+ ssl_context.verify_mode = ssl.CERT_NONE
107
+
108
+ print(f" [HTTPTask] {method} {url}")
109
+
110
+ try:
111
+ start_time = time.time()
112
+ with urllib.request.urlopen(request, timeout=timeout, context=ssl_context) as response:
113
+ elapsed_ms = int((time.time() - start_time) * 1000)
114
+
115
+ response_body = response.read().decode("utf-8")
116
+ response_headers = dict(response.headers)
117
+ status_code = response.status
118
+ final_url = response.url
119
+
120
+ except urllib.error.HTTPError as e:
121
+ elapsed_ms = int((time.time() - start_time) * 1000)
122
+ response_body = e.read().decode("utf-8") if e.fp else ""
123
+ response_headers = dict(e.headers) if e.headers else {}
124
+ status_code = e.code
125
+ final_url = url
126
+
127
+ except urllib.error.URLError as e:
128
+ return TaskResult.terminal(error=f"URL error: {e.reason}")
129
+
130
+ except TimeoutError:
131
+ return TaskResult.terminal(error=f"Request timed out after {timeout}s")
132
+
133
+ outputs = {
134
+ "status_code": status_code,
135
+ "headers": response_headers,
136
+ "body": response_body,
137
+ "elapsed_ms": elapsed_ms,
138
+ "url": final_url,
139
+ }
140
+
141
+ # Check expected status
142
+ if expected_status is not None and status_code != expected_status:
143
+ print(f" [HTTPTask] Failed: expected {expected_status}, got {status_code}")
144
+ return TaskResult.terminal(
145
+ error=f"Expected status {expected_status}, got {status_code}",
146
+ context=outputs,
147
+ )
148
+
149
+ print(f" [HTTPTask] {status_code} in {elapsed_ms}ms")
150
+ return TaskResult.success(outputs=outputs)
151
+
152
+
153
+ # =============================================================================
154
+ # Helper: Setup pipeline infrastructure
155
+ # =============================================================================
156
+
157
+
158
+ def setup_pipeline_runner(store: WorkflowStore, queue: Queue) -> tuple[QueueProcessor, Orchestrator]:
159
+ """Create processor and orchestrator with HTTPTask registered."""
160
+ task_registry = TaskRegistry()
161
+ task_registry.register("http", HTTPTask)
162
+
163
+ processor = QueueProcessor(queue)
164
+
165
+ handlers: list[Any] = [
166
+ StartWorkflowHandler(queue, store),
167
+ StartStageHandler(queue, store),
168
+ StartTaskHandler(queue, store),
169
+ RunTaskHandler(queue, store, task_registry),
170
+ CompleteTaskHandler(queue, store),
171
+ CompleteStageHandler(queue, store),
172
+ CompleteWorkflowHandler(queue, store),
173
+ ]
174
+
175
+ for handler in handlers:
176
+ processor.register_handler(handler)
177
+
178
+ orchestrator = Orchestrator(queue)
179
+ return processor, orchestrator
180
+
181
+
182
+ # =============================================================================
183
+ # Example 1: Simple GET Request
184
+ # =============================================================================
185
+
186
+
187
+ def example_simple_get() -> None:
188
+ """Make a simple GET request to a public API."""
189
+ print("\n" + "=" * 60)
190
+ print("Example 1: Simple GET Request")
191
+ print("=" * 60)
192
+
193
+ store = SqliteWorkflowStore("sqlite:///:memory:", create_tables=True)
194
+ queue = SqliteQueue("sqlite:///:memory:", table_name="queue_messages")
195
+ queue._create_table()
196
+ processor, orchestrator = setup_pipeline_runner(store, queue)
197
+
198
+ workflow = Workflow.create(
199
+ application="http-example",
200
+ name="Simple GET",
201
+ stages=[
202
+ StageExecution(
203
+ ref_id="1",
204
+ type="http",
205
+ name="Get IP Info",
206
+ context={
207
+ "url": "https://httpbin.org/ip",
208
+ "method": "GET",
209
+ },
210
+ tasks=[
211
+ TaskExecution.create(
212
+ name="HTTP GET",
213
+ implementing_class="http",
214
+ stage_start=True,
215
+ stage_end=True,
216
+ ),
217
+ ],
218
+ ),
219
+ ],
220
+ )
221
+
222
+ store.store(workflow)
223
+ orchestrator.start(workflow)
224
+ processor.process_all(timeout=30.0)
225
+
226
+ result = store.retrieve(workflow.id)
227
+ print(f"\nWorkflow Status: {result.status}")
228
+ print(f"Response Status: {result.stages[0].outputs.get('status_code')}")
229
+ print(f"Response Body: {result.stages[0].outputs.get('body', '')[:200]}")
230
+
231
+
232
+ # =============================================================================
233
+ # Example 2: POST with JSON Body
234
+ # =============================================================================
235
+
236
+
237
+ def example_post_json() -> None:
238
+ """Make a POST request with JSON payload."""
239
+ print("\n" + "=" * 60)
240
+ print("Example 2: POST with JSON Body")
241
+ print("=" * 60)
242
+
243
+ store = SqliteWorkflowStore("sqlite:///:memory:", create_tables=True)
244
+ queue = SqliteQueue("sqlite:///:memory:", table_name="queue_messages")
245
+ queue._create_table()
246
+ processor, orchestrator = setup_pipeline_runner(store, queue)
247
+
248
+ workflow = Workflow.create(
249
+ application="http-example",
250
+ name="POST JSON",
251
+ stages=[
252
+ StageExecution(
253
+ ref_id="1",
254
+ type="http",
255
+ name="Create Resource",
256
+ context={
257
+ "url": "https://httpbin.org/post",
258
+ "method": "POST",
259
+ "json_body": {
260
+ "name": "Stabilize",
261
+ "version": "0.9.0",
262
+ "features": ["DAG", "parallel", "retry"],
263
+ },
264
+ },
265
+ tasks=[
266
+ TaskExecution.create(
267
+ name="HTTP POST",
268
+ implementing_class="http",
269
+ stage_start=True,
270
+ stage_end=True,
271
+ ),
272
+ ],
273
+ ),
274
+ ],
275
+ )
276
+
277
+ store.store(workflow)
278
+ orchestrator.start(workflow)
279
+ processor.process_all(timeout=30.0)
280
+
281
+ result = store.retrieve(workflow.id)
282
+ print(f"\nWorkflow Status: {result.status}")
283
+ print(f"Response Status: {result.stages[0].outputs.get('status_code')}")
284
+
285
+ body = result.stages[0].outputs.get("body", "")
286
+ if body:
287
+ try:
288
+ data = json.loads(body)
289
+ print(f"Echoed JSON: {json.dumps(data.get('json', {}), indent=2)}")
290
+ except json.JSONDecodeError:
291
+ print(f"Response: {body[:200]}")
292
+
293
+
294
+ # =============================================================================
295
+ # Example 3: Sequential API Workflow
296
+ # =============================================================================
297
+
298
+
299
+ def example_sequential_api() -> None:
300
+ """Sequential API calls: GET -> POST -> GET to verify."""
301
+ print("\n" + "=" * 60)
302
+ print("Example 3: Sequential API Workflow")
303
+ print("=" * 60)
304
+
305
+ store = SqliteWorkflowStore("sqlite:///:memory:", create_tables=True)
306
+ queue = SqliteQueue("sqlite:///:memory:", table_name="queue_messages")
307
+ queue._create_table()
308
+ processor, orchestrator = setup_pipeline_runner(store, queue)
309
+
310
+ workflow = Workflow.create(
311
+ application="http-example",
312
+ name="Sequential API",
313
+ stages=[
314
+ StageExecution(
315
+ ref_id="1",
316
+ type="http",
317
+ name="Step 1: Get Headers",
318
+ context={
319
+ "url": "https://httpbin.org/headers",
320
+ "method": "GET",
321
+ "headers": {"X-Request-ID": "step-1"},
322
+ },
323
+ tasks=[
324
+ TaskExecution.create(
325
+ name="GET headers",
326
+ implementing_class="http",
327
+ stage_start=True,
328
+ stage_end=True,
329
+ ),
330
+ ],
331
+ ),
332
+ StageExecution(
333
+ ref_id="2",
334
+ type="http",
335
+ name="Step 2: Post Data",
336
+ requisite_stage_ref_ids={"1"},
337
+ context={
338
+ "url": "https://httpbin.org/post",
339
+ "method": "POST",
340
+ "json_body": {"step": 2, "data": "from step 1"},
341
+ "headers": {"X-Request-ID": "step-2"},
342
+ },
343
+ tasks=[
344
+ TaskExecution.create(
345
+ name="POST data",
346
+ implementing_class="http",
347
+ stage_start=True,
348
+ stage_end=True,
349
+ ),
350
+ ],
351
+ ),
352
+ StageExecution(
353
+ ref_id="3",
354
+ type="http",
355
+ name="Step 3: Verify",
356
+ requisite_stage_ref_ids={"2"},
357
+ context={
358
+ "url": "https://httpbin.org/get",
359
+ "method": "GET",
360
+ "headers": {"X-Request-ID": "step-3-verify"},
361
+ },
362
+ tasks=[
363
+ TaskExecution.create(
364
+ name="GET verify",
365
+ implementing_class="http",
366
+ stage_start=True,
367
+ stage_end=True,
368
+ ),
369
+ ],
370
+ ),
371
+ ],
372
+ )
373
+
374
+ store.store(workflow)
375
+ orchestrator.start(workflow)
376
+ processor.process_all(timeout=60.0)
377
+
378
+ result = store.retrieve(workflow.id)
379
+ print(f"\nWorkflow Status: {result.status}")
380
+ for stage in result.stages:
381
+ status = stage.outputs.get("status_code", "N/A")
382
+ elapsed = stage.outputs.get("elapsed_ms", "N/A")
383
+ print(f" {stage.name}: {status} ({elapsed}ms)")
384
+
385
+
386
+ # =============================================================================
387
+ # Example 4: Parallel Requests
388
+ # =============================================================================
389
+
390
+
391
+ def example_parallel_requests() -> None:
392
+ """Make parallel requests to multiple endpoints."""
393
+ print("\n" + "=" * 60)
394
+ print("Example 4: Parallel Requests")
395
+ print("=" * 60)
396
+
397
+ store = SqliteWorkflowStore("sqlite:///:memory:", create_tables=True)
398
+ queue = SqliteQueue("sqlite:///:memory:", table_name="queue_messages")
399
+ queue._create_table()
400
+ processor, orchestrator = setup_pipeline_runner(store, queue)
401
+
402
+ # Start
403
+ # / | \
404
+ # EP1 EP2 EP3
405
+ # \ | /
406
+ # Collect
407
+
408
+ workflow = Workflow.create(
409
+ application="http-example",
410
+ name="Parallel Requests",
411
+ stages=[
412
+ StageExecution(
413
+ ref_id="start",
414
+ type="http",
415
+ name="Start",
416
+ context={
417
+ "url": "https://httpbin.org/get?stage=start",
418
+ "method": "GET",
419
+ },
420
+ tasks=[
421
+ TaskExecution.create(
422
+ name="Start request",
423
+ implementing_class="http",
424
+ stage_start=True,
425
+ stage_end=True,
426
+ ),
427
+ ],
428
+ ),
429
+ # Parallel branches
430
+ StageExecution(
431
+ ref_id="ep1",
432
+ type="http",
433
+ name="Endpoint 1 (IP)",
434
+ requisite_stage_ref_ids={"start"},
435
+ context={
436
+ "url": "https://httpbin.org/ip",
437
+ "method": "GET",
438
+ },
439
+ tasks=[
440
+ TaskExecution.create(
441
+ name="Get IP",
442
+ implementing_class="http",
443
+ stage_start=True,
444
+ stage_end=True,
445
+ ),
446
+ ],
447
+ ),
448
+ StageExecution(
449
+ ref_id="ep2",
450
+ type="http",
451
+ name="Endpoint 2 (Headers)",
452
+ requisite_stage_ref_ids={"start"},
453
+ context={
454
+ "url": "https://httpbin.org/headers",
455
+ "method": "GET",
456
+ },
457
+ tasks=[
458
+ TaskExecution.create(
459
+ name="Get Headers",
460
+ implementing_class="http",
461
+ stage_start=True,
462
+ stage_end=True,
463
+ ),
464
+ ],
465
+ ),
466
+ StageExecution(
467
+ ref_id="ep3",
468
+ type="http",
469
+ name="Endpoint 3 (User-Agent)",
470
+ requisite_stage_ref_ids={"start"},
471
+ context={
472
+ "url": "https://httpbin.org/user-agent",
473
+ "method": "GET",
474
+ },
475
+ tasks=[
476
+ TaskExecution.create(
477
+ name="Get User-Agent",
478
+ implementing_class="http",
479
+ stage_start=True,
480
+ stage_end=True,
481
+ ),
482
+ ],
483
+ ),
484
+ # Join
485
+ StageExecution(
486
+ ref_id="collect",
487
+ type="http",
488
+ name="Collect Results",
489
+ requisite_stage_ref_ids={"ep1", "ep2", "ep3"},
490
+ context={
491
+ "url": "https://httpbin.org/get?stage=complete",
492
+ "method": "GET",
493
+ },
494
+ tasks=[
495
+ TaskExecution.create(
496
+ name="Final request",
497
+ implementing_class="http",
498
+ stage_start=True,
499
+ stage_end=True,
500
+ ),
501
+ ],
502
+ ),
503
+ ],
504
+ )
505
+
506
+ store.store(workflow)
507
+ orchestrator.start(workflow)
508
+ processor.process_all(timeout=60.0)
509
+
510
+ result = store.retrieve(workflow.id)
511
+ print(f"\nWorkflow Status: {result.status}")
512
+ for stage in result.stages:
513
+ status = stage.outputs.get("status_code", "N/A")
514
+ elapsed = stage.outputs.get("elapsed_ms", "N/A")
515
+ print(f" {stage.name}: {status} ({elapsed}ms)")
516
+
517
+
518
+ # =============================================================================
519
+ # Example 5: All HTTP Methods
520
+ # =============================================================================
521
+
522
+
523
+ def example_all_methods() -> None:
524
+ """Demonstrate all supported HTTP methods."""
525
+ print("\n" + "=" * 60)
526
+ print("Example 5: All HTTP Methods")
527
+ print("=" * 60)
528
+
529
+ store = SqliteWorkflowStore("sqlite:///:memory:", create_tables=True)
530
+ queue = SqliteQueue("sqlite:///:memory:", table_name="queue_messages")
531
+ queue._create_table()
532
+ processor, orchestrator = setup_pipeline_runner(store, queue)
533
+
534
+ methods = [
535
+ ("GET", "https://httpbin.org/get", None),
536
+ ("POST", "https://httpbin.org/post", {"action": "create"}),
537
+ ("PUT", "https://httpbin.org/put", {"action": "update"}),
538
+ ("PATCH", "https://httpbin.org/patch", {"action": "partial"}),
539
+ ("DELETE", "https://httpbin.org/delete", None),
540
+ ("HEAD", "https://httpbin.org/get", None),
541
+ ("OPTIONS", "https://httpbin.org/get", None),
542
+ ]
543
+
544
+ stages = []
545
+ prev_ref = None
546
+ for i, (method, url, body) in enumerate(methods, 1):
547
+ ref_id = str(i)
548
+ context: dict[str, Any] = {"url": url, "method": method}
549
+ if body:
550
+ context["json_body"] = body
551
+
552
+ stage = StageExecution(
553
+ ref_id=ref_id,
554
+ type="http",
555
+ name=f"{method} Request",
556
+ requisite_stage_ref_ids={prev_ref} if prev_ref else set(),
557
+ context=context,
558
+ tasks=[
559
+ TaskExecution.create(
560
+ name=f"HTTP {method}",
561
+ implementing_class="http",
562
+ stage_start=True,
563
+ stage_end=True,
564
+ ),
565
+ ],
566
+ )
567
+ stages.append(stage)
568
+ prev_ref = ref_id
569
+
570
+ workflow = Workflow.create(
571
+ application="http-example",
572
+ name="All HTTP Methods",
573
+ stages=stages,
574
+ )
575
+
576
+ store.store(workflow)
577
+ orchestrator.start(workflow)
578
+ processor.process_all(timeout=120.0)
579
+
580
+ result = store.retrieve(workflow.id)
581
+ print(f"\nWorkflow Status: {result.status}")
582
+ for stage in result.stages:
583
+ status = stage.outputs.get("status_code", "N/A")
584
+ elapsed = stage.outputs.get("elapsed_ms", "N/A")
585
+ print(f" {stage.name}: {status} ({elapsed}ms)")
586
+
587
+
588
+ # =============================================================================
589
+ # Main
590
+ # =============================================================================
591
+
592
+
593
+ if __name__ == "__main__":
594
+ print("Stabilize HTTP Examples")
595
+ print("=" * 60)
596
+ print("Using httpbin.org for testing")
597
+
598
+ example_simple_get()
599
+ example_post_json()
600
+ example_sequential_api()
601
+ example_parallel_requests()
602
+ example_all_methods()
603
+
604
+ print("\n" + "=" * 60)
605
+ print("All examples completed!")
606
+ print("=" * 60)