Python client for Varsnap, a snapshot testing service that records and compares function inputs and outputs
Project description
Varsnap Python
Installation
Install from PyPI - pip install varsnap
Requirements
The client depends on four environment variables to be set:
VARSNAP- Should be eithertrueorfalse. Varsnap will be disabled if the variable is anything other thantrue.ENV- If set todevelopment, the client will receive events from production. If set toproduction, the client will emit events.VARSNAP_PRODUCER_TOKEN- Only clients with this token may emit production snapshots. Copied from https://www.varsnap.com/user/VARSNAP_CONSUMER_TOKEN- Only clients with this token may consume production snapshots in development. Copied from https://www.varsnap.com/user/
Usage
Add the varsnap decorator in front of any function you'd like to make better:
from varsnap import varsnap
@varsnap
def example(args, **kwargs):
return 'output'
Custom serialization
Varsnap serializes a function's inputs and outputs as JSON when possible and
falls back to pickle otherwise. To control how a value of a particular type is
serialized, give that type a pair of varsnap_serialize / varsnap_deserialize
classmethods. Varsnap reads the function's type annotations and uses these
classmethods for any annotated parameter or return value:
from varsnap import varsnap
class Money:
def __init__(self, cents):
self.cents = cents
@classmethod
def varsnap_serialize(cls, value):
return str(value.cents)
@classmethod
def varsnap_deserialize(cls, data):
return cls(int(data))
@varsnap
def add_tax(price: Money) -> Money:
return Money(round(price.cents * 1.1))
If a function isn't annotated (or you want to override its annotations), pass the types explicitly to the decorator:
@varsnap(types={'price': Money}, returns=Money)
def add_tax(price):
return Money(round(price.cents * 1.1))
The type is always taken from the decorated function, never from the serialized data, so stored snapshots can't redirect deserialization to a different type. Values whose type doesn't provide these classmethods continue to use the default JSON/pickle serialization.
Security of deserialization
Snapshots are fetched from the varsnap server and deserialized on your machine, so the wire format is treated as untrusted input. Varsnap serializes values in one of three formats:
json:— plain JSON. Always safe to deserialize.type:— produced by a type'svarsnap_serialize. Safe: the class is taken from the decorated function's annotations, never from the payload.pickle:— adill/picklefallback for values JSON can't represent. Unpickling executes arbitrary code embedded in the payload, so anyone who can influence stored snapshot data could run code on the machine that reads it. Varsnap emits a warning whenever it falls back to this path.
Prefer the type: path for any value that would otherwise be pickled: give its
type varsnap_serialize / varsnap_deserialize classmethods, which is both
safe and version-stable.
Testing
With the proper environment variables set, in a test file, add:
import unittest
from varsnap import test
class TestIntegration(unittest.TestCase):
def test_varsnap(self):
matches, logs = test()
if matches is None:
raise unittest.case.SkipTest('No Snaps found')
self.assertTrue(matches, logs)
If you're testing a Flask application, set up a test request context when testing:
# app = Flask()
with app.test_request_context():
matches, logs = test()
Troubleshooting
Decorators changing function names
Using decorators may change the name of functions. In order to not confuse
varsnap, set the decorated function's __qualname__ and __signature__ to
match the original function:
import inspect
def decorator(func):
def decorated(*args, **kwargs):
return func(*args, **kwargs)
decorated.__qualname__ = func.__qualname__
decorated.__signature__ = inspect.signature(func)
return decorated
Publishing
pip install build twine
python -m build
twine upload dist/*
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file varsnap-1.6.0.tar.gz.
File metadata
- Download URL: varsnap-1.6.0.tar.gz
- Upload date:
- Size: 15.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
15644a3b087be0bfaedae0305c75f01a355a96b49134e241c97170afcd3f4418
|
|
| MD5 |
fc74762b27d57a3bb3b1f76c19d634b2
|
|
| BLAKE2b-256 |
d9ee1778f88368df3a0752a5732ae40a596e8c5ec5d7f15c6d9adead61f93a5f
|
Provenance
The following attestation bundles were made for varsnap-1.6.0.tar.gz:
Publisher:
publish.yml on albertyw/varsnap-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
varsnap-1.6.0.tar.gz -
Subject digest:
15644a3b087be0bfaedae0305c75f01a355a96b49134e241c97170afcd3f4418 - Sigstore transparency entry: 2065945788
- Sigstore integration time:
-
Permalink:
albertyw/varsnap-python@9f28e87499f3897e6a1fe36dc10bb9b02c011452 -
Branch / Tag:
refs/tags/v1.6.0 - Owner: https://github.com/albertyw
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9f28e87499f3897e6a1fe36dc10bb9b02c011452 -
Trigger Event:
push
-
Statement type:
File details
Details for the file varsnap-1.6.0-py3-none-any.whl.
File metadata
- Download URL: varsnap-1.6.0-py3-none-any.whl
- Upload date:
- Size: 11.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
37599ddf3738e58d225dfcfe54491f502a043ccc4b9456ab2d543f2acadd09d5
|
|
| MD5 |
cdabee84cbbfe1f6b89a2a4c6c22fb5c
|
|
| BLAKE2b-256 |
11e4d8712f9ea8e445400c4d8a2926230bed60581e5c6a22452cef844962109f
|
Provenance
The following attestation bundles were made for varsnap-1.6.0-py3-none-any.whl:
Publisher:
publish.yml on albertyw/varsnap-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
varsnap-1.6.0-py3-none-any.whl -
Subject digest:
37599ddf3738e58d225dfcfe54491f502a043ccc4b9456ab2d543f2acadd09d5 - Sigstore transparency entry: 2065945840
- Sigstore integration time:
-
Permalink:
albertyw/varsnap-python@9f28e87499f3897e6a1fe36dc10bb9b02c011452 -
Branch / Tag:
refs/tags/v1.6.0 - Owner: https://github.com/albertyw
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9f28e87499f3897e6a1fe36dc10bb9b02c011452 -
Trigger Event:
push
-
Statement type: