Repository: hajimes/mmh3 (language: python)

Issue:
Add Read the Docs documentation
The title says it all. It will also include benchmarking results produced by Issue #53.
Enhance docstrings
Enhance docstrings of the library so that it follows one of the three major styles (probably Google's one). Related to Issue #54.

The update will be reflected in version 4.2.0, which will be released shortly after 2024-10-01, the scheduled date of Python 3.13 release.
Fix and improve type hints
The previous version of type hints did not reflect the actual interfaces of mmh3. This PR fixes the issue, with the introduction of [ReadableBuffer](https://github.com/python/typeshed/blob/6259b616585ec1eb6726294851988472c7ebface/stdlib/_typeshed/__init__.pyi#L281) from typeshed for the official `hashlib`.

Note that as of Python 3.12, ReadbleBuffer in typeshed is an alias for [typing_extensions.Buffer](https://typing-extensions.readthedocs.io/en/latest/#typing_extensions.Buffer), which was officially introduced as [collections.abc.Buffer](https://docs.python.org/3/library/collections.abc.html#collections.abc.Buffer) in Python 3.12 by [PEP 688](https://peps.python.org/pep-0688/).


Discussion / hints:

Fix patch:
diff --git a/docs/api.md b/docs/api.md
new file mode 100644
index 0000000..3c64eb5
--- /dev/null
+++ b/docs/api.md
@@ -0,0 +1,73 @@
+# API Reference
+
+```{caution}
+  This reference contains functions that are not yet released in the stable
+  version.
+```
+
+## Functions for immutables
+
+The following functions are used to hash immutable types, specifically
+`bytes` and `str`. String inputs are automatically converted to `bytes` using
+UTF-8 encoding before hashing.
+
+```{eval-rst}
+.. autofunction:: mmh3.hash
+.. autofunction:: mmh3.hash128
+.. autofunction:: mmh3.hash64
+.. autofunction:: mmh3.hash_bytes
+```
+
+## Functions for Buffer
+
+The following functions are used to hash types that implement the buffer
+protocol such as `bytes`, `bytearray`, `memoryview`, and `numpy` arrays.
+String inputs are also supported and are automatically converted to `bytes`
+using UTF-8 encoding before hashing.
+
+The buffer protocol,
+[originally implemented as a part of Python/C API](https://docs.python.org/3/c-api/buffer.html),
+was formally defined as a Python-level API in
+[PEP 688](https://peps.python.org/pep-0688/)
+in 2022 and its corresponding type hint was introduced as
+[collections.abc.Buffer](https://docs.python.org/3/library/collections.abc.html#collections.abc.Buffer)
+in Python 3.12. For earlier Python versions, `mmh3` uses a type alias for the
+type hint
+[\_typeshed.ReadableBuffer](https://github.com/python/typeshed/blob/d326c9bd424ad60c2b63c2ca1c5c1006c61c3562/stdlib/_typeshed/__init__.pyi#L281),
+which is itself an alias for
+[typing_extensions.Buffer](https://typing-extensions.readthedocs.io/en/latest/#typing_extensions.Buffer),
+the backported type hint for `collections.abc.Buffer`.
+
+```{eval-rst}
+.. autofunction:: mmh3.hash_from_buffer
+.. autofunction:: mmh3.mmh3_32_digest
+.. autofunction:: mmh3.mmh3_32_sintdigest
+.. autofunction:: mmh3.mmh3_32_uintdigest
+.. autofunction:: mmh3.mmh3_x64_128_digest
+.. autofunction:: mmh3.mmh3_x64_128_sintdigest
+.. autofunction:: mmh3.mmh3_x64_128_stupledigest
+.. autofunction:: mmh3.mmh3_x64_128_uintdigest
+.. autofunction:: mmh3.mmh3_x64_128_utupledigest
+.. autofunction:: mmh3.mmh3_x86_128_digest
+.. autofunction:: mmh3.mmh3_x86_128_sintdigest
+.. autofunction:: mmh3.mmh3_x86_128_stupledigest
+.. autofunction:: mmh3.mmh3_x86_128_uintdigest
+.. autofunction:: mmh3.mmh3_x86_128_utupledigest
+```
+
+## Hasher Classes
+
+```{eval-rst}
+.. autoclass:: mmh3.mmh3_32
+   :members:
+```
+
+```{eval-rst}
+.. autoclass:: mmh3.mmh3_x64_128
+   :members:
+```
+
+```{eval-rst}
+.. autoclass:: mmh3.mmh3_x86_128
+   :members:
+```
diff --git a/docs/api.rst b/docs/api.rst
deleted file mode 100644
index 479e4a6..0000000
--- a/docs/api.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-API Reference
-================
-
-.. caution::
-  This reference contains functions that are not yet released in the stable version.
-
-.. automodule:: mmh3
-   :members:
-   :undoc-members:
-   :show-inheritance:
diff --git a/docs/conf.py b/docs/conf.py
index d4925df..b4820b0 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -17,7 +17,12 @@
 # -- General configuration ---------------------------------------------------
 # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
 
-extensions = ["sphinx.ext.autodoc", "sphinx.ext.napoleon", "myst_parser"]
+extensions = [
+    "sphinx.ext.autodoc",
+    "sphinx.ext.napoleon",
+    "sphinx_copybutton",
+    "myst_parser",
+]
 
 templates_path = ["_templates"]
 exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
@@ -30,3 +35,8 @@
 html_theme_options = {
     "github_url": "https://github.com/hajimes/mmh3",
 }
+
+# -- Options for autodoc -------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html
+
+autodoc_member_order = "groupwise"
diff --git a/pyproject.toml b/pyproject.toml
index 810fb30..18c463f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -36,7 +36,8 @@ test = [
 docs = [
   "myst-parser == 4.0.0",
   "shibuya == 2024.8.30",
-  "sphinx == 8.0.2"
+  "sphinx == 8.0.2",
+  "sphinx-copybutton == 0.5.2"
 ]
 benchmark = [
   "pymmh3 == 0.0.5",
diff --git a/src/mmh3/__init__.pyi b/src/mmh3/__init__.pyi
index 3243420..6cc363d 100644
--- a/src/mmh3/__init__.pyi
+++ b/src/mmh3/__init__.pyi
@@ -1,52 +1,52 @@
 # to use list, tuple, dict ... in Python 3.7 and 3.8
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Union, final
+import sys
+from typing import Union, final
 
-if TYPE_CHECKING:
-    from _typeshed import ReadableBuffer
+if sys.version_info >= (3, 12):
+    from collections.abc import Buffer
+else:
+    from _typeshed import ReadableBuffer as Buffer
 
-HashableImmutable = Union[str, bytes]
-HashableBuffer = Union[HashableImmutable, ReadableBuffer]
-
-def hash(key: HashableImmutable, seed: int = 0, signed: bool = True) -> int: ...
+def hash(key: Union[bytes, str], seed: int = 0, signed: bool = True) -> int: ...
 def hash_from_buffer(
-    key: HashableBuffer, seed: int = 0, signed: bool = True
+    key: Union[Buffer, str], seed: int = 0, signed: bool = True
 ) -> int: ...
 def hash64(
-    key: HashableImmutable, seed: int = 0, x64arch: bool = True, signed: bool = True
+    key: Union[bytes, str], seed: int = 0, x64arch: bool = True, signed: bool = True
 ) -> tuple[int, int]: ...
 def hash128(
-    key: HashableImmutable, seed: int = 0, x64arch: bool = True, signed: bool = False
+    key: Union[bytes, str], seed: int = 0, x64arch: bool = True, signed: bool = False
 ) -> int: ...
 def hash_bytes(
-    key: HashableImmutable, seed: int = 0, x64arch: bool = True
+    key: Union[bytes, str], seed: int = 0, x64arch: bool = True
 ) -> bytes: ...
-def mmh3_32_digest(key: HashableBuffer, seed: int = 0) -> bytes: ...
-def mmh3_32_sintdigest(key: HashableBuffer, seed: int = 0) -> int: ...
-def mmh3_32_uintdigest(key: HashableBuffer, seed: int = 0) -> int: ...
-def mmh3_x64_128_digest(key: HashableBuffer, seed: int = 0) -> bytes: ...
-def mmh3_x64_128_sintdigest(key: HashableBuffer, seed: int = 0) -> int: ...
-def mmh3_x64_128_uintdigest(key: HashableBuffer, seed: int = 0) -> int: ...
+def mmh3_32_digest(key: Union[Buffer, str], seed: int = 0) -> bytes: ...
+def mmh3_32_sintdigest(key: Union[Buffer, str], seed: int = 0) -> int: ...
+def mmh3_32_uintdigest(key: Union[Buffer, str], seed: int = 0) -> int: ...
+def mmh3_x64_128_digest(key: Union[Buffer, str], seed: int = 0) -> bytes: ...
+def mmh3_x64_128_sintdigest(key: Union[Buffer, str], seed: int = 0) -> int: ...
+def mmh3_x64_128_uintdigest(key: Union[Buffer, str], seed: int = 0) -> int: ...
 def mmh3_x64_128_stupledigest(
-    key: HashableBuffer, seed: int = 0
+    key: Union[Buffer, str], seed: int = 0
 ) -> tuple[int, int]: ...
 def mmh3_x64_128_utupledigest(
-    key: HashableBuffer, seed: int = 0
+    key: Union[Buffer, str], seed: int = 0
 ) -> tuple[int, int]: ...
-def mmh3_x86_128_digest(key: HashableBuffer, seed: int = 0) -> bytes: ...
-def mmh3_x86_128_sintdigest(key: HashableBuffer, seed: int = 0) -> int: ...
-def mmh3_x86_128_uintdigest(key: HashableBuffer, seed: int = 0) -> int: ...
+def mmh3_x86_128_digest(key: Union[Buffer, str], seed: int = 0) -> bytes: ...
+def mmh3_x86_128_sintdigest(key: Union[Buffer, str], seed: int = 0) -> int: ...
+def mmh3_x86_128_uintdigest(key: Union[Buffer, str], seed: int = 0) -> int: ...
 def mmh3_x86_128_stupledigest(
-    key: HashableBuffer, seed: int = 0
+    key: Union[Buffer, str], seed: int = 0
 ) -> tuple[int, int]: ...
 def mmh3_x86_128_utupledigest(
-    key: HashableBuffer, seed: int = 0
+    key: Union[Buffer, str], seed: int = 0
 ) -> tuple[int, int]: ...
 
 class Hasher:
     def __init__(self, seed: int = 0) -> None: ...
-    def update(self, input: ReadableBuffer) -> None: ...
+    def update(self, data: Buffer) -> None: ...
     def digest(self) -> bytes: ...
     def sintdigest(self) -> int: ...
     def uintdigest(self) -> int: ...
diff --git a/src/mmh3/mmh3module.c b/src/mmh3/mmh3module.c
index c5fc255..3c17a65 100644
--- a/src/mmh3/mmh3module.c
+++ b/src/mmh3/mmh3module.c
@@ -35,10 +35,23 @@ typedef unsigned __int64 uint64_t;
 //-----------------------------------------------------------------------------
 // One shot functions
 
-PyDoc_STRVAR(mmh3_hash_doc,
-             "hash(key[, seed=0, signed=True]) -> 32-bit int\n\n"
-             "Return a hash value as a 32-bit integer. "
-             "Calculated by the MurmurHash3_x86_32 algorithm.");
+PyDoc_STRVAR(
+    mmh3_hash_doc,
+    "hash(key[, seed=0, signed=True]) -> int\n"
+    "\n"
+    "Return a hash as a 32-bit integer.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x86_32 algorithm.\n"
+    "\n"
+    "Args:\n"
+    "    key (bytes | str): The input data to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "    signed (bool): If True, return a signed integer. Otherwise, return "
+    "an unsigned integer.\n"
+    "\n"
+    "Returns:\n"
+    "    int: The hash value as a 32-bit integer.\n");
 
 static PyObject *
 mmh3_hash(PyObject *self, PyObject *args, PyObject *keywds)
@@ -93,11 +106,24 @@ mmh3_hash(PyObject *self, PyObject *args, PyObject *keywds)
 #endif  // defined(_MSC_VER)
 }
 
-PyDoc_STRVAR(mmh3_hash_from_buffer_doc,
-             "hash_from_buffer(key[, seed=0, signed=True]) -> 32-bit int\n\n"
-             "Return a hash value from a memory buffer as a 32-bit integer. "
-             "Calculated by the MurmurHash3_x86_32 algorithm. "
-             "Designed for large memory-views such as numpy arrays.");
+PyDoc_STRVAR(
+    mmh3_hash_from_buffer_doc,
+    "hash_from_buffer(key[, seed=0, signed=True]) -> int\n"
+    "\n"
+    "Return a hash for the buffer as a 32-bit integer.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x86_32 algorithm. Designed for large "
+    "memory-views such as numpy arrays.\n"
+    "\n"
+    "Args:\n"
+    "    key (Buffer | str): The bufer to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "    signed (bool): If True, return a signed integer. Otherwise, return "
+    "an unsigned integer.\n"
+    "\n"
+    "Returns:\n"
+    "    int: The hash value as a 32-bit integer.\n");
 
 static PyObject *
 mmh3_hash_from_buffer(PyObject *self, PyObject *args, PyObject *keywds)
@@ -154,12 +180,24 @@ mmh3_hash_from_buffer(PyObject *self, PyObject *args, PyObject *keywds)
 
 PyDoc_STRVAR(
     mmh3_hash64_doc,
-    "hash64(key[, seed=0, x64arch=True, signed=True]) -> (64-bit int, "
-    "64-bit "
-    "int)\n\n"
-    "Return a tuple of two 64 bit integers given an input string. "
-    "Calculated by the MurmurHash3_x{64, 86}_128 algorithm. Optimized "
-    "for the x64 bit architecture when x64arch=True, otherwise for x86.");
+    "hash64(key[, seed=0, x64arch=True, signed=True]) -> tuple[int, int]\n"
+    "\n"
+    "Return a hash as a tuple of two 64-bit integers.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x{64, 86}_128 algorithm.\n"
+    "\n"
+    "Args:\n"
+    "    key (bytes | str): The input data to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "    x64arch (bool): If True, use an algorithm optimized for 64-bit "
+    "architecture. Otherwise, use one optimized for 32-bit architecture.\n"
+    "    signed (bool): If True, return a signed integer. Otherwise, return "
+    "an unsigned integer.\n"
+    "\n"
+    "Returns:\n"
+    "    tuple[int, int]: The hash value as a tuple of two 64-bit "
+    "integers.\n");
 
 static PyObject *
 mmh3_hash64(PyObject *self, PyObject *args, PyObject *keywds)
@@ -193,13 +231,24 @@ mmh3_hash64(PyObject *self, PyObject *args, PyObject *keywds)
     return retval;
 }
 
-PyDoc_STRVAR(mmh3_hash128_doc,
-             "hash128(key[, seed=0, x64arch=True, signed=False]]) -> 128-bit "
-             "int\n\n"
-             "Return a 128 bit long integer. "
-             "Calculated by the MurmurHash3_x{64, 86}_128 algorithm. "
-             "Optimized for the x64 bit architecture "
-             "when x64arch=True, otherwise for x86.");
+PyDoc_STRVAR(
+    mmh3_hash128_doc,
+    "hash128(key[, seed=0, x64arch=True, signed=False]]) -> int\n"
+    "\n"
+    "Return a hash as a 128-bit integer.\n\n"
+    "Calculated by the MurmurHash3_x{64, 86}_128 algorithm.\n"
+    "\n"
+    "Args:\n"
+    "    key (bytes | str): The input data to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "    x64arch (bool): If True, use an algorithm optimized for 64-bit "
+    "architecture. Otherwise, use one optimized for 32-bit architecture.\n"
+    "    signed (bool): If True, return a signed integer. Otherwise, return "
+    "an unsigned integer.\n"
+    "\n"
+    "Returns:\n"
+    "    int: The hash value as a 128-bit integer.\n");
 
 static PyObject *
 mmh3_hash128(PyObject *self, PyObject *args, PyObject *keywds)
@@ -246,10 +295,20 @@ mmh3_hash128(PyObject *self, PyObject *args, PyObject *keywds)
 
 PyDoc_STRVAR(
     mmh3_hash_bytes_doc,
-    "hash_bytes(key[, seed=0, x64arch=True]) -> bytes\n\n"
-    "Return a 128 bit hash value as bytes for a string. Optimized for "
-    "the x64 bit architecture when "
-    "x64arch=True, otherwise for the x86.");
+    "hash_bytes(key[, seed=0, x64arch=True]) -> bytes\n"
+    "\n"
+    "Return a 16-byte hash of the ``bytes`` type.\n"
+    "\n"
+    "Args:\n"
+    "    key (bytes | str): The input data to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "    x64arch (bool): If True, use an algorithm optimized for 64-bit "
+    "architecture. Otherwise, use one optimized for 32-bit architecture.\n"
+    "\n"
+    "Returns:\n"
+    "    bytes: The hash value as the ``bytes`` type with a length of 16 "
+    "bytes (128 bits).\n");
 
 static PyObject *
 mmh3_hash_bytes(PyObject *self, PyObject *args, PyObject *keywds)
@@ -284,11 +343,24 @@ mmh3_hash_bytes(PyObject *self, PyObject *args, PyObject *keywds)
     return PyBytes_FromStringAndSize((char *)result, MMH3_128_DIGESTSIZE);
 }
 
-PyDoc_STRVAR(mmh3_mmh3_32_digest_doc,
-             "mmh3_32_digest(key[, seed=0]) -> bytes\n\n"
-             "Return a hash value from a memory buffer as bytes. "
-             "Calculated by the MurmurHash3_x86_32 algorithm. "
-             "Designed for large memory-views such as numpy arrays.");
+PyDoc_STRVAR(
+    mmh3_mmh3_32_digest_doc,
+    "mmh3_32_digest(key[, seed=0]) -> bytes\n"
+    "\n"
+    "Return a 4-byte hash of the ``bytes`` type for the buffer.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x86_32 algorithm.\n"
+    "\n"
+    "Args:\n"
+    "    key (Buffer | str): The input buffer to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "\n"
+    "Returns:\n"
+    "    bytes: The hash value as the ``bytes`` type with a length of 4 bytes "
+    "(32 bits).\n"
+    "\n"
+    ".. versionadded:: 4.2.0\n");
 
 static PyObject *
 mmh3_mmh3_32_digest(PyObject *self, PyObject *args, PyObject *keywds)
@@ -316,9 +388,21 @@ mmh3_mmh3_32_digest(PyObject *self, PyObject *args, PyObject *keywds)
 
 PyDoc_STRVAR(
     mmh3_mmh3_32_sintdigest_doc,
-    "mmh3_32_sintdigest(key[, seed=0]) -> 32-bit int\n\n"
-    "Return a hash value from a memory buffer as a signed 32-bit integer. "
-    "Calculated by the MurmurHash3_x86_32 algorithm. ");
+    "mmh3_32_sintdigest(key[, seed=0]) -> int\n"
+    "\n"
+    "Return a hash for the buffer as a 32-bit signed integer.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x86_32 algorithm. "
+    "\n"
+    "Args:\n"
+    "    key (Buffer | str): The input buffer to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "\n"
+    "Returns:\n"
+    "    int: The hash value as a 32-bit signed integer.\n"
+    "\n"
+    ".. versionadded:: 4.2.0\n");
 
 static PyObject *
 mmh3_mmh3_32_sintdigest(PyObject *self, PyObject *args, PyObject *keywds)
@@ -342,9 +426,21 @@ mmh3_mmh3_32_sintdigest(PyObject *self, PyObject *args, PyObject *keywds)
 
 PyDoc_STRVAR(
     mmh3_mmh3_32_uintdigest_doc,
-    "mmh3_32_uintdigest(key[, seed=0]) -> 32-bit int\n\n"
-    "Return a hash value from a memory buffer as an unsigned 32-bit integer. "
-    "Calculated by the MurmurHash3_x86_32 algorithm. ");
+    "mmh3_32_uintdigest(key[, seed=0]) -> int\n"
+    "\n"
+    "Return a hash for the buffer as a 32-bit unsigned integer.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x86_32 algorithm. "
+    "\n"
+    "Args:\n"
+    "    key (Buffer | str): The input buffer to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "\n"
+    "Returns:\n"
+    "    int: The hash value as a 32-bit unsigned integer.\n"
+    "\n"
+    ".. versionadded:: 4.2.0\n");
 
 static PyObject *
 mmh3_mmh3_32_uintdigest(PyObject *self, PyObject *args, PyObject *keywds)
@@ -366,10 +462,24 @@ mmh3_mmh3_32_uintdigest(PyObject *self, PyObject *args, PyObject *keywds)
     return PyLong_FromUnsignedLong(result[0]);
 }
 
-PyDoc_STRVAR(mmh3_mmh3_x64_128_digest_doc,
-             "mmh3_x64_128_digest(key[, seed=0]) -> bytes\n\n"
-             "Return a hash value from a memory buffer as bytes. "
-             "Calculated by the MurmurHash3_x64_128 algorithm. ");
+PyDoc_STRVAR(
+    mmh3_mmh3_x64_128_digest_doc,
+    "mmh3_x64_128_digest(key[, seed=0]) -> bytes\n"
+    "\n"
+    "Return a 16-byte hash of the ``bytes`` type for the buffer.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x64_128 algorithm.\n"
+    "\n"
+    "Args:\n"
+    "    key (Buffer | str): The input buffer to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "\n"
+    "Returns:\n"
+    "    bytes: The hash value as the ``bytes`` type with a length of 16 "
+    "bytes (128 bits).\n"
+    "\n"
+    ".. versionadded:: 4.2.0\n");
 
 static PyObject *
 mmh3_mmh3_x64_128_digest(PyObject *self, PyObject *args, PyObject *keywds)
@@ -398,9 +508,21 @@ mmh3_mmh3_x64_128_digest(PyObject *self, PyObject *args, PyObject *keywds)
 
 PyDoc_STRVAR(
     mmh3_mmh3_x64_128_sintdigest_doc,
-    "mmh3_x64_128_sintdigest(key[, seed=0]) -> int\n\n"
-    "Return a hash value from a memory buffer as a signed 128-bit integer. "
-    "Calculated by the MurmurHash3_x64_128 algorithm. ");
+    "mmh3_x64_128_sintdigest(key[, seed=0]) -> int\n"
+    "\n"
+    "Return a hash for the buffer as a 128-bit signed integer.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x64_128 algorithm. "
+    "\n"
+    "Args:\n"
+    "    key (Buffer | str): The input buffer to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "\n"
+    "Returns:\n"
+    "    int: The hash value as a 128-bit signed integer.\n"
+    "\n"
+    ".. versionadded:: 4.2.0\n");
 
 static PyObject *
 mmh3_mmh3_x64_128_sintdigest(PyObject *self, PyObject *args, PyObject *keywds)
@@ -438,9 +560,21 @@ mmh3_mmh3_x64_128_sintdigest(PyObject *self, PyObject *args, PyObject *keywds)
 
 PyDoc_STRVAR(
     mmh3_mmh3_x64_128_uintdigest_doc,
-    "mmh3_x64_128_uintdigest(key[, seed=0]) -> int\n\n"
-    "Return a hash value from a memory buffer as an unsigned 128-bit integer. "
-    "Calculated by the MurmurHash3_x64_128 algorithm. ");
+    "mmh3_x64_128_uintdigest(key[, seed=0]) -> int\n"
+    "\n"
+    "Return a hash for the buffer as a 128-bit unsigned integer.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x64_128 algorithm. "
+    "\n"
+    "Args:\n"
+    "    key (Buffer | str): The input buffer to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "\n"
+    "Returns:\n"
+    "    int: The hash value as a 128-bit unsigned integer.\n"
+    "\n"
+    ".. versionadded:: 4.2.0\n");
 
 static PyObject *
 mmh3_mmh3_x64_128_uintdigest(PyObject *self, PyObject *args, PyObject *keywds)
@@ -476,11 +610,24 @@ mmh3_mmh3_x64_128_uintdigest(PyObject *self, PyObject *args, PyObject *keywds)
     return retval;
 }
 
-PyDoc_STRVAR(mmh3_mmh3_x64_128_stupledigest_doc,
-             "mmh3_x64_128_stupledigest(key[, seed=0]) -> tuple[int, int]\n\n"
-             "Return a hash value from a memory buffer as a tuple of two "
-             "64-bit signed integers. "
-             "Calculated by the MurmurHash3_x64_128 algorithm. ");
+PyDoc_STRVAR(
+    mmh3_mmh3_x64_128_stupledigest_doc,
+    "mmh3_x64_128_stupledigest(key[, seed=0]) -> tuple[int, int]\n"
+    "\n"
+    "Return a hash for the buffer as a tuple of two 64-bit signed integers.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x64_128 algorithm.\n"
+    "\n"
+    "Args:\n"
+    "    key (Buffer | str): The input buffer to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "\n"
+    "Returns:\n"
+    "    tuple[int, int]: The hash value as a tuple of two 64-bit signed "
+    "integers.\n"
+    "\n"
+    ".. versionadded:: 4.2.0\n");
 
 static PyObject *
 mmh3_mmh3_x64_128_stupledigest(PyObject *self, PyObject *args,
@@ -504,11 +651,25 @@ mmh3_mmh3_x64_128_stupledigest(PyObject *self, PyObject *args,
     return retval;
 }
 
-PyDoc_STRVAR(mmh3_mmh3_x64_128_utupledigest_doc,
-             "mmh3_x64_128_utupledigest(key[, seed=0]) -> tuple[int, int]\n\n"
-             "Return a hash value from a memory buffer as a tuple of two "
-             "64-bit unsigned integers. "
-             "Calculated by the MurmurHash3_x64_128 algorithm. ");
+PyDoc_STRVAR(
+    mmh3_mmh3_x64_128_utupledigest_doc,
+    "mmh3_x64_128_utupledigest(key[, seed=0]) -> tuple[int, int]\n"
+    "\n"
+    "Return a hash for the buffer as a tuple of two 64-bit unsigned "
+    "integers.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x64_128 algorithm.\n"
+    "\n"
+    "Args:\n"
+    "    key (Buffer | str): The input buffer to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "\n"
+    "Returns:\n"
+    "    tuple[int, int]: The hash value as a tuple of two 64-bit unsigned "
+    "integers.\n"
+    "\n"
+    ".. versionadded:: 4.2.0\n");
 
 static PyObject *
 mmh3_mmh3_x64_128_utupledigest(PyObject *self, PyObject *args,
@@ -532,11 +693,24 @@ mmh3_mmh3_x64_128_utupledigest(PyObject *self, PyObject *args,
     return retval;
 }
 
-PyDoc_STRVAR(mmh3_mmh3_x86_128_digest_doc,
-             "mmh3_x86_128_digest(key[, seed=0]) -> bytes\n\n"
-             "Return a hash value from a memory buffer as bytes. "
-             "Calculated by the MurmurHash3_x86_128 algorithm. "
-             "Designed for large memory-views such as numpy arrays.");
+PyDoc_STRVAR(
+    mmh3_mmh3_x86_128_digest_doc,
+    "mmh3_x86_128_digest(key[, seed=0]) -> bytes\n"
+    "\n"
+    "Return a 16-byte hash of the ``bytes`` type for the buffer.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x86_128 algorithm.\n"
+    "\n"
+    "Args:\n"
+    "    key (Buffer | str): The input buffer to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "\n"
+    "Returns:\n"
+    "    bytes: The hash value as the ``bytes`` type with a length of 16 "
+    "bytes (128 bits).\n"
+    "\n"
+    ".. versionadded:: 4.2.0\n");
 
 static PyObject *
 mmh3_mmh3_x86_128_digest(PyObject *self, PyObject *args, PyObject *keywds)
@@ -565,9 +739,21 @@ mmh3_mmh3_x86_128_digest(PyObject *self, PyObject *args, PyObject *keywds)
 
 PyDoc_STRVAR(
     mmh3_mmh3_x86_128_sintdigest_doc,
-    "mmh3_x86_128_sintdigest(key[, seed=0]) -> int\n\n"
-    "Return a hash value from a memory buffer as a signed 128-bit integer. "
-    "Calculated by the MurmurHash3_x86_128 algorithm. ");
+    "mmh3_x86_128_sintdigest(key[, seed=0]) -> int\n"
+    "\n"
+    "Return a hash for the buffer as a 128-bit signed integer.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x86_128 algorithm.\n"
+    "\n"
+    "Args:\n"
+    "    key (Buffer | str): The input buffer to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "\n"
+    "Returns:\n"
+    "    int: The hash value as an signed 128-bit integer.\n"
+    "\n"
+    ".. versionadded:: 4.2.0\n");
 
 static PyObject *
 mmh3_mmh3_x86_128_sintdigest(PyObject *self, PyObject *args, PyObject *keywds)
@@ -605,9 +791,21 @@ mmh3_mmh3_x86_128_sintdigest(PyObject *self, PyObject *args, PyObject *keywds)
 
 PyDoc_STRVAR(
     mmh3_mmh3_x86_128_uintdigest_doc,
-    "mmh3_x86_128_uintdigest(key[, seed=0]) -> int\n\n"
-    "Return a hash value from a memory buffer as an unsigned 128-bit integer. "
-    "Calculated by the MurmurHash3_x86_128 algorithm. ");
+    "mmh3_x86_128_uintdigest(key[, seed=0]) -> int\n"
+    "\n"
+    "Return a hash for the buffer as a 128-bit unsigned integer.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x86_128 algorithm.\n"
+    "\n"
+    "Args:\n"
+    "    key (Buffer | str): The input buffer to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "\n"
+    "Returns:\n"
+    "    int: The hash value as a 128-bit unsigned integer.\n"
+    "\n"
+    ".. versionadded:: 4.2.0\n");
 
 static PyObject *
 mmh3_mmh3_x86_128_uintdigest(PyObject *self, PyObject *args, PyObject *keywds)
@@ -643,11 +841,24 @@ mmh3_mmh3_x86_128_uintdigest(PyObject *self, PyObject *args, PyObject *keywds)
     return retval;
 }
 
-PyDoc_STRVAR(mmh3_mmh3_x86_128_stupledigest_doc,
-             "mmh3_x86_128_stupledigest(key[, seed=0]) -> tuple[int, int]\n\n"
-             "Return a hash value from a memory buffer as a tuple of two "
-             "64-bit signed integers. "
-             "Calculated by the MurmurHash3_x86_128 algorithm. ");
+PyDoc_STRVAR(
+    mmh3_mmh3_x86_128_stupledigest_doc,
+    "mmh3_x86_128_stupledigest(key[, seed=0]) -> tuple[int, int]\n"
+    "\n"
+    "Return a hash for the buffer as a tuple of two 64-bit signed integers.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x86_128 algorithm.\n"
+    "\n"
+    "Args:\n"
+    "    key (Buffer | str): The input buffer to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "\n"
+    "Returns:\n"
+    "    tuple[int, int]: The hash value as a tuple of two 64-bit signed "
+    "integers.\n"
+    "\n"
+    ".. versionadded:: 4.2.0\n");
 
 static PyObject *
 mmh3_mmh3_x86_128_stupledigest(PyObject *self, PyObject *args,
@@ -671,11 +882,25 @@ mmh3_mmh3_x86_128_stupledigest(PyObject *self, PyObject *args,
     return retval;
 }
 
-PyDoc_STRVAR(mmh3_mmh3_x86_128_utupledigest_doc,
-             "mmh3_x86_128_utupledigest(key[, seed=0]) -> tuple[int, int]\n\n"
-             "Return a hash value from a memory buffer as a tuple of two "
-             "64-bit unsigned integers. "
-             "Calculated by the MurmurHash3_x86_128 algorithm. ");
+PyDoc_STRVAR(
+    mmh3_mmh3_x86_128_utupledigest_doc,
+    "mmh3_x86_128_utupledigest(key[, seed=0]) -> tuple[int, int]\n"
+    "\n"
+    "Return a hash for the buffer as a tuple of two 64-bit unsigned "
+    "integers.\n"
+    "\n"
+    "Calculated by the MurmurHash3_x86_128 algorithm.\n"
+    "\n"
+    "Args:\n"
+    "    key (Buffer | str): The input buffer to hash.\n"
+    "    seed (int): The seed value. Must be an integer in the range [0, "
+    "0xFFFFFFFF].\n"
+    "\n"
+    "Returns:\n"
+    "    tuple[int, int]: The hash value as a tuple of two 64-bit unsigned "
+    "integers.\n"
+    "\n"
+    ".. versionadded:: 4.2.0\n");
 
 static PyObject *
 mmh3_mmh3_x86_128_utupledigest(PyObject *self, PyObject *args,
@@ -775,6 +1000,9 @@ MMH3Hasher32_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     return (PyObject *)self;
 }
 
+/* It is impossible to add docstring for __init__ in Python C extension.
+  Therefore, the contsructor docstring should be described in the class
+  docstring. See also https://stackoverflow.com/q/11913492 */
 static int
 MMH3Hasher32_init(MMH3Hasher32 *self, PyObject *args, PyObject *kwds)
 {
@@ -786,6 +1014,13 @@ MMH3Hasher32_init(MMH3Hasher32 *self, PyObject *args, PyObject *kwds)
     return 0;
 }
 
+PyDoc_STRVAR(MMH3Hasher_update_doc,
+             "update(data)\n\n"
+             "Update this hash object's state with the provided bytes-like "
+             "object.\n\n"
+             "Args:\n"
+             "    data (Buffer): The buffer to hash.\n\n");
+
 static PyObject *
 MMH3Hasher32_update(MMH3Hasher32 *self, PyObject *obj)
 {
@@ -838,6 +1073,14 @@ digest32_impl(uint32_t h, uint64_t k1, Py_ssize_t length)
     return h;
 }
 
+PyDoc_STRVAR(MMH3Hasher_digest_doc,
+             "digest() -> bytes\n"
+             "\n"
+             "Return the digest value as a ``bytes`` object.\n"
+             "\n"
+             "Returns:\n"
+             "    bytes: The digest value.\n");
+
 static PyObject *
 MMH3Hasher32_digest(MMH3Hasher32 *self, PyObject *Py_UNUSED(ignored))
 {
@@ -853,6 +1096,14 @@ MMH3Hasher32_digest(MMH3Hasher32 *self, PyObject *Py_UNUSED(ignored))
     return PyBytes_FromStringAndSize(out, MMH3_32_DIGESTSIZE);
 }
 
+PyDoc_STRVAR(MMH3Hasher_sintdigest_doc,
+             "sintdigest() -> int\n"
+             "\n"
+             "Return the digest value as a signed integer.\n"
+             "\n"
+             "Returns:\n"
+             "    int: The digest value as a signed integer.\n");
+
 static PyObject *
 MMH3Hasher32_sintdigest(MMH3Hasher32 *self, PyObject *Py_UNUSED(ignored))
 {
@@ -864,6 +1115,14 @@ MMH3Hasher32_sintdigest(MMH3Hasher32 *self, PyObject *Py_UNUSED(ignored))
     return PyLong_FromLong(result);
 }
 
+PyDoc_STRVAR(MMH3Hasher_uintdigest_doc,
+             "uintdigest() -> int\n"
+             "\n"
+             "Return the digest value as an unsigned integer.\n"
+             "\n"
+             "Returns:\n"
+             "    int: The digest value as an unsigned integer.\n");
+
 static PyObject *
 MMH3Hasher32_uintdigest(MMH3Hasher32 *self, PyObject *Py_UNUSED(ignored))
 {
@@ -871,6 +1130,14 @@ MMH3Hasher32_uintdigest(MMH3Hasher32 *self, PyObject *Py_UNUSED(ignored))
     return PyLong_FromUnsignedLong(h);
 }
 
+PyDoc_STRVAR(MMH3Hasher32_copy_doc,
+             "copy() -> mmh3_32\n"
+             "\n"
+             "Return a copy of the hash object..\n"
+             "\n"
+             "Returns:\n"
+             "    mmh3_32: A copy of this hash object.\n");
+
 static PyObject *
 MMH3Hasher32_copy(MMH3Hasher32 *self, PyObject *Py_UNUSED(ignored))
 {
@@ -890,15 +1157,19 @@ MMH3Hasher32_copy(MMH3Hasher32 *self, PyObject *Py_UNUSED(ignored))
 
 static PyMethodDef MMH3Hasher32_methods[] = {
     {"update", (PyCFunction)MMH3Hasher32_update, METH_O,
-     "Update this hash object's state with the provided string."},
-    {"digest", (PyCFunction)MMH3Hasher32_digest, METH_NOARGS,
-     "Return the digest value as a bytes object."},
+     MMH3Hasher_update_doc},
+    {
+        "digest",
+        (PyCFunction)MMH3Hasher32_digest,
+        METH_NOARGS,
+        MMH3Hasher_digest_doc,
+    },
     {"sintdigest", (PyCFunction)MMH3Hasher32_sintdigest, METH_NOARGS,
-     "Return the digest value as a 32-bit signed integer."},
+     MMH3Hasher_sintdigest_doc},
     {"uintdigest", (PyCFunction)MMH3Hasher32_uintdigest, METH_NOARGS,
-     "Return the digest value as a 32-bit unsigned integer."},
+     MMH3Hasher_uintdigest_doc},
     {"copy", (PyCFunction)MMH3Hasher32_copy, METH_NOARGS,
-     "Return a copy of the hash object."},
+     MMH3Hasher32_copy_doc},
     {NULL} /* Sentinel */
 };
 
@@ -922,18 +1193,23 @@ MMH3Hasher32_get_name(PyObject *self, void *closure)
 
 static PyGetSetDef MMH3Hasher32_getsetters[] = {
     {"digest_size", (getter)MMH3Hasher32_get_digest_size, NULL,
-     "number of bytes in this hashes output", NULL},
+     "int: Number of bytes in this hashes output", NULL},
     {"block_size", (getter)MMH3Hasher32_get_block_size, NULL,
-     "number of bytes of the internal block of this algorithm", NULL},
+     "int: Number of bytes of the internal block of this algorithm", NULL},
     {"name", (getter)MMH3Hasher32_get_name, NULL,
-     "the hash algorithm being used by this object", NULL},
+     "str: The hash algorithm being used by this object", NULL},
     {NULL} /* Sentinel */
 };
 
-PyDoc_STRVAR(MMH3Hasher32Type_doc,
-             "An mmh3_32 is an object used to calculate the "
-             "murmurhash3_x86_32 hash\n"
-             "of a string of information.");
+PyDoc_STRVAR(
+    MMH3Hasher32Type_doc,
+    "__init__(seed=0)\n"
+    "\n"
+    "Hasher for incrementally calculating the murmurhash3_x86_32 hash.\n"
+    "\n"
+    "Args:\n"
+    "    seed (int): The seed value. Must be an integer in the range "
+    "[0, 0xFFFFFFFF].\n");
 
 static PyTypeObject MMH3Hasher32Type = {
     PyVarObject_HEAD_INIT(NULL, 0).tp_name = "mmh3.mmh3_32",
@@ -1136,6 +1412,15 @@ MMH3Hasher128x64_uintdigest(MMH3Hasher128x64 *self,
     return retval;
 }
 
+PyDoc_STRVAR(MMH3Hasher128_stupledigest_doc,
+             "stupledigest() -> tuple[int, int]\n"
+             "\n"
+             "Return the digest value as a tuple of two signed integers.\n"
+             "\n"
+             "Returns:\n"
+             "    tuple[int, int]: The digest value as a tuple of two signed "
+             "integers.\n");
+
 static PyObject *
 MMH3Hasher128x64_stupledigest(MMH3Hasher128x64 *self,
                               PyObject *Py_UNUSED(ignored))
@@ -1156,6 +1441,15 @@ MMH3Hasher128x64_stupledigest(MMH3Hasher128x64 *self,
     return Py_BuildValue(valflag, result1, result2);
 }
 
+PyDoc_STRVAR(MMH3Hasher128_utupledigest_doc,
+             "utupledigest() -> tuple[int, int]\n"
+             "\n"
+             "Return the digest value as a tuple of two unsigned integers.\n"
+             "\n"
+             "Returns:\n"
+             "    tuple[int, int]: The digest value as a tuple of two "
+             "unsigned integers.\n");
+
 static PyObject *
 MMH3Hasher128x64_utupledigest(MMH3Hasher128x64 *self,
                               PyObject *Py_UNUSED(ignored))
@@ -1176,6 +1470,14 @@ MMH3Hasher128x64_utupledigest(MMH3Hasher128x64 *self,
     return Py_BuildValue(valflag, result1, result2);
 }
 
+PyDoc_STRVAR(MMH3Hasher128x64_copy_doc,
+             "copy() -> mmh3_128x64\n"
+             "\n"
+             "Return a copy of the hash object..\n"
+             "\n"
+             "Returns:\n"
+             "    mmh3_128x64: A copy of this hash object.\n");
+
 static PyObject *
 MMH3Hasher128x64_copy(MMH3Hasher128x64 *self, PyObject *Py_UNUSED(ignored))
 {
@@ -1197,20 +1499,19 @@ MMH3Hasher128x64_copy(MMH3Hasher128x64 *self, PyObject *Py_UNUSED(ignored))
 
 static PyMethodDef MMH3Hasher128x64_methods[] = {
     {"update", (PyCFunction)MMH3Hasher128x64_update, METH_O,
-     "Update this hash object's state with the provided string."},
+     MMH3Hasher_update_doc},
     {"digest", (PyCFunction)MMH3Hasher128x64_digest, METH_NOARGS,
-     "Return the digest value as a bytes object."},
+     MMH3Hasher_digest_doc},
     {"sintdigest", (PyCFunction)MMH3Hasher128x64_sintdigest, METH_NOARGS,
-     "Return the digest value as a 128 bit signed integer."},
+     MMH3Hasher_sintdigest_doc},
     {"uintdigest", (PyCFunction)MMH3Hasher128x64_uintdigest, METH_NOARGS,
-     "Return the digest value as a 128 bit unsigned integer."},
+     MMH3Hasher_uintdigest_doc},
     {"stupledigest", (PyCFunction)MMH3Hasher128x64_stupledigest, METH_NOARGS,
-     "Return the digest value as a tuple of two 64 bit signed integers."},
+     MMH3Hasher128_stupledigest_doc},
     {"utupledigest", (PyCFunction)MMH3Hasher128x64_utupledigest, METH_NOARGS,
-     "Return the digest value as a tuple of two 64 bit unsigned "
-     "integers."},
+     MMH3Hasher128_utupledigest_doc},
     {"copy", (PyCFunction)MMH3Hasher128x64_copy, METH_NOARGS,
-     "Return a copy of the hash object."},
+     MMH3Hasher128x64_copy_doc},
     {NULL} /* Sentinel */
 };
 
@@ -1234,18 +1535,23 @@ MMH3Hasher128x64_get_name(PyObject *self, void *closure)
 
 static PyGetSetDef MMH3Hasher128x64_getsetters[] = {
     {"digest_size", (getter)MMH3Hasher128x64_get_digest_size, NULL,
-     "number of bytes in this hashes output", NULL},
+     "int: Number of bytes in this hashes output.", NULL},
     {"block_size", (getter)MMH3Hasher128x64_get_block_size, NULL,
-     "number of bytes of the internal block of this algorithm", NULL},
+     "int: Number of bytes of the internal block of this algorithm.", NULL},
     {"name", (getter)MMH3Hasher128x64_get_name, NULL,
-     "the hash algorithm being used by this object", NULL},
+     "str: The hash algorithm being used by this object.", NULL},
     {NULL} /* Sentinel */
 };
 
-PyDoc_STRVAR(MMH3Hasher128x64Type_doc,
-             "An mmh3_x64_128 is an object used to calculate the "
-             "murmurhash3_x64_128\n"
-             "hash of a string of information.");
+PyDoc_STRVAR(
+    MMH3Hasher128x64Type_doc,
+    "__init__(seed=0)\n"
+    "\n"
+    "Hasher for incrementally calculating the murmurhash3_x64_128 hash.\n"
+    "\n"
+    "Args:\n"
+    "    seed (int): The seed value. Must be an integer in the range "
+    "[0, 0xFFFFFFFF].\n");
 
 static PyTypeObject MMH3Hasher128x64Type = {
     PyVarObject_HEAD_INIT(NULL, 0).tp_name = "mmh3.mmh3_x64_128",
@@ -1482,6 +1788,14 @@ MMH3Hasher128x86_utupledigest(MMH3Hasher128x86 *self,
     return Py_BuildValue(valflag, result1, result2);
 }
 
+PyDoc_STRVAR(MMH3Hasher128x86_copy_doc,
+             "copy() -> mmh3_128x86\n"
+             "\n"
+             "Return a copy of the hash object..\n"
+             "\n"
+             "Returns:\n"
+             "    mmh3_128x86: A copy of this hash object.\n");
+
 static PyObject *
 MMH3Hasher128x86_copy(MMH3Hasher128x86 *self, PyObject *Py_UNUSED(ignored))
 {
@@ -1507,20 +1821,19 @@ MMH3Hasher128x86_copy(MMH3Hasher128x86 *self, PyObject *Py_UNUSED(ignored))
 
 static PyMethodDef MMH3Hasher128x86_methods[] = {
     {"update", (PyCFunction)MMH3Hasher128x86_update, METH_O,
-     "Update this hash object's state with the provided string."},
+     MMH3Hasher_update_doc},
     {"digest", (PyCFunction)MMH3Hasher128x86_digest, METH_NOARGS,
-     "Return the digest value as a bytes object."},
+     MMH3Hasher_digest_doc},
     {"sintdigest", (PyCFunction)MMH3Hasher128x86_sintdigest, METH_NOARGS,
-     "Return the digest value as a 128-bit signed integer."},
+     MMH3Hasher_sintdigest_doc},
     {"uintdigest", (PyCFunction)MMH3Hasher128x86_uintdigest, METH_NOARGS,
-     "Return the digest value as a 128-bit unsigned integer."},
+     MMH3Hasher_uintdigest_doc},
     {"stupledigest", (PyCFunction)MMH3Hasher128x86_stupledigest, METH_NOARGS,
-     "Return the digest value as a tuple of two 64-bit signed integers."},
+     MMH3Hasher128_stupledigest_doc},
     {"utupledigest", (PyCFunction)MMH3Hasher128x86_utupledigest, METH_NOARGS,
-     "Return the digest value as a tuple of two 64-bit unsigned "
-     "integers."},
+     MMH3Hasher128_utupledigest_doc},
     {"copy", (PyCFunction)MMH3Hasher128x86_copy, METH_NOARGS,
-     "Return a copy of the hash object."},
+     MMH3Hasher128x86_copy_doc},
     {NULL} /* Sentinel */
 };
 
@@ -1544,18 +1857,23 @@ MMH3Hasher128x86_get_name(PyObject *self, void *closure)
 
 static PyGetSetDef MMH3Hasher128x86_getsetters[] = {
     {"digest_size", (getter)MMH3Hasher128x86_get_digest_size, NULL,
-     "number of bytes in this hashes output", NULL},
+     "int: Number of bytes in this hashes output", NULL},
     {"block_size", (getter)MMH3Hasher128x86_get_block_size, NULL,
-     "number of bytes of the internal block of this algorithm", NULL},
+     "int: Number of bytes of the internal block of this algorithm", NULL},
     {"name", (getter)MMH3Hasher128x86_get_name, NULL,
-     "the hash algorithm being used by this object", NULL},
+     "str: Te hash algorithm being used by this object", NULL},
     {NULL} /* Sentinel */
 };
 
-PyDoc_STRVAR(MMH3Hasher128x86Type_doc,
-             "An mmh3_x86_128 is an object used to calculate the "
-             "murmurhash3_x86_128\n"
-             "hash of a string of information.");
+PyDoc_STRVAR(
+    MMH3Hasher128x86Type_doc,
+    "__init__(seed=0)\n"
+    "\n"
+    "Hasher for incrementally calculating the murmurhash3_x86_128 hash.\n"
+    "\n"
+    "Args:\n"
+    "    seed (int): The seed value. Must be an integer in the range "
+    "[0, 0xFFFFFFFF].\n");
 
 static PyTypeObject MMH3Hasher128x86Type = {
     PyVarObject_HEAD_INIT(NULL, 0).tp_name = "mmh3.mmh3_x86_128",


Test patch:
diff --git a/tests/test_doctrings.py b/tests/test_doctrings.py
index 6012d52..b50959a 100644
--- a/tests/test_doctrings.py
+++ b/tests/test_doctrings.py
@@ -5,26 +5,24 @@
 def test_function_docstrings() -> None:
     assert "__doc__" in dir(mmh3.hash)
     assert mmh3.hash.__doc__ is not None
-    assert mmh3.hash.__doc__.startswith(
-        "hash(key[, seed=0, signed=True]) -> 32-bit int\n\n"
-    )
+    assert mmh3.hash.__doc__.startswith("hash(key[, seed=0, signed=True]) -> int\n\n")
 
     assert "__doc__" in dir(mmh3.hash_from_buffer)
     assert mmh3.hash_from_buffer.__doc__ is not None
     assert mmh3.hash_from_buffer.__doc__.startswith(
-        "hash_from_buffer(key[, seed=0, signed=True]) -> 32-bit int\n\n"
+        "hash_from_buffer(key[, seed=0, signed=True]) -> int\n\n"
     )
 
     assert "__doc__" in dir(mmh3.hash64)
     assert mmh3.hash64.__doc__ is not None
     assert mmh3.hash64.__doc__.startswith(
-        "hash64(key[, seed=0, x64arch=True, signed=True]) -> (64-bit int, 64-bit int)\n\n"
+        "hash64(key[, seed=0, x64arch=True, signed=True]) -> tuple[int, int]\n\n"
     )
 
     assert "__doc__" in dir(mmh3.hash128)
     assert mmh3.hash128.__doc__ is not None
     assert mmh3.hash128.__doc__.startswith(
-        "hash128(key[, seed=0, x64arch=True, signed=False]]) -> 128-bit int\n\n"
+        "hash128(key[, seed=0, x64arch=True, signed=False]]) -> int\n\n"
     )
 
     assert "__doc__" in dir(mmh3.hash_bytes)