Newer
Older
files = self.file_list()
elif isinstance(files, str):
files = [files]
base_url = self.data['dataStore']['downloadUrl'] + '/datastore_server/' + self.permid + '/'
Swen Vermeul
committed
queue = DataSetDownloadQueue(workers=workers)
# get file list and start download
for filename in files:
file_info = self.get_file_list(start_folder=filename)
file_size = file_info[0]['fileSize']
download_url = base_url + filename + '?sessionID=' + self.openbis.token
filename = os.path.join(self.openbis.hostname, self.permid, filename)
queue.put([download_url, filename, file_size, self.openbis.verify_certificates])
Swen Vermeul
committed
# wait until all files have downloaded
if wait_until_finished:
queue.join()
print("Files downloaded to: %s" % os.path.join(self.openbis.hostname, self.permid))
def get_parents(self):
return self.openbis.get_datasets(withChildren=self.permid)
def get_children(self):
return self.openbis.get_datasets(withParents=self.permid)
def file_list(self):
files = []
for file in self.get_file_list(recursive=True):
if file['isDirectory']:
pass
else:
files.append(file['pathInDataSet'])
return files
def get_files(self, start_folder='/'):
""" Returns a DataFrame of all files in this dataset
"""
def createRelativePath(pathInDataSet):
if self.shareId is None:
return ''
else:
return os.path.join(self.shareId, self.location, pathInDataSet)
files = self.get_file_list(start_folder=start_folder)
df = DataFrame(files)
df['relativePath'] = df['pathInDataSet'].map(createRelativePath)
df['crc32Checksum'] = df['crc32Checksum'].fillna(0.0).astype(int).map(signed_to_unsigned)
return df[['isDirectory', 'pathInDataSet', 'fileSize', 'crc32Checksum']]
def get_file_list(self, recursive=True, start_folder="/"):
""" Lists all files of a given dataset. You can specifiy a start_folder other than "/".
By default, all directories and their containing files are listed recursively. You can
turn off this option by setting recursive=False.
"""
request = {
"method" : "listFilesForDataSet",
"params" : [
self.openbis.token,
self.permid,
"id":"1"
self.data["dataStore"]["downloadUrl"] + '/datastore_server/rmi-dss-api-v1.json',
json.dumps(request),
verify=self.openbis.verify_certificates
)
data = resp.json()
if 'error' in data:
Swen Vermeul
committed
raise ValueError('Error from openBIS: ' + data['error'] )
elif 'result' in data:
return data['result']
Swen Vermeul
committed
raise ValueError('request to openBIS did not return either result nor error')
Swen Vermeul
committed
raise ValueError('internal error while performing post request')
class Vocabulary():
def __init__(self, data):
self.data = data
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
@property
def terms_kv(self):
return [
{voc["code"]:voc["label"] }
for voc
in sorted(self.data['objects'], key=lambda v: v["ordinal"])
]
@property
def terms(self):
return [
voc["code"]
for voc
in sorted(self.data['objects'], key=lambda v: v["ordinal"])
]
def _repr_html_(self):
html = """
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th>vocabulary term</th>
<th>label</th>
<th>description</th>
<th>vocabulary</th>
</tr>
</thead>
<tbody>
"""
for voc in sorted(
self.data['objects'],
key=lambda v: (v["permId"]["vocabularyCode"], v["ordinal"])
):
html += "<tr> <td>{}</td> <td>{}</td> <td>{}</td> <td>{}</td> </tr>".format(
voc['code'],
voc['label'],
voc['description'],
voc['permId']['vocabularyCode']
)
html += """
</tbody>
</table>
"""
return html
class PropertyHolder():
def __init__(self, openbis_obj, type):
self.__dict__['_openbis'] = openbis_obj
self.__dict__['_type'] = type
self.__dict__['_property_names'] = []
for prop in type.data['propertyAssignments']:
self._property_names.append(prop['propertyType']['code'].lower())
def _get_terms(self, vocabulary):
return self._openbis.get_terms(vocabulary)
def _all_props(self):
props = {}
for code in self._type.codes():
props[code] = getattr(self, code)
return props
def __getattr__(self, name):
if name.endswith('_'):
name = name.rstrip('_')
property_type = self._type.prop[name]['propertyType']
if property_type['dataType'] == 'CONTROLLEDVOCABULARY':
return self._openbis.get_terms(name)
else:
return { property_type["label"] : property_type["dataType"]}
else: return None
def __setattr__(self, name, value):
if name not in self._property_names:
raise KeyError("No such property: {}".format(name))
property_type = self._type.prop[name]['propertyType']
data_type = property_type['dataType']
if data_type == 'CONTROLLEDVOCABULARY':
voc = self._openbis.get_terms(name)
if value not in voc.terms:
raise ValueError("Value must be one of these terms: " + ", ".join(voc.terms))
elif data_type in ('INTEGER', 'BOOLEAN', 'VARCHAR'):
if not check_datatype(data_type, value):
raise ValueError("Value must be of type {}".format(data_type))
self.__dict__[name] = value
def __dir__(self):
return self._property_names
def _repr_html_(self):
Swen Vermeul
committed
def nvl(val, string=''):
if val is None:
return string
elif val == 'true':
return True
elif val == 'false':
return False
return val
html = """
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th>property</th>
<th>value</th>
</tr>
</thead>
<tbody>
"""
for prop in self._property_names:
Swen Vermeul
committed
#value = ''
#try:
# value = getattr(self, prop)
#except Exception:
# pass
html += "<tr> <td>{}</td> <td>{}</td> </tr>".format(
Swen Vermeul
committed
prop, nvl(getattr(self, prop, ''),'')
)
html += """
</tbody>
</table>
"""
return html
class AttrHolder():
""" General class for both samples and experiments that hold all common attributes, such as:
- space
Swen Vermeul
committed
- experiment (sample)
- samples (experiment)
- parents (sample, dataset)
- children (sample, dataset)
- tags
"""
def __init__(self, openbis_obj, entity, type=None):
self.__dict__['_openbis'] = openbis_obj
self.__dict__['_entity'] = entity
if type is not None:
self.__dict__['_type_obj'] = type
self.__dict__['_allowed_attrs'] = _definitions(entity)['attrs']
self.__dict__['_identifier'] = None
self.__dict__['_is_new'] = True
Swen Vermeul
committed
def __call__(self, data):
self.__dict__['_is_new'] = False
Swen Vermeul
committed
for attr in self._allowed_attrs:
if attr in ["code","permId","identifier","type",
"container","components","attachments"]:
self.__dict__['_'+attr] = data.get(attr, None)
Swen Vermeul
committed
d = data.get(attr, None)
if d is not None:
d = d['permId']
self.__dict__['_'+attr] = d
elif attr in ["experiment", "project"]:
Swen Vermeul
committed
d = data.get(attr, None)
if d is not None:
d = d['identifier']
self.__dict__['_'+attr] = d
elif attr in ["parents","children","samples"]:
Swen Vermeul
committed
self.__dict__['_'+attr] = []
for item in data[attr]:
self.__dict__['_'+attr].append(item['identifier'])
Swen Vermeul
committed
self.__dict__['_'+attr] = []
for item in data[attr]:
self.__dict__['_'+attr].append({
"code": item['code'],
"@type": "as.dto.tag.id.TagCode"
})
elif attr in ["attachments"]:
pass
else:
self.__dict__['_'+attr] = data.get(attr, None)
def _all_attrs(self):
attr2ids = _definitions('attr2ids')
ids2type = _definitions('ids2type')
request = {}
# look at all attributes available for that entity
Swen Vermeul
committed
for attr in self._allowed_attrs:
# these attributes cannot be changed (or not directly)
if attr in ["code", "permId", "identifier", "type", "attachments"]:
continue
if '_'+attr in self.__dict__:
if self._is_new:
# handle multivalue attributes (parents, children, tags etc.)
if attr in defs['multi']:
items = self.__dict__.get('_'+attr, [])
if items == None:
items = []
Swen Vermeul
committed
request[attr2ids[attr]] = items
Swen Vermeul
committed
request[attr2ids[attr]] = self.__dict__.get('_'+attr, None)
else:
# handle multivalue attributes (parents, children, tags etc.)
# we only cover the Set mechanism, which means we always update all items in a
# list
if attr in defs['multi']:
items = self.__dict__.get('_'+attr, [])
if items == None:
items = []
Swen Vermeul
committed
request[attr2ids[attr]] = {
"actions": [
{
"items": items,
"@type": "as.dto.common.update.ListUpdateActionSet",
}
],
"@type": "as.dto.common.update.IdListUpdateValue"
}
else:
# handle single attribut4es (space, experiment, project, container, etc.)
value = self.__dict__.get('_'+attr, {})
if value is None:
pass
else:
isModified=False
if 'isModified' in value:
isModified=True
del value['isModified']
Swen Vermeul
committed
request[attr2ids[attr]] = {
"@type": "as.dto.common.update.FieldUpdateValue",
"isModified": isModified,
"value": value,
}
if self.__dict__.get('_code', None) is None:
request['autoGeneratedCode'] = True
else:
pass
return request
def __getattr__(self, name):
""" handles all attribute requests dynamically. Values are returned in a sensible way,
for example the identifiers of parents, children and components are returned
as an array of values.
"""
int_name = '_'+name
if int_name in self.__dict__:
Swen Vermeul
committed
if int_name == '_attachments':
return Attachments(self._attachments)
elif int_name in ["_experiment"]:
exp = ''
try:
Swen Vermeul
committed
exp = self.__dict__[int_name]['identifier']
pass
return exp
elif isinstance(self.__dict__[int_name], list):
values = []
for item in self.__dict__[int_name]:
values.append(
item.get("code",
item.get("identifier",
item.get("permId", None)))
)
return values
elif isinstance(self.__dict__[int_name], dict):
return self.__dict__[int_name].get(name,
self.__dict__[int_name].get("code",
self.__dict__[int_name].get("identifier",
self.__dict__[int_name].get("permId", None))))
else:
return self.__dict__[int_name]
else:
return None
def __setattr__(self, name, value):
if name in ["parents", "children", "components"]:
if not isinstance(value, list):
value = [value]
objs = []
for val in value:
# fetch objects in openBIS, make sure they actually exists
obj = getattr(self._openbis, 'get_'+self._entity.lower())(val)
objs.append(obj)
self.__dict__['_'+name] = {
"@type": "as.dto.common.update.IdListUpdateValue",
"actions": [{
"@type": "as.dto.common.update.ListUpdateActionSet",
"items": [item._permId for item in objs]
}]
}
elif name in ["tags"]:
tags = []
for val in value:
tags.append({
"@type": "as.dto.tag.id.TagCode",
"code": val
})
self.__dict__['_tags'] = tags
elif name in ["experiment"]:
# fetch object in openBIS, make sure it actually exists
obj = getattr(self._openbis, "get_"+name)(value)
self.__dict__['_'+name] = obj.data['identifier']
# mark attribute as modified, if it's an existing entity
if self.__dict__['_is_new']:
pass
else:
self.__dict__['_'+name]['isModified'] = True
elif name in ["space"]:
# fetch object in openBIS, make sure it actually exists
obj = getattr(self._openbis, "get_"+name)(value)
self.__dict__['_'+name] = obj['permId']
# mark attribute as modified, if it's an existing entity
if self.__dict__['_is_new']:
pass
else:
elif name in ["project"]:
# fetch object in openBIS, make sure it actually exists
obj = getattr(self._openbis, "get_"+name)(value)
self.__dict__['_'+name] = obj['identifier']
# mark attribute as modified, if it's an existing entity
if self.__dict__['_is_new']:
pass
else:
self.__dict__['_'+name]['isModified'] = True
elif name in ["identifier", "project"]:
raise KeyError("you can not modify the {}".format(name))
elif name == "code":
if self.__dict__['_type_obj'].data['autoGeneratedCode']:
raise KeyError("for this {}Type you can not set a code".format(self.__dict__['_entity']))
else:
self.__dict__['_code'] = value
else:
raise KeyError("no such attribute: {}".format(name))
def get_type(self):
return self._type_obj
def get_parents(self):
Swen Vermeul
committed
# e.g. self._openbis.get_samples(withChildren=self.identifier)
return getattr(self._openbis, 'get_'+self._entity.lower()+'s')(withChildren=self.identifier)
def get_children(self):
Swen Vermeul
committed
# e.g. self._openbis.get_samples(withParents=self.identifier)
return getattr(self._openbis, 'get_'+self._entity.lower()+'s')(withParents=self.identifier)
@property
def set_tags(self, tags):
tagIds = _tagIds_for_tags(tags, 'Set')
self.openbis.update_sample(self.permId, tagIds=tagIds)
def add_tags(self, tags):
tagIds = _tagIds_for_tags(tags, 'Add')
self.openbis.update_sample(self.permId, tagIds=tagIds)
def del_tags(self, tags):
tagIds = _tagIds_for_tags(tags, 'Remove')
self.openbis.update_sample(self.permId, tagIds=tagIds)
def _repr_html_(self):
Swen Vermeul
committed
def nvl(val, string=''):
if val is None:
return string
return val
html = """
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th>attribute</th>
<th>value</th>
</tr>
</thead>
<tbody>
"""
Swen Vermeul
committed
for attr in self._allowed_attrs:
if attr == 'attachments':
continue
html += "<tr> <td>{}</td> <td>{}</td> </tr>".format(
attr, nvl(getattr(self, attr, ''),'')
)
if 'attachments' in self._allowed_attrs and self._attachments is not None:
Swen Vermeul
committed
html += "<tr><td>attachments</td><td>"
html += "<br/>".join(att['fileName'] for att in self._attachments)
html += "</td></tr>"
html += """
</tbody>
</table>
"""
return html
class Sample():
""" A Sample is one of the most commonly used objects in openBIS.
"""
def __init__(self, openbis_obj, type, data=None, **kwargs):
self.__dict__['openbis'] = openbis_obj
self.__dict__['type'] = type
self.__dict__['p'] = PropertyHolder(openbis_obj, type)
self.__dict__['a'] = AttrHolder(openbis_obj, 'Sample', type)
if data is not None:
self._set_data(data)
if kwargs is not None:
for key in kwargs:
setattr(self, key, kwargs[key])
def _set_data(self, data):
# assign the attribute data to self.a by calling it
# (invoking the AttrHolder.__call__ function)
self.a(data)
self.__dict__['data'] = data
# put the properties in the self.p namespace (without checking them)
for key, value in data['properties'].items():
self.p.__dict__[key.lower()] = value
Swen Vermeul
committed
def __dir__(self):
Swen Vermeul
committed
return ['props', 'get_parents()', 'get_children()', 'get_datasets()', 'get_experiment()', 'space', 'project', 'experiment', 'project','tags', 'attachments', 'data']
@property
def props(self):
return self.__dict__['p']
Swen Vermeul
committed
@property
def type(self):
return self.__dict__['type'].data['code']
@type.setter
def type(self, type_name):
sample_type = self.openbis.get_sample_type(type_name)
self.p.__dict__['_type'] = sample_type
self.a.__dict__['_type'] = sample_type
def __getattr__(self, name):
return getattr(self.__dict__['a'], name)
def __setattr__(self, name, value):
if name in ['set_properties', 'set_tags', 'add_tags']:
raise ValueError("These are methods which should not be overwritten")
setattr(self.__dict__['a'], name, value)
def _repr_html_(self):
html = self.a._repr_html_()
return html
def set_properties(self, properties):
self.openbis.update_sample(self.permId, properties=properties)
def save(self):
props = self.p._all_props()
attrs = self.a._all_attrs()
attrs["properties"] = props
if self.identifier is None:
# create a new sample
attrs["@type"] = "as.dto.sample.create.SampleCreation"
attrs["typeId"] = self.__dict__['type'].data['permId']
request = {
"method": "createSamples",
"params": [ self.openbis.token,
[ attrs ]
]
}
resp = self.openbis._post_request(self.openbis.as_v3, request)
new_sample_data = self.openbis.get_sample(resp[0]['permId'], only_data=True)
self._set_data(new_sample_data)
return self
else:
attrs["@type"] = "as.dto.sample.update.SampleUpdate"
attrs["sampleId"] = {
"permId": self.permId,
"@type": "as.dto.sample.id.SamplePermId"
}
request = {
"method": "updateSamples",
"params": [ self.openbis.token,
[ attrs ]
]
}
resp = self.openbis._post_request(self.openbis.as_v3, request)
print('Sample successfully updated')
self.openbis.delete_entity('sample', self.permId, reason)
def get_datasets(self):
return self.openbis.get_datasets(sample=self.permId)
def get_projects(self):
return self.openbis.get_project(withSamples=[self.permId])
Swen Vermeul
committed
def get_experiment(self):
try:
return self.openbis.get_experiment(self._experiment['identifier'])
except Exception:
pass
Swen Vermeul
committed
class Space(dict):
""" managing openBIS spaces
"""
def __init__(self, openbis_obj, *args, **kwargs):
super(Space, self).__init__(*args, **kwargs)
self.__dict__ = self
self.openbis = openbis_obj
""" Lists all samples in a given space. A pandas DataFrame object is returned.
"""
return self.openbis.get_samples(space=self.code, *args, **kwargs)
@property
def projects(self):
return self.openbis.get_projects(space=self.code)
def new_project(self, **kwargs):
return self.openbis.new_project(space=self.code, **kwargs)
@property
def experiments(self):
return self.openbis.get_experiments(space=self.code)
class Things():
"""An object that contains a DataFrame object about an entity available in openBIS.
"""
def __init__(self, openbis_obj, entity, df, identifier_name='code'):
self.df = df
self.identifier_name = identifier_name
def _repr_html_(self):
return self.df._repr_html_()
def __getitem__(self, key):
if self.df is not None and len(self.df) > 0:
row = None
if isinstance(key, int):
# get thing by rowid
row = self.df.loc[[key]]
elif isinstance(key, list):
# treat it as a normal dataframe
return self.df[key]
else:
# get thing by code
row = self.df[self.df[self.identifier_name]==key.upper()]
if row is not None:
# invoke the openbis.get_entity() method
return getattr(self.openbis, 'get_'+self.entity)(row[self.identifier_name].values[0])
class Experiment():
Swen Vermeul
committed
"""
Swen Vermeul
committed
def __init__(self, openbis_obj, type, data=None, **kwargs):
self.__dict__['openbis'] = openbis_obj
self.__dict__['type'] = type
self.__dict__['p'] = PropertyHolder(openbis_obj, type)
self.__dict__['a'] = AttrHolder(openbis_obj, 'Experiment', type)
Swen Vermeul
committed
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
if data is not None:
self._set_data(data)
if kwargs is not None:
for key in kwargs:
setattr(self, key, kwargs[key])
def _set_data(self, data):
# assign the attribute data to self.a by calling it
# (invoking the AttrHolder.__call__ function)
self.a(data)
self.__dict__['data'] = data
# put the properties in the self.p namespace (without checking them)
for key, value in data['properties'].items():
self.p.__dict__[key.lower()] = value
def __dir__(self):
# the list of possible methods/attributes displayed
# when invoking TAB-completition
return [
Swen Vermeul
committed
'project','tags', 'attachments', 'data',
Swen Vermeul
committed
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
]
@property
def props(self):
return self.__dict__['p']
@property
def type(self):
return self.__dict__['type'].data['code']
@type.setter
def type(self, type_name):
experiment_type = self.openbis.get_experiment_type(type_name)
self.p.__dict__['_type'] = experiment_type
self.a.__dict__['_type'] = experiment_type
def __getattr__(self, name):
return getattr(self.__dict__['a'], name)
def __setattr__(self, name, value):
if name in ['set_properties', 'set_tags', 'add_tags']:
raise ValueError("These are methods which should not be overwritten")
setattr(self.__dict__['a'], name, value)
def _repr_html_(self):
html = self.a._repr_html_()
return html
def set_properties(self, properties):
self.openbis.update_experiment(self.permId, properties=properties)
Swen Vermeul
committed
def save(self):
props = self.p._all_props()
attrs = self.a._all_attrs()
attrs["properties"] = props
Swen Vermeul
committed
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
if self.identifier is None:
# create a new experiment
attrs["@type"] = "as.dto.experiment.create.ExperimentCreation"
attrs["typeId"] = self.__dict__['type'].data['permId']
request = {
"method": "createExperiments",
"params": [ self.openbis.token,
[ attrs ]
]
}
resp = self.openbis._post_request(self.openbis.as_v3, request)
new_experiment_data = self.openbis.get_experiment(resp[0]['permId'], only_data=True)
self._set_data(new_experiment_data)
return self
else:
attrs["@type"] = "as.dto.experiment.update.ExperimentUpdate"
attrs["experimentId"] = {
"permId": self.permId,
"@type": "as.dto.experiment.id.ExperimentPermId"
}
request = {
"method": "updateExperiments",
"params": [ self.openbis.token,
[ attrs ]
]
}
resp = self.openbis._post_request(self.openbis.as_v3, request)
print('Experiment successfully updated')
def delete(self, reason):
self.openbis.delete_entity('experiment', self.permId, reason)
Swen Vermeul
committed
def get_datasets(self):
return self.openbis.get_datasets(experiment=self.permId)
Swen Vermeul
committed
def get_projects(self):
return self.openbis.get_project(experiment=self.permId)
Swen Vermeul
committed
def get_samples(self):
return self.openbis.get_samples(experiment=self.permId)
Swen Vermeul
committed
def get_attachments(self):
pass
class PropertyAssignments():
""" holds are properties, that are assigned to an entity, eg. sample or experiment
"""
def __init__(self, openbis_obj, data):
self.openbis = openbis_obj
self.data = data
self.prop = {}
if self.data['propertyAssignments'] is None:
self.data['propertyAssignments'] = []
for pa in self.data['propertyAssignments']:
self.prop[pa['propertyType']['code'].lower()] = pa
def codes(self):
codes = []
for pa in self.data['propertyAssignments']:
codes.append(pa['propertyType']['code'].lower())
return codes
def _repr_html_(self):
html = """
<p>{}: <b>{}</b>
<p>description: {}</p>
Swen Vermeul
committed
""".format(
self.data['@type'].split('.')[-1],
self.data['code'],
self.data['description']
)
if 'autoGeneratedCode' in self.data:
html += "<p>Code autogenerated: {}</p>".format(
self.data['autoGeneratedCode'])
html += """
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th>property</th>
<th>label</th>
<th>description</th>
<th>mandatory</th>
</tr>
</thead>
<tbody>
Swen Vermeul
committed
"""
for pa in self.data['propertyAssignments']:
html += "<tr> <th>{}</th> <td>{}</td> <td>{}</td> <td>{}</td> <td>{}</td> </tr>".format(
pa['propertyType']['code'].lower(),
pa['propertyType']['label'],
pa['propertyType']['description'],
pa['propertyType']['dataType'],
pa['mandatory']
)
html += """
</tbody>
</table>
"""
return html
Swen Vermeul
committed
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
class Attachments:
def __init__(self, attachments):
self.atts = attachments
atts = []
for att in attachments:
atts.append({
"fileName": att["fileName"],
"title": att["title"],
"description": att["description"],
"registrationDate": format_timestamp(att["registrationDate"]),
"version": att["version"],
})
self.df = DataFrame(atts)[['fileName','title','description','registrationDate','version']]
def _repr_html_(self):
return self.df._repr_html_()
def download(self):
pass
def __getitem__(self, key):
if self.df is not None and len(self.df) > 0:
row = None
if isinstance(key, int):
row = self.df.loc[[key]]
if row is not None:
self._download()
class Project:
def __init__(self, openbis_obj, data=None, **kwargs):
self.__dict__['openbis'] = openbis_obj
self.__dict__['type'] = type
self.__dict__['a'] = AttrHolder(openbis_obj, 'Project')
if data is not None:
self.a(data)
self.__dict__['data'] = data
if kwargs is not None:
for key in kwargs:
setattr(self, key, kwargs[key])
def _repr_html_(self):
html = self.a._repr_html_()
return html