def score_and_explain(self, project): """Compute a score for the given ScoringProject.""" discrimination_reason = project.translate_string( 'vous nous avez dit que les employeurs ne ' 'vous donnent pas votre chance') relevant_frustrations = { user_pb2.AGE_DISCRIMINATION: discrimination_reason, user_pb2.ATYPIC_PROFILE: discrimination_reason, user_pb2.NO_OFFERS: project.translate_string( "vous nous avez dit ne pas trouver d'offres correspondant " 'à vos critères'), user_pb2.SEX_DISCRIMINATION: discrimination_reason, } its_easy = project.translate_string( "c'est plus facile à faire qu'on peut le croire") # TODO(pascal): Make this dynamic if we get data for after Feb 2018. if project.now >= datetime.datetime(2018, 2, 7): return scoring_base.NULL_EXPLAINED_SCORE frustration_reasons = { relevant_frustrations[frustration] for frustration in project.user_profile.frustrations if frustration in relevant_frustrations } if frustration_reasons or project.get_search_length_now() > 3: return scoring_base.ExplainedScore( 2, list(frustration_reasons) or [its_easy]) return scoring_base.ExplainedScore(1, [its_easy])
def score_and_explain(self, project): """Compute a score for the given ScoringProject.""" close_jobs = self.get_close_jobs(project) search_since_nb_months = round(project.get_search_length_now()) score_modifier = 0 reasons = [] if len(close_jobs.close_jobs) + len(close_jobs.evolution_jobs) < 2: return scoring_base.NULL_EXPLAINED_SCORE if project.get_user_age() >= 45: return scoring_base.NULL_EXPLAINED_SCORE if project.details.passionate_level >= project_pb2.PASSIONATING_JOB: score_modifier = -1 else: reasons.append( project.translate_string( "vous n'êtes pas trop attaché à votre métier")) if project.details.job_search_has_not_started or search_since_nb_months <= 1: return scoring_base.ExplainedScore(2 + score_modifier, reasons) reasons = [ project.translate_string('vous cherchez depuis {} mois').format( search_since_nb_months) ] if search_since_nb_months >= 12: return scoring_base.ExplainedScore(3, reasons) if search_since_nb_months >= 9: return scoring_base.ExplainedScore(2, reasons) if search_since_nb_months >= 6: return scoring_base.ExplainedScore(1, reasons) return scoring_base.NULL_EXPLAINED_SCORE
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute a score for the given ScoringProject.""" first_modes = project.get_fap_modes() if job_pb2.SPONTANEOUS_APPLICATION in first_modes: return scoring_base.ExplainedScore(3, [ project.translate_static_string( "c'est le canal de recrutement n°1 pour votre métier") ]) # In the category missing-diploma, we always have the alternance strategy which requires # spontaneous application data. if project.details.diagnostic.category_id == 'missing-diploma': return scoring_base.ExplainedScore(2, [ project.translate_static_string( "c'est le meilleur moyen de trouver un contrat en alternance" ) ]) second_modes = project.get_fap_modes(rank='second') if job_pb2.SPONTANEOUS_APPLICATION in second_modes: return scoring_base.ExplainedScore(2, [ project.translate_static_string( "c'est un des meilleurs canaux de recrutement pour votre métier" ) ]) if project.details.diagnostic.category_id == 'bravo' and \ user_profile_pb2.NO_OFFERS in project.user_profile.frustrations: return scoring_base.ExplainedScore(2, [ project.translate_static_string( "vous nous avez dit ne pas trouver assez d'offres.") ]) return scoring_base.NULL_EXPLAINED_SCORE
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute a score for the given ScoringProject.""" close_jobs = self.get_close_jobs(project) search_since_nb_months = round(project.get_search_length_now()) score_modifier = 0 reasons: List[str] = [] if len(close_jobs.close_jobs) + len(close_jobs.evolution_jobs) < 2: return scoring_base.NULL_EXPLAINED_SCORE # TODO(cyrille): Make this more robust. force_in_stuck_market = None # TODO(cyrille): Rather use market_stress to avoid depending on diagnostic to be computed. if project.details.diagnostic.category_id == 'stuck-market': force_in_stuck_market = scoring_base.ExplainedScore(1, reasons) if project.get_user_age() >= 45: return force_in_stuck_market or scoring_base.NULL_EXPLAINED_SCORE if project.details.passionate_level >= project_pb2.PASSIONATING_JOB: score_modifier = -1 else: reasons.append(project.translate_string( "vous n'êtes pas trop attaché à votre métier")) if project.details.job_search_has_not_started or search_since_nb_months <= 1: return scoring_base.ExplainedScore(2 + score_modifier, reasons) reasons = [ project.translate_string('vous cherchez depuis {} mois') .format(search_since_nb_months)] if search_since_nb_months >= 12: return scoring_base.ExplainedScore(3, reasons) if search_since_nb_months >= 9: return scoring_base.ExplainedScore(2, reasons) if search_since_nb_months >= 6: return scoring_base.ExplainedScore(1, reasons) return force_in_stuck_market or scoring_base.NULL_EXPLAINED_SCORE
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute a score for the given ScoringProject.""" local_jobbing = self.get_local_jobbing(project) if len(local_jobbing.reorient_jobbing_jobs) < 2: return scoring_base.NULL_EXPLAINED_SCORE score_modifier = 0 reasons: list[str] = [] if project.details.passionate_level == project_pb2.LIFE_GOAL_JOB: score_modifier = -2 if project.job_group_info().growth_2012_2022 < .1: score_modifier = -1 if score_modifier >= 0: reasons.append( project.translate_static_string( 'votre métier ne vous tient pas trop à cœur')) if project.user_profile.highest_degree <= job_pb2.CAP_BEP: return scoring_base.ExplainedScore(3 + score_modifier, reasons) if project.user_profile.highest_degree <= job_pb2.BAC_BACPRO: return scoring_base.ExplainedScore(max(2 + score_modifier, 1), reasons) if project.user_profile.highest_degree <= job_pb2.BTS_DUT_DEUG: return scoring_base.ExplainedScore(1, reasons) return scoring_base.NULL_EXPLAINED_SCORE
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute a score for the given ScoringProject.""" associations = self.list_associations(project) search_length_reason = project.translate_static_string( "vous nous avez dit que vous êtes en recherche d'emploi " 'depuis %jobSearchLengthAtCreation') if not associations: return scoring_base.NULL_EXPLAINED_SCORE if user_profile_pb2.MOTIVATION in project.user_profile.frustrations: return scoring_base.ExplainedScore(3, [ project.translate_static_string( 'vous nous avez dit avoir du mal à garder votre ' + 'motivation au top') ]) if len(associations) >= 3 and project.get_search_length_at_creation( ) >= 6: return scoring_base.ExplainedScore(3, [search_length_reason]) if project.get_search_length_at_creation() >= 12: return scoring_base.ExplainedScore(3, [search_length_reason]) return scoring_base.ExplainedScore(2, [ project.translate_static_string( "l'accompagnement humain peut beaucoup vous apporter") ])
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: if project.details.diagnostic.category_id == 'enhance-methods-to-interview': return scoring_base.ExplainedScore(3, []) reasons = [ project.translate_static_string( "vous nous avez dit avoir passé beaucoup d'entretiens sans succès" ) ] if project.details.total_interview_count < 0: num_interviews = 0 elif project.details.total_interview_count > 0: num_interviews = project.details.total_interview_count else: num_interviews = _NUM_INTERVIEWS.get( project.details.total_interviews_estimate, 0) job_search_length_months = project.get_search_length_at_creation() if job_search_length_months < 1: job_search_length_months = 1 num_monthly_interviews = num_interviews / job_search_length_months if num_monthly_interviews > _max_monthly_interviews(project): return scoring_base.ExplainedScore(3, reasons) # Whatever the number of month of search, trigger 3 if the user did more than 5 interviews: if num_interviews >= _NUM_INTERVIEWS[project_pb2.DECENT_AMOUNT]: return scoring_base.ExplainedScore(3, reasons) if project.details.diagnostic.category_id == 'bravo': return scoring_base.ExplainedScore(1, []) return scoring_base.NULL_EXPLAINED_SCORE
def score_and_explain(self, project): """Compute a score for the given ScoringProject.""" missions = self.volunteering_missions(project).missions if not missions: return scoring_base.NULL_EXPLAINED_SCORE if project.get_search_length_at_creation() < 9: return scoring_base.ExplainedScore(1, []) return scoring_base.ExplainedScore(2, [ 'ça fait du bien de garder une activité sociale dans une recherche longue' ])
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute a score for the given ScoringProject.""" frustration_reasons = list(self._get_frustrations_reasons(project)) its_easy = project.translate_static_string( "c'est plus facile à faire qu'on peut le croire") if frustration_reasons or project.get_search_length_now() > 3: return scoring_base.ExplainedScore( 2, frustration_reasons or [its_easy]) return scoring_base.ExplainedScore(1, [its_easy])
def score_and_explain(self, project): """Compute a score for the given ScoringProject.""" application_modes = project.job_group_info().application_modes.values() first_modes = set(fap_modes.modes[0].mode for fap_modes in application_modes) first_modes.discard(job_pb2.UNDEFINED_APPLICATION_MODE) if first_modes == {job_pb2.PERSONAL_OR_PROFESSIONAL_CONTACTS}: return scoring_base.ExplainedScore(2, [project.translate_string( 'les embauches se font surtout par les contacts personnels ou professionnels dans' ' votre métier')]) return scoring_base.ExplainedScore(1, [project.translate_string( "c'est un bon moyen d'étendre votre réseau")])
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute a score for the given ScoringProject.""" if (self._num_interviews_increase(project) >= 2 and project.details.job_search_length_months <= 6): return scoring_base.ExplainedScore(3, [project.translate_string( "nous pensons qu'avec votre profil vous pourriez " "décrocher plus d'entretiens")]) if project.details.diagnostic.category_id == 'bravo' and \ user_pb2.RESUME in project.user_profile.frustrations: return scoring_base.ExplainedScore(1, [project.translate_string( 'vous nous avez dit avoir du mal à rédiger votre CV')]) return scoring_base.NULL_EXPLAINED_SCORE
def score_and_explain(self, project): """Compute a score for the given ScoringProject.""" nearby_cities = self.list_nearby_cities(project) if not nearby_cities: return scoring_base.NULL_EXPLAINED_SCORE if project.details.mobility.area_type > geo_pb2.CITY and \ any(c.relative_offers_per_inhabitant >= 2 for c in nearby_cities): return scoring_base.ExplainedScore( 3, ["il y a beaucoup plus d'offres par habitants dans d'autres villes"]) return scoring_base.ExplainedScore( 2, ["il est toujours bon d'avoir une idée des offres dans les autres villes"])
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute a score for the given ScoringProject.""" if project.details.network_estimate != self._network_level: return scoring_base.NULL_EXPLAINED_SCORE first_modes = project.get_fap_modes() first_modes.discard(job_pb2.UNDEFINED_APPLICATION_MODE) if first_modes == {job_pb2.PERSONAL_OR_PROFESSIONAL_CONTACTS}: return scoring_base.ExplainedScore(3, [ 'le réseau est le canal n°1 pour trouver un métier %inDomain' ]) return scoring_base.ExplainedScore(2, [])
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute a score for the given ScoringProject.""" if project.details.weekly_applications_estimate <= project_pb2.LESS_THAN_2 or \ project.details.job_search_length_months < 2: return scoring_base.ExplainedScore(3, [project.translate_string( 'vous nous avez dit que vous en êtes au début de ' 'vos candidatures')]) if project.details.diagnostic.category_id == 'bravo' and \ user_pb2.RESUME in project.user_profile.frustrations: return scoring_base.ExplainedScore(1, [project.translate_string( 'vous nous avez dit avoir du mal à rédiger votre CV')]) return scoring_base.NULL_EXPLAINED_SCORE
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute a score for the given ScoringProject.""" for opened_strategy in project.details.opened_strategies: if opened_strategy.strategy_id in self._strategies: return scoring_base.ExplainedScore( 3, ['vous avez démarré une stratégie qui correspond']) for strategy in project.details.strategies: if strategy.strategy_id in self._strategies: return scoring_base.ExplainedScore(2, [ "c'est une stratégie qui pourrait marcher dans votre cas" ]) return scoring_base.ExplainedScore(1, [])
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute the score for a given project and explains it. Requirements are: - being between 16 and 30 y.o if having a handicap or between 16 and 25 otherwise - having low or no experience (intern maximum) """ age = project.get_user_age() seniority = project.details.seniority reasons: list[str] = [] if age < 16 or seniority > project_pb2.INTERN: return scoring_base.NULL_EXPLAINED_SCORE if project.user_profile.has_handicap and age <= 30: reasons = [ project.translate_static_string('vous avez entre 16 et 30 ans') ] if age <= 25: reasons = [ project.translate_static_string('vous avez entre 16 et 25 ans') ] if not reasons: return scoring_base.NULL_EXPLAINED_SCORE return scoring_base.ExplainedScore(2, reasons)
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute a score for the given ScoringProject.""" reasons: List[str] = [] # For now we just match for people willing to move to the whole country. # There might be cases where we should be able to recommend to people who want to move to # their own region, but it would add complexity to find them. is_not_ready_to_move = project.details.area_type < geo_pb2.COUNTRY is_not_single = project.user_profile.family_situation != user_pb2.SINGLE has_advanced_degree = project.user_profile.highest_degree >= job_pb2.LICENCE_MAITRISE is_not_young = project.get_user_age() > 30 looks_only_for_cdi = project.details.employment_types == [job_pb2.CDI] if (is_not_ready_to_move or is_not_young or is_not_single or has_advanced_degree or looks_only_for_cdi): return scoring_base.NULL_EXPLAINED_SCORE reasons.append( project.translate_string( 'vous nous avez dit être prêt%eFeminine à déménager')) reasons.append( project.translate_string('vous êtes disponible familialement')) if len(self._get_seasonal_departements(project).departement_stats) > 1: reasons.append( project.translate_string( "il y a plus d'offres saisonnières par habitants dans d'autres villes" )) return scoring_base.ExplainedScore(2, reasons) return scoring_base.NULL_EXPLAINED_SCORE
def _score_and_explain_after_filters(project): """A helper function to give a score and an explanation for all advices in the module, once some prerequisite filters have been met. """ if project.user_profile.has_car_driving_license != user_pb2.FALSE: return scoring_base.NULL_EXPLAINED_SCORE reasons = [] license_required = next( (license.percent_required for license in project.job_group_info().requirements.driving_licenses if license.driving_license == job_pb2.CAR), 0) if license_required: reasons.append( project.translate_string( 'le permis est important dans votre métier')) score_modifier = 0 if _license_helps_mobility(project.details.mobility): reasons.append( project.translate_string('le permis augmenterait votre mobilité')) score_modifier = 1 if not reasons: return scoring_base.NULL_EXPLAINED_SCORE score = min( 3, score_modifier + (3 if license_required > 30 else 2 if license_required > 10 else 1 if license_required else 0)) return scoring_base.ExplainedScore(score, reasons)
def _score_and_explain_after_filters(project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """A helper function to give a score and an explanation for all advices in the module, once some prerequisite filters have been met. """ if project.user_profile.has_car_driving_license != boolean_pb2.FALSE: return scoring_base.NULL_EXPLAINED_SCORE reasons = [] license_required = next( (license.percent_required for license in project.job_group_info().requirements.driving_licenses if license.driving_license == job_pb2.CAR), 0) if license_required: reasons.append( project.translate_static_string( 'le permis est important dans votre métier')) score_modifier = 0 if _license_helps_mobility(project.details): reasons.append( project.translate_static_string( 'le permis augmenterait votre mobilité')) score_modifier = 1 if not reasons: return scoring_base.NULL_EXPLAINED_SCORE score = min( 3, score_modifier + ( # Example at 80% is civil engineer F1106. 3 if license_required > 80 else # Example at 67% is translator E1108. 2 if license_required > 67 else # Example at 50% is chiropractor J1408. 1 if license_required > 50 else 0)) return scoring_base.ExplainedScore(score, reasons)
def score_and_explain(self, project): """Compute a score for the given ScoringProject.""" # This job group has jobs that are too different to consider them as a # small change. # TODO(pascal): Check for other such job groups and move the config to # a class property. if project.details.target_job.job_group.rome_id == 'K2401': return scoring_base.NULL_EXPLAINED_SCORE specific_jobs = project.requirements().specific_jobs if not specific_jobs or specific_jobs[ 0].code_ogr == project.details.target_job.code_ogr: return scoring_base.NULL_EXPLAINED_SCORE try: target_job_percentage = next( j.percent_suggested for j in specific_jobs if j.code_ogr == project.details.target_job.code_ogr) except StopIteration: target_job_percentage = 0 has_way_better_job = target_job_percentage + 30 < specific_jobs[ 0].percent_suggested has_better_job = target_job_percentage + 5 < specific_jobs[ 0].percent_suggested is_looking_for_new_job = project.details.kind == project_pb2.REORIENTATION reasons = [] if has_way_better_job: reasons.append( project.translate_string( "il y a beaucoup plus d'offres dans des métiers proches")) elif (project.get_search_length_at_creation() > 6 and has_better_job): reasons.append( project.translate_string( "il y a plus d'offres dans des métiers proches")) if is_looking_for_new_job: reasons.append( project.translate_string( 'vous nous avezdit vouloir vous reconvertir')) if reasons: return scoring_base.ExplainedScore(3, reasons) return scoring_base.ExplainedScore(2, [ project.translate_string( "il y a un bon nombre d'offres dans des métiers proches") ])
def score_and_explain(self, project): """Compute a score for the given ScoringProject.""" application_modes = project.job_group_info().application_modes.values() first_modes = set( fap_modes.modes[0].mode for fap_modes in application_modes if len(fap_modes.modes)) if job_pb2.SPONTANEOUS_APPLICATION in first_modes: return scoring_base.ExplainedScore(3, [project.translate_string( "c'est le canal de recrutement n°1 pour votre métier")]) second_modes = set( fap_modes.modes[1].mode for fap_modes in application_modes if len(fap_modes.modes) > 1) if job_pb2.SPONTANEOUS_APPLICATION in second_modes: return scoring_base.ExplainedScore(2, [project.translate_string( "c'est un des meilleurs canaux de recrutement pour votre métier")]) return scoring_base.NULL_EXPLAINED_SCORE
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute the score for a given project and explains it.""" skills = self._get_skills(project) if not skills.skills: return scoring_base.NULL_EXPLAINED_SCORE return scoring_base.ExplainedScore(2, [])
def score_and_explain(self, project): """Compute the score for a given project and explains it.""" age = project.get_user_age() if age < 16: return scoring_base.NULL_EXPLAINED_SCORE score, reasons = _score_and_explain_after_filters(project) if not score: return scoring_base.NULL_EXPLAINED_SCORE return scoring_base.ExplainedScore(max(1, score - 1), reasons)
def score_and_explain(self, project): """Compute a score for the given ScoringProject.""" if (self._num_interviews_increase(project) >= 2 and project.details.job_search_length_months <= 6): return scoring_base.ExplainedScore(3, [ project.translate_string( "nous pensons qu'avec votre profil vous pourriez " "décrocher plus d'entretiens") ]) return scoring_base.NULL_EXPLAINED_SCORE
def score_and_explain(self, project): # pylint: disable=no-self-use """Compute a score for the given ScoringProject.""" if project.details.weekly_applications_estimate <= project_pb2.LESS_THAN_2 or \ project.details.job_search_length_months < 2: return scoring_base.ExplainedScore(3, [ project.translate_string( 'vous nous avez dit que vous en êtes au début de ' 'vos candidatures') ]) return scoring_base.NULL_EXPLAINED_SCORE
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute the score for a given project and explains it.""" age = project.get_user_age() if age < 16: return scoring_base.NULL_EXPLAINED_SCORE score, reasons = _score_and_explain_after_filters(project) if not score: return scoring_base.NULL_EXPLAINED_SCORE # We bring more value in the driving-license-euro and # driving-license-low-income so we show this one after (lower score). return scoring_base.ExplainedScore(max(1, score - 1), reasons)
def score_and_explain(self, project): """Compute a score for the given ScoringProject.""" reasons = [] if project.details.mobility.area_type != geo_pb2.COUNTRY and \ project.details.mobility.area_type != geo_pb2.WORLD: return scoring_base.NULL_EXPLAINED_SCORE reasons.append( project.translate_string( 'vous nous avez dit être prêt%eFeminine à déménager')) if _find_best_departements(None, project): reasons.append( project.translate_string( "il y a beaucoup plus d'offres par habitants dans d'autres villes" )) return scoring_base.ExplainedScore(2, reasons) return scoring_base.NULL_EXPLAINED_SCORE
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute a score for the given ScoringProject.""" has_any_covid_risk_info = jobs.has_covid_risk_info(project.database) has_any_automation_risk_info = jobs.has_automation_risk_info( project.database) if not has_any_covid_risk_info and not has_any_automation_risk_info: raise scoring_base.NotEnoughDataException( 'No data about jobs being affected by Covid or automation', { 'data.job_group_info.covid_risk', 'data.job_group_info.automation_risk' }) # Total risk from 0 to 100. total_risk = 0 # Covid risk: 0 if safe or no covid data at all, 25 if unknown, 50 if risky. covid_risk = project.job_group_info().covid_risk if covid_risk == job_pb2.COVID_RISKY: total_risk += 50 elif not covid_risk and has_any_covid_risk_info: total_risk += 25 # Automation risk: 0 if super safe or no covid data at all, 25 if unknown, 50 if very risky. automation_risk = project.job_group_info().automation_risk if automation_risk: total_risk += automation_risk // 2 elif has_any_automation_risk_info: total_risk += 25 if total_risk <= 15: # This job is as safe as it can be, no need to explore for more. return scoring_base.NULL_EXPLAINED_SCORE # 81+ => 3 return scoring_base.ExplainedScore(min((total_risk - 15) / 22, 3), [ project.translate_static_string( "il existe des métiers avec peu de risques d'automatisation", ), ])
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute a score for the given ScoringProject.""" relevant_salons = self._get_relevant_salons(project) if not relevant_salons: return scoring_base.NULL_EXPLAINED_SCORE reasons = [] # TODO(cyrille): Refine this depending on salons' locations. if project.details.area_type >= geo_pb2.COUNTRY: reasons.append(project.translate_static_string('vous êtes mobile partout en France')) elif any(salon.HasField('location') for salon in relevant_salons): reasons.append(project.translate_static_string( 'certains salons concernent votre zone géographique')) if any(salon.job_group_ids for salon in relevant_salons): reasons.append( f'des entreprises {project.job_group_info().in_domain} recherchent du monde') return scoring_base.ExplainedScore(1, reasons)
def score_and_explain(self, project: scoring_base.ScoringProject) \ -> scoring_base.ExplainedScore: """Compute a score for the given ScoringProject.""" reasons = [] if project.details.area_type < geo_pb2.COUNTRY: return scoring_base.NULL_EXPLAINED_SCORE reasons.append( project.populate_template( project.translate_static_string( 'vous nous avez dit être prêt%eFeminine à déménager'))) local_stats = project.local_diagnosis() if local_stats.imt.yearly_avg_offers_per_10_candidates and \ local_stats.num_less_stressful_departements: reasons.append( project.translate_static_string( "il y a beaucoup plus d'offres par habitants dans d'autres villes" )) return scoring_base.ExplainedScore(2, reasons) return scoring_base.NULL_EXPLAINED_SCORE