Skip to main content

Simplified Report configuration, generation and distribution

Project description

Easy Reports

test


Easy Reports is a python package which simplifies report configuration, generation and distribution. Reasons for this package creation are:

  • removal of repetitive code from multiple python report scripts written by workers with different level of programming skills
  • ability to extract data from two or more databases
  • ability to join query results into one final dataset
  • simplification of excel file formatting by introducing dictionary bases configuration
  • introduction of @processor decorated functions that can do additional data processing and return dataset for excel generator

Table of Contents

Installation

Create project folder and initialize venv environment

$ mkdir myproject
$ cd myproject
$ python3 -m venv venv

Within the activated environment, use follownig command to install Easy Reports

$ pip install easy-reports

Usage

A minimal Easy Report looks as below:

from easy_reports import EasyReport
from pathlib import Path

app = EasyReport(base_path=Path(__file__).resolve().parent)
app.base_config.from_pyfile('settings.py')
app.load_reports(report_list=['R001'])
app.run()

Application Configuration

Application default confinguration is defined in defaults.py. Config parameters can be changed:

  • defining environment variable prefixed with EASY_REPORTS
  • passed as keyword arguments to EasyReport()
  • loaded from settings.py file

Each Report configuration is created on top of Application's base_config. Selected parameters can be overriden by uppercase attribiutes in Report's Meta.

Report Configuration

By default each Report lives in dedicated folder inside path: app.defs_path

Preferred (default) Report structure consists of:

  • report.py module file that contains Report definition such as settings, mappings and processors
  • subfolders:
    • /sql - SQL scripts used to retrive data
    • /templ - templates of email messages
    • /cache - cached SQL script's results and dataframes used by Excel creator
    • /logs - log files
    • /arch - generated Excel report files

It is not advised but if necessary default folder paths can be changed in Application configuration step. For example change of default /arch can be done by:

  • setting evironment variable
$ export EASY_REPORTS_ARCH_BASE_PATH = '/new_location/arch'
  • passing keyword argument to EasyReport class constructor
app = EasyReport(..., arch_base_path = '/new_location/arch')
  • setting variable in settings.py
ARCH_BASE_PATH = '/new_location/arch'

Reports Loading

Reports loading is done by scaning app.defs_path for subfolders containing report.py modules. Modules (Reports) are imported, configured and stored in app._report list

Report Generation

Reports can be generated individually by calling:

# generate selected Report 'R001'
app.refresh(name='R001')

or all

app.refresh_all()
or 
app.run()

Additional keyword arguments can be passed to the above functions: One of them, useful while preparing and developing new Report module is skip list of blocked parts of Report generation flow

# skip excel creation and email sending
app.refresh(name='R001', skip=['excel','email'])

Examples

Creation of Report boilerplate

New Report boilerplate can be created using CLI command.

$ easy-reports create
Enter new report symbol: R7777
Creating report R7777...

New subfolder R7777 will be created uder defs path. Report folder will contain report.py module file and four subfolders (as shown below)

$ cd defs
defs/$ tree
.
└── R7777
    ├── arch
    ├── cache
    ├── logs
    ├── sql
    └── report.py

Module file report.py contains all configuration needed to generate report files. Global (default) configuration from setting.py can be extended by each report.

  1. If needed additional aliases and connection strings can be defined as below:
db_list = {
    'alias_1': {'url': 'testing'},
    'alias_2': {'url': 'testing'},
    # 'alias_3': {'url': 'testing'}
}
  1. List of SQL files with DB aliases and list of fields used to join resulting Dataframes into one aggregate result.
 sql_list = [
            ('sql_1', 'alias_1', ['PK']),
            ('sql_2', 'alias_2', ['PK']),
            # ('sql_3', 'alias_3', ['PK']),
        ]
  1. Reports can be sent by email. Email configuration is done in the dictonary shown below. Each email is bound with report files by list of ID's
email_config = {
  1: {
    'to': 'recipient@email.com',
    'cc': '',
    'subject': 'Test',
    'onbehalf': '',
    'body': 'This is test',
    'template': '',
    'attachments': [],
    'attachments_rpt_id': [1],
  }
}
  1. Reports configuration is done in the dictionary shown below. Each entry is ID of the report. Report config defines such elements as report filneme, wheather is can be sent by email (added to attachments dictionary), list of sheets. Each sheet must be named and bound to data source (name of Dataframe). Other dictionary keys allow configuration and formatting of the resultig sheet.
rpt_config = {
  1: {
    'filename': 'report_{symbol}_{date}.xlsx',
    'send_email': True,
    'sheets': {
      1: {
        'sheet_name': 'Result',
        'data_src': 'df_result',
        'output_columns': [],
        'freeze_panes': 'B2',
        'header_formats': {
          '*': 'header',
        },
        'column_formats': {
          'column_name': 'fg_excel_35',
        },
        'column_options': {
          'D:F': {'level': 1, 'hidden': True},
          'C:C': {'collapsed': True},
        },
        'conditional_formats': {
          'column_name': [
              {
                'type': 'data_bar',
                'bar_color': '#50DAF6',
                'bar_border_color': 'black',
              },
          ],
        },
        'data_validations': {
          'column_name': {
            'validate': 'list',
            'source': ['Excelent', 'Good', 'Moderate', 'Poor'],
          },
        },
      }
    },
  }
}
  1. Additional processing can be done to aggregate result Dataframe (df_final) or any other stored in self.results dictionary. Functions decorated with @processor are executed in order of definition in the report.py module file. Each function should return dictionary of Name and Dataframe object witch will be added to self.results dictionary.
@processor
def p01(self) -> dict:
    df = self.results['df_final']
    # dataframe processing
    return {'df_result': df}
  1. Default settings can be overriden by defining variables in the Meta class body:

Default subfolder names can be modified by defining any of below variables

class Report(ReportBase):
  class Meta:
    LOGS_DIR = 'logs'
    ARCH_DIR = 'arch'
    SQL_DIR = 'sql'
    CACHE_DIR = 'cache'
    TEMPL_DIR = 'templ'
    ...

If necessary full paths can be provided that will override any other path and folder settings

class Report(ReportBase):
  class Meta:
    logs_path = pathlib.Path('/custom_path/logs').resolve()
    arch_path = pathlib.Path('/custom_path/arch').resolve()
    sql_path = pathlib.Path('/custom_path/sql').resolve()
    cache_path = pathlib.Path('/custom_path/cache').resolve()
    templ_path = pathlib.Path('/custom_path/templ').resolve()
    ...

Testing

Packege can has been tested against three databases: Postgres, MySQL and SqlServer. Test can be run by deploying stack of Docker containers.

Running command bellow will start container in detached mode and run pytest in the app contaner when all db container are ready.

$ docker compose up -d

While contaner are running in the background tests from host machine can be run. Prior to running pytest or tox aliases to localhost for db-postgres, db-mysql, db-mssql must be added to enable host name resolution.

Contributing

To contribute to the project, you can:

  • Submit bug reports and feature requests through the GitHub issue tracker
  • Fork the repository and submit pull requests with bug fixes or new features
  • Help improve the documentation

Please read the contributing guidelines for more information.

License

This project is licensed under the MIT License. See the LICENSE file for details.

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

easy-reports-1.0.0.tar.gz (27.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

easy_reports-1.0.0-py3-none-any.whl (22.3 kB view details)

Uploaded Python 3

File details

Details for the file easy-reports-1.0.0.tar.gz.

File metadata

  • Download URL: easy-reports-1.0.0.tar.gz
  • Upload date:
  • Size: 27.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.10.12

File hashes

Hashes for easy-reports-1.0.0.tar.gz
Algorithm Hash digest
SHA256 cc89e4896c77f356fd64268a1ac76287c9c81242a2533f8df04519f6ad94b6e5
MD5 26463290418135a8250efe410dce887f
BLAKE2b-256 b2a160bfa486026e64227ff9427c0f9e424b47a570b9e0223b4f0db6a36fc6db

See more details on using hashes here.

File details

Details for the file easy_reports-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: easy_reports-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 22.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.10.12

File hashes

Hashes for easy_reports-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fc2afecb73d5fc548d6a1a6dd78fec5976e53dc30372ec1fb268d0f35433ceb1
MD5 476160916aae5eb47dd725b8365864d7
BLAKE2b-256 75c0d0e5fe9ad9a42f65df806627a28dc7a3338758bdbc0d4304d692c72fa02d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page