Esempio n. 1
0
def main():

    args = process_args()

    if args.output not in ['text', 'tcx', 'both']:
        raise ValueError('output should be one of "text", "tcx", or "both"')

    data_file_path = expanduser('~') + '/PycharmProjects/first/database/FIRSTregularPlans.xml'
    data = FirstData(xml_path=data_file_path)

    runner = FirstRunner(name=args.runner_name)

    target_time = FirstTime.from_string(args.target_time)
    if args.ref_race_type is not None:
        target_time = data.equivalent_time(time_from=target_time,
                                           race_index_from=data.race_type_index_by_name(args.ref_race_type),
                                           race_index_to=data.race_type_index_by_name(args.race_type))
    if args.race_name is not None:
        race_name = args.race_name
    else:
        race_name = args.race_type

    race_date = datetime.datetime.strptime(args.race_date, '%m/%d/%Y').date()
    race = FirstRace(race_type=data.get_race_type_by_name(args.race_type),
                     name=race_name, race_date=race_date, target_time=target_time)
    ws = get_keyrun_days(args.keyrun_days)

    plan = FirstPlan(name=args.race_name, weekly_schedule=ws, race=race, runner=runner)
    plan.generate_workouts(data=data)

    base_file_name = str(race_date) + race_name
    if args.output == 'text' or args.output == 'both':
        file_name = expanduser('~/Downloads/') + base_file_name + '.txt'
        target = open(file_name, 'w')
        target.write(plan.details(level=3))
        target.close()

    if args.output == 'tcx' or args.output == 'both':
        file_name = expanduser('~/Downloads/') + base_file_name + '.tcx'
        target = open(file_name, 'w')
        target.write(plan.tcx())
        target.close()
Esempio n. 2
0
    def generate_workouts(self, data: FirstData) -> None:
        """
        Generate the training plan

        :param data: the database
        :type data: FirstData
        """

        self.can_generate_workouts()
        if self.workouts is not None and len(self.workouts) > 0:
            del self.workouts[:]

        FirstStepBase.reset_global_id(
        )  # ids are auto incremented. Make sure you start from 0

        index = data.race_type_index_by_name(name=self.race.race_type.name)
        plan_instructions = data.plan_instructions[index]
        time_index = data.pace_index_by_race_time(
            race_time=self.race.target_time,
            race_name=self.race.race_type.name)
        # TODO for now all plans have 3 weekly key-runs. Add a parameter num_weekly_runs to generalize
        num_weekly_runs = 3
        num_weeks = len(plan_instructions.instructions) / num_weekly_runs
        start_date = self.race.race_date - timedelta(weeks=(num_weeks - 1))
        dow = start_date.weekday()
        delta = dow - self.weekly_schedule[0]
        start_date = start_date - timedelta(days=delta)
        delta = self.weekly_schedule[1] - self.weekly_schedule[0]
        second_date = start_date + timedelta(days=delta)
        delta = self.weekly_schedule[2] - self.weekly_schedule[0]
        third_date = start_date + timedelta(days=delta)
        week_dates = [start_date, second_date, third_date]
        weekday_index = 0
        race_pace = self.race.race_pace()
        for wi in plan_instructions.instructions:
            self.workouts.append(
                FirstWorkout.from_instructions(
                    instructions=wi,
                    wo_date=week_dates[weekday_index],
                    data=data,
                    time_index=time_index,
                    race_pace=race_pace))
            week_dates[weekday_index] += timedelta(days=7)
            weekday_index = (weekday_index + 1) % num_weekly_runs
        if self.workouts[-1].workout_date != self.race.race_date:
            self.workouts[-1].workout_date = self.race.race_date
        if self.workouts[-2].workout_date >= self.race.race_date:
            self.workouts[-2].workout_date -= timedelta(days=1)
Esempio n. 3
0
    def test_equivalent_time(self):

        try:  # good path
            data = FirstData(json_path=Config.DATABASE_JSON)
            self.assertEqual(4, len(data.race_types))
            self.assertEqual(1, data.race_type_index_by_name(name='10K'))
            self.assertEqual(2,
                             data.race_type_index_by_name(name='HalfMarathon'))
            self.assertEqual(91, len(data.race_times))
            self.assertEqual(4, len(data.race_times[0]))
            from_time = FirstTime.from_string(string='0:20:13')
            self.assertEqual(
                '1:34:15',
                str(
                    data.equivalent_time(time_from=from_time,
                                         race_index_from=0,
                                         race_index_to=2)))
            from_time = FirstTime.from_string('1:54:32')
            self.assertEqual(
                '4:01:39',
                str(
                    data.equivalent_time(time_from=from_time,
                                         race_index_from=2,
                                         race_index_to=3)))
        except ValueError as vex:
            self.fail(str(vex))
        except IOError as ioex:
            self.fail(str(ioex))

        try:  # bad race name
            _ = data.race_type_index_by_name('lulu')
            self.fail('Should not get here with a bad race type name')
        except ValueError as ex:
            self.assertEqual('Race type lulu not found', str(ex))

        try:  # time not found high
            from_time = FirstTime.from_string('4:49:59')
            _ = data.equivalent_time(time_from=from_time,
                                     race_index_from=2,
                                     race_index_to=0)
            self.fail('Should not get here with time not found')
        except ValueError as ex:
            self.assertEqual('Time is longer than the highest database time',
                             str(ex))

        try:  # time not found low
            from_time = FirstTime.from_string('0:49:59')
            _ = data.equivalent_time(time_from=from_time,
                                     race_index_from=2,
                                     race_index_to=0)
            self.fail('Should not get here with time not found')
        except ValueError as ex:
            self.assertEqual('Time is shorter than the lowest database time',
                             str(ex))

        try:  # index out of range
            _ = data.equivalent_time(time_from=from_time,
                                     race_index_from=-1,
                                     race_index_to=2)
            self.fail('Should not get here with bad index')
        except ValueError as ex:
            self.assertEqual('Race index must be between 0 and 3', str(ex))

        try:  # index out of range
            _ = data.equivalent_time(time_from=from_time,
                                     race_index_from=4,
                                     race_index_to=2)
            self.fail('Should not get here with bad index')
        except ValueError as ex:
            self.assertEqual('Race index must be between 0 and 3', str(ex))

        try:  # index out of range
            _ = data.equivalent_time(time_from=from_time,
                                     race_index_from=1,
                                     race_index_to=-2)
            self.fail('Should not get here with bad index')
        except ValueError as ex:
            self.assertEqual('Race index must be between 0 and 3', str(ex))

        try:  # index out of range
            _ = data.equivalent_time(time_from=from_time,
                                     race_index_from=1,
                                     race_index_to=55)
            self.fail('Should not get here with bad index')
        except ValueError as ex:
            self.assertEqual('Race index must be between 0 and 3', str(ex))

        try:  # bad database file
            _ = FirstData(json_path='lulu')
            self.fail('Should not get here with bad file name')
        except IOError as ioex:
            self.assertEqual("[Errno 2] No such file or directory: 'lulu'",
                             str(ioex))
Esempio n. 4
0
    def test_generate_workouts(self):

        data_file_path = expanduser(
            '~') + '/PycharmProjects/first/database/FIRSTregularPlans.xml'
        data = FirstData(xml_path=data_file_path)
        ws1 = [0, 2, 5]
        target_time = data.equivalent_time(
            time_from=FirstTime(minutes=30),
            race_index_from=data.race_type_index_by_name('5K'),
            race_index_to=data.race_type_index_by_name('Marathon'))
        sf_marathon = FirstRace(
            race_type=data.get_race_type_by_name('Marathon'),
            name='San Francisco Marathon',
            race_date=date(year=2017, month=7, day=23),
            target_time=target_time)
        me = FirstRunner(name='Daniel BenDavid',
                         age=56,
                         gender='m',
                         email='*****@*****.**')
        p1 = FirstPlan(name='My first marathon training plan',
                       weekly_schedule=ws1,
                       race=sf_marathon,
                       runner=me)

        try:  # positive
            p1.generate_workouts(data=data)
            # print p1.details(1)
            self.assertEqual(48, len(p1.workouts))
            wo = p1.workouts[0]
            self.assertEqual('Week 1 Keyrun 1', wo.name)
            self.assertEqual(3, len(wo.steps))
            step = wo.steps[0]
            self.assertEqual('warmup', step.name)
            self.assertEqual(0, step.step_id)
            self.assertEqual('time', step.get_duration_type())
            self.assertEqual('0:15:00', str(step.time))
            self.assertEqual('0:11:31 min per mile', str(step.pace))

            step = wo.steps[1]
            self.assertEqual('repeat X 3', step.name)
            self.assertEqual(1, step.step_id)
            self.assertEqual(3, step.repeat)  # repeat
            self.assertEqual(2, len(step.steps))
            substep = step.steps[0]
            self.assertEqual('1600m', substep.name)
            self.assertEqual(2, substep.step_id)
            self.assertEqual('distance', substep.get_duration_type())
            self.assertEqual('1600.0 m', str(substep.distance))
            self.assertEqual('0:09:26 min per mile', str(substep.pace))
            substep = step.steps[1]
            self.assertEqual('200 m@RI', substep.name)
            self.assertEqual(3, substep.step_id)
            self.assertEqual('distance', substep.get_duration_type())
            self.assertEqual('200.0 m', str(substep.distance))
            self.assertEqual('0:11:31 min per mile', str(substep.pace))

            step = wo.steps[2]
            self.assertEqual('cooldown', step.name)
            self.assertEqual(4, step.step_id)
            self.assertEqual('time', step.get_duration_type())
            self.assertEqual('0:10:00', str(step.time))
            self.assertEqual('0:11:31 min per mile', str(step.pace))

            file_name = expanduser(
                '~/PycharmProjects/first/database/cmp_plan_marathon.tcx')
            # to_file = open(file_name, 'w')
            # to_file.write(p1.tcx())
            # to_file.close()
            from_file = open(file_name)
            cmp_string = from_file.read()
            from_file.close()
            self.assertEqual(cmp_string, p1.tcx())

        except ValueError as vex:
            self.fail(str(vex))
        except TypeError as tex:
            self.fail(str(tex))

        ws1 = [0, 3, 6]
        target_time = data.equivalent_time(
            time_from=FirstTime(minutes=22, seconds=36),
            race_index_from=data.race_type_index_by_name('5K'),
            race_index_to=data.race_type_index_by_name('HalfMarathon'))
        sf_half_marathon = FirstRace(
            race_type=data.get_race_type_by_name('HalfMarathon'),
            name='San Francisco Marathon',
            race_date=date(year=2017, month=7, day=23),
            target_time=target_time)
        me = FirstRunner(name='Daniel BenDavid',
                         age=56,
                         gender='m',
                         email='*****@*****.**')
        p2 = FirstPlan(name='San Francisco half-marathon training plan',
                       weekly_schedule=ws1,
                       race=sf_half_marathon,
                       runner=me)

        try:  # positive
            p2.generate_workouts(data=data)
            # print p2.details(1)
            # print p2.details(2)

            file_name = expanduser(
                '~/PycharmProjects/first/database/cmp_plan_half_marathon.tcx')
            # to_file = open(file_name, 'w')
            # $ to_file.write(p2.tcx())
            # to_file.close()
            from_file = open(file_name)
            cmp_string = from_file.read()
            from_file.close()
            self.assertEqual(cmp_string, p2.tcx())

        except ValueError as vex:
            self.fail(str(vex))
        except TypeError as tex:
            self.fail(str(tex))
Esempio n. 5
0
    def test_generate_workouts(self):

        data = FirstData(json_path=Config.DATABASE_JSON)
        ws1 = [0, 2, 5]
        target_time = data.equivalent_time(time_from=FirstTime(minutes=30),
                                           race_index_from=data.race_type_index_by_name('5K'),
                                           race_index_to=data.race_type_index_by_name('Marathon'))
        sf_marathon = FirstRace(race_type=data.get_race_type_by_name('Marathon'),
                                name='San Francisco Marathon',
                                race_date=date(year=2017, month=7, day=23),
                                target_time=target_time)
        me = FirstRunner(name='Daniel BenDavid', age=56, gender='m', email='*****@*****.**')
        p1 = FirstPlan(name='My first marathon training plan', weekly_schedule=ws1, race=sf_marathon, runner=me)

        try:  # positive
            p1.generate_workouts(data=data)
            self.assertEqual(48, len(p1.workouts))
            wo = p1.workouts[0]
            self.assertEqual('Week 1 Keyrun 1', wo.name)
            self.assertEqual(3, len(wo.steps))
            step = wo.steps[0]
            self.assertEqual('warmup', step.name)
            self.assertEqual(0, step.step_id)
            self.assertEqual('time', step.get_duration_type())
            self.assertEqual('0:15:00', str(step.time))
            self.assertEqual('0:11:31 min per mile', str(step.pace))

            step = wo.steps[1]
            self.assertEqual('repeat X 3', step.name)
            self.assertEqual(1, step.step_id)
            self.assertEqual(3, step.repeat)  # repeat
            self.assertEqual(2, len(step.steps))
            substep = step.steps[0]
            self.assertEqual('1600m', substep.name)
            self.assertEqual(2, substep.step_id)
            self.assertEqual('distance', substep.get_duration_type())
            self.assertEqual('1600.0 m', str(substep.distance))
            self.assertEqual('0:09:26 min per mile', str(substep.pace))
            substep = step.steps[1]
            self.assertEqual('200 m@RI', substep.name)
            self.assertEqual(3, substep.step_id)
            self.assertEqual('distance', substep.get_duration_type())
            self.assertEqual('200.0 m', str(substep.distance))
            self.assertEqual('0:11:31 min per mile', str(substep.pace))

            step = wo.steps[2]
            self.assertEqual('cooldown', step.name)
            self.assertEqual(4, step.step_id)
            self.assertEqual('time', step.get_duration_type())
            self.assertEqual('0:10:00', str(step.time))
            self.assertEqual('0:11:31 min per mile', str(step.pace))

            file_name = 'cmp_plan_marathon.tcx'
            with open('{}/{}'.format(Config.TEST_RESOURCE_DIR, file_name), 'r') as from_file:
                cmp_string = from_file.read()
                self.assertEqual(cmp_string, p1.tcx())
            file_name = 'cmp_plan_marathon.json'
            with open('{}/{}'.format(Config.TEST_RESOURCE_DIR, file_name), 'r') as from_file:
                cmp_json = json.load(from_file)
                self.assertEqual(cmp_json, p1.to_json())
            file_name = 'cmp_plan_marathon.html'
            with open('{}/{}'.format(Config.TEST_RESOURCE_DIR, file_name), 'r') as from_file:
                cmp_html = from_file.read()
                self.assertEqual(cmp_html, p1.to_html())

        except ValueError as vex:
            self.fail(str(vex))
        except TypeError as tex:
            self.fail(str(tex))

        ws1 = [0, 3, 6]
        target_time = data.equivalent_time(time_from=FirstTime(minutes=22, seconds=36),
                                           race_index_from=data.race_type_index_by_name('5K'),
                                           race_index_to=data.race_type_index_by_name('HalfMarathon'))
        sf_half_marathon = FirstRace(race_type=data.get_race_type_by_name('HalfMarathon'),
                                     name='San Francisco Marathon',
                                     race_date=date(year=2017, month=7, day=23),
                                     target_time=target_time)
        me = FirstRunner(name='Daniel BenDavid', age=56, gender='m', email='*****@*****.**')
        p2 = FirstPlan(name='San Francisco half-marathon training plan', weekly_schedule=ws1,
                       race=sf_half_marathon, runner=me)

        try:  # positive
            p2.generate_workouts(data=data)

            file_name = 'cmp_plan_half_marathon.tcx'
            from_file = open('{}/{}'.format(Config.TEST_RESOURCE_DIR, file_name))
            cmp_string = from_file.read()
            from_file.close()
            self.assertEqual(cmp_string, p2.tcx())

        except ValueError as vex:
            self.fail(str(vex))
        except TypeError as tex:
            self.fail(str(tex))
Esempio n. 6
0
def main():

    args = process_args()

    if 'text' not in args.output and 'tcx' not in args.output and \
            'json' not in args.output and 'html' not in args.output:
        raise ValueError(
            'Unknown output formats (). Available text, tcx, html, and json'.
            format(args.output))

    data = FirstData(json_path=Config.DATABASE_JSON)

    runner = FirstRunner(name=args.runner_name)

    target_time = FirstTime.from_string(string=args.target_time)
    if args.ref_race_type is not None:
        target_time = data.equivalent_time(
            time_from=target_time,
            race_index_from=data.race_type_index_by_name(
                name=args.ref_race_type),
            race_index_to=data.race_type_index_by_name(name=args.race_type))
    if args.race_name is not None:
        race_name = args.race_name
    else:
        race_name = args.race_type

    race_date = datetime.datetime.strptime(args.race_date, '%m/%d/%Y').date()
    race = FirstRace(race_type=data.get_race_type_by_name(name=args.race_type),
                     name=race_name,
                     race_date=race_date,
                     target_time=target_time)
    ws = get_keyrun_days(user_string=args.keyrun_days)

    plan = FirstPlan(name=args.race_name,
                     weekly_schedule=ws,
                     race=race,
                     runner=runner)
    plan.generate_workouts(data=data)

    base_file_name = str(race_date) + race_name
    if 'text' in args.output:
        file_name = '{}/{}.{}'.format(Config.DOWNLOADS_DIR, base_file_name,
                                      'txt')
        target = open(file_name, 'w')
        target.write(plan.details(level=3))
        target.close()

    if 'tcx' in args.output:
        file_name = '{}/{}.{}'.format(Config.DOWNLOADS_DIR, base_file_name,
                                      'tcx')
        target = open(file_name, 'w')
        target.write(plan.tcx())
        target.close()

    if 'json' in args.output:
        file_name = '{}/{}.{}'.format(Config.DOWNLOADS_DIR, base_file_name,
                                      'json')
        target = open(file_name, 'w')
        target.write(json.dumps(plan.to_json(args.length_unit)))
        target.close()

    if 'html' in args.output:
        file_name = '{}/{}.{}'.format(Config.DOWNLOADS_DIR, base_file_name,
                                      'html')
        target = open(file_name, 'w')
        target.write(plan.to_html(args.length_unit))
        target.close()
Esempio n. 7
0
    def test_equivalent_time(self):

        data_file_path = expanduser(
            '~') + '/PycharmProjects/first/database/FIRSTregularPlans.xml'
        try:  # good path
            data = FirstData(xml_path=data_file_path)
            self.assertEqual(4, len(data.race_types))
            self.assertEqual(1, data.race_type_index_by_name('10K'))
            self.assertEqual(2, data.race_type_index_by_name('HalfMarathon'))
            self.assertEqual(91, len(data.race_times))
            self.assertEqual(4, len(data.race_times[0]))
            from_time = FirstTime.from_string('0:20:13')
            self.assertEqual(
                '1:34:15',
                str(
                    data.equivalent_time(time_from=from_time,
                                         race_index_from=0,
                                         race_index_to=2)))
            from_time = FirstTime.from_string('1:54:32')
            self.assertEqual(
                '4:01:39',
                str(
                    data.equivalent_time(time_from=from_time,
                                         race_index_from=2,
                                         race_index_to=3)))
        except ValueError as vex:
            self.fail(str(vex))
        except IOError as ioex:
            self.fail(str(ioex))

        try:  # bad race name
            index = data.race_type_index_by_name('lulu')
            self.fail('Should not get here with a bad race type name')
        except ValueError as ex:
            self.assertEqual(
                'FirstSegment.race_type_index_by_name - Race type lulu not found',
                str(ex))

        try:  # time not found high
            from_time = FirstTime.from_string('4:49:59')
            equivalent_time = data.equivalent_time(time_from=from_time,
                                                   race_index_from=2,
                                                   race_index_to=0)
            self.fail('Should not get here with time not found')
        except ValueError as ex:
            self.assertEqual(
                'FirstData.equivalent_time - time is longer than the highest database time',
                str(ex))

        try:  # time not found low
            from_time = FirstTime.from_string('0:49:59')
            equivalent_time = data.equivalent_time(time_from=from_time,
                                                   race_index_from=2,
                                                   race_index_to=0)
            self.fail('Should not get here with time not found')
        except ValueError as ex:
            self.assertEqual(
                'FirstData.equivalent_time - time is shorter than the lowest database time',
                str(ex))

        try:  # bad time type
            equivalent_time = data.equivalent_time(time_from='abc',
                                                   race_index_from=0,
                                                   race_index_to=1)
            self.fail('Should not get here with bad time type')
        except TypeError as ex:
            self.assertEqual(
                'FirstData.equivalent_time - time_from must be an instance of FirstTime',
                str(ex))

        try:  # bad index type
            equivalent_time = data.equivalent_time(time_from=from_time,
                                                   race_index_from='abc',
                                                   race_index_to=2)
            self.fail('Should not get here with bad index')
        except TypeError as ex:
            self.assertEqual(
                'FirstData.equivalent_time - race_index_from must be an int',
                str(ex))

        try:  # bad index type
            equivalent_time = data.equivalent_time(time_from=from_time,
                                                   race_index_from=0,
                                                   race_index_to='abc')
            self.fail('Should not get here with bad index')
        except TypeError as ex:
            self.assertEqual(
                'FirstData.equivalent_time - race_index_to must be an int',
                str(ex))

        try:  # index out of range
            equivalent_time = data.equivalent_time(time_from=from_time,
                                                   race_index_from=-1,
                                                   race_index_to=2)
            self.fail('Should not get here with bad index')
        except ValueError as ex:
            self.assertEqual(
                'FirstData.equivalent_time - race index must be between 0 and 3',
                str(ex))

        try:  # index out of range
            equivalent_time = data.equivalent_time(time_from=from_time,
                                                   race_index_from=4,
                                                   race_index_to=2)
            self.fail('Should not get here with bad index')
        except ValueError as ex:
            self.assertEqual(
                'FirstData.equivalent_time - race index must be between 0 and 3',
                str(ex))

        try:  # index out of range
            equivalent_time = data.equivalent_time(time_from=from_time,
                                                   race_index_from=1,
                                                   race_index_to=-2)
            self.fail('Should not get here with bad index')
        except ValueError as ex:
            self.assertEqual(
                'FirstData.equivalent_time - race index must be between 0 and 3',
                str(ex))

        try:  # index out of range
            equivalent_time = data.equivalent_time(time_from=from_time,
                                                   race_index_from=1,
                                                   race_index_to=55)
            self.fail('Should not get here with bad index')
        except ValueError as ex:
            self.assertEqual(
                'FirstData.equivalent_time - race index must be between 0 and 3',
                str(ex))

        try:  # bad database file
            bad_data = FirstData(xml_path='lulu')
            self.fail('Should not get here with bad file name')
        except IOError as ioex:
            self.assertEqual("[Errno 2] No such file or directory: 'lulu'",
                             str(ioex))