question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add custom object convertor (DataModel or API)

See original GitHub issue

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.

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:open
  • Created a year ago
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
astanincommented, Oct 19, 2022

provide a convenient interface like table that returns tabulate.DataModel class instance.

I like the idea of having an abstract tabulate.DataModel.

0reactions
baterflyritycommented, Oct 7, 2022

@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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Create a Custom Data Model Object from an Existing Data ...
On the Data Model tab, click New. · Click From Existing. · Click the tab for the type of DMO that you want...
Read more >
How to write custom converters for JSON serialization - .NET
This article shows how to create custom converters for the JSON serialization classes that are provided in the System.Text.Json namespace.
Read more >
Storing Custom Data Types With Custom TypeConverter in ...
This tutorial will guide the reader through the process of creating a custom data type converter to store a custom data type in...
Read more >
MapStruct Spring Page to custom object conversion includes ...
I am using this mapping in order to convert the content field of the Page object to a list of custom objects found...
Read more >
Python Convert JSON data Into a Custom Python Object
Learn Use of jsonpickle to convert JSON into a custom Python Object. ... For example, you receive employee JSON data from the API...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found