Open baterflyrity opened 2 years ago
That's an interesting idea but I'm not convinced it is useful to many users. Let's see if there is enough interest in this issue.
I would also like to know what real problems it is trying to solve. In your example ClientBase could have implemented an iterable with pretty much the same results.
I would almost always prefer to keep user-specific data transformation outside of the library and very explicit. A list comprehension can be done by the end users, and can extract just the data (columns) which need to be displayed. The semantics of the table attribute would have to be defined. I don't like that the "record" and the "set of records" expose the same interface.
@astanin , sure, it was not clear... The main idea is to separate what and how user data is rendered - something like model-view approach.
As for now there is only two ways to render data: provide hard-coded class or iterable of iterables. I propose to implement a ways of defining middleware model→view adapter. Usually it is done via magic methods.
Yes, you are right about interface similarity. Guess it should be something like __table__
,__header__
and __row__
.
A list comprehension can be done by the end users, and can extract just the data (columns) which need to be displayed.
Agree except tabulate is used only by end users. Imagine I publish my awesome data library grizzlies which datasets support pretty printing and array conversion. How can I distinguish dataset casting to tabulate data and to numpy data? So I will need to use conditional imports, __str__
overloading, e.t.c.
@baterflyrity
Imagine I publish my awesome data library grizzlies which datasets support pretty printing and array conversion. How can I distinguish dataset casting to tabulate data and to numpy data?
So you are the provider of a data source, and have control about how it is defined (can change its class, methods, etc.). You want it to be printable through tabulate and let say some other similar data transformation tool.
What's the value of a hidden special method __table__
over using an explicit adapter? Something like this:
users = ClientBase(...)
print(tabulate(users.as_table(), headers="keys", tablefmt="..."))
It requires exactly the same effort on your part, the method is more discoverable by the end users, and it uses a well tested code path of the library rather than a rarely used option (I expect fewer bugs).
BTW, I just noted that your original request was written before dataclasses support was merged (pull request #125). In 0.9.0 you can now use it like this:
>>> users = [User(0, 'Bob'), User(1, 'Ben')]
>>> print(tabulate(users, tablefmt="grid"))
+---+-----+
| 0 | Bob |
+---+-----+
| 1 | Ben |
+---+-----+
I hope it already saves some typing.
Guess it should be something like table,header and row.
Thinking about it, tabulate already supports this kind of a magic API that data should implement. If you consider that an iterable of dicts is printable, this is what needs to be done:
keys
and values
attributes on its values (records)@astanin ,
What's the value of a hidden special method table over using an explicit adapter?
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.
If you consider that an iterable of dicts is printable, this is what needs to be done:
- make the data object iterable
- define keys and values attributes on its values (records)
Or just provide a convenient interface like __table__
that returns tabulate.DataModel
class instance.
In 0.9.0 you can now use it like this...
Very nice, did not notice.
provide a convenient interface like table that returns tabulate.DataModel class instance.
I like the idea of having an abstract tabulate.DataModel.
Hello!
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.
Proposed usage
Next I want to implement my changes like this:
This code results in the same table:![изображение](https://user-images.githubusercontent.com/15788974/163728554-7a02447c-fc55-4adc-9603-aab1b5ae52d2.png)
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:
Benefits
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)