interactive module to generate code/aliases to save things I do often
Project description
TL;DR: This converts a file like this (config file at ~/.config/ttally.py
):
# https://github.com/seanbreckenridge/ttally
from datetime import datetime
from typing import NamedTuple, Optional
class Weight(NamedTuple):
when: datetime
pounds: float
class Food(NamedTuple):
when: datetime
calories: int
food: str
quantity: float
water: int # how much ml of water was in this
@staticmethod
def attr_validators() -> dict:
# https://sean.fish/d/ttally_types.py?redirect
from my.config.seanb.ttally_types import prompt_float_default # type: ignore
# if I don't supply a quantity, default to 1
return {"quantity": lambda: prompt_float_default("quantity")}
class Event(NamedTuple):
"""e.g. a concert or something"""
event_type: str
when: datetime
description: str
score: Optional[int]
comments: Optional[str]
@staticmethod
def attr_validators() -> dict:
from my.config.seanb.ttally_types import edit_in_vim # type: ignore
return {"comments": edit_in_vim}
import os
from enum import Enum
with open(os.path.join(os.environ["HPIDATA"], "self_types.txt")) as f:
SelfTypes = Enum("SelfTypes", [s.rstrip().upper() for s in f])
class Self(NamedTuple):
when: datetime
what: SelfTypes # type: ignore
to (shell aliases)...
alias event='python3 -m ttally prompt event'
alias event-now='python3 -m ttally prompt-now event'
alias event-recent='python3 -m ttally recent event'
alias food='python3 -m ttally prompt food'
alias food-now='python3 -m ttally prompt-now food'
alias food-recent='python3 -m ttally recent food'
alias self='python3 -m ttally prompt self'
alias self-now='python3 -m ttally prompt-now self'
alias self-recent='python3 -m ttally recent self'
alias weight='python3 -m ttally prompt weight'
alias weight-now='python3 -m ttally prompt-now weight'
alias weight-recent='python3 -m ttally recent weight'
Whenever I run any of those aliases, it inspects the model in the config file, and on-the-fly creates and runs an interactive interface like this:
... which saves what I enter to a file:
- when: 1598856786,
glasses": 2.0
ttally
ttally
is an interactive module using autotui
to save things I do often to YAML/JSON
Currently, I use this to store info like whenever I eat something/drink water/my current weight/thoughts on concerts
Given a NamedTuple
defined in ~/.config/ttally.py
, this creates interactive interfaces which validates my input and saves it to a file
The {tuple}-now
aliases set the any datetime
values for the prompted tuple to now
This also gives me {tuple}-recent
aliases, which print recent items I've logged. For example:
$ water-recent 5
2021-03-20 18:23:24 2.0
2021-03-20 01:28:27 1.0
2021-03-19 23:34:12 1.0
2021-03-19 22:49:05 1.5
2021-03-19 16:05:34 1.0
The -recent
aliases can accept all
to print all items, or a duration like 1d
or 6h
to print data from the last few hours/days.
Why/How
Goals
- validates my user input to basic types
- stores it as a user-editable format (YAML)
- can be loaded into python as typed objects
- minimal boilerplate to add a new model
- can be synced across multiple machines without conflicts
- allow completely custom types or prompts - see autotui docs, my custom prompts
This intentionally uses YAML and doesn't store the info into a single "merged" database. That way:
- you can just open the YAML file and quickly change/edit some item, no need to re-invent a CRUD interface (though
ttally edit-recent
does exist) - files can be synced across machines and to my phone using syncthing without file conflicts
- prevents issues with trying to merge multiple databases from different machines together (I've tried)
The YAML files are versioned with the date/OS/platform, so I'm able to add items on my linux, mac, or android (using termux
) and sync them across all my devices using SyncThing
. Each device creates its own file it adds items to, like:
food-darwin-seans-mbp.localdomain-2021-03.yaml
food-linux-bastion-2021-03.yaml
food-linux-localhost-2021-04.yaml
... which can then be combined back into python, like:
>>> from more_itertools import take # just to grab a few items
>>> from ttally.__main__ import ext
>>> from ttally.config import Food
>>> take(3, ext.glob_namedtuple(Food))
[Food(when=datetime.datetime(2020, 9, 27, 6, 49, 34, tzinfo=datetime.timezone.utc), calories=440, food='ramen, egg'),
Food(when=datetime.datetime(2020, 9, 27, 6, 52, 16, tzinfo=datetime.timezone.utc), calories=160, food='2 eggs'),
Food(when=datetime.datetime(2020, 9, 27, 6, 53, 44, tzinfo=datetime.timezone.utc), calories=50, food='ginger chai')]
... or into JSON using ttally export food
The from-json
command can be used to send this JSON which matches a model, i.e. providing a non-interactive interface to add items, in case I want to call this from a script
hpi query
from HPI
can be used with the ttally.__main__
module, like:
# how many calories in the last day
$ hpi query ttally.__main__.food --recent 1d -s | jq -r '(.quantity)*(.calories)' | datamash sum 1
2252
If you'd prefer to use JSON files, you can set the TTALLY_EXT=json
environment variable.
This can load data from YAML or JSON (or both at the same time), every couple months I'll combine all the versioned files to a single merged file using the merge
command:
ttally merge food
Installation
pip install ttally
Usage: ttally [OPTIONS] COMMAND [ARGS]...
Tally things that I do often!
Given a few namedtuples, this creates serializers/deserializers and an
interactive interface using 'autotui', and aliases to:
prompt using default autotui behavior, writing to the ttally datafile, same
as above, but if the model has a datetime, set it to now, query the 10 most
recent items for a model
Options:
--help Show this message and exit.
Commands:
datafile print the datafile location
edit edit the datafile
edit-recent fuzzy select/edit recent items
export export all data from a model
from-json add item by piping JSON
generate generate shell aliases
merge merge all data for a model into one file
models list models
prompt tally an item
prompt-now tally an item (now)
recent print recently tallied items
update-cache cache export data
Configuration
You need to setup a ~/.config/ttally.py
file. You can use the block above as a starting point, or with mine:
curl -s 'https://sean.fish/d/ttally.py' > ~/.config/ttally.py
To setup aliases; You can do it each time you launch you terminal like:
eval "$(python3 -m ttally generate)"
Or, 'cache' the generated aliases by putting a block like this in your shell config:
TTALLY_ALIASES="${HOME}/.cache/ttally_aliases"
if [[ ! -e "${TTALLY_ALIASES}" ]]; then # alias file doesn't exist
python3 -m ttally generate >"${TTALLY_ALIASES}" # generate and save the aliases
fi
source "${TTALLY_ALIASES}" # make aliases available in your shell
i.e., it runs the first time I open a terminal, but then stays the same until I remove the file
You can set the TTALLY_DATA_DIR
environment variable to the directory that ttally
should save data to, defaults to ~/.local/share/ttally
. If you want to use a different path for configuration, you can set the TTALLY_CFG
to the absolute path to the file.
For shell completion to autocomplete options/model names:
eval "$(_TTALLY_COMPLETE=bash_source ttally)" # in ~/.bashrc
eval "$(_TTALLY_COMPLETE=zsh_source ttally)" # in ~/.zshrc
eval "$(_TTALLY_COMPLETE=fish_source ttally)" # in ~/.config/fish/config.fish
Caching
ttally update-cache
can be used to speedup the export
and recent
commands:
Usage: ttally update-cache [OPTIONS]
Caches data for 'export' and 'recent' by saving the current data and an
index to ~/.cache/ttally
exit code 0 if cache was updated, 2 if it was already up to date
Options:
--print-hashes print current filehash debug info
--help Show this message and exit.
I personally run it once every 3 minutes in the background, so at least my first interaction with ttally
is guaranteed to be fast
Default cache directory can be overwritten with the TTALLY_CACHE_DIR
environment variable
Subclassing/Extension
The entire ttally
library/CLI can also be subclassed/extended for custom usage, by using ttally.core.Extension
class and wrap_cli
to add additional click commands. For an example, see flipflop.py
Shell Scripts
cz
lets me fuzzy select something I've eaten in the past using fzf
, like:
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file ttally-0.1.4.tar.gz
.
File metadata
- Download URL: ttally-0.1.4.tar.gz
- Upload date:
- Size: 22.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 96f945a4a8f36638d2eeefef0c0e9788916490766d90b6ce5e4c23a01d4036cf |
|
MD5 | 3b5b1c63edc142b0622cb29beffbacdb |
|
BLAKE2b-256 | 14fccf0ed2cf01d65d58edb05db9a56acbb5867e1b9b501ca3feca24a2a3e89d |
File details
Details for the file ttally-0.1.4-py3-none-any.whl
.
File metadata
- Download URL: ttally-0.1.4-py3-none-any.whl
- Upload date:
- Size: 18.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5b0cd23c88e90e3fff1a8ec8607fe1b7e1151fcae0caf8171e94facc473826b6 |
|
MD5 | 4c791ecf522f5f669df1ea0fc1f3ff24 |
|
BLAKE2b-256 | 09d482729d81fb1721f0008affd40e46213a40b407e43b4691ed41776a8226de |