@register_format()
General¶
register_format() allows you to add support for your custom file formats, such as the following Array type.
from dataclasses import dataclass
from typing import List
@dataclass
class Array:
numbers: List[int]
from pathlib import Path
from inline_snapshot import register_format, TextDiff, Format
from my_array import Array
@register_format
class ArrayFormat(TextDiff, Format[Array]):
suffix = ".arr"
@staticmethod
def is_format_for(data: object):
return isinstance(data, Array)
@staticmethod
def encode(value: Array, path: Path):
with path.open("w", encoding="utf-8", newline="\n") as f:
f.write("\n".join(map(str, value.numbers)))
@staticmethod
def decode(path: Path) -> Array:
with path.open("r", encoding="utf-8", newline="\n") as f:
return Array(list(map(int, f.read().splitlines())))
You can then use external() to save this type into an external file.
from my_array import Array
from inline_snapshot import external
def test_array():
assert Array([1, 2, 3]) == external()
inline-snapshot will check if the type matches by using is_format_for() and create a file with the given suffix.
Report¶
inline-snapshot needs to know how changes in your external files should be displayed. TextDiff and BinaryDiff can be used as mixin classes (see the Array example above) to provide generic representations for text or binary formats, but you can also define custom functions for your files.
rich_diff()is used every time the external snapshot value is changed and should show the difference between the original and new versions in a human-readable form.rich_show()is used every time an external snapshot is created and should show a human-readable form of the initial value.
from pathlib import Path
from inline_snapshot import register_format, Format, external
from number_set import NumberSet
@register_format
class NumberSetFormat(Format[NumberSet]):
suffix = ".numberset"
def rich_diff(self, original: Path, new: Path):
original_numbers = set(self.decode(original).numbers)
new_numbers = set(self.decode(new).numbers)
return (
f"new numbers: [green]{new_numbers-original_numbers}[/]\n"
f"removed numbers: [red]{original_numbers-new_numbers}[/]"
)
def rich_show(self, path: Path):
return " ".join(f"[blue]{n}[/]" for n in self.decode(path).numbers)
def is_format_for(self, data: object):
return isinstance(data, NumberSet)
def encode(self, value: NumberSet, path: Path):
with path.open("w", encoding="utf-8", newline="\n") as f:
f.write("\n".join(sorted(map(str, value.numbers))))
def decode(self, path: Path) -> NumberSet:
with path.open("r", encoding="utf-8", newline="\n") as f:
return NumberSet(set(map(int, f.read().splitlines())))
from dataclasses import dataclass
from typing import Set
@dataclass
class NumberSet:
numbers: Set[int]
The custom format is then used every time a NumberSet is compared with an empty external.
from number_set import NumberSet
from inline_snapshot import external
def test():
assert NumberSet([1, 2, 5]) == external()
assert NumberSet([1, 2, 8]) == external()
Reference¶
Format
¶
Base class for the Format Protocol.
priority = 0
class-attribute
instance-attribute
¶
Determines the correct format when multiple format handlers can handle
a given value (is_format_for).
priority is 0 by default and can be set to a smaller number for
generic formats that work with many data types (e.g., .json), where
is_format_for() also returns True for str and bytes. This allows
you to use assert "text" == external() without explicitly providing
a ".txt" suffix to distinguish it from ".json".
A higher priority can be used for more specific formats, such as bytes
with a b"\x89PNG" prefix that should be stored as .png files.
suffix
instance-attribute
¶
The suffix associated with this format handler.
Every format implementation must define a suffix. This suffix is used when the external file is written and is required to find the correct format handler when the file is read again.
decode(path)
¶
Reads the value from the specified path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
The path to a temporary file where the value is stored. |
required |
Returns:
| Type | Description |
|---|---|
T
|
The value of the external object. |
encode(value, path)
¶
Converts the value and stores it in the specified path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
T
|
The value to be stored. |
required |
path
|
Path
|
The path to a temporary file where the value should be stored. |
required |
is_format_for(value)
¶
Determines if this format handler can handle the given value.
This function is used to find the correct format handler when no suffix is provided.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
object
|
The value to be formatted. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
rich_diff(original, new)
¶
Displays a diff between the original and new files.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
original
|
Path
|
The path to the original external file. |
required |
new
|
Path
|
The path to the new external file. |
required |
Returns:
| Type | Description |
|---|---|
RenderableType
|
A rich renderable object representing the diff. This can be a |
RenderableType
|
textual diff or another type of representation. |
rich_show(path)
¶
Displays a representation of a newly created external object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
The path to the external file. |
required |
Returns:
| Type | Description |
|---|---|
RenderableType
|
A rich renderable object representing the new object. The |
RenderableType
|
representation should be concise. |
register_format(format=None, *, replace_handler=False)
¶
Registers a new format handler for the suffix format.suffix.
This function can also be used as a decorator:
which is equivalent to:
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
format
|
type[Format[FormatT]] | Format[FormatT] | None
|
The format handler class or instance. |
None
|
replace_handler
|
bool
|
If |
False
|
Raises:
| Type | Description |
|---|---|
UsageError
|
If a handler for the same suffix already exists and |