Skip to content

Commit

Permalink
Closes stravalib#10 and closes stravalib#20 - Added a sanity check fu…
Browse files Browse the repository at this point in the history
…nctional test for laps (only will work for me)
  • Loading branch information
hozn committed Jul 13, 2014
1 parent 717f4fc commit b13f05c
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 29 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ dist/
*.egg-info/
*.egg/
docs/_build/
test.ini
2 changes: 1 addition & 1 deletion stravalib/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ def get_activity_laps(self, activity_id):
'/activities/{id}/laps',
id=activity_id)

return BatchedResultsIterator(entity=model.ActivityLaps,
return BatchedResultsIterator(entity=model.ActivityLap,
bind_client=self,
result_fetcher=result_fetcher)

Expand Down
36 changes: 29 additions & 7 deletions stravalib/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,9 +350,12 @@ class ActivityKudos(LoadableEntity):

approve_followers = Attribute(bool, (SUMMARY,DETAILED)) #: Whether athlete has elected to approve followers

class ActivityLaps(LoadableEntity):
class ActivityLap(LoadableEntity):

name = Attribute(unicode, (SUMMARY,DETAILED)) #: Name of lap


athlete = EntityAttribute(Athlete, (SUMMARY,DETAILED))

elapsed_time = TimeIntervalAttribute((SUMMARY, DETAILED)) #: :class:`datetime.timedelta` of elapsed time for lap
moving_time = TimeIntervalAttribute((SUMMARY, DETAILED)) #: :class:`datetime.timedelta` of moving time for lap
start_date = TimestampAttribute((SUMMARY,DETAILED)) #: :class:`datetime.datetime` when lap was started in GMT
Expand All @@ -361,8 +364,8 @@ class ActivityLaps(LoadableEntity):
start_index= Attribute(int, (SUMMARY,DETAILED)) #:
end_index= Attribute(int, (SUMMARY,DETAILED)) #:
total_elevation_gain = Attribute(float, (SUMMARY,DETAILED,), units=uh.meters) #: What is total elevation gain for lap
average_speed = Attribute(float, (SUMMARY,DETAILED,)) #: Average speed for lap
max_speed = Attribute(float, (SUMMARY,DETAILED,)) #: Max speed for lap
average_speed = Attribute(float, (SUMMARY,DETAILED,), units=uh.meters_per_second) #: Average speed for lap
max_speed = Attribute(float, (SUMMARY,DETAILED,), units=uh.meters_per_second) #: Max speed for lap
average_cadence = Attribute(float, (SUMMARY,DETAILED,)) #: Average cadence for lap
average_watts = Attribute(float, (SUMMARY,DETAILED,)) #: Average watts for lap
average_heartrate = Attribute(float, (SUMMARY,DETAILED,)) #: Average heartrate for lap
Expand Down Expand Up @@ -435,6 +438,7 @@ class Segment(LoadableEntity):
climb_category = Attribute(int, (SUMMARY,DETAILED)) # 0-5, lower is harder
city = Attribute(unicode, (SUMMARY,DETAILED)) #: The city this segment is in.
state = Attribute(unicode, (SUMMARY,DETAILED)) #: The state this segment is in.
country = Attribute(unicode, (SUMMARY,DETAILED)) #: The country this segment is in.
private = Attribute(bool, (SUMMARY,DETAILED)) #: Whether this is a private segment.
starred = Attribute(bool, (SUMMARY,DETAILED)) #: Whether this segment is starred by authenticated athlete

Expand Down Expand Up @@ -476,6 +480,7 @@ class BaseEffort(LoadableEntity):
distance = Attribute(int, (SUMMARY,DETAILED), units=uh.meters) #: The distance for this effort.
average_watts = Attribute(float, (SUMMARY,DETAILED)) #: Average power during effort
average_heartrate = Attribute(float, (SUMMARY,DETAILED)) #: Average HR during effort
max_heartrate = Attribute(float, (SUMMARY,DETAILED)) #: Max HR during effort
average_cadence = Attribute(float, (SUMMARY,DETAILED)) #: Average cadence during effort


Expand All @@ -489,8 +494,10 @@ class SegmentEffort(BaseEffort):
Class representing a best effort on a particular segment.
"""
start_index = Attribute(int, (SUMMARY,DETAILED)) # the activity stream index of the start of this effort
end_index = Attribute(int, (SUMMARY,DETAILED)) # the activity stream index of the end of this effort

end_index = Attribute(int, (SUMMARY,DETAILED)) # the activity stream index of the end of this effort
hidden = Attribute(bool, (SUMMARY,DETAILED,)) # indicates a hidden/non-important effort when returned as part of an activity, value may change over time.


class Activity(LoadableEntity):
"""
Represents an activity (ride, run, etc.).
Expand Down Expand Up @@ -564,7 +571,7 @@ class Activity(LoadableEntity):

average_speed = Attribute(float, (SUMMARY,DETAILED), units=uh.meters_per_second) #: Average speed for activity.
max_speed = Attribute(float, (SUMMARY,DETAILED), units=uh.meters_per_second) #: Max speed for activity
calories = Attribute(float, (SUMMARY,DETAILED)) #: Calculation of how many calories burned on activity

truncated = Attribute(int, (SUMMARY,DETAILED)) #: Only present if activity is owned by authenticated athlete, set to 0 if not truncated by privacy zones
has_kudoed = Attribute(bool, (SUMMARY,DETAILED)) #: If authenticated user has kudoed this activity

Expand All @@ -582,6 +589,7 @@ class Activity(LoadableEntity):

average_temp = Attribute(int, (SUMMARY,DETAILED)) #: (undocumented) Average temperature (when available from device) during activity.

calories = Attribute(float, (DETAILED,)) #: Calculation of how many calories burned on activity
description = Attribute(unicode, (DETAILED,)) #: (undocumented) Description of activity.
workout_type = Attribute(unicode, (DETAILED,)) #: (undocumented)

Expand All @@ -599,6 +607,20 @@ def comments(self):
self._comments = []
return self._comments

@property
def laps(self):
"""
Iterator of :class:`stravalib.model.ActivityLaps` objects for this activity.
"""
if self._friends is None:
self.assert_bind_client()
if self.friend_count > 0:
self._friends = self.bind_client.get_athlete_friends(self.id)
else:
# Shortcut if we know there aren't any
self._friends = []
return self._friends

@property
def zones(self):
"""
Expand Down
19 changes: 15 additions & 4 deletions stravalib/tests/functional/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
import warnings
import os
import ConfigParser

from stravalib import model
from stravalib.client import Client

from stravalib.tests import TestBase

# This is the access token from the Strava examples :)
TEST_ACCESS_TOKEN = "83ebeabdec09f6670863766f792ead24d61fe3f9"
from stravalib.tests import TestBase, TESTS_DIR, RESOURCES_DIR

TEST_CFG = os.path.join(TESTS_DIR, 'test.ini')

class FunctionalTestBase(TestBase):

def setUp(self):
super(FunctionalTestBase, self).setUp()
self.client = Client(access_token=TEST_ACCESS_TOKEN)
if not os.path.exists(TEST_CFG):
raise Exception("Unable to run the write tests without a tests.ini that defines an access_token with write privs.")

cfg = ConfigParser.SafeConfigParser()
with open(TEST_CFG) as fp:
cfg.readfp(fp, 'test.ini')
access_token = cfg.get('write_tests', 'access_token')

self.client = Client(access_token=access_token)

9 changes: 9 additions & 0 deletions stravalib/tests/functional/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ def test_get_activity(self):
# Ensure that iw as read in with correct units
self.assertEquals(22.5308, float(uh.kilometers(activity.distance)))

def test_get_activity_laps(self):
activity = self.client.get_activity(165094211)
laps = list(self.client.get_activity_laps(165094211))
self.assertEquals(5, len(laps))
# This obviously is far from comprehensive, just a sanity check
self.assertEquals(u'Lap 1', laps[0].name)
self.assertEquals(178.0, laps[0].max_heartrate)


def test_get_activity_zones(self):
"""
Test loading zones for activity.
Expand Down
19 changes: 2 additions & 17 deletions stravalib/tests/functional/test_client_write.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,12 @@
from __future__ import absolute_import, unicode_literals
import os
import ConfigParser
from datetime import datetime, timedelta
from io import BytesIO

from stravalib import model, exc, attributes, unithelper as uh
from stravalib.client import Client
from stravalib.tests import TestBase, TESTS_DIR, RESOURCES_DIR
from stravalib.tests.functional import FunctionalTestBase

TEST_CFG = os.path.join(TESTS_DIR, 'test.ini')

class ClientWriteTest(TestBase):

def setUp(self):
if not os.path.exists(TEST_CFG):
raise Exception("Unable to run the write tests without a tests.ini that defines an access_token with write privs.")

cfg = ConfigParser.SafeConfigParser()
with open(TEST_CFG) as fp:
cfg.readfp(fp, 'test.ini')
access_token = cfg.get('write_tests', 'access_token')

self.client = Client(access_token=access_token)
class ClientWriteTest(FunctionalTestBase):

def test_create_activity(self):
"""
Expand Down

0 comments on commit b13f05c

Please sign in to comment.