Exemplo n.º 1
0
    def _create(cls, lims, creation_tag=None, udfs=None, **kwargs):
        """Create an instance from attributes and return it"""
        if not udfs:
            udfs = {}
        instance = cls(lims, _create_new=True)
        if creation_tag:
            instance.root = ElementTree.Element(
                nsmap(cls._PREFIX + ':' + creation_tag))
        elif cls._TAG:
            instance.root = ElementTree.Element(
                nsmap(cls._PREFIX + ':' + cls._TAG))
        else:
            instance.root = ElementTree.Element(
                nsmap(cls._PREFIX + ':' + cls.__name__.lower()))
        for key in udfs:
            instance.udf[key] = udfs[key]
        for attribute in kwargs:
            if hasattr(instance, attribute):
                setattr(instance, attribute, kwargs.get(attribute))
            else:
                raise TypeError(
                    "%s create: got an unexpected keyword argument '%s'" %
                    (cls.__name__, attribute))

        return instance
Exemplo n.º 2
0
 def _update_elems(self):
     self._elems = []
     if self._udt:
         elem = self.rootnode.find(nsmap('udf:type'))
         if elem is not None:
             self._udt = elem.attrib['name']
             self._elems = elem.findall(nsmap('udf:field'))
     else:
         tag = nsmap('udf:field')
         for elem in self.rootnode.getchildren():
             if elem.tag == tag:
                 self._elems.append(elem)
Exemplo n.º 3
0
 def _update_elems(self):
     self._elems = []
     if self._udt:
         elem = self.rootnode.find(nsmap('udf:type'))
         if elem is not None:
             self._udt = elem.attrib['name']
             self._elems = elem.findall(nsmap('udf:field'))
     else:
         tag = nsmap('udf:field')
         for elem in self.rootnode.getchildren():
             if elem.tag == tag:
                 self._elems.append(elem)
Exemplo n.º 4
0
    def _create(cls, lims, creation_tag=None, **kwargs):
        """Create an instance from attributes and return it"""
        instance = cls(lims, _create_new=True)
        if creation_tag:
            instance.root = ElementTree.Element(nsmap(cls._PREFIX + ':' + creation_tag))
        elif cls._TAG:
            instance.root = ElementTree.Element(nsmap(cls._PREFIX + ':' + cls._TAG))
        else:
            instance.root = ElementTree.Element(nsmap(cls._PREFIX + ':' + cls.__name__.lower()))
        for attribute in kwargs:
            if hasattr(instance, attribute):
                setattr(instance, attribute, kwargs.get(attribute))
            else:
                raise TypeError("%s create: got an unexpected keyword argument '%s'" % (cls.__name__, attribute))

        return instance
Exemplo n.º 5
0
 def create(cls, lims, **kwargs):
     """Create an instance from attributes then post it to the LIMS"""
     instance = cls(lims, _create_new=True)
     if cls._TAG:
         instance.root = ElementTree.Element(nsmap(cls._PREFIX + ":" + cls._TAG))
     else:
         instance.root = ElementTree.Element(nsmap(cls._PREFIX + ":" + cls.__name__.lower()))
     for attribute in kwargs:
         if hasattr(instance, attribute):
             setattr(instance, attribute, kwargs.get(attribute))
         else:
             raise TypeError("%s create: got an unexpected keyword argument '%s'" % (cls.__name__, attribute))
     data = lims.tostring(ElementTree.ElementTree(instance.root))
     instance.root = lims.post(uri=lims.get_uri(cls._URI), data=data)
     instance._uri = instance.root.attrib["uri"]
     return instance
Exemplo n.º 6
0
 def set_udt(self, name):
     assert isinstance(name, str)
     if not self._udt:
         raise AttributeError('cannot set name for a UDF dictionary')
     self._udt = name
     elem = self.rootnode.find(nsmap('udf:type'))
     assert elem is not None
     elem.set('name', name)
Exemplo n.º 7
0
 def set_udt(self, name):
     assert isinstance(name, str)
     if not self._udt:
         raise AttributeError('cannot set name for a UDF dictionary')
     self._udt = name
     elem = self.rootnode.find(nsmap('udf:type'))
     assert elem is not None
     elem.set('name', name)
Exemplo n.º 8
0
class Sample(Entity):
    "Customer's sample to be analyzed; associated with a project."

    _URI = 'samples'
    _PREFIX = 'smp'

    name = StringDescriptor('name')
    date_received = StringDescriptor('date-received')
    date_completed = StringDescriptor('date-completed')
    project = EntityDescriptor('project', Project)
    submitter = EntityDescriptor('submitter', Researcher)
    # artifact: defined below
    udf = UdfDictionaryDescriptor()
    udt = UdtDictionaryDescriptor()
    notes = EntityListDescriptor('note', Note)
    files = EntityListDescriptor(nsmap('file:file'), File)
    externalids = ExternalidListDescriptor()
    # biosource XXX

    @classmethod
    def create(cls, lims, container, position, **kwargs):
        """Create an instance of Sample from attributes then post it to the LIMS

        Udfs can be sent in with the kwarg `udfs`. It should be a dictionary-like.
        """
        if not isinstance(container, Container):
            raise TypeError('%s is not of type Container' % container)
        udfs = kwargs.pop("udfs", None)
        instance = super(Sample, cls)._create(lims,
                                              creation_tag='samplecreation',
                                              **kwargs)

        location = ElementTree.SubElement(instance.root, 'location')
        ElementTree.SubElement(location, 'container', dict(uri=container.uri))
        position_element = ElementTree.SubElement(location, 'value')
        position_element.text = position

        # NOTE: This is a quick fix. I assume that it must be possible to initialize samples
        # with UDFs
        for key, value in udfs.items():
            attrib = {
                "name": key,
                "xmlns:udf": "http://genologics.com/ri/userdefined",
            }
            udf = ElementTree.SubElement(instance.root,
                                         'udf:field',
                                         attrib=attrib)
            udf.text = value

        data = lims.tostring(ElementTree.ElementTree(instance.root))
        instance.root = lims.post(uri=lims.get_uri(cls._URI), data=data)
        instance._uri = instance.root.attrib['uri']
        return instance
Exemplo n.º 9
0
class Project(Entity):
    "Project concerning a number of samples; associated with a researcher."

    _URI = 'projects'
    _PREFIX = 'prj'

    name = StringDescriptor('name')
    open_date = StringDescriptor('open-date')
    close_date = StringDescriptor('close-date')
    invoice_date = StringDescriptor('invoice-date')
    researcher = EntityDescriptor('researcher', Researcher)
    udf = UdfDictionaryDescriptor()
    udt = UdtDictionaryDescriptor()
    files = EntityListDescriptor(nsmap('file:file'), File)
    externalids = ExternalidListDescriptor()
Exemplo n.º 10
0
class ProcessTypeParameter(object):

    instance = None
    name = None
    root = None
    tag = 'parameter'

    string = StringDescriptor('string')
    run_program_per_event = StringDescriptor('run-program-per-event')
    channel = StringDescriptor('channel')
    invocation_type = StringDescriptor('invocation-type')
    file = EntityListDescriptor(nsmap('file:file'), File)

    def __init__(self, pt_instance, node):
        self.instance = pt_instance
        self.root = node
        self.name = self.root.attrib['name']

    def get(self):
        pass
class Sample(Entity):
    "Customer's sample to be analyzed; associated with a project."

    _URI = 'samples'
    _TAG = 'sample'
    _PREFIX = 'smp'

    name = StringDescriptor('name')
    date_received = StringDescriptor('date-received')
    date_completed = StringDescriptor('date-completed')
    project = EntityDescriptor('project', Project)
    submitter = EntityDescriptor('submitter', Researcher)
    # artifact: defined below
    udf = UdfDictionaryDescriptor()
    udt = UdtDictionaryDescriptor()
    notes = EntityListDescriptor('note', Note)
    files = EntityListDescriptor(nsmap('file:file'), File)
    externalids = ExternalidListDescriptor()
    # biosource XXX
    control_type = EntityDescriptor('control-type', Controltype)

    @classmethod
    def create(cls, lims, container, position, udfs=None, **kwargs):
        """Create an instance of Sample from attributes then post it to the LIMS"""
        if udfs is None:
            udfs = {}
        if not isinstance(container, Container):
            raise TypeError('%s is not of type Container' % container)
        instance = super(Sample, cls)._create(lims,
                                              creation_tag='samplecreation',
                                              udfs=udfs,
                                              **kwargs)

        location = ElementTree.SubElement(instance.root, 'location')
        ElementTree.SubElement(location, 'container', dict(uri=container.uri))
        position_element = ElementTree.SubElement(location, 'value')
        position_element.text = position
        data = lims.tostring(ElementTree.ElementTree(instance.root))
        instance.root = lims.post(uri=lims.get_uri(cls._URI), data=data)
        instance._uri = instance.root.attrib['uri']
        return instance
Exemplo n.º 12
0
class Artifact(Entity):
    "Any process input or output; analyte or file."

    _URI = 'artifacts'
    _TAG = 'artifact'
    _PREFIX = 'art'

    name = StringDescriptor('name')
    type = StringDescriptor('type')
    output_type = StringDescriptor('output-type')
    parent_process = EntityDescriptor('parent-process', Process)
    volume = StringDescriptor('volume')
    concentration = StringDescriptor('concentration')
    qc_flag = StringDescriptor('qc-flag')
    location = LocationDescriptor('location')
    working_flag = BooleanDescriptor('working-flag')
    samples = EntityListDescriptor('sample', Sample)
    udf = UdfDictionaryDescriptor()
    files = EntityListDescriptor(nsmap('file:file'), File)
    reagent_labels = ReagentLabelList()

    # artifact_flags XXX
    # artifact_groups XXX

    def input_artifact_list(self):
        """Returns the input artifact ids of the parrent process."""
        input_artifact_list = []
        try:
            for tuple in self.parent_process.input_output_maps:
                if tuple[1]['limsid'] == self.id:
                    input_artifact_list.append(tuple[0]['uri'])  # ['limsid'])
        except:
            pass
        return input_artifact_list

    def get_state(self):
        "Parse out the state value from the URI."
        parts = urlparse(self.uri)
        params = parse_qs(parts.query)
        try:
            return params['state'][0]
        except (KeyError, IndexError):
            return None

    @property
    def container(self):
        "The container where the artifact is located, or None"
        try:
            return self.location[0]
        except:
            return None

    def stateless(self):
        "returns the artefact independently of it's state"
        parts = urlparse(self.uri)
        if 'state' in parts[4]:
            stateless_uri = urlunparse(
                [parts[0], parts[1], parts[2], parts[3], '', ''])
            return Artifact(self.lims, uri=stateless_uri)
        else:
            return self

    # XXX set_state ?
    state = property(get_state)
    stateless = property(stateless)

    def _get_workflow_stages_and_statuses(self):
        self.get()
        result = []
        rootnode = self.root.find('workflow-stages')
        for node in rootnode.findall('workflow-stage'):
            result.append((Stage(self.lims, uri=node.attrib['uri']),
                           node.attrib['status'], node.attrib['name']))
        return result

    workflow_stages_and_statuses = property(_get_workflow_stages_and_statuses)
Exemplo n.º 13
0
class Process(Entity):
    "Process (instance of Processtype) executed producing ouputs from inputs."

    _URI = 'processes'
    _PREFIX = 'prc'

    type = EntityDescriptor('type', Processtype)
    date_run = StringDescriptor('date-run')
    technician = EntityDescriptor('technician', Researcher)
    protocol_name = StringDescriptor('protocol-name')
    input_output_maps = InputOutputMapList()
    udf = UdfDictionaryDescriptor()
    udt = UdtDictionaryDescriptor()
    files = EntityListDescriptor(nsmap('file:file'), File)
    process_parameter = StringDescriptor('process-parameter')
    instrument = EntityDescriptor('instrument', Instrument)

    # process_parameters XXX

    def outputs_per_input(self,
                          inart,
                          ResultFile=False,
                          SharedResultFile=False,
                          Analyte=False):
        """Getting all the output artifacts related to a particual input artifact"""

        inouts = [
            io for io in self.input_output_maps if io[0]['limsid'] == inart
        ]
        if ResultFile:
            inouts = [
                io for io in inouts if io[1]['output-type'] == 'ResultFile'
            ]
        elif SharedResultFile:
            inouts = [
                io for io in inouts
                if io[1]['output-type'] == 'SharedResultFile'
            ]
        elif Analyte:
            inouts = [io for io in inouts if io[1]['output-type'] == 'Analyte']
        outs = [io[1]['uri'] for io in inouts]
        return outs

    def input_per_sample(self, sample):
        """gettiung all the input artifacts dereved from the specifyed sample"""
        ins_all = self.all_inputs()
        ins = []
        for inp in ins_all:
            for samp in inp.samples:
                if samp.name == sample and inp not in ins:
                    ins.append(inp)
        return ins

    def all_inputs(self, unique=True, resolve=False):
        """Retrieving all input artifacts from input_output_maps
        if unique is true, no duplicates are returned.
        """
        # if the process has no input, that is not standard and we want to know about it
        try:
            ids = [io[0]['limsid'] for io in self.input_output_maps]
        except TypeError:
            logger.error("Process ", self, " has no input artifacts")
            raise TypeError
        if unique:
            ids = list(frozenset(ids))
        if resolve:
            return self.lims.get_batch(
                [Artifact(self.lims, id=id) for id in ids if id is not None])
        else:
            return [Artifact(self.lims, id=id) for id in ids if id is not None]

    def all_outputs(self, unique=True, resolve=False):
        """Retrieving all output artifacts from input_output_maps
        if unique is true, no duplicates are returned.
        """
        # Given how ids is structured, io[1] might be None : some process don't have an output.
        ids = [
            io[1]['limsid'] for io in self.input_output_maps
            if io[1] is not None
        ]
        if unique:
            ids = list(frozenset(ids))
        if resolve:
            return self.lims.get_batch(
                [Artifact(self.lims, id=id) for id in ids if id is not None])
        else:
            return [Artifact(self.lims, id=id) for id in ids if id is not None]

    def shared_result_files(self):
        """Retreve all resultfiles of output-generation-type PerAllInputs."""
        artifacts = self.all_outputs(unique=True)
        return [a for a in artifacts if a.output_type == 'SharedResultFile']

    def result_files(self):
        """Retreve all resultfiles of output-generation-type perInput."""
        artifacts = self.all_outputs(unique=True)
        return [a for a in artifacts if a.output_type == 'ResultFile']

    def analytes(self):
        """Retreving the output Analytes of the process, if existing. 
        If the process is not producing any output analytes, the input 
        analytes are returned. Input/Output is returned as a information string.
        Makes aggregate processes and normal processes look the same."""
        info = 'Output'
        artifacts = self.all_outputs(unique=True)
        analytes = [a for a in artifacts if a.type == 'Analyte']
        if len(analytes) == 0:
            artifacts = self.all_inputs(unique=True)
            analytes = [a for a in artifacts if a.type == 'Analyte']
            info = 'Input'
        return analytes, info

    def parent_processes(self):
        """Retrieving all parent processes through the input artifacts"""
        return [i_a.parent_process for i_a in self.all_inputs(unique=True)]

    def output_containers(self):
        """Retrieve all unique output containers"""
        cs = []
        for o_a in self.all_outputs(unique=True):
            if o_a.container:
                cs.append(o_a.container)
        return list(frozenset(cs))

    @property
    def step(self):
        """Retrive the Step coresponding to this process. They share the same id"""
        return Step(self.lims, id=self.id)
Exemplo n.º 14
0
 def __get__(self, instance, cls):
     instance.get()
     result = []
     for node in instance.root.findall(nsmap('ri:externalid')):
         result.append((node.attrib.get('id'), node.attrib.get('uri')))
     return result
Exemplo n.º 15
0
    def __setitem__(self, key, value):
        self._lookup[key] = value
        for node in self._elems:
            if node.attrib['name'] != key: continue
            vtype = node.attrib['type'].lower()

            if value is None:
                pass
            elif vtype == 'string':
                if not self._is_string(value):
                    raise TypeError('String UDF requires str or unicode value')
            elif vtype == 'str':
                if not self._is_string(value):
                    raise TypeError('String UDF requires str or unicode value')
            elif vtype == 'text':
                if not self._is_string(value):
                    raise TypeError('Text UDF requires str or unicode value')
            elif vtype == 'numeric':
                if not isinstance(value, (int, float, Decimal)):
                    raise TypeError('Numeric UDF requires int or float value')
                value = str(value)
            elif vtype == 'boolean':
                if not isinstance(value, bool):
                    raise TypeError('Boolean UDF requires bool value')
                value = value and 'true' or 'false'
            elif vtype == 'date':
                if not isinstance(value, datetime.date):  # Too restrictive?
                    raise TypeError('Date UDF requires datetime.date value')
                value = str(value)
            elif vtype == 'uri':
                if not self._is_string(value):
                    raise TypeError(
                        'URI UDF requires str or punycode (unicode) value')
                value = str(value)
            else:
                raise NotImplemented("UDF type '%s'" % vtype)
            if not isinstance(value, str):
                if not self._is_string(value):
                    value = str(value).encode('UTF-8')
            node.text = value
            break
        else:  # Create new entry; heuristics for type
            if self._is_string(value):
                vtype = '\n' in value and 'Text' or 'String'
            elif isinstance(value, bool):
                vtype = 'Boolean'
                value = value and 'true' or 'false'
            elif isinstance(value, (int, float, Decimal)):
                vtype = 'Numeric'
                value = str(value)
            elif isinstance(value, datetime.date):
                vtype = 'Date'
                value = str(value)
            else:
                raise NotImplementedError("Cannot handle value of type '%s'"
                                          " for UDF" % type(value))
            if self._udt:
                root = self.rootnode.find(nsmap('udf:type'))
            else:
                root = self.rootnode
            elem = ElementTree.SubElement(root,
                                          nsmap('udf:field'),
                                          type=vtype,
                                          name=key)
            if not isinstance(value, str):
                if not self._is_string(value):
                    value = str(value).encode('UTF-8')

            elem.text = value

            #update the internal elements and lookup with new values
            self._update_elems()
            self._prepare_lookup()
Exemplo n.º 16
0
 def __get__(self, instance, cls):
     instance.get()
     result = []
     for node in instance.root.findall(nsmap('ri:externalid')):
         result.append((node.attrib.get('id'), node.attrib.get('uri')))
     return result
Exemplo n.º 17
0
    def __setitem__(self, key, value):
        self._lookup[key] = value
        for node in self._elems:
            if node.attrib['name'] != key: continue
            vtype = node.attrib['type'].lower()

            if value is None:
                pass
            elif vtype == 'string':
                if not self._is_string(value):
                    raise TypeError('String UDF requires str or unicode value')
            elif vtype == 'str':
                if not self._is_string(value):
                    raise TypeError('String UDF requires str or unicode value')
            elif vtype == 'text':
                if not self._is_string(value):
                    raise TypeError('Text UDF requires str or unicode value')
            elif vtype == 'numeric':
                if not isinstance(value, (int, float, Decimal)):
                    raise TypeError('Numeric UDF requires int or float value')
                value = str(value)
            elif vtype == 'boolean':
                if not isinstance(value, bool):
                    raise TypeError('Boolean UDF requires bool value')
                value = value and 'true' or 'false'
            elif vtype == 'date':
                if not isinstance(value, datetime.date):  # Too restrictive?
                    raise TypeError('Date UDF requires datetime.date value')
                value = str(value)
            elif vtype == 'uri':
                if not self._is_string(value):
                    raise TypeError('URI UDF requires str or punycode (unicode) value')
                value = str(value)
            else:
                raise NotImplemented("UDF type '%s'" % vtype)
            if not isinstance(value, str):
                if not self._is_string(value):
                    value = str(value).encode('UTF-8')
            node.text = value
            break
        else:  # Create new entry; heuristics for type
            if self._is_string(value):
                vtype = '\n' in value and 'Text' or 'String'
            elif isinstance(value, bool):
                vtype = 'Boolean'
                value = value and 'true' or 'false'
            elif isinstance(value, (int, float, Decimal)):
                vtype = 'Numeric'
                value = str(value)
            elif isinstance(value, datetime.date):
                vtype = 'Date'
                value = str(value)
            else:
                raise NotImplementedError("Cannot handle value of type '%s'"
                                          " for UDF" % type(value))
            if self._udt:
                root = self.rootnode.find(nsmap('udf:type'))
            else:
                root = self.rootnode
            elem = ElementTree.SubElement(root,
                                          nsmap('udf:field'),
                                          type=vtype,
                                          name=key)
            if not isinstance(value, str):
                if not self._is_string(value):
                    value = str(value).encode('UTF-8')

            elem.text = value

            #update the internal elements and lookup with new values
            self._update_elems()
            self._prepare_lookup()