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

New Full Logbook #38

Merged
merged 16 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,28 @@ All [Aurora Climbing](https://auroraclimbing.com/) based boards (Kilter, Tension

To download your logbook entries for a given board:

`boardlib logbook <board_name> --username=<username> --output=<output_file_name>.csv --grade-type="hueco"`
`boardlib logbook <board_name> --username=<username> --output=<output_file_name>.csv --grade-type="hueco" --database=<local_database_file>`

This outputs a CSV file with the following fields:

```json
["board", "angle", "name", "date", "grade", "tries", "is_mirror"]
["board", "angle", "climb_name", "date", "logged_grade", "displayed_grade", "difficulty", "tries", "is_mirror", "sessions_count", "tries_total", "is_repeat", "is_ascent", "comment"]
```

For example, the command

`boardlib moon2017 --username="Luke EF" --output="moon2017.csv" --grade-type="hueco"`
`boardlib tension --username="Luke EF" --output="tension.csv" --grade-type="hueco" --database="tension.db"`

would output a file named `moon2017.csv` with the following contents:
would output a file named `tension.csv` with the following contents:

```
board,angle,name,date,grade,tries, is_mirror
moon2017,40,C3PO,2021-07-13,V5,1, False
moon2017,40,LITTLE BLACK SUBMARINE,2021-07-13,V5,2, False
moon2017,40,MOUNTAIN GOAT HARD,2021-07-13,V5,1, False
board,angle,climb_name,date,logged_grade,displayed_grade,difficulty,tries,is_mirror,sessions_count,tries_total,is_repeat,is_ascent,comment
tension,40,trash bag better,2024-06-17 16:21:23,V3,V3,16.0,3,False,1,3,False,True,
tension,40,Bumble,2024-06-17 16:28:23,V3,V3,16.0,1,True,1,1,False,True,
tension,40,sender2,2024-06-17 16:38:06,V5,V5,20.0,2,False,1,2,False,True,
...
```

When no local database is provided, displayed_grade and difficulty remain empty.
See `boardlib --help` for a full list of supported board names and feature flags.

#### Supported Boards 🛹
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ classifiers = [
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
dependencies = ["bs4", "requests"]
dependencies = ["bs4", "requests", "pandas"]

[project.scripts]
boardlib = "boardlib.__main__:main"
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
beautifulsoup4
requests
requests
pandas
48 changes: 25 additions & 23 deletions src/boardlib/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
import boardlib.api.moon
import boardlib.db.aurora

LOGBOOK_FIELDS = ("board", "angle", "name", "date", "grade", "tries", "is_mirror")

LOGBOOK_FIELDS = ("board", "angle", "climb_name", "date", "logged_grade", "displayed_grade", "difficulty", "tries", "is_mirror", "sessions_count", "tries_total", "is_repeat", "is_ascent", "comment")


def logbook_entries(board, username, password, grade_type="font", database=None):
Expand All @@ -27,29 +28,14 @@ def logbook_entries(board, username, password, grade_type="font", database=None)
raise ValueError(f"Unknown board {board}")


def write_entries(output_file, entries, no_headers=False):
writer = csv.DictWriter(output_file, LOGBOOK_FIELDS)

def write_entries(output_file, entries, no_headers=False, fields=LOGBOOK_FIELDS):
writer = csv.DictWriter(output_file, fieldnames=fields)
if not no_headers:
writer.writeheader()

writer.writerows(entries)


def handle_logbook_command(args):
env_var = f"{args.board.upper()}_PASSWORD"
password = os.environ.get(env_var)
if not password:
password = getpass.getpass("Password: ")
entries = logbook_entries(args.board, args.username, password, args.grade_type, args.database)

if args.output:
with open(args.output, "w", encoding="utf-8") as output_file:
write_entries(output_file, entries, args.no_headers)
else:
sys.stdout.reconfigure(encoding="utf-8")
write_entries(sys.stdout, entries, args.no_headers)


def handle_database_command(args):
if not args.database_path.exists():
args.database_path.parent.mkdir(parents=True, exist_ok=True)
Expand All @@ -62,6 +48,21 @@ def handle_database_command(args):
print(f"Synchronized {row_count} rows in {table_name}")


def handle_logbook_command(args):
env_var = f"{args.board.upper()}_PASSWORD"
password = os.environ.get(env_var)
if not password:
password = getpass.getpass("Password: ")
entries = boardlib.api.aurora.logbook_entries(args.board, args.username, password, args.grade_type, args.database)

if args.output:
with open(args.output, "w", encoding="utf-8") as output_file:
write_entries(output_file, entries.to_dict(orient="records"), args.no_headers, fields=LOGBOOK_FIELDS)
else:
sys.stdout.reconfigure(encoding="utf-8")
write_entries(sys.stdout, entries.to_dict(orient="records"), args.no_headers, fields=LOGBOOK_FIELDS)


def add_database_parser(subparsers):
database_parser = subparsers.add_parser(
"database", help="Download and sync the database"
Expand All @@ -82,10 +83,10 @@ def add_database_parser(subparsers):
)
database_parser.set_defaults(func=handle_database_command)


def add_logbook_parser(subparsers):
logbook_parser = subparsers.add_parser(
"logbook", help="Download logbook entries to CSV"
"logbook", help="Download full logbook entries (ascents and bids) to CSV"
)
logbook_parser.add_argument(
"board",
Expand All @@ -110,12 +111,12 @@ def add_logbook_parser(subparsers):
logbook_parser.add_argument(
"-d",
"--database",
help="Path to the local database (optional). Using a local database can significantly speed up the logbook generation. Create a local database with the 'boardlib database' command.",
help="Path to the local database (optional). Using a local database will significantly speed up the logbook generation and is required to retrieve 'displayed_grade' and 'difficulty'. Create a local database with the 'database' command.",
type=pathlib.Path,
required=False,
)
logbook_parser.set_defaults(func=handle_logbook_command)


def main():
parser = argparse.ArgumentParser()
Expand All @@ -126,5 +127,6 @@ def main():
args.func(args)



if __name__ == "__main__":
main()
Loading