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

Add a report-bikes-cummulative-distance command #14

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 27 additions & 1 deletion src/strava_offline/cli.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import datetime
from typing import TextIO
from typing import Optional, TextIO

import click

Expand Down Expand Up @@ -44,6 +44,11 @@

option_output = click.option('-o', '--output', type=click.File('w'), default='-', help="Output file")
option_year = click.argument('year', type=int, default=datetime.datetime.now().year)
option_year_start = click.argument('start_year', type=int, default=datetime.datetime.fromtimestamp(0).year)
option_year_end = click.argument('end_year', type=int, default=datetime.datetime.now().year)
option_time_resolution = click.option('-r', '--resolution', type=click.Choice(['day', 'month', 'year']), default='day')
option_output_format = click.option('-f', '--format', type=click.Choice(['plain', 'csv']), default='plain')
option_bike = click.option('-b', '--bike', type=str, required=False)


@cli.command(name='report-yearly')
Expand All @@ -65,6 +70,27 @@
with sync.database(config) as db:
print(reports.yearly_bikes(db, year), file=output)

@cli.command(name='report-bikes-cummulative-distance')

Check failure on line 73 in src/strava_offline/cli.py

View workflow job for this annotation

GitHub Actions / check (3.10)

expected 2 blank lines, found 1

Check failure on line 73 in src/strava_offline/cli.py

View workflow job for this annotation

GitHub Actions / check (3.9)

expected 2 blank lines, found 1

Check failure on line 73 in src/strava_offline/cli.py

View workflow job for this annotation

GitHub Actions / check (3.11)

expected 2 blank lines, found 1

Check failure on line 73 in src/strava_offline/cli.py

View workflow job for this annotation

GitHub Actions / check (3.12)

expected 2 blank lines, found 1

Check failure on line 73 in src/strava_offline/cli.py

View workflow job for this annotation

GitHub Actions / check (3.8)

expected 2 blank lines, found 1

Check failure on line 73 in src/strava_offline/cli.py

View workflow job for this annotation

GitHub Actions / check-distro (ubuntu:rolling)

expected 2 blank lines, found 1

Check failure on line 73 in src/strava_offline/cli.py

View workflow job for this annotation

GitHub Actions / check-distro (debian:oldstable)

expected 2 blank lines, found 1

Check failure on line 73 in src/strava_offline/cli.py

View workflow job for this annotation

GitHub Actions / check-distro (ubuntu:devel)

expected 2 blank lines, found 1

Check failure on line 73 in src/strava_offline/cli.py

View workflow job for this annotation

GitHub Actions / check-distro (debian:unstable)

expected 2 blank lines, found 1

Check failure on line 73 in src/strava_offline/cli.py

View workflow job for this annotation

GitHub Actions / check-distro (debian:stable)

expected 2 blank lines, found 1

Check failure on line 73 in src/strava_offline/cli.py

View workflow job for this annotation

GitHub Actions / check-distro (ubuntu:latest)

expected 2 blank lines, found 1
@config.DatabaseConfig.options()
@option_output
@option_time_resolution
@option_output_format
@option_bike
@option_year_start
@option_year_end
def cli_report_bikes_cummulative_distance(
config: config.DatabaseConfig,
output: TextIO,
resolution: str,
format: str,
bike: Optional[str],
start_year: int, end_year: int,
) -> None:
"Show monthly report by bike"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's actually daily, isn't it? Also probably wanna mention "cummulative" here as well :-)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! I probably changed the default and completely forgot about the docstr


with sync.database(config) as db:
print(reports.bikes_cummulative_distance(db, resolution, format, bike, start_year, end_year), file=output)


@cli.command(name='report-bikes')
@config.DatabaseConfig.options()
Expand Down
72 changes: 70 additions & 2 deletions src/strava_offline/reports.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
from io import StringIO
import sqlite3
import csv
from typing import Optional

from tabulate import tabulate


def tabulate_execute(db: sqlite3.Connection, sql: str, *params) -> str:
def tabulate_execute(db: sqlite3.Connection, sql: str, *params, format='plain') -> str:
# db.set_trace_callback(print)
# sqlite3.enable_callback_tracebacks(True)
table = (dict(row) for row in db.execute(sql, params))
return tabulate(table, headers='keys')
if format == 'csv':
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we turn this into a separate commit that adds configurable output formats to all reports, pls? You can steal some code from here: https://github.com/liskin/strava-gear/blob/0b6195ca6e08a8790998d2f0e756aba682a6d93c/src/strava_gear/cli.py#L42-L47
Also the strava-gear code passes the output stream to the report function instead of using StringIO, and that's probably better as well. I'll be happy to do this refactoring myself later but if you want to help I wouldn't mind :-)

table = list(table)
if len(table) == 0:
return ""

keys = list(table[0].keys())
stream = StringIO()
writer = csv.DictWriter(stream, keys)
writer.writeheader()
for row in table:
writer.writerow(row)

return stream.getvalue()

else:
return tabulate(table, headers='keys', tablefmt=format)


def yearly(db: sqlite3.Connection, year: int) -> str:
Expand Down Expand Up @@ -34,6 +54,54 @@
""", f"{year}-%")


def bikes_cummulative_distance(db: sqlite3.Connection, resolution: str, output_format: str, bike: Optional[str], start_year: int, end_year) -> str:

Check failure on line 57 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check (3.10)

line too long (147 > 120 characters)

Check failure on line 57 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check (3.9)

line too long (147 > 120 characters)

Check failure on line 57 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check (3.11)

line too long (147 > 120 characters)

Check failure on line 57 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check (3.12)

line too long (147 > 120 characters)

Check failure on line 57 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check (3.8)

line too long (147 > 120 characters)

Check failure on line 57 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (ubuntu:rolling)

line too long (147 > 120 characters)

Check failure on line 57 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (debian:oldstable)

line too long (147 > 120 characters)

Check failure on line 57 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (ubuntu:devel)

line too long (147 > 120 characters)

Check failure on line 57 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (debian:unstable)

line too long (147 > 120 characters)

Check failure on line 57 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (debian:stable)

line too long (147 > 120 characters)

Check failure on line 57 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (ubuntu:latest)

line too long (147 > 120 characters)
sql_template = """
WITH
daily AS (
SELECT
b.name AS "Bike"
,CASE
WHEN ? == "day" THEN strftime("%Y-%m-%d", a.start_date)
WHEN ? == "month" THEN strftime("%Y-%m-01", a.start_date)
WHEN ? == "year" THEN strftime("%Y-01-01", a.start_date)
END AS "Date"
,CAST(SUM(a.distance) / 1000.0 AS DOUBLE) AS "Distance (km)"
,CAST(SUM(a.moving_time) / 3600.0 AS DOUBLE) AS "Moving time (hour)"
,CAST(SUM(a.total_elevation_gain) AS DOUBLE) AS "Total Elevation (m)"
FROM activity a INNER JOIN bike b ON a.gear_id = b.id
GROUP BY 1, 2
)

,daily_with_cumsum AS (
SELECT
*
,SUM(`Distance (km)`) OVER (PARTITION BY Bike ORDER BY Date ASC) AS "Cummulative (km)"
,SUM(`Moving time (hour)`) OVER (PARTITION BY Bike ORDER BY Date ASC) AS "Cummulative (hour)"
,SUM(`Total Elevation (m)`) OVER (PARTITION BY Bike ORDER BY Date ASC) AS "Cummulative (elevation)"
FROM daily
)

SELECT
Bike
,Date
,printf("%.02f", `Distance (km)`) AS `Distance (km)`
,printf("%.02f", `Cummulative (km)`) AS `Cummulative (km)`
,printf("%.02f", `Total Elevation (m)`) AS `Total Elevation (m)`
,printf("%.02f", `Cummulative (elevation)`) AS `Cummulative (elevation)`
,printf("%.02f", `Moving Time (hour)`) AS `Moving Time (hour)`
,printf("%.02f", `Cummulative (hour)`) AS `Cummulative (hour)`
FROM daily_with_cumsum
WHERE
CAST(strftime("%Y", Date) AS INT) BETWEEN ? AND ?
AND
Bike LIKE ?
ORDER BY Bike ASC, Date ASC
"""

bike = bike or ""
return tabulate_execute(db, sql_template , resolution, resolution, resolution, start_year, end_year, f'{bike}%', format=output_format)

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check (3.10)

whitespace before ','

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check (3.10)

line too long (138 > 120 characters)

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check (3.9)

whitespace before ','

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check (3.9)

line too long (138 > 120 characters)

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check (3.11)

whitespace before ','

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check (3.11)

line too long (138 > 120 characters)

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check (3.12)

whitespace before ','

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check (3.12)

line too long (138 > 120 characters)

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check (3.8)

whitespace before ','

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check (3.8)

line too long (138 > 120 characters)

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (ubuntu:rolling)

whitespace before ','

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (ubuntu:rolling)

line too long (138 > 120 characters)

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (debian:oldstable)

whitespace before ','

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (debian:oldstable)

line too long (138 > 120 characters)

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (ubuntu:devel)

whitespace before ','

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (ubuntu:devel)

line too long (138 > 120 characters)

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (debian:unstable)

whitespace before ','

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (debian:unstable)

line too long (138 > 120 characters)

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (debian:stable)

whitespace before ','

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (debian:stable)

line too long (138 > 120 characters)

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (ubuntu:latest)

whitespace before ','

Check failure on line 102 in src/strava_offline/reports.py

View workflow job for this annotation

GitHub Actions / check-distro (ubuntu:latest)

line too long (138 > 120 characters)


def bikes(db: sqlite3.Connection) -> str:
return tabulate_execute(db, """
SELECT
Expand Down
Loading