CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-gidgethub

An asynchronous GitHub API library designed as a sans-I/O library for GitHub API access

Pending
Overview
Eval results
Files

sansio.mddocs/

Sans-I/O Functions

Pure functions for HTTP request/response processing, webhook validation, rate limiting, and URL formatting without performing any I/O operations. This sans-I/O design allows users to choose their preferred HTTP library while gidgethub handles GitHub-specific API details.

Capabilities

Webhook Validation

Validate the signature of GitHub webhook events using HMAC with SHA-256 or SHA-1.

def validate_event(payload: bytes, *, signature: str, secret: str) -> None:
    """
    Validate the signature of a webhook event.
    
    Parameters:
    - payload: The raw webhook payload bytes
    - signature: The signature from X-Hub-Signature or X-Hub-Signature-256 header
    - secret: The webhook secret configured in GitHub
    
    Raises:
    - ValidationFailure: If signature validation fails
    """

Request Header Creation

Create GitHub-specific HTTP headers with proper user agent, API version, and authentication.

def create_headers(
    requester: str,
    *,
    accept: str = accept_format(),
    oauth_token: Optional[str] = None,
    jwt: Optional[str] = None
) -> Dict[str, str]:
    """
    Create a dict representing GitHub-specific header fields.
    
    Parameters:
    - requester: User agent identifier (username or project name)
    - accept: Accept header for API version and format
    - oauth_token: Personal access token for authentication
    - jwt: JWT bearer token for GitHub App authentication
    
    Returns:
    - Dict of lowercased header field names to values
    
    Raises:
    - ValueError: If both oauth_token and jwt are provided
    """

def accept_format(
    *, 
    version: str = "v3", 
    media: Optional[str] = None, 
    json: bool = True
) -> str:
    """
    Construct the specification of the format that a request should return.
    
    Parameters:
    - version: GitHub API version (default: "v3")
    - media: Media type for alternative formats
    - json: Whether to request JSON format
    
    Returns:
    - Accept header value
    """

Response Processing

Decode HTTP responses and extract rate limit information and pagination links.

def decipher_response(
    status_code: int, 
    headers: Mapping[str, str], 
    body: bytes
) -> Tuple[Any, Optional[RateLimit], Optional[str]]:
    """
    Decipher an HTTP response for a GitHub API request.
    
    Parameters:
    - status_code: HTTP response status code
    - headers: HTTP response headers (with lowercase keys)
    - body: HTTP response body bytes
    
    Returns:
    - Tuple of (decoded_body, rate_limit, next_page_url)
    
    Raises:
    - HTTPException: For non-success status codes
    - RateLimitExceeded: When rate limit is exceeded
    - InvalidField: For 422 responses with field errors
    - ValidationError: For 422 responses with validation errors
    """

URL Formatting

Construct and expand GitHub API URLs with template variables.

def format_url(
    url: str, 
    url_vars: Optional[variable.VariableValueDict], 
    *, 
    base_url: str = DOMAIN
) -> str:
    """
    Construct a URL for the GitHub API.
    
    Parameters:
    - url: Absolute or relative URL (can be URI template)
    - url_vars: Variables for URI template expansion
    - base_url: Base URL for relative URLs (default: https://api.github.com)
    
    Returns:
    - Fully-qualified expanded URL
    """

Event Processing

Process GitHub webhook events from HTTP requests.

class Event:
    """Details of a GitHub webhook event."""
    
    def __init__(self, data: Any, *, event: str, delivery_id: str) -> None:
        """
        Initialize webhook event.
        
        Parameters:
        - data: Parsed webhook payload data
        - event: Event type (e.g., "push", "pull_request")
        - delivery_id: Unique delivery identifier
        """
    
    @classmethod
    def from_http(
        cls, 
        headers: Mapping[str, str], 
        body: bytes, 
        *, 
        secret: Optional[str] = None
    ) -> "Event":
        """
        Construct an event from HTTP headers and JSON body data.
        
        Parameters:
        - headers: HTTP headers (with lowercase keys)
        - body: Raw HTTP body bytes
        - secret: Webhook secret for validation (optional)
        
        Returns:
        - Event instance
        
        Raises:
        - BadRequest: For invalid content type
        - ValidationFailure: For signature validation failures
        """
    
    # Attributes
    data: Any  # Parsed webhook payload
    event: str  # Event type
    delivery_id: str  # Unique delivery ID

Rate Limit Tracking

Track GitHub API rate limits from HTTP response headers.

class RateLimit:
    """The rate limit imposed upon the requester."""
    
    def __init__(self, *, limit: int, remaining: int, reset_epoch: float) -> None:
        """
        Instantiate a RateLimit object.
        
        Parameters:
        - limit: Rate limit per hour
        - remaining: Remaining requests in current window
        - reset_epoch: Reset time in seconds since UTC epoch
        """
    
    def __bool__(self) -> bool:
        """True if requests are remaining or the reset datetime has passed."""
    
    def __str__(self) -> str:
        """Provide all details in a reasonable format."""
    
    @classmethod
    def from_http(cls, headers: Mapping[str, str]) -> Optional["RateLimit"]:
        """
        Gather rate limit information from HTTP headers.
        
        Parameters:
        - headers: HTTP response headers (with lowercase keys)
        
        Returns:
        - RateLimit instance or None if headers not found
        """
    
    # Attributes
    limit: int  # Requests per hour limit
    remaining: int  # Remaining requests
    reset_datetime: datetime.datetime  # Reset time (timezone-aware UTC)

Usage Examples

Webhook Validation

import gidgethub.sansio

def handle_webhook(request_headers, request_body, webhook_secret):
    try:
        # Validate webhook signature
        signature = request_headers.get('x-hub-signature-256', 
                                       request_headers.get('x-hub-signature'))
        gidgethub.sansio.validate_event(request_body, 
                                        signature=signature, 
                                        secret=webhook_secret)
        
        # Parse webhook event
        event = gidgethub.sansio.Event.from_http(request_headers, 
                                                  request_body, 
                                                  secret=webhook_secret)
        
        print(f"Received {event.event} event: {event.delivery_id}")
        return event
        
    except gidgethub.ValidationFailure as exc:
        print(f"Webhook validation failed: {exc}")
        raise

Manual HTTP Request Processing

import gidgethub.sansio
import httpx

async def make_github_request(url, oauth_token=None):
    # Create headers
    headers = gidgethub.sansio.create_headers(
        "my-app/1.0",
        oauth_token=oauth_token
    )
    
    # Make HTTP request
    async with httpx.AsyncClient() as client:
        response = await client.get(url, headers=headers)
        
        # Process response
        data, rate_limit, next_page = gidgethub.sansio.decipher_response(
            response.status_code,
            dict(response.headers),
            response.content
        )
        
        print(f"Rate limit: {rate_limit}")
        if next_page:
            print(f"Next page: {next_page}")
            
        return data

Constants

DOMAIN: str = "https://api.github.com"  # Default GitHub API base URL

Types

from typing import Any, Dict, Mapping, Optional, Tuple
from uritemplate import variable
import datetime

# Type alias for URI template variables
VariableValueDict = variable.VariableValueDict

Install with Tessl CLI

npx tessl i tessl/pypi-gidgethub

docs

actions.md

api-client.md

apps.md

exceptions.md

http-implementations.md

index.md

routing.md

sansio.md

tile.json