def _compute_diagnostic_text( scoring_project: scoring.ScoringProject, unused_overall_score: float) \ -> Tuple[str, List[int]]: """Create the left-side text of the diagnostic for a given project. Returns: A tuple containing the text, and a list of the orders of missing sentences (if text is empty). """ sentences = [] missing_sentences_orders = [] templates_per_order = itertools.groupby( _SENTENCE_TEMPLATES.get_collection(scoring_project.database), key=lambda template: template.order) for order, templates_iterator in templates_per_order: templates = list(templates_iterator) template = next( scoring.filter_using_score(templates, lambda template: template.filters, scoring_project), None) if not template: if any(template.optional for template in templates): continue # TODO(pascal): Set to warning when we have theoretical complete coverage. logging.debug('Could not find a sentence %d for user.', order) missing_sentences_orders.append(order) continue translated_template = scoring_project.translate_string( template.sentence_template) sentences.append( scoring_project.populate_template(translated_template)) return '\n\n'.join( sentences ) if not missing_sentences_orders else '', missing_sentences_orders
def _compute_diagnostic_overall( project: scoring.ScoringProject, diagnostic: diagnostic_pb2.Diagnostic, category: Optional[diagnostic_pb2.DiagnosticCategory] ) -> diagnostic_pb2.Diagnostic: all_overalls = _DIAGNOSTIC_OVERALL.get_collection(project.database) restricted_overalls: Iterable[diagnostic_pb2.DiagnosticTemplate] = [] if category and (not category.are_strategies_for_alpha_only or project.features_enabled.alpha): restricted_overalls = \ [o for o in all_overalls if o.category_id == category.category_id] if not restricted_overalls: restricted_overalls = [o for o in all_overalls if not o.category_id] overall_template = next((scoring.filter_using_score( restricted_overalls, lambda t: t.filters, project)), None) if not overall_template: # TODO(cyrille): Put a warning here once enough cases are covered with overall templates. return diagnostic diagnostic.overall_sentence = project.populate_template( project.translate_string(overall_template.sentence_template)) diagnostic.text = project.populate_template( project.translate_string(overall_template.text_template)) diagnostic.strategies_introduction = project.populate_template( project.translate_string(overall_template.strategies_introduction)) diagnostic.overall_score = overall_template.score return diagnostic
def test_multiple_filters(self): """Filter an item with multiple filters.""" get_scoring_func = mock.MagicMock() get_scoring_func.return_value = ['test-two', 'test-zero'] filtered = scoring.filter_using_score([42], get_scoring_func, None) self.assertEqual([], list(filtered))
def test_unknown_filter(self): """Filter an item with an unknown filter.""" get_scoring_func = mock.MagicMock() get_scoring_func.return_value = ['unknown-filter'] filtered = scoring.filter_using_score([42], get_scoring_func, None) self.assertEqual([42], list(filtered))
def test_filter_list_constant_scorer(self): """Filter a list returning constant scorer.""" get_scoring_func = mock.MagicMock() get_scoring_func.side_effect = [['test-zero'], ['test-two'], ['test-zero']] filtered = scoring.filter_using_score(range(3), get_scoring_func, None) self.assertEqual([1], list(filtered))
def _compute_diagnostic_overall( project: scoring.ScoringProject, diagnostic: diagnostic_pb2.Diagnostic, main_challenge: diagnostic_pb2.DiagnosticMainChallenge ) -> diagnostic_pb2.Diagnostic: all_overalls = _DIAGNOSTIC_OVERALL.get_collection(project.database) restricted_overalls = [ o for o in all_overalls if o.category_id == main_challenge.category_id ] try: overall_template = next( (scoring.filter_using_score(restricted_overalls, lambda t: t.filters, project))) except StopIteration: logging.warning('No overall template for project: %s', main_challenge.category_id) return diagnostic diagnostic.overall_sentence = project.populate_template( project.translate_airtable_string( 'diagnosticOverall', overall_template.id, 'sentence_template', is_genderized=True, hint=overall_template.sentence_template)) diagnostic.text = project.populate_template( project.translate_airtable_string('diagnosticOverall', overall_template.id, 'text_template', is_genderized=True, hint=overall_template.text_template)) diagnostic.strategies_introduction = project.populate_template( project.translate_airtable_string( 'diagnosticOverall', overall_template.id, 'strategies_introduction', is_genderized=True, hint=overall_template.strategies_introduction)) diagnostic.overall_score = overall_template.score diagnostic.bob_explanation = main_challenge.bob_explanation all_responses = _DIAGNOSTIC_RESPONSES.get_collection(project.database) self_diagnostic_category_id = project.details.original_self_diagnostic.category_id response_id = f'{self_diagnostic_category_id}:{main_challenge.category_id}' response_text = next( (response.text for response in all_responses if response.response_id == response_id), '') diagnostic.response = project.translate_airtable_string( 'diagnosticResponses', response_id, 'text', is_genderized=True, hint=response_text) return diagnostic
def compute_sub_diagnostic_observations( scoring_project: scoring.ScoringProject, topic: diagnostic_pb2.DiagnosticTopic) \ -> Iterator[diagnostic_pb2.SubDiagnosticObservation]: """Find all relevant observations for a given sub-diagnostic topic.""" templates = scoring.filter_using_score( (template for template in _SUBTOPIC_OBSERVATION_TEMPLATES.get_collection( scoring_project.database) if template.topic == topic), lambda template: template.filters, scoring_project) for template in templates: yield diagnostic_pb2.SubDiagnosticObservation( text=scoring_project.populate_template( scoring_project.translate_string(template.sentence_template)), is_attention_needed=template.is_attention_needed)
def list_all_tips( user: user_pb2.User, project: project_pb2.Project, piece_of_advice: project_pb2.Advice, database: pymongo_database.Database ) -> List[action_pb2.ActionTemplate]: """List all available tips for a piece of advice. Args: user: the full user info. project: the project to give tips for. piece_of_advice: the piece of advice to give tips for. database: access to the database to get modules and tips. Returns: An iterable of tips for this module. """ try: module = next(m for m in _advice_modules(database) if m.advice_id == piece_of_advice.advice_id) except StopIteration: logging.warning('Advice module %s does not exist anymore', piece_of_advice.advice_id) return [] # Get tip templates. all_tip_templates = _tip_templates(database) tip_templates = filter(None, (all_tip_templates.get(t) for t in module.tip_template_ids)) # Filter tips. scoring_project = scoring.ScoringProject(project, user, database, now=now.get()) filtered_tips = scoring.filter_using_score(tip_templates, lambda t: t.filters, scoring_project) return [_translate_tip(tip, scoring_project) for tip in filtered_tips]
def _compute_sub_diagnostic_text( scoring_project: scoring.ScoringProject, sub_diagnostic: diagnostic_pb2.SubDiagnostic) \ -> str: """Create the sentence of the diagnostic for a given project on a given topic. Returns: The text for the diagnostic submetric. """ template = next( scoring.filter_using_score( (template for template in _SUBTOPIC_SENTENCE_TEMPLATES.get_collection( scoring_project.database) if template.topic == sub_diagnostic.topic), lambda template: template.filters, scoring_project), None) if not template: # TODO(cyrille): Change to warning once we have theoretical complete coverage. logging.debug('Could not find a sentence for topic %s for user.', sub_diagnostic.topic) return '' translated_template = scoring_project.translate_string( template.sentence_template) return scoring_project.populate_template(translated_template)
def test_filter_list_with_no_filters(self) -> None: """Filter a list with no filters to apply.""" filtered = scoring.filter_using_score(range(5), lambda a: [], self.dummy_project) self.assertEqual([0, 1, 2, 3, 4], list(filtered))