def to_service_uid(uid_brain_obj_str): """Resolves the passed in element to a valid uid. Returns None if the value cannot be resolved to a valid uid """ if api.is_uid(uid_brain_obj_str) and uid_brain_obj_str != "0": return uid_brain_obj_str if api.is_object(uid_brain_obj_str): obj = api.get_object(uid_brain_obj_str) if IAnalysisService.providedBy(obj): return api.get_uid(obj) elif IRoutineAnalysis.providedBy(obj): return obj.getServiceUID() else: logger.error("Type not supported: {}".format(obj.portal_type)) return None if isinstance(uid_brain_obj_str, six.string_types): # Maybe is a keyword? query = dict(portal_type="AnalysisService", getKeyword=uid_brain_obj_str) brains = api.search(query, SETUP_CATALOG) if len(brains) == 1: return api.get_uid(brains[0]) # Or maybe a title query = dict(portal_type="AnalysisService", title=uid_brain_obj_str) brains = api.search(query, SETUP_CATALOG) if len(brains) == 1: return api.get_uid(brains[0]) return None
def _to_service(self, thing): """Convert to Analysis Service :param thing: UID/Catalog Brain/Object/Something :returns: Analysis Service object or None """ # Convert UIDs to objects if api.is_uid(thing): thing = api.get_object_by_uid(thing, None) # Bail out if the thing is not a valid object if not api.is_object(thing): logger.warn("'{}' is not a valid object!".format(repr(thing))) return None # Ensure we have an object here and not a brain obj = api.get_object(thing) if IAnalysisService.providedBy(obj): return obj if IAnalysis.providedBy(obj): return obj.getAnalysisService() # An object, but neither an Analysis nor AnalysisService? # This should never happen. portal_type = api.get_portal_type(obj) logger.error("ARAnalysesField doesn't accept objects from {} type. " "The object will be dismissed.".format(portal_type)) return None
def _to_service(self, thing): """Convert to Analysis Service :param thing: UID/Catalog Brain/Object/Something :returns: Analysis Service object or None """ # Convert UIDs to objects if api.is_uid(thing): thing = api.get_object_by_uid(thing, None) # Bail out if the thing is not a valid object if not api.is_object(thing): logger.warn("'{}' is not a valid object!".format(repr(thing))) return None # Ensure we have an object here and not a brain obj = api.get_object(thing) if IAnalysisService.providedBy(obj): return obj if IAnalysis.providedBy(obj): return obj.getAnalysisService() # An object, but neither an Analysis nor AnalysisService? # This should never happen. msg = "ARAnalysesField doesn't accept objects from {} type. " \ "The object will be dismissed.".format(api.get_portal_type(obj)) logger.warn(msg) return None
def create_analysis(context, source, **kwargs): """Create a new Analysis. The source can be an Analysis Service or an existing Analysis, and all possible field values will be set to the values found in the source object. :param context: The analysis will be created inside this object. :param source: The schema of this object will be used to populate analysis. :param kwargs: The values of any keys which match schema fieldnames will be inserted into the corrosponding fields in the new analysis. :returns: Analysis object that was created :rtype: Analysis """ an_id = kwargs.get('id', source.getKeyword()) analysis = _createObjectByType("Analysis", context, an_id) copy_analysis_field_values(source, analysis, **kwargs) # AnalysisService field is not present on actual AnalysisServices. if IAnalysisService.providedBy(source): analysis.setAnalysisService(source) else: analysis.setAnalysisService(source.getAnalysisService()) # Set the interims from the Service service_interims = analysis.getAnalysisService().getInterimFields() # Avoid references from the analysis interims to the service interims service_interims = copy.deepcopy(service_interims) analysis.setInterimFields(service_interims) analysis.unmarkCreationFlag() zope.event.notify(ObjectInitializedEvent(analysis)) return analysis
def addReferenceAnalysis(self, service): """ Creates a new Reference Analysis object based on this Sample Reference, with the type passed in and associates the newly created object to the Analysis Service passed in. :param service: Object, brain or UID of the Analysis Service :param reference_type: type of ReferenceAnalysis, where 'b' is is Blank and 'c' is Control :type reference_type: A String :returns: the newly created Reference Analysis :rtype: string """ if api.is_uid(service) or api.is_brain(service): return self.addReferenceAnalysis(api.get_object(service)) if not IAnalysisService.providedBy(service): return None interim_fields = service.getInterimFields() analysis = _createObjectByType("ReferenceAnalysis", self, id=tmpID()) # Copy all the values from the schema # TODO Add Service as a param in ReferenceAnalysis constructor and do # this logic there instead of here discard = [ 'id', ] keys = service.Schema().keys() for key in keys: if key in discard: continue if key not in analysis.Schema().keys(): continue val = service.getField(key).get(service) # Campbell's mental note:never ever use '.set()' directly to a # field. If you can't use the setter, then use the mutator in order # to give the value. We have realized that in some cases using # 'set' when the value is a string, it saves the value # as unicode instead of plain string. # analysis.getField(key).set(analysis, val) mutator_name = analysis.getField(key).mutator mutator = getattr(analysis, mutator_name) mutator(val) analysis.setAnalysisService(service) ref_type = self.getBlank() and 'b' or 'c' analysis.setReferenceType(ref_type) analysis.setInterimFields(interim_fields) analysis.unmarkCreationFlag() renameAfterCreation(analysis) return analysis
def _resolve_items_to_service_uids(items): portal = api.portal.get() # We need to send a list of service UIDS to setAnalyses function. # But we may have received one, or a list of: # AnalysisService instances # Analysis instances # service titles # service UIDs # service Keywords service_uids = [] # Maybe only a single item was passed if type(items) not in (list, tuple): items = [ items, ] for item in items: uid = False # service objects if IAnalysisService.providedBy(item): uid = item.UID() service_uids.append(uid) # Analysis objects (shortcut for eg copying analyses from other AR) if IAnalysis.providedBy(item): uid = item.getService().UID() service_uids.append(uid) # Maybe object UID. bsc = getToolByName(portal, 'bika_setup_catalog') brains = bsc(UID=item) if brains: uid = brains[0].UID service_uids.append(uid) # Maybe service Title bsc = getToolByName(portal, 'bika_setup_catalog') brains = bsc(portal_type='AnalysisService', title=item) if brains: uid = brains[0].UID service_uids.append(uid) # Maybe service Title bsc = getToolByName(portal, 'bika_setup_catalog') brains = bsc(portal_type='AnalysisService', getKeyword=item) if brains: uid = brains[0].UID service_uids.append(uid) if not uid: raise RuntimeError( str(item) + " should be the UID, title, keyword " " or title of an AnalysisService.") return service_uids
def get(self, instance, **kwargs): an_interims = RecordsField.get(self, instance, **kwargs) or [] if not IAnalysisService.providedBy(instance): return an_interims # This instance implements IAnalysisService calculation = instance.getCalculation() if not calculation: return an_interims # Ensure the service includes the interims from the calculation an_keys = map(lambda interim: interim['keyword'], an_interims) # Avoid references from the service interims to the calculation interims calc_interims = copy.deepcopy(calculation.getInterimFields()) calc_interims = filter(lambda inter: inter['keyword'] not in an_keys, calc_interims) return an_interims + calc_interims
def _resolve_items_to_service_uids(items): portal = api.portal.get() # We need to send a list of service UIDS to setAnalyses function. # But we may have received one, or a list of: # AnalysisService instances # Analysis instances # service titles # service UIDs # service Keywords service_uids = [] # Maybe only a single item was passed if type(items) not in (list, tuple): items = [items, ] for item in items: uid = False # service objects if IAnalysisService.providedBy(item): uid = item.UID() service_uids.append(uid) # Analysis objects (shortcut for eg copying analyses from other AR) if IAnalysis.providedBy(item): uid = item.getService().UID() service_uids.append(uid) # Maybe object UID. bsc = getToolByName(portal, 'bika_setup_catalog') brains = bsc(UID=item) if brains: uid = brains[0].UID service_uids.append(uid) # Maybe service Title bsc = getToolByName(portal, 'bika_setup_catalog') brains = bsc(portal_type='AnalysisService', title=item) if brains: uid = brains[0].UID service_uids.append(uid) # Maybe service Keyword bsc = getToolByName(portal, 'bika_setup_catalog') brains = bsc(portal_type='AnalysisService', getKeyword=item) if brains: uid = brains[0].UID service_uids.append(uid) if not uid: raise RuntimeError( str(item) + " should be the UID, title, keyword " " or title of an AnalysisService.") return service_uids
def resolve_to_uid(item): if api.is_uid(item): return item elif IAnalysisService.providedBy(item): return item.UID() elif IRoutineAnalysis.providedBy(item): return item.getServiceUID() bsc = api.get_tool("bika_setup_catalog") brains = bsc(portal_type='AnalysisService', getKeyword=item) if brains: return brains[0].UID brains = bsc(portal_type='AnalysisService', title=item) if brains: return brains[0].UID raise RuntimeError( str(item) + " should be the UID, title, keyword " " or title of an AnalysisService.")
def _get_service_uid(self, item): if api.is_uid(item): return item if not api.is_object(item): logger.warn("Not an UID: {}".format(item)) return None obj = api.get_object(item) if IAnalysisService.providedBy(obj): return api.get_uid(obj) if IAnalysis.providedBy(obj) and IRequestAnalysis.providedBy(obj): return obj.getServiceUID() # An object, but neither an Analysis nor AnalysisService? # This should never happen. msg = "ARAnalysesField doesn't accept objects from {} type. " \ "The object will be dismissed." logger.warn(msg.format(api.get_portal_type(obj))) return None
def create_analysis(context, source, **kwargs): """Create a new Analysis. The source can be an Analysis Service or an existing Analysis, and all possible field values will be set to the values found in the source object. :param context: The analysis will be created inside this object. :param source: The schema of this object will be used to populate analysis. :param kwargs: The values of any keys which match schema fieldnames will be inserted into the corrosponding fields in the new analysis. :returns: Analysis object that was created :rtype: Analysis """ an_id = kwargs.get('id', source.getKeyword()) analysis = _createObjectByType("Analysis", context, an_id) copy_analysis_field_values(source, analysis, **kwargs) # AnalysisService field is not present on actual AnalysisServices. if IAnalysisService.providedBy(source): analysis.setAnalysisService(source) else: analysis.setAnalysisService(source.getAnalysisService()) analysis.unmarkCreationFlag() zope.event.notify(ObjectInitializedEvent(analysis)) return analysis
def _resolve_items_to_service_uids(items): """ Returns a list of service uids without duplicates based on the items :param items: A list (or one object) of service-related info items. The list can be heterogeneous and each item can be: - Analysis Service instance - Analysis instance - Analysis Service title - Analysis Service UID - Analysis Service Keyword If an item that doesn't match any of the criterias above is found, the function will raise a RuntimeError """ portal = None bsc = None service_uids = [] # Maybe only a single item was passed if type(items) not in (list, tuple): items = [items, ] for item in items: # service objects if IAnalysisService.providedBy(item): uid = item.UID() service_uids.append(uid) continue # Analysis objects (shortcut for eg copying analyses from other AR) if IAnalysis.providedBy(item): uid = item.getService().UID() service_uids.append(uid) continue # An object UID already there? if (item in service_uids): continue # Maybe object UID. portal = portal if portal else api.portal.get() bsc = bsc if bsc else getToolByName(portal, 'bika_setup_catalog') brains = bsc(UID=item) if brains: uid = brains[0].UID service_uids.append(uid) continue # Maybe service Title brains = bsc(portal_type='AnalysisService', title=item) if brains: uid = brains[0].UID service_uids.append(uid) continue # Maybe service Keyword brains = bsc(portal_type='AnalysisService', getKeyword=item) if brains: uid = brains[0].UID service_uids.append(uid) continue raise RuntimeError( str(item) + " should be the UID, title, keyword " " or title of an AnalysisService.") return list(set(service_uids))
def _resolve_items_to_service_uids(items): """ Returns a list of service uids without duplicates based on the items :param items: A list (or one object) of service-related info items. The list can be heterogeneous and each item can be: - Analysis Service instance - Analysis instance - Analysis Service title - Analysis Service UID - Analysis Service Keyword If an item that doesn't match any of the criterias above is found, the function will raise a RuntimeError """ portal = None bsc = None service_uids = [] # Maybe only a single item was passed if type(items) not in (list, tuple): items = [ items, ] for item in items: # service objects if IAnalysisService.providedBy(item): uid = item.UID() service_uids.append(uid) continue # Analysis objects (shortcut for eg copying analyses from other AR) if IAnalysis.providedBy(item): uid = item.getService().UID() service_uids.append(uid) continue # An object UID already there? if (item in service_uids): continue # Maybe object UID. portal = portal if portal else api.portal.get() bsc = bsc if bsc else getToolByName(portal, 'bika_setup_catalog') brains = bsc(UID=item) if brains: uid = brains[0].UID service_uids.append(uid) continue # Maybe service Title brains = bsc(portal_type='AnalysisService', title=item) if brains: uid = brains[0].UID service_uids.append(uid) continue # Maybe service Keyword brains = bsc(portal_type='AnalysisService', getKeyword=item) if brains: uid = brains[0].UID service_uids.append(uid) continue raise RuntimeError( str(item) + " should be the UID, title, keyword " " or title of an AnalysisService.") return list(set(service_uids))
def doActionToAnalysis(source_analysis, action): """ This functions executes the action against the analysis. :base: a full analysis object. The new analyses will be cloned from it. :action: a dictionary representing an action row. [{'action': 'duplicate', ...}, {,}, ...] :returns: the new analysis """ if not IRequestAnalysis.providedBy(source_analysis): # Only routine analyses (assigned to a Request) are supported logger.warn("Only IRequestAnalysis are supported in reflex testing") return None state = api.get_review_status(source_analysis) action_id = action.get('action', '') if action_id == "new_analysis": # Create a new analysis (different from the original) service_uid = action.get("new_analysis", "") if not api.is_uid(service_uid): logger.error("Not a valid UID: {}".format(service_uid)) return None service = api.get_object_by_uid(service_uid, None) if not service or not IAnalysisService.providedBy(service): logger.error("No valid service for UID {}".format(service_uid)) return None analysis = create_analysis(source_analysis.aq_parent, service) analysis.setSamplePartition(source_analysis.getSamplePartition()) changeWorkflowState(analysis, "bika_analysis_workflow", "sample_received") elif action_id == 'setvisibility': target_id = action.get('setvisibilityof', '') if target_id == "original": analysis = source_analysis else: analysis = _fetch_analysis_for_local_id(source_analysis, target_id) elif action_id == 'repeat' and state != 'retracted': # Repeat an analysis consist on cancel it and then create a new # analysis with the same analysis service used for the canceled # one (always working with the same sample). It'll do a retract # action doActionFor(source_analysis, 'retract') analysis_request = source_analysis.getRequest() analysis = analysis_request.getAnalyses(sort_on="created")[-1] analysis = api.get_object(analysis) analysis.setResult('') elif action_id == 'duplicate' or state == 'retracted': analysis = duplicateAnalysis(source_analysis) analysis.setResult('') elif action_id == 'setresult': target = action.get('setresulton', '') result_value = action.get('setresultdiscrete', '') or \ action['setresultvalue'] if target == 'original': analysis = source_analysis.getOriginalReflexedAnalysis() analysis.setResult(result_value) elif target == 'new': # Create a new analysis analysis = duplicateAnalysis(source_analysis) analysis.setResult(result_value) doActionFor(analysis, 'submit') else: logger.error("Unknown 'setresulton' directive: {}".format(target)) return None else: logger.error("Unknown Reflex Rule action: {}".format(action_id)) return None analysis.setReflexRuleAction(action_id) analysis.setIsReflexAnalysis(True) analysis.setReflexAnalysisOf(source_analysis) analysis.setReflexRuleActionsTriggered( source_analysis.getReflexRuleActionsTriggered()) if action.get('showinreport', '') == "invisible": analysis.setHidden(True) elif action.get('showinreport', '') == "visible": analysis.setHidden(False) # Setting the original reflected analysis if source_analysis.getOriginalReflexedAnalysis(): analysis.setOriginalReflexedAnalysis( source_analysis.getOriginalReflexedAnalysis()) else: analysis.setOriginalReflexedAnalysis(source_analysis) analysis.setReflexRuleLocalID(action.get('an_result_id', '')) # Setting the remarks to base analysis #remarks = get_remarks(action, analysis) #analysis.setRemarks(remarks) return analysis