__init__.py :  » Development » SnapLogic » snaplogic » rp » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Development » SnapLogic 
SnapLogic » snaplogic » rp » __init__.py
# $SnapHashLicense:
# 
# SnapLogic - Open source data services
# 
# Copyright (C) 2008-2009, SnapLogic, Inc.  All rights reserved.
# 
# See http://www.snaplogic.org for more information about
# the SnapLogic project. 
# 
# This program is free software, distributed under the terms of
# the GNU General Public License Version 2. See the LEGAL file
# at the top of the source tree.
# 
# "SnapLogic" is a trademark of SnapLogic, Inc.
# 
# 
# $

# $Id: __init__.py 6314 2009-02-11 01:07:59Z grisha $

"""
This package contains SnapLogic-provided Representation Plugins (RPs).

"""

from snaplogic.common.snap_exceptions import *

content_type_map = {}

SNAP_MAGIC_CONTENT_TYPE = 'snapi-undefined/snapi-undefined'

SNAP_ASN1_CONTENT_TYPE = 'application/x-snap-asn1'

def get_supported_content_types():
    """
    Get supported content types.
    
    Get a list of content types supported by this RP Layer.
    
    @return: a list of supported content types with preferences.
        
    @rtype: sequence, each of whose elements is a two-tuple, with first
    element being content type, and the second being the preference 
    (q-value)
    
    """ 
    return ['application/x-snap-asn1;q=1.0', 
            'application/json;q=0.9', 
            'application/asn1;q=0.8',
            'text/html;q=0.6',
            'text/csv;q=0.6',
            'text/tab-separated-values;q=0.6']

def _content_type_comparator(x, y):
    """
    Compare content type preferences.
    
    A comparator used to sort accepted content types based on
    preferences. It is intended to be used in L{select_content_type}.
    
    See L{cmp}.
    
    @param x: a tuple describing an acceptable content type, with three elements:
    content-type, preference (q-value), and further specification of media range
    (e.g., 'level=1').
    @type x: tuple
    
    @param y: same as x
    @type y: tuple
    
    @return: -1 if x is preferable, 1 if y is preferable, 0 if they are the same.
    @rtype: int
    
    """
    
    if type(x) == tuple:
        x = list(x)
    if type(y) == tuple:
        y = list(y)
    if x[2] is None:
        x[2] = '1.0'
    if y[2] is None:
        y[2] = '1.0'
    compare_quality = -cmp(float(x[2]),float(y[2]))
    if compare_quality:
        return compare_quality
    (xtype,xsubtype) = x[0].split('/')
    (ytype,ysubtype) = y[0].split('/')
    
    if xtype == '*':
        return 1
    if ytype == '*':
        return -1
    if xsubtype == '*':
        return 1
    if ysubtype == '*':
        return -1
    
    if xtype == ytype and xsubtype == ysubtype:
        if x[1] and not y[1]:
            return -1
        elif y[1] and not x[1]:
            return 1
    return 0
    
def negotiate_content_type_str(client_ctype, server_ctype):
    """
    Carries out content negotiation between client and this HTTP server with content types specified in string form.
    
    @param client_ctype:  A content type requested by client GET request (via Accept header) or
        specified in client POST request (via Content-Type header).
    @type client_ctype:   str

    @param server_ctype:  A list of content type names to consider for satisfying the client request. If None,
                          the list defaults to the supported RP content types.
    @type server_ctype:   list

    @return:              The negotiated content type name or None if negotiation fails.
    @rtype:               str
    
    """
    if not client_ctype:
        client_ctype = "*/*"
    else:
        client_list = client_ctype.split(',')
    matched_ct = select_content_type(client_list, server_ctype)
    if matched_ct is None:
        return None

    return matched_ct

def select_content_type(accept_list, supported=None):
    """
    Select content type for reply to client.

    Applies the algorithm specified in RFC 2616, section 14.1 to
    select the content type with which to respond to the client,
    based on the provided list of content types acceptable by
    the client.
    
    @param accept_list: list of strings, each representing a media type, e.g., 
    ['image/gif', 'text/html;level=1', 'text/xml;q=1.0']. Each element of the list
    can legitimately occur by itself in the Accept: header field. 
    
    @param supported: list of supported content types. If this
    parameter is None, the content types (see L{get_supported_content_types}) 
    from the config files are used.
    
    @type supported: list 
    
    @return: a tuple consisting of a negotiated content type and negotiated version (or None
    if not applicable) 
    @rtype: tuple
    """
    if supported is None:
        supported = get_supported_content_types()
    
        
    # For now we just ignore the q parameter, and treat 'supported'
    # list
    supported = _parse_accept_list(supported)
    
    accept = _parse_accept_list(accept_list)
    accept.sort(_content_type_comparator)
    for candidate in accept:
        try:
            (type,subtype) = candidate[0].split('/')
        except Exception, e:
            raise ValueError('Malformed content type: %s, expected: type/subtype' % candidate[0])
        for sup in supported:
            sup_media_with_range = sup[0]
            if sup[1]:
                sup_media_with_range += ';' + sup[1]
            if type == '*':
                return sup_media_with_range
            (sup_type, sup_subtype) = sup_media_with_range.split('/')
            if type == sup_type:
                if subtype == '*' or subtype == sup_subtype:
                    return sup_media_with_range
    return None

def _parse_accept_list(accept_list):
    """
    Parses the list of accept_strings, for internal use.
    
    @param accept_list: a list of media ranges with accept parameters. Basically this is 
    the value of the Accept: header as specified in RFC 2616, split on comma.
    @type accepts: sequence
    
    @return: list of tuples representing values in the client-supplied Accept: 
    header. Each tuple contains 3 elements:
    content-type, further specification of media range (if any) and
    preference (assumed to be '1.0' if None). 
    
    @rtype: list of tuples. Each tuple contains 3 elements:
    content-type, further specification of media range (e.g., 'level=1'),
    and q value (preference; assumed to be '1.0' if None),
    """
    retval = []
    for accept in accept_list:
        elements = [s.strip() for s in accept.split(';')]
        media_type = elements[0]
        media_range = ''
        # Default q value
        q_value = '1.0'
        for param in elements[1:]:
            (name,value) = param.split('=')
            if name != 'q':
                if media_range:
                    media_range += ';'
                media_range += param
            else:
                q_value = value
                break
        tup = (media_type, media_range, q_value)
        retval.append(tup)
    return retval

def get_rp(accept, supported=None):
    """
    Get RP plugin based on the contents of the HTTP Accept: header.
    
    @param accept: Value of HTTP Accept: header, as specified in RFC 2616, section 14.1.
    @type accept: str
    
    @return: RP plugin, or None if not found.
    @rtype: module
    
    """ 
    accept_list = [s.strip() for s in accept.split(',')]
    ct = select_content_type(accept_list, supported)
    rp = _get_rp(ct)
    return rp
                    
def _get_rp(content_type):
    """
    Facade method for getting the correct RP plugin module given the content type.
    In the future, this will be based on the values of config file.
    
    @param content_type: MIME content type to use
    @type content_type: str
  
    @return: RP module, which has the Reader and Writer class defined
    @rtype: module 
    
    """
    
    global content_type_map
    if not content_type_map:
        from snaplogic.rp import json_rp,snap_asn1_rp,snap_asn1_rp_old,html_rp,tsv_rp,csv_rp
        content_type_map = {
                    
                    'application/json' : json_rp,
                    'application/asn1' : snap_asn1_rp_old,
                    'application/x-snap-asn1' : snap_asn1_rp,
                    'text/html'        : html_rp,
                    tsv_rp.CONTENT_TYPE: tsv_rp,
                    csv_rp.CONTENT_TYPE: csv_rp
                    }
    
    try:
        rp_module = content_type_map[content_type]
    except KeyError:
        rp_module = None
    return rp_module


def create_record(view, **kwargs):
    """
    Create a record out of a keyword-value dictionary

    This can be used to create a minimal record data structure
    from a view.

    The record will contain those keyword-value pairs in the kwargs
    that are also defined in the view.
    
    @param view   : View to base the record on
    @type  view   : dict

    @param kwargs : Key-value pairs to put in the record
    @type  kwargs : dict

    @return       : record structure
    @rtype        : list
    
    """
    def extract(viewpoint):
        return viewpoint[1]
    return [kwargs[extract(viewpoint)]
            for viewpoint in view
            if extract(viewpoint) in kwargs]

def create_simple_view(**kwargs):
    """
    Create a view out of a keyword-value dictionary

    This is a function for creating simple views.  The final field is
    always an empty string.

    @param kwargs : Mapping of field names to their types
    @type  kwargs : dict (string -> string)

    @return       : view structure
    @rtype        : list
    
    """
    return [(_field, _type, '')
            for _field, _type in kwargs.iteritems()]

def makeRawRecord(record, fieldNumbers = None):
    """
    Creates a "raw record" out of Snap Record. A "raw record" is merely a tuple
    of all field values, with no information on field names and types. 
    
    @param record: Snap record
    @type record: L{SnapLogic.Utils.DataTypes.Record}
    
    @param fieldNumbers: Mapping of record to actual fields requested downstream.
    @type fieldNumbers: list
    
    @return: a record as a list of values (Python objects)
    @rtype: list
    
    """
    if fieldNumbers != None:
        i = 1
        raw_rec = []
        for fieldName in record.fieldNames:
            if i in fieldNumbers:
                raw_rec.append(record.fields[fieldName])
            i += 1
        return raw_rec
    else:
        return [record.fields[f] for f in record.fieldNames] + record.passThroughFields

OBJECT_RESDEF = 'resdef'
"""Denotes a ResDef object type"""

OBJECT_TYPES = [OBJECT_RESDEF]

class _RPReader(object):
    
    """
    A marker interface for a Reader class of an RP plugin.
    All readers are iterators.
    
    
    """
    
    def __init__(self, stream=None, options=None):
        """
        Initialize the reader.
        
        @param stream:  Stream to read from. If None, the stream instance variable
        must be set later, before any other calls. 
        @type stream: L{SnapStream}

        @param options: A dictionary with optional parameters that may be interpreted
                        by the selected RP in any way. For example, an indication to
                        the HTML RP to use fixed-width rather than proportional font.
        @type  options: dict

        """
        self.stream  = stream
        self.options = options
    
    def read_nb(self):
        """
        Non-blocking read. 
        
        Reads as many objects from the stream as possible, and returns them as a sequence.
        
        @return: Sequence of objects read. Empty sequence is returned when no objects can
        be read. None is returned when end of stream has been reached.
        @rtype: sequence
        
        """
        if self.__class__.supports_non_blocking_read():
            raise SnapException('Implementation error: RPReader must implement this method.')
        else:
            raise SnapException('Operation not supported.')
        
    @classmethod
    def supports_non_blocking_read(cls):
        """
        Returns True if this Reader class supports non-blocking read (see L{read_nb})
        
        @return: True if this Reader supports non-blocking read, False otherwise
        @rtype: bool
        
        """
        return False
    
    def __iter__(self):
        return self
   
    def next(self):
        """
        This is a no-op implementation of a next() method necessary to make
        this an iterator. Reads the next raw record -- a list of field values, 
        as supported Python objects. Subclasses should override.
        
        @raise SnapEOFError: when the premature end of the underlying stream
        has been reached.  
         
        """
        pass
    
            
class _RPWriter(object):
    
    """
    For writing Python objects, in their appropriate representation, to a stream.
    
    """
    
    def __init__(self, stream=None, human_readable=False, stream_type=None, options=None):
        """
        Initializes the RP Writer object.
        
        @param stream: stream to write to. If None, L{stream} instance variable must be set
        prior to calling other methods on this object.
        @type stream: a duck-typed stream, supporting write() method.
        
        @param version: Version, as 'MAJOR.MINOR'  
        
        @param human_readable: 
        @type human_readable: bool
        
        @param stream_type: describes types of objects that will be written to this stream. This 
        is only useful if human_readable parameter is True, and will be used to appropriately
        format the objects. Note that they "type" here means one of L{OBJECT_TYPES}. If this argument is 
        None, then the RPWriter is object-agnostic. Note also that RPWRiter MAY choose to be 
        object-agnostic in any case. 
        @type stream_type: str
        
        @param options: A dictionary with optional parameters that may be interpreted
                        by the selected RP in any way. For example, an indication to
                        the HTML RP to use fixed-width rather than proportional font.
        @type  options: dict

        """
        self.stream         = stream
        self.human_readable = human_readable
        self.stream_type    = stream_type
        self.options        = options


    def initialize(self, header=""):
        """
        Initialize the underlying stream (by writing any headers
        necessary before starting to write records).
        
        @param header: header to write before sending records
        @type header: str
        
        @return: raw data written to the stream
        @rtype: str
        
        """
        
        pass
    
    def end(self, footer=""):
        """
        Write out any footers necessary. Does not actually close
        the underlying stream.
        
        @param header: footer to write before sending records
        @type footer: str
        
        @return: raw data written to the stream
        @rtype: str
        
        """
        pass
        
    def write(self, record, options=None):
        """
        Writes out a record's representation onto the underlying stream. This
        is not a Snap Record, but a Python data type (primitives, dicts, lists,
        etc).
        
        @param record: a record to write
        @type record: a python object

        @param options: a per-object dictionary of option, which may be used
                        or ignored by specific RPs.
        @type options: dict
        
        @return: raw data written to the stream
        @rtype: str
        
        """
        pass
    

www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.