def perform(self, *args, **kwargs): all_vehicles: bool = kwargs.get('all_vehicles') or False is_dry_run: bool = kwargs.get('is_dry_run') or False if all_vehicles: plate_lookups = PlateLookup.get_all_by( count_towards_frequency=True) else: plate_lookups = PlateLookup.get_all_by( boot_eligible=True, count_towards_frequency=True) threads = [] num_threads = 100 chunk_length = math.ceil(len(plate_lookups)/num_threads) for n in range(0, num_threads): chunk_begin = n * chunk_length chunk_plate_lookups = plate_lookups[chunk_begin:(chunk_begin + chunk_length)] print(f'this thread will handle lookups: {[l.id for l in chunk_plate_lookups]}') threads.append(threading.Thread(target=self.update_lookups, args=(chunk_plate_lookups,))) for thread in threads: thread.start() for thread in threads: thread.join() if not is_dry_run: PlateLookup.query.session.commit()
def _query_for_lookup_frequency(self, plate_query: PlateQuery) -> int: """How many times has this plate been queried before?""" return len( PlateLookup.get_all_by(plate=plate_query.plate, plate_types=plate_query.plate_types, state=plate_query.state, count_towards_frequency=True))
def _query_for_previous_lookup( self, plate_query: PlateQuery) -> Optional[PlateLookup]: """ See if we've seen this vehicle before. """ lookups_for_vehicle: List[PlateLookup] = PlateLookup.get_all_by( plate=plate_query.plate, state=plate_query.state, plate_types=plate_query.plate_types, count_towards_frequency=True) if lookups_for_vehicle: lookups_for_vehicle.sort(key=lambda x: x.created_at, reverse=True) return lookups_for_vehicle[0] else: return None
def _perform_plate_lookup( self, campaigns: List[Campaign], plate_query: PlateQuery, unique_identifier: str) -> OpenDataServiceResponse: LOG.debug('Performing lookup for plate.') nyc_open_data_service: OpenDataService = OpenDataService() open_data_response: OpenDataServiceResponse = nyc_open_data_service.look_up_vehicle( plate_query=plate_query) LOG.debug(f'Violation data: {open_data_response}') if open_data_response.success: open_data_plate_lookup: OpenDataServicePlateLookup = open_data_response.data bus_lane_camera_violations = 0 red_light_camera_violations = 0 speed_camera_violations = 0 for violation_type_summary in open_data_plate_lookup.violations: if violation_type_summary['title'] in self.CAMERA_VIOLATIONS: violation_count = violation_type_summary['count'] if violation_type_summary['title'] == 'Bus Lane Violation': bus_lane_camera_violations = violation_count if violation_type_summary[ 'title'] == 'Failure To Stop At Red Light': red_light_camera_violations = violation_count elif violation_type_summary[ 'title'] == 'School Zone Speed Camera Violation': speed_camera_violations = violation_count camera_streak_data: CameraStreakData = open_data_plate_lookup.camera_streak_data # If this came from message, add it to the plate_lookups table. if plate_query.message_source and plate_query.message_id and plate_query.created_at: new_lookup = PlateLookup( boot_eligible=camera_streak_data.max_streak >= 5 if camera_streak_data else False, bus_lane_camera_violations=bus_lane_camera_violations, created_at=plate_query.created_at, message_id=plate_query.message_id, message_source=plate_query.message_source, num_tickets=open_data_plate_lookup.num_violations, plate=plate_query.plate, plate_types=plate_query.plate_types, red_light_camera_violations=red_light_camera_violations, speed_camera_violations=speed_camera_violations, state=plate_query.state, unique_identifier=unique_identifier, username=plate_query.username) # Iterate through included campaigns to tie lookup to each for campaign in campaigns: # insert join record for campaign lookup new_lookup.campaigns.append(campaign) # Insert plate lookup PlateLookup.query.session.add(new_lookup) PlateLookup.query.session.commit() else: LOG.info(f'open data plate lookup failed') return open_data_response
def _query_for_lookup_frequency(self, plate_query: PlateQuery) -> int: return len( PlateLookup.get_all_by(plate=plate_query.plate, plate_types=plate_query.plate_types, state=plate_query.state, count_towards_frequency=True))
def perform(self, *args, **kwargs): is_dry_run: bool = kwargs.get('is_dry_run') or False use_dvaa_thresholds: bool = kwargs.get('use_dvaa_thresholds') or False use_only_visible_tweets: bool = kwargs.get('use_only_visible_tweets') or False tweet_detection_service = TweetDetectionService() tweeter = TrafficViolationsTweeter() eastern = pytz.timezone('US/Eastern') utc = pytz.timezone('UTC') now = datetime.now() # If today is leap day, there were no lookups a year ago today if (now.day == self.LEAP_DAY_DATE and now.month == self.LEAP_DAY_MONTH): return # If today is March 1, and last year was a leap year, show lookups # from the previous February 29. one_year_after_leap_day = True if ( now.day == self.POST_LEAP_DAY_DATE and now.month == self.POST_LEAP_DAY_MONTH and self._is_leap_year(now.year - 1)) else False top_of_the_hour_last_year = now.replace( microsecond=0, minute=0, second=0) - relativedelta(years=1) top_of_the_next_hour_last_year = ( top_of_the_hour_last_year + relativedelta(hours=1)) if use_dvaa_thresholds: threshold_attribute: str = 'boot_eligible_under_dvaa_threshold' else: threshold_attribute: str = 'boot_eligible_under_rdaa_threshold' base_query: list[Tuple[int]] = PlateLookup.query.session.query( func.max(PlateLookup.id).label('most_recent_vehicle_lookup') ).filter( or_( and_(PlateLookup.created_at >= top_of_the_hour_last_year, PlateLookup.created_at < top_of_the_next_hour_last_year, getattr(PlateLookup, threshold_attribute) == True, PlateLookup.count_towards_frequency == True), and_(one_year_after_leap_day, PlateLookup.created_at >= (top_of_the_hour_last_year - relativedelta(days=1)), PlateLookup.created_at < (top_of_the_next_hour_last_year - relativedelta(days=1)), getattr(PlateLookup, threshold_attribute) == True, PlateLookup.count_towards_frequency == True) ) ) if use_only_visible_tweets: base_query = base_query.filter( PlateLookup.message_source == lookup_sources.LookupSource.STATUS.value) recent_plate_lookup_ids = base_query.group_by( PlateLookup.plate, PlateLookup.state ).all() lookup_ids_to_update: list[int] = [id[0] for id in recent_plate_lookup_ids] lookups_to_update: list[PlateLookup] = PlateLookup.get_all_in( id=lookup_ids_to_update) if not lookups_to_update: LOG.debug(f'No vehicles for which to perform retrospective job ' f'between {top_of_the_hour_last_year} and ' f'and {top_of_the_next_hour_last_year}.') for previous_lookup in lookups_to_update: LOG.debug(f'Performing retrospective job for ' f'{L10N.VEHICLE_HASHTAG.format(previous_lookup.state, previous_lookup.plate)} ') plate_query: PlateQuery = PlateQuery(created_at=now, message_source=previous_lookup.message_source, plate=previous_lookup.plate, plate_types=previous_lookup.plate_types, state=previous_lookup.state) nyc_open_data_service: OpenDataService = OpenDataService() data_before_query: OpenDataServiceResponse = nyc_open_data_service.look_up_vehicle( plate_query=plate_query, until=previous_lookup.created_at) lookup_before_query: OpenDataServicePlateLookup = data_before_query.data camera_streak_data_before_query: CameraStreakData = lookup_before_query.camera_streak_data['Mixed'] data_after_query: OpenDataServiceResponse = nyc_open_data_service.look_up_vehicle( plate_query=plate_query, since=previous_lookup.created_at, until=previous_lookup.created_at + relativedelta(years=1)) lookup_after_query: OpenDataServicePlateLookup = data_after_query.data new_bus_lane_camera_violations: Optional[int] = None new_speed_camera_violations: Optional[int] = None new_red_light_camera_violations: Optional[int] = None for violation_type_summary in lookup_after_query.violations: if violation_type_summary['title'] in self.CAMERA_VIOLATIONS: violation_count = violation_type_summary['count'] if violation_type_summary['title'] == 'Bus Lane Violation': new_bus_lane_camera_violations = violation_count if violation_type_summary['title'] == 'Failure To Stop At Red Light': new_red_light_camera_violations = violation_count if violation_type_summary['title'] == 'School Zone Speed Camera Violation': new_speed_camera_violations = violation_count if new_bus_lane_camera_violations is None: new_bus_lane_camera_violations = 0 if new_red_light_camera_violations is None: new_red_light_camera_violations = 0 if new_speed_camera_violations is None: new_speed_camera_violations = 0 new_boot_eligible_violations = (new_red_light_camera_violations + new_speed_camera_violations) if new_boot_eligible_violations > 0: vehicle_hashtag = L10N.VEHICLE_HASHTAG.format( previous_lookup.state, previous_lookup.plate) previous_lookup_created_at = utc.localize( previous_lookup.created_at) previous_lookup_date = previous_lookup_created_at.astimezone(eastern).strftime( L10N.REPEAT_LOOKUP_DATE_FORMAT) previous_lookup_time = previous_lookup_created_at.astimezone(eastern).strftime( L10N.REPEAT_LOOKUP_TIME_FORMAT) red_light_camera_violations_string = ( f'{new_red_light_camera_violations} | Red Light Camera Violations\n' if new_red_light_camera_violations > 0 else '') speed_camera_violations_string = ( f'{new_speed_camera_violations} | Speed Safety Camera Violations\n' if new_speed_camera_violations > 0 else '') reckless_driver_summary_string = ( f'{vehicle_hashtag} was originally ' f'queried on {previous_lookup_date} ' f'at {previous_lookup_time}') # assume we can't link can_link_tweet = False # Where did this come from? if previous_lookup.message_source == lookup_sources.LookupSource.STATUS.value: # Determine if tweet is still visible: if tweet_detection_service.tweet_exists(id=previous_lookup.message_id, username=previous_lookup.username): can_link_tweet = True if can_link_tweet: reckless_driver_summary_string += L10N.PREVIOUS_LOOKUP_STATUS_STRING.format( previous_lookup.username, previous_lookup.username, previous_lookup.message_id) else: reckless_driver_summary_string += '.' if use_only_visible_tweets and not can_link_tweet: # If we're only displaying tweets we can quote tweet, # skip this one since we can'tt. continue reckless_driver_update_string = ( f'From {camera_streak_data_before_query.min_streak_date} to ' f'{camera_streak_data_before_query.max_streak_date}, this vehicle ' f'received {camera_streak_data_before_query.max_streak} camera ' f'violations. Over the past 12 months, this vehicle ' f'received {new_boot_eligible_violations} new camera violation' f"{'' if new_boot_eligible_violations == 1 else 's'}: \n\n" f'{red_light_camera_violations_string}' f'{speed_camera_violations_string}') messages: list[str] = [ reckless_driver_summary_string, reckless_driver_update_string] if not is_dry_run: success: bool = tweeter.send_status( message_parts=messages, on_error_message=( f'Error printing reckless driver update. ' f'Tagging @bdhowald.')) if success: LOG.debug('Reckless driver retrospective job ' 'ran successfully.') else: print(reckless_driver_update_string)
def _perform_plate_lookup( self, campaigns: list[Campaign], plate_query: PlateQuery, unique_identifier: str) -> OpenDataServiceResponse: LOG.debug('Performing lookup for plate.') nyc_open_data_service: OpenDataService = OpenDataService() open_data_response: OpenDataServiceResponse = nyc_open_data_service.look_up_vehicle( plate_query=plate_query) LOG.debug(f'Violation data: {open_data_response}') if open_data_response.success: open_data_plate_lookup: OpenDataServicePlateLookup = open_data_response.data bus_lane_camera_violations = 0 red_light_camera_violations = 0 speed_camera_violations = 0 for violation_type_summary in open_data_plate_lookup.violations: if violation_type_summary['title'] in self.CAMERA_VIOLATIONS: violation_count = violation_type_summary['count'] if violation_type_summary['title'] == 'Bus Lane Violation': bus_lane_camera_violations = violation_count if violation_type_summary[ 'title'] == 'Failure To Stop At Red Light': red_light_camera_violations = violation_count elif violation_type_summary[ 'title'] == 'School Zone Speed Camera Violation': speed_camera_violations = violation_count camera_streak_data: CameraStreakData = open_data_plate_lookup.camera_streak_data # If this came from message, add it to the plate_lookups table. if plate_query.message_source and plate_query.message_id and plate_query.created_at: new_lookup = PlateLookup( boot_eligible_under_dvaa_threshold= (camera_streak_data['Failure to Stop at Red Light']. max_streak >= thresholds. DANGEROUS_VEHICLE_ABATEMENT_ACT_RED_LIGHT_CAMERA_THRESHOLD if camera_streak_data['Failure to Stop at Red Light'] else False or camera_streak_data['School Zone Speed Camera Violation']. max_streak >= thresholds. DANGEROUS_VEHICLE_ABATEMENT_ACT_SCHOOL_ZONE_SPEED_CAMERA_THRESHOLD if camera_streak_data['School Zone Speed Camera Violation'] else False), boot_eligible_under_rdaa_threshold=( camera_streak_data['Mixed'].max_streak >= thresholds.RECKLESS_DRIVER_ACCOUNTABILITY_ACT_THRESHOLD if camera_streak_data['Mixed'] else False), bus_lane_camera_violations=bus_lane_camera_violations, created_at=plate_query.created_at, message_id=plate_query.message_id, message_source=plate_query.message_source, num_tickets=open_data_plate_lookup.num_violations, plate=plate_query.plate, plate_types=plate_query.plate_types, red_light_camera_violations=red_light_camera_violations, responded_to=True, speed_camera_violations=speed_camera_violations, state=plate_query.state, unique_identifier=unique_identifier, username=plate_query.username) # Iterate through included campaigns to tie lookup to each for campaign in campaigns: # insert join record for campaign lookup new_lookup.campaigns.append(campaign) # Insert plate lookup PlateLookup.query.session.add(new_lookup) PlateLookup.query.session.commit() else: LOG.info('open data plate lookup failed') return open_data_response
def test_print_reckless_driver_retrospective( self, mocked_tweet_detection_service_tweet_exists, mocked_traffic_violations_tweeter, mocked_plate_lookup_get_all_in, mocked_open_data_service_look_up_vehicle, can_link_tweet=True, dry_run=False, new_camera_violations_string='10 new camera violations', red_light_camera_tickets_after_previous_lookup=3, red_light_camera_tickets_before_previous_lookup=5, speed_camera_tickets_after_previous_lookup=7, speed_camera_tickets_before_previous_lookup=15, use_dvaa_thresholds: bool = False, use_only_visible_tweets: bool = False): job = RecklessDriverRetrospectiveJob() mocked_tweet_detection_service_tweet_exists.return_value = can_link_tweet plate = 'ABCDEFG' plate_types = 'COM,PAS' state = 'NY' now = datetime.now() previous_message_id = random.randint(1000000000000000000, 2000000000000000000) previous_message_source = 'status' previous_num_tickets = 123 previous_username = '******' rdaa_max_streak = (red_light_camera_tickets_before_previous_lookup + speed_camera_tickets_before_previous_lookup) rdaa_min_streak_date = datetime(2018, 11, 26, 0, 0, 0).strftime('%B %-d, %Y') rdaa_max_streak_date = datetime(2019, 11, 22, 0, 0, 0).strftime('%B %-d, %Y') dvaa_red_light_camera_max_streak = red_light_camera_tickets_before_previous_lookup dvaa_red_light_camera_min_streak_date = datetime( 2018, 9, 14, 0, 0, 0).strftime('%B %-d, %Y') dvaa_red_light_camera_max_streak_date = datetime( 2019, 12, 17, 0, 0, 0).strftime('%B %-d, %Y') dvaa_speed_camera_max_streak = speed_camera_tickets_before_previous_lookup dvaa_speed_camera_min_streak_date = datetime(2018, 11, 26, 0, 0, 0).strftime('%B %-d, %Y') dvaa_speed_camera_max_streak_date = datetime(2019, 11, 22, 0, 0, 0).strftime('%B %-d, %Y') plate_lookup_to_return = PlateLookup( bus_lane_camera_violations=2, created_at=datetime(2020, 1, 3, 14, 37, 12), message_id=previous_message_id, message_source=previous_message_source, num_tickets=previous_num_tickets, plate=plate, plate_types=plate_types, red_light_camera_violations= red_light_camera_tickets_before_previous_lookup, speed_camera_violations=speed_camera_tickets_before_previous_lookup, state=state, username=previous_username) below_dvaa_thresholds = (dvaa_red_light_camera_max_streak < 5 and dvaa_speed_camera_max_streak < 15) new_camera_violations_exist = ( red_light_camera_tickets_after_previous_lookup + speed_camera_tickets_after_previous_lookup) > 0 if use_dvaa_thresholds and below_dvaa_thresholds: # We don't expect a lookup here. expect_response = False plate_lookups = [] elif use_only_visible_tweets and not can_link_tweet: # We don't expect a lookup here. expect_response = False plate_lookups = [plate_lookup_to_return] elif not new_camera_violations_exist: # We don't expect a lookup here. expect_response = False plate_lookups = [plate_lookup_to_return] elif dry_run: # We don't expect a lookup here. expect_response = False plate_lookups = [plate_lookup_to_return] else: expect_response = True plate_lookups = [plate_lookup_to_return] mocked_plate_lookup_get_all_in.return_value = plate_lookups open_data_plate_lookup_before_previous_lookup = OpenDataServicePlateLookup( boroughs=[], camera_streak_data={ 'Failure to Stop at Red Light': CameraStreakData( min_streak_date=dvaa_red_light_camera_min_streak_date, max_streak=dvaa_red_light_camera_max_streak, max_streak_date=dvaa_red_light_camera_max_streak_date), 'Mixed': CameraStreakData(min_streak_date=rdaa_min_streak_date, max_streak=rdaa_max_streak, max_streak_date=rdaa_max_streak_date), 'School Zone Speed Camera Violation': CameraStreakData( min_streak_date=dvaa_speed_camera_min_streak_date, max_streak=dvaa_speed_camera_max_streak, max_streak_date=dvaa_speed_camera_max_streak_date), }, fines=FineData(), num_violations=150, plate=plate, plate_types=plate_types, state=state, violations=[{ 'count': red_light_camera_tickets_before_previous_lookup, 'title': 'Failure To Stop At Red Light' }, { 'count': speed_camera_tickets_before_previous_lookup, 'title': 'School Zone Speed Camera Violation' }], years=[]) open_data_response_before_previous_lookup = OpenDataServiceResponse( data=open_data_plate_lookup_before_previous_lookup, success=True) open_data_plate_lookup_after_previous_lookup = OpenDataServicePlateLookup( boroughs=[], camera_streak_data={ 'Failure to Stop at Red Light': CameraStreakData( min_streak_date=dvaa_red_light_camera_min_streak_date, max_streak=dvaa_red_light_camera_max_streak, max_streak_date=dvaa_red_light_camera_max_streak_date), 'Mixed': CameraStreakData(min_streak_date=rdaa_min_streak_date, max_streak=rdaa_max_streak, max_streak_date=rdaa_max_streak_date), 'School Zone Speed Camera Violation': CameraStreakData( min_streak_date=dvaa_speed_camera_min_streak_date, max_streak=dvaa_speed_camera_max_streak, max_streak_date=dvaa_speed_camera_max_streak_date), }, fines=FineData(), num_violations=150, plate=plate, plate_types=plate_types, state=state, violations=[{ 'count': red_light_camera_tickets_after_previous_lookup, 'title': 'Failure To Stop At Red Light' }, { 'count': speed_camera_tickets_after_previous_lookup, 'title': 'School Zone Speed Camera Violation' }], years=[]) open_data_response_after_previous_lookup = OpenDataServiceResponse( data=open_data_plate_lookup_after_previous_lookup, success=True) mocked_open_data_service_look_up_vehicle.side_effect = [ open_data_response_before_previous_lookup, open_data_response_after_previous_lookup ] can_link_tweet_string = ( f' by @BarackObama: ' f'https://twitter.com/BarackObama/status/{previous_message_id}' if can_link_tweet else '') red_light_camera_tickets_diff_string = ( f'{red_light_camera_tickets_after_previous_lookup} | Red Light Camera Violations\n' if red_light_camera_tickets_after_previous_lookup else '') speed_camera_tickets_diff_string = ( f'{speed_camera_tickets_after_previous_lookup} | Speed Safety Camera Violations\n' if speed_camera_tickets_after_previous_lookup else '') summary_string = ( f'#NY_ABCDEFG was originally queried on January 3, 2020 at 09:37AM' f'{can_link_tweet_string}.') update_string = ( f'From November 26, 2018 to November 22, 2019, this vehicle ' f'received 20 camera violations. Over the past 12 months, this ' f'vehicle received {new_camera_violations_string}: \n\n' f'{red_light_camera_tickets_diff_string}' f'{speed_camera_tickets_diff_string}') job.run(is_dry_run=dry_run, use_only_visible_tweets=use_only_visible_tweets) if expect_response: mocked_traffic_violations_tweeter().send_status.assert_called_with( message_parts=[summary_string, update_string], on_error_message=(f'Error printing reckless driver update. ' f'Tagging @bdhowald.')) else: mocked_traffic_violations_tweeter().send_status.assert_not_called()
def test_print_reckless_driver_retrospective(self, mocked_tweet_detection_service_tweet_exists, mocked_traffic_violations_tweeter, mocked_plate_lookup_get_all_in, mocked_plate_lookup_query, mocked_open_data_service_look_up_vehicle, can_link_tweet=False, dry_run=False, new_camera_violations_string='10 new camera violations', red_light_camera_tickets_after_previous_lookup=3, speed_camera_tickets_after_previous_lookup=7, red_light_camera_tickets_before_previous_lookup=8, speed_camera_tickets_before_previous_lookup=12): job = RecklessDriverRetrospectiveJob() # mocked_plate_lookup_query.session.query( # ).filter().group_by().all.return_value = [1,2,3] mocked_tweet_detection_service_tweet_exists.return_value = can_link_tweet plate = 'ABCDEFG' plate_types = 'COM,PAS' state = 'NY' now = datetime.now() previous_message_id = random.randint(1000000000000000000, 2000000000000000000) previous_message_source = 'status' previous_num_tickets = 123 previous_username = '******' max_streak = 20 min_streak_date = datetime(2018, 11, 26, 0, 0, 0).strftime('%B %-d, %Y') max_streak_date = datetime(2019, 11, 22, 0, 0, 0).strftime('%B %-d, %Y') plate_lookups = [ PlateLookup( bus_lane_camera_violations=2, created_at=datetime(2020, 1, 3, 14, 37, 12), message_id=previous_message_id, message_source=previous_message_source, num_tickets=previous_num_tickets, plate=plate, plate_types=plate_types, red_light_camera_violations=red_light_camera_tickets_before_previous_lookup, speed_camera_violations=speed_camera_tickets_before_previous_lookup, state=state, username=previous_username)] mocked_plate_lookup_get_all_in.return_value = plate_lookups open_data_plate_lookup_before_previous_lookup = OpenDataServicePlateLookup( boroughs=[], camera_streak_data=CameraStreakData( min_streak_date=min_streak_date, max_streak=max_streak, max_streak_date=max_streak_date), fines=FineData(), num_violations=150, plate=plate, plate_types=plate_types, state=state, violations=[ {'count': red_light_camera_tickets_before_previous_lookup, 'title': 'Failure To Stop At Red Light'}, {'count': speed_camera_tickets_before_previous_lookup, 'title': 'School Zone Speed Camera Violation'}], years=[]) open_data_response_before_previous_lookup = OpenDataServiceResponse( data=open_data_plate_lookup_before_previous_lookup, success=True) open_data_plate_lookup_after_previous_lookup = OpenDataServicePlateLookup( boroughs=[], camera_streak_data=CameraStreakData( min_streak_date=min_streak_date, max_streak=max_streak, max_streak_date=max_streak_date), fines=FineData(), num_violations=150, plate=plate, plate_types=plate_types, state=state, violations=[ {'count': red_light_camera_tickets_after_previous_lookup, 'title': 'Failure To Stop At Red Light'}, {'count': speed_camera_tickets_after_previous_lookup, 'title': 'School Zone Speed Camera Violation'}], years=[]) open_data_response_after_previous_lookup = OpenDataServiceResponse( data=open_data_plate_lookup_after_previous_lookup, success=True) mocked_open_data_service_look_up_vehicle.side_effect = [ open_data_response_before_previous_lookup, open_data_response_after_previous_lookup] can_link_tweet_string = ( f' by @BarackObama: ' f'https://twitter.com/BarackObama/status/{previous_message_id}' if can_link_tweet else '') red_light_camera_tickets_diff_string = ( f'{red_light_camera_tickets_after_previous_lookup} | Red Light Camera Violations\n' if red_light_camera_tickets_after_previous_lookup else '') speed_camera_tickets_diff_string = ( f'{speed_camera_tickets_after_previous_lookup} | Speed Safety Camera Violations\n' if speed_camera_tickets_after_previous_lookup else '') summary_string = ( f'#NY_ABCDEFG was originally queried on January 3, 2020 at 09:37AM' f'{can_link_tweet_string}.') update_string = ( f'From November 26, 2018 to November 22, 2019, this vehicle ' f'received 20 camera violations. Over the past 12 months, this ' f'vehicle received {new_camera_violations_string}: \n\n' f'{red_light_camera_tickets_diff_string}' f'{speed_camera_tickets_diff_string}') reckless_string = ( f'Thank you to @bradlander for making the Dangerous Driver ' f'Abatement Act a reality.') job_should_be_run = (red_light_camera_tickets_after_previous_lookup + speed_camera_tickets_after_previous_lookup) > 0 job.run(is_dry_run=dry_run) if not dry_run and job_should_be_run: mocked_traffic_violations_tweeter().send_status.assert_called_with( message_parts=[summary_string, update_string, reckless_string], on_error_message=( f'Error printing reckless driver update. ' f'Tagging @bdhowald.'))