| 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 | |
|---|