Skip to content

Commit

Permalink
Make the Record type available as asyncpg.Record.
Browse files Browse the repository at this point in the history
Fixes: #93.
  • Loading branch information
elprans committed Mar 24, 2017
1 parent c919573 commit 5940b46
Show file tree
Hide file tree
Showing 8 changed files with 41 additions and 17 deletions.
3 changes: 2 additions & 1 deletion asyncpg/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
from .connection import connect # NOQA
from .exceptions import * # NOQA
from .pool import create_pool # NOQA
from .protocol import Record # NOQA
from .types import * # NOQA


__all__ = ('connect', 'create_pool') + exceptions.__all__ # NOQA
__all__ = ('connect', 'create_pool', 'Record') + exceptions.__all__ # NOQA
2 changes: 1 addition & 1 deletion asyncpg/protocol/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0


from .protocol import Protocol
from .protocol import Protocol, Record # NOQA
2 changes: 1 addition & 1 deletion asyncpg/protocol/protocol.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -529,4 +529,4 @@ def _create_record(object mapping, tuple elems):
return rec


record.ApgRecord_InitTypes()
Record = <object>record.ApgRecord_InitTypes()
5 changes: 4 additions & 1 deletion asyncpg/protocol/record/__init__.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0


cimport cpython


cdef extern from "record/recordobj.h":

int ApgRecord_InitTypes() except -1
cpython.PyTypeObject *ApgRecord_InitTypes() except NULL

int ApgRecord_CheckExact(object)
object ApgRecord_New(object, int)
Expand Down
15 changes: 8 additions & 7 deletions asyncpg/protocol/record/recordobj.c
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ static PyMethodDef record_methods[] = {

PyTypeObject ApgRecord_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"Record", /* tp_name */
"asyncpg.Record", /* tp_name */
sizeof(ApgRecordObject) - sizeof(PyObject *), /* tp_basic_size */
sizeof(PyObject *), /* tp_itemsize */
(destructor)record_dealloc, /* tp_dealloc */
Expand Down Expand Up @@ -849,25 +849,26 @@ record_new_items_iter(PyObject *seq)
}


int ApgRecord_InitTypes(void)
PyTypeObject *
ApgRecord_InitTypes(void)
{
if (PyType_Ready(&ApgRecord_Type) < 0) {
return -1;
return NULL;
}

if (PyType_Ready(&ApgRecordDesc_Type) < 0) {
return -1;
return NULL;
}

if (PyType_Ready(&ApgRecordIter_Type) < 0) {
return -1;
return NULL;
}

if (PyType_Ready(&ApgRecordItems_Type) < 0) {
return -1;
return NULL;
}

return 0;
return &ApgRecord_Type;
}


Expand Down
6 changes: 3 additions & 3 deletions asyncpg/protocol/record/recordobj.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ extern PyTypeObject ApgRecordDesc_Type;
#define ApgRecord_GET_ITEM(op, i) \
(((ApgRecordObject *)(op))->ob_item[i])

int ApgRecord_InitTypes(void);
PyObject * ApgRecord_New(PyObject *, Py_ssize_t);
PyObject * ApgRecordDesc_New(PyObject *, PyObject *);
PyTypeObject *ApgRecord_InitTypes(void);
PyObject *ApgRecord_New(PyObject *, Py_ssize_t);
PyObject *ApgRecordDesc_New(PyObject *, PyObject *);

#endif
13 changes: 10 additions & 3 deletions docs/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,9 @@ Record Objects
==============

Each row (or composite type value) returned by calls to ``fetch*`` methods
is represented by an instance of the ``Record`` object. ``Record`` objects
are similar to instances of ``collections.namedtuple`` and allow addressing
of values either by a numeric index or by a field name:
is represented by an instance of the :class:`~asyncpg.Record` object.
``Record`` objects are a tuple-/dict-like hybrid, and allow addressing of
items either by a numeric index or by a field name:

.. code-block:: pycon
Expand All @@ -267,7 +267,14 @@ of values either by a numeric index or by a field name:
16388
>>> r[0]
16388
>>> dict(r)
{'oid': 16388, 'rolname': 'elvis', 'rolsuper': True}
>>> tuple(r)
(16388, 'elvis', True)
.. note::

``Record`` objects currently cannot be created from Python code.

.. class:: Record()

Expand Down
12 changes: 12 additions & 0 deletions tests/test_record.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import pickle
import sys

import asyncpg
from asyncpg import _testbase as tb
from asyncpg.protocol.protocol import _create_record as Record

Expand Down Expand Up @@ -297,3 +298,14 @@ async def test_record_duplicate_colnames(self):
self.assertEqual(r['a'], 2)
self.assertEqual(r[0], 1)
self.assertEqual(repr(r), '<Record a=1 a=2>')

async def test_record_isinstance(self):
"""Test that Record works with isinstance."""
r = await self.con.fetchrow('SELECT 1 as a, 2 as b')
self.assertTrue(isinstance(r, asyncpg.Record))

async def test_record_no_new(self):
"""Instances of Record cannot be directly created."""
with self.assertRaisesRegex(
TypeError, "cannot create 'asyncpg.Record' instances"):
asyncpg.Record()

0 comments on commit 5940b46

Please sign in to comment.