Reports

The package it is provided with a Report object and a ReportBook object.

The Report object provides an interface for a complete workflow-based report (see Report workflow).

The ReportBook object, on the other hand, is a list of Report objects.

This will follow the workflows of each Report it contains, except for the output, which can be saved in a single Excel file.

Report at work

The Report object provides an interface to the entire workflow of a report: it accepts an input, processes the data and provides an output. To instantiate an object, you basically need three things:

  • input: a Dataset object, mandatory.

  • filter, map function or/and column: they are the same objects you would use in an Executor object, optional.

  • output: a FileManager object, optional.

import pyreports
import tablib

# Instantiate a simple Report object
mydata = tablib.Dataset([('Arthur', 'Dent', 55000), ('Ford', 'Prefect', 65000)], headers=['name', 'surname', 'salary'])
myrep = pyreports.Report(mydata)

# View report
myrep           # repr(myrep)
print(myrep)    # str(myrep)

Advanced Report instance

The Report object is very complex. Instantiating it as above makes little sense, because the result will be identical to the input dataset. This object enables a series of features for data processing.

import pyreports
import tablib

# Instantiate a Report object
salary55k = pyreports.manager('csv', '/tmp/salary55k.csv')
mydata = tablib.Dataset([('Arthur', 'Dent', 55000), ('Ford', 'Prefect', 65000)], headers=['name', 'surname', 'salary'])
report_only_55k = pyreports.Report(mydata, filters=[55000], title='Report salary 55k', output=salary55k)

# View report
myrep           # <Report object, title=Report salary 55k>

The example above, creates a Report object that filters input data only for employees with a salary of 55k. But we can also edit the data on-demand and then filter it, as follows in the next example.

Note

You can also pass a function to the filters argument, as for an Executor object.

import pyreports
import tablib

# My custom function for modifying salary data
def stringify_salary(salary):
    if isinstance(salary, int):
        return f'$ {salary}'
    else:
        return salary

# Instantiate a Report object
salary55k = pyreports.manager('csv', '/tmp/salary55k.csv')
mydata = tablib.Dataset([('Arthur', 'Dent', 55000), ('Ford', 'Prefect', 65000)], headers=['name', 'surname', 'salary'])
report_only_55k = pyreports.Report(mydata,
                                    filters=['$ 55000'],
                                    map_func=stringify_salary,
                                    title='Report salary 55k',
                                    output=salary55k)

# View report
myrep           # <Report object, title=Report salary 55k>

Note

It is also possible to declare a counter of the processed lines by setting count=True. Moreover, as for an Executor object, you can specify a single return column using the column argument; ex. column='surname'.

Execute Report

Once a Report object has been instantiated, you can execute the filters and editing functions (map) set during the creation of the object.

# Apply filters and map function
report_only_55k.exec()

# Print result
print(report_only_55k)

# Adding count after creation
report_only_55k.count = True
report_only_55k.exec()
print(report_only_55k)

Warning

Once a filter or map function is applied, it will not be possible to go back. If you want to change filters after call the exec method, you need to re-instantiate the object.

Export

Once the exec method is called, and then once the data is processed, we can export the data based on the output set when instantiating the object.

Note

If the output has not been specified, calling the export method will print the data to stdout.

# Save report on /tmp/salary55k.csv
report_only_55k.export()

# Unset output
report_only_55k.output = None
report_only_55k.export()            # This print the data on stdout

# Set output
report_only_55k.output = salary55k
report_only_55k.export()            # Save report on /tmp/salary55k.csv

ReportBook at work

The ReportBook object is a collection (list) of Report objects. This basically allows you to collect multiple reports in a single container object. The main advantage is the ability to iterate over each Report and access its properties.

import pyreports
import tablib

# Instantiate the Report objects
mydata = tablib.Dataset([('Arthur', 'Dent', 55000), ('Ford', 'Prefect', 65000)], headers=['name', 'surname', 'salary'])
report_only_55k = pyreports.Report(mydata, filters=[55000], title='Report salary 55k')
report_only_65k = pyreports.Report(mydata, filters=[65000], title='Report salary 65k')

# Create a ReportBook
salary = pyreports.ReportBook([report_only_55k, report_only_65k])

# View ReportBook
salary           # repr(salary)
print(salary)    # str(salary)

Note

The ReportBook object supports the title property, as follows: pyreports.ReportBook(title='My report book')

Export reports

The ReportBook object has an export method. This method not only saves Report objects to its output, but first executes the exec method of each Report object it contains.

Warning

As for Report objects, even a ReportBook object once the export method has been called, it will need to be instantiated again if you want to reset the data to the source, before applying the filters and map functions.

# Export a ReportBook
salary.export()         # This run exec() and export() on each Report object

# Export each Report on one file Excel (xlsx)
salary.export('/tmp/salary_report.xlsx')

Add and remove report

Being a container, the ReportBook object can be used to add and remove Report object.

# Create an empty ReportBook
salary = pyreports.ReportBook(title='Salary report')

# Add a Report object
salary.add(report_only_55k)
salary.add(report_only_65k)

# Remove last Report object added
salary.remove()                     # Remove report_only_65k object
salary.remove(0)                    # Remove report_only_55k object, via index

Count reports

The ReportBook object supports the protocol for the built-in len function, to count the Report objects it contains.

# Count object
len(salary)

Iteration

The ReportBook object supports the python iteration protocol (return of generator object). This means that you can use it in a for loop or in a list comprehension.

# For each report in ReportBook
for report in salary:
    print(report)

# List comprehension
my_list_of_report = [report for report in salary]

Merge

ReportBook objects can be joined together, using the + operator.

# ReportBook
book1 = pyreports.ReportBook([report1, report2])
book2 = pyreports.ReportBook([report3, report4])
# Merge ReportBook
tot_book = book1 + book2
tot_book = book1.__add__(book2)

print(tot_book)

# ReportBook None
#   Report1
#   Report2
#   Report3
#   Report4