def _record_revocation_on_violation_response( violation_response: StateSupervisionViolationResponse, terminating_officer: Optional[StateAgent]): """Adds revocation information onto the provided |violation_response| as necessary.""" violation_response.response_type = StateSupervisionViolationResponseType.PERMANENT_DECISION.value violation_response.decision = StateSupervisionViolationResponseDecision.REVOCATION.value if terminating_officer: create_if_not_exists(terminating_officer, violation_response, 'decision_agents')
def _hydrate_person_external_ids(_file_tag: str, row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): for obj in extracted_objects: if isinstance(obj, StatePerson): control_numbers = row['control_numbers'].split( ',') if row['control_numbers'] else [] state_ids = row['state_ids'].split( ',') if row['state_ids'] else [] parole_numbers = row['parole_numbers'].split( ',') if row['parole_numbers'] else [] external_ids_to_create = [] for state_id in state_ids: external_ids_to_create.append( StatePersonExternalId( state_person_external_id_id=state_id, id_type=US_PA_SID)) for control_number in control_numbers: external_ids_to_create.append( StatePersonExternalId( state_person_external_id_id=control_number, id_type=US_PA_CONTROL)) for parole_number in parole_numbers: external_ids_to_create.append( StatePersonExternalId( state_person_external_id_id=parole_number, id_type=US_PA_PBPP)) for id_to_create in external_ids_to_create: create_if_not_exists(id_to_create, obj, 'state_person_external_ids')
def _hydrate_races(_file_tag: str, row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): for obj in extracted_objects: if isinstance(obj, StatePerson): races = row['races_ethnicities_list'].split( ',') if row['races_ethnicities_list'] else [] for race in races: race_obj = StatePersonRace(race=race) create_if_not_exists(race_obj, obj, 'state_person_external_ids')
def _set_case_type_from_supervision_level( self, _file_tag: str, _row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): """Sets supervision period case type from the supervision level if necessary.""" for obj in extracted_objects: if isinstance(obj, StateSupervisionPeriod): supervision_level = obj.supervision_level if supervision_level and \ self.get_enum_overrides().parse(supervision_level, StateSupervisionCaseType) is not None: case_type_to_create = StateSupervisionCaseTypeEntry( case_type=supervision_level) create_if_not_exists( case_type_to_create, obj, 'state_supervision_case_type_entries')
def _add_supervising_officer( _file_tag: str, row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): agent_id = row.get('agnt_id', '') agent_name = row.get('name', '') if not agent_id or not agent_name: return for obj in extracted_objects: if isinstance(obj, StatePerson): agent_to_create = StateAgent( state_agent_id=agent_id, full_name=agent_name, agent_type=StateAgentType.SUPERVISION_OFFICER.value) create_if_not_exists(agent_to_create, obj, 'supervising_officer')
def _add_supervising_officer(_file_tag: str, row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): """Adds the current supervising officer onto the extracted person.""" supervising_officer_id = row.get('AGENT') if not supervising_officer_id: return for extracted_object in extracted_objects: if isinstance(extracted_object, StatePerson): agent_to_create = StateAgent( state_agent_id=supervising_officer_id, agent_type=StateAgentType.SUPERVISION_OFFICER.value) create_if_not_exists(agent_to_create, extracted_object, 'supervising_officer')
def _add_judge_to_court_cases(_file_tag: str, row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): judge_id = row.get('judge_cd', '') judge_name = row.get('judge_name', '') if not judge_id or not judge_name: return judge_to_create = StateAgent(state_agent_id=judge_id, full_name=judge_name, agent_type=StateAgentType.JUDGE.value) for obj in extracted_objects: if isinstance(obj, StateCourtCase): create_if_not_exists(judge_to_create, obj, 'judge')
def _hydrate_external_id(_file_tag: str, row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): for obj in extracted_objects: if isinstance(obj, StatePerson): external_ids_to_create = [] for column, id_type in columns_to_id_types.items(): value = row.get(column, '').strip() if value: external_ids_to_create.append( StatePersonExternalId(state_person_external_id_id=value, id_type=id_type)) for id_to_create in external_ids_to_create: create_if_not_exists(id_to_create, obj, 'state_person_external_ids')
def _add_supervising_officer(_file_tag: str, row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): agent_id = row.get('empl_sdesc', '') agent_name = row.get('empl_ldesc', '') if not agent_id or not agent_name or agent_id == UNKNOWN_EMPLOYEE_SDESC: return for obj in extracted_objects: if isinstance(obj, StateSupervisionPeriod): agent_to_create = StateAgent( state_agent_id=agent_id, full_name=agent_name, agent_type=StateAgentType.SUPERVISION_OFFICER.value) create_if_not_exists(agent_to_create, obj, 'supervising_officer')
def _hydrate_violation_types(_file_tag: str, row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): """Adds ViolationTypeEntries onto the already generated SupervisionViolations.""" violation_types = sorted_list_from_str(row.get('violation_types', '')) if not violation_types: return for obj in extracted_objects: if isinstance(obj, StateSupervisionViolation): for violation_type in violation_types: violation_type_to_create = StateSupervisionViolationTypeEntry( violation_type=violation_type) create_if_not_exists(violation_type_to_create, obj, 'state_supervision_violation_types')
def _hydrate_sentence_group_ids(_file_tag: str, row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): for obj in extracted_objects: if isinstance(obj, StatePerson): inmate_numbers = row['inmate_numbers'].split( ',') if row['inmate_numbers'] else [] sentence_groups_to_create = [] for inmate_number in inmate_numbers: sentence_groups_to_create.append( StateSentenceGroup( state_sentence_group_id=inmate_number)) for sg_to_create in sentence_groups_to_create: create_if_not_exists(sg_to_create, obj, 'state_sentence_groups')
def _add_terminating_officer_to_supervision_periods( _file_tag: str, row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): """When present, adds supervising officer to the extracted SupervisionPeriods.""" terminating_officer_id = row.get('TERMINATING_OFFICER', None) if not terminating_officer_id: return agent_to_create = StateAgent( state_agent_id=terminating_officer_id, agent_type=StateAgentType.SUPERVISION_OFFICER.value) for extracted_object in extracted_objects: if isinstance(extracted_object, StateSupervisionPeriod): create_if_not_exists(agent_to_create, extracted_object, 'supervising_officer')
def _rationalize_race_and_ethnicity(_file_tag: str, _, cache: Optional[IngestObjectCache]): """For a person whose provided race is HISPANIC, we set the ethnicity to HISPANIC, and the race will be cleared. """ if cache is None: raise ValueError("Ingest object cache is unexpectedly None") for person in cache.get_objects_of_type('state_person'): updated_person_races = [] for person_race in person.state_person_races: if person_race.race in {'5', 'HIS'}: ethnicity_to_create = StatePersonEthnicity(ethnicity=Ethnicity.HISPANIC.value) create_if_not_exists(ethnicity_to_create, person, 'state_person_ethnicities') else: updated_person_races.append(person_race) person.state_person_races = updated_person_races
def copy_name_to_alias(_file_tag: str, _row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): """Copy all name fields stored on a StatePerson object to a new StateAlias child object. """ for extracted_object in extracted_objects: if isinstance(extracted_object, StatePerson): alias_to_create = StateAlias( full_name=extracted_object.full_name, surname=extracted_object.surname, given_names=extracted_object.given_names, middle_names=extracted_object.middle_names, name_suffix=extracted_object.name_suffix, alias_type=StatePersonAliasType.GIVEN_NAME.value) create_if_not_exists(alias_to_create, extracted_object, 'state_aliases')
def _add_sentence_children(_file_tag: str, row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): term_code = row.get('SENTENCE_TERM_CODE', None) for extracted_object in extracted_objects: if isinstance(extracted_object, StateSentenceGroup): sentence_id = _generate_sentence_id(row) max_length = get_normalized_ymd_str('YEARS', 'MONTHS', 'DAYS', row) if term_code == 'SUSP': supervision_sentence = StateSupervisionSentence( state_supervision_sentence_id=sentence_id, supervision_type=StateSupervisionType.PROBATION.value, max_length=max_length) create_if_not_exists(supervision_sentence, extracted_object, 'state_supervision_sentences') else: incarceration_sentence = StateIncarcerationSentence( state_incarceration_sentence_id=sentence_id, max_length=max_length) create_if_not_exists(incarceration_sentence, extracted_object, 'state_incarceration_sentences')
def _rationalize_race_and_ethnicity(_file_tag: str, _row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): ethnicity_override_values = [] for ethnicity in Ethnicity: ethnicity_override_values.extend(enum_overrides.get(ethnicity, [])) for obj in extracted_objects: if isinstance(obj, StatePerson): updated_person_races = [] for person_race in obj.state_person_races: if person_race.race in ethnicity_override_values: ethnicity_to_create = StatePersonEthnicity( ethnicity=person_race.race) create_if_not_exists(ethnicity_to_create, obj, 'state_person_ethnicities') else: updated_person_races.append(person_race) obj.state_person_races = updated_person_races
def _add_supervision_contact_fields( _file_tag: str, row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): """Adds all extra fields needed on SupervisionContact entities that cannot be automatically mapped via YAMLs.""" agent_id = row.get('usr_id', '') agent_name = row.get('name', '') for obj in extracted_objects: if isinstance(obj, StateSupervisionContact): if agent_id and agent_name: agent_to_create = StateAgent( state_agent_id=agent_id, full_name=agent_name, agent_type=StateAgentType.SUPERVISION_OFFICER.value) create_if_not_exists(agent_to_create, obj, 'contacted_agent') obj.resulted_in_arrest = str(obj.status == CONTACT_RESULT_ARREST) if obj.location in CONTACT_TYPES_TO_BECOME_LOCATIONS: obj.contact_type = obj.location obj.location = None
def _hydrate_violation_report_fields( _file_tag: str, row: Dict[str, str], extracted_objects: List[IngestObject], _cache: IngestObjectCache): """Adds fields/children to the SupervisionViolationResponses as necessary. This assumes all SupervisionViolationResponses are of violation reports. """ parole_recommendation = row.get('parolee_placement_recommendation', '') probation_recommendation = row.get('probationer_placement_recommendation', '') recommendations = list(filter(None, [parole_recommendation, probation_recommendation])) for obj in extracted_objects: if isinstance(obj, StateSupervisionViolationResponse): obj.response_type = StateSupervisionViolationResponseType.VIOLATION_REPORT.value for recommendation in recommendations: if recommendation in VIOLATION_REPORT_NO_RECOMMENDATION_VALUES: continue recommendation_to_create = StateSupervisionViolationResponseDecisionEntry(decision=recommendation) create_if_not_exists( recommendation_to_create, obj, 'state_supervision_violation_response_decisions')
def _record_revocation_on_violation(violation: StateSupervisionViolation, row: Dict[str, str]): """Adds revocation information onto the provided |violation| as necessary.""" # These three flags are either '0' (False) or '-1' (True). That -1 may now be (1) after a recent Docstars # change. revocation_for_new_offense = row.get('REV_NOFF_YN', None) in ['-1', '(1)'] revocation_for_absconsion = row.get('REV_ABSC_YN', None) in ['-1', '(1)'] revocation_for_technical = row.get('REV_TECH_YN', None) in ['-1', '(1)'] def _get_ncic_codes(): first = row.get('NEW_OFF', None) second = row.get('NEW_OFF2', None) third = row.get('NEW_OFF3', None) return [code for code in [first, second, third] if code] violation_types = [] violation_type = None if revocation_for_new_offense: violation_type = StateSupervisionViolationType.FELONY.value violation_types.append(violation_type) ncic_codes = _get_ncic_codes() violent_flags = [ncic.get_is_violent(code) for code in ncic_codes] violation.is_violent = str(any(violent_flags)) elif revocation_for_absconsion: violation_type = StateSupervisionViolationType.ABSCONDED.value violation_types.append(violation_type) elif revocation_for_technical: violation_type = StateSupervisionViolationType.TECHNICAL.value violation_types.append(violation_type) # TODO(2668): Once BQ dashboard for ND is using new pipeline calcs that reference # state_supervision_violation_types (2750), delete the flat violation_type field on # StateSupervisionViolation entirely. violation.violation_type = violation_type for violation_type in violation_types: vt = StateSupervisionViolationTypeEntry(violation_type=violation_type) create_if_not_exists(vt, violation, 'state_supervision_violation_types')