]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Add XML Dumper example
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sat, 28 Aug 2021 16:36:04 +0000 (18:36 +0200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sat, 28 Aug 2021 16:36:04 +0000 (18:36 +0200)
docs/advanced/adapt.rst
docs/api/abc.rst
psycopg/psycopg/abc.py

index 8ffdbd1b7d5c225b10fb109231cf8628d62cde32..16d42ff82ca08e6c844b6f50a971a85f6ab4230d 100644 (file)
@@ -53,17 +53,20 @@ returned.
     when a query is executed.
 
 
-Writing a custom loader: XML
-----------------------------
+.. _adapt-example-xml:
 
-Psycopg doesn't provide a loader for the XML data type because there are just
-too many ways of handling it in Python. Creating a loader to parse the
+Writing a custom adapter: XML
+-----------------------------
+
+Psycopg doesn't provide adapters for the XML data type, because there are just
+too many ways of handling XML in Python.Creating a loader to parse the
 `PostgreSQL xml type`__ to `~xml.etree.ElementTree` is very simple, using the
-`psycopg.adapt.Loader` base class.
+`psycopg.adapt.Loader` base class and implementing the
+`~psycopg.abc.Loader.load()` method:
 
-Note that it is possible to use a `~psycopg.types.TypesRegistry`, exposed by
-any `~psycopg.abc.AdaptContext`, to obtain information on builtin types, or
-extension types if they have been registered::
+.. __: https://www.postgresql.org/docs/current/datatype-xml.html
+
+.. code:: python
 
     >>> import xml.etree.ElementTree as ET
     >>> from psycopg.adapt import Loader
@@ -83,11 +86,37 @@ extension types if they have been registered::
     ...            <book><title>Manual</title><chapter>...</chapter></book>')
     ...     """)
 
-    >>> cur.fetchone()[0]
+    >>> elem = cur.fetchone()[0]
+    >>> elem
     <Element 'book' at 0x7ffb55142ef0>
 
-.. __: https://www.postgresql.org/docs/current/datatype-xml.html
+The opposite operation, converting Python objects to PostgreSQL, is performed
+by dumpers. The `psycopg.adapt.Dumper` base class makes easy to implement one:
+you only need to implement the `~psycopg.abc.Dumper.dump()` method::
+
+    >>> from psycopg.adapt import Dumper
 
+    >>> class XmlDumper(Dumper):
+    ...     # Setting an OID is not necessary but can be helpful
+    ...     oid = psycopg.adapters.types["xml"].oid
+    ...
+    ...     def dump(self, elem):
+    ...         return ET.tostring(elem)
+
+    >>> # Register the dumper on the adapters of a context
+    >>> conn.adapters.register_dumper(ET.Element, XmlDumper)
+
+    >>> # Now, in that context, it is possible to use ET.Element objects as parameters
+    >>> conn.execute("SELECT xpath('//title/text()', %s)", [elem]).fetchone()[0]
+    ['Manual']
+
+Note that it is possible to use a `~psycopg.types.TypesRegistry`, exposed by
+any `~psycopg.abc.AdaptContext`, to obtain information on builtin types, or
+extension types if they have been registered on that context using the
+`~psycopg.types.TypeInfo`\.\ `~psycopg.types.TypeInfo.register()` method.
+
+
+.. _adapt-example-float:
 
 Example: PostgreSQL numeric to Python float
 -------------------------------------------
@@ -124,6 +153,8 @@ In this example the customised adaptation takes effect only on the connection
 `!conn` and on any cursor created from it, not on other connections.
 
 
+.. _adapt-example-inf-date:
+
 Example: handling infinity date
 -------------------------------
 
index 0740e9c76f8de4245c143e1820f4620c99225b52..7d311f943e0c99c9753acdba4c4cf1beec0132cf 100644 (file)
@@ -42,13 +42,13 @@ checking.
 
     .. autoattribute:: oid
 
-        If the oid is not specified, PostgreSQL will try to infer the type
+        If the OID is not specified, PostgreSQL will try to infer the type
         from the context, but this may fail in some contexts and may require a
         cast (e.g. specifying :samp:`%s::{type}` for its placeholder).
 
-        .. admonition:: todo
-
-            Document how to find type OIDs in a database.
+        You can use the `psycopg.adapters`\ ``.``\ `~psycopg.adapt.AdaptersMap.types`
+        registry to find the OID of builtin types, and you can use
+        `~psycopg.types.TypeInfo` to extend the registry to custom types.
 
     .. automethod:: get_key
     .. automethod:: upgrade
index 137acd4bde229745f887c237143c1f475b0bcc88..1ba3448a6d3c9ba3b3e43dcc7b9c8bf95bf9a6ea 100644 (file)
@@ -96,11 +96,17 @@ class Dumper(Protocol):
         ...
 
     def dump(self, obj: Any) -> Buffer:
-        """Convert the object *obj* to PostgreSQL representation."""
+        """Convert the object *obj* to PostgreSQL representation.
+
+        :param obj: the object to convert.
+        """
         ...
 
     def quote(self, obj: Any) -> Buffer:
-        """Convert the object *obj* to escaped representation."""
+        """Convert the object *obj* to escaped representation.
+
+        :param obj: the object to convert.
+        """
         ...
 
     def get_key(self, obj: Any, format: PyFormat) -> DumperKey:
@@ -165,6 +171,11 @@ class Loader(Protocol):
         ...
 
     def load(self, data: Buffer) -> Any:
+        """
+        Convert the data returned by the database into a Python object.
+
+        :param data: the data to convert.
+        """
         ...