1from functools import partial
2
3from .common import perform_regression_check, check_text_files
4
5
6class FileRegressionFixture:
7    """
8    Implementation of `file_regression` fixture.
9    """
10
11    def __init__(self, datadir, original_datadir, request):
12        """
13        :type datadir: Path
14        :type original_datadir: Path
15        :type request: FixtureRequest
16        """
17        self.request = request
18        self.datadir = datadir
19        self.original_datadir = original_datadir
20        self.force_regen = False
21
22    def check(
23        self,
24        contents,
25        encoding=None,
26        extension=".txt",
27        newline=None,
28        basename=None,
29        fullpath=None,
30        binary=False,
31        obtained_filename=None,
32        check_fn=None,
33    ):
34        """
35        Checks the contents against a previously recorded version, or generate a new file.
36
37        :param str contents: content to be verified.
38        :param str|None encoding: Encoding used to write file, if any.
39        :param str extension: Extension of file.
40        :param str|None newline: See `io.open` docs.
41        :param bool binary: If the file is binary or text.
42        :param obtained_filename: ..see:: FileRegressionCheck
43        :param check_fn: a function with signature ``(obtained_filename, expected_filename)`` that should raise
44            AssertionError if both files differ.
45            If not given, use internal function which compares text using :py:mod:`difflib`.
46        """
47        __tracebackhide__ = True
48
49        if binary and encoding:
50            raise ValueError(
51                "Only binary ({!r}) or encoding ({!r}) parameters must be passed at the same time.".format(
52                    binary, encoding
53                )
54            )
55
56        if binary:
57            assert isinstance(
58                contents, bytes
59            ), "Expected bytes contents but received type {}".format(
60                type(contents).__name__
61            )
62        else:
63            assert isinstance(
64                contents, str
65            ), "Expected text/unicode contents but received type {}".format(
66                type(contents).__name__
67            )
68
69        import io
70
71        if check_fn is None:
72
73            if binary:
74
75                def check_fn(obtained_filename, expected_filename):
76                    if obtained_filename.read_bytes() != expected_filename.read_bytes():
77                        raise AssertionError(
78                            "Binary files {} and {} differ.".format(
79                                obtained_filename, expected_filename
80                            )
81                        )
82
83            else:
84                check_fn = partial(check_text_files, encoding=encoding)
85
86        def dump_fn(filename):
87            mode = "wb" if binary else "w"
88            with open(str(filename), mode, encoding=encoding, newline=newline) as f:
89                f.write(contents)
90
91        perform_regression_check(
92            datadir=self.datadir,
93            original_datadir=self.original_datadir,
94            request=self.request,
95            check_fn=check_fn,
96            dump_fn=dump_fn,
97            extension=extension,
98            basename=basename,
99            fullpath=fullpath,
100            force_regen=self.force_regen,
101            obtained_filename=obtained_filename,
102        )
103
104    # non-PEP 8 alias used internally at ESSS
105    Check = check
106