Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calories, kilojoules and other metrics are None #198

Open
samirak93 opened this issue Jun 23, 2020 · 12 comments
Open

Calories, kilojoules and other metrics are None #198

samirak93 opened this issue Jun 23, 2020 · 12 comments
Assignees
Labels

Comments

@samirak93
Copy link

Hi,
On the official API page, the sample get_activities seems to have numeric values for calories, kilojoules and other metrics.
https://developers.strava.com/docs/reference/#api-Activities-getActivityById

get_activities returns None for these metrics. Is this expected? Any reason behind this?

@lwasser
Copy link
Collaborator

lwasser commented Jan 17, 2024

hey @samirak93 i'm going through old issues to see what has been fixed and what we need to work on. Have you tried this recently with the big overhaul we've done to the stravalib api? Please let me know. we can leave this open if it's still an issue or close if it's not. i definitely see what you are seeing with the example API response. but am wondering if this has been fixed with the most recently updates that we've made.

@lwasser
Copy link
Collaborator

lwasser commented Jan 17, 2024

i actually see another recent issue here related to this from @martin-ueding which suggests this may still be a bug. confirmation would be great.

@lwasser lwasser self-assigned this Jan 17, 2024
@martin-ueding
Copy link

I use stravalib 1.5 in my project and it downloads 0 for the calories. I've just checked with it.

@jsamoocha
Copy link
Collaborator

jsamoocha commented Jan 18, 2024

Hi, I'm getting sensible values in responses. Can you make sure that the raw http response has a value for calories for your specific request?

@lwasser
Copy link
Collaborator

lwasser commented Jan 20, 2024

hey @jsamoocha 👋 SO -- i just finally had time to test this locally. i went on a hike this morning before work and i have the hike here in strava and see my calories in strava. however locally when i pull the hike down i see this: calories: None when i print out the dictionary return for the data. i will try to back track through my code and add breakpoints to try to see what the API response looks like.

however, is there a simpler way to view the raw http response other than breakpoints in the code for when that response is ingested? i'm going to try manually now but i just wondered if there was an easier way to test this. many thanks! normally with me this is user error 😆

@lwasser
Copy link
Collaborator

lwasser commented Jan 20, 2024

Ok update here is what i did.

i authenticated & got an activity ID for today's hike. then i made a direct call using requests.

activities = client.get_activities(after="2024-01-18")
api_url = f"https://www.strava.com/api/v3/activities/{activity_id}"
headers = {"Authorization": f"Bearer {my_token}"}
response = requests.get(api_url, headers=headers)
a = response.json()
a["calories"]

that returned 488 which is what i expected (and why i'm eating salted dark chocolate covered caramels now).

However this - returns None for calories

# Assume i've already authenticated and such - i have a little helper to do that
activities = client.get_activities(after="2024-01-18")

for i, activity in enumerate(activities):
    print(i)
    strava_data = activity.to_dict()

print(strava_data["calories"])

the above returns None making me think i should slow down on the caramels. Something does seem up with this but i can't yet figure out how to track down where the issue is - especially if you are seeing ok values.

@jsamoocha
Copy link
Collaborator

jsamoocha commented Jan 20, 2024

Ah, I finally see the issue. get_activities() (plural) returns (below the surface, on the Strava API level) a list of SummaryActivity objects, which don't have calories as attribute.

I tested the above using get_activity() (singular), which returns a DetailedActivity.

To retrieve the activity's calories, one needs to make a request per activity using get_activity().

To prevent confusion in the future, we could also differentiate between the different levels of detail. But that will introduce a breaking change.

@lwasser
Copy link
Collaborator

lwasser commented Jan 20, 2024

ahhhhh i should have looked more closely. this works:

activities = client.get_activities(after="2024-01-18")
for activity in activities:
    fin = client.get_activity(activity.id)
    fin.calories

i saw where calories was stored in the code but i made the (wrong) assumption that that would be inherited into the return for get_Activities (there is no factual basis for that assumption).

i really spun on this one as i thought perhaps it was something that was happening when the data were ingested from the api call into the model so i kept trying to create the right breakpoints vs actually just looking at where and how calories were stored 🙈 .

I'm thinking we (as a fix for now)

  1. update docs (i've been meaning to do this i can work on a docstring and documentation update
  2. provide a small usage example in the object docstring to direct people.

That would not break anything but it might help users. thoughts?

@lwasser
Copy link
Collaborator

lwasser commented Jan 20, 2024

ok thinking about this a bit more -

i understand now what's happening. i do see what the API returns for that call by default and it doesn't include any of that "detailed level" data such as calories

but the Activity class that is returned via the batch iterator object inherits from detailedActivity so it by default has all of the detail level attrs in it (but they are empty). As a user that is confusing because you see the dictionary element in the object return calories if you use .keys() so one would expect the value to be there.

i don't recall how it behaved previously. what would be the breakpoint if we were to address this and make sure only the items returned by the strava API were in the Activity class objects retrieved when looping through the iterator?

Screenshot 2024-01-20 at 1 00 06 PM

@martin-ueding
Copy link

Thank you for this detailed investigation!

I think that it will be hard to say what breaks when one returns the right class. But perhaps that breakage will be good! If somebody tries to use the calories field, it will be a hard error instead of the uninitialized values.

I'm not sure whether there is a soft approach to this that would give users tone to react before the breaking change, though.

@jsamoocha
Copy link
Collaborator

jsamoocha commented Jan 21, 2024

I'm not sure whether there is a soft approach to this that would give users [time] to react before the breaking change, though.

Yes, as an intermediate version we can introduce the correct subclasses that reflect Strava's response types, but catch AttributeErrors from missing attributes with a __getattr__() implementation that logs a warning and returns None (reflecting the current state of affairs).

I'd like to do this after we moved to a version 2.0 with removed backward compatibility hacks. That will make the above changes much easier.

@lwasser
Copy link
Collaborator

lwasser commented Jan 28, 2024

cool, i'll leave this open. maybe i can create a set of milestones related to post version 2.0 and we can at some point make a 2.0 migration set of milestone issues as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Active issue
Development

No branches or pull requests

4 participants