Skip to main content

Print objects with data beautifully

Project description

Downloads Downloads Coverage Status Lines of code Hits-of-Code Test-Package Python versions PyPI version Checked with mypy Ruff DeepWiki

logo

Pythonistas follow an implicit convention to create special __repr__ methods that return text closely resembling the code used to construct the object. With this library, you can easily implement __repr__ for your own classes to follow this convention.

Table of contents

Installation

You can install printo with pip:

pip install printo

You can also use instld to quickly try this package and others without installing them.

Basic usage

The main function in this library is describe_data_object; it returns a string representing the initialization code for your object. There are three required positional parameters:

  • A class name.
  • A list or tuple of positional arguments.
  • A dict of keyword arguments, where the keys are the names of the arguments, and the values are arbitrary objects.

Here's a simple example of how it works:

from printo import describe_data_object

print(
    describe_data_object(
        'MyClassName',
        (1, 2, 'some text'),
        {'variable_name': 1, 'second_variable_name': 'kek'},
    )
)
#> MyClassName(1, 2, 'some text', variable_name=1, second_variable_name='kek')

Filtering

You can prevent individual parameters from being displayed. To do this, pass a dict to the filters parameter. The keys identify arguments by index or name. The values are functions that return a boolTrue keeps the argument and False skips it:

print(
    describe_data_object(
        'MyClassName',
        (1, 2, 'some text'),
        {'variable_name': 1, 'second_variable_name': 'kek'},
        filters={1: lambda x: False if x == 2 else True, 'second_variable_name': lambda x: False},
    )
)
#> MyClassName(1, 'some text', variable_name=1)

You can also use the provided not_none filter to automatically exclude None values:

from printo import not_none

print(
    describe_data_object(
        'MyClassName',
        (1, None),
        {},
        filters={1: not_none},
    )
)
#> MyClassName(1)

Custom display of objects

By default, all argument values are represented in the same way as the standard repr function would show them. There are only three exceptions:

  • For regular functions, the function name is displayed.
  • For classes, the class name is displayed.
  • For lambda functions, the complete source code is displayed. However, if a single line of source code contains more than one lambda function, only the λ symbol is displayed (this is a technical limitation of source code reflection in Python).

You can provide a custom serialization function for each argument value via the serializer parameter:

print(
    describe_data_object(
        'MyClassName',
        (1, 2, 'lol'),
        {'variable_name': 1, 'second_variable_name': 'kek'},
        serializer=lambda x: repr(x * 2),
    )
)
#> MyClassName(2, 4, 'lollol', variable_name=2, second_variable_name='kekkek')

Placeholders

For individual parameters, you can pass arbitrary strings that will be displayed instead of the actual values. This can be useful, for example, to hide the values of sensitive fields when serializing objects.

Pass a dict to the placeholders parameter, where the keys are argument names (for keyword arguments) or indices (for positional parameters, zero-indexed), and the values are strings:

print(
    describe_data_object(
        'MySuperClass',
        (1, 2, 'lol'),
        {'variable_name': 1, 'second_variable_name': 'kek'},
        placeholders={
            1: '***',
            'variable_name': '***',
        },
    )
)
#> MySuperClass(1, ***, 'lol', variable_name=***, second_variable_name='kek')

🤓 If you set a placeholder for a parameter, the custom serializer will not be applied to it.

Auto mode

You can remove the boilerplate code by using the @repred decorator for your class:

from printo import repred

@repred
class SomeClass:
    def __init__(self, a, b, c, *args, **kwargs):
        self.a = a
        self.b = b
        self.c = c
        self.args = args
        self.kwargs = kwargs

print(SomeClass(1, 2, 3))
#> SomeClass(1, 2, 3)
print(SomeClass(1, 2, 3, 4, 5))
#> SomeClass(1, 2, 3, 4, 5)
print(SomeClass(1, 2, 3, 4, 5, d=lambda x: x))
#> SomeClass(1, 2, 3, 4, 5, d=lambda x: x)

How does it work? Behind the scenes, the decorator uses AST analysis to generate code. The program attempts to determine which arguments passed to __init__ are stored in which attributes. In other words, it looks for direct assignments of the form self.a = a in the __init__ method.

If there is no direct assignment of a specific argument, an exception will be raised:

@repred
class SomeClass:
    def __init__(self, a):
        ...

#> ...
#> printo.errors.ParameterMappingNotFoundError: No internal object property or custom getter was found for the parameter a.

↑ The error occurs when the class is decorated.

If, for some reason, you are unable to specify this mapping in the body of the __init__ method, you can pass a function for a specific parameter that will extract it:

@repred(getters={'a': lambda x: x.a})
class SomeClass:
    def __init__(self, a):
        self.a = self.convert_a(a)

    def convert_a(self, a):
        return a

print(SomeClass(123))
#> SomeClass(a=123)

By default, @repred displays all arguments as keywords in most cases. However, you can pass the prefer_positional argument to the decorator, which will cause it to prefer omitting argument names in such cases:

@repred
class Class1:
    def __init__(self, a, b):
        self.a = a
        self.b = b

@repred(prefer_positional=True)
class Class2:
    def __init__(self, a, b):
        self.a = a
        self.b = b

print(Class1(123, 456))
#> Class1(a=123, b=456)
print(Class2(123, 456))
#> Class2(123, 456)

If you want to prevent certain __init__ parameters from being displayed, you can add their names to the ignore list:

@repred(ignore=['a'])
class SomeClass:
    def __init__(self, a, b):
        self.a = a
        self.b = b

print(SomeClass(123, 456))
#> SomeClass(b=456)

You can also add value-based filters for individual arguments by passing a dict of filters, similar to how it works in manual mode:

from printo import not_none

@repred(filters={'a': not_none})
class SomeClass:
    def __init__(self, a, b):
        self.a = a
        self.b = b

print(SomeClass(None, None))
#> SomeClass(b=None)
print(SomeClass(123, 456))
#> SomeClass(a=123, b=456)

By default, the class name is displayed based on its __name__ attribute, but you can configure it to use the __qualname__ attribute instead:

def function():
    @repred(qualname=True)
    class SomeClass:
        def __init__(self, a, b):
            self.a = a
            self.b = b
    return SomeClass

print(function()(123, 456))
#> function.<locals>.SomeClass(a=123, b=456)

⚠️ Auto mode is currently experimental, so there may be some bugs.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

printo-0.0.19.tar.gz (11.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

printo-0.0.19-py3-none-any.whl (9.6 kB view details)

Uploaded Python 3

File details

Details for the file printo-0.0.19.tar.gz.

File metadata

  • Download URL: printo-0.0.19.tar.gz
  • Upload date:
  • Size: 11.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for printo-0.0.19.tar.gz
Algorithm Hash digest
SHA256 337001bb9ead0a53d94574f82fb366b394b52f105075e4991e6f4302de25957b
MD5 926979e69a7be35af26a8d4e0907e7a2
BLAKE2b-256 6dc62b9a20a6f51b6b1fd39212961f7424c5b89e98fbde8663d4ddf43ca6192a

See more details on using hashes here.

Provenance

The following attestation bundles were made for printo-0.0.19.tar.gz:

Publisher: release.yml on mutating/printo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file printo-0.0.19-py3-none-any.whl.

File metadata

  • Download URL: printo-0.0.19-py3-none-any.whl
  • Upload date:
  • Size: 9.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for printo-0.0.19-py3-none-any.whl
Algorithm Hash digest
SHA256 b453edf2f5e7b65c1a9afc74f25f752001ccf5ece6963f5ec29bf47811cc39ad
MD5 3c35c3a8e082947d722c44fcdbcaee4f
BLAKE2b-256 d68bf4db98f5b36b058e2401640a8ce974d2fdcf1855c86af611503d0ba8e60d

See more details on using hashes here.

Provenance

The following attestation bundles were made for printo-0.0.19-py3-none-any.whl:

Publisher: release.yml on mutating/printo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page