Commit 83029192 authored by Tres Seaver's avatar Tres Seaver

Document / enforce that fsBTree deals in bytes, not text.

parent ab9cfb5c
...@@ -1420,10 +1420,10 @@ def to_long(self, v): ...@@ -1420,10 +1420,10 @@ def to_long(self, v):
return int(v) return int(v)
def to_str(l): def to_bytes(l):
def to(self, v): def to(self, v):
if not (isinstance(v, str) and len(v) == l): if not (isinstance(v, bytes) and len(v) == l):
raise TypeError("%s-character string expected" % l) raise TypeError("%s-byte array expected" % l)
return v return v
return to return to
......
...@@ -26,6 +26,8 @@ if sys.version_info[0] < 3: #pragma NO COVER Python2 ...@@ -26,6 +26,8 @@ if sys.version_info[0] < 3: #pragma NO COVER Python2
cmp = cmp cmp = cmp
_bytes = str _bytes = str
def _ascii(x):
return bytes(x)
def _u(s, encoding='unicode_escape'): def _u(s, encoding='unicode_escape'):
return unicode(s, encoding) return unicode(s, encoding)
...@@ -45,6 +47,8 @@ else: #pragma NO COVER Python3 ...@@ -45,6 +47,8 @@ else: #pragma NO COVER Python3
return (x > y) - (y > x) return (x > y) - (y > x)
_bytes = bytes _bytes = bytes
def _ascii(x):
return bytes(x, 'ascii')
def _u(s, encoding=None): def _u(s, encoding=None):
if encoding is None: if encoding is None:
......
...@@ -71,15 +71,19 @@ typedef unsigned char char6[6]; ...@@ -71,15 +71,19 @@ typedef unsigned char char6[6];
#include "Python.h" #include "Python.h"
static PyObject *bucket_toString(PyObject *self); static PyObject *bucket_toBytes(PyObject *self);
static PyObject *bucket_fromString(PyObject *self, PyObject *state); static PyObject *bucket_fromBytes(PyObject *self, PyObject *state);
#define EXTRA_BUCKET_METHODS \ #define EXTRA_BUCKET_METHODS \
{"toString", (PyCFunction) bucket_toString, METH_NOARGS, \ {"toBytes", (PyCFunction) bucket_toBytes, METH_NOARGS, \
"toString() -- Return the state as a string"}, \ "toBytes() -- Return the state as a bytes array"}, \
{"fromString", (PyCFunction) bucket_fromString, METH_O, \ {"fromBytes", (PyCFunction) bucket_fromBytes, METH_O, \
"fromString(s) -- Set the state of the object from a string"}, \ "fromSBytes(s) -- Set the state of the object from a bytes array"}, \
{"toString", (PyCFunction) bucket_toBytes, METH_NOARGS, \
"toString() -- Deprecated alias for 'toBytes'"}, \
{"fromString", (PyCFunction) bucket_fromBytes, METH_O, \
"fromString(s) -- Deprecated alias for 'fromBytes'"}, \
#ifdef PY3K #ifdef PY3K
#define INITMODULE PyInit__fsBTree #define INITMODULE PyInit__fsBTree
...@@ -89,7 +93,7 @@ static PyObject *bucket_fromString(PyObject *self, PyObject *state); ...@@ -89,7 +93,7 @@ static PyObject *bucket_fromString(PyObject *self, PyObject *state);
#include "BTreeModuleTemplate.c" #include "BTreeModuleTemplate.c"
static PyObject * static PyObject *
bucket_toString(PyObject *oself) bucket_toBytes(PyObject *oself)
{ {
Bucket *self = (Bucket *)oself; Bucket *self = (Bucket *)oself;
PyObject *items = NULL; PyObject *items = NULL;
...@@ -115,7 +119,7 @@ bucket_toString(PyObject *oself) ...@@ -115,7 +119,7 @@ bucket_toString(PyObject *oself)
} }
static PyObject * static PyObject *
bucket_fromString(PyObject *oself, PyObject *state) bucket_fromBytes(PyObject *oself, PyObject *state)
{ {
Bucket *self = (Bucket *)oself; Bucket *self = (Bucket *)oself;
int len; int len;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
# fsBTrees are data structures used for ZODB FileStorage. They are not # fsBTrees are data structures used for ZODB FileStorage. They are not
# expected to be "public" excpect to FileStorage. # expected to be "public" excpect to FileStorage.
# Each item in an fsBTree maps a two-byte key to a six-byte value.
__all__ = ('Bucket', 'Set', 'BTree', 'TreeSet', __all__ = ('Bucket', 'Set', 'BTree', 'TreeSet',
'fsBucket', 'fsSet', 'fsBTree', 'fsTreeSet', 'fsBucket', 'fsSet', 'fsBTree', 'fsTreeSet',
...@@ -31,14 +32,14 @@ from ._base import TreeSet ...@@ -31,14 +32,14 @@ from ._base import TreeSet
from ._base import difference as _difference from ._base import difference as _difference
from ._base import intersection as _intersection from ._base import intersection as _intersection
from ._base import set_operation as _set_operation from ._base import set_operation as _set_operation
from ._base import to_str as _to_str from ._base import to_bytes as _to_bytes
from ._base import union as _union from ._base import union as _union
_BUCKET_SIZE = 500 _BUCKET_SIZE = 500
_TREE_SIZE = 500 _TREE_SIZE = 500
using64bits = False using64bits = False
_to_key = _to_str(2) _to_key = _to_bytes(2)
_to_value = _to_str(6) _to_value = _to_bytes(6)
class fsBucketPy(Bucket): class fsBucketPy(Bucket):
...@@ -47,7 +48,7 @@ class fsBucketPy(Bucket): ...@@ -47,7 +48,7 @@ class fsBucketPy(Bucket):
_to_value = _to_value _to_value = _to_value
def toString(self): def toString(self):
return ''.join(self._keys) + ''.join(self._values) return b''.join(self._keys) + b''.join(self._values)
def fromString(self, v): def fromString(self, v):
length = len(v) length = len(v)
......
...@@ -2909,18 +2909,18 @@ class Test_helpers(unittest.TestCase): ...@@ -2909,18 +2909,18 @@ class Test_helpers(unittest.TestCase):
faux_self = object() faux_self = object()
self.assertRaises(TypeError, to_long, faux_self, ()) self.assertRaises(TypeError, to_long, faux_self, ())
def test_to_str_w_ok(self): def test_to_bytes_w_ok(self):
from BTrees._base import to_str from BTrees._base import to_bytes
faux_self = object() faux_self = object()
conv = to_str(3) conv = to_bytes(3)
self.assertEqual(conv(faux_self, 'abc'), 'abc') self.assertEqual(conv(faux_self, b'abc'), b'abc')
def test_to_str_w_invalid_length(self): def test_to_bytes_w_invalid_length(self):
from BTrees._base import to_str from BTrees._base import to_bytes
faux_self = object() faux_self = object()
conv = to_str(3) conv = to_bytes(3)
self.assertRaises(TypeError, conv, faux_self, 'ab') self.assertRaises(TypeError, conv, faux_self, b'ab')
self.assertRaises(TypeError, conv, faux_self, 'abcd') self.assertRaises(TypeError, conv, faux_self, b'abcd')
def test_MERGE(self): def test_MERGE(self):
from BTrees._base import MERGE from BTrees._base import MERGE
......
...@@ -19,24 +19,28 @@ class fsBucketBase(object): ...@@ -19,24 +19,28 @@ class fsBucketBase(object):
def _makeOne(self, *args, **kw): def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw) return self._getTargetClass()(*args, **kw)
def _makeBytesItems(self):
from .._compat import _ascii
return[(_ascii(c*2), _ascii(c*6)) for c in 'abcdef']
def test_toString(self): def test_toString(self):
bucket = self._makeOne([(c*2, c*6) for c in 'abcdef']) bucket = self._makeOne(self._makeBytesItems())
self.assertEqual(bucket.toString(), self.assertEqual(bucket.toString(),
'aabbccddeeffaaaaaabbbbbbccccccddddddeeeeeeffffff') b'aabbccddeeffaaaaaabbbbbbccccccddddddeeeeeeffffff')
def test_fromString(self): def test_fromString(self):
before = self._makeOne([(c*2, c*6) for c in 'abcdef']) before = self._makeOne(self._makeBytesItems())
after = before.fromString(before.toString()) after = before.fromString(before.toString())
self.assertEqual(before.__getstate__(), after.__getstate__()) self.assertEqual(before.__getstate__(), after.__getstate__())
def test_fromString_empty(self): def test_fromString_empty(self):
before = self._makeOne([(c*2, c*6) for c in 'abcdef']) before = self._makeOne(self._makeBytesItems())
after = before.fromString('') after = before.fromString(b'')
self.assertEqual(after.__getstate__(), ((),)) self.assertEqual(after.__getstate__(), ((),))
def test_fromString_invalid(self): def test_fromString_invalid_length(self):
bucket = self._makeOne([(c*2, c*6) for c in 'abcdef']) bucket = self._makeOne(self._makeBytesItems())
self.assertRaises(ValueError, bucket.fromString, 'xxx') self.assertRaises(ValueError, bucket.fromString, b'xxx')
class fsBucketTests(unittest.TestCase, fsBucketBase): class fsBucketTests(unittest.TestCase, fsBucketBase):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment