[2] | 1 | from sqlalchemy.types import * |
---|
| 2 | import pkg_resources |
---|
| 3 | pkg_resources.require("simplejson") |
---|
| 4 | import simplejson |
---|
| 5 | import pickle |
---|
| 6 | import copy |
---|
| 7 | from galaxy.util.bunch import Bunch |
---|
| 8 | from galaxy.util.aliaspickler import AliasPickleModule |
---|
| 9 | |
---|
| 10 | import logging |
---|
| 11 | log = logging.getLogger( __name__ ) |
---|
| 12 | |
---|
| 13 | # Default JSON encoder and decoder |
---|
| 14 | json_encoder = simplejson.JSONEncoder( sort_keys=True ) |
---|
| 15 | json_decoder = simplejson.JSONDecoder( ) |
---|
| 16 | |
---|
| 17 | class JSONType( TypeDecorator ): |
---|
| 18 | """ |
---|
| 19 | Defines a JSONType for SQLAlchemy. Takes a primitive as input and |
---|
| 20 | JSONifies it. This should replace PickleType throughout Galaxy. |
---|
| 21 | """ |
---|
| 22 | impl = Binary |
---|
| 23 | |
---|
| 24 | def process_bind_param( self, value, dialect ): |
---|
| 25 | if value is None: |
---|
| 26 | return None |
---|
| 27 | return json_encoder.encode( value ) |
---|
| 28 | |
---|
| 29 | def process_result_value( self, value, dialect ): |
---|
| 30 | if value is None: |
---|
| 31 | return None |
---|
| 32 | return json_decoder.decode( str( value ) ) |
---|
| 33 | |
---|
| 34 | def copy_value( self, value ): |
---|
| 35 | # return json_decoder.decode( json_encoder.encode( value ) ) |
---|
| 36 | return copy.deepcopy( value ) |
---|
| 37 | |
---|
| 38 | def compare_values( self, x, y ): |
---|
| 39 | # return json_encoder.encode( x ) == json_encoder.encode( y ) |
---|
| 40 | return ( x == y ) |
---|
| 41 | |
---|
| 42 | def is_mutable( self ): |
---|
| 43 | return True |
---|
| 44 | |
---|
| 45 | metadata_pickler = AliasPickleModule( { |
---|
| 46 | ( "cookbook.patterns", "Bunch" ) : ( "galaxy.util.bunch" , "Bunch" ) |
---|
| 47 | } ) |
---|
| 48 | |
---|
| 49 | class MetadataType( JSONType ): |
---|
| 50 | """ |
---|
| 51 | Backward compatible metadata type. Can read pickles or JSON, but always |
---|
| 52 | writes in JSON. |
---|
| 53 | """ |
---|
| 54 | def process_result_value( self, value, dialect ): |
---|
| 55 | if value is None: |
---|
| 56 | return None |
---|
| 57 | ret = None |
---|
| 58 | try: |
---|
| 59 | ret = metadata_pickler.loads( str( value ) ) |
---|
| 60 | if ret: |
---|
| 61 | ret = dict( ret.__dict__ ) |
---|
| 62 | except: |
---|
| 63 | try: |
---|
| 64 | ret = json_decoder.decode( str( value ) ) |
---|
| 65 | except: |
---|
| 66 | ret = None |
---|
| 67 | return ret |
---|
| 68 | |
---|
| 69 | class TrimmedString( TypeDecorator ): |
---|
| 70 | impl = String |
---|
| 71 | def process_bind_param( self, value, dialect ): |
---|
| 72 | """Automatically truncate string values""" |
---|
| 73 | if self.impl.length and value is not None: |
---|
| 74 | value = value[0:self.impl.length] |
---|
| 75 | return value |
---|
| 76 | |
---|