[Python-modules-commits] [asyncpg] 01/04: Import asyncpg_0.8.4.orig.tar.gz
Piotr Ożarowski
piotr at moszumanska.debian.org
Tue Jan 10 19:27:05 UTC 2017
This is an automated email from the git hooks/post-receive script.
piotr pushed a commit to branch master
in repository asyncpg.
commit e9cb3b6f12e56cc396c8f31e98ed2d2f037d9973
Author: Piotr Ożarowski <piotr at debian.org>
Date: Tue Jan 10 20:19:05 2017 +0100
Import asyncpg_0.8.4.orig.tar.gz
---
PKG-INFO | 9 +-
README.rst | 7 +-
asyncpg.egg-info/PKG-INFO | 9 +-
asyncpg.egg-info/SOURCES.txt | 1 +
asyncpg/introspection.py | 49 +-
asyncpg/protocol/buffer.pxd | 34 +-
asyncpg/protocol/buffer.pyx | 46 +-
asyncpg/protocol/codecs/array.pyx | 438 +-
asyncpg/protocol/codecs/base.pxd | 13 +-
asyncpg/protocol/codecs/base.pyx | 174 +-
asyncpg/protocol/codecs/bits.pyx | 8 +-
asyncpg/protocol/codecs/bytea.pyx | 2 +-
asyncpg/protocol/codecs/datetime.pyx | 67 +-
asyncpg/protocol/codecs/geometry.pyx | 23 +-
asyncpg/protocol/codecs/hstore.pyx | 10 +-
asyncpg/protocol/codecs/int.pyx | 6 +-
asyncpg/protocol/codecs/network.pyx | 4 +-
asyncpg/protocol/codecs/range.pyx | 6 +-
asyncpg/protocol/codecs/record.pyx | 9 +-
asyncpg/protocol/codecs/text.pyx | 4 +-
asyncpg/protocol/codecs/textutils.pyx | 72 +
asyncpg/protocol/codecs/txid.pyx | 9 +-
asyncpg/protocol/consts.pxi | 1 +
asyncpg/protocol/coreproto.pxd | 4 +-
asyncpg/protocol/coreproto.pyx | 6 +-
asyncpg/protocol/hton.pxd | 10 +-
asyncpg/protocol/pgtypes.pxi | 136 +-
asyncpg/protocol/prepared_stmt.pxd | 2 +-
asyncpg/protocol/prepared_stmt.pyx | 4 +-
asyncpg/protocol/protocol.c | 18377 +++++++++++++++++++++-----------
asyncpg/protocol/protocol.pyx | 6 +-
asyncpg/protocol/python.pxd | 5 +
asyncpg/protocol/record/recordobj.c | 10 +-
asyncpg/protocol/settings.pxd | 2 +-
asyncpg/protocol/settings.pyx | 11 +-
setup.py | 4 +-
tests/test_codecs.py | 108 +-
tests/test_connect.py | 17 +-
tests/test_pool.py | 2 +-
tests/test_timeout.py | 25 +-
40 files changed, 13168 insertions(+), 6562 deletions(-)
diff --git a/PKG-INFO b/PKG-INFO
index 76babe9..eef00cf 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: asyncpg
-Version: 0.8.1
+Version: 0.8.4
Summary: An asyncio PosgtreSQL driver
Home-page: https://github.com/MagicStack/asyncpg
Author: MagicStack Inc
@@ -24,6 +24,9 @@ Description: asyncpg -- A fast PostgreSQL Database Client Library for Python/asy
framework. You can read more about asyncpg in an introductory
`blog post <http://magic.io/blog/asyncpg-1m-rows-from-postgres-to-python/>`_.
+ asyncpg requires Python 3.5 or later and is supported for PostgreSQL
+ versions 9.1 to 9.6.
+
Documentation
-------------
@@ -65,8 +68,8 @@ Description: asyncpg -- A fast PostgreSQL Database Client Library for Python/asy
Installation
------------
- asyncpg requires Python 3.5 and is available on PyPI.
- Use pip to install it::
+ asyncpg is available on PyPI and has no dependencies.
+ Use pip to install::
$ pip install asyncpg
diff --git a/README.rst b/README.rst
index c970192..8730e0f 100644
--- a/README.rst
+++ b/README.rst
@@ -16,6 +16,9 @@ of PostgreSQL server binary protocol for use with Python's ``asyncio``
framework. You can read more about asyncpg in an introductory
`blog post <http://magic.io/blog/asyncpg-1m-rows-from-postgres-to-python/>`_.
+asyncpg requires Python 3.5 or later and is supported for PostgreSQL
+versions 9.1 to 9.6.
+
Documentation
-------------
@@ -57,8 +60,8 @@ This enables asyncpg to have easy-to-use support for:
Installation
------------
-asyncpg requires Python 3.5 and is available on PyPI.
-Use pip to install it::
+asyncpg is available on PyPI and has no dependencies.
+Use pip to install::
$ pip install asyncpg
diff --git a/asyncpg.egg-info/PKG-INFO b/asyncpg.egg-info/PKG-INFO
index 76babe9..eef00cf 100644
--- a/asyncpg.egg-info/PKG-INFO
+++ b/asyncpg.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: asyncpg
-Version: 0.8.1
+Version: 0.8.4
Summary: An asyncio PosgtreSQL driver
Home-page: https://github.com/MagicStack/asyncpg
Author: MagicStack Inc
@@ -24,6 +24,9 @@ Description: asyncpg -- A fast PostgreSQL Database Client Library for Python/asy
framework. You can read more about asyncpg in an introductory
`blog post <http://magic.io/blog/asyncpg-1m-rows-from-postgres-to-python/>`_.
+ asyncpg requires Python 3.5 or later and is supported for PostgreSQL
+ versions 9.1 to 9.6.
+
Documentation
-------------
@@ -65,8 +68,8 @@ Description: asyncpg -- A fast PostgreSQL Database Client Library for Python/asy
Installation
------------
- asyncpg requires Python 3.5 and is available on PyPI.
- Use pip to install it::
+ asyncpg is available on PyPI and has no dependencies.
+ Use pip to install::
$ pip install asyncpg
diff --git a/asyncpg.egg-info/SOURCES.txt b/asyncpg.egg-info/SOURCES.txt
index 5cc7811..1a18c5c 100644
--- a/asyncpg.egg-info/SOURCES.txt
+++ b/asyncpg.egg-info/SOURCES.txt
@@ -60,6 +60,7 @@ asyncpg/protocol/codecs/numeric.pyx
asyncpg/protocol/codecs/range.pyx
asyncpg/protocol/codecs/record.pyx
asyncpg/protocol/codecs/text.pyx
+asyncpg/protocol/codecs/textutils.pyx
asyncpg/protocol/codecs/tsearch.pyx
asyncpg/protocol/codecs/txid.pyx
asyncpg/protocol/codecs/uuid.pyx
diff --git a/asyncpg/introspection.py b/asyncpg/introspection.py
index 4554629..a9050d9 100644
--- a/asyncpg/introspection.py
+++ b/asyncpg/introspection.py
@@ -7,8 +7,8 @@
INTRO_LOOKUP_TYPES = '''\
WITH RECURSIVE typeinfo_tree(
- oid, ns, name, kind, basetype, elemtype, range_subtype,
- elem_has_bin_input, elem_has_bin_output, attrtypoids, attrnames, depth)
+ oid, ns, name, kind, basetype, has_bin_io, elemtype, elemdelim,
+ range_subtype, elem_has_bin_io, attrtypoids, attrnames, depth)
AS (
WITH composite_attrs
AS (
@@ -58,10 +58,23 @@ AS (
ELSE NULL
END) AS basetype,
+ t.typreceive::oid != 0 AND t.typsend::oid != 0
+ AS has_bin_io,
t.typelem AS elemtype,
+ elem_t.typdelim AS elemdelim,
range_t.rngsubtype AS range_subtype,
- elem_t.typreceive::oid != 0 AS elem_has_bin_input,
- elem_t.typsend::oid != 0 AS elem_has_bin_output,
+ (CASE WHEN t.typtype = 'r' THEN
+ (SELECT
+ range_elem_t.typreceive::oid != 0 AND
+ range_elem_t.typsend::oid != 0
+ FROM
+ pg_catalog.pg_type AS range_elem_t
+ WHERE
+ range_elem_t.oid = range_t.rngsubtype)
+ ELSE
+ elem_t.typreceive::oid != 0 AND
+ elem_t.typsend::oid != 0
+ END) AS elem_has_bin_io,
(CASE WHEN t.typtype = 'c' THEN
(SELECT ca.typoids
FROM composite_attrs AS ca
@@ -91,8 +104,8 @@ AS (
)
SELECT
- ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.elemtype,
- ti.range_subtype, ti.elem_has_bin_input, ti.elem_has_bin_output,
+ ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.has_bin_io,
+ ti.elemtype, ti.elemdelim, ti.range_subtype, ti.elem_has_bin_io,
ti.attrtypoids, ti.attrnames, 0
FROM
typeinfo AS ti
@@ -102,8 +115,8 @@ AS (
UNION ALL
SELECT
- ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.elemtype,
- ti.range_subtype, ti.elem_has_bin_input, ti.elem_has_bin_output,
+ ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.has_bin_io,
+ ti.elemtype, ti.elemdelim, ti.range_subtype, ti.elem_has_bin_io,
ti.attrtypoids, ti.attrnames, tt.depth + 1
FROM
typeinfo ti,
@@ -126,8 +139,8 @@ ORDER BY
# Prior to 9.2 PostgreSQL did not have range types.
INTRO_LOOKUP_TYPES_91 = '''\
WITH RECURSIVE typeinfo_tree(
- oid, ns, name, kind, basetype, elemtype, range_subtype,
- elem_has_bin_input, elem_has_bin_output, attrtypoids, attrnames, depth)
+ oid, ns, name, kind, basetype, has_bin_io, elemtype, elemdelim,
+ range_subtype, elem_has_bin_io, attrtypoids, attrnames, depth)
AS (
WITH composite_attrs
AS (
@@ -177,10 +190,14 @@ AS (
ELSE NULL
END) AS basetype,
+ t.typreceive::oid != 0 AND t.typsend::oid != 0
+ AS has_bin_io,
t.typelem AS elemtype,
+ elem_t.typdelim AS elemdelim,
NULL::oid AS range_subtype,
- elem_t.typreceive::oid != 0 AS elem_has_bin_input,
- elem_t.typsend::oid != 0 AS elem_has_bin_output,
+ elem_t.typreceive::oid != 0 AND
+ elem_t.typsend::oid != 0
+ AS elem_has_bin_io,
(CASE WHEN t.typtype = 'c' THEN
(SELECT ca.typoids
FROM composite_attrs AS ca
@@ -207,8 +224,8 @@ AS (
)
SELECT
- ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.elemtype,
- ti.range_subtype, ti.elem_has_bin_input, ti.elem_has_bin_output,
+ ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.has_bin_io,
+ ti.elemtype, ti.elemdelim, ti.range_subtype, ti.elem_has_bin_io,
ti.attrtypoids, ti.attrnames, 0
FROM
typeinfo AS ti
@@ -218,8 +235,8 @@ AS (
UNION ALL
SELECT
- ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.elemtype,
- ti.range_subtype, ti.elem_has_bin_input, ti.elem_has_bin_output,
+ ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.has_bin_io,
+ ti.elemtype, ti.elemdelim, ti.range_subtype, ti.elem_has_bin_io,
ti.attrtypoids, ti.attrnames, tt.depth + 1
FROM
typeinfo ti,
diff --git a/asyncpg/protocol/buffer.pxd b/asyncpg/protocol/buffer.pxd
index 2ef7fab..6687e8e 100644
--- a/asyncpg/protocol/buffer.pxd
+++ b/asyncpg/protocol/buffer.pxd
@@ -9,12 +9,12 @@ cdef class Memory:
cdef:
char* buf
object owner
- int length
+ ssize_t length
cdef as_bytes(self)
@staticmethod
- cdef inline Memory new(char* buf, object owner, int length)
+ cdef inline Memory new(char* buf, object owner, ssize_t length)
cdef class WriteBuffer:
@@ -26,10 +26,10 @@ cdef class WriteBuffer:
char *_buf
# Allocated size
- size_t _size
+ ssize_t _size
# Length of data in the buffer
- size_t _length
+ ssize_t _length
# Number of memoryviews attached to the buffer
int _view_count
@@ -39,8 +39,8 @@ cdef class WriteBuffer:
cdef inline _check_readonly(self)
cdef inline len(self)
- cdef inline _ensure_alloced(self, size_t extra_length)
- cdef _reallocate(self, new_size)
+ cdef inline _ensure_alloced(self, ssize_t extra_length)
+ cdef _reallocate(self, ssize_t new_size)
cdef inline start_message(self, char type)
cdef inline end_message(self)
cdef write_buffer(self, WriteBuffer buf)
@@ -81,31 +81,31 @@ cdef class ReadBuffer:
int32_t _bufs_len
# A read position in the first buffer in `_bufs`
- int32_t _pos0
+ ssize_t _pos0
# Length of the first buffer in `_bufs`
- int32_t _len0
+ ssize_t _len0
# A total number of buffered bytes in ReadBuffer
- int32_t _length
+ ssize_t _length
char _current_message_type
int _current_message_len
- int32_t _current_message_len_unread
+ ssize_t _current_message_len_unread
bint _current_message_ready
cdef feed_data(self, data)
cdef inline _ensure_first_buf(self)
cdef _switch_to_next_buf(self)
cdef inline read_byte(self)
- cdef inline char* _try_read_bytes(self, int nbytes)
- cdef inline read(self, int nbytes)
+ cdef inline char* _try_read_bytes(self, ssize_t nbytes)
+ cdef inline read(self, ssize_t nbytes)
cdef inline read_bytes(self, ssize_t n)
cdef inline read_int32(self)
cdef inline read_int16(self)
cdef inline read_cstr(self)
cdef int32_t has_message(self) except -1
- cdef inline char* try_consume_message(self, int32_t* len)
+ cdef inline char* try_consume_message(self, ssize_t* len)
cdef Memory consume_message(self)
cdef discard_message(self)
cdef inline _discard_message(self)
@@ -119,13 +119,13 @@ cdef class ReadBuffer:
cdef class FastReadBuffer:
cdef:
const char* buf
- size_t len
+ ssize_t len
- cdef inline const char* read(self, size_t n) except NULL
+ cdef inline const char* read(self, ssize_t n) except NULL
cdef inline const char* read_all(self)
cdef inline FastReadBuffer slice_from(self, FastReadBuffer source,
- size_t len)
- cdef _raise_ins_err(self, size_t n, size_t len)
+ ssize_t len)
+ cdef _raise_ins_err(self, ssize_t n, ssize_t len)
@staticmethod
cdef FastReadBuffer new()
diff --git a/asyncpg/protocol/buffer.pyx b/asyncpg/protocol/buffer.pyx
index 1649ec9..e999b7a 100644
--- a/asyncpg/protocol/buffer.pyx
+++ b/asyncpg/protocol/buffer.pyx
@@ -21,7 +21,7 @@ cdef class Memory:
return cpython.PyBytes_FromStringAndSize(self.buf, self.length)
@staticmethod
- cdef inline Memory new(char* buf, object owner, int length):
+ cdef inline Memory new(char* buf, object owner, ssize_t length):
cdef Memory mem
mem = Memory.__new__(Memory)
mem.buf = buf
@@ -70,13 +70,13 @@ cdef class WriteBuffer:
cdef inline len(self):
return self._length
- cdef inline _ensure_alloced(self, size_t extra_length):
- cdef size_t new_size = extra_length + self._length
+ cdef inline _ensure_alloced(self, ssize_t extra_length):
+ cdef ssize_t new_size = extra_length + self._length
if new_size > self._size:
self._reallocate(new_size)
- cdef _reallocate(self, new_size):
+ cdef _reallocate(self, ssize_t new_size):
cdef char *new_buf
if new_size < _BUFFER_MAX_GROW:
@@ -86,18 +86,18 @@ cdef class WriteBuffer:
new_size += _BUFFER_INITIAL_SIZE
if self._smallbuf_inuse:
- new_buf = <char*>PyMem_Malloc(sizeof(char) * new_size)
+ new_buf = <char*>PyMem_Malloc(sizeof(char) * <size_t>new_size)
if new_buf is NULL:
self._buf = NULL
self._size = 0
self._length = 0
raise MemoryError
- memcpy(new_buf, self._buf, self._size)
+ memcpy(new_buf, self._buf, <size_t>self._size)
self._size = new_size
self._buf = new_buf
self._smallbuf_inuse = False
else:
- new_buf = <char*>PyMem_Realloc(<void*>self._buf, new_size)
+ new_buf = <char*>PyMem_Realloc(<void*>self._buf, <size_t>new_size)
if new_buf is NULL:
PyMem_Free(self._buf)
self._buf = NULL
@@ -117,7 +117,7 @@ cdef class WriteBuffer:
cdef inline end_message(self):
# "length-1" to exclude the message type byte
- cdef size_t mlen = self._length - 1
+ cdef ssize_t mlen = self._length - 1
self._check_readonly()
if not self._message_mode:
@@ -125,8 +125,10 @@ cdef class WriteBuffer:
'end_message can only be called with start_message')
if self._length < 5:
raise BufferError('end_message: buffer is too small')
+ if mlen > _MAXINT32:
+ raise BufferError('end_message: message is too large')
- hton.pack_int32(&self._buf[1], mlen)
+ hton.pack_int32(&self._buf[1], <int32_t>mlen)
return self
cdef write_buffer(self, WriteBuffer buf):
@@ -138,7 +140,7 @@ cdef class WriteBuffer:
self._ensure_alloced(buf._length)
memcpy(self._buf + self._length,
<void*>buf._buf,
- buf._length)
+ <size_t>buf._length)
self._length += buf._length
cdef write_byte(self, char b):
@@ -171,7 +173,7 @@ cdef class WriteBuffer:
self._check_readonly()
self._ensure_alloced(len)
- memcpy(self._buf + self._length, <void*>data, len)
+ memcpy(self._buf + self._length, <void*>data, <size_t>len)
self._length += len
cdef write_int16(self, int16_t i):
@@ -246,7 +248,7 @@ cdef class ReadBuffer:
cdef feed_data(self, data):
cdef:
- int32_t dlen
+ ssize_t dlen
bytes data_bytes
if not cpython.PyBytes_CheckExact(data):
@@ -293,7 +295,7 @@ cdef class ReadBuffer:
raise RuntimeError(
'debug: second buffer of ReadBuffer is empty')
- cdef inline char* _try_read_bytes(self, int nbytes):
+ cdef inline char* _try_read_bytes(self, ssize_t nbytes):
# Important: caller must call _ensure_first_buf() prior
# to calling try_read_bytes, and must not overread
@@ -319,10 +321,10 @@ cdef class ReadBuffer:
else:
return NULL
- cdef inline read(self, int nbytes):
+ cdef inline read(self, ssize_t nbytes):
cdef:
object result
- int nread
+ ssize_t nread
char *buf
self._ensure_first_buf()
@@ -419,8 +421,8 @@ cdef class ReadBuffer:
'to be in the buffer')
cdef:
- int pos
- int nread
+ ssize_t pos
+ ssize_t nread
bytes result
char* buf
char* buf_start
@@ -504,8 +506,8 @@ cdef class ReadBuffer:
self._current_message_ready = 1
return 1
- cdef inline char* try_consume_message(self, int32_t* len):
- cdef int32_t buf_len
+ cdef inline char* try_consume_message(self, ssize_t* len):
+ cdef ssize_t buf_len
if not self._current_message_ready:
return NULL
@@ -579,7 +581,7 @@ cdef class ReadBuffer:
@cython.freelist(_BUFFER_FREELIST_SIZE)
cdef class FastReadBuffer:
- cdef inline const char* read(self, size_t n) except NULL:
+ cdef inline const char* read(self, ssize_t n) except NULL:
cdef const char *result
if n > self.len:
@@ -599,12 +601,12 @@ cdef class FastReadBuffer:
return result
cdef inline FastReadBuffer slice_from(self, FastReadBuffer source,
- size_t len):
+ ssize_t len):
self.buf = source.read(len)
self.len = len
return self
- cdef _raise_ins_err(self, size_t n, size_t len):
+ cdef _raise_ins_err(self, ssize_t n, ssize_t len):
raise BufferError(
'insufficient data in buffer: requested {}, remaining {}'.
format(n, self.len))
diff --git a/asyncpg/protocol/codecs/array.pyx b/asyncpg/protocol/codecs/array.pyx
index 92706c4..5c13b2e 100644
--- a/asyncpg/protocol/codecs/array.pyx
+++ b/asyncpg/protocol/codecs/array.pyx
@@ -10,6 +10,9 @@ from collections.abc import Container as ContainerABC
DEF ARRAY_MAXDIM = 6 # defined in postgresql/src/includes/c.h
+# "NULL"
+cdef Py_UCS4 *APG_NULL = [0x004E, 0x0055, 0x004C, 0x004C, 0x0000]
+
ctypedef object (*encode_func_ex)(ConnectionSettings settings,
WriteBuffer buf,
@@ -38,21 +41,26 @@ cdef inline _is_sub_array(object obj):
cdef _get_array_shape(object obj, int32_t *dims, int32_t *ndims):
cdef:
- int32_t mylen = len(obj)
- int32_t elemlen = -2
+ ssize_t mylen = len(obj)
+ ssize_t elemlen = -2
object it
+ if mylen > _MAXINT32:
+ raise ValueError('too many elements in array value')
+
if ndims[0] > ARRAY_MAXDIM:
raise ValueError(
'number of array dimensions ({}) exceed the maximum expected ({})'.
format(ndims[0], ARRAY_MAXDIM))
- dims[ndims[0] - 1] = mylen
+ dims[ndims[0] - 1] = <int32_t>mylen
for elem in obj:
if _is_sub_array(elem):
if elemlen == -2:
elemlen = len(elem)
+ if elemlen > _MAXINT32:
+ raise ValueError('too many elements in array value')
ndims[0] += 1
_get_array_shape(elem, dims, ndims)
else:
@@ -123,7 +131,7 @@ cdef inline array_encode(ConnectionSettings settings, WriteBuffer buf,
# flags
buf.write_int32(0)
# element type
- buf.write_int32(elem_oid)
+ buf.write_int32(<int32_t>elem_oid)
# upper / lower bounds
for i in range(ndims):
buf.write_int32(dims[i])
@@ -137,11 +145,11 @@ cdef inline array_decode(ConnectionSettings settings, FastReadBuffer buf,
cdef:
int32_t ndims = hton.unpack_int32(buf.read(4))
int32_t flags = hton.unpack_int32(buf.read(4))
- uint32_t elem_oid = hton.unpack_int32(buf.read(4))
+ uint32_t elem_oid = <uint32_t>hton.unpack_int32(buf.read(4))
list result
- uint32_t i
+ int i
int32_t elem_len
- int64_t elem_count = 1
+ int32_t elem_count = 1
FastReadBuffer elem_buf = FastReadBuffer.new()
int32_t dims[ARRAY_MAXDIM]
Codec elem_codec
@@ -152,8 +160,8 @@ cdef inline array_decode(ConnectionSettings settings, FastReadBuffer buf,
if ndims > ARRAY_MAXDIM:
raise RuntimeError(
- 'number of array dimensions exceed the maximum expected ({})'.
- format(ARRAY_MAXDIM))
+ 'number of array dimensions ({}) exceed the maximum expected ({})'.
+ format(ndims, ARRAY_MAXDIM))
if decoder == NULL:
# No decoder is known beforehand, look it up
@@ -168,12 +176,12 @@ cdef inline array_decode(ConnectionSettings settings, FastReadBuffer buf,
for i in range(ndims):
dims[i] = hton.unpack_int32(buf.read(4))
- elem_count *= dims[i]
# Ignore the lower bound information
buf.read(4)
if ndims == 1:
# Fast path for flat arrays
+ elem_count = dims[0]
result = cpython.PyList_New(elem_count)
for i in range(elem_count):
@@ -307,6 +315,416 @@ cdef inline _nested_array_decode(ConnectionSettings settings,
return result
+cdef textarray_decode(ConnectionSettings settings, FastReadBuffer buf,
+ decode_func_ex decoder, const void *decoder_arg,
+ Py_UCS4 typdelim):
+ cdef:
+ Py_UCS4 *array_text
+ str s
+
+ # Make a copy of array data since we will be mutating it for
+ # the purposes of element decoding.
+ s = text_decode(settings, buf)
+ array_text = PyUnicode_AsUCS4Copy(s)
+
+ try:
+ return _textarray_decode(
+ settings, array_text, decoder, decoder_arg, typdelim)
+ except ValueError as e:
+ raise ValueError(
+ 'malformed array literal {!r}: {}'.format(s, e.args[0]))
+ finally:
+ PyMem_Free(array_text)
+
+
+cdef _textarray_decode(ConnectionSettings settings,
+ Py_UCS4 *array_text,
+ decode_func_ex decoder,
+ const void *decoder_arg,
+ Py_UCS4 typdelim):
+
+ cdef:
+ bytearray array_bytes
+ list result
+ list new_stride
+ Py_UCS4 *ptr
+ int32_t ndims = 0
+ int32_t ubound = 0
+ int32_t lbound = 0
+ int32_t dims[ARRAY_MAXDIM]
+ int32_t inferred_dims[ARRAY_MAXDIM]
+ int32_t inferred_ndims = 0
+ void *strides[ARRAY_MAXDIM]
+ int32_t indexes[ARRAY_MAXDIM]
+ int32_t nest_level = 0
+ int32_t item_level = 0
+ bint end_of_array = False
+
+ bint end_of_item = False
+ bint has_quoting = False
+ bint strip_spaces = False
+ bint in_quotes = False
+ Py_UCS4 *item_start
+ Py_UCS4 *item_ptr
+ Py_UCS4 *item_end
+
+ int i
+ object item
+ str item_text
+ FastReadBuffer item_buf = FastReadBuffer.new()
+ char *pg_item_str
+ ssize_t pg_item_len
+
+ ptr = array_text
+
+ while True:
+ while apg_ascii_isspace(ptr[0]):
+ ptr += 1
+
+ if ptr[0] != '[':
+ # Finished parsing dimensions spec.
+ break
+
+ ptr += 1 # '['
+
+ if ndims > ARRAY_MAXDIM:
+ raise ValueError(
+ 'number of array dimensions ({}) exceed the '
+ 'maximum expected ({})'.format(ndims, ARRAY_MAXDIM))
+
+ ptr = apg_parse_int32(ptr, &ubound)
+ if ptr == NULL:
+ raise ValueError('missing array dimension value')
+
+ if ptr[0] == ':':
+ ptr += 1
+ lbound = ubound
+
+ # [lower:upper] spec. We disregard the lbound for decoding.
+ ptr = apg_parse_int32(ptr, &ubound)
+ if ptr == NULL:
+ raise ValueError('missing array dimension value')
+ else:
+ lbound = 1
+
+ if ptr[0] != ']':
+ raise ValueError('missing \']\' after array dimensions')
+
+ ptr += 1 # ']'
+
+ dims[ndims] = ubound - lbound + 1
+ ndims += 1
+
+ if ndims != 0:
+ # If dimensions were given, the '=' token is expected.
+ if ptr[0] != '=':
+ raise ValueError('missing \'=\' after array dimensions')
+
+ ptr += 1 # '='
+
+ # Skip any whitespace after the '=', whitespace
+ # before was consumed in the above loop.
+ while apg_ascii_isspace(ptr[0]):
+ ptr += 1
+
+ # Infer the dimensions from the brace structure in the
+ # array literal body, and check that it matches the explicit
+ # spec. This also validates that the array literal is sane.
+ _infer_array_dims(ptr, typdelim, inferred_dims, &inferred_ndims)
+
+ if inferred_ndims != ndims:
+ raise ValueError(
+ 'specified array dimensions do not match array content')
+
+ for i in range(ndims):
+ if inferred_dims[i] != dims[i]:
+ raise ValueError(
+ 'specified array dimensions do not match array content')
+ else:
+ # Infer the dimensions from the brace structure in the array literal
+ # body. This also validates that the array literal is sane.
+ _infer_array_dims(ptr, typdelim, dims, &ndims)
+
+ while not end_of_array:
+ # We iterate over the literal character by character
+ # and modify the string in-place removing the array-specific
+ # quoting and determining the boundaries of each element.
+ end_of_item = has_quoting = in_quotes = False
+ strip_spaces = True
+
+ # Pointers to array element start, end, and the current pointer
+ # tracking the position where characters are written when
+ # escaping is folded.
+ item_start = item_end = item_ptr = ptr
+ item_level = 0
+
+ while not end_of_item:
+ if ptr[0] == '"':
+ in_quotes = not in_quotes
+ if in_quotes:
+ strip_spaces = False
+ else:
+ item_end = item_ptr
+ has_quoting = True
+
+ elif ptr[0] == '\\':
+ # Quoted character, collapse the backslash.
+ ptr += 1
+ has_quoting = True
+ item_ptr[0] = ptr[0]
+ item_ptr += 1
+ strip_spaces = False
+ item_end = item_ptr
+
+ elif in_quotes:
+ # Consume the string until we see the closing quote.
+ item_ptr[0] = ptr[0]
+ item_ptr += 1
+
+ elif ptr[0] == '{':
+ # Nesting level increase.
+ nest_level += 1
+
+ indexes[nest_level - 1] = 0
+ new_stride = cpython.PyList_New(dims[nest_level - 1])
+ strides[nest_level - 1] = \
+ <void*>(<cpython.PyObject>new_stride)
+
+ if nest_level > 1:
+ cpython.Py_INCREF(new_stride)
+ cpython.PyList_SET_ITEM(
+ <object><cpython.PyObject*>strides[nest_level - 2],
+ indexes[nest_level - 2],
+ new_stride)
+ else:
+ result = new_stride
+
+ elif ptr[0] == '}':
+ if item_level == 0:
+ # Make sure we keep track of which nesting
+ # level the item belongs to, as the loop
+ # will continue to consume closing braces
+ # until the delimiter or the end of input.
+ item_level = nest_level
+
+ nest_level -= 1
+
+ if nest_level == 0:
+ end_of_array = end_of_item = True
+
+ elif ptr[0] == typdelim:
+ # Array element delimiter,
+ end_of_item = True
+ if item_level == 0:
+ item_level = nest_level
+
+ elif apg_ascii_isspace(ptr[0]):
+ if not strip_spaces:
+ item_ptr[0] = ptr[0]
+ item_ptr += 1
+ # Ignore the leading literal whitespace.
+
+ else:
+ item_ptr[0] = ptr[0]
+ item_ptr += 1
+ strip_spaces = False
+ item_end = item_ptr
+
+ ptr += 1
+
+ # end while not end_of_item
+
+ if item_end == item_start:
+ # Empty array
+ continue
+
+ item_end[0] = '\0'
+
+ if not has_quoting and apg_strcasecmp(item_start, APG_NULL) == 0:
+ # NULL element.
+ item = None
+ else:
+ # XXX: find a way to avoid the redundant encode/decode
+ # cycle here.
+ item_text = PyUnicode_FromKindAndData(
+ PyUnicode_4BYTE_KIND,
+ <void *>item_start,
+ item_end - item_start)
+
+ # Prepare the element buffer and call the text decoder
+ # for the element type.
+ as_pg_string_and_size(
+ settings, item_text, &pg_item_str, &pg_item_len)
+ item_buf.buf = pg_item_str
+ item_buf.len = pg_item_len
+ item = decoder(settings, item_buf, decoder_arg)
+
+ # Place the decoded element in the array.
+ cpython.Py_INCREF(item)
+ cpython.PyList_SET_ITEM(
+ <object><cpython.PyObject*>strides[item_level - 1],
+ indexes[item_level - 1],
+ item)
+
+ indexes[nest_level - 1] += 1
+
+ return result
+
+
+cdef enum _ArrayParseState:
+ APS_START = 1
+ APS_STRIDE_STARTED = 2
+ APS_STRIDE_DONE = 3
+ APS_STRIDE_DELIMITED = 4
+ APS_ELEM_STARTED = 5
+ APS_ELEM_DELIMITED = 6
+
+
+cdef _UnexpectedCharacter(const Py_UCS4 *array_text, const Py_UCS4 *ptr):
+ return ValueError('unexpected character {!r} at position {}'.format(
+ cpython.PyUnicode_FromOrdinal(<int>ptr[0]), ptr - array_text + 1))
+
+
+cdef _infer_array_dims(const Py_UCS4 *array_text,
+ Py_UCS4 typdelim,
+ int32_t *dims,
+ int32_t *ndims):
+ cdef:
+ const Py_UCS4 *ptr = array_text
+ int i
+ int nest_level = 0
+ bint end_of_array = False
+ bint end_of_item = False
+ bint in_quotes = False
+ bint array_is_empty = True
+ int stride_len[ARRAY_MAXDIM]
+ int prev_stride_len[ARRAY_MAXDIM]
+ _ArrayParseState parse_state = APS_START
+
+ for i in range(ARRAY_MAXDIM):
+ dims[i] = prev_stride_len[i] = 0
+ stride_len[i] = 1
+
+ while not end_of_array:
+ end_of_item = False
+
+ while not end_of_item:
+ if ptr[0] == '\0':
+ raise ValueError('unexpected end of string')
+
+ elif ptr[0] == '"':
+ if (parse_state not in (APS_STRIDE_STARTED,
+ APS_ELEM_DELIMITED) and
+ not (parse_state == APS_ELEM_STARTED and in_quotes)):
+ raise _UnexpectedCharacter(array_text, ptr)
+
+ in_quotes = not in_quotes
+ if in_quotes:
+ parse_state = APS_ELEM_STARTED
+ array_is_empty = False
+
+ elif ptr[0] == '\\':
+ if parse_state not in (APS_STRIDE_STARTED,
+ APS_ELEM_STARTED,
+ APS_ELEM_DELIMITED):
+ raise _UnexpectedCharacter(array_text, ptr)
+
+ parse_state = APS_ELEM_STARTED
+ array_is_empty = False
+
+ if ptr[1] != '\0':
+ ptr += 1
+ else:
+ raise ValueError('unexpected end of string')
+
+ elif in_quotes:
+ # Ignore everything inside the quotes.
+ pass
+
+ elif ptr[0] == '{':
+ if parse_state not in (APS_START,
+ APS_STRIDE_STARTED,
+ APS_STRIDE_DELIMITED):
+ raise _UnexpectedCharacter(array_text, ptr)
+
+ parse_state = APS_STRIDE_STARTED
+ if nest_level >= ARRAY_MAXDIM:
+ raise ValueError(
+ 'number of array dimensions ({}) exceed the '
+ 'maximum expected ({})'.format(
+ nest_level, ARRAY_MAXDIM))
+
+ dims[nest_level] = 0
+ nest_level += 1
+ if ndims[0] < nest_level:
+ ndims[0] = nest_level
+
+ elif ptr[0] == '}':
+ if (parse_state not in (APS_ELEM_STARTED, APS_STRIDE_DONE) and
+ not (nest_level == 1 and
+ parse_state == APS_STRIDE_STARTED)):
+ raise _UnexpectedCharacter(array_text, ptr)
+
+ parse_state = APS_STRIDE_DONE
+
+ if nest_level == 0:
+ raise _UnexpectedCharacter(array_text, ptr)
+
+ nest_level -= 1
+
+ if (prev_stride_len[nest_level] != 0 and
+ stride_len[nest_level] != prev_stride_len[nest_level]):
+ raise ValueError(
+ 'inconsistent sub-array dimensions'
+ ' at position {}'.format(
+ ptr - array_text + 1))
+
+ prev_stride_len[nest_level] = stride_len[nest_level]
+ stride_len[nest_level] = 1
+ if nest_level == 0:
+ end_of_array = end_of_item = True
+ else:
+ dims[nest_level - 1] += 1
+
... 40877 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/asyncpg.git
More information about the Python-modules-commits
mailing list