command line tool for organizing finances
Project description
FINANCEAGER
An application (possibly running as Flask webservice) that helps you administering your daily expenses and earnings. Interact via the command line interface.
The financeager
backend holds databases (internally referred to as 'periods'). A period contains entries of a certain year.
Quickstart
Who is this for?
You might be someone who wants to organize finances with a simple software because you're tired of Excel and the like. And you like the command line. And Python.
NOTE
The project is actively developed. Expect things to break - e.g. the command line interface, the REST API definitions, ... - before version 1.0.0 is released.
Installation
From PyPI package
pip install financeager
Using pipx
If you're using Python >= 3.6 and have pipx
installed, install financeager
into an isolated environment via
pipx install financeager
From source (master branch)
Clone the repo
git clone https://github.com/pylipp/financeager
cd financeager
Create a virtual environment
python -m venv --python=$(which python3) .venv
source .venv/bin/activate
Install
pip install --upgrade --editable .
Alternatively, you can omit the second and third step and install financeager
to ~/.local
with (requires pip3
)
pip3 install . --user
Usage
You can use financeager
as a client-server or a serverless application (default). The user interacts via the command line interface (CLI).
Serverless mode
The user request invoked from the CLI is passed to the backend which opens the appropriate database, processes the request, closes the database and returns a response. All communication happens within a single process, hence the label 'serverless'. The databases are stored in ~/.local/share/financeager
.
Client-server mode
To run financeager
as client-server application, start the flask webservice by
export FLASK_APP=financeager/fflask.py
flask run # --help for more info
This does not store data persistently! Specify the environment variable
FINANCEAGER_DATA_DIR
.
For production use, you should wrap
app = fflask.create_app(data_dir=...)
in a WSGI or FCGI (seeexamples/
directory).
To communicate with the webservice, the financeager
configuration has to be adjusted. Create and open the file ~/.config/financeager/config
. If you're on the machine that runs the webservice, put the lines
[SERVICE]
name = flask
If you're on an actual remote 'client' machine, put
[SERVICE]
name = flask
[SERVICE:FLASK]
host = https://foo.pythonanywhere.com
timeout = 10
username = foouser
password = S3cr3t
This specifies the timeout for HTTP requests and username/password for basic auth, if required by the server.
In any case, you're all set up! See the next section about the available client CLI commands and options.
Command line client
usage: financeager [-h] [-V] {add,get,remove,update,copy,list,periods} ...
optional arguments:
-h, --help show this help message and exit
-V, --version display version info and exit
subcommands:
{add,get,remove,update,copy,list,periods}
list of available subcommands
add add an entry to the database
get show information about single entry
remove remove an entry from the database
update update one or more fields of an database entry
copy copy an entry from one period to another
list list all entries in the period database
periods list all period databases
On the client side, financeager
provides the following commands to interact with the backend: add
, update
, remove
, get
, list
, periods
, copy
.
Add earnings (no/positive sign) and expenses (negative sign) to the database:
> financeager add burgers -19.99 --category Restaurants
> financeager add lottery 123.45 --date 03-14
Category and date can be optionally specified. They default to None and the current day's date, resp. financeager
will try to derive the entry category from the database if not specified. If several matches are found, the default category is used.
Add recurrent entries using the -t recurrent
flag (t
for table name) and specify the frequency (yearly, half-yearly, quarterly, bi-monthly, monthly, weekly, daily) with the -f
flag and optionally start and end date with the -s
and -e
flags, resp.
> financeager add rent -500 -t recurrent -f monthly -s 01-01 -c rent
If not specified, the start date defaults to the current date and the end date to the last day of the database's year.
Did you make a mistake when adding a new entry? Update one or more fields by calling the update
command with the entry's ID and the respective corrected fields:
> financeager update 1 --name "McKing Burgers" --value -18.59
Remove an entry by specifying its ID (visible in the output of the list
command). This removes the burgers
entry:
> financeager remove 1
This would remove the recurrent rent entries (ID is also 1 because standard and recurrent entries are stored in separate tables):
> financeager remove 1 --table-name recurrent
Show a side-by-side overview of earnings and expenses (filter by date/category/name/value by passing the --filters
option, e.g. --filters category=food
to show entries in the categories food
)
> financeager list
Earnings | Expenses
Name Value Date ID | Name Value Date ID
Unspecified 123.45 | Rent 1500.00
Lottery 123.45 03-14 2 | Rent January 500.00 01-01 1
| Rent February 500.00 02-01 1
| Rent March 500.00 03-01 1
=============================================================================
Total 123.45 | Total 1500.00
The aforementioned financeager
commands operate on the default database (named by the current year, e.g. 2017) unless another period is specified by the --period
flag.
> financeager add xmas-gifts -42 --date 12-23 --period 2016
Copy an entry from one database to another by specifying entry ID and source/destination period:
> financeager copy 1 --source 2017 --destination 2018
Detailed information is available from
> financeager --help
> financeager <subcommand> --help
You can turn on printing debug messages to the terminal using the --verbose
option, e.g.
> financeager list --verbose
You can find a log of interactions at ~/.local/share/financeager/log
(on both the client machine and the server).
More on configuration
Besides specifying the backend to communicate with, you can also configure frontend options: the name of the default category (assigned when omitting the category option when e.g. adding an entry) and the date format (string that datetime.strptime
understands; note the double percent). The defaults are:
[FRONTEND]
default_category = unspecified
date_format = %%m-%%d
The financeager
command line client tries to read the configuration from ~/.config/financeager/config
. You can specify a custom path by passing it along with the -C
/--config
command line option.
More Goodies
financeager
will store requests if the server is not reachable (the timeout is configurable). The offline backup is restored the next time a connection is established. This feature is only available when running financeager with flask.
Expansion
Want to use a different database? Should be straightforward by deriving from Period
and implementing the _entry()
methods. Modify the Server
class accordingly to use the new period type.
Architecture
The following diagram sketches the relationship between financeager's modules. See the module docstrings for more information.
+--------+ +-----------+ +---------+
| config |-->| cli |<->| offline |
+--------+ +-----------+ +---------+
¦ Λ
V ¦
+-------------------------------------+
| communication |
+-------------------------------------+
+---------+ +---------+
[pre-processing] [formatting] <-- | listing | <-- | entries |
+---------+ +---------+
¦ Λ
V ¦
+--------------+ | +--------------+
| httprequests | | | | FRONTEND
+--------------+ | | |
================ | | | ==========
+--------------+ | | localserver |
| fflask | | | | BACKEND
+--------------+ | | |
| resources | | | |
+--------------+ | +--------------+
¦ Λ
V ¦
+-------------------------------------+
| server |
+-------------------------------------+
¦ Λ
V ¦
+-------------------------------------+
| period |
+-------------------------------------+
Known bugs
- see issues
- Please. Report. Them.
Contributing
Always welcome! For installation, follow the steps above (section 'From source') and install development dependencies via
pip install --upgrade --editable .[develop]
pre-commit install
gitlint install-hook
You're all set for hacking! Please adhere to test-driven development, if possible: When adding a feature, or fixing a bug, try to construct a test first, and subsequently adapt the implementation. Run the tests from the root directory via
python setup.py test
If you added a non-cosmetic change (i.e. a change in functionality, e.g. a bug fix or a new feature), please update Changelog.md
accordingly as well. Check this README whether the content is still up to date.
Releasing
- Tag the latest commit on master by incrementing the current version accordingly (scheme
v0.X
). - Run
make release
.
financeager
features
Ideas
- experiment with urwid for building TUI or remi for HTML-based GUI
- support querying of standard/recurrent table with
list
- return element data as response to add/copy/update request
- support passing multiple elements IDs to update/remove/copy/get (maybe together with asynchronous HTTP requests)
- extended period names (something along
2018-personal
) - support
list
at date other than today
Discarded ideas
- select from multiple options if possible (e.g. when searching or deleting an entry): breaks the concept of having a single request-response action. Instead, the user is expected to know which element he wants to delete (by using the element ID) and can give a precise command
Roadmap for release of version 1.0
This requires some restructuring of the software architecture. Motivation and goals are outlined below.
Status quo
- module functionalities and responsibilities particularly overlap
- also apparent in test code: no clear distinction between integration and unit tests
Goals
- three separated top modules: core, backend, client
- responsibilities:
- core:
- constants
- configuration (maybe move to client)
- exceptions
- backend:
- interfaces (localserver, fflask)
- REST API (resources)
- database management (server, period)
- client
- CLI
- communication pre-/post-processing
- HTTP requests
- response formatting (entries, listing)
- core:
- consistent, modular test structure
- pave way for terminal user interface
TODOs
- remove TinyDB usage from model and entries
- remove entries import from period
- more fine-grained error-handling in period (distinguish between errors during validation and about non-existing elements)
- integration test of cli module
- move data dir to ~/.local/share/financeager
- install pre-commit framework
- use logging module instead of print
- use marshmallow package for keyword validation/serialization in period and resources
- have return codes in cli.run
- introduce
verbose
cli option - add loggers to config and offline modules
- add loggers to resources and server
- avoid test code interfering with actual file system content
- test offline feature with 'none' backend
- rename 'model' to 'listing'
- clean up
test_communication
PERSONAL NOTE
This is a 'sandbox' project of mine. I'm exploring and experimenting with databases, data models, server applications (Pyro4
and flask
), frontends (command line, Qt-based GUI), software architecture, programming best practices (cough) and general Python development.
Feel free to browse the project and give feedback (comments, issues, pull requests).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
File details
Details for the file financeager-0.22-py2.py3-none-any.whl
.
File metadata
- Download URL: financeager-0.22-py2.py3-none-any.whl
- Upload date:
- Size: 44.2 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.1.0 requests-toolbelt/0.9.1 tqdm/4.32.1 CPython/3.5.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 056a2a1abbd66edab21c667a67a8345132386a4a62cf4bf035e40a4b9fba14f7 |
|
MD5 | ec3de96db476a35c99122e4e068184b5 |
|
BLAKE2b-256 | 45b4bc1c2481f75aaee48d30c8960fc8fa7a3276c95b4bb7e435ce62b163921e |