File: custom-database.rst

package info (click to toggle)
python-hypothesis 6.138.14-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 15,304 kB
  • sloc: python: 63,312; ruby: 1,107; sh: 253; makefile: 41; javascript: 6
file content (52 lines) | stat: -rw-r--r-- 2,501 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
Write a custom Hypothesis database
==================================

To define your own |ExampleDatabase| class, implement the |ExampleDatabase.save|, |ExampleDatabase.fetch|, and |ExampleDatabase.delete| methods.

For example, here's a simple database class that uses :mod:`sqlite <sqlite3>` as the backing data store:

.. code-block:: python

    import sqlite3
    from collections.abc import Iterable

    from hypothesis.database import ExampleDatabase

    class SQLiteExampleDatabase(ExampleDatabase):
        def __init__(self, db_path: str):
            self.conn = sqlite3.connect(db_path)

            self.conn.execute(
                """
                CREATE TABLE examples (
                    key BLOB,
                    value BLOB,
                    UNIQUE (key, value)
                )
            """
            )

        def save(self, key: bytes, value: bytes) -> None:
            self.conn.execute(
                "INSERT OR IGNORE INTO examples VALUES (?, ?)",
                (key, value),
            )

        def fetch(self, key: bytes) -> Iterable[bytes]:
            cursor = self.conn.execute("SELECT value FROM examples WHERE key = ?", (key,))
            yield from [value[0] for value in cursor.fetchall()]

        def delete(self, key: bytes, value: bytes) -> None:
            self.conn.execute(
                "DELETE FROM examples WHERE key = ? AND value = ?",
                (key, value),
            )

Database classes are not required to implement |ExampleDatabase.move|. The default implementation of a move is a |ExampleDatabase.delete| of the value in the old key, followed by a |ExampleDatabase.save| of the value in the new key. You can override |ExampleDatabase.move| to override this behavior, if for instance the backing store offers a more efficient move implementation.

Change listening
----------------

To support change listening in a database class, you should call |ExampleDatabase._broadcast_change| whenever a value is saved, deleted, or moved in the backing database store. How you track this depends on the details of the database class. For instance, in |DirectoryBasedExampleDatabase|, Hypothesis installs a filesystem monitor via :pypi:`watchdog` in order to broadcast change events.

Two useful related methods are |ExampleDatabase._start_listening| and |ExampleDatabase._stop_listening|, which a database class can override to know when to start or stop expensive listening operations. See documentation for details.