Commit cad182e8 authored by olb's avatar olb
Browse files

python packaging

parent 815ba9f1
/settings.py
*.pyc
/python-env
/build/
/dist/
/hreports.egg-info/
/.vim/
*.pyc
.*.swp
Hreport build html reports on top of helger.
Hreport build html reports on top of hledger.
There are several kinds of report :
......
#!/usr/bin/env python
""" Annual report
"""
import locale
import logging
import os
import shutil
import sys
from jinja2 import Environment, FileSystemLoader
from hreports import settings
from hreports.hledger import AccountingYears, Hledger
from hreports.scripts import main
assert sys.version_info >= (3, 5)
logging.basicConfig(level=logging.INFO)
LOGGER = logging.getLogger('hreport')
TPL_ENV = Environment(
loader=FileSystemLoader(settings.get('TEMPLATES_DIRS')),
extensions=['jinja2.ext.with_'],
)
def incomes_statement(accounting_years, report, context=None):
expenses = accounting_years.extract(match='|'.join(
report['expenses']['accounts']
))
incomes = accounting_years.extract(match='|'.join(
report['incomes']['accounts']
))
context = context or dict()
context.update({
'incomes': incomes,
'expenses': expenses,
'conf': report,
})
template = TPL_ENV.get_template('income-statement.html')
return template.render(**context)
def balance_sheet(accounting_years, report, context=None):
liabilities = accounting_years.extract(match='|'.join(
report['liabilities']['accounts']
))
assets = accounting_years.extract(match='|'.join(
report['assets']['accounts']
))
context = context or dict()
context.update({
'liabilities': liabilities,
'assets': assets,
'conf': report,
})
template = TPL_ENV.get_template('balance-sheet.html')
return template.render(**context)
def cash(accounting_years, report, context=None):
accounting_year = accounting_years.get_year(accounting_years.last_year())
context = context or dict()
context.update({
'accounting_year': accounting_year,
'conf': report,
})
template = TPL_ENV.get_template('cash.html')
return template.render(**context)
def chart_of_accounts(accounting_years, report, context=None):
accounting_year = accounting_years.get_year(accounting_years.last_year())
context = context or dict()
context.update({
'chart_of_accounts': accounting_year.chart_of_accounts,
'conf': report,
})
template = TPL_ENV.get_template('chart-of-accounts.html')
return template.render(**context)
def process_args(argv):
"""
No more options. Maybe in the futur.
"""
options = {}
return options
def load(options):
accounting_years = AccountingYears()
accounting_years_closed = AccountingYears()
for year in settings.get('ACCOUNTING_YEARS'):
LOGGER.info('loading year %s with hledger', year)
hledger = Hledger(
settings.get('ACCOUNTING_YEARS_OPTIONS')[year]['incomes_statement'],
settings.get('ACCOUNTING_YEARS_OPTIONS')[year]['chart_of_accounts'],
inverted=settings.get('INVERTED'),
)
accounting_years.add_year(
hledger.accounting_year(year)
)
LOGGER.info('loading closed year %s with hledger', year)
hledger = Hledger(
settings.get('ACCOUNTING_YEARS_OPTIONS')[year]['balance_sheet'],
settings.get('ACCOUNTING_YEARS_OPTIONS')[year]['chart_of_accounts'],
inverted=settings.get('INVERTED'),
)
accounting_years_closed.add_year(
hledger.accounting_year(year)
)
return (accounting_years, accounting_years_closed)
def doreport(accounting_years, accounting_years_closed, report, context=None):
accounting_years = accounting_years.clone_until(report['year'])
accounting_years_closed = accounting_years_closed.clone_until(report['year'])
directory = os.path.dirname(report['output'])
css_path = os.path.join(settings.get('OUTPUT_DIR'), 'style.css')
css_url = os.path.relpath(css_path, directory)
context = context or dict()
context.update({
'css_url': css_url,
})
if report['type'] in ['incomes_statement', 'is']:
output = incomes_statement(accounting_years, report, context)
elif report['type'] in ['balance_sheet', 'bs']:
output = balance_sheet(accounting_years_closed, report, context)
elif report['type'] in ['cash', ]:
output = cash(accounting_years, report, context)
elif report['type'] in ['chart_of_accounts', 'coa']:
output = chart_of_accounts(accounting_years, report, context)
if not os.path.exists(directory):
os.makedirs(directory)
elif not os.path.isdir(directory):
raise Exception('%s must be a directory' % directory)
LOGGER.info('write report %s to file %s', report['output'], report['type'])
ofile = open(report['output'], 'w+')
print(output, file=ofile)
ofile.close()
def doreports(options):
(accounting_years, accounting_years_closed) = load(options)
for report in settings.get('REPORTS'):
doreport(accounting_years, accounting_years_closed, report)
def doindex(options, context=None):
template = TPL_ENV.get_template('index.html')
output = os.path.join(
settings.get('OUTPUT_DIR'),
'index.html')
ofile = open(output, 'w+')
reports = settings.get('REPORTS')
reports_by_year = {}
for report in reports:
if not report['year'] in reports_by_year:
reports_by_year[report['year']] = []
reports_by_year[report['year']].append(report)
context = context or dict()
context.update({
'css_url': 'style.css',
'accounting_years': settings.get('ACCOUNTING_YEARS'),
'reports': reports_by_year,
})
LOGGER.info('write index to file %s', output)
print(template.render(**context), file=ofile)
def doassets(options):
source = os.path.join(settings.get('STATIC_DIR'), 'style.css')
output = os.path.join(settings.get('OUTPUT_DIR'), 'style.css')
LOGGER.info('copy %s to %s', source, output)
shutil.copyfile(source, output)
def main(argv):
locale.setlocale(locale.LC_ALL, 'fr_FR.utf-8')
options = process_args(argv)
doreports(options)
doindex(options)
doassets(options)
if __name__ == "__main__":
main(sys.argv[1:])
main()
#!/usr/bin/env python
""" Annual report
"""
import locale
import logging
import os
import shutil
import sys
assert sys.version_info >= (3, 5)
from jinja2 import Environment, FileSystemLoader
from hreports import settings
from hreports.hledger import AccountingYears, Hledger
logging.basicConfig(level=logging.INFO)
LOGGER = logging.getLogger('hreport')
TPL_ENV = Environment(
loader=FileSystemLoader(settings.get('TEMPLATES_DIR')),
extensions=['jinja2.ext.with_'],
)
def incomes_statement(accounting_years, report, context=None):
expenses = accounting_years.extract(match='|'.join(
report['expenses']['accounts']
))
incomes = accounting_years.extract(match='|'.join(
report['incomes']['accounts']
))
context = context or dict()
context.update({
'incomes': incomes,
'expenses': expenses,
'conf': report,
})
template = TPL_ENV.get_template('income-statement.html')
return template.render(**context)
def balance_sheet(accounting_years, report, context=None):
liabilities = accounting_years.extract(match='|'.join(
report['liabilities']['accounts']
))
assets = accounting_years.extract(match='|'.join(
report['assets']['accounts']
))
context = context or dict()
context.update({
'liabilities': liabilities,
'assets': assets,
'conf': report,
})
template = TPL_ENV.get_template('balance-sheet.html')
return template.render(**context)
def cash(accounting_years, report, context=None):
accounting_year = accounting_years.get_year(accounting_years.last_year())
context = context or dict()
context.update({
'accounting_year': accounting_year,
'conf': report,
})
template = TPL_ENV.get_template('cash.html')
return template.render(**context)
def chart_of_accounts(accounting_years, report, context=None):
accounting_year = accounting_years.get_year(accounting_years.last_year())
context = context or dict()
context.update({
'chart_of_accounts': accounting_year.chart_of_accounts,
'conf': report,
})
template = TPL_ENV.get_template('chart-of-accounts.html')
return template.render(**context)
def process_args(argv):
"""
No more options. Maybe in the futur.
"""
options = {}
return options
def load(options):
accounting_years = AccountingYears()
accounting_years_closed = AccountingYears()
for year in settings.get('ACCOUNTING_YEARS'):
LOGGER.info('loading year %s with hledger', year)
hledger = Hledger(
settings.get('ACCOUNTING_YEARS_OPTIONS')[year]['incomes_statement'],
settings.get('ACCOUNTING_YEARS_OPTIONS')[year]['chart_of_accounts'],
inverted=settings.get('INVERTED'),
)
accounting_years.add_year(
hledger.accounting_year(year)
)
LOGGER.info('loading closed year %s with hledger', year)
hledger = Hledger(
settings.get('ACCOUNTING_YEARS_OPTIONS')[year]['balance_sheet'],
settings.get('ACCOUNTING_YEARS_OPTIONS')[year]['chart_of_accounts'],
inverted=settings.get('INVERTED'),
)
accounting_years_closed.add_year(
hledger.accounting_year(year)
)
return (accounting_years, accounting_years_closed)
def doreport(accounting_years, accounting_years_closed, report, context=None):
accounting_years = accounting_years.clone_until(report['year'])
accounting_years_closed = accounting_years_closed.clone_until(report['year'])
directory = os.path.dirname(report['output'])
css_path = os.path.join(settings.get('OUTPUT_DIR'), 'style.css')
css_url = os.path.relpath(css_path, directory)
context = context or dict()
context.update({
'css_url': css_url,
})
if report['type'] in ['incomes_statement', 'is']:
output = incomes_statement(accounting_years, report, context)
elif report['type'] in ['balance_sheet', 'bs']:
output = balance_sheet(accounting_years_closed, report, context)
elif report['type'] in ['cash', ]:
output = cash(accounting_years, report, context)
elif report['type'] in ['chart_of_accounts', 'coa']:
output = chart_of_accounts(accounting_years, report, context)
if not os.path.exists(directory):
os.makedirs(directory)
elif not os.path.isdir(directory):
raise Exception('%s must be a directory' % directory)
LOGGER.info('write report %s to file %s', report['output'], report['type'])
ofile = open(report['output'], 'w+')
print(output, file=ofile)
ofile.close()
def doreports(options):
(accounting_years, accounting_years_closed) = load(options)
for report in settings.get('REPORTS'):
doreport(accounting_years, accounting_years_closed, report)
def doindex(options, context=None):
template = TPL_ENV.get_template('index.html')
output = os.path.join(
settings.get('OUTPUT_DIR'),
'index.html')
ofile = open(output, 'w+')
reports = settings.get('REPORTS')
reports_by_year = {}
for report in reports:
if not report['year'] in reports_by_year:
reports_by_year[report['year']] = []
reports_by_year[report['year']].append(report)
context = context or dict()
context.update({
'css_url': 'style.css',
'accounting_years': settings.get('ACCOUNTING_YEARS'),
'reports': reports_by_year,
})
LOGGER.info('write index to file %s', output)
print(template.render(**context), file=ofile)
def doassets(options):
source = os.path.join(settings.get('STATIC_DIR'), 'style.css')
output = os.path.join(settings.get('OUTPUT_DIR'), 'style.css')
LOGGER.info('copy %s to %s', source, output)
shutil.copyfile(source, output)
def main():
locale.setlocale(locale.LC_ALL, 'fr_FR.utf-8')
argv = sys.argv[1:]
options = process_args(argv)
doreports(options)
doindex(options)
doassets(options)
if __name__ == "__main__":
main()
......@@ -28,13 +28,13 @@ if __SETTINGS is None:
if 'OUTPUT_DIR' not in __SETTINGS:
raise Exception('need OUTPUT_DIR settings')
if 'TEMPLATES_DIRS' not in __SETTINGS:
__SETTINGS['TEMPLATES_DIRS'] = os.path.join(
os.path.dirname(__file__), '..', 'templates')
if 'TEMPLATES_DIR' not in __SETTINGS:
__SETTINGS['TEMPLATES_DIR'] = os.path.join(
os.path.dirname(__file__), 'templates')
if 'STATIC_DIR' not in __SETTINGS:
__SETTINGS['STATIC_DIR'] = os.path.join(
os.path.dirname(__file__), '..', 'static')
os.path.dirname(__file__), 'static')
if 'INVERTED' not in __SETTINGS:
__SETTINGS['INVERTED'] = False
......
import setuptools
with open("README.md", "r") as fh:
long_description = fh.read()
setuptools.setup(
name="hreports",
version="0.0.1",
author="olb",
author_email="olb@nebkha.net",
description="build html reports on top of hledger",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://forge.gresille.org/olb/hreports",
packages=setuptools.find_packages(),
package_data={
'hreports': [
'templates/*',
'templates/inc/*',
'static/*',
]
},
classifiers=[
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
],
install_requires=[
'jinja2',
],
python_requires='>=3',
entry_points={
'console_scripts': [
'hreport=hreports.scripts:main',
],
},
)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment