Add custom object convertor (DataModel or API)
See original GitHub issueHello!
Subject
I like tabulate idea but one thing does not leave me calm. Why should I convert (format) different objects to one of supported data structure by myself each time? Thus I propose adding magic attribute based object convertor via __table__(self)
method like __str__
and __repr__
.
Explanation
Just to be clear I have prepared two examples. Firstly I show how I use tabulate now. Then I use monkey patch to bring it to life proposed changes.
Regular usage
This example shows regular tabulate usage for custom data.
from dataclasses import dataclass
from tabulate import tabulate
@dataclass
class User:
id: int
name: str
users = [User(0, 'Bob'), User(1, 'Ben')]
print(tabulate([[u.id, u.name] for u in users], ['#', 'Client'], tablefmt='fancy_grid'))
Proposed usage
Next I want to implement my changes like this:
from dataclasses import dataclass
from tabulate import tabulate
@dataclass
class User:
id: int
name: str
def __table__(self):
return [self.id, self.name]
class ClientBase:
def __init__(self, *users: User):
self._users = users
def __table__(self):
return [u.__table__() for u in self._users], ['#', 'Client']
users = ClientBase(User(0, 'Bob'), User(1, 'Ben'))
print(monkey_patched_tabulate(users, tablefmt='fancy_grid'))
This code results in the same table:
Implementation
So I have successfully monkey patched stable tabulate version but I suggest this changes to the community. My current implementation just adds several lines of code in def _normalize_tabular_data(tabular_data, headers, showindex=“default”) method. Here it is:
def monkey_patched_tabulate(tabular_data, *args, **kwargs):
# ...
# somewhere in type checks
if hasattr(tabular_data, '__table__'):
# Object with custom __table__ convertor
rows, headers = tabular_data.__table__()
if headers is not None:
kwargs.update(headers=headers)
return monkey_patched_tabulate(rows, *args, **kwargs)
# other checks
else: # it's a usual an iterable of iterables, or a NumPy array
# convert rows with custom __table__ convertor
rows = [row.__table__() if hasattr(row, '__table__') else row for row in tabular_data]
# ... rest of the code
return tabulate(rows, *args, **kwargs) # recursive call of _normalize_tabular_data() replaced with my patch method
Benefits
- Formatting/conversion implemented by library/data models but end users.
- Remove manual conversion of rows and headers on each call.
Closing thoughts
All in all I hope my idea will help someone. Unfortunately I do not have enough time now to create PR thus one is welcome to do it)
Issue Analytics
- State:
- Created a year ago
- Comments:6 (4 by maintainers)
Top GitHub Comments
I like the idea of having an abstract tabulate.DataModel.
@astanin ,
The same value as for
_normalize_tabular_data
function existence. As long as you use integrated normalizer for several popular types you can just allow users to provide their own custom normalizer.Or just provide a convenient interface like
__table__
that returnstabulate.DataModel
class instance.Very nice, did not notice.