From: Daniele Varrazzo Date: Sat, 28 Aug 2021 16:36:04 +0000 (+0200) Subject: Add XML Dumper example X-Git-Tag: 3.0.beta1~14 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8a106413ffb0043070142db4c5b44fc9b8e9f8b0;p=thirdparty%2Fpsycopg.git Add XML Dumper example --- diff --git a/docs/advanced/adapt.rst b/docs/advanced/adapt.rst index 8ffdbd1b7..16d42ff82 100644 --- a/docs/advanced/adapt.rst +++ b/docs/advanced/adapt.rst @@ -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:: ... Manual...') ... """) - >>> cur.fetchone()[0] + >>> elem = cur.fetchone()[0] + >>> elem -.. __: 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 ------------------------------- diff --git a/docs/api/abc.rst b/docs/api/abc.rst index 0740e9c76..7d311f943 100644 --- a/docs/api/abc.rst +++ b/docs/api/abc.rst @@ -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 diff --git a/psycopg/psycopg/abc.py b/psycopg/psycopg/abc.py index 137acd4bd..1ba3448a6 100644 --- a/psycopg/psycopg/abc.py +++ b/psycopg/psycopg/abc.py @@ -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. + """ ...