def test_move_activity_at_end_of_plan_updates_leg(): plan = Plan('a') plan.add(Activity(1, 'home', area='a')) plan.add(Leg(1)) plan.add(Activity(2, 'shop', area='b')) plan.move_activity(2) assert plan[1].end_location == 'a'
def test_move_activity_at_start_of_plan_updates_leg(): plan = Plan('a') plan.add(Activity(1, 'shop', 'b')) plan.add(Leg(1)) plan.add(Activity(2, 'home', 'a')) plan.move_activity(0) assert plan[1].start_location == 'a'
def test_activity_tours_segments_home_to_home_looped_plan(activities_and_tour): plan = Plan(1) for i in range(len(activities_and_tour['activities']) - 1): plan.add(activities_and_tour['activities'][i]) plan.add(Leg(1)) plan.add(activities_and_tour['activities'][-1]) assert plan.activity_tours() == activities_and_tour['tours']
def test_finalise(): plan = Plan() act = Activity(1, 'home', 1, start_time=mtdt(0)) plan.add(act) leg = Leg(1, 'car', start_area=1, end_area=2, start_time=mtdt(900), end_time=mtdt(930)) plan.add(leg) act = Activity(2, 'work', 1, start_time=mtdt(930)) plan.add(act) plan.finalise() assert plan.day[0].end_time == mtdt(900) assert plan.day[-1].end_time == END_OF_DAY
def test_duration(): plan = Plan() act = Activity(1, 'home', 1, start_time=mtdt(0)) plan.add(act) leg = Leg(1, 'car', start_area=1, end_area=2, start_time=mtdt(900), end_time=mtdt(930)) plan.add(leg) act = Activity(2, 'work', 1, start_time=mtdt(930)) plan.add(act) plan.finalise() assert plan.day[0].duration == timedelta(minutes=900) assert plan.day[1].duration == timedelta(minutes=30) assert plan.day[-1].duration == timedelta(seconds=(24*60-930)*60)
def test_reverse_iter(): plan = Plan() act = Activity(1, 'home', 1, start_time=mtdt(0)) plan.add(act) leg = Leg(1, 'car', start_area=1, end_area=2, start_time=mtdt(900), end_time=mtdt(930)) plan.add(leg) act = Activity(2, 'work', 1, start_time=mtdt(930)) plan.add(act) idxs = list(i for i, c in plan.reversed()) assert idxs == [2,1,0]
def test_matching_activity_tours_delegates_to_plan_activity_tours( mocker, plain_filter): mocker.patch.object(Plan, 'activity_tours') MoveActivityTourToHomeLocation(['']).matching_activity_tours( Plan(1), plain_filter) Plan.activity_tours.assert_called_once()
def test_person_add_leg_leg_raise_error(): plan = Plan() act = Activity(1, 'home', 1) plan.add(act) leg = Leg(1, 'car', start_area=1, end_area=2) plan.add(leg) leg = Leg(2, 'car', start_area=2, end_area=1) with pytest.raises(PAMSequenceValidationError): plan.add(leg)
def test_activity_tours_segments_home_to_other_act_nonlooped_plan( activities_and_tour): plan = Plan(1) for i in range(len(activities_and_tour['activities'])): plan.add(activities_and_tour['activities'][i]) plan.add(Leg(1)) other_act = Activity(8, 'other', 'e') plan.add(other_act) assert plan[0].act != plan[-1].act assert plan.activity_tours( ) == activities_and_tour['tours'] + [[other_act]]
def test_matching_activity_tours_matches_one_tour(mocker, activity_tours, plain_filter): mocker.patch.object(Plan, 'activity_tours', return_value=activity_tours) mocker.patch.object(MoveActivityTourToHomeLocation, 'tour_matches_activities', side_effect=[True, False]) matching_tours = MoveActivityTourToHomeLocation( ['']).matching_activity_tours(Plan(1), plain_filter) assert matching_tours == [activity_tours[0]]
def test_matching_activity_tours_delegates_to_tour_matches_activities( mocker, activity_tours, plain_filter): mocker.patch.object(Plan, 'activity_tours', return_value=[activity_tours[0]]) mocker.patch.object(MoveActivityTourToHomeLocation, 'tour_matches_activities') MoveActivityTourToHomeLocation(['']).matching_activity_tours( Plan(1), plain_filter) MoveActivityTourToHomeLocation.tour_matches_activities.assert_called_once_with( activity_tours[0], plain_filter)
def test_person_add_activity_activity_raise_error(): plan = Plan() act = Activity(1, 'home', 1) plan.add(act) act = Activity(2, 'work', 1) with pytest.raises(PAMSequenceValidationError): plan.add(act)
def test_person_add_leg(): plan = Plan() act = Activity(1, 'home', 1) plan.add(act) leg = Leg(1, 'car', start_area=1, end_area=2) plan.add(leg) assert len(plan.day) == 2
def test_fix_time_consistency(): plan = Plan() plan.add( Activity(seq=1, act='home', area='A', start_time=mtdt(0), end_time=mtdt(600))) plan.add( Leg(seq=2, mode='car', start_area='A', end_area='B', start_time=mtdt(610), end_time=mtdt(620))) plan.add( Activity(seq=3, act='work', area='B', start_time=mtdt(620), end_time=END_OF_DAY)) plan.fix_time_consistency() assert plan[1].start_time == mtdt(600)
def test_return_first_act_as_home_act_if_missing(): plan = Plan() plan.add( Activity(seq=1, act='work', area='A', start_time=mtdt(0), end_time=mtdt(600))) plan.add( Leg(seq=2, mode='car', start_area='A', end_area='B', start_time=mtdt(600), end_time=mtdt(620))) plan.add( Activity(seq=3, act='shop', area='B', start_time=mtdt(620), end_time=mtdt(1200))) assert plan.home == 'A'
def test_compare_plans_not_equal_types(): plana = Plan() plana.add( Activity(seq=1, act='work', area='A', start_time=mtdt(0), end_time=mtdt(600))) plana.add( Leg(seq=2, mode='car', start_area='A', end_area='B', start_time=mtdt(600), end_time=mtdt(620))) plana.add( Activity(seq=3, act='shop', area='B', start_time=mtdt(620), end_time=mtdt(1200))) with pytest.raises(UserWarning): assert not plana == None
def test_mode_and_activity_classes(): plan = Plan() plan.add( Activity(seq=1, act='home', area='A', start_time=mtdt(0), end_time=mtdt(600))) plan.add( Leg(seq=2, mode='car', start_area='A', end_area='B', start_time=mtdt(600), end_time=mtdt(620))) plan.add( Activity(seq=3, act='work', area='B', start_time=mtdt(620), end_time=mtdt(1200))) assert plan.activity_classes == set(['home', 'work']) assert plan.mode_classes == set(['car'])
def test_person_add_leg_first_raise_error(): plan = Plan() leg = Leg(1, 'car', start_area=1, end_area=2) with pytest.raises(PAMSequenceValidationError): plan.add(leg)
class Person: logger = logging.getLogger(__name__) def __init__(self, pid, freq=1, attributes=None, home_area=None): self.pid = str(pid) self.freq = freq self.attributes = attributes self.plan = Plan(home_area=home_area) self.home_area = home_area @property def home(self): if self.plan: return self.plan.home @property def activities(self): if self.plan: for act in self.plan.activities: yield act @property def legs(self): if self.plan: for leg in self.plan.legs: yield leg @property def length(self): return len(self.plan) def __len__(self): return self.length def __getitem__(self, val): return self.plan[val] def __iter__(self): for component in self.plan: yield component @property def has_valid_plan(self): """ Check sequence of Activities and Legs. :return: True """ return self.plan.is_valid @property def closed_plan(self): """ Check if plan starts and stops at the same facility (based on activity and location) :return: Bool """ return self.plan.closed @property def first_activity(self): return self.plan.first @property def home_based(self): return self.plan.home_based def add(self, p): """ Safely add a new component to the plan. :param p: :return: """ self.plan.add(p) def finalise(self): """ Add activity end times based on start time of next activity. """ self.plan.finalise() def clear_plan(self): self.plan.clear() def print(self): print(self) print(self.attributes) self.plan.print() def plot(self): plot_person(self) def __str__(self): return f"Person: {self.pid}" def remove_activity(self, seq): """ Remove an activity from plan at given seq. Check for wrapped removal. Return (adjusted) idx of previous and subsequent activities as a tuple :param seq: :return: tuple """ return self.plan.remove_activity(seq) def move_activity(self, seq, default='home'): """ Move an activity from plan at given seq to default location :param seq: :param default: 'home' or pam.activity.Location :return: None """ return self.plan.move_activity(seq, default) def fill_plan(self, p_idx, s_idx, default='home'): """ Fill a plan after Activity has been removed. :param p_idx: location of previous Activity :param s_idx: location of subsequent Activity :param default: :return: bool """ return self.plan.fill_plan(p_idx, s_idx, default=default) def stay_at_home(self): self.plan.stay_at_home() def pickle(self, path): with open(path, 'wb') as file: pickle.dump(self, file)
def test_move_activity_with_different_default_updates_legs(): plan = Plan('a') plan.add(Activity(1, 'home', area='a')) plan.add(Leg(1)) plan.add(Activity(2, 'shop', area='b')) plan.add(Leg(2)) plan.add(Activity(3, 'home', area='a')) new_loc = Location(area='heyooo') plan.move_activity(2, default=new_loc) assert plan[1].end_location == new_loc assert plan[3].start_location == new_loc
def test_get_component(): plan = Plan() plan.add( Activity(seq=1, act='home', area='A', start_time=mtdt(0), end_time=mtdt(600))) plan.add( Leg(seq=2, mode='car', start_area='A', end_area='B', start_time=mtdt(600), end_time=mtdt(620))) plan.add( Activity(seq=3, act='work', area='B', start_time=mtdt(620), end_time=mtdt(1200))) assert plan.get(0).act == 'home' assert plan.get(4) is None assert plan.get(4, '1') == '1'
def test_mode_shift_single_tour(): plan = Plan('a') plan.add(Activity(1, 'home', 'a', start_time=mtdt(0), end_time=mtdt(60))) plan.add(Leg(1, mode='car', start_time=mtdt(60), end_time=mtdt(90))) plan.add(Activity(2, 'shop', 'b', start_time=mtdt(90), end_time=mtdt(500))) plan.add(Leg(2, mode='car', start_time=mtdt(500), end_time=mtdt(400))) plan.add( Activity(3, 'home', 'a', start_time=mtdt(400), end_time=mtdt(24 * 60 - 1))) plan.mode_shift(1, 'pt') assert [leg.mode for leg in plan.legs] == ['pt', 'pt']
def test_compare_plans_not_equal(): plana = Plan() plana.add( Activity(seq=1, act='work', area='A', start_time=mtdt(0), end_time=mtdt(600))) plana.add( Leg(seq=2, mode='car', start_area='A', end_area='B', start_time=mtdt(600), end_time=mtdt(620))) plana.add( Activity(seq=3, act='shop', area='B', start_time=mtdt(620), end_time=mtdt(1200))) planb = Plan() planb.add( Activity(seq=1, act='work', area='A', start_time=mtdt(0), end_time=mtdt(800))) planb.add( Leg(seq=2, mode='car', start_area='A', end_area='B', start_time=mtdt(800), end_time=mtdt(620))) planb.add( Activity(seq=3, act='shop', area='B', start_time=mtdt(620), end_time=mtdt(1200))) assert not plana == planb
def test_mode_shift_two_tours_third_leg(): plan = Plan('a') plan.add(Activity(1, 'home', 'a', start_time=mtdt(0), end_time=mtdt(60))) plan.add(Leg(1, mode='car', start_time=mtdt(60), end_time=mtdt(90))) plan.add(Activity(2, 'shop', 'b', start_time=mtdt(90), end_time=mtdt(500))) plan.add(Leg(2, mode='car', start_time=mtdt(500), end_time=mtdt(400))) plan.add(Activity(3, 'home', 'a', start_time=mtdt(400), end_time=mtdt(860))) plan.add(Leg(3, mode='car', start_time=mtdt(860), end_time=mtdt(900))) plan.add(Activity(4, 'work', 'a', start_time=mtdt(920), end_time=mtdt(930))) plan.add(Leg(4, mode='car', start_time=mtdt(930), end_time=mtdt(1000))) plan.add( Activity(5, 'home', 'a', start_time=mtdt(1000), end_time=mtdt(24 * 60 - 1))) plan.mode_shift(5, 'pt') assert [leg.mode for leg in plan.legs] == ['car', 'car', 'pt', 'pt']
def test_add_wrong_type(): plan = Plan() with pytest.raises(UserWarning): plan.add(None)
def test_mode_shift_multiple_tours(): plan = Plan('a') plan.add(Activity(1, 'home', 'a', start_time=mtdt(0), end_time=mtdt(60))) plan.add(Leg(1, mode='car', start_time=mtdt(60), end_time=mtdt(90))) plan.add(Activity(2, 'work', 'b', start_time=mtdt(90), end_time=mtdt(500))) plan.add(Leg(2, mode='car', start_time=mtdt(500), end_time=mtdt(400))) plan.add(Activity(3, 'shop', 'b', start_time=mtdt(400), end_time=mtdt(450))) plan.add(Leg(3, mode='car', start_time=mtdt(450), end_time=mtdt(600))) plan.add(Activity(4, 'work', 'b', start_time=mtdt(600), end_time=mtdt(660))) plan.add(Leg(4, mode='car', start_time=mtdt(660), end_time=mtdt(800))) plan.add(Activity(5, 'home', 'a', start_time=mtdt(830), end_time=mtdt(860))) plan.add(Leg(5, mode='walk', start_time=mtdt(860), end_time=mtdt(900))) plan.add( Activity(6, 'other', 'a', start_time=mtdt(900), end_time=mtdt(920))) plan.add(Leg(6, mode='walk', start_time=mtdt(920), end_time=mtdt(950))) plan.add( Activity(7, 'home', 'a', start_time=mtdt(950), end_time=mtdt(24 * 60 - 1))) plan.mode_shift(5, 'pt') assert [leg.mode for leg in plan.legs] == ['pt', 'pt', 'pt', 'pt', 'walk', 'walk']
def __init__(self, pid, freq=1, attributes=None, home_area=None): self.pid = str(pid) self.freq = freq self.attributes = attributes self.plan = Plan(home_area=home_area) self.home_area = home_area
def test_leg_duration(): plan = Plan('a') plan.add( Activity(seq=1, act='home', area='a', start_time=mtdt(0), end_time=mtdt(60))) plan.add( Leg(seq=1, mode='car', start_area='a', end_area='b', start_time=mtdt(60), end_time=mtdt(90))) plan.add( Activity(seq=2, act='work', area='b', start_time=mtdt(90), end_time=mtdt(120))) plan.add( Leg(seq=2, mode='car', start_area='b', end_area='a', start_time=mtdt(120), end_time=mtdt(180))) plan.add( Activity(seq=3, act='home', area='a', start_time=mtdt(180), end_time=mtdt(24 * 60 - 1))) plan.mode_shift(3, 'rail', mode_speed={ 'car': 37, 'bus': 10, 'walk': 4, 'cycle': 14, 'pt': 23, 'rail': 37 }, update_duration=True) assert [act.duration for act in plan] == [ timedelta(seconds=3603), timedelta(seconds=1800), timedelta(seconds=1800), timedelta(seconds=3600), timedelta(seconds=75597) ]
def test_plan(): plan = Plan() plan.add( Activity( seq=1, act='home', area='a', start_time=mtdt(0), end_time=mtdt(180) ) ) plan.add( Leg( seq=1, mode='car', start_area='a', end_area='b', start_time=mtdt(180), end_time=mtdt(190) ) ) plan.add( Activity( seq=2, act='work', area='b', start_time=mtdt(190), end_time=mtdt(200) ) ) plan.add( Leg( seq=1, mode='car', start_area='b', end_area='a', start_time=mtdt(200), end_time=mtdt(390) ) ) plan.add( Activity( seq=3, act='home', area='b', start_time=mtdt(390), end_time=END_OF_DAY ) ) return plan
def test_person_add_activity(): plan = Plan() act = Activity(1, 'home', 1) plan.add(act) assert len(plan.day) == 1