Ejemplo n.º 1
0
    def test_add_workout(self):

        ws1 = [0, 2, 5]
        rt1 = FirstRaceType(name='Marathon', distance=FirstDistance.from_string('42.195 km'))
        rd1 = date(year=2017, month=7, day=29)
        r1 = FirstRace(name='SFM', race_type=rt1, race_date=rd1)
        rn1 = FirstRunner(name='DBD')
        p1 = FirstPlan(name='My first marathon training plan', weekly_schedule=ws1, race=r1, runner=rn1)

        t_warmup = FirstTime.from_string('0:15:00')
        p_warmup = FirstPace.from_string('0:10:00 min per mile')
        s_warmup = FirstStepBody(name='Warm up', pace=p_warmup, time=t_warmup)

        s_repeat = FirstStepRepeat(name='repeat X 8', repeat=8)
        d_interval = FirstDistance.from_string('400 m')
        p_fast = FirstPace.from_string('0:08:00 min per mile')
        s_fast = FirstStepBody(name='Fast', pace=p_fast, distance=d_interval)
        s_repeat.add_step(s_fast)
        s_slow = FirstStepBody(name='Rest', pace=p_warmup, distance=d_interval)
        s_repeat.add_step(s_slow)

        t_cooldown = FirstTime.from_string('0:10:00')
        s_cooldown = FirstStepBody(name='Cool down', pace=p_warmup, time=t_cooldown)

        wo = FirstWorkout(name='Week 1 Key-run 1', workout_date=date(year=2017, month=6, day=24))
        wo.add_step(step=s_warmup)
        wo.add_step(step=s_repeat)
        wo.add_step(step=s_cooldown)

        try:  # first workout
            p1.add_workout(workout=wo)
            cmp_string = ('Training Plan:\nName - "My first marathon training plan"\n' +
                          'Workout days: Mon, Wed, Sat\nRace:\n' +
                          '  Name - "SFM" of type Marathon - 42.195 km\nRunner:\n  Name - "DBD"\nWorkouts:\n' +
                          '  "Week 1 Key-run 1"\n    Sat 2017-06-24\n    scheduled\n' +
                          'Total 1 workouts\n')
            self.assertEqual(cmp_string, str(p1))

            file_name = 'cmp_plan2.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_plan2.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_plan2_km.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(output_unit='km'))
            file_name = 'cmp_plan2.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())
            file_name = 'cmp_plan2_km.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(output_unit='km'))
        except TypeError as ex:
            self.fail(str(ex))
Ejemplo n.º 2
0
    def test_from_string(self):

        try:
            distance = FirstDistance.from_string(string='1 mile')
            self.assertEqual('1.0 mile', str(distance))
        except ValueError as ex:
            self.fail(ex)

        try:
            _ = FirstDistance.from_string('onlyonetoken')
            self.fail('from_string is expected to fail with only one token')
        except ValueError as ex:
            self.assertEqual('2 tokens are expected, number and unit, but got "onlyonetoken"', str(ex))

        try:
            _ = FirstDistance.from_string('34t papa')
            self.fail('from_string is expected to fail if the first token is not a number')
        except ValueError as ex:
            message = 'first token is expected to be a number but could not convert string to float: \'34t\''
            self.assertEqual(message, str(ex))

        try:
            _ = FirstDistance.from_string('-35.2 papa')
            self.fail('FirstDistance is expected to fail if the number is negative')
        except ValueError as ex:
            self.assertEqual('-35.2 is not a positive number', str(ex))

        try:
            _ = FirstDistance.from_string('42.2 papa')
            self.fail('FirstDistance is expected to fail for invalid unit')
        except ValueError as ex:
            self.assertEqual('"papa" is not a valid unit', str(ex))
Ejemplo n.º 3
0
    def to_distance(self, time, unit):

        """
        How far you run given duration with this pace
        
        :param time: the duration
        :param unit: the desired unit of the result
        :return: the distance value for this unit
        :rtype: float
        """
        factor = time.total_seconds()/self.time.total_seconds()
        result_distance = FirstDistance(distance=factor, unit=self.length_unit)
        return result_distance.convert_to(unit=unit)
Ejemplo n.º 4
0
    def from_time_distance(cls,
                           time: FirstTime,
                           distance: FirstDistance,
                           unit: str = None):
        """
        Constructor: Initiate FirstPace from time/distance

        :param time:
        :type time: FirstTime
        :param distance:
        :type distance: FirstDistance
        :param unit: length unit
        :type unit: str
        :return: instance to FirstPace
        :rtype: FirstPace
        """
        if unit is None:
            unit = distance.unit
        factor = distance.convert_to(
            unit=unit)  # 400m with unit = mile will become ~0.25
        seconds = time.total_seconds(
        ) / factor  # 2 minutes for 400m will give ~(2*60)/0.25

        return cls(minutes=int(seconds // 60),
                   seconds=round(seconds % 60),
                   length_unit=unit)
Ejemplo n.º 5
0
    def test_race_type(self):

        try:
            race_type = FirstRaceType(
                name='marathon',
                distance=FirstDistance.from_string('26.219 mile'))
            self.assertEqual('marathon - 26.219 mile', str(race_type))
            self.assertEqual(
                {
                    'distance': {
                        'distance': 26.219,
                        'unit': 'mile'
                    },
                    'name': 'marathon'
                }, race_type.to_json())
            self.assertEqual(
                {
                    'distance': {
                        'distance': 42.195390336,
                        'unit': 'km'
                    },
                    'name': 'marathon'
                }, race_type.to_json(output_unit='km'))
            self.assertEqual('26.219 mile', race_type.distance.to_html())
            self.assertEqual('42.195 km',
                             race_type.distance.to_html(output_unit='km'))
        except ValueError as ex:
            self.fail(str(ex))
Ejemplo n.º 6
0
 def test_json_n_html(self):
     try:
         distance = FirstDistance.from_string(string='1 mile')
         self.assertEqual({'distance': 1.0, 'unit': 'mile'}, distance.to_json())
         self.assertEqual({'distance': 1.609344, 'unit': 'km'}, distance.to_json(output_unit='km'))
         self.assertEqual('1.000 mile', distance.to_html())
         self.assertEqual('1.609 km', distance.to_html(output_unit='km'))
     except ValueError as ex:
         self.fail(ex)
Ejemplo n.º 7
0
    def test_from_string(self):

        try:
            d1 = FirstDistance.from_string('1 mile')
            self.assertEqual('1.0 mile', str(d1))
        except ValueError as ex:
            self.fail(ex)

        try:
            d2 = FirstDistance.from_string('onlyonetoken')
            self.fail('from_string is expected to fail with only one token')
        except ValueError as ex:
            self.assertEqual(
                'FirstDistance.from_string - from_string() ' +
                'expects 2 tokens, number and unit, but got "onlyonetoken"',
                str(ex))

        try:
            d3 = FirstDistance.from_string('34t papa')
            self.fail(
                'from_string is expected to fail if the first token is not a number'
            )
        except ValueError as ex:
            message = (
                'FirstDistance.from_string - ' +
                'expects the first token to be a number but invalid literal for float(): 34t'
            )
            self.assertEqual(message, str(ex))

        try:
            d4 = FirstDistance.from_string('-35.2 papa')
            self.fail(
                'FirstDistance is expected to fail if the number is negative')
        except ValueError as ex:
            self.assertEqual(
                'FirstDistance.__init__ - -35.2 is not a positive number',
                str(ex))

        try:
            d5 = FirstDistance.from_string('42.2 papa')
            self.fail('FirstDistance is expected to fail for invalid unit')
        except ValueError as ex:
            self.assertEqual(
                'FirstDistance.__init__ - "papa" is not a valid unit', str(ex))
Ejemplo n.º 8
0
    def __init__(self, name, distance, unit):
        """
        Constructor

        :param name: like Marathon
        :type name: str
        :param distance: distance value
        :type distance: float
        :param unit: length unit
        :type unit: str
        :return: instance of FirstRaceType
        :rtype: FirstRaceType
        """
        where_am_i = 'FirstRace.__init__'
        if not FirstDistance.is_valid_unit(unit):
            raise ValueError(where_am_i +
                             ' - "%1s" is not a valid length unit' % unit)
        self.name = name
        self.distance = FirstDistance(distance=distance, unit=unit)
Ejemplo n.º 9
0
    def to_html(self, output_unit: Union[str, None] = None) -> str:

        if output_unit and output_unit != self.length_unit:
            dist = FirstDistance(1.0, output_unit)
            seconds_time = self.to_time(dist, 'second')
            output_pace = FirstPace(seconds=round(seconds_time),
                                    length_unit=output_unit)
            return '{} min per {}'.format(str(output_pace.time), output_unit)
        else:
            return '{} min per {}'.format(str(self.time), self.length_unit)
Ejemplo n.º 10
0
    def from_instructions(cls, instructions: str, data: FirstData,
                          time_index: int, rp: FirstPace):
        """
        Create a step from an instruction string

        :param instructions: instruction string
        :type instructions: str
        :param data: First database
        :type data: FirstData
        :param time_index: the index in the paces table
        :type time_index: int
        :param rp: race pace
        :type rp: FirstPace
        :return: the step
        :rtype: FirstStep
        """
        segment_name = instructions.split('@')[0]
        increment = None
        pace = None
        duration = None
        try:
            segment = data.segment_by_name(segment_name)
            distance = segment.distance
        except KeyError:
            distance = FirstDistance.from_string(segment_name)
            segment_name = instructions.split('@')[1]
            pace_list = segment_name.split('+')
            segment_name = pace_list[0]
            if len(pace_list) > 1:
                increment = int(pace_list[1])
            else:
                increment = None
            if segment_name == 'RP':  # special case for race-pace
                segment = None
                pace = FirstPace.copy(rp)
            else:
                segment = data.segment_by_name(segment_name)

        if segment is not None:
            if segment.ref_pace_name is not None:
                segment_name = segment.ref_pace_name
            segment_index = data.segment_index_by_name(
                segment_name) + 1  # +1 since the first column is the ref time
            pace = data.segments_paces[time_index][segment_index]
            duration = segment.duration

        if increment is not None:
            pace.increment(increment)
        return cls(name=instructions,
                   pace=pace,
                   time=duration,
                   distance=distance)
Ejemplo n.º 11
0
    def __get_segments_json(self, json_segments: Dict) -> None:

        self.reference_race = json_segments['reference_race']
        index = 0
        for segment_type in json_segments['segment_types']:
            name = segment_type['name']
            type_str = segment_type['type']
            ref_pace = segment_type['ref_pace_name']
            if type_str == 'DISTANCE':
                distance = FirstDistance.from_string(
                    string=segment_type['distance'])
                self.segments.append(FirstSegment(name=name,
                                                  distance=distance))
            elif type_str == 'TIME':
                duration = FirstTime.from_string(string=segment_type['time'])
                self.segments.append(
                    FirstSegment(name=name,
                                 duration=duration,
                                 ref_pace_name=ref_pace))
            else:  # PACE
                self.segments.append(
                    FirstSegment(name=name, ref_pace_name=ref_pace))

            self.segments_lookup[name] = index
            index += 1

        pace_unit = json_segments['pace_unit']
        distance_unit = pace_unit.split()[-1]
        for line in json_segments['paces']:
            items = line.split()
            paces_list = [FirstTime.from_string(items[0])]
            index = 0
            for pace_str in items[1:]:
                time_str = '0:{}'.format(pace_str)
                ref_segment = self.segments[index]
                if ref_segment.get_type() == 'distance':
                    cur_time = FirstTime.from_string(time_str)
                    cur_distance = ref_segment.distance
                    paces_list.append(
                        FirstPace.from_time_distance(time=cur_time,
                                                     distance=cur_distance,
                                                     unit=distance_unit))
                elif ref_segment.get_type() == 'pace':
                    paces_list.append(
                        FirstPace.from_string('{} {}'.format(
                            time_str, pace_unit)))
                else:
                    raise ValueError(
                        'Duration segments have already a reference pace')

                index += 1
            self.segments_paces.append(paces_list)
Ejemplo n.º 12
0
    def test_to_string(self):

        ws1 = [0, 2, 5]
        ws2 = [1, 3, 6]

        try:  # name only
            p1 = FirstPlan(name='My first marathon training plan', weekly_schedule=ws1)
            self.assertEqual('Training Plan:\nName - "My first marathon training plan"\nWorkout days: Mon, Wed, Sat\n',
                             str(p1))

            file_name = 'cmp_plan1.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())
            cmp_json = {"name": "My first marathon training plan",
                        "weekly_schedule": ["mon", "wed", "sat"],
                        "workouts": []}
            self.assertEqual(cmp_json, p1.to_json())
            cmp_html = ('<!DOCTYPE html>\n' +
                        '<html>\n' +
                        '  <head>\n' +
                        '  </head>\n' +
                        '  <body>\n' +
                        '    <h1>Training Plan: My first marathon training plan</h1>\n' +
                        '    <div>\n' +
                        '      <h2>\n' +
                        '        Schedule:\n' +
                        '      </h2>\n' +
                        '    </div>\n' +
                        '  </body>\n' +
                        '</html>')
            self.assertEqual(cmp_html, p1.to_html())
        except TypeError as tex:
            self.fail(str(tex))
        except ValueError as vex:
            self.fail(str(vex))

        rt1 = FirstRaceType(name='Marathon', distance=FirstDistance.from_string('42.195 km'))
        rd1 = date(year=2017, month=7, day=29)
        r1 = FirstRace(name='SFM', race_type=rt1, race_date=rd1)
        rn1 = FirstRunner(name='DBD')

        try:  # all
            p2 = FirstPlan(name='My first marathon training plan', weekly_schedule=ws2, race=r1, runner=rn1)
            cmp_string = ('Training Plan:\nName - "My first marathon training plan"\nWorkout days: Tue, Thu, Sun\n' +
                          'Race:\n  Name - "SFM" of type Marathon - 42.195 km\nRunner:\n  Name - "DBD"\n')
            self.assertEqual(cmp_string, str(p2))
        except TypeError as tex:
            self.fail(str(tex))
        except ValueError as vex:
            self.fail(str(vex))
Ejemplo n.º 13
0
    def meters_per_second_delta(self, delta_in_seconds: int) -> float:
        """
        Convert to speed in m/s for tcx with delta for tolerance

        :param delta_in_seconds:
        :type delta_in_seconds: int
        :return: calculated speed in m/s
        :rtype: float
        """
        seconds = self.time.total_seconds() + delta_in_seconds
        meters = FirstDistance(distance=1.0,
                               unit=self.length_unit).convert_to(unit='m')

        return meters / seconds
Ejemplo n.º 14
0
    def __init__(self,
                 name,
                 age=None,
                 gender=None,
                 email=None,
                 length_unit='mile'):
        """
        Constructor

        :param name:
        :type name: str
        :param age: years only
        :type age: int
        :param gender: for now anything
        :type gender: str
        :param email: Should be a valid email address
        :type email: str
        :param length_unit: preferred and valid length unit
        :type length_unit: str
        """
        where_am_i = 'FirstRunner.__init__'
        if not isinstance(name, basestring):
            raise TypeError(where_am_i + ' - name must be a string')
        if age is not None:
            if not isinstance(age, int):
                raise TypeError(where_am_i + ' - age must be an integer')
            if age <= 0:
                raise ValueError(where_am_i + ' - age must be positive')
        if gender is not None:
            if not isinstance(gender, basestring):
                raise TypeError(where_am_i + ' - gender must be a string')
            # for now no limit on gender but if the plan has gender related instructions then we might post a warning
            # when a gender is not recognized by the plan
        if not isinstance(length_unit, basestring):
            raise TypeError(where_am_i +
                            ' - length_unit is expected to be a string')
        if not FirstDistance.is_valid_unit(length_unit):
            raise ValueError(where_am_i + ' - length unit not recognized')

        if FirstUtils.is_internet_on():
            from validate_email import validate_email

            if email is not None and not validate_email(email=email):
                raise ValueError(where_am_i + ' - invalid email address')

        self.name = name
        self.age = age
        self.gender = gender
        self.email = email
        self.length_unit = length_unit
Ejemplo n.º 15
0
    def to_time(self, distance: FirstDistance, unit: str) -> float:
        """
        How much time will take to run a given distance with this pace

        :param distance: the distance
        :type distance: FirstDistance
        :param unit: the desired unit of the result
        :type unit: str
        :return: the time value for this unit
        :rtype: float
        """
        factor = distance.convert_to(unit=self.length_unit)
        seconds = self.time.total_seconds() * factor
        result_time = FirstTime(seconds=round(seconds))
        return result_time.convert_to(unit=unit)
Ejemplo n.º 16
0
    def meters_per_second_delta(self, delta_in_seconds):

        """
        Convert to speed in m/s for tcx with delta for tolerance
        :param delta_in_seconds:
        :type delta_in_seconds: int
        :return:
        """
        where_am_i = 'FirstPace.meters_per_second_delta'
        if not isinstance(delta_in_seconds, int):
            raise ValueError(where_am_i + ' - delta_in_seconds must be an integer')

        seconds = self.time.total_seconds() + delta_in_seconds
        meters = FirstDistance(distance=1.0, unit=self.length_unit).convert_to(unit='m')

        return meters / seconds
Ejemplo n.º 17
0
    def to_json(self, output_unit: Union[str, None] = None) -> Dict:

        if output_unit and output_unit != self.length_unit:
            dist = FirstDistance(1.0, output_unit)
            seconds_time = self.to_time(dist, 'second')
            output_pace = FirstPace(seconds=round(seconds_time),
                                    length_unit=output_unit)
            return {
                'pace': str(output_pace),
                'length_unit': output_unit,
                'time': output_pace.time.to_json()
            }
        else:
            return {
                'pace': str(self),
                'length_unit': self.length_unit,
                'time': self.time.to_json()
            }
Ejemplo n.º 18
0
    def __init__(self, minutes=0, seconds=0, length_unit='mile'):

        """
        Constructor

        :param minutes:
        :type minutes: int
        :param seconds:
        :type seconds: int
        :param length_unit:
        :type length_unit: str
        :return: instance of FirstPace
        :rtype: FirstPace
        """
        where_am_i = 'FirstPace.__init__'
        if not FirstDistance.is_valid_unit(length_unit):
            raise ValueError(where_am_i + ' - "%1s" is not a valid length unit' % length_unit)
        self.time = FirstTime(minutes=minutes, seconds=seconds)
        self.length_unit = length_unit
Ejemplo n.º 19
0
    def __init__(self, json_path: str):
        """
        Constructor

        :return: instance of FirstData
        :rtype: FirstData
        """

        self.race_types = []
        self.race_times = []
        self.segments = []
        self.segments_lookup = {}
        self.reference_race = None
        self.segments_paces = []
        self.plan_instructions = []

        if json_path is not None:
            with open(json_path, 'r') as fd:
                data_dict = json.load(fd)

                self.name = data_dict['name']
                self.note = data_dict['note']

                self.race_types = [
                    FirstRaceType(name=race['name'],
                                  distance=FirstDistance.from_string(
                                      race['distance']))
                    for race in data_dict['races']
                ]
                self.race_times = [[
                    FirstTime.from_string(string=time) for time in times
                ] for times in data_dict['equivalent_times']]
                self.__get_segments_json(json_segments=data_dict['segments'])
                self.plan_instructions = [
                    PlanInstructions(
                        name=plan['name'],
                        race_name=plan['race_name'],
                        instructions=[line for line in plan['instructions']])
                    for plan in data_dict['workout_instructions']
                ]
        else:
            raise ValueError('json_path should point to an existing file')
Ejemplo n.º 20
0
    def from_string(cls, str_input):

        """
        Constructor: Instantiate FirstPace from a string input
        
        :param str_input: format - '0:MM:SS per unit'
        :type str_input: str
        :return: instance of FirstPace
        :rtype: FirstPace
        """
        where_am_i = 'FirstPace.from_string'
        tokens = str_input.split()

        p_time = FirstTime.from_string(tokens[0])  # pass the exception on
        length_unit = tokens[-1]

        if not FirstDistance.is_valid_unit(unit=tokens[-1]):
            raise ValueError(where_am_i + ' - "%1s" is not a valid length unit' % length_unit)

        return cls(minutes=p_time.seconds//60, seconds=p_time.seconds % 60, length_unit=length_unit)
Ejemplo n.º 21
0
    def __init__(self,
                 minutes: int = 0,
                 seconds: int = 0,
                 length_unit: str = 'mile'):
        """
        Constructor

        :param minutes:
        :type minutes: int
        :param seconds:
        :type seconds: int
        :param length_unit:
        :type length_unit: str
        :return: instance of FirstPace
        :rtype: FirstPace
        """
        if not FirstDistance.is_valid_unit(unit=length_unit):
            raise ValueError(
                '"{}" is not a valid length unit'.format(length_unit))
        self.time = FirstTime(minutes=minutes, seconds=seconds)
        self.length_unit = length_unit
Ejemplo n.º 22
0
    def test_convert_to(self):

        try:
            d1 = FirstDistance(distance=5, unit='km')
        except ValueError as ex:
            self.fail(ex)

        try:
            result = d1.convert_to(unit='mm')
            self.fail('convert_to is expected to fail with unknown unit')
        except ValueError as ex:
            self.assertEqual(
                'FirstDistance.convert_to - mm is not a valid unit', str(ex))

        try:
            result = d1.convert_to(unit='km')
            self.assertEqual(5, result)
        except ValueError as ex:
            self.fail(ex)

        try:
            result = d1.convert_to(unit='m')
            self.assertEqual(5000, result)
        except ValueError as ex:
            self.fail(ex)

        try:
            result = d1.convert_to(unit='ft')
            self.assertEqual('16404.20', '{:.2f}'.format(result))
        except ValueError as ex:
            self.fail(ex)

        try:
            result = d1.convert_to(unit='mile')
            self.assertEqual('3.11', '{:.2f}'.format(result))
        except ValueError as ex:
            self.fail(ex)
Ejemplo n.º 23
0
    def test_to_string(self):

        try:
            d1 = FirstDistance(distance=300, unit='mm')
            self.fail(
                'FirstDistance is expected to fail for wrong length unit')
        except ValueError as ex:
            self.assertEqual(
                'FirstDistance.__init__ - "mm" is not a valid unit', str(ex))

        try:
            d1 = FirstDistance(distance=-300, unit='m')
            self.fail('FirstDistance is expected to fail for negative length')
        except ValueError as ex:
            self.assertEqual(
                'FirstDistance.__init__ - -300 is not a positive number',
                str(ex))

        try:
            d1 = FirstDistance(distance=300, unit='m')
            self.assertEqual('300 m', str(d1))
        except ValueError as ex:
            self.fail(ex)

        try:
            d1 = FirstDistance(distance=5, unit='km')
            self.assertEqual('5 km', str(d1))
        except ValueError as ex:
            self.fail(ex)

        try:
            d1 = FirstDistance(distance=26.2, unit='mile')
            self.assertEqual('26.2 mile', str(d1))
        except ValueError as ex:
            self.fail(ex)

        try:
            d1 = FirstDistance(distance=5280, unit='ft')
            self.assertEqual('5280 ft', str(d1))
        except ValueError as ex:
            self.fail(ex)
Ejemplo n.º 24
0
    def test_race(self):

        rt1 = FirstRaceType(name='5K',
                            distance=FirstDistance.from_string('5.0 km'))
        rd1 = date(year=2017, month=7, day=29)
        tt1 = FirstTime.from_string(string='0:25:30')
        tt2 = FirstTime.from_string(string='0:24:34')

        try:  # positive
            race = FirstRace(race_type=rt1,
                             race_date=rd1,
                             name='Martial Cottle Park 5K',
                             target_time=tt1)
            cmp_string = ('Martial Cottle Park 5K of type ' + str(rt1) + '\n' +
                          'On ' + str(rd1) + '\n' + 'Target time - ' +
                          str(tt1) + '\n' + 'Status - scheduled\n')
            self.assertEqual(cmp_string, str(race))
            cmp_json = {
                'Name': 'Martial Cottle Park 5K',
                'race_date': '2017-07-29',
                'race_type': {
                    'distance': {
                        'distance': 5.0,
                        'unit': 'km'
                    },
                    'name': '5K'
                },
                'status': 'scheduled',
                'target_time': {
                    'seconds': 1530,
                    'time': '0:25:30'
                }
            }
            self.assertEqual(cmp_json, race.to_json())
            cmp_json = {
                'Name': 'Martial Cottle Park 5K',
                'race_date': '2017-07-29',
                'race_type': {
                    'distance': {
                        'distance': 3.10686,
                        'unit': 'mile'
                    },
                    'name': '5K'
                },
                'status': 'scheduled',
                'target_time': {
                    'seconds': 1530,
                    'time': '0:25:30'
                }
            }
            FirstUtils.assert_deep_almost_equal(
                self, cmp_json, race.to_json(output_unit='mile'), 5)
            cmp_html = (
                '<div>\n' + '  <h2>Race:</h2>\n' +
                '  <table style="border-spacing: 15px 0">\n' +
                '    <tbody>\n' + '      <tr>\n' + '        <td>Name:</td>\n' +
                '        <td><b>Martial Cottle Park 5K</b></td>\n' +
                '      </tr>\n' + '      <tr>\n' + '        <td>Type:</td>\n' +
                '        <td><b>5K</b></td>\n' + '      </tr>\n' +
                '      <tr>\n' + '        <td>Distance:</td>\n' +
                '        <td><b>5.000 km</b></td>\n' + '      </tr>\n' +
                '      <tr>\n' + '        <td>Date:</td>\n' +
                '        <td><b>2017-07-29</b></td>\n' + '      </tr>\n' +
                '      <tr>\n' + '        <td>Target time:</td>\n' +
                '        <td><b>0:25:30</b></td>\n' + '      </tr>\n' +
                '      <tr>\n' + '        <td>Status:</td>\n' +
                '        <td><b>scheduled</b></td>\n' + '      </tr>\n' +
                '    </tbody>\n' + '  </table>\n' + '</div>')
            self.assertEqual(cmp_html, race.to_html().indented_str())
            cmp_html = (
                '<div>\n' + '  <h2>Race:</h2>\n' +
                '  <table style="border-spacing: 15px 0">\n' +
                '    <tbody>\n' + '      <tr>\n' + '        <td>Name:</td>\n' +
                '        <td><b>Martial Cottle Park 5K</b></td>\n' +
                '      </tr>\n' + '      <tr>\n' + '        <td>Type:</td>\n' +
                '        <td><b>5K</b></td>\n' + '      </tr>\n' +
                '      <tr>\n' + '        <td>Distance:</td>\n' +
                '        <td><b>3.107 mile</b></td>\n' + '      </tr>\n' +
                '      <tr>\n' + '        <td>Date:</td>\n' +
                '        <td><b>2017-07-29</b></td>\n' + '      </tr>\n' +
                '      <tr>\n' + '        <td>Target time:</td>\n' +
                '        <td><b>0:25:30</b></td>\n' + '      </tr>\n' +
                '      <tr>\n' + '        <td>Status:</td>\n' +
                '        <td><b>scheduled</b></td>\n' + '      </tr>\n' +
                '    </tbody>\n' + '  </table>\n' + '</div>')
            self.assertEqual(cmp_html,
                             race.to_html(output_unit='mile').indented_str())
        except TypeError as tex:
            self.fail(str(tex))
        except ValueError as vex:
            self.fail(str(vex))

        try:  # add actual time
            race.set_status(status='done')
            race.set_actual_time(a_time=tt2)
            cmp_string = ('Martial Cottle Park 5K of type ' + str(rt1) + '\n' +
                          'On ' + str(rd1) + '\n' + 'Target time - ' +
                          str(tt1) + '\n' + 'Status - done\n' +
                          'Actual time - ' + str(tt2) + '\n')
            self.assertEqual(cmp_string, str(race))
            cmp_json = {
                'Name': 'Martial Cottle Park 5K',
                'actual_time': '0:24:34',
                'race_date': '2017-07-29',
                'race_type': {
                    'distance': {
                        'distance': 5.0,
                        'unit': 'km'
                    },
                    'name': '5K'
                },
                'status': 'done',
                'target_time': {
                    'seconds': 1530,
                    'time': '0:25:30'
                }
            }
            self.assertEqual(cmp_json, race.to_json())
            cmp_json = {
                'Name': 'Martial Cottle Park 5K',
                'actual_time': '0:24:34',
                'race_date': '2017-07-29',
                'race_type': {
                    'distance': {
                        'distance': 3.10686,
                        'unit': 'mile'
                    },
                    'name': '5K'
                },
                'status': 'done',
                'target_time': {
                    'seconds': 1530,
                    'time': '0:25:30'
                }
            }
            FirstUtils.assert_deep_almost_equal(
                self, cmp_json, race.to_json(output_unit='mile'), 5)
        except TypeError as tex:
            self.fail(str(tex))
        except ValueError as vex:
            self.fail(str(vex))

        try:  # remove target time
            race.set_target_time()
            cmp_string = ('Martial Cottle Park 5K of type ' + str(rt1) + '\n' +
                          'On ' + str(rd1) + '\n' + 'Status - done\n' +
                          'Actual time - ' + str(tt2) + '\n')
            self.assertEqual(cmp_string, str(race))
        except TypeError as tex:
            self.fail(str(tex))
        except ValueError as vex:
            self.fail(str(vex))

        try:  # negative
            race.set_status('lulu')
            self.fail('Should not get here with a bad status')
        except ValueError as ex:
            self.assertEqual("Status not in ['scheduled', 'done', 'skipped']",
                             str(ex))
Ejemplo n.º 25
0
    def test_add_workout(self):

        ws1 = [0, 2, 5]
        rt1 = FirstRaceType(name='Marathon', distance=42.195, unit='km')
        rd1 = date(year=2017, month=7, day=29)
        r1 = FirstRace(name='SFM', race_type=rt1, race_date=rd1)
        rn1 = FirstRunner(name='DBD')
        p1 = FirstPlan(name='My first marathon training plan',
                       weekly_schedule=ws1,
                       race=r1,
                       runner=rn1)

        t_warmup = FirstTime.from_string('0:15:00')
        p_warmup = FirstPace.from_string('0:10:00 min per mile')
        s_warmup = FirstStepBody(name='Warm up', pace=p_warmup, time=t_warmup)

        s_repeat = FirstStepRepeat(name='repeat X 8', repeat=8)
        d_interval = FirstDistance.from_string('400 m')
        p_fast = FirstPace.from_string('0:08:00 min per mile')
        s_fast = FirstStepBody(name='Fast', pace=p_fast, distance=d_interval)
        s_repeat.add_step(s_fast)
        s_slow = FirstStepBody(name='Rest', pace=p_warmup, distance=d_interval)
        s_repeat.add_step(s_slow)

        t_cooldown = FirstTime.from_string('0:10:00')
        s_cooldown = FirstStepBody(name='Cool down',
                                   pace=p_warmup,
                                   time=t_cooldown)

        wo = FirstWorkout(name='Week 1 Key-run 1',
                          workout_date=date(year=2017, month=6, day=24))
        wo.add_step(step=s_warmup)
        wo.add_step(step=s_repeat)
        wo.add_step(step=s_cooldown)

        try:  # first workout
            p1.add_workout(workout=wo)
            cmp_string = (
                'Training Plan:\nName - "My first marathon training plan"\n' +
                'Workout days: Mon, Wed, Sat\nRace:\n' +
                '  Name - "SFM" of type Marathon - 42.195 km\nRunner:\n  Name - "DBD"\nWorkouts:\n'
                + '  "Week 1 Key-run 1"\n    Sat 2017-06-24\n    scheduled\n' +
                'Total 1 workouts\n')
            self.assertEqual(cmp_string, str(p1))

            file_name = expanduser(
                '~/PycharmProjects/first/database/cmp_plan2.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 TypeError as ex:
            self.fail(str(ex))

        try:  # bad workout
            p1.add_workout(workout='workout')
            self.fail('Should not get here with bad workout')
        except TypeError as ex:
            self.assertEqual(
                'FirstPlan.add_workout - workout must be an instance of FirstWorkout',
                str(ex))
Ejemplo n.º 26
0
    def test_repeat(self):

        FirstStepBase.reset_global_id()

        p1 = FirstPace.from_string('0:10:00 min per mile')
        d1 = FirstDistance.from_string('3 mile')
        t1 = FirstTime.from_string('0:15:00')

        try:
            name = '3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)'
            s1 = FirstStepRepeat(name=name, repeat=3)
            self.assertEqual(
                'Step: "' + name + '"  id = 0\ntype - repeat  repeat - 3\n',
                str(s1))
            self.assertAlmostEquals(0.0, s1.total(unit='mile'), 5)
            self.assertAlmostEquals(0.0, s1.total(what='time', unit='minute'))
            tcx_string = (
                '<Step xsi:type="Repeat_t">\n' + '  <StepId>0</StepId>\n' +
                '  <Name>3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)</Name>\n'
                + '  <Repetitions>3</Repetitions>\n' + '</Step>\n')
            self.assertEqual(tcx_string, s1.tcx())
        except TypeError as tex:
            self.fail(str(tex))
        except ValueError as vex:
            self.fail(str(vex))

        try:
            s2 = FirstStepBody(name='3 mile @ 10 min per mile',
                               pace=p1,
                               distance=d1)
            s3 = FirstStepBody(name='15 minutes @ 19 min per mile',
                               pace=p1,
                               time=t1)
            s1.add_step(s2)
            s1.add_step(s3)
            short = 'Step: "' + name + '"  id = 0\ntype - repeat  repeat - 3\n'
            self.assertEqual(short, str(s1))
            detail = 'Step: "3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)"\n' +\
                     '  Step: "3 mile @ 10 min per mile"\n' +\
                     '    3.0 mile  at  0:10:00 min per mile\n' +\
                     '  Step: "15 minutes @ 19 min per mile"\n' +\
                     '    0:15:00  at  0:10:00 min per mile\n'
            self.assertEqual(detail, s1.details())
            self.assertAlmostEquals(13.5, s1.total(unit='mile'), 5)
            self.assertAlmostEquals(135.0, s1.total(what='time',
                                                    unit='minute'))
            tcx_string = (
                '  <Step xsi:type="Repeat_t">\n' + '    <StepId>0</StepId>\n' +
                '    <Name>3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)</Name>\n'
                + '    <Repetitions>3</Repetitions>\n' +
                '    <Child xsi:type="Step_t">\n' +
                '      <StepId>1</StepId>\n' +
                '      <Name>3 mile @ 10 min per mile</Name>\n' +
                '      <Duration xsi:type="Distance_t">\n' +
                '        <Meters>4828</Meters>\n' + '      </Duration>\n' +
                '      <Intensity>Active</Intensity>\n' +
                '      <Target xsi:type="Speed_t">\n' +
                '        <SpeedZone xsi:type="CustomSpeedZone_t">\n' +
                '        <LowInMetersPerSecond>2.6382689</LowInMetersPerSecond>\n'
                +
                '        <HighInMetersPerSecond>2.7277017</HighInMetersPerSecond>\n'
                + '      </SpeedZone>\n' + '      </Target>\n' +
                '    </Child>\n' + '    <Child xsi:type="Step_t">\n' +
                '      <StepId>2</StepId>\n' +
                '      <Name>15 minutes @ 19 min per mile</Name>\n' +
                '      <Duration xsi:type="Time_t">\n' +
                '        <Seconds>900</Seconds>\n' + '      </Duration>\n' +
                '      <Intensity>Active</Intensity>\n' +
                '      <Target xsi:type="Speed_t">\n' +
                '        <SpeedZone xsi:type="CustomSpeedZone_t">\n' +
                '        <LowInMetersPerSecond>2.6382689</LowInMetersPerSecond>\n'
                +
                '        <HighInMetersPerSecond>2.7277017</HighInMetersPerSecond>\n'
                + '      </SpeedZone>\n' + '      </Target>\n' +
                '    </Child>\n'
                '  </Step>\n')
            self.assertEqual(tcx_string, s1.tcx(indent='  ', delta_seconds=10))
        except TypeError as tex:
            self.fail(str(tex))
        except ValueError as vex:
            self.fail(str(vex))

        try:  # bad repeat type
            dummy = FirstStepRepeat(name='bla', repeat='3')
            self.fail('Should not get here with bad repeat type')
        except TypeError as ex:
            self.assertEqual(
                'FirstStepRepeat.__init__ - repeat must be an integer',
                str(ex))

        try:  # negative repeat
            dummy = FirstStepRepeat(name='bla', repeat=-3)
            self.fail('Should not get here with negative repeat value')
        except ValueError as ex:
            self.assertEqual(
                'FirstStepRepeat.__init__ - repeat must be greater than 0',
                str(ex))

        try:  # bad child step type
            s1.add_step('bad step')
            self.fail('Should not get here with bad step type')
        except TypeError as ex:
            self.assertEqual(
                'FirstStepRepeat.add_step - step must be an instance of FirstStepBase',
                str(ex))
Ejemplo n.º 27
0
    def test_body(self):

        FirstStepBase.reset_global_id()

        p1 = FirstPace.from_string('0:10:00 min per mile')
        d1 = FirstDistance.from_string('3 mile')
        t1 = FirstTime.from_string('0:15:00')

        try:  # distance step
            s1 = FirstStepBody(name='3 miles @ 10 minutes per mile',
                               pace=p1,
                               distance=d1)
            cmp_string = 'Step: "3 miles @ 10 minutes per mile"  id = 0\n' + \
                         'type - body  pace - 0:10:00 min per mile\nDistance - 3.0 mile\n'
            self.assertEqual(cmp_string, str(s1))
            self.assertAlmostEquals(3.0, s1.total(unit='mile'), 5)
            self.assertAlmostEquals(4.828032, s1.total(unit='km'), 5)
            self.assertAlmostEquals(30.0, s1.total(what='time', unit='minute'),
                                    5)
            self.assertAlmostEquals(0.5, s1.total(what='time', unit='hour'), 5)
            tcx_string = (
                '<Step xsi:type="Step_t">\n' + '  <StepId>0</StepId>\n' +
                '  <Name>3 miles @ 10 minutes per mile</Name>\n' +
                '  <Duration xsi:type="Distance_t">\n' +
                '    <Meters>4828</Meters>\n' + '  </Duration>\n' +
                '  <Intensity>Active</Intensity>\n' +
                '  <Target xsi:type="Speed_t">\n' +
                '    <SpeedZone xsi:type="CustomSpeedZone_t">\n' +
                '    <LowInMetersPerSecond>2.6600727</LowInMetersPerSecond>\n'
                +
                '    <HighInMetersPerSecond>2.7047798</HighInMetersPerSecond>\n'
                + '  </SpeedZone>\n' + '  </Target>\n' + '</Step>\n')
            self.assertEqual(tcx_string, s1.tcx())  # no indent
            tcx_string = (
                '    <Step xsi:type="Step_t">\n' +
                '      <StepId>0</StepId>\n' +
                '      <Name>3 miles @ 10 minutes per mile</Name>\n' +
                '      <Duration xsi:type="Distance_t">\n' +
                '        <Meters>4828</Meters>\n' + '      </Duration>\n' +
                '      <Intensity>Active</Intensity>\n' +
                '      <Target xsi:type="Speed_t">\n' +
                '        <SpeedZone xsi:type="CustomSpeedZone_t">\n' +
                '        <LowInMetersPerSecond>2.6688955</LowInMetersPerSecond>\n'
                +
                '        <HighInMetersPerSecond>2.6957186</HighInMetersPerSecond>\n'
                + '      </SpeedZone>\n' + '      </Target>\n' +
                '    </Step>\n')
            self.assertEqual(tcx_string,
                             s1.tcx(indent='    ',
                                    delta_seconds=3))  # with indent
        except TypeError as tex:
            self.fail(str(tex))
        except ValueError as vex:
            self.fail(str(vex))

        try:  # time step
            s1 = FirstStepBody(name='15 minutes @ 10 minutes per mile',
                               pace=p1,
                               time=t1)
            cmp_string = 'Step: "15 minutes @ 10 minutes per mile"  id = 1\n' + \
                         'type - body  pace - 0:10:00 min per mile\nTime - 0:15:00\n'
            self.assertEqual(cmp_string, str(s1))
            self.assertAlmostEquals(15.0, s1.total(what='time', unit='minute'),
                                    5)
            self.assertAlmostEquals(7920.0, s1.total(unit='ft'))
            tcx_string = (
                '<Step xsi:type="Step_t">\n' + '  <StepId>1</StepId>\n' +
                '  <Name>15 minutes @ 10 minutes per mile</Name>\n' +
                '  <Duration xsi:type="Time_t">\n' +
                '    <Seconds>900</Seconds>\n' + '  </Duration>\n' +
                '  <Intensity>Active</Intensity>\n' +
                '  <Target xsi:type="Speed_t">\n' +
                '    <SpeedZone xsi:type="CustomSpeedZone_t">\n' +
                '    <LowInMetersPerSecond>2.6600727</LowInMetersPerSecond>\n'
                +
                '    <HighInMetersPerSecond>2.7047798</HighInMetersPerSecond>\n'
                + '  </SpeedZone>\n' + '  </Target>\n' + '</Step>\n')
            self.assertEqual(tcx_string, s1.tcx())
        except TypeError as tex:
            self.fail(str(tex))
        except ValueError as vex:
            self.fail(str(vex))

        try:  # bad name type
            dummy = FirstStepBody(name=123, pace=p1, time=t1)
            self.fail('Should not get here with bad name')
        except TypeError as ex:
            self.assertEqual('FirstStepBase.__init__ - name must be a string',
                             str(ex))

        try:  # bad pace
            dummy = FirstStepBody(name='dummy', pace='bad pace type', time=t1)
            self.fail('Should not get here with bad pace')
        except TypeError as ex:
            self.assertEqual(
                'FirstStepBody.__init__ - pace must be an instance of FirstPace',
                str(ex))

        try:  # no distance and no time
            dummy = FirstStepBody(name='dummy', pace=p1)
            self.fail('Should not get here with neither distance nor duration')
        except ValueError as ex:
            self.assertEqual(
                'FirstStepBody.__init__ - Either distance or time must have a value',
                str(ex))

        try:  # bad distance
            dummy = FirstStepBody(name='dummy', pace=p1, distance=123.45)
            self.fail('Should not get here with bad distance')
        except TypeError as ex:
            self.assertEqual(
                'FirstStepBody.__init__ - distance must be an instance of FirstDistance',
                str(ex))

        try:  # bad time
            dummy = FirstStepBody(name='dummy', pace=p1, time=987.65)
            self.fail('Should not get here with bad time')
        except TypeError as ex:
            self.assertEqual(
                'FirstStepBody.__init__ - time must be an instance of FirstTime',
                str(ex))

        try:  # both distance and time
            dummy = FirstStepBody(name='dummy', pace=p1, distance=d1, time=t1)
            self.fail('Should not get here with both distance and time')
        except ValueError as ex:
            self.assertEqual(
                'FirstStepBody.__init__ - cannot set both distance and duration in the same step',
                str(ex))
Ejemplo n.º 28
0
    def __parse_segments(self, segment_def, ref_race, pace_unit,
                         segment_paces):

        where_am_i = 'FirstData.__parse_segments'
        index = 0
        for segment in segment_def:
            name = segment[0].text
            segment_type = segment[1].text
            distance = None
            duration = None
            ref_pace_name = None
            if segment_type == 'DISTANCE':
                distance = FirstDistance(distance=float(segment[2][0].text),
                                         unit=segment[2][1].text)
            elif segment_type == 'TIME':
                duration = FirstTime(seconds=int(segment[2][0].text),
                                     minutes=int(segment[2][1].text),
                                     hours=int(segment[2][2].text))
                ref_pace_name = segment[3].text
            else:  # PACE
                ref_pace_name = segment[2].text

            self.segments.append(
                FirstSegment(name=name,
                             distance=distance,
                             duration=duration,
                             ref_pace_name=ref_pace_name))
            self.segments_lookup[name] = index
            index += 1

        self.reference_race = ref_race.text
        dist_unit = pace_unit.text.split()[-1]

        for line in segment_paces:
            paces_list = []
            first = True
            index = 0
            for value in line.text.split():
                if first:
                    paces_list.append(FirstTime.from_string(value))
                    first = False
                else:
                    # why incrementing index makes ref_segment.get_type undefined?
                    time_string = '0:' + value
                    ref_segment = self.segments[index]
                    if ref_segment.get_type() == 'distance':
                        cur_time = FirstTime.from_string(time_string)
                        cur_dist = ref_segment.distance
                        paces_list.append(
                            FirstPace.from_time_distance(time=cur_time,
                                                         distance=cur_dist,
                                                         unit=dist_unit))
                    elif ref_segment.get_type() == 'pace':
                        paces_list.append(
                            FirstPace.from_string(time_string + ' ' +
                                                  pace_unit.text))
                    else:
                        raise ValueError(
                            where_am_i +
                            ' - Duration segments have already a reference pace'
                        )

                    index = index + 1

            self.segments_paces.append(paces_list)
Ejemplo n.º 29
0
    def test_body(self):

        FirstStepBase.reset_global_id()

        pace = FirstPace.from_string(str_input='0:10:00 min per mile')
        distance = FirstDistance.from_string(string='3 mile')
        time = FirstTime.from_string(string='0:15:00')

        try:  # distance step
            step_b = FirstStepBody(name='3 miles @ 10 minutes per mile',
                                   pace=pace,
                                   distance=distance)
            cmp_string = 'Step: "3 miles @ 10 minutes per mile"  id = 0\n' + \
                         'type - body  pace - 0:10:00 min per mile\nDistance - 3.0 mile\n'
            self.assertEqual(cmp_string, str(step_b))
            self.assertAlmostEqual(3.0, step_b.total(unit='mile'), 5)
            self.assertAlmostEqual(4.828032, step_b.total(unit='km'), 5)
            self.assertAlmostEqual(30.0,
                                   step_b.total(what='time', unit='minute'), 5)
            self.assertAlmostEqual(0.5, step_b.total(what='time', unit='hour'),
                                   5)
            tcx_string = (
                '<Step xsi:type="Step_t">\n' + '  <StepId>0</StepId>\n' +
                '  <Name>3 miles @ 10 minutes per mile</Name>\n' +
                '  <Duration xsi:type="Distance_t">\n' +
                '    <Meters>4828</Meters>\n' + '  </Duration>\n' +
                '  <Intensity>Active</Intensity>\n' +
                '  <Target xsi:type="Speed_t">\n' +
                '    <SpeedZone xsi:type="CustomSpeedZone_t">\n' +
                '      <LowInMetersPerSecond>2.6600727</LowInMetersPerSecond>\n'
                +
                '      <HighInMetersPerSecond>2.7047798</HighInMetersPerSecond>\n'
                + '    </SpeedZone>\n' + '  </Target>\n' + '</Step>')
            self.assertEqual(tcx_string,
                             step_b.tcx().indented_str())  # no indent
            tcx_string = (
                '<Step xsi:type="Step_t">\n' + '  <StepId>0</StepId>\n' +
                '  <Name>3 miles @ 10 minutes per mile</Name>\n' +
                '  <Duration xsi:type="Distance_t">\n' +
                '    <Meters>4828</Meters>\n' + '  </Duration>\n' +
                '  <Intensity>Active</Intensity>\n' +
                '  <Target xsi:type="Speed_t">\n' +
                '    <SpeedZone xsi:type="CustomSpeedZone_t">\n' +
                '      <LowInMetersPerSecond>2.6688955</LowInMetersPerSecond>\n'
                +
                '      <HighInMetersPerSecond>2.6957186</HighInMetersPerSecond>\n'
                + '    </SpeedZone>\n' + '  </Target>\n' + '</Step>')
            self.assertEqual(tcx_string,
                             step_b.tcx(delta_seconds=3).indented_str())
            cmp_json = {
                'distance': {
                    'distance': 3.0,
                    'unit': 'mile'
                },
                'name': '3 miles @ 10 minutes per mile',
                'pace': {
                    'length_unit': 'mile',
                    'pace': '0:10:00 min per mile',
                    'time': {
                        'seconds': 600,
                        'time': '0:10:00'
                    }
                }
            }
            self.assertEqual(cmp_json, step_b.to_json())
            cmp_json = {
                'distance': {
                    'distance': 4.828032,
                    'unit': 'km'
                },
                'name': '3 miles @ 10 minutes per mile',
                'pace': {
                    'length_unit': 'km',
                    'pace': '0:06:13 min per km',
                    'time': {
                        'seconds': 373,
                        'time': '0:06:13'
                    }
                }
            }
            self.assertEqual(cmp_json, step_b.to_json(output_unit='km'))
            cmp_html = (
                '<div style="margin-left: 20px">\n' + '  <p>\n' +
                '    3 miles @ 10 minutes per mile - 3.000 mile at 0:10:00 min per mile\n'
                + '  </p>\n' + '</div>')
            self.assertEqual(cmp_html, step_b.to_html().indented_str())
            cmp_html = (
                '<div style="margin-left: 20px">\n' + '  <p>\n' +
                '    3 miles @ 10 minutes per mile - 4.828 km at 0:06:13 min per km\n'
                + '  </p>\n' + '</div>')
            self.assertEqual(cmp_html,
                             step_b.to_html(output_unit='km').indented_str())
        except TypeError as tex:
            self.fail(str(tex))
        except ValueError as vex:
            self.fail(str(vex))

        try:  # time step
            step_b = FirstStepBody(name='15 minutes @ 10 minutes per mile',
                                   pace=pace,
                                   time=time)
            cmp_string = 'Step: "15 minutes @ 10 minutes per mile"  id = 1\n' + \
                         'type - body  pace - 0:10:00 min per mile\nTime - 0:15:00\n'
            self.assertEqual(cmp_string, str(step_b))
            self.assertAlmostEqual(15.0,
                                   step_b.total(what='time', unit='minute'), 5)
            self.assertAlmostEqual(7920.0, step_b.total(unit='ft'))
            tcx_string = (
                '<Step xsi:type="Step_t">\n' + '  <StepId>1</StepId>\n' +
                '  <Name>15 minutes @ 10 minutes per mile</Name>\n' +
                '  <Duration xsi:type="Time_t">\n' +
                '    <Seconds>900</Seconds>\n' + '  </Duration>\n' +
                '  <Intensity>Active</Intensity>\n' +
                '  <Target xsi:type="Speed_t">\n' +
                '    <SpeedZone xsi:type="CustomSpeedZone_t">\n' +
                '      <LowInMetersPerSecond>2.6600727</LowInMetersPerSecond>\n'
                +
                '      <HighInMetersPerSecond>2.7047798</HighInMetersPerSecond>\n'
                + '    </SpeedZone>\n' + '  </Target>\n' + '</Step>')
            self.assertEqual(tcx_string, step_b.tcx().indented_str())
            cmp_json = {
                'name': '15 minutes @ 10 minutes per mile',
                'pace': {
                    'length_unit': 'mile',
                    'pace': '0:10:00 min per mile',
                    'time': {
                        'seconds': 600,
                        'time': '0:10:00'
                    }
                },
                'time': {
                    'seconds': 900,
                    'time': '0:15:00'
                }
            }
            self.assertEqual(cmp_json, step_b.to_json())
            cmp_json = {
                'name': '15 minutes @ 10 minutes per mile',
                'pace': {
                    'length_unit': 'km',
                    'pace': '0:06:13 min per km',
                    'time': {
                        'seconds': 373,
                        'time': '0:06:13'
                    }
                },
                'time': {
                    'seconds': 900,
                    'time': '0:15:00'
                }
            }
            self.assertEqual(cmp_json, step_b.to_json(output_unit='km'))
            cmp_html = (
                '<div style="margin-left: 20px">\n' + '  <p>\n' +
                '    15 minutes @ 10 minutes per mile - 0:15:00 at 0:10:00 min per mile\n'
                + '  </p>\n' + '</div>')
            self.assertEqual(cmp_html, step_b.to_html().indented_str())
            cmp_html = (
                '<div style="margin-left: 20px">\n' + '  <p>\n' +
                '    15 minutes @ 10 minutes per mile - 0:15:00 at 0:06:13 min per km\n'
                + '  </p>\n' + '</div>')
            self.assertEqual(cmp_html,
                             step_b.to_html(output_unit='km').indented_str())
        except TypeError as tex:
            self.fail(str(tex))
        except ValueError as vex:
            self.fail(str(vex))

        try:  # no distance and no time
            _ = FirstStepBody(name='dummy', pace=pace)
            self.fail('Should not get here with neither distance nor duration')
        except ValueError as ex:
            self.assertEqual('Either distance or time must have a value',
                             str(ex))

        try:  # both distance and time
            _ = FirstStepBody(name='dummy',
                              pace=pace,
                              distance=distance,
                              time=time)
            self.fail('Should not get here with both distance and time')
        except ValueError as ex:
            self.assertEqual(
                'Cannot set both distance and duration in the same step',
                str(ex))
Ejemplo n.º 30
0
    def test_repeat(self):

        FirstStepBase.reset_global_id()

        pace = FirstPace.from_string(str_input='0:10:00 min per mile')
        distance = FirstDistance.from_string(string='3 mile')
        time = FirstTime.from_string(string='0:15:00')

        try:
            name = '3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)'
            step_r = FirstStepRepeat(name=name, repeat=3)
            self.assertEqual(
                'Step: "' + name + '"  id = 0\ntype - repeat  repeat - 3\n',
                str(step_r))
            self.assertAlmostEqual(0.0, step_r.total(unit='mile'), 5)
            self.assertAlmostEqual(0.0, step_r.total(what='time',
                                                     unit='minute'))
            tcx_string = (
                '<Step xsi:type="Repeat_t">\n' + '  <StepId>0</StepId>\n' +
                '  <Name>3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)</Name>\n'
                + '  <Repetitions>3</Repetitions>\n' + '</Step>')
            self.assertEqual(tcx_string, step_r.tcx().indented_str())
        except TypeError as tex:
            self.fail(str(tex))
        except ValueError as vex:
            self.fail(str(vex))

        try:
            step_b1 = FirstStepBody(name='3 mile @ 10 min per mile',
                                    pace=pace,
                                    distance=distance)
            step_b2 = FirstStepBody(name='15 minutes @ 19 min per mile',
                                    pace=pace,
                                    time=time)
            step_r.add_step(step_b1)
            step_r.add_step(step_b2)
            short = 'Step: "' + name + '"  id = 0\ntype - repeat  repeat - 3\n'
            self.assertEqual(short, str(step_r))
            detail = 'Step: "3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)"\n' + \
                     '  Step: "3 mile @ 10 min per mile"\n' + \
                     '    3.0 mile  at  0:10:00 min per mile\n' + \
                     '  Step: "15 minutes @ 19 min per mile"\n' + \
                     '    0:15:00  at  0:10:00 min per mile\n'
            self.assertEqual(detail, step_r.details())
            self.assertAlmostEqual(13.5, step_r.total(unit='mile'), 5)
            self.assertAlmostEqual(135.0,
                                   step_r.total(what='time', unit='minute'))
            tcx_string = (
                '<Step xsi:type="Repeat_t">\n' + '  <StepId>0</StepId>\n' +
                '  <Name>3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)</Name>\n'
                + '  <Repetitions>3</Repetitions>\n' +
                '  <Child xsi:type="Step_t">\n' + '    <StepId>1</StepId>\n' +
                '    <Name>3 mile @ 10 min per mile</Name>\n' +
                '    <Duration xsi:type="Distance_t">\n' +
                '      <Meters>4828</Meters>\n' + '    </Duration>\n' +
                '    <Intensity>Active</Intensity>\n' +
                '    <Target xsi:type="Speed_t">\n' +
                '      <SpeedZone xsi:type="CustomSpeedZone_t">\n' +
                '        <LowInMetersPerSecond>2.6382689</LowInMetersPerSecond>\n'
                +
                '        <HighInMetersPerSecond>2.7277017</HighInMetersPerSecond>\n'
                + '      </SpeedZone>\n' + '    </Target>\n' + '  </Child>\n' +
                '  <Child xsi:type="Step_t">\n' + '    <StepId>2</StepId>\n' +
                '    <Name>15 minutes @ 19 min per mile</Name>\n' +
                '    <Duration xsi:type="Time_t">\n' +
                '      <Seconds>900</Seconds>\n' + '    </Duration>\n' +
                '    <Intensity>Active</Intensity>\n' +
                '    <Target xsi:type="Speed_t">\n' +
                '      <SpeedZone xsi:type="CustomSpeedZone_t">\n' +
                '        <LowInMetersPerSecond>2.6382689</LowInMetersPerSecond>\n'
                +
                '        <HighInMetersPerSecond>2.7277017</HighInMetersPerSecond>\n'
                + '      </SpeedZone>\n' + '    </Target>\n' + '  </Child>\n'
                '</Step>')
            self.assertEqual(tcx_string,
                             step_r.tcx(delta_seconds=10).indented_str())
            cmp_json = {
                'name':
                '3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)',
                'repeat':
                3,
                'steps': [{
                    'distance': {
                        'distance': 3.0,
                        'unit': 'mile'
                    },
                    'name': '3 mile @ 10 min per mile',
                    'pace': {
                        'length_unit': 'mile',
                        'pace': '0:10:00 min per mile',
                        'time': {
                            'seconds': 600,
                            'time': '0:10:00'
                        }
                    }
                }, {
                    'name': '15 minutes @ 19 min per mile',
                    'pace': {
                        'length_unit': 'mile',
                        'pace': '0:10:00 min per mile',
                        'time': {
                            'seconds': 600,
                            'time': '0:10:00'
                        }
                    },
                    'time': {
                        'seconds': 900,
                        'time': '0:15:00'
                    }
                }]
            }
            self.assertEqual(cmp_json, step_r.to_json())
            cmp_json = {
                'name':
                '3 X (3 mile @ 10 min per mile + 15 minutes @ 19 min per mile)',
                'repeat':
                3,
                'steps': [{
                    'distance': {
                        'distance': 4.828032,
                        'unit': 'km'
                    },
                    'name': '3 mile @ 10 min per mile',
                    'pace': {
                        'length_unit': 'km',
                        'pace': '0:06:13 min per km',
                        'time': {
                            'seconds': 373,
                            'time': '0:06:13'
                        }
                    }
                }, {
                    'name': '15 minutes @ 19 min per mile',
                    'pace': {
                        'length_unit': 'km',
                        'pace': '0:06:13 min per km',
                        'time': {
                            'seconds': 373,
                            'time': '0:06:13'
                        }
                    },
                    'time': {
                        'seconds': 900,
                        'time': '0:15:00'
                    }
                }]
            }
            self.assertEqual(cmp_json, step_r.to_json(output_unit='km'))
            cmp_html = (
                '<div style="margin-left: 20px">\n' + '  <p>\n' +
                '    Repeat 3 times:\n' + '  </p>\n' +
                '  <div style="margin-left: 20px">\n' + '    <p>\n' +
                '      3 mile @ 10 min per mile - 3.000 mile at 0:10:00 min per mile\n'
                + '    </p>\n' + '  </div>\n' +
                '  <div style="margin-left: 20px">\n' + '    <p>\n' +
                '      15 minutes @ 19 min per mile - 0:15:00 at 0:10:00 min per mile\n'
                + '    </p>\n' + '  </div>\n' + '</div>')
            self.assertEqual(cmp_html, step_r.to_html().indented_str())
            cmp_html = (
                '<div style="margin-left: 20px">\n' + '  <p>\n' +
                '    Repeat 3 times:\n' + '  </p>\n' +
                '  <div style="margin-left: 20px">\n' + '    <p>\n' +
                '      3 mile @ 10 min per mile - 4.828 km at 0:06:13 min per km\n'
                + '    </p>\n' + '  </div>\n' +
                '  <div style="margin-left: 20px">\n' + '    <p>\n' +
                '      15 minutes @ 19 min per mile - 0:15:00 at 0:06:13 min per km\n'
                + '    </p>\n' + '  </div>\n' + '</div>')
            self.assertEqual(cmp_html,
                             step_r.to_html(output_unit='km').indented_str())
        except TypeError as tex:
            self.fail(str(tex))
        except ValueError as vex:
            self.fail(str(vex))

        try:  # negative repeat
            _ = FirstStepRepeat(name='bla', repeat=-3)
            self.fail('Should not get here with negative repeat value')
        except ValueError as ex:
            self.assertEqual('repeat must be greater than 0', str(ex))