[Python] Implementation of print report breaks and headers

Discussão em 'Python' iniciado por Stack, Setembro 25, 2024.

  1. Stack

    Stack Membro Participativo

    How does one implement report breaks in general and in Python specifically?

    I'm referring to functionality that allows for inserting a title header before the record where some field changes, or a footer with totals after the change. Like in MS Access back in the day.

    Currently using an iterable object and lambdas to check for breaks like this:

    from typing import Literal, Callable

    class BreakResult():
    def __init__(self, name, state, slice_start, data=[]):
    self.name = name
    self.state = state
    self.slice_start = slice_start

    def __bool__(self):
    # Return True if the list is non-empty
    return self.state

    # Define behavior when used in an integer context
    def __int__(self):
    return self.slice_start

    def __str__(self):
    return self.name if self.state else ""

    class BreakForIterable():
    def __init__(self, name, break_lambda:Callable, where:Literal['after', 'before']='after'):
    self.name = name
    self.break_lambda = break_lambda
    self.where = where
    self._slice_start = 0
    self._state = False

    @property
    def slice_start(self):
    pass

    def __call__(self, i, data):
    # returns true, slice_start or None, slice_end or none

    if self.where == "before":
    # return true if:
    # - record number is 0
    # - lambda returns different values for current record and the previous one
    # and set the slice start to the current record
    if i == 0:
    slice_start = self._slice_start
    self._slice_start = i
    return BreakResult(self.name, True, slice_start)
    elif self.break_lambda(data) != self.break_lambda(data[i-1]):
    slice_start = self._slice_start
    self._slice_start = i
    return BreakResult(self.name, True, slice_start)
    else:
    return BreakResult(self.name, False, None)
    elif self.where == "after":
    # return true if:
    # - record number is equal to the last
    # - lambda returns different values for current record and the next one
    # and set the slice start to the current record
    if i == 0:
    return BreakResult(self.name, False, None)
    elif i == len(data) - 1:
    slice_start = self._slice_start
    self._slice_start = i + 1
    return BreakResult(self.name, True, slice_start)
    elif self.break_lambda(data) != self.break_lambda(data[i+1]):
    slice_start = self._slice_start
    self._slice_start = i + 1
    return BreakResult(self.name, True, slice_start)
    else:
    return BreakResult(self.name, False, None)
    return BreakResult(self.name, False, None)

    class IterableWithBreaks():
    def __init__(self, data):
    self.data = data # this is the data list
    self.breaks = [] # this is the list of breaks. Order is important

    def add_break(self, name, break_lambda, where="after"):
    self.breaks.append(BreakForIterable(name, break_lambda, where))
    return self

    def check_breaks(self, i, where:Literal['after', 'before']):
    rl = []
    for b in [ b for b in self.breaks if b.where == where]:
    r = b(i, self.data)
    rl.append(r)
    return [ r for r in rl if r ]

    def __iter__(self):
    self._index = 0 # Initialize the index for iteration
    return self

    def __next__(self):
    if self._index < len(self.data):
    result = self.data[self._index]
    self._index += 1
    return result
    else:
    raise StopIteration # End of the iteration

    def __getitem__(self, index):
    return self.data[index]

    # Define behavior for setting elements
    def __setitem__(self, index, value):
    self.data[index] = value

    # Define behavior for deleting elements
    def __delitem__(self, index):
    del self.data[index]


    but this smells to me like a naive approach - especially if I were to try adding totals to a header.

    Is there a better approach? Or are there libraries that do that better? Anything from reporting tools (open source) to Python libraries (better, as I'd be able to better control graphics) would work.

    Continue reading...

Compartilhe esta Página