mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Metadata is now correctly wired up to the database and Datasets. Please review this as I got stuck on a bug for a few hours and may have something blatantly stupid going on. Next step is to add the metadata to all of the datatypes and do the edit.tml
This commit is contained in:
@@ -27,8 +27,8 @@ class Data( object ):
|
||||
'test'
|
||||
>>> DataTest.get_metadata_spec()['test'].desc
|
||||
>>> DataTest.get_metadata_spec()['test'].attributes
|
||||
>>> DataTest.get_metadata_spec()['test'].wrapper
|
||||
<class 'galaxy.datatypes.metadata.MetadataWrapper'>
|
||||
>>> DataTest.get_metadata_spec()['test'].param
|
||||
<class 'galaxy.datatypes.metadata.MetadataParameter'>
|
||||
|
||||
"""
|
||||
__metaclass__ = DataMeta
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import sys
|
||||
from cookbook.patterns import Bunch
|
||||
|
||||
# Taken in part from Elixir and how they do it: http://elixir.ematia.de
|
||||
|
||||
@@ -22,16 +23,7 @@ class MetadataSpecCollection( dict ):
|
||||
def iter( self ):
|
||||
return self.itervalues()
|
||||
|
||||
class MetadataWrapper( object ):
|
||||
def __init__( self, metadata ):
|
||||
self.set_value( metadata )
|
||||
def get_value( self ):
|
||||
return self.value
|
||||
def set_value( self, value ):
|
||||
value = self.marshal(value)
|
||||
self.validate(value)
|
||||
self.value = value
|
||||
|
||||
class MetadataParameter( object ):
|
||||
def marshal( self, value ):
|
||||
'''
|
||||
This method should/can be overridden to convert the incomming
|
||||
@@ -47,36 +39,56 @@ class MetadataWrapper( object ):
|
||||
|
||||
class MetadataElementSpec( object ):
|
||||
READONLY = 1
|
||||
def __init__( self, datatype, name=None, desc=None, wrapper=MetadataWrapper, attributes=None, default=None ):
|
||||
def __init__( self, datatype, name=None, desc=None, param=MetadataParameter, attributes=None, default=None ):
|
||||
self.name = name
|
||||
self.desc = desc
|
||||
self.wrapper = wrapper
|
||||
self.param = param
|
||||
self.attributes = attributes
|
||||
self.default = default
|
||||
datatype._metadataspec.append( self )
|
||||
def hasAttribute( self, attribute ):
|
||||
return ((self.permission & attribute) == attribute)
|
||||
def wrap( self, metadata ):
|
||||
return self.wrapper(metadata)
|
||||
return self.param(metadata)
|
||||
|
||||
class MetadataCollection( dict ):
|
||||
def __init__( self, spec=None, *args ):
|
||||
dict.__init__( self )
|
||||
self.spec = spec
|
||||
def __setitem__( self, key, value ):
|
||||
if spec:
|
||||
wrapper = spec[key].wrap( value )
|
||||
dict.__setitem__( self, key, wrapper )
|
||||
else:
|
||||
dict.__setitem__( self, key, value )
|
||||
def __getitem__( self, key ):
|
||||
if spec:
|
||||
if key not in self:
|
||||
return self.spec[key].default
|
||||
class MetadataCollection:
|
||||
"""
|
||||
MetadataCollection is not a collection at all, but rather a proxy
|
||||
to the real metadata which is stored as a Bunch. This class
|
||||
handles updating the reference to the Bunch when it is changed (so
|
||||
that SQLAlchemy knows to update it) as well as returning default
|
||||
values in cases when metadata is not set.
|
||||
"""
|
||||
def __init__(self, parent, spec):
|
||||
self.parent = parent
|
||||
self.bunch = parent._metadata or Bunch()
|
||||
self.spec = spec or dict()
|
||||
def __iter__(self):
|
||||
return self.bunch.__iter__()
|
||||
def get( self, key, default=None ):
|
||||
if self.spec:
|
||||
if self.spec.get(name, None):
|
||||
default = default or self.spec[name].default
|
||||
return self.bunch.get( key, default )
|
||||
def items(self):
|
||||
return self.bunch.items()
|
||||
def __str__(self):
|
||||
return self.bunch.__str__()
|
||||
def __nonzero__(self):
|
||||
return self.bunch.__nonzero__()
|
||||
def __getattr__(self, name):
|
||||
try:
|
||||
return self.bunch.get( name )
|
||||
except AttributeError, e:
|
||||
if self.spec.get(name, None):
|
||||
return self.spec[name].default
|
||||
else:
|
||||
return dict.__getitem__(self, key).get_value()
|
||||
return None
|
||||
def __setattr__(self, name, value):
|
||||
if name in ["parent","bunch","spec"]:
|
||||
self.__dict__[name] = value
|
||||
else:
|
||||
return dict.__getitem__(self, key)
|
||||
setattr(self.__dict__["bunch"], name, value)
|
||||
self.bunch = self.parent._metadata = Bunch( **self.bunch.__dict__ )
|
||||
|
||||
MetadataElement = Statement(MetadataElementSpec)
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ from cookbook.patterns import Bunch
|
||||
from galaxy import util
|
||||
import tempfile
|
||||
import galaxy.datatypes.registry
|
||||
from galaxy.datatypes.metadata import MetadataCollection
|
||||
|
||||
datatypes_registry = galaxy.datatypes.registry.Registry() #Default Value Required for unit tests
|
||||
|
||||
@@ -152,7 +153,7 @@ class Dataset( object ):
|
||||
self.extension = extension
|
||||
self.dbkey = dbkey
|
||||
self.state = state
|
||||
self.metadata = metadata or Bunch()
|
||||
self._metadata = metadata or Bunch()
|
||||
self.parent_id = parent_id
|
||||
self.designation = designation
|
||||
self.deleted = False
|
||||
@@ -160,6 +161,9 @@ class Dataset( object ):
|
||||
# Relationships
|
||||
self.history = history
|
||||
self.validation_errors = validation_errors
|
||||
|
||||
# Deprecated: the metadatacollection now updates the object
|
||||
# reference whenever any metadata is changed
|
||||
def mark_metadata_changed( self ):
|
||||
"""
|
||||
Register changes to metadata with the history
|
||||
@@ -167,8 +171,10 @@ class Dataset( object ):
|
||||
FIXME: This is just temporary, I'd like to implement some kind of
|
||||
object proxy mapper property for SQLAlchemy that handles
|
||||
this magically.
|
||||
|
||||
Fixed. INS, 7/5/2007 Waiting to remove...
|
||||
"""
|
||||
self.metadata = Bunch( **self.metadata.__dict__ )
|
||||
self._metadata = Bunch( **self._metadata.__dict__ )
|
||||
|
||||
@property
|
||||
def ext( self ):
|
||||
@@ -180,6 +186,15 @@ class Dataset( object ):
|
||||
@property
|
||||
def datatype( self ):
|
||||
return datatypes_registry.get_datatype_by_extension( self.extension )
|
||||
|
||||
def get_metadata( self ):
|
||||
if not self._metadata: self._metadata = Bunch()
|
||||
return MetadataCollection( self, self.datatype.get_metadata_spec() )
|
||||
def set_metadata( self, bunch ):
|
||||
# Needs to accept a MetadataCollection, a bunch, or a dict
|
||||
self._metadata = Bunch( **dict( bunch.items() ) )
|
||||
metadata = property( get_metadata, set_metadata )
|
||||
|
||||
def change_datatype( self, new_ext ):
|
||||
datatypes_registry.change_datatype( self, new_ext )
|
||||
def get_size( self ):
|
||||
@@ -286,19 +301,6 @@ class Dataset( object ):
|
||||
except OSError, e:
|
||||
log.critical('%s delete error %s' % (self.__class__.__name__, e))
|
||||
|
||||
# change datatype
|
||||
def set_datatype( self, ext ):
|
||||
current = datatypes_registry.get_datatype_by_extension( self.extension )
|
||||
new = datatypes_registry.get_datatype_by_extension( ext )
|
||||
|
||||
# Copy over metadata that applies...according to spec (?)
|
||||
new_meta = new.get_metadata_spec()
|
||||
new_meta_bunch = Bunch()
|
||||
for item in new_meta:
|
||||
if item.name in self.metadata:
|
||||
new_meta_bunch[item.name] = self.metadata[item.name]
|
||||
self.metadata = new_meta_bunch
|
||||
|
||||
class ValidationError( object ):
|
||||
def __init__( self, message=None, err_type=None, attributes=None ):
|
||||
self.message = message
|
||||
|
||||
@@ -65,7 +65,7 @@ Dataset.table = Table( "dataset", metadata,
|
||||
Column( "extension", TrimmedString( 64 ) ),
|
||||
Column( "dbkey", TrimmedString( 64 ) ),
|
||||
Column( "state", TrimmedString( 64 ) ),
|
||||
Column( "metadata", PickleType() ),
|
||||
Column( "metadata", PickleType(), key="_metadata" ),
|
||||
Column( "parent_id", Integer, nullable=True ),
|
||||
Column( "designation", TrimmedString( 255 ) ),
|
||||
Column( "deleted", Boolean ),
|
||||
|
||||
@@ -31,7 +31,7 @@ class MappingTests( unittest.TestCase ):
|
||||
assert hists[1].name == ( "H" * 255 )
|
||||
assert hists[0].user == users[0]
|
||||
assert hists[1].user is None
|
||||
assert hists[1].datasets[0].metadata['chromCol'] == 1
|
||||
assert hists[1].datasets[0].metadata.chromCol == 1
|
||||
assert hists[1].datasets[0].file_name == "/tmp/dataset_%d.dat" % hists[1].datasets[0].id
|
||||
# Do an update and check
|
||||
hists[1].name = "History 2b"
|
||||
|
||||
@@ -117,7 +117,7 @@ class DefaultToolAction( object ):
|
||||
# FIXME: init_meta should take a dataset to copy from as an
|
||||
# argument
|
||||
if metadata_source:
|
||||
data.metadata = Bunch( ** inp_data[metadata_source].metadata.__dict__ )
|
||||
data.metadata = inp_data[metadata_source].metadata
|
||||
else:
|
||||
data.init_meta()
|
||||
# Take dbkey from LAST input
|
||||
|
||||
Reference in New Issue
Block a user