CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-google-api-python-client

Google API Client Library for Python that provides discovery-based access to hundreds of Google services with authentication, caching, and media upload/download support.

Pending
Overview
Eval results
Files

mimeparse.mddocs/

MIME Type Parsing and Content Negotiation

The mimeparse module provides utilities for parsing MIME types, media ranges, and performing content negotiation. It helps applications determine the best content type to serve based on client preferences and server capabilities.

Capabilities

MIME Type Parsing

Parse MIME type strings into structured components for analysis and comparison.

def parse_mime_type(mime_type):
    """
    Parse a MIME type string into its components.
    
    Args:
        mime_type (str): MIME type string (e.g., 'text/html; charset=utf-8')
        
    Returns:
        tuple: (type, subtype, params) where:
            - type (str): Main type (e.g., 'text')
            - subtype (str): Subtype (e.g., 'html')  
            - params (dict): Parameters (e.g., {'charset': 'utf-8'})
    """

def parse_media_range(range):
    """
    Parse a media range string into components with quality factor.
    
    Args:
        range (str): Media range string (e.g., 'text/html;q=0.9')
        
    Returns:
        tuple: (type, subtype, params, quality) where:
            - type (str): Main type
            - subtype (str): Subtype
            - params (dict): Parameters excluding quality
            - quality (float): Quality factor (0.0 to 1.0)
    """

Content Negotiation

Determine the best content type match based on client preferences and server capabilities.

def quality_parsed(mime_type_list, ranges):
    """
    Calculate quality for parsed MIME types against client ranges.
    
    Args:
        mime_type_list (list): List of (type, subtype, params) tuples
        ranges (list): List of parsed media ranges with quality factors
        
    Returns:
        float: Quality factor (0.0 to 1.0) for the best match
    """

def quality(mime_type, ranges):
    """
    Calculate quality of a MIME type against client Accept header ranges.
    
    Args:
        mime_type (str): MIME type to evaluate (e.g., 'application/json')
        ranges (str): Accept header value with media ranges and quality factors
        
    Returns:
        float: Quality factor (0.0 to 1.0) indicating preference level
    """

def best_match(supported, header):
    """
    Find the best matching MIME type from supported types.
    
    Args:
        supported (list): List of MIME types supported by the server
        header (str): Client Accept header value
        
    Returns:
        str: Best matching MIME type from supported list, or None if no match
    """

Usage Examples

Basic MIME Type Parsing

from googleapiclient.mimeparse import parse_mime_type, parse_media_range

# Parse a simple MIME type
mime_type = "text/html"
type_, subtype, params = parse_mime_type(mime_type)
print(f"Type: {type_}, Subtype: {subtype}, Params: {params}")
# Output: Type: text, Subtype: html, Params: {}

# Parse MIME type with parameters
mime_type_with_params = "text/html; charset=utf-8; boundary=something"
type_, subtype, params = parse_mime_type(mime_type_with_params)
print(f"Type: {type_}, Subtype: {subtype}, Params: {params}")
# Output: Type: text, Subtype: html, Params: {'charset': 'utf-8', 'boundary': 'something'}

# Parse media range with quality factor
media_range = "application/json;q=0.8"
type_, subtype, params, quality = parse_media_range(media_range)
print(f"Quality: {quality}")
# Output: Quality: 0.8

Content Negotiation

from googleapiclient.mimeparse import best_match, quality

# Server-supported MIME types
supported_types = [
    'application/json',
    'application/xml',
    'text/html',
    'text/plain'
]

# Client Accept headers (examples)
accept_headers = [
    'application/json, application/xml;q=0.9, */*;q=0.1',
    'text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8',
    'application/xml, application/json;q=0.8, text/plain;q=0.5',
    '*/*'
]

for accept_header in accept_headers:
    best = best_match(supported_types, accept_header)
    print(f"Accept: {accept_header}")
    print(f"Best match: {best}")
    print()

# Check quality of specific MIME type
mime_type = 'application/json'
accept_header = 'application/json;q=0.9, application/xml;q=0.8, */*;q=0.1'
quality_score = quality(mime_type, accept_header)
print(f"Quality of {mime_type}: {quality_score}")

API Response Content Negotiation

from googleapiclient.mimeparse import best_match
from googleapiclient import discovery
from flask import Flask, request

app = Flask(__name__)

class ContentNegotiator:
    """Handle content negotiation for API responses."""
    
    def __init__(self):
        self.supported_formats = {
            'application/json': self._format_json,
            'application/xml': self._format_xml,
            'text/csv': self._format_csv,
            'text/plain': self._format_plain
        }
    
    def negotiate_response_format(self, data, accept_header):
        """
        Negotiate the best response format based on Accept header.
        
        Args:
            data: Response data to format
            accept_header (str): Client Accept header
            
        Returns:
            tuple: (formatted_data, content_type)
        """
        supported_types = list(self.supported_formats.keys())
        best_type = best_match(supported_types, accept_header)
        
        if not best_type:
            # Default to JSON if no match
            best_type = 'application/json'
        
        formatter = self.supported_formats[best_type]
        formatted_data = formatter(data)
        
        return formatted_data, best_type
    
    def _format_json(self, data):
        """Format data as JSON."""
        import json
        return json.dumps(data, indent=2)
    
    def _format_xml(self, data):
        """Format data as XML."""
        # Simplified XML formatting
        def dict_to_xml(d, root_name='root'):
            xml = f'<{root_name}>'
            for key, value in d.items():
                if isinstance(value, dict):
                    xml += dict_to_xml(value, key)
                elif isinstance(value, list):
                    for item in value:
                        xml += dict_to_xml(item, key[:-1] if key.endswith('s') else key)
                else:
                    xml += f'<{key}>{value}</{key}>'
            xml += f'</{root_name}>'
            return xml
        
        return dict_to_xml(data, 'response')
    
    def _format_csv(self, data):
        """Format data as CSV."""
        import csv
        import io
        
        output = io.StringIO()
        if isinstance(data, list) and data:
            # Assume list of dictionaries
            fieldnames = data[0].keys()
            writer = csv.DictWriter(output, fieldnames=fieldnames)
            writer.writeheader()
            writer.writerows(data)
        elif isinstance(data, dict):
            # Single dictionary
            writer = csv.DictWriter(output, fieldnames=data.keys())
            writer.writeheader()
            writer.writerow(data)
        
        return output.getvalue()
    
    def _format_plain(self, data):
        """Format data as plain text."""
        return str(data)

# Flask route with content negotiation
negotiator = ContentNegotiator()

@app.route('/api/messages')
def get_messages():
    # Get messages from Gmail API
    service = discovery.build('gmail', 'v1', credentials=credentials)
    try:
        messages_result = service.users().messages().list(
            userId='me', 
            maxResults=10
        ).execute()
        
        messages = messages_result.get('messages', [])
        
        # Negotiate response format
        accept_header = request.headers.get('Accept', 'application/json')
        formatted_data, content_type = negotiator.negotiate_response_format(
            messages, 
            accept_header
        )
        
        return formatted_data, 200, {'Content-Type': content_type}
        
    except Exception as e:
        error_data = {'error': str(e)}
        accept_header = request.headers.get('Accept', 'application/json')
        formatted_error, content_type = negotiator.negotiate_response_format(
            error_data, 
            accept_header
        )
        return formatted_error, 500, {'Content-Type': content_type}

if __name__ == '__main__':
    app.run(debug=True)

MIME Type Validation

from googleapiclient.mimeparse import parse_mime_type

class MimeTypeValidator:
    """Validate and analyze MIME types."""
    
    def __init__(self):
        self.allowed_types = {
            'text': ['plain', 'html', 'csv', 'css', 'javascript'],
            'application': ['json', 'xml', 'pdf', 'zip', 'octet-stream'],
            'image': ['jpeg', 'png', 'gif', 'svg+xml'],
            'audio': ['mpeg', 'wav', 'ogg'],
            'video': ['mp4', 'mpeg', 'quicktime']
        }
    
    def is_valid_mime_type(self, mime_type):
        """
        Check if a MIME type is valid and allowed.
        
        Args:
            mime_type (str): MIME type to validate
            
        Returns:
            tuple: (is_valid, reason)
        """
        try:
            type_, subtype, params = parse_mime_type(mime_type)
        except Exception as e:
            return False, f"Invalid MIME type format: {e}"
        
        if type_ not in self.allowed_types:
            return False, f"Type '{type_}' not allowed"
        
        if subtype not in self.allowed_types[type_]:
            return False, f"Subtype '{subtype}' not allowed for type '{type_}'"
        
        return True, "Valid MIME type"
    
    def get_file_categories(self, mime_types):
        """Categorize MIME types by file type."""
        categories = {
            'documents': [],
            'images': [],
            'media': [],
            'data': [],
            'other': []
        }
        
        for mime_type in mime_types:
            try:
                type_, subtype, _ = parse_mime_type(mime_type)
                
                if type_ == 'text' or (type_ == 'application' and subtype in ['pdf', 'msword']):
                    categories['documents'].append(mime_type)
                elif type_ == 'image':
                    categories['images'].append(mime_type)
                elif type_ in ['audio', 'video']:
                    categories['media'].append(mime_type)
                elif type_ == 'application' and subtype in ['json', 'xml', 'csv']:
                    categories['data'].append(mime_type)
                else:
                    categories['other'].append(mime_type)
                    
            except Exception:
                categories['other'].append(mime_type)
        
        return categories

# Usage
validator = MimeTypeValidator()

test_mime_types = [
    'text/plain',
    'application/json',
    'image/jpeg',
    'invalid/mime/type',
    'application/unknown'
]

for mime_type in test_mime_types:
    is_valid, reason = validator.is_valid_mime_type(mime_type)
    print(f"{mime_type}: {'✓' if is_valid else '✗'} - {reason}")

# Categorize file types
file_mime_types = [
    'text/plain', 'application/pdf', 'image/jpeg', 
    'audio/mpeg', 'application/json', 'text/html'
]

categories = validator.get_file_categories(file_mime_types)
for category, types in categories.items():
    if types:
        print(f"{category.title()}: {', '.join(types)}")

Advanced Content Negotiation

from googleapiclient.mimeparse import quality_parsed, parse_media_range

class AdvancedContentNegotiator:
    """Advanced content negotiation with custom scoring."""
    
    def __init__(self):
        self.type_preferences = {
            'application/json': 1.0,
            'application/xml': 0.8,
            'text/html': 0.6,
            'text/plain': 0.4
        }
    
    def negotiate_with_scoring(self, supported_types, accept_header):
        """
        Negotiate content type with custom server preferences.
        
        Args:
            supported_types (list): MIME types supported by server
            accept_header (str): Client Accept header
            
        Returns:
            tuple: (best_type, combined_score)
        """
        # Parse client preferences
        client_ranges = []
        for range_str in accept_header.split(','):
            range_str = range_str.strip()
            try:
                type_, subtype, params, quality = parse_media_range(range_str)
                client_ranges.append((type_, subtype, params, quality))
            except Exception:
                continue
        
        best_match = None
        best_score = 0.0
        
        for mime_type in supported_types:
            # Parse server MIME type
            try:
                from googleapiclient.mimeparse import parse_mime_type
                type_, subtype, params = parse_mime_type(mime_type)
                server_parsed = [(type_, subtype, params)]
                
                # Calculate client quality
                client_quality = quality_parsed(server_parsed, client_ranges)
                
                # Apply server preference
                server_preference = self.type_preferences.get(mime_type, 0.5)
                
                # Combined score
                combined_score = client_quality * server_preference
                
                if combined_score > best_score:
                    best_score = combined_score
                    best_match = mime_type
                    
            except Exception:
                continue
        
        return best_match, best_score
    
    def get_negotiation_details(self, supported_types, accept_header):
        """Get detailed negotiation information."""
        details = []
        
        for mime_type in supported_types:
            try:
                from googleapiclient.mimeparse import quality
                client_quality = quality(mime_type, accept_header)
                server_preference = self.type_preferences.get(mime_type, 0.5)
                combined_score = client_quality * server_preference
                
                details.append({
                    'mime_type': mime_type,
                    'client_quality': client_quality,
                    'server_preference': server_preference,
                    'combined_score': combined_score
                })
            except Exception:
                continue
        
        # Sort by combined score
        details.sort(key=lambda x: x['combined_score'], reverse=True)
        return details

# Usage
negotiator = AdvancedContentNegotiator()

supported = ['application/json', 'application/xml', 'text/html', 'text/plain']
accept_header = 'text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8'

best_type, score = negotiator.negotiate_with_scoring(supported, accept_header)
print(f"Best match: {best_type} (score: {score:.3f})")

# Get detailed breakdown
details = negotiator.get_negotiation_details(supported, accept_header)
print("\nNegotiation details:")
for detail in details:
    print(f"  {detail['mime_type']}: "
          f"client={detail['client_quality']:.2f}, "
          f"server={detail['server_preference']:.2f}, "
          f"combined={detail['combined_score']:.3f}")

MIME Type Utilities

from googleapiclient.mimeparse import parse_mime_type, best_match

class MimeTypeUtils:
    """Utility functions for working with MIME types."""
    
    @staticmethod
    def is_text_type(mime_type):
        """Check if MIME type is a text type."""
        try:
            type_, _, _ = parse_mime_type(mime_type)
            return type_ == 'text'
        except Exception:
            return False
    
    @staticmethod
    def is_binary_type(mime_type):
        """Check if MIME type is a binary type."""
        try:
            type_, subtype, _ = parse_mime_type(mime_type)
            # Common binary types
            binary_types = {
                'image': True,
                'audio': True,
                'video': True,
                'application': subtype not in ['json', 'xml', 'javascript', 'css']
            }
            return binary_types.get(type_, False)
        except Exception:
            return False
    
    @staticmethod
    def get_preferred_extension(mime_type):
        """Get preferred file extension for MIME type."""
        extensions = {
            'text/plain': '.txt',
            'text/html': '.html',
            'text/css': '.css',
            'application/json': '.json',
            'application/xml': '.xml',
            'application/pdf': '.pdf',
            'image/jpeg': '.jpg',
            'image/png': '.png',
            'image/gif': '.gif',
            'audio/mpeg': '.mp3',
            'video/mp4': '.mp4'
        }
        return extensions.get(mime_type, '')
    
    @staticmethod
    def select_encoding(mime_type):
        """Select appropriate encoding for MIME type."""
        if MimeTypeUtils.is_text_type(mime_type):
            return 'utf-8'
        else:
            return 'binary'

# Usage examples
utils = MimeTypeUtils()

test_types = [
    'text/plain',
    'application/json', 
    'image/jpeg',
    'application/pdf',
    'audio/mpeg'
]

for mime_type in test_types:
    is_text = utils.is_text_type(mime_type)
    is_binary = utils.is_binary_type(mime_type)
    extension = utils.get_preferred_extension(mime_type)
    encoding = utils.select_encoding(mime_type)
    
    print(f"{mime_type}:")
    print(f"  Text: {is_text}, Binary: {is_binary}")
    print(f"  Extension: {extension}, Encoding: {encoding}")
    print()

Install with Tessl CLI

npx tessl i tessl/pypi-google-api-python-client@2.181.1

docs

auth.md

channel.md

discovery.md

errors.md

http.md

index.md

media.md

mimeparse.md

model.md

schema.md

testing.md

tile.json