PageRenderTime 27ms CodeModel.GetById 19ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/galaxy/model/custom_types.py

https://bitbucket.org/cistrome/cistrome-harvard/
Python | 149 lines | 82 code | 26 blank | 41 comment | 12 complexity | 21839754e7ee38749e2de04a16a63c4c MD5 | raw file
  1from sqlalchemy.types import *
  2
  3import json
  4import pickle
  5import copy
  6import uuid
  7import binascii
  8from galaxy.util.bunch import Bunch
  9from galaxy.util.aliaspickler import AliasPickleModule
 10
 11# For monkeypatching BIGINT
 12import sqlalchemy.dialects.sqlite
 13import sqlalchemy.dialects.postgresql
 14import sqlalchemy.dialects.mysql
 15
 16import logging
 17log = logging.getLogger( __name__ )
 18
 19# Default JSON encoder and decoder
 20json_encoder = json.JSONEncoder( sort_keys=True )
 21json_decoder = json.JSONDecoder( )
 22
 23def _sniffnfix_pg9_hex(value):
 24    """
 25    Sniff for and fix postgres 9 hex decoding issue
 26    """
 27    try:
 28        if value[0] == 'x':
 29            return binascii.unhexlify(value[1:])
 30        elif value.startswith( '\\x' ):
 31            return binascii.unhexlify( value[2:] )
 32        else:
 33            return value
 34    except Exception, ex:
 35        return value
 36
 37class JSONType( TypeDecorator ):
 38    """
 39    Defines a JSONType for SQLAlchemy.  Takes a primitive as input and
 40    JSONifies it.  This should replace PickleType throughout Galaxy.
 41    """
 42    impl = LargeBinary
 43
 44    def process_bind_param( self, value, dialect ):
 45        if value is None:
 46            return None
 47        return json_encoder.encode( value )
 48
 49    def process_result_value( self, value, dialect ):
 50        if value is None:
 51            return None
 52        return json_decoder.decode( str( _sniffnfix_pg9_hex(value) ) )
 53
 54    def copy_value( self, value ):
 55        # return json_decoder.decode( json_encoder.encode( value ) )
 56        return copy.deepcopy( value )
 57
 58    def compare_values( self, x, y ):
 59        # return json_encoder.encode( x ) == json_encoder.encode( y )
 60        return ( x == y )
 61
 62    def is_mutable( self ):
 63        return True
 64
 65metadata_pickler = AliasPickleModule( {
 66    ( "cookbook.patterns", "Bunch" ) : ( "galaxy.util.bunch" , "Bunch" )
 67} )
 68
 69class MetadataType( JSONType ):
 70    """
 71    Backward compatible metadata type. Can read pickles or JSON, but always
 72    writes in JSON.
 73    """
 74    def process_result_value( self, value, dialect ):
 75        if value is None:
 76            return None
 77        ret = None
 78        try:
 79            ret = metadata_pickler.loads( str( value ) )
 80            if ret:
 81                ret = dict( ret.__dict__ )
 82        except:
 83            try:
 84                ret = json_decoder.decode( str( _sniffnfix_pg9_hex(value) ) )
 85            except:
 86                ret = None
 87        return ret
 88
 89class UUIDType(TypeDecorator):
 90    """
 91    Platform-independent UUID type.
 92
 93    Based on http://docs.sqlalchemy.org/en/rel_0_8/core/types.html#backend-agnostic-guid-type
 94    Changed to remove sqlalchemy 0.8 specific code
 95
 96    CHAR(32), storing as stringified hex values.
 97    """
 98    impl = CHAR
 99
100    def load_dialect_impl(self, dialect):
101        return dialect.type_descriptor(CHAR(32))
102
103    def process_bind_param(self, value, dialect):
104        if value is None:
105            return value
106        else:
107            if not isinstance(value, uuid.UUID):
108                return "%.32x" % uuid.UUID(value)
109            else:
110                # hexstring
111                return "%.32x" % value
112
113    def process_result_value(self, value, dialect):
114        if value is None:
115            return value
116        else:
117            return uuid.UUID(value)
118
119
120class TrimmedString( TypeDecorator ):
121    impl = String
122    def process_bind_param( self, value, dialect ):
123        """Automatically truncate string values"""
124        if self.impl.length and value is not None:
125            value = value[0:self.impl.length]
126        return value
127
128
129#class BigInteger( Integer ):
130    #"""
131    #A type for bigger ``int`` integers.
132
133    #Typically generates a ``BIGINT`` in DDL, and otherwise acts like
134    #a normal :class:`Integer` on the Python side.
135
136    #"""
137
138#class BIGINT( BigInteger ):
139    #"""The SQL BIGINT type."""
140
141#class SLBigInteger( BigInteger ):
142    #def get_col_spec( self ):
143        #return "BIGINT"
144
145#sqlalchemy.dialects.sqlite.SLBigInteger = SLBigInteger
146#sqlalchemy.dialects.sqlite.colspecs[BigInteger] = SLBigInteger
147#sqlalchemy.dialects.sqlite.ischema_names['BIGINT'] = SLBigInteger
148#sqlalchemy.dialects.postgres.colspecs[BigInteger] = sqlalchemy.dialects.postgres.PGBigInteger
149#sqlalchemy.dialects.mysql.colspecs[BigInteger] = sqlalchemy.dialects.mysql.MSBigInteger