Skip to content

Commit

Permalink
Documentation (#12)
Browse files Browse the repository at this point in the history
* Start adding documentation strings to methods

Beginning the work of getting the code base ready to upload to pypi.

* Adding documentation to reports

Also starting to clean up how the report methods are called.  Don't like
how the documentation looks when passing a configuration dictionary in
as the only parameter, instead will pass in **configuration

* Updating reports, but not finished yet

* Updating reports, but not finished yet

* Updated the documentation

Now need to process all of the todos and make sure that the changes to the arguments work with the reports that I have already defined.

* Update some issues found by code analyzer.

* Add category to account_walker_parameters

- account walker can now take a category definition
- remove **kwargs from reports for testing purposes
- more documentation for bucket and bucket generation
- remove category_budget_level report (can now use budget_level)
- documentation for reports base module
- fix arguments for multi_report to match the rest of the reports

* Cleaning up TODOs

Remove todo associated with start and end (already fixed).
Use credit_account.sign instead of magic multipliers.

* Clean up TODOs

- account_levels, replace good_value with goal
- use account.sign instead of magic - sign.

* Clean up TODOs

- replace expenses_base with expenses (arguments)
- use current date configuration value instead of date.today()

* Start work to fix time_series data returns

Need this to be consistent across the board and it's not.  So this code
is starting to fix that work.

* Fix time_series return definitions

want them to be a list of arrays, instead of a list of dictionaries.

* Change account parameter names to remove smurfing

* Remove todos

- change account parameter names to remove smurfing
- use account walker parameters for income and retirement account params

* Remove todos

- Return a list of accounts associated with a category, not a set
- wrapper now provides a name for the group by default
- Remove todos in the networth calculators
  - account walker parameters in the payload calculator
  - no longer have to differentiate between liability and regular
    accounts in the payload calculator.

* Removed more TODOs from the source code

- Updated documentation to explain away some of the TODOs
- Remove need for category mapping in investment allocation report
- Update split query to handle credits and debits, and to sort based
  on transaction.post_date (this my improve performance now because not
  using sub queries).

* Clean up some more stuff

- setup.py url
- Remove "empty" __init__.py contents
- Fix name in license
- Update values in README

* Add description information to setup.py
  • Loading branch information
rerobins authored Apr 20, 2018
1 parent 1fcb90b commit 9acd08d
Show file tree
Hide file tree
Showing 39 changed files with 929 additions and 475 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2017 Robert RObinson
Copyright (c) 2017 Robert Robinson

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# GNUCash Reporting

A simple python library for generating reports from GNUCash data files. This repository provides a framework and application. The output is a collection of JSON files that can be displayed using a viewer application (similar to: [GNUCash Reporting Viewer](https://github.com/MeerkatLabs/gnucash-reporting-view)).
A simple python library for generating reports from a GNUCash database. This repository provides a framework and
application. The output is a collection of JSON files that can be displayed using a viewer application (similar to:
[GNUCash Reporting Viewer](https://github.com/MeerkatLabs/gnucash-reporting-view)).

## Requirements

* GNUCash Python Bindings
* Piecash
* PyYaml
* SimpleJSON
* NumPy
Expand All @@ -17,8 +19,8 @@ gnucash_reports -c configuration.yaml

## Documentation

Stored in the documentation folder of this project.
`TODO`

## License

BSD3 Clause License
MIT License
1 change: 0 additions & 1 deletion gnucash_reports/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
__author__ = 'rerobins'
1 change: 0 additions & 1 deletion gnucash_reports/collate/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
__author__ = 'rerobins'
52 changes: 43 additions & 9 deletions gnucash_reports/collate/bucket.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
Data structures that will be used to sort data into buckets and return the results. These are essentially helpers for
dictionaries that will execute a hashing function and update the contents of the hash value with the new data.
"""
from dateutil.rrule import MONTHLY

import gnucash_reports.collate.bucket_generation as generator
Expand All @@ -7,15 +11,15 @@
class BucketCollate(object):
"""
Wrapper that will collate a collection of data based on the hash_method and store_methods provided.
Also provides functionality for generation of the buckets as well.
"""

def __init__(self, bucket_generation, hash_method, store_function):
"""
Create a bucket sort function.
:param bucket_generation:
:param hash_method:
:param store_function:
:param bucket_generation: function that creates a list of buckets (dictionary) for data to be stored in.
:param hash_method: hash method that will be used to convert values into keys if keys are not defined when
storing values.
:param store_function: function that defines how the content will be stored in the bucket.
"""
self._bucket_generation = bucket_generation
self._hash_method = hash_method
Expand All @@ -24,9 +28,11 @@ def __init__(self, bucket_generation, hash_method, store_function):
self._container = self._bucket_generation()

def reinitialize(self):
"""Clear the containers with brand new content."""
self._container = self._bucket_generation()

def store_value(self, value, key=None):
"""Store a value ine the container using the store function defined during initialization."""
if key is None:
key = self._hash_method(value)
bucket = self._container[key]
Expand All @@ -35,33 +41,61 @@ def store_value(self, value, key=None):

@property
def container(self):
"""Dictionary that contains the buckets."""
return self._container


class PeriodCollate(BucketCollate):
"""
Bucket Collation based on collecting data based on a period of dates.
"""
def __init__(self, start, end, default_value_generator, store_function, frequency=MONTHLY, interval=1):
super(PeriodCollate, self).__init__(generator.monthly_buckets(start, end,
default_value_generator=default_value_generator,
frequency=frequency, interval=interval),
"""
Initializer.
:param start: start date
:param end: end date.
:param default_value_generator: method that will generate the default values for all of the buckets.
:param store_function: function that will be used to update the contents of the bucket when storing a value.
:param frequency: how large are the buckets (Monthly, daily, yearly) should be a dateutil.rrule enumeration.
:param interval: how many frequencies are stored in a bucket.
"""
super(PeriodCollate, self).__init__(generator.frequency_buckets(start, end,
default_value_generator=default_value_generator,
frequency=frequency, interval=interval),
keys.period(start, end, frequency=frequency, interval=interval),
store_function)


class CategoryCollate(BucketCollate):
"""
Collage all of the splits into buckets based on the category that their account is defined in.
Collate incoming splits into buckets based on the category that their account is defined in. Categories are based
on the configuration values defined in gnucash_reports.configuration.expense_categories
"""

def __init__(self, default_value_generator, store_function):
"""
Initializer
:param default_value_generator: function that creates a default value for each of the buckets.
:param store_function: function that will be used to update the content of the bucket when storing a split
value.
"""
super(CategoryCollate, self).__init__(generator.category_buckets(default_value_generator),
keys.category_key_fetcher,
store_function)


class AccountCollate(BucketCollate):
"""
Collage all of the splits into buckets based on the category that their account is defined in.
Collate all of the splits into buckets based on the last account name in the split's account tree.
"""

def __init__(self, default_value_generator, store_function):
"""
Initializer.
:param default_value_generator: function that creates a default value for each of the buckets.
:param store_function: function that will be used to update the content of the bucket when storing a split
value.
"""
super(AccountCollate, self).__init__(generator.category_buckets(default_value_generator),
keys.account_key_fetcher,
store_function)
23 changes: 19 additions & 4 deletions gnucash_reports/collate/bucket_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,31 @@


def decimal_generator():
"""Generates a single bucket containing a decimal object initialized to 0.0."""
return Decimal('0.0')


def integer_generator():
"""Generates a single bucket that contains a 0 integer."""
return int()


def debit_credit_generator():
"""Create a single bucket that contains a dictionary containing values for debit and credit values."""
return dict(debit=Decimal('0.0'), credit=Decimal('0.0'))


def monthly_buckets(start, end, frequency=MONTHLY, interval=1, default_value_generator=decimal_generator):
def frequency_buckets(start, end, frequency=MONTHLY, interval=1, default_value_generator=decimal_generator):
"""
Configure a method that will define all of the buckets based on stepping frequency distance between the start and
end dates provided.
:param start: start date for the collator.
:param end: end date for the collator.
:param frequency: how large of a step will the buckets contain (must be a dateutil.rrule enumeration)
:param interval: how many steps in a bucket.
:param default_value_generator: function used to generate the initialized value for the bucket.
:return: function that will generate the buckets based on the period definition details created.
"""

def generate_buckets():
results = dict()
Expand All @@ -30,9 +43,11 @@ def generate_buckets():

def category_buckets(default_value_generator):
"""
Create a default dictionary that will generate the buckets if they are missing.
:param default_value_generator: value generator.
:return:
Method generator that will create the collator collection. Uses a default dictionary that will retrieve its
initial value from the default value generator method provided.
:param default_value_generator: function that creates the default value for the bucket.
:return: function that will create a default dictionary using default value generator method to generate default
values.
"""
def generate_buckets():
return defaultdict(default_value_generator)
Expand Down
31 changes: 14 additions & 17 deletions gnucash_reports/collate/key_generator.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
from datetime import date

import re
from dateutil.rrule import rrule, MONTHLY

from gnucash_reports.configuration.expense_categories import get_category_for_account
from gnucash_reports.utilities import clean_account_name


def monthly(data_key):
def period(start, end, frequency=MONTHLY, interval=1):
"""
Returns the bucket that the hash value should be stored into based on the data key that is provided.
:param data_key: data key value.
:return: hash key value.
Defines a key generation method that will hash a split's transaction's post date into the appropriate bucket key
for the period bucket that was defined.
:param start: start date of all buckets
:param end: end date of all buckets
:param frequency: size of the bucket using dateutil.rrule enumeration
:param interval: how many frequencies in a bucket
:return: a method that will hash the incoming split value into a date key for the collator.
"""
split_date = data_key.transaction.post_date.replace(tzinfo=None, microsecond=0)
return date(split_date.year, split_date.month, 1)


def period(start, end, frequency=MONTHLY, interval=1):

intervals = rrule(frequency, start, interval=interval, until=end)

Expand All @@ -30,17 +27,17 @@ def method(data_key):

def category_key_fetcher(data_key):
"""
Look up the category that is associated with the account defined in the split.
:param data_key: split
:return:
Find the category that the account name belongs to.
:param data_key: transaction split
:return: string
"""
return get_category_for_account(clean_account_name(data_key.account.fullname))


def account_key_fetcher(data_key):
"""
Look up the category that is associated with the account defined in the split.
:param data_key: split
:return:
Return the last account name in the tree. Account names are split on both : and . characters.
:param data_key: transaction split
:return: string
"""
return re.split('[:.]', data_key.account.fullname)[-1]
25 changes: 11 additions & 14 deletions gnucash_reports/collate/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,23 @@

def split_summation(bucket, value):
"""
sum the new value to the value in the bucket.
:param bucket: Decimal object
:param value: Split object
:return: new bucket value
Add value into the contents of the bucket.
:param bucket: Summation of all splits that have been stored in this bucket.
:param value: Split object to add to bucket
:return: new bucket value as a decimal.
"""
bucket += value.value
return bucket


def store_credit_debit(bucket, value):
"""
Store the value of the split into the buckets value. If the decimal is positive it is considered a credit,
otherwise it is a debit.
:param bucket: dictionary containing debits and credits.
:param value: a decimal or a split
:return:
"""
if isinstance(value, Decimal):
decimal_value = value
else:
Expand All @@ -24,13 +31,3 @@ def store_credit_debit(bucket, value):
bucket['credit'] += decimal_value

return bucket


def store_summation(bucket, value):
bucket += value
return bucket


def count(bucket, value):
bucket += 1
return bucket
19 changes: 8 additions & 11 deletions gnucash_reports/commands/reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@
import argparse
import glob
import logging
import sys

import os
import os.path
import simplejson as json

from gnucash_reports.wrapper import initialize
from gnucash_reports.reports import run_report
from gnucash_reports.configuration import configure_application
from gnucash_reports.utilities import load_plugins
from datetime import datetime

from yaml import load

try:
Expand All @@ -20,14 +25,6 @@

logger = logging.getLogger(__name__)

sys.path.insert(0, os.path.abspath(os.getcwd()))

from gnucash_reports.wrapper import initialize
from gnucash_reports.reports import run_report
from gnucash_reports.configuration import configure_application
from gnucash_reports.utilities import load_plugins
from datetime import datetime


def main():
"""
Expand Down Expand Up @@ -77,7 +74,7 @@ def main():

for report_definition in report_configuration['definitions']:

result = run_report(report_definition)
result = run_report(**report_definition)

if result:
result_definition['reports'].append(result)
Expand Down
3 changes: 2 additions & 1 deletion gnucash_reports/commands/update_prices.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ def main():
if value is None:
continue

print 'Setting value of: %s to %s %s for date: %s' % (commodity.mnemonic, value, currency.get_currency(), quote_date)
print 'Setting value of: %s to %s %s for date: %s' % (commodity.mnemonic, value, currency.get_currency(),
quote_date)

Price(currency=currency.get_currency(),
commodity=commodity,
Expand Down
2 changes: 1 addition & 1 deletion gnucash_reports/configuration/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .base import configure_application
from gnucash_reports.configuration.base import configure_application
24 changes: 15 additions & 9 deletions gnucash_reports/configuration/alphavantage.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,31 @@
import requests

_API_KEY = None
BASE_URL='https://www.alphavantage.co/query'
FUNCTION='TIME_SERIES_DAILY'
BASE_URL = 'https://www.alphavantage.co/query'
FUNCTION = 'TIME_SERIES_DAILY'

META_DATA_KEY='Meta Data'
LAST_REFRESHED='3. Last Refreshed'
META_DATA_KEY = 'Meta Data'
LAST_REFRESHED = '3. Last Refreshed'

DATA_KEY='Time Series (Daily)'
CLOSE_KEY='4. close'
DATA_KEY = 'Time Series (Daily)'
CLOSE_KEY = '4. close'

DATE_FORMAT = '%Y-%m-%d'


def configure(json_configuration):
def configure(configuration):
"""Read the alpha vantage key out of the configuration object and store it in the api key global."""
global _API_KEY
_API_KEY = json_configuration.get('alpha_vantage', dict()).get('api_key', None)
_API_KEY = configuration.get('alpha_vantage', dict()).get('api_key', None)


def get_price_information(symbol, date=None):

"""
Accessor for retrieving the price information from alphavantage web service.
:param symbol: ticker symbol to look up.
:param date: date to look up content for. If None, will return the data for the last updated object.
:return: tuple containing the date and the closing value for the symbol.
"""
payload = {
'function': FUNCTION,
'apikey': _API_KEY,
Expand Down
Loading

0 comments on commit 9acd08d

Please sign in to comment.