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

Easier usage with floats #913

Open
shughes-uk opened this issue Oct 27, 2024 · 4 comments
Open

Easier usage with floats #913

shughes-uk opened this issue Oct 27, 2024 · 4 comments
Labels

Comments

@shughes-uk
Copy link

shughes-uk commented Oct 27, 2024

**Is your feature request related to a problem? Please describe **

We can't use syrupy when we are snapshotting objects with floats in them, due to precision issues.

Describe the solution you'd like

A way to set up a level of precision to match floats, ideally globally for all tests via a config option.

Describe alternatives you've considered

Using custom matchers on an individual attribute basis but thats a giant pain.

Additional context

@noahnu
Copy link
Collaborator

noahnu commented Nov 3, 2024

Using custom matchers on an individual attribute basis but thats a giant pain.

You can use a matcher based on type rather than attribute name.

Regardless, this has come up before. Open to ideas/contributions.

@noahnu noahnu added the feature request New feature or request label Nov 3, 2024
@shughes-uk
Copy link
Author

shughes-uk commented Nov 3, 2024

Using custom matchers on an individual attribute basis but thats a giant pain.

You can use a matcher based on type rather than attribute name.

Regardless, this has come up before. Open to ideas/contributions.

Interesting, I'm not sure i understand the matcher system based on the docs, I came away with the impression it would simply be asserting an attribute had a specific type. I was hoping I could do something like that but failed and was looking at custom serializers.

Ideally i could just drop in the pytest.approx function, i would be happy to make a docs PR with an example of how to do it if you can show me how!

@noahnu noahnu added this to the syrupy/5.0.0 milestone Feb 14, 2025
@noahnu
Copy link
Collaborator

noahnu commented Feb 17, 2025

A matcher is a function which takes two arguments:

  • data: The value to be serialized.
  • path: A tuple containing the path in the original object (since the matchers are applied recursively).

it then returns the "new" value. It's essentially just a replacement function (maybe "matcher" was a bad name in hindsight).

We have 2 built-in matchers which provide some syntactic sugar:

  • path_type: Lets you replace all values recursvely based on an isinstance check. E.g. replace all UUID instances with "" or all datetime instances with "".
  • path_value: Lets you replace all values recursively based on (optionally regular expression) match on the path or value. For example, instead of replacing all datetime fields by an instance of check on the value, you can replace all datetime fields when the key (path) contains "_time" in the name.

In Syrupy v5, multiple matchers can be composed using "compose_matchers".

In your case:

def test_round_float(snapshot):
    assert (2.0 / 3.0) == snapshot(
        matcher=path_type(
            types=(float,), replacer=lambda data, _: round(data, 5)
        )
    )

which produces a snapshot like so:

# name: test_round_float
  0.66667

To use something like pytest.approx is a bit tricky because we need to serialize some value. In theory you could override the matches function:

to have it somehow deserialize some pytest.approx context (won't be simple though).

Let me know if that helps.

@noahnu noahnu removed this from the syrupy/5.0.0 milestone Feb 17, 2025
@shughes-uk
Copy link
Author

Thanks for the in depth reply! I'll see what I can come up with tomorrow

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

No branches or pull requests

2 participants