diff --git a/intent_parser/accessor/aquarium_opil_accessor.py b/intent_parser/accessor/aquarium_opil_accessor.py new file mode 100644 index 00000000..44ac0034 --- /dev/null +++ b/intent_parser/accessor/aquarium_opil_accessor.py @@ -0,0 +1,38 @@ +import intent_parser.utils.intent_parser_utils as ip_utils +import intent_parser.protocols.opil_parameter_utils as opil_utils +import logging + +from intent_parser.intent_parser_exceptions import IntentParserException + + +class AquariumOpilAccessor(object): + """ + Retrieve experimental request from Aquarium-opil. + Refer to link for getting aquarium-opil file: + https://github.com/aquariumbio/aquarium-opil + """ + + logger = logging.getLogger('aqurium_opil_accessor') + _SUPPORTED_PROTOCOLS = {'jellyfish': 'jellyfish_htc.xml' + } + + def __init__(self): + pass + + def get_experimental_request_as_opil_doc(self, experimental_request_name): + if experimental_request_name in self._SUPPORTED_PROTOCOLS: + opil_doc = ip_utils.load_sbol_xml_file(self._SUPPORTED_PROTOCOLS[experimental_request_name]) + return opil_doc + + raise IntentParserException('Aquarium does not support %s as an experimental request' % experimental_request_name) + + def get_protocol_interface(self, protocol_name): + opil_doc = self.get_experimental_request_as_opil_doc(protocol_name) + protocol_interfaces = opil_utils.get_protocol_interfaces_from_sbol_doc(opil_doc) + if len(protocol_interfaces) == 0: + raise IntentParserException('No opil protocol interface found from aquarium protocol %s' % protocol_name) + + if len(protocol_interfaces) > 1: + raise IntentParserException('Expected to find one opil protocol interface for %s but more than one was found' % protocol_name) + + return protocol_interfaces[0] \ No newline at end of file diff --git a/intent_parser/accessor/strateos_accessor.py b/intent_parser/accessor/strateos_accessor.py index 6cf3b89f..de28f335 100644 --- a/intent_parser/accessor/strateos_accessor.py +++ b/intent_parser/accessor/strateos_accessor.py @@ -2,11 +2,12 @@ from intent_parser.intent_parser_exceptions import IntentParserException from transcriptic import Connection import intent_parser.constants.intent_parser_constants as ip_constants +import intent_parser.protocols.opil_parameter_utils as opil_utils import logging import opil import time import threading - +import sbol3 class StrateosAccessor(object): """ @@ -123,19 +124,18 @@ def _fetch_protocols(self): def convert_protocol_to_opil(self, protocol): strateos_namespace = 'http://strateos.com/' + protocol_name = protocol['name'] sg = opil.StrateosOpilGenerator() sbol_doc = sg.parse_strateos_json(strateos_namespace, - protocol['name'], + protocol_name, protocol['id'], protocol['inputs']) - protocol_interface = None - for obj in sbol_doc.objects: - if type(obj) is opil.opil_factory.ProtocolInterface: - protocol_interface = obj - - if not protocol_interface: + protocol_interfaces = opil_utils.get_protocol_interfaces_from_sbol_doc(sbol_doc) + if len(protocol_interfaces) == 0: + raise IntentParserException('Unable to locate OPIL protocol interface when converting transcriptic protocol for %s ' % protocol_name) + if len(protocol_interfaces) > 1: raise IntentParserException( - 'Unable to locate OPIL protocol interface when converting transcriptic protocols to OPIL') + 'Expected to find one opil protocol interface for %s but more than one was found' % protocol_name) - return protocol_interface, sbol_doc + return protocol_interfaces[0], sbol_doc diff --git a/intent_parser/constants/intent_parser_constants.py b/intent_parser/constants/intent_parser_constants.py index dd6e155a..c07e733c 100644 --- a/intent_parser/constants/intent_parser_constants.py +++ b/intent_parser/constants/intent_parser_constants.py @@ -145,11 +145,25 @@ UO_MILLI_MOLAR = 'https://identifiers.org/UO:0000063' UO_GRAM_PER_LITER = 'https://identifiers.org/UO:0000175' UO_NANO_GRAM_PER_LITER = 'https://identifiers.org/UO:0010050' + # measurement-typeis specific to SD2 project SD2_AUTOMATED_TEST_URI = 'http://sd2e.org#automatedTest' SD2_CONDITION_SPACE_URI = 'http://sd2e.org#conditionSpace' SD2_EXPERIMENTAL_DESIGN_URI = 'http://sd2e.org#experimentalDesign' +MEASUREMENT_TYPE_MAPPINGS = { + MEASUREMENT_TYPE_FLOW: NCIT_FLOW_URI, + MEASUREMENT_TYPE_RNA_SEQ: NCIT_RNA_SEQ_URI, + MEASUREMENT_TYPE_DNA_SEQ: NCIT_DNA_SEQ_URI, + MEASUREMENT_TYPE_PROTEOMICS: NCIT_PROTEOMICS_URI, + MEASUREMENT_TYPE_SEQUENCING_CHROMATOGRAM: NCIT_SEQUENCING_CHROMATOGRAM_URI, + MEASUREMENT_TYPE_AUTOMATED_TEST: SD2_AUTOMATED_TEST_URI, + MEASUREMENT_TYPE_CFU: NCIT_CFU_URI, + MEASUREMENT_TYPE_PLATE_READER: NCIT_PLATE_READER_URI, + MEASUREMENT_TYPE_CONDITION_SPACE: SD2_CONDITION_SPACE_URI, + MEASUREMENT_TYPE_EXPERIMENTAL_DESIGN: SD2_EXPERIMENTAL_DESIGN_URI +} + # Strateos Protocols Supported in IP GROWTH_CURVE_PROTOCOL = 'GrowthCurve' OBSTACLE_COURSE_PROTOCOL = 'ObstacleCourse' diff --git a/intent_parser/document/analyze_document_controller.py b/intent_parser/document/analyze_document_controller.py index e99260fb..e521f7df 100644 --- a/intent_parser/document/analyze_document_controller.py +++ b/intent_parser/document/analyze_document_controller.py @@ -48,6 +48,13 @@ def _write_ignored_terms(self): self.LOGGER.info('Writing ignored terms to file.') ip_utils.write_json_to_file(self._ignore_terms, self.ANALYZE_IGNORE_TERMS_FILE) + def get_all_analyzed_results(self, document_id): + if document_id not in self.analyzed_documents: + return None + + analyze_document = self.analyzed_documents[document_id] + return analyze_document.get_result() + def get_first_analyze_result(self, document_id): if document_id not in self.analyzed_documents: return None @@ -76,6 +83,11 @@ def remove_analyze_result_with_term(self, document_id, matching_term): analyze_document = self.analyzed_documents[document_id] return analyze_document.remove_all(matching_term) + def remove_document(self, document_id): + if document_id not in self.analyzed_documents: + return + self.analyzed_documents.pop(document_id) + def remove_analyze_result(self, document_id, paragraph_index, matching_term, sbh_uri, start_offset, end_offset): if document_id not in self.analyzed_documents: return diff --git a/intent_parser/intent/control_intent.py b/intent_parser/intent/control_intent.py index 0b68d5d0..48f3a0e7 100644 --- a/intent_parser/intent/control_intent.py +++ b/intent_parser/intent/control_intent.py @@ -5,7 +5,7 @@ import intent_parser.constants.sd2_datacatalog_constants as dc_constants import intent_parser.constants.intent_parser_constants as ip_constants import sbol3.constants as sbol_constants -import opil + """ Intent Parser's representation for a control. """ @@ -106,7 +106,8 @@ def _encode_content_using_sbol(self, sbol_document): content_template = LocalSubComponent(identity=self._id_provider.get_unique_sd2_id(), types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) content_template.name = 'content template' - content_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + content_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) content_variants = [] content_variant_measures = [] @@ -114,15 +115,20 @@ def _encode_content_using_sbol(self, sbol_document): if isinstance(content, ReagentIntent): content_component = content.to_sbol(sbol_document) content_variants.append(content_component) + content_variant_measure = content.to_opil() + content_variant_measures.append(content_variant_measure) + if content.get_timepoint() is not None: - content_variant_measure = content.get_timepoint().to_sbol() - content_variant_measures.append(content_variant_measure) + content_timepoint_measure = content.get_timepoint().to_opil() + content_variant_measures.append(content_timepoint_measure) + elif isinstance(content, NamedStringValue): content_component = Component(identity=self._id_provider.get_unique_sd2_id(), component_type=sbol_constants.SBO_FUNCTIONAL_ENTITY) content_component.name = content.get_named_link().get_name() - content_sub_component = SubComponent(content.get_named_link().get_link()) - content_component.features = [content_sub_component] + if content.get_named_link().get_link() is not None: + content_sub_component = SubComponent(content.get_named_link().get_link()) + content_component.features = [content_sub_component] content_variants.append(content_component) sbol_document.add(content_component) @@ -141,14 +147,15 @@ def _encode_control_type_using_opil(self, opil_measurement): def _encode_timepoints_using_opil(self, opil_measurement): encoded_timepoints = [] for timepoint in self._timepoints: - encoded_timepoints.append(timepoint.to_sbol()) + encoded_timepoints.append(timepoint.to_opil()) opil_measurement.time = encoded_timepoints def _encode_strains_using_sbol(self, sbol_document): strain_template = LocalSubComponent(identity=self._id_provider.get_unique_sd2_id(), types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) strain_template.name = 'strains template' - strain_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + strain_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) strain_variable.name = 'strain VariableFeature' strain_variable.variable = strain_template strain_variable.variant = [strain.to_sbol(sbol_document) for strain in self._strains] diff --git a/intent_parser/intent/experimental_request_intent.py b/intent_parser/intent/experimental_request_intent.py new file mode 100644 index 00000000..807a7618 --- /dev/null +++ b/intent_parser/intent/experimental_request_intent.py @@ -0,0 +1,22 @@ +from intent_parser.intent.control_intent import ControlIntent +from intent_parser.intent.lab_intent import LabIntent +from intent_parser.intent.measurement_intent import MeasurementIntent +from intent_parser.intent.parameter_intent import ParameterIntent +import logging + +class ExperimentalRequestIntent(object): + """ + Intent Parser's representation of an experimental request + """ + + logger = logging.getLogger('experimental_request_intent') + + def __init__(self, experimental_request_name=''): + self._experimental_request_name = experimental_request_name + self._lab_intent = LabIntent() + self._measurement_intents = [] + self._control_intent = ControlIntent() + self._parameter_intent = ParameterIntent() + + def add_measurement_intent(self, measurement_intent): + self._measurement_intents.add(measurement_intent) \ No newline at end of file diff --git a/intent_parser/intent/measure_property_intent.py b/intent_parser/intent/measure_property_intent.py index 2e8bae42..9f1c5f47 100644 --- a/intent_parser/intent/measure_property_intent.py +++ b/intent_parser/intent/measure_property_intent.py @@ -1,9 +1,10 @@ from intent_parser.intent_parser_exceptions import IntentParserException from intent_parser.utils.id_provider import IdProvider -from sbol3 import Component, Measure, SubComponent +from sbol3 import Component, SubComponent from typing import Union import intent_parser.constants.sd2_datacatalog_constants as dc_constants import intent_parser.constants.intent_parser_constants as ip_constants +import opil import sbol3.constants as sbol_constants class MeasuredUnit(object): @@ -76,18 +77,18 @@ def get_unit_name_from_uri(self, unit_uri: str): def get_value(self): return self._value - def to_sbol(self): + def to_opil(self): if self._unit_type is not None: return self._get_sbol_measure_by_unit_type() else: if self._unit in self._FLUID_UNIT_MAP: - return self._encode_fluid_using_sbol() + return self._encode_fluid_using_opil() elif self._unit in self._TEMPERATURE_UNIT_MAP: - return self._encode_temperature_using_sbol() + return self._encode_temperature_using_opil() elif self._unit in self._TIME_UNIT_MAP: - return self._encode_timepoint_using_sbol() + return self._encode_timepoint_using_opil() else: - return Measure(float(self._value), ip_constants.NCIT_NOT_APPLICABLE) + return opil.Measure(float(self._value), ip_constants.NCIT_NOT_APPLICABLE) def to_structure_request(self): return {dc_constants.VALUE: float(self._value), @@ -95,113 +96,113 @@ def to_structure_request(self): def _get_sbol_measure_by_unit_type(self): if self._unit_type == ip_constants.UNIT_TYPE_FLUID: - return self._encode_fluid_using_sbol() + return self._encode_fluid_using_opil() elif self._unit_type == ip_constants.UNIT_TYPE_TIMEPOINT: - return self._encode_timepoint_using_sbol() + return self._encode_timepoint_using_opil() elif self._unit_type == ip_constants.UNIT_TYPE_TEMPERATURE: - return self._encode_temperature_using_sbol() + return self._encode_temperature_using_opil() else: raise IntentParserException('%s measurement type not supported' % self._unit_type) - def _encode_fluid_using_sbol(self): + def _encode_fluid_using_opil(self): if self._unit == '%': - measure = Measure(self._value, ip_constants.NCIT_CONCENTRATION) + measure = opil.Measure(self._value, ip_constants.NCIT_CONCENTRATION) return measure elif self._unit == 'M': - measure = Measure(self._value, ip_constants.UO_MOLAR) + measure = opil.Measure(self._value, ip_constants.UO_MOLAR) return measure elif self._unit == 'mM': - measure = Measure(self._value, ip_constants.UO_MILLI_MOLAR) + measure = opil.Measure(self._value, ip_constants.UO_MILLI_MOLAR) return measure elif self._unit == 'X': - measure = Measure(self._value, ip_constants.NCIT_FOLD_CHANGE) + measure = opil.Measure(self._value, ip_constants.NCIT_FOLD_CHANGE) return measure elif self._unit == 'g/L': - measure = Measure(self._value, ip_constants.UO_GRAM_PER_LITER) + measure = opil.Measure(self._value, ip_constants.UO_GRAM_PER_LITER) return measure elif self._unit == 'ug/ml': - measure = Measure(self._value, ip_constants.NCIT_MICROGRAM_PER_MILLILITER) + measure = opil.Measure(self._value, ip_constants.NCIT_MICROGRAM_PER_MILLILITER) return measure elif self._unit == 'micromole': - measure = Measure(self._value, ip_constants.NCIT_MICROMOLE) + measure = opil.Measure(self._value, ip_constants.NCIT_MICROMOLE) return measure elif self._unit == 'nM': - measure = Measure(self._value, ip_constants.NCIT_NANOMOLE) + measure = opil.Measure(self._value, ip_constants.NCIT_NANOMOLE) return measure elif self._unit == 'uM': - measure = Measure(self._value, ip_constants.NCIT_MICROMOLE) + measure = opil.Measure(self._value, ip_constants.NCIT_MICROMOLE) return measure elif self._unit == 'mg/ml': - measure = Measure(self._value, ip_constants.UO_MILLIGRAM_PER_MILLILITER) + measure = opil.Measure(self._value, ip_constants.UO_MILLIGRAM_PER_MILLILITER) return measure elif self._unit == 'ng/ul': - measure = Measure(self._value, ip_constants.UO_NANO_GRAM_PER_LITER) + measure = opil.Measure(self._value, ip_constants.UO_NANO_GRAM_PER_LITER) return measure elif self._unit == 'microlitre': - measure = Measure(self._value, ip_constants.OTU_MICROLITRE) + measure = opil.Measure(self._value, ip_constants.OTU_MICROLITRE) return measure else: raise IntentParserException('%s is not a supported unit.' % self._unit) - def _encode_temperature_using_sbol(self): + def _encode_temperature_using_opil(self): if self._unit == 'celsius': - measure = Measure(self._value, ip_constants.NCIT_CELSIUS) + measure = opil.Measure(self._value, ip_constants.NCIT_CELSIUS) measure.name = 'celsius' return measure elif self._unit == 'fahrenheit': - measure = Measure(self._value, ip_constants.NCIT_FAHRENHEIT) + measure = opil.Measure(self._value, ip_constants.NCIT_FAHRENHEIT) measure.name = 'fahrenheit' return measure else: raise IntentParserException('%s is not a supported unit.' % self._unit) - def _encode_timepoint_using_sbol(self): + def _encode_timepoint_using_opil(self): if self._unit == 'day': - measure = Measure(self._value, ip_constants.NCIT_DAY) + measure = opil.Measure(self._value, ip_constants.NCIT_DAY) measure.name = 'day' return measure elif self._unit == 'hour': - measure = Measure(self._value, ip_constants.NCIT_HOUR) + measure = opil.Measure(self._value, ip_constants.NCIT_HOUR) measure.name = 'hour' return measure elif self._unit == 'femtosecond': - measure = Measure(self._value, ip_constants.OTU_FEMTOSECOND) + measure = opil.Measure(self._value, ip_constants.OTU_FEMTOSECOND) measure.name = 'femtosecond' return measure elif self._unit == 'microsecond': - measure = Measure(self._value, ip_constants.NCIT_MICROSECOND) + measure = opil.Measure(self._value, ip_constants.NCIT_MICROSECOND) measure.name = 'microsecond' return measure elif self._unit == 'millisecond': - measure = Measure(self._value, ip_constants.NCIT_MILLISECOND) + measure = opil.Measure(self._value, ip_constants.NCIT_MILLISECOND) measure.name = 'millisecond' return measure elif self._unit == 'minute': - measure = Measure(self._value, ip_constants.NCIT_MINUTE) + measure = opil.Measure(self._value, ip_constants.NCIT_MINUTE) measure.name = 'minute' return measure elif self._unit == 'month': - measure = Measure(self._value, ip_constants.NCIT_MONTH) + measure = opil.Measure(self._value, ip_constants.NCIT_MONTH) measure.name = 'month' return measure elif self._unit == 'nanosecond': - measure = Measure(self._value, ip_constants.NCIT_NANOSECOND) + measure = opil.Measure(self._value, ip_constants.NCIT_NANOSECOND) measure.name = 'nanosecond' return measure elif self._unit == 'picosecond': - measure = Measure(self._value, ip_constants.NCIT_PICOSECOND) + measure = opil.Measure(self._value, ip_constants.NCIT_PICOSECOND) measure.name = 'picosecond' return measure elif self._unit == 'second': - measure = Measure(self._value, ip_constants.NCIT_SECOND) + measure = opil.Measure(self._value, ip_constants.NCIT_SECOND) measure.name = 'second' return measure elif self._unit == 'week': - measure = Measure(self._value, ip_constants.NCIT_WEEK) + measure = opil.Measure(self._value, ip_constants.NCIT_WEEK) measure.name = 'week' return measure elif self._unit == 'year': - measure = Measure(self._value, ip_constants.NCIT_YEAR) + measure = opil.Measure(self._value, ip_constants.NCIT_YEAR) measure.name = 'year' return measure else: @@ -289,7 +290,7 @@ def __init__(self, media_name: NamedLink, media_value: NamedLink): def get_media_name(self) -> NamedLink: return self._media_name - def get_timepoint(self) -> NamedLink: + def get_timepoint(self) -> TimepointIntent: return self._timepoint def set_timepoint(self, timepoint: TimepointIntent): @@ -340,6 +341,8 @@ def to_sbol(self, sbol_document): content_component = Component(identity=self._id_provider.get_unique_sd2_id(), component_type=sbol_constants.SBO_FUNCTIONAL_ENTITY) content_component.name = self._reagent_name.get_name() + if self._reagent_name.get_link() is None: + raise IntentParserException('Expecting to get name of reagent linked to a SynBioHub entry but none was given for %s.' % self._reagent_name.get_name()) content_sub_component = SubComponent(self._reagent_name.get_link()) content_component.features = [content_sub_component] sbol_document.add(content_component) diff --git a/intent_parser/intent/measurement_intent.py b/intent_parser/intent/measurement_intent.py index d79454ca..637ef2fe 100644 --- a/intent_parser/intent/measurement_intent.py +++ b/intent_parser/intent/measurement_intent.py @@ -87,16 +87,15 @@ def to_sbol(self, sbol_document): media_templates = [] for content in self._contents.get_contents(): - media_template, media_variable = content.to_sbol_for_media(sbol_document) - all_sample_templates.append(media_template) - all_sample_variables.append(media_variable) - media_templates.append(media_template) + media_templates, media_variables = content.to_sbol_for_media(sbol_document) + all_sample_templates.extend(media_templates) + all_sample_variables.extend(media_variables) + media_templates.extend(media_templates) content_templates, content_variables = content.to_sbol(sbol_document) all_sample_templates.extend(content_templates) all_sample_variables.extend(content_variables) - if len(self._strains) > 0: strain_template, strain_variable = self._encode_strains_using_sbol(sbol_document) all_sample_templates.append(strain_template) @@ -195,7 +194,8 @@ def _encode_batches_using_sbol(self): types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) batch_template.name = ip_constants.HEADER_BATCH_VALUE - batch_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + batch_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) batch_variable.variable = batch_template batch_variable.variant_measure = [Measure(value, ip_constants.NCIT_NOT_APPLICABLE) for value in self._batches] return batch_template, batch_variable @@ -241,7 +241,8 @@ def _encode_control_using_sbol(self, sbol_document): types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) control_template.name = ip_constants.HEADER_CONTROL_TYPE_VALUE - control_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + control_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) control_variable.variable = control_template control_variable.variant_derivation = [control.to_sbol(sbol_document) for control in self._controls] return control_template, control_variable @@ -251,7 +252,8 @@ def _encode_optical_densities_using_sbol(self): types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) ods_template.name = ip_constants.HEADER_ODS_VALUE - ods_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + ods_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) ods_variable.variable = ods_template ods_variable.variant_measure = [Measure(value, ip_constants.NCIT_NOT_APPLICABLE) for value in self._optical_densities] return ods_template, ods_variable @@ -261,7 +263,8 @@ def _encode_replicates_using_sbol(self): types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) replicate_template.name = ip_constants.HEADER_REPLICATE_VALUE - replicate_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + replicate_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) replicate_variable.variable = replicate_template replicate_variable.variant_measure = [Measure(value, ip_constants.NCIT_NOT_APPLICABLE) for value in self._replicates] return replicate_template, replicate_variable @@ -270,7 +273,8 @@ def _encode_strains_using_sbol(self, sbol_document): strain_template = LocalSubComponent(identity=self._id_provider.get_unique_sd2_id(), types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) strain_template.name = ip_constants.HEADER_STRAINS_VALUE - strain_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + strain_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) strain_variable.variable = strain_template strain_variable.variant = [strain.to_sbol(sbol_document) for strain in self._strains] @@ -279,16 +283,17 @@ def _encode_strains_using_sbol(self, sbol_document): def _encode_timepoint_using_opil(self, opil_measurement): encoded_timepoints = [] for timepoint in self._timepoints: - encoded_timepoints.append(timepoint.to_sbol()) + encoded_timepoints.append(timepoint.to_opil()) opil_measurement.time = encoded_timepoints def _encode_temperature_using_sbol(self): # sbol3 requires that a VariantMeasure must point to a VariableFeature with a templated Feature. # However, there is no need for creating a template Feature to encode temperature. To address this, # temperatures will be attached to a media Feature. - temperature_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + temperature_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) temperature_variable.name = 'temperature variants' - temperature_variable.variant_measure = [temperature.to_sbol() for temperature in self._temperatures] + temperature_variable.variant_measure = [temperature.to_opil() for temperature in self._temperatures] return temperature_variable class MeasurementContent(object): @@ -391,44 +396,45 @@ def to_sbol(self, sbol_document): all_variables = [] if len(self._reagents) > 0: reagent_templates, reagent_variables = self._encode_reagent_using_sbol(sbol_document) - all_templates.append(reagent_templates) - all_variables.append(reagent_variables) + all_templates.extend(reagent_templates) + all_variables.extend(reagent_variables) if len(self._column_ids) > 0: - col_id_template, col_id_variable = self._encode_col_ids_using_sbol() + col_id_template, col_id_variable = self._encode_col_ids_using_sbol(sbol_document) all_templates.append(col_id_template) all_variables.append(col_id_variable) if len(self._dna_reaction_concentrations) > 0: - dna_reaction_concentration_template, dna_reaction_concentration_variable = self._encode_dna_reaction_concentration_using_sbol() + dna_reaction_concentration_template, dna_reaction_concentration_variable = self._encode_dna_reaction_concentration_using_sbol(sbol_document) all_templates.append(dna_reaction_concentration_template) all_variables.append(dna_reaction_concentration_variable) if len(self._lab_ids) > 0: - lab_id_template, lab_id_variable = self._encode_lab_ids_using_sbol() + lab_id_template, lab_id_variable = self._encode_lab_ids_using_sbol(sbol_document) all_templates.append(lab_id_template) all_variables.append(lab_id_variable) if len(self._num_neg_controls) > 0: - num_neg_control_template, num_neg_control_variable = self._encode_number_of_negative_controls_using_sbol() + num_neg_control_template, num_neg_control_variable = self._encode_number_of_negative_controls_using_sbol(sbol_document) all_templates.append(num_neg_control_template) all_variables.append(num_neg_control_variable) if len(self._rna_inhibitor_reaction_flags) > 0: - use_rna_inhib_template, use_rna_inhib_variable = self._encode_use_rna_inhibitor_using_sbol() + use_rna_inhib_template, use_rna_inhib_variable = self._encode_use_rna_inhibitor_using_sbol(sbol_document) all_templates.append(use_rna_inhib_template) all_variables.append(use_rna_inhib_variable) if len(self._row_ids) > 0: - row_id_template, row_id_variable = self._encode_for_row_ids_using_sbol() + row_id_template, row_id_variable = self._encode_for_row_ids_using_sbol(sbol_document) all_templates.append(row_id_template) all_variables.append(row_id_variable) if len(self._template_dna_values) > 0: - template_dna_template, template_dna_variable = self._encode_template_dna_using_sbol() + template_dna_template, template_dna_variable = self._encode_template_dna_using_sbol(sbol_document) all_templates.append(template_dna_template) all_variables.append(template_dna_variable) return all_templates, all_variables - def _encode_col_ids_using_sbol(self): + def _encode_col_ids_using_sbol(self, sbol_document): col_id_template = LocalSubComponent(identity=self._id_provider.get_unique_sd2_id(), types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) col_id_template.name = ip_constants.HEADER_COLUMN_ID_VALUE - col_id_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + col_id_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) col_id_variable.variable = col_id_template col_id_components = [] @@ -437,16 +443,18 @@ def _encode_col_ids_using_sbol(self): component_type=sbol_constants.SBO_FUNCTIONAL_ENTITY) col_id_component.name = str(value.get_value()) col_id_components.append(col_id_component) + sbol_document.add(col_id_component) col_id_variable.variant = col_id_components return col_id_template, col_id_variable - def _encode_dna_reaction_concentration_using_sbol(self): + def _encode_dna_reaction_concentration_using_sbol(self, sbol_document): dna_reaction_concentration_template = LocalSubComponent(identity=self._id_provider.get_unique_sd2_id(), types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) dna_reaction_concentration_template.name = ip_constants.HEADER_DNA_REACTION_CONCENTRATION_VALUE - dna_reaction_concentration_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + dna_reaction_concentration_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) dna_reaction_concentration_variable.variable = dna_reaction_concentration_template dna_reaction_concentration_components = [] @@ -455,15 +463,17 @@ def _encode_dna_reaction_concentration_using_sbol(self): component_type=sbol_constants.SBO_FUNCTIONAL_ENTITY) lab_component.name = str(value.get_value()) dna_reaction_concentration_components.append(lab_component) + sbol_document.add(lab_component) dna_reaction_concentration_variable.variant = dna_reaction_concentration_components return dna_reaction_concentration_template, dna_reaction_concentration_variable - def _encode_lab_ids_using_sbol(self): + def _encode_lab_ids_using_sbol(self, sbol_document): lab_id_template = LocalSubComponent(identity=self._id_provider.get_unique_sd2_id(), types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) lab_id_template.name = ip_constants.HEADER_LAB_ID_VALUE - lab_id_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + lab_id_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) lab_id_variable.variable = lab_id_template lab_id_components = [] @@ -472,40 +482,62 @@ def _encode_lab_ids_using_sbol(self): component_type=sbol_constants.SBO_FUNCTIONAL_ENTITY) lab_component.name = value.get_value() lab_id_components.append(lab_component) + sbol_document.add(lab_component) lab_id_variable.variant = lab_id_components return lab_id_template, lab_id_variable + def _filter_unique_medias(self): + unique_medias = {} + for media in self._medias: + media_name = media.get_media_name().get_name() + media_link = media.get_media_name().get_link() + if media_name not in unique_medias: + unique_medias[media_name] = [media] + else: + unique_medias[media_name].append(media) + return unique_medias + def to_sbol_for_media(self, sbol_document): # method is public in order to provide other measurement information link to media - media_template = LocalSubComponent(identity=self._id_provider.get_unique_sd2_id(), - types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) - media_template.name = 'media template' - media_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + if len(self._medias) == 0: + raise IntentParserException('There must be at least one media present in order generate opil.') - media_variants = [] - media_variant_measures = [] - for media in self._medias: - media_variants.append(media.to_sbol(sbol_document)) - if media.get_timepoint() is not None: - media_variant_measure = media.get_timepoint().to_sbol() - media_variant_measures.append(media_variant_measure) + media_templates = [] + media_variables = [] + for media_name, medias in self._filter_unique_medias().items(): + media_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) + media_variants = [] + media_variant_measure = None + for media in medias: + media_variants.append(media.to_sbol(sbol_document)) + if media.get_timepoint() is not None: + media_variant_measure = media.get_timepoint().to_opil() + + media_template = LocalSubComponent(identity=self._id_provider.get_unique_sd2_id(), + types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) + media_template.name = media_name + media_variable.variable = media_template + if len(media_variants) == 0: + raise IntentParserException('no media values generated for sbol.') - media_variable.variable = media_template - if len(media_variants) == 0: - raise IntentParserException('no media values generated for sbol.') - media_variable.variant = media_variants + media_variable.variant = media_variants - if len(media_variant_measures) > 0: - media_variable.variant_measure = media_variant_measures - return media_template, media_variable + if media_variant_measure: + media_template.measures = [media_variant_measure] + media_templates.append(media_template) + media_variables.append(media_variable) + + return media_templates, media_variables - def _encode_number_of_negative_controls_using_sbol(self): + def _encode_number_of_negative_controls_using_sbol(self, sbol_document): num_neg_control_template = LocalSubComponent(identity=self._id_provider.get_unique_sd2_id(), types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) num_neg_control_template.name = ip_constants.HEADER_NUMBER_OF_NEGATIVE_CONTROLS_VALUE - num_neg_control_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + num_neg_control_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) num_neg_control_variable.variable = num_neg_control_template num_neg_control_components = [] @@ -514,36 +546,63 @@ def _encode_number_of_negative_controls_using_sbol(self): component_type=sbol_constants.SBO_FUNCTIONAL_ENTITY) num_neg_control_component.name = str(value.get_value()) num_neg_control_components.append(num_neg_control_component) + sbol_document.add(num_neg_control_component) num_neg_control_variable.variant = num_neg_control_components return num_neg_control_template, num_neg_control_variable + def _filter_unique_reagents(self): + unique_reagents = {} + for reagent in self._reagents: + reagent_name = reagent.get_reagent_name().get_name() + reagent_link = reagent.get_reagent_name().get_link() + if reagent_name not in unique_reagents: + unique_reagents[reagent_name] = [reagent] + else: + unique_reagents[reagent_name].append(reagent) + return unique_reagents + def _encode_reagent_using_sbol(self, sbol_document): - reagent_template = LocalSubComponent(identity=self._id_provider.get_unique_sd2_id(), - types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) - reagent_template.name = 'reagent template' - reagent_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + reagent_templates = [] + reagent_variables = [] - reagent_variants = [] - reagent_variant_measures = [] + for reagent_name, reagents in self._filter_unique_reagents().items(): + reagent_variant_measures = [] + reagent_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) - for reagent in self._reagents: - reagent_variants.append(reagent.to_sbol(sbol_document)) - if reagent.get_timepoint() is not None: - reagent_variant_measure = reagent.get_timepoint().to_sbol() - reagent_variant_measures.append(reagent_variant_measure) + reagent_timepoint_measure = None + for reagent in reagents: + current_reagent_name = reagent.get_reagent_name().get_name() + current_reagent_link = reagent.get_reagent_name().get_link() - reagent_variable.variable = reagent_template - reagent_variable.variant = reagent_variants - reagent_variable.variant_measure = reagent_variant_measures - return reagent_template, reagent_variable + if reagent_name != current_reagent_name: + raise IntentParserException('expected name for reagent %s but got %s' % (reagent_name, current_reagent_name)) - def _encode_use_rna_inhibitor_using_sbol(self): + reagent_variant_measure = reagent.to_opil() + reagent_variant_measures.append(reagent_variant_measure) + if reagent.get_timepoint() is not None: + reagent_timepoint_measure = reagent.get_timepoint().to_opil() + + reagent_template = LocalSubComponent(identity=self._id_provider.get_unique_sd2_id(), + types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) + reagent_template.name = reagent_name + if reagent_timepoint_measure: + reagent_template.measures = [reagent_timepoint_measure] + reagent_variable.variable = reagent_template + reagent_variable.variant_measure = reagent_variant_measures + reagent_templates.append(reagent_template) + reagent_variables.append(reagent_variable) + + return reagent_templates, reagent_variables + + def _encode_use_rna_inhibitor_using_sbol(self, sbol_document): use_rna_inhib_template = LocalSubComponent(identity=self._id_provider.get_unique_sd2_id(), types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) use_rna_inhib_template.name = ip_constants.HEADER_USE_RNA_INHIBITOR_IN_REACTION_VALUE - use_rna_inhib_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + use_rna_inhib_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) use_rna_inhib_variable.variable = use_rna_inhib_template use_rna_inhib_components = [] @@ -552,15 +611,17 @@ def _encode_use_rna_inhibitor_using_sbol(self): component_type=sbol_constants.SBO_FUNCTIONAL_ENTITY) use_rna_inhib_component.name = str(value.get_value()) use_rna_inhib_components.append(use_rna_inhib_component) + sbol_document.add(use_rna_inhib_component) use_rna_inhib_variable.variant = use_rna_inhib_components return use_rna_inhib_template, use_rna_inhib_variable - def _encode_for_row_ids_using_sbol(self): + def _encode_for_row_ids_using_sbol(self, sbol_document): row_id_template = LocalSubComponent(identity=self._id_provider.get_unique_sd2_id(), types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) row_id_template.name = ip_constants.HEADER_ROW_ID_VALUE - row_id_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + row_id_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) row_id_variable.variable = row_id_template row_id_components = [] @@ -569,24 +630,27 @@ def _encode_for_row_ids_using_sbol(self): component_type=sbol_constants.SBO_FUNCTIONAL_ENTITY) row_id_component.name = str(value.get_value()) row_id_components.append(row_id_component) + sbol_document.add(row_id_component) row_id_variable.variant = row_id_components return row_id_template, row_id_variable - def _encode_template_dna_using_sbol(self): + def _encode_template_dna_using_sbol(self, sbol_document): template_dna_template = LocalSubComponent(identity=self._id_provider.get_unique_sd2_id(), types=[sbol_constants.SBO_FUNCTIONAL_ENTITY]) template_dna_template.name = ip_constants.HEADER_TEMPLATE_DNA_VALUE - template_dna_variable = VariableFeature(cardinality=sbol_constants.SBOL_ONE) + template_dna_variable = VariableFeature(identity=self._id_provider.get_unique_sd2_id(), + cardinality=sbol_constants.SBOL_ONE) template_dna_variable.variable = template_dna_template template_dna_components = [] for value in self._template_dna_values: template_dna_component = Component(identity=self._id_provider.get_unique_sd2_id(), component_type=sbol_constants.SBO_FUNCTIONAL_ENTITY) - template_dna_component.name = value.get_value() + template_dna_component.name = value.get_name() template_dna_components.append(template_dna_component) + sbol_document.add(template_dna_components) template_dna_variable.variant = template_dna_components return template_dna_template, template_dna_variable diff --git a/intent_parser/protocols/opil_parameter_utils.py b/intent_parser/protocols/opil_parameter_utils.py index 6ab85fee..8d2a15c3 100644 --- a/intent_parser/protocols/opil_parameter_utils.py +++ b/intent_parser/protocols/opil_parameter_utils.py @@ -5,6 +5,9 @@ import opil import sbol3 +from intent_parser.intent_parser_exceptions import IntentParserException + + def clone_boolean_parameter_field(boolean_parameter): return create_opil_boolean_parameter_field(boolean_parameter.identity, boolean_parameter.name) @@ -55,7 +58,7 @@ def create_opil_measurement_parameter_field(field_id: str, field: str): def create_opil_measurement_parameter_value(value_id: str, value: float, unit: str): parameter_value = opil.MeasureValue(value_id) measure = MeasuredUnit(value, unit) - parameter_value.has_measure = measure.to_sbol() + parameter_value.has_measure = measure.to_opil() return parameter_value def clone_string_parameter_field(string_parameter): @@ -113,6 +116,21 @@ def get_protocol_id_from_annotaton(protocol): return id_annotation.property_owner.strateos_id +def get_protocol_interfaces_from_sbol_doc(sbol_doc) -> list: + protocol_interfaces = [] + for obj in sbol_doc.objects: + if type(obj) is opil.opil_factory.ProtocolInterface: + protocol_interfaces.append(obj) + + return protocol_interfaces + +def get_opil_experimental_request(opil_doc): + experimental_request = [] + for opil_object in opil_doc.objects: + if type(opil_object) is opil.oil_factory.ExperimentalRequest: + experimental_request.append(opil_object) + return experimental_request + def get_parameters_from_protocol_interface(protocol_interface): return [parameter for parameter in protocol_interface.has_parameter] diff --git a/intent_parser/requirements.txt b/intent_parser/requirements.txt index 425b1205..6f2a3d31 100644 --- a/intent_parser/requirements.txt +++ b/intent_parser/requirements.txt @@ -8,7 +8,7 @@ google-auth-oauthlib gunicorn jsonschema oauth2client -opil==1.0b1 +opil==1.0b2 pymongo pyspellchecker python-docx @@ -16,7 +16,7 @@ python-Levenshtein python-magic requests_oauthlib sbol2 -sbol3==1.0a5 +sbol3==1.0a6 six==1.13.0 tenacity transcriptic diff --git a/intent_parser/server/intent_parser_processor.py b/intent_parser/server/intent_parser_processor.py index 016f83a1..70f50cdd 100644 --- a/intent_parser/server/intent_parser_processor.py +++ b/intent_parser/server/intent_parser_processor.py @@ -279,7 +279,7 @@ def _report_current_analyze_term(self, document_id): actions.append(final_result_action) else: search_result_actions = intent_parser_view.create_analyze_result_dialog(current_result.get_matching_term(), - current_result.get_strain_reference_link(), + current_result.get_sbh_uri(), current_result.get_matching_term(), document_id, current_result.get_paragraph_index(), @@ -343,6 +343,43 @@ def process_submit_to_synbiohub(self, data): 'results': {'operationSucceeded': True} } + def _link_term(self, data): + actions = [] + paragraph_index = data['selectionStartParagraph'] + offset = data['selectionStartOffset'] + end_offset = data['selectionEndOffset'] + sbh_link = data['extra']['link'] + link_text_action = intent_parser_view.link_text(paragraph_index, offset, end_offset, sbh_link) + actions.append(link_text_action) + return actions + + def _link_all_terms(self, data): + actions = [] + document_id = intent_parser_utils.get_document_id_from_json_body(data) + intent_parser = LabExperiment(document_id) + doc_factory = IntentParserDocumentFactory() + ip_document = doc_factory.from_google_doc(intent_parser.load_from_google_doc()) + + + dictionary_term = {data['commonName']: data['extra']['link']} + self.analyze_controller.process_dictionary_terms(document_id, + ip_document, + 'intent_parser', + self._get_or_create_cursor_location(data), + dictionary_term) + + search_results = self.analyze_controller.get_all_analyzed_results(document_id) + sbh_link = data['extra']['link'] + for matching_term in search_results: + paragraph_index = matching_term.get_paragraph_index() + offset = matching_term.get_start_offset() + end_offset = matching_term.get_end_offset() + link_text_action = intent_parser_view.link_text(paragraph_index, offset, end_offset, sbh_link) + actions.append(link_text_action) + + self.analyze_controller.remove_document(document_id) + return actions + def process_submit_form(self, json_body): if 'data' not in json_body: error_message = ['No data provided from button click.'] @@ -355,6 +392,14 @@ def process_submit_form(self, json_body): result = {} if action_type == intent_parser_constants.SUBMIT_FORM: result = self.process_submit_to_synbiohub(data) + elif action_type == 'link': + actions = self._link_term(data) + result['actions'] = actions + result['results'] = {'operationSucceeded': True} + elif action_type == 'linkAll': + actions = self._link_all_terms(data) + result['actions'] = actions + result['results'] = {'operationSucceeded': True} elif action_type == intent_parser_constants.SUBMIT_FORM_CREATE_CONTROLS_TABLE: actions = self.process_controls_table(data, json_body['documentId']) result['actions'] = actions @@ -517,7 +562,7 @@ def process_analyze_yes_to_all(self, document_id, data): actions.append(intent_parser_view.link_text(term.get_paragraph_index(), term.get_start_offset(), term.get_end_offset(), - term.get_strain_reference_link())) + term.get_sbh_uri())) actions.extend(self._report_current_analyze_term(document_id)) return {'actions': actions} diff --git a/intent_parser/server/intent_parser_server.py b/intent_parser/server/intent_parser_server.py index 1da6ff02..2c2e4196 100644 --- a/intent_parser/server/intent_parser_server.py +++ b/intent_parser/server/intent_parser_server.py @@ -38,7 +38,7 @@ def __init__(self): pass def get(self): - return redirect("https://github.com/SD2E/experimental-intent-parser", code=302) + return redirect("https://sd2e.github.io/experimental-intent-parser/", code=302) class GetStatus(Resource): def __init__(self, ip_processor): diff --git a/intent_parser/table/table_processor/experimental_request_processor.py b/intent_parser/table/table_processor/experimental_request_processor.py new file mode 100644 index 00000000..9da20a0f --- /dev/null +++ b/intent_parser/table/table_processor/experimental_request_processor.py @@ -0,0 +1,91 @@ +import intent_parser.constants.intent_parser_constants as ip_constants +import intent_parser.protocols.opil_parameter_utils as opil_utils +import logging + +from intent_parser.intent.experimental_request_intent import ExperimentalRequestIntent +from intent_parser.intent.measure_property_intent import MeasuredUnit +from intent_parser.intent.measurement_intent import MeasurementIntent +from intent_parser.table.table_processor.processor import Processor + +class ExperimentalRequestProcessor(Processor): + """ + Intent Parser's representation of an experimental request + """ + + logger = logging.getLogger('experimental_request') + + def __init__(self, opil_document): + super().__init__() + self._opil_document = opil_document + self._experiment_request_intent = None + + def get_intent(self): + return self._experiment_request_intent + + def process_opil_experimental_request(self): + experimental_requests = opil_utils.get_opil_experimental_request(self._opil_document) + protocol_interfaces = opil_utils.get_protocol_interfaces_from_sbol_doc(self._opil_document) + if len(experimental_requests) == 0: + self.validation_errors.append('No experimental request found from opil document.') + return + + elif len(experimental_requests) > 1: + self.validation_errors.append('Expected to get one ExperimentRequests per opil document but more than one were found.') + return + + self._process_experiment_request(experimental_requests[-1], protocol_interfaces) + + def _process_experiment_request(self, experiment_request, protocol_interfaces): + if experiment_request.name: + self._experiment_request_intent = ExperimentalRequestIntent(experiment_request.name) + else: + self._experiment_request_intent = ExperimentalRequestIntent() + + if experiment_request.measurements: + self._process_opil_measurements(experiment_request.measurements) + + if experiment_request.has_parameter_value: + self._process_opil_parameters(protocol_interfaces, experiment_request.has_parameter_value) + + + def _process_opil_measurements(self, opil_measurements): + measurement_intents = [] + for opil_measurement in opil_measurements: + # opil custom annotation created for IP: + # - file-type + # - controls + # - column_ids, dna_reaction_concentrations, lab_ids, num_neg_controls, rna_inhibitor_reaction_flags + # - row_ids, template_dna_values + # This does not appear in other opil lab document so skip. + measurement_intent = MeasurementIntent() + + if opil_measurement.time: + self._process_opil_timepoints(opil_measurement.time, measurement_intent) + + if opil_measurement.instance_of: + measurement_type = self._process_opil_measurement_type(opil_measurement.instance_of) + if measurement_type: + measurement_intent.set_measurement_type(measurement_type) + + measurement_intents.append(measurement_intent) + + return measurement_intents + + def _process_opil_measurement_type(self, opil_measurement_type): + measurement_type = '' + opil_measurement_type_uri = opil_measurement_type.type + for measurement_type, measurement_type_uri in ip_constants.MEASUREMENT_TYPE_MAPPINGS.items(): + if opil_measurement_type_uri == measurement_type_uri: + measurement_type = measurement_type + return measurement_type + + def _process_opil_timepoints(self, opil_times, measurement_intent): + for opil_measure in opil_times: + value = opil_measure.has_measure.value + # TODO: convert unit_uri to unit name that IP supports from Google doc. + unit_uri = opil_measure.has_measure.unit + timepoint = MeasuredUnit(value, '', unit_type=ip_constants.UNIT_TYPE_TIMEPOINT) + measurement_intent.add_timepoint(timepoint) + + def _process_opil_parameters(self, protocol_interfaces, opil_parameter_values): + pass \ No newline at end of file diff --git a/intent_parser/tests/test_opil_output.py b/intent_parser/tests/test_opil_output.py index 2d29b8c7..40c6f48c 100644 --- a/intent_parser/tests/test_opil_output.py +++ b/intent_parser/tests/test_opil_output.py @@ -1,15 +1,20 @@ from intent_parser.accessor.sbol_dictionary_accessor import SBOLDictionaryAccessor from intent_parser.accessor.strateos_accessor import StrateosAccessor -from intent_parser.intent.measure_property_intent import TimepointIntent -from intent_parser.intent.measurement_intent import MeasurementIntent +from intent_parser.intent.measure_property_intent import TimepointIntent, ReagentIntent, NamedLink, MediaIntent +from intent_parser.intent.measurement_intent import MeasurementIntent, ContentIntent from intent_parser.protocols.protocol_factory import ProtocolFactory from intent_parser.table.intent_parser_cell import IntentParserCell from intent_parser.table.table_processor.opil_processor import OPILProcessor +from sbol3 import CombinatorialDerivation, Component, LocalSubComponent, VariableFeature from unittest.mock import patch import intent_parser.constants.intent_parser_constants as ip_constants import intent_parser.tests.test_util as test_utils import unittest import opil +import sbol3.constants as sbol_constants + +from intent_parser.utils.id_provider import IdProvider + class OpilTest(unittest.TestCase): @@ -27,6 +32,7 @@ def setUp(self, mock_intent_parser_sbh): sbol_dictionary, file_types=['CSV'], lab_names=[ip_constants.LAB_TRANSCRIPTIC]) + self._id_provider = IdProvider() def tearDown(self): pass @@ -66,11 +72,11 @@ def test_file_type_to_opil(self): measurement_intent.add_file_type('CSV') opil_measurement, _ = measurement_intent.to_opil() self.assertIsNotNone(opil_measurement) - self.assertEqual('CSV', opil_measurement.file_type) + self.assertEqual('CSV', [opil_measurement.file_type]) def test_timepoint_to_sbol(self): timepoint = TimepointIntent(12.0, 'hour') - sbol_timepoint = timepoint.to_sbol() + sbol_timepoint = timepoint.to_opil() self.assertIsNotNone(sbol_timepoint) self.assertEqual(sbol_timepoint.value, 12) self.assertEqual(sbol_timepoint.unit, ip_constants.NCIT_HOUR) @@ -85,9 +91,43 @@ def test_measurement_timepoint_size_1(self): self.assertIsNotNone(opil_measurement) opil_measurement_time = opil_measurement.time - self.assertIsNotNone(opil_measurement_time) - self.assertEqual(opil_measurement_time.value, timepoint.to_sbol().value) - self.assertEqual(opil_measurement_time.unit, timepoint.to_sbol().unit) + # TODO: opil can't deference child objects unless they are added to an opil.Document + # self.assertIsNotNone(opil_measurement_time) + # self.assertEqual(opil_measurement_time.value, timepoint.to_sbol().value) + # self.assertEqual(opil_measurement_time.unit, timepoint.to_sbol().unit) + + def test_reagent_to_opil_without_timepoint(self): + reagent_name = NamedLink('M9', 'https://hub.sd2e.org/user/sd2e/design/M9/1') + reagent = ReagentIntent(reagent_name, 10.0, 'uM') + + media_name = NamedLink('media', 'https://hub.sd2e.org/user/sd2e/design/M9/1') + opil_document = opil.Document() + + content_intent = ContentIntent() + content_intent.add_reagent(reagent) + all_templates, all_variables = content_intent.to_sbol(opil_document) + self.assertEqual(1, len(all_templates)) + self.assertEqual(1, len(all_variables)) + reagent_template = all_templates[0] + self.assertTrue(type(reagent_template) == LocalSubComponent) + self.assertEqual(reagent_name.get_name(), reagent_template.name) + + reagent_variable = all_variables[0] + self.assertTrue(type(reagent_variable) == VariableFeature) + self.assertEqual(reagent_variable.variable, reagent_template.identity) + self.assertEqual(1, len(reagent_variable.variant_measure)) + reagent_value = reagent_variable.variant_measure[0] + self.assertEqual(reagent.to_opil().value, reagent_value.value) + self.assertEqual(reagent.to_opil().unit, reagent_value.unit) + + measurement_intent = MeasurementIntent() + measurement_intent.add_content(content_intent) + measurement_intent.to_sbol(opil_document) + combinatorial_derivations = [cd for cd in opil_document.objects if type(cd) == CombinatorialDerivation] + self.assertEqual(1, len(combinatorial_derivations)) + combinatorial_derivation = combinatorial_derivations[0] + + def _create_transcriptic_lab_table(self): lab_table = test_utils.create_fake_lab_table() diff --git a/intent_parser/utils/intent_parser_utils.py b/intent_parser/utils/intent_parser_utils.py index c9d4d2e6..40a9ca05 100644 --- a/intent_parser/utils/intent_parser_utils.py +++ b/intent_parser/utils/intent_parser_utils.py @@ -1,9 +1,10 @@ from collections import namedtuple as _namedtuple -from intent_parser.intent_parser_exceptions import RequestErrorException +from intent_parser.intent_parser_exceptions import IntentParserException, RequestErrorException from difflib import Match from http import HTTPStatus import json import Levenshtein +import sbol3 import re IPSMatch = _namedtuple('Match', 'a b size content_word_length') @@ -14,6 +15,13 @@ def get_google_doc_id(doc_url): doc_id = matched_pattern.group('id') return doc_id +def load_sbol_xml_file(file_path): + sbol_doc = sbol3.Document() + try: + sbol_doc.read(file_path, sbol3.RDF_XML) + except ValueError: + raise IntentParserException('Unable to load sbol file.') + def load_json_file(file_path): with open(file_path, 'r') as file: json_data = json.load(file)