Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pretty printing object instances (counter examples) #164

Open
PiotrZakrzewski opened this issue May 27, 2022 · 7 comments
Open

Pretty printing object instances (counter examples) #164

PiotrZakrzewski opened this issue May 27, 2022 · 7 comments

Comments

@PiotrZakrzewski
Copy link

Is your feature request related to a problem? Please describe.
When working with class instances as function parameters counter examples provided on stdout of crosshair show str(object) which does not contain info about the value of fields of this counter example. It looks like this:

/home/piotrzakrzewski/code/project/package/module/modulepy:29: error: false when calling function() (which returns <package.module.ClassName object at 0x7f30ffb49c10>)

Describe the solution you'd like
Using rich.inspect could allow for pretty printing objects even without custom __repr__
image

see https://rich.readthedocs.io/en/stable/introduction.html
Describe alternatives you've considered
Add msg / or at least docs to inform user that implementing __repr__ will improve their user experience?

@pschanely
Copy link
Owner

What a neat idea!

I'm also musing about a hybrid approach: if a good repr exists, it's nice to have something that's trivially copy+pasteable into an repl / debugger / unit test. Issue #48 is also a counterexample repr problem that might be influenced by our choices.

I will need to perform some experiments; depending on how rich.inspect is implemented, some of the CrossHair smoke and mirrors for symbolic values might leak through. (either way, it's a good test) I'll have time in the next week to dig in.

@pschanely
Copy link
Owner

Some exploration (and interesting CrossHair fixes related to rich's dynamic imports) has happened. But there's a bit of an onion to unravel here: I'd like to make a few improvements along the way, so it'll take a while. More updates in a few weeks!

@pschanely
Copy link
Owner

So this took me a few months to get to ... instead of a few weeks. But better late than never. As of 98ec6da, I've got something working: we output an eval()-able string that approximates the way we constructed the instance within CrossHair. This should remove the counterexample dependency on repr() for custom class instances.

This is an ~aggressively breaking change, and I'll want to poke at a few things before I cut a release ... but will update this issue again when that happens.

@azewiusz
Copy link
Contributor

I just want to mention that I came across this "issue" when started playing with CrossHair 0.0.31, classes annotated with @dataclasses.dataclass are represented nicely when I output pytest tests, but once I get to custom classes I get something like mentioned here - object reference.

def test_myfunction():
    assert myfunction(<concolic.intro.Counter object at 0x0000021928B99DD8>) == False

@pschanely
Copy link
Owner

pschanely commented Oct 16, 2022

Oh, great - glad that multiple people are interested in this. Would y'all give 0.0.32 a try? It contains my changes to make this issue better.

Here is a trivial example that reports the counterexample even though the class doesn't define repr: https://crosshair-web.org/?crosshair=0.1&python=3.8&gist=ea119ca6c87f9d92a6d75f58fad24898

@azewiusz
Copy link
Contributor

The one thing I can say about provided counterexample is that object attribute values are not mentioned by their names, but generally good direction.

/tmp/main.py:12: error: false when calling process(Foo(0, 0)) (which returns (0, 0))

@pschanely
Copy link
Owner

The one thing I can say about provided counterexample is that object attribute values are not mentioned by their names, but generally good direction.

/tmp/main.py:12: error: false when calling process(Foo(0, 0)) (which returns (0, 0))

Ah, indeed. I'd point out that keyword-only arguments (those after the optional *, marker) will be reported with a keyword. (like the "z" parameter in this example)

But the current behavior suppresses keywords when it can. This is something a matter of taste; I've made a poll in #180 - please vote!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants