A Python library for parsing and working with Postman collection.json files
Project description
Python Postman
A comprehensive Python library for working with Postman collections. Parse, execute, search, and analyze Postman collection.json files with a clean, object-oriented interface. Execute HTTP requests with full async/sync support, dynamic variable resolution, and authentication handling.
Features
- Parse Postman Collections: Load collections from files, JSON strings, or dictionaries
- Object-Oriented API: Work with collections using intuitive Python objects
- Full Collection Support: Access requests, folders, variables, authentication, and events
- HTTP Request Execution: Execute requests using httpx with full async/sync support
- Variable Resolution: Dynamic variable substitution with proper scoping
- Authentication Handling: Automatic auth processing for Bearer, Basic, and API Key
- Request Extensions: Runtime modification of URLs, headers, body, and auth
- Validation: Built-in validation for collection structure and schema compliance
- Iteration: Easy iteration through all requests regardless of folder structure
- Search: Find requests and folders by name
- Type Hints: Full type annotation support for better IDE experience
Installation
# Basic installation (parsing only)
pip install python-postman
# With HTTP execution support
pip install python-postman[execution]
# or
pip install python-postman httpx
Quick Start
Loading a Collection
from python_postman import PythonPostman
# Load from file
collection = PythonPostman.from_file("path/to/collection.json")
# Load from JSON string
json_string = '{"info": {"name": "My Collection"}, "item": []}'
collection = PythonPostman.from_json(json_string)
# Load from dictionary
collection_dict = {"info": {"name": "My Collection"}, "item": []}
collection = PythonPostman.from_dict(collection_dict)
Accessing Collection Information
# Basic collection info
print(f"Collection Name: {collection.info.name}")
print(f"Description: {collection.info.description}")
print(f"Schema: {collection.info.schema}")
# Collection-level variables
for variable in collection.variables: # This requests a list of Variable objects
print(f"Variable: {variable.key} = {variable.value}")
# Collection variables dictionary. This is a quick way to get key-value pairs.
# You can pass/update these and add them to the execution context.
collection_variables = collection.get_variables()
# Collection-level authentication
if collection.auth:
print(f"Auth Type: {collection.auth.type}")
Working with Requests
# Get a list of requests by name
collection.list_requests()
# Find specific request by name
login_request = collection.get_request_by_name("Login Request")
if login_request:
print(f"Found request: {login_request.method} {login_request.url}")
# Iterate through all requests (flattens folder structure)
for request in collection.get_requests():
print(f"Request: {request.method} {request.name}")
print(f"URL: {request.url}")
# Access headers
for header in request.headers:
print(f"Header: {header.key} = {header.value}")
# Access request body
if request.body:
print(f"Body Type: {request.body.mode}")
print(f"Body Content: {request.body.raw}")
Working with Folders
# Access top-level items
for item in collection.items:
if hasattr(item, 'items'): # It's a folder
print(f"Folder: {item.name}")
print(f"Items in folder: {len(item.items)}")
# Get all requests in this folder
for request in item.get_requests():
print(f" Request: {request.name}")
else: # It's a request
print(f"Request: {item.name}")
# Find specific folder by name
folder = collection.get_folder_by_name("Authentication")
if folder:
print(f"Found folder: {folder.name}")
print(f"Subfolders: {len(folder.get_subfolders())}")
Working with Variables
# Collection variables
for var in collection.variables:
print(f"Collection Variable: {var.key} = {var.value}")
if var.description:
print(f" Description: {var.description}")
# Folder variables (if folder has variables)
for item in collection.items:
if hasattr(item, 'variables') and item.variables:
print(f"Folder '{item.name}' variables:")
for var in item.variables:
print(f" {var.key} = {var.value}")
Authentication
# Collection-level auth
if collection.auth:
print(f"Collection Auth: {collection.auth.type}")
# Access auth details based on type
if collection.auth.type == "bearer":
token = collection.auth.bearer.get("token")
print(f"Bearer Token: {token}")
elif collection.auth.type == "basic":
username = collection.auth.basic.get("username")
print(f"Basic Auth Username: {username}")
# Request-level auth (overrides collection auth)
for request in collection.get_requests():
if request.auth:
print(f"Request '{request.name}' has {request.auth.type} auth")
Events (Scripts)
# Access script content from collection-level events
for event in collection.events:
print(f"Collection Event: {event.listen}")
print(f"Script Content: {event.script}")
# Access script content from request-level events
# Note: JavaScript execution is not supported - scripts are accessible as text only
for request in collection.get_requests():
for event in request.events:
if event.listen == "prerequest":
print(f"Pre-request script for {request.name}: {event.script}")
elif event.listen == "test":
print(f"Test script for {request.name}: {event.script}")
Validation
# Validate collection structure
validation_result = collection.validate()
if validation_result.is_valid:
print("Collection is valid!")
else:
print("Collection validation failed:")
for error in validation_result.errors:
print(f" - {error}")
# Quick validation without creating full objects
is_valid = PythonPostman.validate_collection_dict(collection_dict)
print(f"Collection dict is valid: {is_valid}")
Creating New Collections
# Create a new empty collection
collection = PythonPostman.create_collection(
name="My New Collection",
description="A collection created programmatically"
)
print(f"Created collection: {collection.info.name}")
HTTP Request Execution
The library supports executing HTTP requests from Postman collections using httpx. This feature requires the httpx dependency.
Basic Request Execution
import asyncio
from python_postman import PythonPostman
from python_postman.execution import RequestExecutor, ExecutionContext
async def main():
# Load collection
collection = PythonPostman.from_file("api_collection.json")
# Create executor
executor = RequestExecutor(
client_config={"timeout": 30.0, "verify": True},
global_headers={"User-Agent": "python-postman/1.0"}
)
# Create execution context with variables
context = ExecutionContext(
environment_variables={
"base_url": "https://api.example.com",
"api_key": "your-api-key"
}
)
# Execute a single request
request = collection.get_request_by_name("Get Users")
result = await executor.execute_request(request, context)
if result.success:
print(f"Status: {result.response.status_code}")
print(f"Response: {result.response.json}")
print(f"Time: {result.response.elapsed_ms:.2f}ms")
else:
print(f"Error: {result.error}")
await executor.aclose()
asyncio.run(main())
Synchronous Execution
from python_postman.execution import RequestExecutor, ExecutionContext
# Synchronous execution
with RequestExecutor() as executor:
context = ExecutionContext(
environment_variables={"base_url": "https://httpbin.org"}
)
result = executor.execute_request_sync(request, context)
if result.success:
print(f"Status: {result.response.status_code}")
Collection Execution
# Execute entire collection
async def execute_collection():
executor = RequestExecutor()
# Sequential execution
result = await executor.execute_collection(collection)
print(f"Executed {result.total_requests} requests")
print(f"Success rate: {result.successful_requests}/{result.total_requests}")
# Parallel execution
result = await executor.execute_collection(
collection,
parallel=True,
stop_on_error=False
)
# Get the request responses
for result in result.results:
print(f"Request: {result.request.name}")
print(f"Result Text: {result.response.text}")
print(f"Parallel execution completed in {result.total_time_ms:.2f}ms")
await executor.aclose()
Variable Management
# Variable scoping: request > folder > collection > environment
context = ExecutionContext(
environment_variables={"env": "production"},
collection_variables={"api_version": "v1", "timeout": "30"},
folder_variables={"endpoint": "/users"},
request_variables={"user_id": "12345"}
)
# Variables are resolved with proper precedence
url = context.resolve_variables("{{base_url}}/{{api_version}}{{endpoint}}/{{user_id}}")
print(url) # "https://api.example.com/v1/users/12345"
# Dynamic variable updates
context.set_variable("session_token", "abc123", "environment")
Path Parameters
The library supports both Postman-style variables ({{variable}}) and path parameters (:parameter):
# Path parameters use :parameterName syntax
context = ExecutionContext(
environment_variables={
"baseURL": "https://api.example.com",
"userId": "12345",
"datasetId": "abc123"
}
)
# Mix Postman variables and path parameters
url = context.resolve_variables("{{baseURL}}/users/:userId/datasets/:datasetId")
print(url) # "https://api.example.com/users/12345/datasets/abc123"
# Path parameters follow the same scoping rules as Postman variables
url = context.resolve_variables("{{baseURL}}/:datasetId?$offset=0&$limit=10")
print(url) # "https://api.example.com/abc123?$offset=0&$limit=10"
Request Extensions
from python_postman.execution import RequestExtensions
# Runtime request modifications
extensions = RequestExtensions(
# Substitute existing values
header_substitutions={"Authorization": "Bearer {{new_token}}"},
url_substitutions={"host": "staging.api.example.com"},
# Add new values
header_extensions={"X-Request-ID": "req-{{timestamp}}"},
param_extensions={"debug": "true", "version": "v2"},
body_extensions={"metadata": {"client": "python-postman"}}
)
result = await executor.execute_request(
request,
context,
extensions=extensions
)
Authentication
# Authentication is handled automatically based on collection/request auth settings
# Bearer Token
context = ExecutionContext(
environment_variables={"bearer_token": "eyJhbGciOiJIUzI1NiIs..."}
)
# Basic Auth
context = ExecutionContext(
environment_variables={
"username": "admin",
"password": "secret123"
}
)
# API Key
context = ExecutionContext(
environment_variables={"api_key": "sk-1234567890abcdef"}
)
# Auth is applied automatically during request execution
result = await executor.execute_request(request, context)
Request Methods on Models
# Execute requests directly from Request objects
request = collection.get_request_by_name("Health Check")
# Async execution
result = await request.execute(
executor=executor,
context=context,
substitutions={"env": "staging"}
)
# Sync execution
result = request.execute_sync(
executor=executor,
context=context
)
# Execute collections directly
result = await collection.execute(
executor=executor,
parallel=True
)
Error Handling
from python_postman.execution import (
ExecutionError,
RequestExecutionError,
VariableResolutionError,
AuthenticationError
)
try:
result = await executor.execute_request(request, context)
if not result.success:
print(f"Request failed: {result.error}")
except VariableResolutionError as e:
print(f"Variable error: {e}")
except AuthenticationError as e:
print(f"Auth error: {e}")
except RequestExecutionError as e:
print(f"Execution error: {e}")
API Reference
Main Classes
PythonPostman: Main entry point for loading collectionsCollection: Represents a complete Postman collectionRequest: Individual HTTP requestFolder: Container for organizing requests and sub-foldersVariable: Collection, folder, or request-level variablesAuth: Authentication configurationEvent: Pre-request and test script definitions (text only, execution not supported)
Exception Handling
The library provides specific exceptions for different error scenarios:
from python_postman import (
PostmanCollectionError, # Base exception
CollectionParseError, # JSON parsing errors
CollectionValidationError, # Structure validation errors
CollectionFileError, # File operation errors
)
try:
collection = PythonPostman.from_file("collection.json")
except CollectionFileError as e:
print(f"File error: {e}")
except CollectionParseError as e:
print(f"Parse error: {e}")
except CollectionValidationError as e:
print(f"Validation error: {e}")
Requirements
- Python 3.8+
- No external dependencies for core functionality
Development
Setting up Development Environment
# Clone the repository
git clone https://github.com/python-postman/python-postman.git
cd python-postman
# Install development dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run tests with coverage
pytest --cov=python_postman
# Format code
black python_postman tests
isort python_postman tests
# Type checking
mypy python_postman
Running Tests
# Run all tests
pytest
# Run specific test file
pytest tests/test_collection.py
# Run with verbose output
pytest -v
# Run with coverage report
pytest --cov=python_postman --cov-report=html
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
0.8.0 (Updated version)
- Updated version to 0.8.0
- Updated README.md
- Updated pyproject.toml
- Updated tests
- Updated docs
- Updated examples
- Updated code
Support
If you encounter any issues or have questions, please file an issue on the GitHub issue tracker.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file python_postman-0.9.0.tar.gz.
File metadata
- Download URL: python_postman-0.9.0.tar.gz
- Upload date:
- Size: 298.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
391eea40fc4b17c0291daa7310af7e448440385567297f2ab0ed0410df9c1227
|
|
| MD5 |
28a45d70f8d5328431ca7f1cf7cdae13
|
|
| BLAKE2b-256 |
1c0f4810fd90ed86745c125ebb2e418ed62a9c86a5aa11ee62738a0145163190
|
Provenance
The following attestation bundles were made for python_postman-0.9.0.tar.gz:
Publisher:
python-publish.yml on yudiell/python-postman
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
python_postman-0.9.0.tar.gz -
Subject digest:
391eea40fc4b17c0291daa7310af7e448440385567297f2ab0ed0410df9c1227 - Sigstore transparency entry: 602610105
- Sigstore integration time:
-
Permalink:
yudiell/python-postman@f52cb4d0d3bf749e4ba82552618981a25f2b503a -
Branch / Tag:
refs/tags/v0.9.0 - Owner: https://github.com/yudiell
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@f52cb4d0d3bf749e4ba82552618981a25f2b503a -
Trigger Event:
release
-
Statement type:
File details
Details for the file python_postman-0.9.0-py3-none-any.whl.
File metadata
- Download URL: python_postman-0.9.0-py3-none-any.whl
- Upload date:
- Size: 93.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
30ab25a8991e2550de7bedaf2878a7de803d1a466ad5af5951b8cb82192987a9
|
|
| MD5 |
802e2e9385f615a65e9398b2848afb94
|
|
| BLAKE2b-256 |
cfbd65813cf10f8785ef05915ba7c83e324b87efa1c772d119439c765f18b5a0
|
Provenance
The following attestation bundles were made for python_postman-0.9.0-py3-none-any.whl:
Publisher:
python-publish.yml on yudiell/python-postman
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
python_postman-0.9.0-py3-none-any.whl -
Subject digest:
30ab25a8991e2550de7bedaf2878a7de803d1a466ad5af5951b8cb82192987a9 - Sigstore transparency entry: 602610133
- Sigstore integration time:
-
Permalink:
yudiell/python-postman@f52cb4d0d3bf749e4ba82552618981a25f2b503a -
Branch / Tag:
refs/tags/v0.9.0 - Owner: https://github.com/yudiell
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@f52cb4d0d3bf749e4ba82552618981a25f2b503a -
Trigger Event:
release
-
Statement type: