database as a list of the base type.
-The following `!TypeInfo` subclasses allow to fetch more specialised
-information from certain class of PostgreSQL types.
-
-.. autoclass:: psycopg.types.composite.CompositeInfo
-
-.. autoclass:: psycopg.types.range.RangeInfo
-
+For recursive types, Psycopg offers a few `!TypeInfo` subclasses which can be
+used to extract more complete information, for instance
+`~psycopg.types.composite.CompositeInfo` and `~psycopg.types.range.RangeInfo`.
`!TypeInfo` objects are collected in `TypesRegistry` instances, which help type
information lookup. Every `~psycopg.adapt.AdaptersMap` expose its type map on
.. _types-adaptation:
-Adaptation between Python and PostgreSQL types
-==============================================
+Adapting basic Python types
+===========================
Many standard Python types are adapted into SQL and returned as Python
objects when a query is executed.
+--------------------+-------------------------+--------------------------+
| `!dict` | :sql:`hstore` | :ref:`adapt-hstore` |
+--------------------+-------------------------+--------------------------+
- | Psycopg's `!Range` | :sql:`range` | :ref:`adapt-range` |
- +--------------------+-------------------------+--------------------------+
.. index::
.. _adapt-composite:
.. _adapt-hstore:
-.. _adapt-range:
TODO adaptation
--- /dev/null
+.. currentmodule:: psycopg
+
+.. index::
+ single: Adaptation
+ pair: Objects; Adaptation
+ single: Data types; Adaptation
+
+.. _extra-adaptation:
+
+Adapting other PostgreSQL types
+===============================
+
+PostgreSQL offers other data types which don't map to native Python types.
+Psycopg offers wrappers and conversion functions to allow their use.
+
+
+.. _adapt-range:
+
+Range adaptation
+----------------
+
+PostgreSQL `range types`__ are a family of data types representing a range of
+value between two elements. The type of the element is called the range
+*subtype*. PostgreSQL offers a few built-in range types and allows the
+definition of custom ones.
+
+.. __: https://www.postgresql.org/docs/current/rangetypes.html
+
+All the PostgreSQL range types are loaded as the `~psycopg.types.range.Range`
+Python type, which is a `~typing.Generic` type and can hold bounds of
+different types.
+
+.. autoclass:: psycopg.types.range.Range
+
+ This Python type is only used to pass and retrieve range values to and
+ from PostgreSQL and doesn't attempt to replicate the PostgreSQL range
+ features: it doesn't perform normalization and doesn't implement all the
+ operators__ supported by the database.
+
+ .. __: https://www.postgresql.org/docs/current/static/functions-range.html#RANGE-OPERATORS-TABLE
+
+ `!Range` objects are immutable, hashable, and support the ``in`` operator
+ (checking if an element is within the range). They can be tested for
+ equivalence. Empty ranges evaluate to `!False` in boolean context,
+ nonempty evaluate to `!True`.
+
+ `!Range` objects have the following attributes:
+
+ .. autoattribute:: isempty
+ .. autoattribute:: lower
+ .. autoattribute:: upper
+ .. autoattribute:: lower_inc
+ .. autoattribute:: upper_inc
+ .. autoattribute:: lower_inf
+ .. autoattribute:: upper_inf
+
+The built-in range objects are adapted automatically: if a `!Range` objects
+contains `~datetime.date` bounds, it is dumped using the :sql:`daterange` OID,
+and of course :sql:`daterange` values are loaded back as `!Range[date]`.
+
+If you create your own range type you can use `~psycopg.types.range.RangeInfo`
+and `~psycopg.types.range.register_range()` to associate the range type with
+its subtype and make it work like the builtin ones.
+
+.. autoclass:: psycopg.types.range.RangeInfo
+
+ `~RangeInfo` is a `~psycopg.types.TypeInfo` subclass: check its
+ documentation for generic details.
+
+.. autofunction:: psycopg.types.range.register_range
+
+Example::
+
+ >>> conn.execute("create type strrange as range (subtype = text)")
+
+ >>> info = RangeInfo.fetch(conn, "strrange")
+ >>> register_range(info, conn)
+
+ >>> conn.execute("select pg_typeof(%s)", [Range("a", "z")]).fetchone()[0]
+ 'strrange'
+
+ >>> conn.execute("select '[a,z]'::strrange").fetchone()[0]
+ Range('a', 'z', '[]')
class Range(Generic[T]):
- """Python representation for a PostgreSQL |range|_ type.
+ """Python representation for a PostgreSQL range type.
:param lower: lower bound for the range. `!None` means unbound
:param upper: upper bound for the range. `!None` means unbound
"""
Register custom range adapters on a context.
- Just register loaders associated to the range oid, loading bounds of the
- right subtype. Dumping the range just works, navigating from tye Python
- type to the type oid, to the range oid.
+ Register loaders so that loading data of this type will result in a `Range`
+ with bounds parsed as the right subtype.
"""
# Register arrays and type info