python-attrs / python-attrs/attrs

Add utility to print source of attrs class.

Open
#1,472 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Feature
Dominant language
Python
Stars
5.8k
Forks
480
Avg merge
2h 15m
Merged PRs (30d)
2

Description

I love this library. It lets me write classes without writing boilerplate that would take a lot of time. However, I am a very curious person, and I'd like to know what code attrs generated for my class. It can be useful to both debug unexpected behaviour and to get a feel for all the boilerplate attrs handles for me. In the docs there is an example that if I write:

@attrs.define
class SmartClass:
    a = attrs.field()
    b = attrs.field()

it will roughly be translated into:

class ArtisanalClass:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __repr__(self):
        return f"ArtisanalClass(a={self.a}, b={self.b})"

    def __eq__(self, other):
        if other.__class__ is self.__class__:
            return (self.a, self.b) == (other.a, other.b)
        else:
            return NotImplemented

    def __ne__(self, other):
        result = self.__eq__(other)
        if result is NotImplemented:
            return NotImplemented
        else:
            return not result

    def __lt__(self, other):
        if other.__class__ is self.__class__:
            return (self.a, self.b) < (other.a, other.b)
        else:
            return NotImplemented

    def __le__(self, other):
        if other.__class__ is self.__class__:
            return (self.a, self.b) <= (other.a, other.b)
        else:
            return NotImplemented

    def __gt__(self, other):
        if other.__class__ is self.__class__:
            return (self.a, self.b) > (other.a, other.b)
        else:
            return NotImplemented

    def __ge__(self, other):
        if other.__class__ is self.__class__:
            return (self.a, self.b) >= (other.a, other.b)
        else:
            return NotImplemented

    def __hash__(self):
        return hash((self.__class__, self.a, self.b))

First of all, this example is weird since the class name has changed, and also, there are comparison methods despite the fact that order=True wasn't given. Also, __slots__ are missing. Ignoring, these issues it would still be nice to see the code generated by attrs.

I tried to write a simple class:

@attrs.define
class SmartClass:
    a: int
    b: str = "default"

    def __repr__(self) -> str:
        return f"<SmartClass(a={self.a})>"

and I tried to inspect its code using inspect.getsource:

import inspect

print(inspect.getsource(SmartClass))

However, I just got the original class definition without any attrs generated methods. The docs show that inspect.getsource can retrieve the generated code for individual methods. However, I would also like to be able to see the entire generated code with a regular class syntax. I think a utility function should be added to return the entire generated source code, so it can be inspected.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the documented hand-written-class example and the “How does it work?” documentation, then compare them with Python’s inspect.getsource behavior shown in the issue. Define and implement a utility that returns the complete generated class source, including attrs-generated methods and class details; done means the generated code can be inspected as regular class syntax.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.