Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
edefaca
Update readme.markdown
hannahburkhardt Apr 4, 2022
52446ce
Fix black installation issue in CI flow (#138)
hannahburkhardt Apr 4, 2022
4c402a4
functionality for getting reports updated (#140)
AlanGrenfell Apr 29, 2022
5c6bc75
Negative values export as positive (#143)
judgewooden Jul 27, 2022
af516ff
Updates python-myfitnesspal to use browser_cookie3 for gathering logi…
coddingtonbear Aug 27, 2022
69d5edc
Updates python-myfitnesspal to use browser_cookie3 for gathering logi…
coddingtonbear Aug 27, 2022
bf0360b
Bump version: 1.17.0 → 2.0.0
coddingtonbear Aug 27, 2022
892dd4c
Updating 'rich' requirement version.
coddingtonbear Aug 27, 2022
ce21cc5
Updating docs.
coddingtonbear Aug 27, 2022
d6f16b3
Adding 'Upgrading to 2.x' doc.
coddingtonbear Aug 27, 2022
ee1b811
Doc formatting changes.
coddingtonbear Aug 27, 2022
989137d
Adding instuctions for helping people log into myfitnesspal when runn…
coddingtonbear Sep 11, 2022
934960e
146 fix get report datetime issue (#147)
hannahburkhardt Oct 26, 2022
223995b
[#147] Minor style fixes.
coddingtonbear Jan 16, 2023
d066812
Bump version: 2.0.0 → 2.0.1
coddingtonbear Jan 16, 2023
09c5fee
Isolate execution flow for friend shared diary (#153)
sean-freeman Mar 28, 2023
3378a78
- measurements/edits now expects the (escaped) measurement name, not …
hannahburkhardt May 27, 2023
452bfbd
unit test and formatting fixes
hannahburkhardt May 28, 2023
a66cbe5
more black and flake8 lint fixes
hannahburkhardt May 28, 2023
db822aa
Remove `utf8` field from the search request as it seems to no longer …
hannahburkhardt Jun 3, 2023
9baf832
Handle non-existed nutritional info in search results (#160)
hannahburkhardt Jun 3, 2023
596970d
Merge pull request #161 from coddingtonbear/151_get_measurements_problem
coddingtonbear Jun 16, 2023
50b7964
[168] Adding some changes that make it possible to get more insight i…
coddingtonbear Dec 3, 2023
cd13674
Fixing a bug in which not logging requests would cause an error due t…
coddingtonbear Jan 4, 2024
1bbda81
Use cloudscraper for performing requests; thanks @qmirioni!
coddingtonbear Jan 4, 2024
cecd11a
Mypy corrections.
coddingtonbear Jan 4, 2024
3cf3be1
Mypy corrections.
coddingtonbear Jan 4, 2024
66185f8
Bump version: 2.0.1 → 2.1.0
coddingtonbear Jan 4, 2024
5804294
update URL and path to result data
hannahburkhardt Aug 21, 2024
522ef7c
Merge pull request #184 from hannahburkhardt/177_get-report-update
coddingtonbear Mar 9, 2025
2ab167a
Updating python spec versions to be a little morre modern.
coddingtonbear Mar 9, 2025
c6c0003
Modernization.
coddingtonbear Mar 9, 2025
14ab98a
Specify python versions as strings.
coddingtonbear Mar 9, 2025
75ba9ae
Fixing a test, updating lxml to require 5.x version.
coddingtonbear Mar 9, 2025
70e8fa0
Release 2.1.1; adds fixes for report gathering.
coddingtonbear Mar 9, 2025
cffb0fa
Explicitly declare which directory is our package.
coddingtonbear Mar 9, 2025
539fa51
Bump version: 2.1.1 → 2.1.2
coddingtonbear Mar 9, 2025
661ad6e
fix: removes cloudscraper causing 403
ThisALV Jul 13, 2025
a4702d1
Merge pull request #197 from ThisALV/fix-403-auth
coddingtonbear Sep 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 1.17.0
current_version = 2.1.2
commit = True
tag = True
tag_name = {new_version}
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: 3.8
python-version: "3.13"

- name: Install Python dependencies
run: pip install black==20.8b1 flake8==3.8.3
run: pip install black==22.6.0 flake8==5.0.4

- name: Run linters
uses: samuelmeuli/lint-action@v1.5.3
uses: wearerequired/lint-action
with:
github_token: ${{ secrets.github_token }}
# Enable linters
Expand Down
5 changes: 1 addition & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.7, 3.8]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v2
Expand All @@ -24,6 +24,3 @@ jobs:
- name: Test with pytest
run: |
pytest
env:
MFP_INTEGRATION_TESTING_USERNAME: ${{ secrets.MFP_INTEGRATION_TESTING_USERNAME }}
MFP_INTEGRATION_TESTING_PASSWORD: ${{ secrets.MFP_INTEGRATION_TESTING_PASSWORD }}
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ share/*
pip-selfcheck.json
env/*
.vscode/*
.mypy_cache/*
.mypy_cache/*
.idea/
venv/
24 changes: 10 additions & 14 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,31 @@ repos:
# Sort imports prior to black reformatting, to
# ensure black always takes prescedence
- repo: https://github.com/timothycrosley/isort
rev: 4.3.21
rev: 6.0.1
hooks:
- id: isort
- repo: https://github.com/ambv/black
rev: 20.8b1
rev: 25.1.0
hooks:
- id: black
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.4.0
- repo: https://github.com/pycqa/flake8
rev: 7.1.2
hooks:
- id: end-of-file-fixer
files: '.*\.py$'
- id: flake8
additional_dependencies:
- flake8-bugbear==19.3.0
- flake8-printf-formatting==1.1.0
- flake8-pytest==1.3
- flake8-pytest-style==0.1.3
- repo: https://github.com/asottile/pyupgrade
rev: v1.25.1
rev: v3.19.1
hooks:
- id: pyupgrade
args: ["--py37-plus"]
args: ["--py39-plus"]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.782
rev: v1.15.0
hooks:
- id: mypy
args:
- --pretty
- --show-error-codes
- --show-error-context
- --ignore-missing-imports
additional_dependencies:
- types-requests
- types-python-dateutil
4 changes: 4 additions & 0 deletions changelog.markdown
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 2.0.0 (2022-08-26)

* Now uses the [`browser_cookie3`](https://github.com/borisbabic/browser_cookie3) library for gathering log in credentials instead of logging in to MyFitnessPal directly. This became necessary due to the recent addition of a hidden captcha in the log-in flow for MyFitnessPal; see [Issue #144](https://github.com/coddingtonbear/python-myfitnesspal/issues/144) for details.

# 1.13 (2018-11-20)

* Adds support for searching for food items and accessing their nutritional values. Thanks @pydolan!
Expand Down
20 changes: 4 additions & 16 deletions docs/source/cmdline.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,11 @@ Using the Command-Line API

Although most people will probably be using Python-MyFitnessPal as a way
of integrating their MyFitnessPal data into another application,
Python-MyFitnessPal does provide a command-line API with a handful of
commands described below.
Python-MyFitnessPal does provide a command-line API with a single
command described below.

``store-password $USERNAME``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Store a password for a given MyFitnessPal account in your system’s
keyring.

``delete-password $USERNAME``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Delete a password for a given MyFitnessPal account from your system
keyring.

``day $USERNAME [$DATE]``
~~~~~~~~~~~~~~~~~~~~~~~~~
``day [$DATE]``
~~~~~~~~~~~~~~~

Display meals and totals for a given date. If no date is specified,
totals will be printed for today.
33 changes: 20 additions & 13 deletions docs/source/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,23 @@ You can either install from pip::
Authentication
--------------

It is a good security practice to not type out the passwords for any of your services (including MyFitnessPal) in either a source file or in the console in such a way that somebody else might be able to read them. Toward that end, python-myfitnesspal allows you to use your system keyring.

To store your MyFitnessPal password in the system keyring, run::

myfitnesspal store-password my_username

You will immediately be asked for your password, and that password will be stored in your system keyring for later interactions with MyFitnessPal.

Please note that all examples below *assume* you've stored your password in your system keyring like above, but you can also provide your password by providing your password as a keyword argument to the `myfitnesspal.Client` instance:

.. code:: python

client = myfitnesspal.Client('my_username', password='my_password')
This library uses your local browser's MyFitnessPal cookies
for interacting with MyFitnessPal via the `browser_cookie3 <https://github.com/borisbabic/browser_cookie3>`_ library.
To control which user account this library uses for interacting with MyFitnessPal,
just log in to the appropriate account in your browser
and,
with a bit of luck,
python-myfitnesspal should be able to find the authentication credentials needed.

By default, this library will look for cookies set for the ``www.myfitnesspal.com`` and ``myfitnesspal.com`` domains in all browsers supported by ``browser_cookie3``. You can control which cookiejar is used by passing a ``http.cookiejar.CookieJar`` object via the constructor's `cookiejar` keyword parameter. See `browser_cookie3's readme <https://github.com/borisbabic/browser_cookie3>`_ for details around how you might select a cookiejar from a particular browser.

.. note::

Starting on August 25th, 2022, MyFitnessPal added
a hidden captcha to their login flow.
That change unfortunately prevents this library from logging-in directly,
and as of version 2.0 of python-myfitnesspal,
this library now relies on reading browser cookies directly
for gathering login credentials.

See `Issue #144 <https://github.com/coddingtonbear/python-myfitnesspal/issues/144>`_ for details and context.
4 changes: 2 additions & 2 deletions docs/source/how_to/diary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ To access a single day’s information:

import myfitnesspal

client = myfitnesspal.Client('my_username')
client = myfitnesspal.Client()

day = client.get_date(2013, 3, 2)
day
Expand Down Expand Up @@ -133,7 +133,7 @@ argument.

.. code:: python

client = myfitnesspal.Client('my_username', unit_aware=True)
client = myfitnesspal.Client(unit_aware=True)
day = client.get_date(2013, 3, 2)
lunch = day['lunch']
print lunch
Expand Down
4 changes: 2 additions & 2 deletions docs/source/how_to/exercises.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ To get a list of cardiovascular exercises

import myfitnesspal

client = myfitnesspal.Client('my_username')
client = myfitnesspal.Client()

day = client.get_date(2019, 3, 12)

Expand All @@ -38,7 +38,7 @@ To get a list of strength exercises

import myfitnesspal

client = myfitnesspal.Client('my_username')
client = myfitnesspal.Client()

day = client.get_date(2019, 3, 12)

Expand Down
4 changes: 2 additions & 2 deletions docs/source/how_to/food_search.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ To search for items:

import myfitnesspal

client = myfitnesspal.Client('my_username')
client = myfitnesspal.Client()

food_items = client.get_food_search_results("bacon cheeseburger")
food_items
Expand All @@ -34,7 +34,7 @@ To get details for a particular food:

import myfitnesspal

client = myfitnesspal.Client('my_username')
client = myfitnesspal.Client()

item = client.get_food_item_details("89755756637885")
item.servings
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
Accessing a Friend’s Diary
==========================

If a friend has their diary visibility set to public, you can grab their
If a friend has their diary visibility set to "Public", you can grab their
diary entries:

.. code:: python

import myfitnesspal

client = myfitnesspal.Client()

friend_day = client.get_date(2020, 8, 23, username="username_of_my_friend")
>>> friend_day
<08/23/20 {'calories': 891.0, 'carbohydrates': 105.0, 'fat': 38.0, 'protein': 29.0, 'sodium': 0.0, 'sugar': 2.0}>
54 changes: 54 additions & 0 deletions docs/source/how_to/friends_diary_shared.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
Accessing a Friend’s Diary (Shared)
===================================

If a friend has their diary visibility set to "Friends Only", you can grab their
diary entries.

To access a single day’s information:

.. code:: python

import myfitnesspal

client = myfitnesspal.Client()

friend_day = client.get_date(2020, 8, 23, friend_username="username_of_my_friend")

friend_day
# >> <03/02/13 {'sodium': 3326, 'carbohydrates': 369, 'calories': 2001, 'fat': 22, 'sugar': 103, 'protein': 110}>

friend_day.totals
# >> {'calories': 2001,
# 'carbohydrates': 369,
# 'fat': 22,
# 'protein': 110,
# 'sodium': 3326,
# 'sugar': 103}

friend_day.meals
# >> [<Breakfast {}>,
# <Lunch {'sodium': 712, 'carbohydrates': 106, 'calories': 485, 'fat': 3, 'sugar': 0, 'protein': 17}>,
# <Dinner {'sodium': 2190, 'carbohydrates': 170, 'calories': 945, 'fat': 11, 'sugar': 17, 'protein': 53}>,
# <Snacks {'sodium': 424, 'carbohydrates': 93, 'calories': 571, 'fat': 8, 'sugar': 86, 'protein': 40}>]


To access a week’s information with a loop on a date range:

.. code:: python

import datetime

start_date = datetime.date(2023, 2, 18)
end_date = datetime.date(2023, 2, 25)

friend_shared_diary_data = []

for day in range(int((end_date - start_date).days)):
loop_year=((start_date + datetime.timedelta(day)).strftime("%Y"))
loop_month=((start_date + datetime.timedelta(day)).strftime("%m"))
loop_day=((start_date + datetime.timedelta(day)).strftime("%d"))
loop_pretty_date=str(start_date + datetime.timedelta(day))
diary_day_data = client.get_date(loop_year, loop_month, loop_day, friend_username="username_of_my_friend")
friend_shared_diary_data.append({loop_pretty_date: diary_day_data.totals})

print(friend_shared_diary_data)
2 changes: 2 additions & 0 deletions docs/source/how_to/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ How-to Guides
exercises
measurements
food_search
reports
use_with_wsl
2 changes: 1 addition & 1 deletion docs/source/how_to/measurements.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ To access measurements from the past 30 days:

import myfitnesspal

client = myfitnesspal.Client('my_username')
client = myfitnesspal.Client()

weight = client.get_measurements('Weight')
weight
Expand Down
50 changes: 50 additions & 0 deletions docs/source/how_to/reports.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Accessing Reports
=================

To access report data from the past 30 days:

.. code:: python

import myfitnesspal

client = myfitnesspal.Client()

client.get_report(report_name="Net Calories", report_category="Nutrition")
# >> OrderedDict([(datetime.date(2015, 5, 14), 1701.0), (datetime.date(2015, 5, 13), 1732.8), (datetime.date(2015, 5,12), 1721.8),
# (datetime.date(2015, 5, 11), 1701.6), (datetime.date(2015, 5, 10), 1272.4), (datetime.date(2015, 5, 9), 1720.2),
# (datetime.date(2015, 5, 8), 1071.0), (datetime.date(2015, 5, 7), 1721.2), (datetime.date(2015, 5, 6), 1270.8),
# (datetime.date(2015, 5, 5), 1701.8), (datetime.date(2015, 5, 4), 1724.2), (datetime.date(2015, 5, 3), 1722.2),
# (datetime.date(2015, 5, 2), 1701.0), (datetime.date(2015, 5, 1), 1721.2), (datetime.date(2015, 4, 30), 1721.6),
# (datetime.date(2015, 4, 29), 1072.4), (datetime.date(2015, 4, 28), 1272.2), (datetime.date(2015, 4, 27), 1723.2),
# (datetime.date(2015, 4, 26), 1791.8), (datetime.date(2015, 4, 25), 1720.8), (datetime.date(2015, 4, 24), 1721.2),
# (datetime.date(2015, 4, 23), 1721.6), (datetime.date(2015, 4, 22), 1723.2), (datetime.date(2015, 4, 21), 1724.2),
# (datetime.date(2015, 4, 20), 1273.6), (datetime.date(2015, 4, 19), 1721.8), (datetime.date(2015, 4, 18), 1720.4),
# (datetime.date(2015, 4, 17), 1629.8), (datetime.date(2015, 4, 16), 1270.4), (datetime.date(2015, 4, 15), 1270.8),
# (datetime.date(2015, 4, 14), 1721.6)])

.. code:: python

import datetime

may = datetime.date(2015, 5, 1)

client.get_report("Net Calories", "Nutrition", may)
# >> OrderedDict([(datetime.date(2015, 5, 14), 172.8), (datetime.date(2015, 5, 13), 173.1), (datetime.date(2015, 5, 12), 127.7),
# (datetime.date(2015, 5, 11), 172.7), (datetime.date(2015, 5, 10), 172.8), (datetime.date(2015, 5, 9), 172.4),
# (datetime.date(2015, 5, 8), 172.6), (datetime.date(2015, 5, 7), 172.7), (datetime.date(2015, 5, 6), 172.6),
# (datetime.date(2015, 5, 5), 172.9), (datetime.date(2015, 5, 4), 173.0), (datetime.date(2015, 5, 3), 172.6),
# (datetime.date(2015, 5, 2), 172.6), (datetime.date(2015, 5, 1), 172.7)])

To access report data within a date range:

.. code:: python

thisweek = datetime.date(2015, 5, 11)
lastweek = datetime.date(2015, 5, 4)

client.get_report("Net Calories", "Nutrition", thisweek, lastweek)
# >> OrderedDict([(datetime.date(2015, 5, 11), 1721.6), (datetime.date(2015, 5, 10), 1722.4), (datetime.date(2015, 5,9), 1720.2),
# (datetime.date(2015, 5, 8), 1271.0), (datetime.date(2015, 5, 7), 1721.2), (datetime.date(2015, 5, 6), 1720.8),
# (datetime.date(2015, 5, 5), 1721.8), (datetime.date(2015, 5, 4), 1274.2)])

Report data is returned as ordered dictionaries. The first argument specifies the report name, the second argument specifies the category name - both of which can be anything listed in the MyFitnessPal `Reports <https://www.myfitnesspal.com/reports>`_ page. When specifying a date range, the order of the date arguments does not matter.
11 changes: 11 additions & 0 deletions docs/source/how_to/use_with_wsl.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Use on Windows Subsystem for Linux
==================================

When using python-myfitnesspal on Windows via Windows Subsystem for Linux
you will encounter one extra complication when logging in
due to the mechanism python-myfitnesspal uses
for gathering authentication credentials.

You must log in to MyFitnessPal
via a browser installed on your guest (Linux) installation
instead of via one installed the conventional way.
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Python Myfitnesspal
how_to/index
contributing
api/index
upgrading

Do you track your eating habits on `MyFitnessPal <https://www.myfitnesspal.com/>`_? Have you ever wanted to analyze the information you're entering into MyFitnessPal programatically?

Expand Down
Loading