From: Daniele Varrazzo Date: Mon, 8 Feb 2021 01:42:31 +0000 (+0100) Subject: Add some docs on TypeInfo and adaptation docs corrections X-Git-Tag: 3.0.dev0~121 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=753dfa7dfcfd1388ef1322027214ed0a8a43a5a2;p=thirdparty%2Fpsycopg.git Add some docs on TypeInfo and adaptation docs corrections --- diff --git a/docs/adaptation.rst b/docs/adaptation.rst index 4b951e804..f5fae47c7 100644 --- a/docs/adaptation.rst +++ b/docs/adaptation.rst @@ -16,21 +16,26 @@ returned. described in this page is useful if you intend to *customise* the adaptation rules. -The `Dumper` is the base object to perform conversion from a Python object to -a `!bytes` string understood by PostgreSQL. The string returned *shouldn't be -quoted*: the value will be passed to the database using functions such as -:pq:`PQexecParams()` so quoting and quotes escaping is not necessary. +- The `~psycopg3.types.TypeInfo` object allows to query type information from + a database, which can be used by the adapters: for instance to make them + able to decode arrays of base types or composite types. -The `Loader` is the base object to perform the opposite operation: to read a -`!bytes` string from PostgreSQL and create a Python object. +- The `Dumper` is the base object to perform conversion from a Python object + to a `!bytes` string understood by PostgreSQL. The string returned + *shouldn't be quoted*: the value will be passed to the database using + functions such as :pq:`PQexecParams()` so quoting and quotes escaping is not + necessary. + +- The `Loader` is the base object to perform the opposite operation: to read a + `!bytes` string from PostgreSQL and create a Python object. `!Dumper` and `!Loader` are abstract classes: concrete classes must implement the `~Dumper.dump()` and `~Loader.load()` methods. `!psycopg3` provides implementation for several builtin Python and PostgreSQL types. -.. admonition:: TODO - - Document the builtin adapters, where are they? +Psycopg provides adapters for several builtin types, which can be used as the +base to build more complex ones: they all live in the `psycopg3.types` +package. Dumpers and loaders configuration @@ -74,8 +79,11 @@ right instance. `!Connection`, the `!Cursor`. - For every Python type passed as query argument, the `!Transformer` will - instantiate a `!Dumper`. All the objects of the same type will be converted - by the same dumper. + instantiate a `!Dumper`. Usually all the objects of the same type will be + converted by the same dumper; certain dumpers may be used in more than one + instance, because the same Python type maps to more than one PostgreSQL type + (for instance, a Python `int` might be better dumped as a PostgreSQL + :sql:`integer`, :sql:`bigint`, :sql:`smallint` according to its value). - For every OID returned by the query, the `!Transformer` will instantiate a `!Loader`. All the values with the same OID will be converted by the same diff --git a/docs/api/index.rst b/docs/api/index.rst index eeae9cc45..275906cf7 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -9,4 +9,5 @@ ../cursor ../sql ../errors + ../types ../pq diff --git a/docs/pq.rst b/docs/pq.rst index 1f8788059..cfc95e9cb 100644 --- a/docs/pq.rst +++ b/docs/pq.rst @@ -1,6 +1,6 @@ .. _psycopg3.pq: -`pq` -- Libpq wrapper module +`pq` -- libpq wrapper module ============================ .. index:: diff --git a/docs/types.rst b/docs/types.rst new file mode 100644 index 000000000..3f144bbb8 --- /dev/null +++ b/docs/types.rst @@ -0,0 +1,107 @@ +.. currentmodule:: psycopg3.types + +.. _psycopg3.types: + +`!types` -- types mapping and adaptation +======================================== + +.. module:: psycopg3.types + +The `!psycopg3.types` package exposes the concrete implementation of `Loader` +and `Dumper` to manage builtin objects, together with objects to describe +PostgreSQL types and wrappers to help or customise the types conversion. + + +Types information +----------------- + +The `TypeInfo` object describes simple information about a PostgreSQL data +type, such as its name, oid and array oid. The class can be used to query a +database for custom data types: this allows for instance to load automatically +arrays of a custom type, once a loader for the base type has been registered. + +The `!TypeInfo` object doesn't instruct `!psycopg3` to convert a PostgreSQL +type into a Python type: this is the role of a `Loader`. However it can extend +the behaviour of the adapters: if you create a loader for `!MyType`, using +`TypeInfo` you will be able to manage seamlessly arrays of `!MyType` or ranges +and composite types using it as a subtypes. + +.. seealso:: :ref:`adaptation` describes about how to convert from Python + types to PostgreSQL types and back. + +.. code:: python + + from psycopg3.adapt import Loader + from psycopg3.types import TypeInfo + + t = TypeInfo.fetch(conn, "mytype") + t.register(conn) + + for record in conn.execute("select mytypearray from mytable"): + # records will return lists of "mytype" as string + + class MyTypeLoader(Loader): + def load(self, data): + # parse the data and return a MyType instance + + MyTypeLoader.register(conn) + + for record in conn.execute("select mytypearray from mytable"): + # records will return lists of MyType instances + + +.. autoclass:: TypeInfo + + .. automethod:: fetch + .. automethod:: fetch_async + .. automethod:: register + + The *context* can be a `~psycopg3.Connection` or `~psycopg3.Cursor`. + Specifying no context will register the `!TypeInfo` globally. + + Registering the `TypeInfo` in a context allows the adapters of that + context to look up type information: for instance it allows to + recognise automatically arrays of that type and load them from the + database as a list of the base type (how the base type is converted to + Python is demanded to a `Loader`. + + +The following `!TypeInfo` subclasses allow to fetch more specialised +information from certain class of PostgreSQL types and to create more +specialised adapters configurations. + + +.. autoclass:: CompositeInfo + + .. automethod:: register + + Using `!CompositeInfo.register()` will also register a specialised + loader to fetch the composite type as a Python named tuple, or a + custom object if *factory* is specified. + + +.. autoclass:: RangeInfo + + .. automethod:: register + + Using `!RangeInfo.register()` will also register a specialised loaders + and dumpers. For instance, if you create a PostgreSQL range on the + type :sql:`inet`, loading these object with the database will use the + loader for the :sql:`inet` type to parse the range bounds - either the + builtin ones or any one you might have configured. + + The type information will also be used by the `Range` dumper so that + if you dump a `!Range(address1, address2)` object it will use the + correct oid for your :sql:`inetrange` type. + + +Objects wrappers +---------------- + +.. admonition:: TODO + + Document the various objects wrappers + + - Int2, Int4, Int8, ... + - Json, Jsonb + - Range