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