1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/eca1b4b64574/ Changeset: eca1b4b64574 User: carlfeberhard Date: 2015-02-02 18:33:06+00:00 Summary: Managers: add shorthand for adding a serializer view, back off of class-level url service, more testing Affected #: 10 files diff -r 620437dab02aa2bf8508292bc0df4b2e1066264e -r eca1b4b64574cf09b4cbe35c4a8b103c1b455a79 lib/galaxy/managers/base.py --- a/lib/galaxy/managers/base.py +++ b/lib/galaxy/managers/base.py @@ -29,6 +29,9 @@ pkg_resources.require( "SQLAlchemy >= 0.4" ) import sqlalchemy +pkg_resources.require("Routes") +import routes + from galaxy import exceptions from galaxy import model from galaxy import web @@ -490,15 +493,17 @@ that should be called for those keys. E.g. { 'x' : lambda trans, item, key: item.x, ... } + Note: if a key to serialize is not listed in the Serializer.serializable_keyset + or serializers, it will not be returned. + To serialize call: my_serializer = MySerializer( app ) ... keys_to_serialize = [ 'id', 'name', 'attr1', 'attr2', ... ] item_dict = MySerializer.serialize( trans, my_item, keys_to_serialize ) - # if a key to serialize is not listed in the Serializer.serializable_keys or serializers, it will not be added """ #: 'service' to use for getting urls - use class var to allow overriding when testing - url_for = web.url_for + #url_service = def __init__( self, app ): """ @@ -506,14 +511,17 @@ """ self.app = app + # a list of valid serializable keys that can use the default (string) serializer + # this allows us to: 'mention' the key without adding the default serializer + # TODO: we may want to eventually error if a key is requested + # that is in neither serializable_keyset or serializers + self.serializable_keyset = set([]) # a map of dictionary keys to the functions (often lambdas) that create the values for those keys self.serializers = {} - # a list of valid serializable keys that can use the default (string) serializer - # this allows us to: 'mention' the key without adding the default serializer - # NOTE: if a key is requested that is in neither serializable_keys or serializers, it is not returned - self.serializable_keys = [] # add subclass serializers defined there self.add_serializers() + # update the keyset by the serializers (removing the responsibility from subclasses) + self.serializable_keyset.update( self.serializers.keys() ) # views are collections of serializable attributes (a named array of keys) # inspired by model.dict_{view}_visible_keys @@ -528,6 +536,19 @@ # to be overridden in subclasses pass + def add_view( self, view_name, key_list, include_keys_from=None ): + """ + Add the list of serializable attributes `key_list` to the serializer's + view dictionary under the key `view_name`. + + If `include_keys_from` is a proper view name, extend `key_list` by + the list in that view. + """ + key_list += self.views.get( include_keys_from, [] ) + self.views[ view_name ] = key_list + self.serializable_keyset.update( key_list ) + return key_list + def serialize( self, trans, item, keys ): """ Serialize the model `item` to a dictionary. @@ -542,7 +563,7 @@ # check both serializers and serializable keys if key in self.serializers: returned[ key ] = self.serializers[ key ]( trans, item, key ) - elif key in self.serializable_keys: + elif key in self.serializable_keyset: returned[ key ] = self.default_serializer( trans, item, key ) # ignore bad/unreg keys return returned @@ -569,6 +590,10 @@ id = getattr( item, key ) return self.app.security.encode_id( id ) if id is not None else None + @staticmethod + def url_for( *args, **kwargs ): + return routes.url_for( *args, **kwargs ) + # serializing to a view where a view is a predefied list of keys to serialize def serialize_to_view( self, trans, item, view=None, keys=None, default_view=None ): """ @@ -628,7 +653,7 @@ self.app = app self.deserializers = {} - self.deserializable_keys = [] + self.deserializable_keyset = set([]) self.add_deserializers() # a sub object that can validate incoming values self.validate = ModelValidator( self.app ) diff -r 620437dab02aa2bf8508292bc0df4b2e1066264e -r eca1b4b64574cf09b4cbe35c4a8b103c1b455a79 lib/galaxy/managers/datasets.py --- a/lib/galaxy/managers/datasets.py +++ b/lib/galaxy/managers/datasets.py @@ -192,8 +192,8 @@ def __init__( self, app ): super( DatasetSerializer, self ).__init__( app ) - # most of these views build/add to the previous view - summary_view = [ + self.default_view = 'summary' + self.add_view( 'summary', [ 'id', 'create_time', 'update_time', 'state', @@ -203,19 +203,13 @@ #'extra_files_path', 'file_size', 'total_size', 'uuid', - ] + ]) # could do visualizations and/or display_apps - self.serializable_keys = summary_view + [ - ] - self.views = { - 'summary' : summary_view, - } - self.default_view = 'summary' - def add_serializers( self ): super( DatasetSerializer, self ).add_serializers() deletable.PurgableSerializerMixin.add_serializers( self ) + self.serializers.update({ 'id' : self.serialize_id, 'create_time' : self.serialize_date, diff -r 620437dab02aa2bf8508292bc0df4b2e1066264e -r eca1b4b64574cf09b4cbe35c4a8b103c1b455a79 lib/galaxy/managers/deletable.py --- a/lib/galaxy/managers/deletable.py +++ b/lib/galaxy/managers/deletable.py @@ -35,7 +35,7 @@ class DeletableSerializerMixin( object ): def add_serializers( self ): - pass + self.serializable_keyset.add( 'deleted' ) # TODO: these are of questionable value if we don't want to enable users to delete/purge via update @@ -87,6 +87,7 @@ def add_serializers( self ): DeletableSerializerMixin.add_serializers( self ) + self.serializable_keyset.add( 'purged' ) class PurgableDeserializerMixin( DeletableDeserializerMixin ): diff -r 620437dab02aa2bf8508292bc0df4b2e1066264e -r eca1b4b64574cf09b4cbe35c4a8b103c1b455a79 lib/galaxy/managers/hdas.py --- a/lib/galaxy/managers/hdas.py +++ b/lib/galaxy/managers/hdas.py @@ -315,8 +315,8 @@ super( HDASerializer, self ).__init__( app ) self.hda_manager = HDAManager( app ) - # most of these views build/add to the previous view - summary_view = [ + self.default_view = 'summary' + self.add_view( 'summary', [ 'id', 'name', 'history_id', 'hid', # why include if model_class is there? @@ -325,12 +325,8 @@ 'state', 'extension', 'deleted', 'purged', 'visible', 'resubmitted', 'type', 'url' - ] - inaccessible = [ - 'id', 'name', 'history_id', 'hid', 'history_content_type', - 'state', 'deleted', 'visible' - ] - detailed_view = summary_view + [ + ]) + self.add_view( 'detailed', [ 'model_class', 'history_id', 'hid', # why include if model_class is there? @@ -362,19 +358,17 @@ 'annotation', 'tags', 'api_type' - ] - extended_view = detailed_view + [ + ], include_keys_from='summary' ) + + self.add_view( 'extended', [ 'tool_version', 'parent_id', 'designation', - ] + ], include_keys_from='detailed' ) - self.serializable_keys = extended_view + [ - ] - self.views = { - 'summary' : summary_view, - 'detailed' : detailed_view, - 'extended' : extended_view, - } - self.default_view = 'summary' + # keyset returned to create show a dataset where the owner has no access + self.add_view( 'inaccessible', [ + 'id', 'name', 'history_id', 'hid', 'history_content_type', + 'state', 'deleted', 'visible' + ]) def add_serializers( self ): super( HDASerializer, self ).add_serializers() @@ -597,4 +591,4 @@ 'importable' : self.deserialize_bool, }) - self.deserializable_keys.extend( self.deserializers.keys() ) + self.deserializable_keyset.update( self.deserializers.keys() ) diff -r 620437dab02aa2bf8508292bc0df4b2e1066264e -r eca1b4b64574cf09b4cbe35c4a8b103c1b455a79 lib/galaxy/managers/histories.py --- a/lib/galaxy/managers/histories.py +++ b/lib/galaxy/managers/histories.py @@ -249,12 +249,13 @@ def __init__( self, app ): super( HistorySerializer, self ).__init__( app ) + self.history_manager = HistoryManager( app ) - self.hda_manager = hdas.HDAManager( app ) self.hda_serializer = hdas.HDASerializer( app ) - summary_view = [ + self.default_view = 'summary' + self.add_view( 'summary', [ 'id', 'model_class', 'name', @@ -266,9 +267,8 @@ 'published', 'annotation', 'tags', - ] - # in the Historys' case, each of these views includes the keys from the previous - detailed_view = summary_view + [ + ]) + self.add_view( 'detailed', [ 'contents_url', #'hdas', 'empty', @@ -281,16 +281,8 @@ 'state', 'state_details', 'state_ids', - ] - extended_view = detailed_view + [ - ] - self.serializable_keys = extended_view + [] - self.views = { - 'summary' : summary_view, - 'detailed' : detailed_view, - 'extended' : extended_view, - } - self.default_view = 'summary' + # in the Historys' case, each of these views includes the keys from the previous + ], include_keys_from='summary' ) #assumes: outgoing to json.dumps and sanitized def add_serializers( self ): @@ -300,19 +292,19 @@ self.serializers.update({ 'model_class' : lambda *a: 'History', 'id' : self.serialize_id, - 'count' : lambda trans, item, key: len( item.datasets ), 'create_time' : self.serialize_date, 'update_time' : self.serialize_date, 'size' : lambda t, i, k: int( i.get_disk_size() ), 'nice_size' : lambda t, i, k: i.get_disk_size( nice_size=True ), + 'state' : lambda t, i, k: self.history_manager.get_history_state( t, i ), 'url' : lambda t, i, k: self.url_for( 'history', id=t.security.encode_id( i.id ) ), 'contents_url' : lambda t, i, k: self.url_for( 'history_contents', history_id=t.security.encode_id( i.id ) ), + 'empty' : lambda t, i, k: len( i.datasets ) <= 0, - + 'count' : lambda trans, item, key: len( item.datasets ), 'hdas' : lambda t, i, k: [ t.security.encode_id( hda.id ) for hda in i.datasets ], - 'state' : lambda t, i, k: self.history_manager.get_history_state( t, i ), 'state_details' : lambda t, i, k: self.history_manager.get_state_counts( t, i ), 'state_ids' : lambda t, i, k: self.history_manager.get_state_ids( t, i ), 'contents' : self.serialize_contents diff -r 620437dab02aa2bf8508292bc0df4b2e1066264e -r eca1b4b64574cf09b4cbe35c4a8b103c1b455a79 lib/galaxy/managers/pages.py --- a/lib/galaxy/managers/pages.py +++ b/lib/galaxy/managers/pages.py @@ -46,17 +46,9 @@ super( PageSerializer, self ).__init__( app ) self.page_manager = PageManager( app ) - summary_view = [ - ] - # in the Pages' case, each of these views includes the keys from the previous - detailed_view = summary_view + [ - ] - self.serializable_keys = detailed_view + [] - self.views = { - 'summary': summary_view, - 'detailed': detailed_view - } self.default_view = 'summary' + self.add_view( 'summary', [] ) + self.add_view( 'detailed', [] ) def add_serializers( self ): super( PageSerializer, self ).add_serializers() @@ -79,4 +71,4 @@ super( PageDeserializer, self ).add_deserializers() self.deserializers.update({ }) - self.deserializable_keys = self.deserializers.keys() + self.deserializable_keyset.update( self.deserializers.keys() ) diff -r 620437dab02aa2bf8508292bc0df4b2e1066264e -r eca1b4b64574cf09b4cbe35c4a8b103c1b455a79 lib/galaxy/managers/sharable.py --- a/lib/galaxy/managers/sharable.py +++ b/lib/galaxy/managers/sharable.py @@ -319,7 +319,7 @@ 'user_id' : self.serialize_id, 'username_and_slug' : self.serialize_username_and_slug }) - self.serializable_keys.extend([ + self.serializable_keyset.update([ 'importable', 'published', 'slug' ]) diff -r 620437dab02aa2bf8508292bc0df4b2e1066264e -r eca1b4b64574cf09b4cbe35c4a8b103c1b455a79 lib/galaxy/managers/users.py --- a/lib/galaxy/managers/users.py +++ b/lib/galaxy/managers/users.py @@ -202,28 +202,26 @@ """ super( UserSerializer, self ).__init__() - summary_view = [ + self.default_view = 'summary' + self.add_view( 'summary', [ 'id', 'email', 'username' - ] - # in the Historys' case, each of these views includes the keys from the previous - detailed_view = summary_view + [ - 'update_time', 'create_time', - 'total_disk_usage', 'nice_total_disk_usage', - 'deleted', 'purged', + ]) + self.add_view( 'detailed', [ + 'update_time', + 'create_time', + 'total_disk_usage', + 'nice_total_disk_usage', + 'deleted', + 'purged', 'active' - ] - extended_view = detailed_view + [ - #'preferences', - #'tags', # all tags - #'annotations' # all annotations - ] - self.serializable_keys = extended_view - self.views = { - 'summary' : summary_view, - 'detailed' : detailed_view, - 'extended' : extended_view, - } - self.default_view = 'summary' + ], include_keys_from='summary' ) + #self.add_view( 'summary', [ + # 'preferences', + # # all tags + # 'tags', + # # all annotations + # 'annotations' + #], include_keys_from='detailed' ) def add_serializers( self ): self.serializers.update({ diff -r 620437dab02aa2bf8508292bc0df4b2e1066264e -r eca1b4b64574cf09b4cbe35c4a8b103c1b455a79 lib/galaxy/managers/visualizations.py --- a/lib/galaxy/managers/visualizations.py +++ b/lib/galaxy/managers/visualizations.py @@ -48,17 +48,9 @@ super( VisualizationSerializer, self ).__init__( app ) self.visualizations_manager = VisualizationManager( app ) - summary_view = [ - ] - # in the Visualizations' case, each of these views includes the keys from the previous - detailed_view = summary_view + [ - ] - self.serializable_keys = detailed_view + [] - self.views = { - 'summary' : summary_view, - 'detailed' : detailed_view - } self.default_view = 'summary' + self.add_view( 'summary', [] ) + self.add_view( 'detailed', [] ) def add_serializers( self ): super( VisualizationSerializer, self ).add_serializers() @@ -81,4 +73,4 @@ super( VisualizationDeserializer, self ).add_deserializers() self.deserializers.update({ }) - self.deserializable_keys = self.deserializers.keys() + self.deserializable_keyset.update( self.deserializers.keys() ) diff -r 620437dab02aa2bf8508292bc0df4b2e1066264e -r eca1b4b64574cf09b4cbe35c4a8b103c1b455a79 test/unit/managers/test_HistoryManager.py --- a/test/unit/managers/test_HistoryManager.py +++ b/test/unit/managers/test_HistoryManager.py @@ -339,17 +339,13 @@ detailed_view = self.history_serializer.serialize_to_view( self.trans, history1, view='detailed' ) self.assertHasKeys( detailed_view, self.history_serializer.views[ 'detailed' ] ) - self.log( 'should have a extended view' ) - extended_view = self.history_serializer.serialize_to_view( self.trans, history1, view='extended' ) - self.assertHasKeys( extended_view, self.history_serializer.views[ 'extended' ] ) - self.log( 'should have the summary view as default view' ) default_view = self.history_serializer.serialize_to_view( self.trans, history1, default_view='summary' ) self.assertHasKeys( summary_view, self.history_serializer.views[ 'summary' ] ) self.log( 'should have a serializer for all serializable keys' ) need_no_serializers = ( basestring, bool, type( None ) ) - for key in self.history_serializer.serializable_keys: + for key in self.history_serializer.serializable_keyset: instantiated_attribute = getattr( history1, key, None ) if not ( ( key in self.history_serializer.serializers ) or ( isinstance( instantiated_attribute, need_no_serializers ) ) ): @@ -372,24 +368,61 @@ keys=[ 'state_ids', 'user_id' ] ) self.assertHasKeys( serialized, [ 'state_ids', 'user_id' ] ) - def test_serializers( self ): - # size - # nice size - pass + def test_sharable( self ): + user2 = self.user_mgr.create( self.trans, **user2_data ) + history1 = self.history_mgr.create( self.trans, name='history1', user=user2 ) + + self.log( 'should have a serializer for all SharableModel keys' ) + sharable_attrs = [ 'user_id', 'username_and_slug', 'importable', 'published', 'slug' ] + serialized = self.history_serializer.serialize( self.trans, history1, sharable_attrs ) + self.assertHasKeys( serialized, sharable_attrs ) + + def test_purgable( self ): + user2 = self.user_mgr.create( self.trans, **user2_data ) + history1 = self.history_mgr.create( self.trans, name='history1', user=user2 ) + + self.log( 'deleted and purged should be returned in their default states' ) + keys = [ 'deleted', 'purged' ] + serialized = self.history_serializer.serialize( self.trans, history1, keys ) + self.assertEqual( serialized[ 'deleted' ], False ) + self.assertEqual( serialized[ 'purged' ], False ) + + self.log( 'deleted and purged should return their current state' ) + self.history_mgr.delete( self.trans, history1 ) + serialized = self.history_serializer.serialize( self.trans, history1, keys ) + self.assertEqual( serialized[ 'deleted' ], True ) + self.assertEqual( serialized[ 'purged' ], False ) + + self.history_mgr.purge( self.trans, history1 ) + serialized = self.history_serializer.serialize( self.trans, history1, keys ) + self.assertEqual( serialized[ 'deleted' ], True ) + self.assertEqual( serialized[ 'purged' ], True ) + + #pprint.pprint( self.history_serializer.serialize( self.trans, history1, [ 'contents' ] ) ) + + def test_history_serializers( self ): + user2 = self.user_mgr.create( self.trans, **user2_data ) + history1 = self.history_mgr.create( self.trans, name='history1', user=user2 ) + + serialized = self.history_serializer.serialize( self.trans, history1, [ 'size', 'nice_size' ]) + self.assertIsInstance( serialized[ 'size' ], int ) + self.assertIsInstance( serialized[ 'nice_size' ], basestring ) def test_contents( self ): user2 = self.user_mgr.create( self.trans, **user2_data ) history1 = self.history_mgr.create( self.trans, name='history1', user=user2 ) self.log( 'a history with no contents should be properly reflected in empty, etc.' ) - keys = [ 'empty', 'count', 'state_ids', 'state_details', 'state' ] + keys = [ 'empty', 'count', 'state_ids', 'state_details', 'state', 'hdas' ] serialized = self.history_serializer.serialize( self.trans, history1, keys ) self.assertEqual( serialized[ 'state' ], 'new' ) self.assertEqual( serialized[ 'empty' ], True ) self.assertEqual( serialized[ 'count' ], 0 ) self.assertEqual( sum( serialized[ 'state_details' ].values() ), 0 ) self.assertEqual( serialized[ 'state_ids' ][ 'ok' ], [] ) + self.assertIsInstance( serialized[ 'hdas' ], list ) + self.log( 'a history with contents should be properly reflected in empty, etc.' ) hda1 = self.hda_mgr.create( self.trans, history=history1, hid=1 ) self.hda_mgr.update( self.trans, hda1, dict( state='ok' ) ) @@ -399,8 +432,9 @@ self.assertEqual( serialized[ 'count' ], 1 ) self.assertEqual( serialized[ 'state_details' ][ 'ok' ], 1 ) self.assertIsInstance( serialized[ 'state_ids' ][ 'ok' ], list ) + self.assertIsInstance( serialized[ 'hdas' ], list ) + self.assertIsInstance( serialized[ 'hdas' ][0], basestring ) - #pprint.pprint( self.history_serializer.serialize( self.trans, history1, [ 'contents' ] ) ) # ============================================================================= class HistoryDeserializerTestCase( BaseTestCase ): Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.