python-postman 0.7.0__tar.gz → 0.8.0__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.
Files changed (92) hide show
  1. {python_postman-0.7.0 → python_postman-0.8.0}/.github/workflows/python-publish.yml +64 -64
  2. {python_postman-0.7.0 → python_postman-0.8.0}/PKG-INFO +257 -3
  3. {python_postman-0.7.0 → python_postman-0.8.0}/README.md +253 -2
  4. python_postman-0.8.0/examples/README.md +308 -0
  5. python_postman-0.8.0/examples/advanced_execution.py +177 -0
  6. python_postman-0.8.0/examples/authentication_examples.py +187 -0
  7. python_postman-0.8.0/examples/basic_execution.py +67 -0
  8. python_postman-0.8.0/examples/complete_workflow.py +440 -0
  9. python_postman-0.8.0/examples/path_parameters_example.py +304 -0
  10. python_postman-0.8.0/examples/synchronous_execution.py +134 -0
  11. python_postman-0.8.0/examples/usage_patterns.py +361 -0
  12. python_postman-0.8.0/examples/variable_examples.py +206 -0
  13. {python_postman-0.7.0 → python_postman-0.8.0}/pyproject.toml +13 -1
  14. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/__init__.py +70 -1
  15. python_postman-0.8.0/python_postman/execution/__init__.py +64 -0
  16. python_postman-0.8.0/python_postman/execution/auth_handler.py +245 -0
  17. python_postman-0.8.0/python_postman/execution/context.py +341 -0
  18. python_postman-0.8.0/python_postman/execution/exceptions.py +208 -0
  19. python_postman-0.8.0/python_postman/execution/executor.py +781 -0
  20. python_postman-0.8.0/python_postman/execution/extensions.py +420 -0
  21. python_postman-0.8.0/python_postman/execution/response.py +165 -0
  22. python_postman-0.8.0/python_postman/execution/results.py +250 -0
  23. python_postman-0.8.0/python_postman/execution/script_runner.py +468 -0
  24. python_postman-0.8.0/python_postman/execution/variable_resolver.py +339 -0
  25. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/models/collection.py +132 -1
  26. python_postman-0.8.0/python_postman/models/request.py +319 -0
  27. python_postman-0.8.0/tests/test_auth_handler.py +560 -0
  28. python_postman-0.8.0/tests/test_collection.py +329 -0
  29. python_postman-0.8.0/tests/test_data/README_integration_tests.md +160 -0
  30. python_postman-0.8.0/tests/test_data/auth_execution_collection.json +324 -0
  31. python_postman-0.8.0/tests/test_data/cftc.gov.postman_collection.json +99 -0
  32. python_postman-0.8.0/tests/test_data/error_scenarios_collection.json +349 -0
  33. python_postman-0.8.0/tests/test_data/execution_collection.json +285 -0
  34. python_postman-0.8.0/tests/test_data/nested_execution_collection.json +355 -0
  35. python_postman-0.8.0/tests/test_data/performance_collection.json +377 -0
  36. python_postman-0.8.0/tests/test_execution_context.py +291 -0
  37. python_postman-0.8.0/tests/test_execution_exceptions.py +482 -0
  38. python_postman-0.8.0/tests/test_execution_integration.py +1049 -0
  39. python_postman-0.8.0/tests/test_executor.py +1910 -0
  40. python_postman-0.8.0/tests/test_extensions.py +587 -0
  41. python_postman-0.8.0/tests/test_imports.py +348 -0
  42. python_postman-0.8.0/tests/test_request_execution.py +279 -0
  43. python_postman-0.8.0/tests/test_response.py +306 -0
  44. python_postman-0.8.0/tests/test_script_runner.py +552 -0
  45. python_postman-0.8.0/tests/test_variable_resolver.py +547 -0
  46. {python_postman-0.7.0 → python_postman-0.8.0}/uv.lock +118 -2
  47. python_postman-0.7.0/python_postman/models/request.py +0 -147
  48. python_postman-0.7.0/tests/test_collection.py +0 -119
  49. {python_postman-0.7.0 → python_postman-0.8.0}/.gitignore +0 -0
  50. {python_postman-0.7.0 → python_postman-0.8.0}/LICENSE +0 -0
  51. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/exceptions/__init__.py +0 -0
  52. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/exceptions/base.py +0 -0
  53. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/exceptions/file_error.py +0 -0
  54. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/exceptions/parse_error.py +0 -0
  55. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/exceptions/validation_error.py +0 -0
  56. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/models/__init__.py +0 -0
  57. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/models/auth.py +0 -0
  58. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/models/body.py +0 -0
  59. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/models/collection_info.py +0 -0
  60. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/models/event.py +0 -0
  61. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/models/folder.py +0 -0
  62. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/models/header.py +0 -0
  63. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/models/item.py +0 -0
  64. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/models/url.py +0 -0
  65. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/models/variable.py +0 -0
  66. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/parser.py +0 -0
  67. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/utils/__init__.py +0 -0
  68. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/utils/json_parser.py +0 -0
  69. {python_postman-0.7.0 → python_postman-0.8.0}/python_postman/utils/validators.py +0 -0
  70. {python_postman-0.7.0 → python_postman-0.8.0}/tests/__init__.py +0 -0
  71. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_auth.py +0 -0
  72. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_body.py +0 -0
  73. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_collection_info.py +0 -0
  74. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_data/README.md +0 -0
  75. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_data/auth_collection.json +0 -0
  76. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_data/empty_collection.json +0 -0
  77. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_data/events_collection.json +0 -0
  78. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_data/invalid_collection.json +0 -0
  79. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_data/malformed_json.json +0 -0
  80. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_data/nested_collection.json +0 -0
  81. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_data/simple_collection.json +0 -0
  82. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_event.py +0 -0
  83. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_exceptions.py +0 -0
  84. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_folder.py +0 -0
  85. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_header.py +0 -0
  86. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_integration.py +0 -0
  87. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_item.py +0 -0
  88. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_json_parser.py +0 -0
  89. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_parser.py +0 -0
  90. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_request.py +0 -0
  91. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_url.py +0 -0
  92. {python_postman-0.7.0 → python_postman-0.8.0}/tests/test_variable.py +0 -0
@@ -1,65 +1,65 @@
1
- # This workflow will upload a Python Package to PyPI when a release is published
2
- # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3
-
4
- name: Publish Python Package to PyPI
5
-
6
- on:
7
- release:
8
- types: [published]
9
-
10
- permissions:
11
- contents: read
12
-
13
- jobs:
14
- build:
15
- name: Build distribution 📦
16
- runs-on: ubuntu-latest
17
- steps:
18
- - name: Checkout repository
19
- uses: actions/checkout@v5
20
-
21
- - name: Set up Python
22
- uses: actions/setup-python@v6
23
- with:
24
- python-version: "3.x"
25
- cache: pip # Cache pip dependencies for faster runs
26
-
27
- - name: Install build dependencies
28
- run: |
29
- python -m pip install --upgrade pip
30
- python -m pip install build
31
-
32
- - name: Build package
33
- run: python -m build
34
-
35
- - name: Verify build artifacts
36
- run: |
37
- ls -la dist/
38
- python -m pip install twine
39
- python -m twine check dist/*
40
-
41
- - name: Store the distribution packages
42
- uses: actions/upload-artifact@v4
43
- with:
44
- name: python-package-distributions
45
- path: dist/
46
-
47
- publish-to-pypi:
48
- name: Publish Python 🐍 distribution 📦 to PyPI
49
- needs: [build]
50
- runs-on: ubuntu-latest
51
- environment:
52
- name: pypi
53
- url: https://pypi.org/p/${{ github.event.repository.name }}
54
- permissions:
55
- id-token: write # IMPORTANT: mandatory for trusted publishing
56
-
57
- steps:
58
- - name: Download all the dists
59
- uses: actions/download-artifact@v4
60
- with:
61
- name: python-package-distributions
62
- path: dist/
63
-
64
- - name: Publish distribution 📦 to PyPI
1
+ # This workflow will upload a Python Package to PyPI when a release is published
2
+ # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3
+
4
+ name: Publish Python Package to PyPI
5
+
6
+ on:
7
+ release:
8
+ types: [published]
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ build:
15
+ name: Build distribution 📦
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - name: Checkout repository
19
+ uses: actions/checkout@v5
20
+
21
+ - name: Set up Python
22
+ uses: actions/setup-python@v6
23
+ with:
24
+ python-version: "3.x"
25
+ cache: pip # Cache pip dependencies for faster runs
26
+
27
+ - name: Install build dependencies
28
+ run: |
29
+ python -m pip install --upgrade pip
30
+ python -m pip install build
31
+
32
+ - name: Build package
33
+ run: python -m build
34
+
35
+ - name: Verify build artifacts
36
+ run: |
37
+ ls -la dist/
38
+ python -m pip install twine
39
+ python -m twine check dist/*
40
+
41
+ - name: Store the distribution packages
42
+ uses: actions/upload-artifact@v4
43
+ with:
44
+ name: python-package-distributions
45
+ path: dist/
46
+
47
+ publish-to-pypi:
48
+ name: Publish Python 🐍 distribution 📦 to PyPI
49
+ needs: [build]
50
+ runs-on: ubuntu-latest
51
+ environment:
52
+ name: pypi
53
+ url: https://pypi.org/p/${{ github.event.repository.name }}
54
+ permissions:
55
+ id-token: write # IMPORTANT: mandatory for trusted publishing
56
+
57
+ steps:
58
+ - name: Download all the dists
59
+ uses: actions/download-artifact@v4
60
+ with:
61
+ name: python-package-distributions
62
+ path: dist/
63
+
64
+ - name: Publish distribution 📦 to PyPI
65
65
  uses: pypa/gh-action-pypi-publish@release/v1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-postman
3
- Version: 0.7.0
3
+ Version: 0.8.0
4
4
  Summary: A Python library for parsing and working with Postman collection.json files
5
5
  Project-URL: Homepage, https://github.com/python-postman/python-postman
6
6
  Project-URL: Repository, https://github.com/python-postman/python-postman
@@ -29,8 +29,11 @@ Provides-Extra: dev
29
29
  Requires-Dist: black>=23.0.0; extra == 'dev'
30
30
  Requires-Dist: isort>=5.12.0; extra == 'dev'
31
31
  Requires-Dist: mypy>=1.0.0; extra == 'dev'
32
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
32
33
  Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
33
34
  Requires-Dist: pytest>=8.4.2; extra == 'dev'
35
+ Provides-Extra: execution
36
+ Requires-Dist: httpx>=0.25.0; extra == 'execution'
34
37
  Description-Content-Type: text/markdown
35
38
 
36
39
  # Python Postman Collection Parser
@@ -42,6 +45,11 @@ A Python library for parsing and working with Postman collection.json files. Thi
42
45
  - **Parse Postman Collections**: Load collections from files, JSON strings, or dictionaries
43
46
  - **Object-Oriented API**: Work with collections using intuitive Python objects
44
47
  - **Full Collection Support**: Access requests, folders, variables, authentication, and scripts
48
+ - **HTTP Request Execution**: Execute requests using httpx with full async/sync support
49
+ - **Variable Resolution**: Dynamic variable substitution with proper scoping
50
+ - **Authentication Handling**: Automatic auth processing for Bearer, Basic, and API Key
51
+ - **Script Execution**: Run pre-request and test scripts with result collection
52
+ - **Request Extensions**: Runtime modification of URLs, headers, body, and auth
45
53
  - **Validation**: Built-in validation for collection structure and schema compliance
46
54
  - **Iteration**: Easy iteration through all requests regardless of folder structure
47
55
  - **Search**: Find requests and folders by name
@@ -50,7 +58,13 @@ A Python library for parsing and working with Postman collection.json files. Thi
50
58
  ## Installation
51
59
 
52
60
  ```bash
61
+ # Basic installation (parsing only)
53
62
  pip install python-postman
63
+
64
+ # With HTTP execution support
65
+ pip install python-postman[execution]
66
+ # or
67
+ pip install python-postman httpx
54
68
  ```
55
69
 
56
70
  ## Quick Start
@@ -219,6 +233,246 @@ collection = PythonPostman.create_collection(
219
233
  print(f"Created collection: {collection.info.name}")
220
234
  ```
221
235
 
236
+ ## HTTP Request Execution
237
+
238
+ The library supports executing HTTP requests from Postman collections using httpx. This feature requires the `httpx` dependency.
239
+
240
+ ### Basic Request Execution
241
+
242
+ ```python
243
+ import asyncio
244
+ from python_postman import PythonPostman
245
+ from python_postman.execution import RequestExecutor, ExecutionContext
246
+
247
+ async def main():
248
+ # Load collection
249
+ collection = PythonPostman.from_file("api_collection.json")
250
+
251
+ # Create executor
252
+ executor = RequestExecutor(
253
+ client_config={"timeout": 30.0, "verify": True},
254
+ global_headers={"User-Agent": "python-postman/1.0"}
255
+ )
256
+
257
+ # Create execution context with variables
258
+ context = ExecutionContext(
259
+ environment_variables={
260
+ "base_url": "https://api.example.com",
261
+ "api_key": "your-api-key"
262
+ }
263
+ )
264
+
265
+ # Execute a single request
266
+ request = collection.get_request_by_name("Get Users")
267
+ result = await executor.execute_request(request, context)
268
+
269
+ if result.success:
270
+ print(f"Status: {result.response.status_code}")
271
+ print(f"Response: {result.response.json}")
272
+ print(f"Time: {result.response.elapsed_ms:.2f}ms")
273
+ else:
274
+ print(f"Error: {result.error}")
275
+
276
+ await executor.aclose()
277
+
278
+ asyncio.run(main())
279
+ ```
280
+
281
+ ### Synchronous Execution
282
+
283
+ ```python
284
+ from python_postman.execution import RequestExecutor, ExecutionContext
285
+
286
+ # Synchronous execution
287
+ with RequestExecutor() as executor:
288
+ context = ExecutionContext(
289
+ environment_variables={"base_url": "https://httpbin.org"}
290
+ )
291
+
292
+ result = executor.execute_request_sync(request, context)
293
+ if result.success:
294
+ print(f"Status: {result.response.status_code}")
295
+ ```
296
+
297
+ ### Collection Execution
298
+
299
+ ```python
300
+ # Execute entire collection
301
+ async def execute_collection():
302
+ executor = RequestExecutor()
303
+
304
+ # Sequential execution
305
+ result = await executor.execute_collection(collection)
306
+ print(f"Executed {result.total_requests} requests")
307
+ print(f"Success rate: {result.successful_requests}/{result.total_requests}")
308
+
309
+ # Parallel execution
310
+ result = await executor.execute_collection(
311
+ collection,
312
+ parallel=True,
313
+ stop_on_error=False
314
+ )
315
+ print(f"Parallel execution completed in {result.total_time_ms:.2f}ms")
316
+
317
+ await executor.aclose()
318
+ ```
319
+
320
+ ### Variable Management
321
+
322
+ ```python
323
+ # Variable scoping: request > folder > collection > environment
324
+ context = ExecutionContext(
325
+ environment_variables={"env": "production"},
326
+ collection_variables={"api_version": "v1", "timeout": "30"},
327
+ folder_variables={"endpoint": "/users"},
328
+ request_variables={"user_id": "12345"}
329
+ )
330
+
331
+ # Variables are resolved with proper precedence
332
+ url = context.resolve_variables("{{base_url}}/{{api_version}}{{endpoint}}/{{user_id}}")
333
+ print(url) # "https://api.example.com/v1/users/12345"
334
+
335
+ # Dynamic variable updates
336
+ context.set_variable("session_token", "abc123", "environment")
337
+ ```
338
+
339
+ ### Path Parameters
340
+
341
+ The library supports both Postman-style variables (`{{variable}}`) and path parameters (`:parameter`):
342
+
343
+ ```python
344
+ # Path parameters use :parameterName syntax
345
+ context = ExecutionContext(
346
+ environment_variables={
347
+ "baseURL": "https://api.example.com",
348
+ "userId": "12345",
349
+ "datasetId": "abc123"
350
+ }
351
+ )
352
+
353
+ # Mix Postman variables and path parameters
354
+ url = context.resolve_variables("{{baseURL}}/users/:userId/datasets/:datasetId")
355
+ print(url) # "https://api.example.com/users/12345/datasets/abc123"
356
+
357
+ # Path parameters follow the same scoping rules as Postman variables
358
+ url = context.resolve_variables("{{baseURL}}/:datasetId?$offset=0&$limit=10")
359
+ print(url) # "https://api.example.com/abc123?$offset=0&$limit=10"
360
+ ```
361
+
362
+ ### Request Extensions
363
+
364
+ ```python
365
+ from python_postman.execution import RequestExtensions
366
+
367
+ # Runtime request modifications
368
+ extensions = RequestExtensions(
369
+ # Substitute existing values
370
+ header_substitutions={"Authorization": "Bearer {{new_token}}"},
371
+ url_substitutions={"host": "staging.api.example.com"},
372
+
373
+ # Add new values
374
+ header_extensions={"X-Request-ID": "req-{{timestamp}}"},
375
+ param_extensions={"debug": "true", "version": "v2"},
376
+ body_extensions={"metadata": {"client": "python-postman"}}
377
+ )
378
+
379
+ result = await executor.execute_request(
380
+ request,
381
+ context,
382
+ extensions=extensions
383
+ )
384
+ ```
385
+
386
+ ### Authentication
387
+
388
+ ```python
389
+ # Authentication is handled automatically based on collection/request auth settings
390
+
391
+ # Bearer Token
392
+ context = ExecutionContext(
393
+ environment_variables={"bearer_token": "eyJhbGciOiJIUzI1NiIs..."}
394
+ )
395
+
396
+ # Basic Auth
397
+ context = ExecutionContext(
398
+ environment_variables={
399
+ "username": "admin",
400
+ "password": "secret123"
401
+ }
402
+ )
403
+
404
+ # API Key
405
+ context = ExecutionContext(
406
+ environment_variables={"api_key": "sk-1234567890abcdef"}
407
+ )
408
+
409
+ # Auth is applied automatically during request execution
410
+ result = await executor.execute_request(request, context)
411
+ ```
412
+
413
+ ### Request Methods on Models
414
+
415
+ ```python
416
+ # Execute requests directly from Request objects
417
+ request = collection.get_request_by_name("Health Check")
418
+
419
+ # Async execution
420
+ result = await request.execute(
421
+ executor=executor,
422
+ context=context,
423
+ substitutions={"env": "staging"}
424
+ )
425
+
426
+ # Sync execution
427
+ result = request.execute_sync(
428
+ executor=executor,
429
+ context=context
430
+ )
431
+
432
+ # Execute collections directly
433
+ result = await collection.execute(
434
+ executor=executor,
435
+ parallel=True
436
+ )
437
+ ```
438
+
439
+ ### Error Handling
440
+
441
+ ```python
442
+ from python_postman.execution import (
443
+ ExecutionError,
444
+ RequestExecutionError,
445
+ VariableResolutionError,
446
+ AuthenticationError
447
+ )
448
+
449
+ try:
450
+ result = await executor.execute_request(request, context)
451
+ if not result.success:
452
+ print(f"Request failed: {result.error}")
453
+ except VariableResolutionError as e:
454
+ print(f"Variable error: {e}")
455
+ except AuthenticationError as e:
456
+ print(f"Auth error: {e}")
457
+ except RequestExecutionError as e:
458
+ print(f"Execution error: {e}")
459
+ ```
460
+
461
+ ### Test Scripts and Results
462
+
463
+ ```python
464
+ # Test results are automatically collected from test scripts
465
+ result = await executor.execute_request(request, context)
466
+
467
+ if result.test_results:
468
+ print(f"Tests: {result.test_results.passed} passed, {result.test_results.failed} failed")
469
+
470
+ # Check individual assertions
471
+ for assertion in result.test_results.assertions:
472
+ if not assertion.passed:
473
+ print(f"Failed: {assertion.name} - {assertion.error}")
474
+ ```
475
+
222
476
  ## API Reference
223
477
 
224
478
  ### Main Classes
@@ -316,9 +570,9 @@ This project is licensed under the MIT License - see the LICENSE file for detail
316
570
 
317
571
  ## Changelog
318
572
 
319
- ### 0.7.0 (Updated version)
573
+ ### 0.8.0 (Updated version)
320
574
 
321
- - Updated version to 0.7.0
575
+ - Updated version to 0.8.0
322
576
  - Updated README.md
323
577
  - Updated pyproject.toml
324
578
  - Updated tests