summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSVN-Git Migration <python-modules-team@lists.alioth.debian.org>2015-10-08 08:34:01 -0700
committerSVN-Git Migration <python-modules-team@lists.alioth.debian.org>2015-10-08 08:34:01 -0700
commitecfc3ba4143115d03622dc947cd7bbf834f76f23 (patch)
tree53a8a4f6d748a463e95453c37d0eb7cc8ee51636
parent0b68c6d00a2c84a5db13ba5fa304a6eadc4279f2 (diff)
Imported Upstream version 1.3.6
-rw-r--r--LICENSE9
-rw-r--r--MANIFEST.in16
-rw-r--r--PKG-INFO26
-rw-r--r--README.rst6
-rw-r--r--blist.egg-info/PKG-INFO26
-rw-r--r--blist.egg-info/SOURCES.txt38
-rw-r--r--blist.egg-info/not-zip-safe2
-rw-r--r--blist.egg-info/top_level.txt4
-rw-r--r--blist.py8
-rw-r--r--blist/__init__.py10
-rw-r--r--blist/_blist.c (renamed from _blist.c)77
-rw-r--r--blist/_btuple.py (renamed from _btuple.py)12
-rw-r--r--blist/_sorteddict.py (renamed from _sorteddict.py)33
-rw-r--r--blist/_sortedlist.py (renamed from _sortedlist.py)2
-rw-r--r--blist/blist.h (renamed from blist.h)0
-rw-r--r--blist/test/__init__.py (renamed from test/__init__.py)0
-rw-r--r--blist/test/btuple_tests.py (renamed from test/btuple_tests.py)8
-rw-r--r--blist/test/list_tests.py (renamed from test/list_tests.py)82
-rw-r--r--blist/test/mapping_tests.py (renamed from test/mapping_tests.py)3
-rw-r--r--blist/test/seq_tests.py (renamed from test/seq_tests.py)4
-rw-r--r--blist/test/sorteddict_tests.py160
-rw-r--r--blist/test/sortedlist_tests.py (renamed from test/sortedlist_tests.py)9
-rw-r--r--blist/test/test_list.py (renamed from test/test_list.py)4
-rw-r--r--blist/test/test_set.py (renamed from test/test_set.py)5
-rw-r--r--blist/test/test_support.py (renamed from test/test_support.py)2
-rw-r--r--blist/test/unittest.py (renamed from test/unittest.py)8
-rw-r--r--distribute_setup.py481
-rw-r--r--ez_setup.py370
-rwxr-xr-xsetup.py17
-rw-r--r--test/sorteddict_tests.py81
-rwxr-xr-xtest_blist.py7
31 files changed, 815 insertions, 695 deletions
diff --git a/LICENSE b/LICENSE
index b51c68f..ed58843 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,19 +1,22 @@
Copyright 2007-2010 Stutzbach Enterprises, LLC
(daniel@stutzbachenterprises.com)
+Copyright 2012 Google, Inc. All Rights Reserved.
+(stutzbach@google.com)
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
- with the distribution.
+ with the distribution.
3. The name of the author may not be used to endorse or promote
products derived from this software without specific prior written
- permission.
+ permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
diff --git a/MANIFEST.in b/MANIFEST.in
index ae9099c..e41c75c 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,15 +1,15 @@
-include _blist.c
-include blist.py
-include _sorteddict.py
-include _sortedlist.py
-include _btuple.py
+include blist/_blist.c
+include blist/__init__.py
+include blist/_sorteddict.py
+include blist/_sortedlist.py
+include blist/_btuple.py
include setup.py
include test_blist.py
-include test/*.py
+include blist/test/*.py
include README.rst
include LICENSE
include prototype/blist.py
-include distribute_setup.py
+include ez_setup.py
include speed_test.py
include blist.rst
-include blist.h
+include blist/blist.h
diff --git a/PKG-INFO b/PKG-INFO
index a43d00d..2f27158 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: blist
-Version: 1.3.4
+Version: 1.3.6
Summary: a list-like type with better asymptotic performance and similar performance on small lists
Home-page: http://stutzbachenterprises.com/blist/
Author: Stutzbach Enterprises, LLC
@@ -9,7 +9,7 @@ License: BSD
Description: blist: a list-like type with better performance
===============================================
- The ``blist`` is a drop-in replacement for the Python list the provides
+ The ``blist`` is a drop-in replacement for the Python list that provides
better performance when modifying large lists. The blist package also
provides ``sortedlist``, ``sortedset``, ``weaksortedlist``,
``weaksortedset``, ``sorteddict``, and ``btuple`` types.
@@ -19,7 +19,7 @@ Description: blist: a list-like type with better performance
http://stutzbachenterprises.com/blist-doc/
Python's built-in list is a dynamically-sized array; to insert or
- removal an item from the beginning or middle of the list, it has to
+ remove an item from the beginning or middle of the list, it has to
move most of the list in memory, i.e., O(n) operations. The blist
uses a flexible, hybrid array/tree structure and only needs to move a
small portion of items in memory, specifically using O(log n)
@@ -74,7 +74,7 @@ Description: blist: a list-like type with better performance
- sortedlist
- sortedset
- weaksortedlist
- - weaksorteset
+ - weaksortedset
- sorteddict
- btuple
@@ -130,7 +130,7 @@ Description: blist: a list-like type with better performance
- Constructing a btuple from a blist takes O(1) time.
- Taking a slice of a btuple takes O(n) time, where n is the size of
- the original tuple. The size of the slice does not matter.
+ the original tuple. The size of the slice does not matter.
>>> from blist import blist, btuple
>>> x = blist([0]) # x is a blist with one element
@@ -144,7 +144,7 @@ Description: blist: a list-like type with better performance
distribution, the Python header files are also required. In either
case, just run:
- python setup.py install
+ python setup.py install
If you're running Linux and see a bunch of compilation errors from
GCC, you probably do not have the Python header files installed.
@@ -159,7 +159,7 @@ Description: blist: a list-like type with better performance
If you downloaded the source distribution and wish to run the
associated test suite, you can also run:
- python setup.py test
+ python setup.py test
which will verify the correct installation and functioning of the
package. The tests require Python 2.6 or higher.
@@ -178,13 +178,13 @@ Description: blist: a list-like type with better performance
In addition to the tests include in the source distribution, we
perform the following to add extra rigor to our testing process:
- 1. We use a "fuzzer": a program that randomly generates list
- operations, performs them using both the blist and the built-in
- list, and compares the results.
+ 1. We use a "fuzzer": a program that randomly generates list
+ operations, performs them using both the blist and the built-in
+ list, and compares the results.
- 2. We use a modified Python interpreter where we have replaced the
- array-based built-in list with the blist. Then, we run all of
- the regular Python unit tests.
+ 2. We use a modified Python interpreter where we have replaced the
+ array-based built-in list with the blist. Then, we run all of
+ the regular Python unit tests.
Keywords: blist list b+tree btree fast copy-on-write sparse array sortedlist sorted sortedset weak weaksortedlist weaksortedset sorteddict btuple
Platform: UNKNOWN
diff --git a/README.rst b/README.rst
index 32e569c..cc60384 100644
--- a/README.rst
+++ b/README.rst
@@ -1,7 +1,7 @@
blist: a list-like type with better performance
===============================================
-The ``blist`` is a drop-in replacement for the Python list the provides
+The ``blist`` is a drop-in replacement for the Python list that provides
better performance when modifying large lists. The blist package also
provides ``sortedlist``, ``sortedset``, ``weaksortedlist``,
``weaksortedset``, ``sorteddict``, and ``btuple`` types.
@@ -11,7 +11,7 @@ Full documentation is at the link below:
http://stutzbachenterprises.com/blist-doc/
Python's built-in list is a dynamically-sized array; to insert or
-removal an item from the beginning or middle of the list, it has to
+remove an item from the beginning or middle of the list, it has to
move most of the list in memory, i.e., O(n) operations. The blist
uses a flexible, hybrid array/tree structure and only needs to move a
small portion of items in memory, specifically using O(log n)
@@ -66,7 +66,7 @@ The blist package provides other data structures based on the blist:
- sortedlist
- sortedset
- weaksortedlist
-- weaksorteset
+- weaksortedset
- sorteddict
- btuple
diff --git a/blist.egg-info/PKG-INFO b/blist.egg-info/PKG-INFO
index a43d00d..2f27158 100644
--- a/blist.egg-info/PKG-INFO
+++ b/blist.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: blist
-Version: 1.3.4
+Version: 1.3.6
Summary: a list-like type with better asymptotic performance and similar performance on small lists
Home-page: http://stutzbachenterprises.com/blist/
Author: Stutzbach Enterprises, LLC
@@ -9,7 +9,7 @@ License: BSD
Description: blist: a list-like type with better performance
===============================================
- The ``blist`` is a drop-in replacement for the Python list the provides
+ The ``blist`` is a drop-in replacement for the Python list that provides
better performance when modifying large lists. The blist package also
provides ``sortedlist``, ``sortedset``, ``weaksortedlist``,
``weaksortedset``, ``sorteddict``, and ``btuple`` types.
@@ -19,7 +19,7 @@ Description: blist: a list-like type with better performance
http://stutzbachenterprises.com/blist-doc/
Python's built-in list is a dynamically-sized array; to insert or
- removal an item from the beginning or middle of the list, it has to
+ remove an item from the beginning or middle of the list, it has to
move most of the list in memory, i.e., O(n) operations. The blist
uses a flexible, hybrid array/tree structure and only needs to move a
small portion of items in memory, specifically using O(log n)
@@ -74,7 +74,7 @@ Description: blist: a list-like type with better performance
- sortedlist
- sortedset
- weaksortedlist
- - weaksorteset
+ - weaksortedset
- sorteddict
- btuple
@@ -130,7 +130,7 @@ Description: blist: a list-like type with better performance
- Constructing a btuple from a blist takes O(1) time.
- Taking a slice of a btuple takes O(n) time, where n is the size of
- the original tuple. The size of the slice does not matter.
+ the original tuple. The size of the slice does not matter.
>>> from blist import blist, btuple
>>> x = blist([0]) # x is a blist with one element
@@ -144,7 +144,7 @@ Description: blist: a list-like type with better performance
distribution, the Python header files are also required. In either
case, just run:
- python setup.py install
+ python setup.py install
If you're running Linux and see a bunch of compilation errors from
GCC, you probably do not have the Python header files installed.
@@ -159,7 +159,7 @@ Description: blist: a list-like type with better performance
If you downloaded the source distribution and wish to run the
associated test suite, you can also run:
- python setup.py test
+ python setup.py test
which will verify the correct installation and functioning of the
package. The tests require Python 2.6 or higher.
@@ -178,13 +178,13 @@ Description: blist: a list-like type with better performance
In addition to the tests include in the source distribution, we
perform the following to add extra rigor to our testing process:
- 1. We use a "fuzzer": a program that randomly generates list
- operations, performs them using both the blist and the built-in
- list, and compares the results.
+ 1. We use a "fuzzer": a program that randomly generates list
+ operations, performs them using both the blist and the built-in
+ list, and compares the results.
- 2. We use a modified Python interpreter where we have replaced the
- array-based built-in list with the blist. Then, we run all of
- the regular Python unit tests.
+ 2. We use a modified Python interpreter where we have replaced the
+ array-based built-in list with the blist. Then, we run all of
+ the regular Python unit tests.
Keywords: blist list b+tree btree fast copy-on-write sparse array sortedlist sorted sortedset weak weaksortedlist weaksortedset sorteddict btuple
Platform: UNKNOWN
diff --git a/blist.egg-info/SOURCES.txt b/blist.egg-info/SOURCES.txt
index 0dc5784..b2924a3 100644
--- a/blist.egg-info/SOURCES.txt
+++ b/blist.egg-info/SOURCES.txt
@@ -1,30 +1,30 @@
LICENSE
MANIFEST.in
README.rst
-_blist.c
-_btuple.py
-_sorteddict.py
-_sortedlist.py
-blist.h
-blist.py
-distribute_setup.py
+ez_setup.py
setup.py
speed_test.py
test_blist.py
+blist/__init__.py
+blist/_blist.c
+blist/_btuple.py
+blist/_sorteddict.py
+blist/_sortedlist.py
+blist/blist.h
blist.egg-info/PKG-INFO
blist.egg-info/SOURCES.txt
blist.egg-info/dependency_links.txt
blist.egg-info/not-zip-safe
blist.egg-info/top_level.txt
-prototype/blist.py
-test/__init__.py
-test/btuple_tests.py
-test/list_tests.py
-test/mapping_tests.py
-test/seq_tests.py
-test/sorteddict_tests.py
-test/sortedlist_tests.py
-test/test_list.py
-test/test_set.py
-test/test_support.py
-test/unittest.py \ No newline at end of file
+blist/test/__init__.py
+blist/test/btuple_tests.py
+blist/test/list_tests.py
+blist/test/mapping_tests.py
+blist/test/seq_tests.py
+blist/test/sorteddict_tests.py
+blist/test/sortedlist_tests.py
+blist/test/test_list.py
+blist/test/test_set.py
+blist/test/test_support.py
+blist/test/unittest.py
+prototype/blist.py \ No newline at end of file
diff --git a/blist.egg-info/not-zip-safe b/blist.egg-info/not-zip-safe
index d3f5a12..8b13789 100644
--- a/blist.egg-info/not-zip-safe
+++ b/blist.egg-info/not-zip-safe
@@ -1 +1 @@
-
+
diff --git a/blist.egg-info/top_level.txt b/blist.egg-info/top_level.txt
index 48b0d1f..5d8f43a 100644
--- a/blist.egg-info/top_level.txt
+++ b/blist.egg-info/top_level.txt
@@ -1,5 +1 @@
-_btuple
blist
-_sorteddict
-_sortedlist
-_blist
diff --git a/blist.py b/blist.py
deleted file mode 100644
index efe3ff2..0000000
--- a/blist.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from _blist import *
-import collections
-if hasattr(collections, 'MutableSet'): # Only supported in Python 2.6+
- from _sortedlist import sortedlist, sortedset, weaksortedlist, weaksortedset
- from _sorteddict import sorteddict
- from _btuple import btuple
- collections.MutableSequence.register(blist)
-del collections
diff --git a/blist/__init__.py b/blist/__init__.py
new file mode 100644
index 0000000..931aaac
--- /dev/null
+++ b/blist/__init__.py
@@ -0,0 +1,10 @@
+__version__ = '1.3.6'
+from blist._blist import *
+import collections
+if hasattr(collections, 'MutableSet'): # Only supported in Python 2.6+
+ from blist._sortedlist import sortedlist, sortedset, weaksortedlist, weaksortedset
+ from blist._sorteddict import sorteddict
+ from blist._btuple import btuple
+ collections.MutableSequence.register(blist)
+ del _sortedlist, _sorteddict, _btuple
+del collections
diff --git a/_blist.c b/blist/_blist.c
index 7efb681..f7fcb60 100644
--- a/_blist.c
+++ b/blist/_blist.c
@@ -668,7 +668,7 @@ _check_fast_cmp_type(PyObject *ob, int op)
#endif
/************************************************************************
- * Utility functions for removal items from a BList
+ * Utility functions for removal of items from a BList
*
* Objects in Python can execute arbitrary code when garbage
* collected, which means they may make calls that modify the BList
@@ -4693,7 +4693,8 @@ wrap_leaf_array(sortwrapperobject *restrict array,
#define ISLT(X, Y, COMPARE, fast_cmp_type) \
((COMPARE) == NULL ? \
FAST_ISLT(X, Y, fast_cmp_type) : \
- islt(X, Y, COMPARE))
+ islt(((sortwrapperobject *)(X))->key, \
+ ((sortwrapperobject *)(Y))->key, COMPARE))
#else
#define ISLT(X, Y, COMPARE, fast_cmp_type) \
(FAST_ISLT((X), (Y), (fast_cmp_type)))
@@ -5354,12 +5355,18 @@ array_enable_GC(PyBList **leafs, Py_ssize_t num_leafs)
#define MASK (HISTOGRAM_SIZE - 1)
#define NUM_PASSES (((sizeof(unsigned long)*8-1) / BITS_PER_PASS)+1)
+/* The histogram arrays are two-dimension arrays of
+ * [HISTOGRAM_SIZE][NUM_PASSES]. Since that can end up somewhat large (16k on
+ * a 64-bit build), we allocate them on the heap instead of on the stack.
+ */
+typedef Py_ssize_t histogram_array_t[NUM_PASSES];
+
BLIST_LOCAL_INLINE(int)
sort_ulong(sortwrapperobject *restrict sortarray, Py_ssize_t n)
{
sortwrapperobject *restrict scratch, *from, *to, *tmp;
- Py_ssize_t histograms[HISTOGRAM_SIZE][NUM_PASSES];
Py_ssize_t i, j, sums[NUM_PASSES], count[NUM_PASSES], tsum;
+ histogram_array_t *histograms;
memset(sums, 0, sizeof sums);
memset(count, 0, sizeof count);
@@ -5368,7 +5375,13 @@ sort_ulong(sortwrapperobject *restrict sortarray, Py_ssize_t n)
if (scratch == NULL)
return -1;
- memset(histograms, 0, sizeof histograms);
+ histograms = PyMem_New(histogram_array_t, HISTOGRAM_SIZE);
+ if (histograms == NULL) {
+ PyMem_Free(scratch);
+ return -1;
+ }
+ memset(histograms, 0, sizeof(histogram_array_t) * HISTOGRAM_SIZE);
+
for (i = 0; i < n; i++) {
unsigned long v = sortarray[i].fkey.k_ulong;
for (j = 0; j < NUM_PASSES; j++) {
@@ -5408,6 +5421,7 @@ sort_ulong(sortwrapperobject *restrict sortarray, Py_ssize_t n)
for (i = 0; i < n; i++)
sortarray[i].value = scratch[i].value;
+ PyMem_Free(histograms);
PyMem_Free(scratch);
return 0;
}
@@ -5424,8 +5438,8 @@ BLIST_LOCAL_INLINE(int)
sort_uint64(sortwrapperobject *restrict sortarray, Py_ssize_t n)
{
sortwrapperobject *restrict scratch, *from, *to, *tmp;
- Py_ssize_t histograms[HISTOGRAM_SIZE][NUM_PASSES];
Py_ssize_t i, j, sums[NUM_PASSES], count[NUM_PASSES], tsum;
+ histogram_array_t *histograms;
memset(sums, 0, sizeof sums);
memset(count, 0, sizeof count);
@@ -5434,7 +5448,13 @@ sort_uint64(sortwrapperobject *restrict sortarray, Py_ssize_t n)
if (scratch == NULL)
return -1;
- memset(histograms, 0, sizeof histograms);
+ histograms = PyMem_New(histogram_array_t, HISTOGRAM_SIZE);
+ if (histograms == NULL) {
+ PyMem_Free(scratch);
+ return -1;
+ }
+ memset(histograms, 0, sizeof(histogram_array_t) * HISTOGRAM_SIZE);
+
for (i = 0; i < n; i++) {
PY_UINT64_T v = sortarray[i].fkey.k_uint64;
for (j = 0; j < NUM_PASSES; j++) {
@@ -5472,6 +5492,7 @@ sort_uint64(sortwrapperobject *restrict sortarray, Py_ssize_t n)
for (i = 0; i < n; i++)
sortarray[i].value = scratch[i].value;
+ PyMem_Free(histograms);
PyMem_Free(scratch);
return 0;
}
@@ -5726,7 +5747,7 @@ py_blist_traverse(PyObject *oself, visitproc visit, void *arg)
}
BLIST_PYAPI(int)
-py_blist_clear(PyObject *oself)
+py_blist_tp_clear(PyObject *oself)
{
PyBList *self;
@@ -5965,7 +5986,11 @@ py_blist_ass_subscript(PyObject *oself, PyObject *item, PyObject *value)
ext_mark(self, 0, DIRTY);
+#if PY_MAJOR_VERSION < 3 || PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 2
if (PySlice_GetIndicesEx((PySliceObject*)item, self->n,
+#else
+ if (PySlice_GetIndicesEx(item, self->n,
+#endif
&start, &stop,&step,&slicelength)<0)
return _int(-1);
@@ -6802,6 +6827,27 @@ py_blist_pop(PyBList *self, PyObject *args)
}
BLIST_PYAPI(PyObject *)
+py_blist_clear(PyBList *self)
+{
+ invariants(self, VALID_USER|VALID_RW|VALID_DECREF);
+
+ blist_forget_children(self);
+ self->n = 0;
+ self->leaf = 1;
+ ext_dealloc((PyBListRoot *) self);
+
+ decref_flush();
+ Py_RETURN_NONE;
+}
+
+BLIST_PYAPI(PyObject *)
+py_blist_copy(PyBList *self)
+{
+ invariants(self, VALID_USER);
+ return (PyObject *) _blist(blist_root_copy(self));
+}
+
+BLIST_PYAPI(PyObject *)
py_blist_insert(PyBList *self, PyObject *args)
{
Py_ssize_t i;
@@ -6909,7 +6955,11 @@ py_blist_subscript(PyObject *oself, PyObject *item)
PyBList* result;
PyObject* it;
+#if PY_MAJOR_VERSION < 3 || PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 2
if (PySlice_GetIndicesEx((PySliceObject*)item, self->n,
+#else
+ if (PySlice_GetIndicesEx(item, self->n,
+#endif
&start, &stop,&step,&slicelength)<0) {
return _ob(NULL);
}
@@ -7070,6 +7120,10 @@ PyDoc_STRVAR(reverse_doc,
PyDoc_STRVAR(sort_doc,
"L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;\n\
cmp(x, y) -> -1, 0, 1");
+PyDoc_STRVAR(clear_doc,
+"L.clear() -> None -- remove all items from L");
+PyDoc_STRVAR(copy_doc,
+"L.copy() -> list -- a shallow copy of L");
static PyMethodDef blist_methods[] = {
{"__getitem__", (PyCFunction)py_blist_subscript, METH_O|METH_COEXIST, getitem_doc},
@@ -7084,6 +7138,9 @@ static PyMethodDef blist_methods[] = {
{"pop", (PyCFunction)py_blist_pop, METH_VARARGS, pop_doc},
{"remove", (PyCFunction)py_blist_remove, METH_O, remove_doc},
{"index", (PyCFunction)py_blist_index, METH_VARARGS, index_doc},
+ {"clear", (PyCFunction)py_blist_clear, METH_NOARGS, clear_doc},
+ {"copy", (PyCFunction)py_blist_copy, METH_NOARGS, copy_doc},
+
{"count", (PyCFunction)py_blist_count, METH_O, count_doc},
{"reverse", (PyCFunction)py_blist_reverse, METH_NOARGS, reverse_doc},
{"sort", (PyCFunction)py_blist_sort, METH_VARARGS | METH_KEYWORDS, sort_doc},
@@ -7217,7 +7274,7 @@ PyTypeObject PyBList_Type = {
#ifdef BLIST_IN_PYTHON
"__internal_blist",
#else
- "_blist.__internal_blist",
+ "blist._blist.__internal_blist",
#endif
sizeof(PyBList),
0,
@@ -7264,7 +7321,7 @@ PyTypeObject PyRootBList_Type = {
#ifdef BLIST_IN_PYTHON
"list",
#else
- "_blist.blist",
+ "blist.blist",
#endif
sizeof(PyBListRoot),
0,
@@ -7291,7 +7348,7 @@ PyTypeObject PyRootBList_Type = {
,
blist_doc, /* tp_doc */
py_blist_traverse, /* tp_traverse */
- py_blist_clear, /* tp_clear */
+ py_blist_tp_clear, /* tp_clear */
py_blist_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
py_blist_iter, /* tp_iter */
diff --git a/_btuple.py b/blist/_btuple.py
index 76e1d03..1e409cd 100644
--- a/_btuple.py
+++ b/blist/_btuple.py
@@ -1,4 +1,4 @@
-from _blist import blist
+from blist._blist import blist
from ctypes import c_int
import collections
class btuple(collections.Sequence):
@@ -42,15 +42,9 @@ class btuple(collections.Sequence):
return self._hash
def __add__(self, other):
- rv = self._btuple_or_tuple(other, blist.__add__)
- if rv is NotImplemented:
- raise TypeError
- return rv
+ return self._btuple_or_tuple(other, blist.__add__)
def __radd__(self, other):
- rv = self._btuple_or_tuple(other, blist.__radd__)
- if rv is NotImplemented:
- raise TypeError
- return rv
+ return self._btuple_or_tuple(other, blist.__radd__)
def __contains__(self, item):
return item in self._blist
def __eq__(self, other):
diff --git a/_sorteddict.py b/blist/_sorteddict.py
index 225b806..fcdf7e4 100644
--- a/_sorteddict.py
+++ b/blist/_sorteddict.py
@@ -1,6 +1,6 @@
-from _sortedlist import sortedset
+from blist._sortedlist import sortedset, ReprRecursion
import collections, sys
-from _blist import blist
+from blist._blist import blist
class missingdict(dict):
def __missing__(self, key):
@@ -14,9 +14,9 @@ class KeysView(collections.KeysView, collections.Sequence):
def index(self, key):
return self._mapping._sortedkeys.index(key)
def count(self, key):
- return self._mapping.count(key)
- def _from_iterable(cls, it):
- return sortedset(key=self._mapping._sortedkeys.key)
+ return 1 if key in self else 0
+ def _from_iterable(self, it):
+ return sortedset(it, key=self._mapping._sortedkeys._key)
def bisect_left(self, key):
return self._mapping._sortedkeys.bisect_left(key)
def bisect_right(self, key):
@@ -29,7 +29,7 @@ class ItemsView(collections.ItemsView, collections.Sequence):
keys = self._mapping._sortedkeys[index]
return self._from_iterable((key, self._mapping[key])
for key in keys)
- key = self._mapping.sortedkeys[index]
+ key = self._mapping._sortedkeys[index]
return (key, self._mapping[key])
def index(self, item):
key, value = item
@@ -39,18 +39,19 @@ class ItemsView(collections.ItemsView, collections.Sequence):
raise ValueError
def count(self, item):
return 1 if item in self else 0
- def _from_iterable(cls, it):
- return sortedset(key=lambda item:
- self._mapping._sortedkeys.key(item[0]))
+ def _from_iterable(self, it):
+ keyfunc = self._mapping._sortedkeys._key
+ if keyfunc is None:
+ return sortedset(it)
+ else:
+ return sortedset(it, key=lambda item: keyfunc(item[0]))
class ValuesView(collections.ValuesView, collections.Sequence):
def __getitem__(self, index):
if isinstance(index, slice):
keys = self._mapping._sortedkeys[index]
- rv = sortedset(key=self._mapping._sortedkeys.key)
- rv.update(self._mapping[key] for key in keys)
- return rv
- key = self._mapping.sortedkeys[index]
+ return [self._mapping[key] for key in keys]
+ key = self._mapping._sortedkeys[index]
return self._mapping[key]
class sorteddict(collections.MutableMapping):
@@ -134,7 +135,11 @@ class sorteddict(collections.MutableMapping):
return rv
def __repr__(self):
- return 'sorteddict(%s)' % repr(self._map)
+ with ReprRecursion(self) as r:
+ if r:
+ return 'sorteddict({...})'
+ return ('sorteddict({%s})' %
+ ', '.join('%r: %r' % (k, self._map[k]) for k in self))
def __eq__(self, other):
if not isinstance(other, sorteddict):
diff --git a/_sortedlist.py b/blist/_sortedlist.py
index 762d20b..b34f69e 100644
--- a/_sortedlist.py
+++ b/blist/_sortedlist.py
@@ -1,4 +1,4 @@
-from _blist import blist
+from blist._blist import blist
import collections, bisect, weakref, operator, itertools, sys, threading
try: # pragma: no cover
izip = itertools.izip
diff --git a/blist.h b/blist/blist.h
index 7476fe1..7476fe1 100644
--- a/blist.h
+++ b/blist/blist.h
diff --git a/test/__init__.py b/blist/test/__init__.py
index e69de29..e69de29 100644
--- a/test/__init__.py
+++ b/blist/test/__init__.py
diff --git a/test/btuple_tests.py b/blist/test/btuple_tests.py
index d027ea6..a6ccbb6 100644
--- a/test/btuple_tests.py
+++ b/blist/test/btuple_tests.py
@@ -1,14 +1,12 @@
# Based on Python's tuple_tests.py, licensed under the Python License
# Agreement
-import unittest
import sys
-from . import seq_tests
-import blist
import random
import gc
-from _btuple import btuple
-import gc
+from blist import btuple
+from blist.test import unittest
+from blist.test import seq_tests
class bTupleTest(seq_tests.CommonTest):
type2test = btuple
diff --git a/test/list_tests.py b/blist/test/list_tests.py
index 53976a9..70dbe66 100644
--- a/test/list_tests.py
+++ b/blist/test/list_tests.py
@@ -8,8 +8,9 @@ Tests common to list and UserList.UserList
import sys
import os
-from . import unittest
-from test import test_support, seq_tests
+from blist.test import unittest
+from blist.test import test_support
+from blist.test import seq_tests
from decimal import Decimal
@@ -429,6 +430,47 @@ class CommonTest(seq_tests.CommonTest):
self.assertRaises(TypeError, u.reverse, 42)
+ def test_clear(self):
+ u = self.type2test([2, 3, 4])
+ u.clear()
+ self.assertEqual(u, [])
+
+ u = self.type2test([])
+ u.clear()
+ self.assertEqual(u, [])
+
+ u = self.type2test([])
+ u.append(1)
+ u.clear()
+ u.append(2)
+ self.assertEqual(u, [2])
+
+ self.assertRaises(TypeError, u.clear, None)
+
+ def test_copy(self):
+ u = self.type2test([1, 2, 3])
+ v = u.copy()
+ self.assertEqual(v, [1, 2, 3])
+
+ u = self.type2test([])
+ v = u.copy()
+ self.assertEqual(v, [])
+
+ # test that it's indeed a copy and not a reference
+ u = self.type2test(['a', 'b'])
+ v = u.copy()
+ v.append('i')
+ self.assertEqual(u, ['a', 'b'])
+ self.assertEqual(v, u + self.type2test(['i']))
+
+ # test that it's a shallow, not a deep copy
+ u = self.type2test([1, 2, [3, 4], 5])
+ v = u.copy()
+ self.assertEqual(u, v)
+ self.assertIs(v[3], u[3])
+
+ self.assertRaises(TypeError, u.copy, None)
+
def test_sort(self):
u = self.type2test([1, 0])
u.sort()
@@ -556,3 +598,39 @@ class CommonTest(seq_tests.CommonTest):
def __iter__(self):
return Iter()
self.assertRaises(KeyboardInterrupt, self.type2test, F())
+
+ def test_sort_cmp(self):
+ u = self.type2test([1, 0])
+ u.sort()
+ self.assertEqual(u, [0, 1])
+
+ u = self.type2test([2,1,0,-1,-2])
+ u.sort()
+ self.assertEqual(u, self.type2test([-2,-1,0,1,2]))
+
+ self.assertRaises(TypeError, u.sort, 42, 42)
+
+ if sys.version_info[0] >= 3:
+ return # Python 3 removed the cmp option for sort.
+
+ def revcmp(a, b):
+ return cmp(b, a)
+ u.sort(revcmp)
+ self.assertEqual(u, self.type2test([2,1,0,-1,-2]))
+
+ # The following dumps core in unpatched Python 1.5:
+ def myComparison(x,y):
+ return cmp(x%3, y%7)
+ z = self.type2test(range(12))
+ z.sort(myComparison)
+
+ self.assertRaises(TypeError, z.sort, 2)
+
+ def selfmodifyingComparison(x,y):
+ z.append(1)
+ return cmp(x, y)
+ self.assertRaises(ValueError, z.sort, selfmodifyingComparison)
+
+ self.assertRaises(TypeError, z.sort, lambda x, y: 's')
+
+ self.assertRaises(TypeError, z.sort, 42, 42, 42, 42)
diff --git a/test/mapping_tests.py b/blist/test/mapping_tests.py
index e51756f..d0a8da9 100644
--- a/test/mapping_tests.py
+++ b/blist/test/mapping_tests.py
@@ -1,8 +1,9 @@
# This file taken from Python, licensed under the Python License Agreement
# tests common to dict and UserDict
-import unittest, sys
+import sys
import collections
+from blist.test import unittest
try:
from collections import UserDict # Python 3
except ImportError:
diff --git a/test/seq_tests.py b/blist/test/seq_tests.py
index 3d87126..ba2b619 100644
--- a/test/seq_tests.py
+++ b/blist/test/seq_tests.py
@@ -5,8 +5,8 @@ from __future__ import print_function
Tests common to tuple, list and UserList.UserList
"""
-from . import unittest
-from test import test_support
+from blist.test import test_support
+from blist.test import unittest
import sys
# Various iterables
diff --git a/blist/test/sorteddict_tests.py b/blist/test/sorteddict_tests.py
new file mode 100644
index 0000000..b92033f
--- /dev/null
+++ b/blist/test/sorteddict_tests.py
@@ -0,0 +1,160 @@
+import bisect
+import sys
+import blist
+from blist.test import mapping_tests
+
+def CmpToKey(mycmp):
+ 'Convert a cmp= function into a key= function'
+ class K(object):
+ def __init__(self, obj):
+ self.obj = obj
+ def __lt__(self, other):
+ return mycmp(self.obj, other.obj) == -1
+ return K
+
+class sorteddict_test(mapping_tests.TestHashMappingProtocol):
+ type2test = blist.sorteddict
+
+ def _reference(self):
+ """Return a dictionary of values which are invariant by storage
+ in the object under test."""
+ return {1:2, 3:4, 5:6}
+
+ class Collider(object):
+ def __init__(self, x):
+ self.x = x
+ def __repr__(self):
+ return 'Collider(%r)' % self.x
+ def __eq__(self, other):
+ return self.__class__ == other.__class__ and self.x == other.x
+ def __lt__(self, other):
+ if type(self) != type(other):
+ return NotImplemented
+ return self.x < other.x
+ def __hash__(self):
+ return 42
+
+ def test_repr(self):
+ d = self._empty_mapping()
+ self.assertEqual(repr(d), 'sorteddict({})')
+ d[1] = 2
+ self.assertEqual(repr(d), 'sorteddict({1: 2})')
+ d = self._empty_mapping()
+ d[1] = d
+ self.assertEqual(repr(d), 'sorteddict({1: sorteddict({...})})')
+ d = self._empty_mapping()
+ d[self.Collider(1)] = 1
+ d[self.Collider(2)] = 2
+ self.assertEqual(repr(d),
+ 'sorteddict({Collider(1): 1, Collider(2): 2})')
+ d = self._empty_mapping()
+ d[self.Collider(2)] = 2
+ d[self.Collider(1)] = 1
+ self.assertEqual(repr(d),
+ 'sorteddict({Collider(1): 1, Collider(2): 2})')
+
+ class Exc(Exception): pass
+
+ class BadRepr(object):
+ def __repr__(self):
+ raise Exc()
+
+ d = self._full_mapping({1: BadRepr()})
+ self.assertRaises(Exc, repr, d)
+
+ def test_mutatingiteration(self):
+ pass
+
+ def test_sort(self):
+ u = self.type2test.fromkeys([1, 0])
+ self.assertEqual(list(u.keys()), [0, 1])
+
+ u = self.type2test.fromkeys([2,1,0,-1,-2])
+ self.assertEqual(u, self.type2test.fromkeys([-2,-1,0,1,2]))
+ self.assertEqual(list(u.keys()), [-2,-1,0,1,2])
+
+ a = self.type2test.fromkeys(reversed(list(range(512))))
+ self.assertEqual(list(a.keys()), list(range(512)))
+
+ def revcmp(a, b): # pragma: no cover
+ if a == b:
+ return 0
+ elif a < b:
+ return 1
+ else: # a > b
+ return -1
+ u = self.type2test.fromkeys([2,1,0,-1,-2], key=CmpToKey(revcmp))
+ self.assertEqual(list(u.keys()), [2,1,0,-1,-2])
+
+ # The following dumps core in unpatched Python 1.5:
+ def myComparison(x,y):
+ xmod, ymod = x%3, y%7
+ if xmod == ymod:
+ return 0
+ elif xmod < ymod:
+ return -1
+ else: # xmod > ymod
+ return 1
+
+ self.type2test.fromkeys(list(range(12)), key=CmpToKey(myComparison))
+
+ #def selfmodifyingComparison(x,y):
+ # z[x+y] = None
+ # return cmp(x, y)
+ #z = self.type2test(CmpToKey(selfmodifyingComparison))
+ #self.assertRaises(ValueError, z.update, [(i,i) for i in range(12)])
+
+ self.assertRaises(TypeError, self.type2test.fromkeys, 42, 42, 42, 42)
+
+ def test_view_indexing_without_key(self):
+ self._test_view_indexing(key=None)
+
+ def test_view_indexing_with_key(self):
+ self._test_view_indexing(key=lambda x: -x)
+
+ def _test_view_indexing(self, key):
+ expected_items = [(3, "first"), (7, "second")]
+ if key is not None:
+ u = self.type2test(key, expected_items)
+ expected_items.sort(key=lambda item: key(item[0]))
+ else:
+ u = self.type2test(expected_items)
+ expected_items.sort()
+ expected_keys, expected_values = list(zip(*expected_items))
+
+ if sys.version_info[0] < 3:
+ keys = u.viewkeys()
+ values = u.viewvalues()
+ items = u.viewitems()
+ else:
+ keys = u.keys()
+ values = u.values()
+ items = u.items()
+
+ for i in range(len(expected_items)):
+ self.assertEqual(keys[i], expected_keys[i])
+ self.assertEqual(values[i], expected_values[i])
+ self.assertEqual(items[i], expected_items[i])
+
+ for i in range(-1, len(expected_items)+1):
+ for j in range(-1, len(expected_items)+1):
+ self.assertEqual(keys[i:j], blist.sortedset(expected_keys[i:j]))
+ self.assertEqual(values[i:j], list(expected_values[i:j]))
+ self.assertEqual(items[i:j], blist.sortedset(expected_items[i:j]))
+
+ self.assertEqual(list(reversed(keys)), list(reversed(expected_keys)))
+ for i, key in enumerate(expected_keys):
+ self.assertEqual(keys.index(key), expected_keys.index(key))
+ self.assertEqual(keys.count(key), 1)
+ self.assertEqual(keys.bisect_left(key), i)
+ self.assertEqual(keys.bisect_right(key), i+1)
+ self.assertEqual(keys.count(object()), 0)
+ self.assertRaises(ValueError, keys.index, object())
+
+ for item in expected_items:
+ self.assertEqual(items.index(item), expected_items.index(item))
+ self.assertEqual(items.count(item), 1)
+ self.assertEqual(items.count((7, "foo")), 0)
+ self.assertEqual(items.count((object(), object())), 0)
+ self.assertRaises(ValueError, items.index, (7, "foo"))
+ self.assertRaises(ValueError, items.index, (object(), object()))
diff --git a/test/sortedlist_tests.py b/blist/test/sortedlist_tests.py
index 7618b4d..1cff8b9 100644
--- a/test/sortedlist_tests.py
+++ b/blist/test/sortedlist_tests.py
@@ -1,11 +1,12 @@
# This file based loosely on Python's list_tests.py.
-import unittest, collections, operator
import sys
-from . import list_tests, seq_tests
-import blist
-import random
+import collections, operator
import gc
+import random
+import blist
+from blist.test import unittest
+from blist.test import list_tests, seq_tests
def CmpToKey(mycmp):
'Convert a cmp= function into a key= function'
diff --git a/test/test_list.py b/blist/test/test_list.py
index 51c22e4..060bf79 100644
--- a/test/test_list.py
+++ b/blist/test/test_list.py
@@ -1,6 +1,6 @@
from __future__ import print_function
-from . import unittest
-from test import test_support, list_tests
+from blist.test import unittest
+from blist.test import test_support, list_tests
class ListTest(list_tests.CommonTest):
type2test = list
diff --git a/test/test_set.py b/blist/test/test_set.py
index a27d01e..da78daf 100644
--- a/test/test_set.py
+++ b/blist/test/test_set.py
@@ -2,8 +2,6 @@
from __future__ import print_function
-import unittest
-from . import test_support as support
import gc
import weakref
import operator
@@ -14,6 +12,9 @@ import sys
import warnings
import collections
+from blist.test import unittest
+from blist.test import test_support as support
+
from blist import sortedset as set
class PassThru(Exception):
diff --git a/test/test_support.py b/blist/test/test_support.py
index d632ba4..5d7550d 100644
--- a/test/test_support.py
+++ b/blist/test/test_support.py
@@ -3,7 +3,7 @@
from __future__ import print_function
"""Supporting definitions for the Python regression tests."""
-if __name__ != 'test.test_support':
+if __name__ != 'blist.test.test_support':
raise ImportError('test_support must be imported from the test package')
import sys
diff --git a/test/unittest.py b/blist/test/unittest.py
index 2ff3e2d..46398c1 100644
--- a/test/unittest.py
+++ b/blist/test/unittest.py
@@ -201,6 +201,13 @@ class TestCase:
raise ValueError("no such test method in %s: %s" % \
(self.__class__, methodName))
+ def assertIs(self, expr1, expr2, msg=None):
+ """Just like self.assertTrue(a is b), but with a nicer default message."""
+ if expr1 is not expr2:
+ standardMsg = '%s is not %s' % (safe_repr(expr1),
+ safe_repr(expr2))
+ self.fail(self._formatMessage(msg, standardMsg))
+
def assertIn(self, member, container, msg=None):
"""Just like self.assertTrue(a in b), but with a nicer default message."""
if member not in container:
@@ -252,6 +259,7 @@ class TestCase:
def run(self, result=None):
self.run_(result, False)
+ self.run_(result, False)
try:
self.run_(result, True)
except AttributeError:
diff --git a/distribute_setup.py b/distribute_setup.py
deleted file mode 100644
index 4f7bd08..0000000
--- a/distribute_setup.py
+++ /dev/null
@@ -1,481 +0,0 @@
-#!python
-"""Bootstrap distribute installation
-
-If you want to use setuptools in your package's setup.py, just include this
-file in the same directory with it, and add this to the top of your setup.py::
-
- from distribute_setup import use_setuptools
- use_setuptools()
-
-If you want to require a specific version of setuptools, set a download
-mirror, or use an alternate download directory, you can do so by supplying
-the appropriate options to ``use_setuptools()``.
-
-This file can also be run as a script to install or upgrade setuptools.
-"""
-import os
-import sys
-import time
-import fnmatch
-import tempfile
-import tarfile
-from distutils import log
-
-try:
- from site import USER_SITE
-except ImportError:
- USER_SITE = None
-
-try:
- import subprocess
-
- def _python_cmd(*args):
- args = (sys.executable,) + args
- return subprocess.call(args) == 0
-
-except ImportError:
- # will be used for python 2.3
- def _python_cmd(*args):
- args = (sys.executable,) + args
- # quoting arguments if windows
- if sys.platform == 'win32':
- def quote(arg):
- if ' ' in arg:
- return '"%s"' % arg
- return arg
- args = [quote(arg) for arg in args]
- return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
-
-DEFAULT_VERSION = "0.6.12"
-DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
-SETUPTOOLS_FAKED_VERSION = "0.6c11"
-
-SETUPTOOLS_PKG_INFO = """\
-Metadata-Version: 1.0
-Name: setuptools
-Version: %s
-Summary: xxxx
-Home-page: xxx
-Author: xxx
-Author-email: xxx
-License: xxx
-Description: xxx
-""" % SETUPTOOLS_FAKED_VERSION
-
-
-def _install(tarball):
- # extracting the tarball
- tmpdir = tempfile.mkdtemp()
- log.warn('Extracting in %s', tmpdir)
- old_wd = os.getcwd()
- try:
- os.chdir(tmpdir)
- tar = tarfile.open(tarball)
- _extractall(tar)
- tar.close()
-
- # going in the directory
- subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
- os.chdir(subdir)
- log.warn('Now working in %s', subdir)
-
- # installing
- log.warn('Installing Distribute')
- if not _python_cmd('setup.py', 'install'):
- log.warn('Something went wrong during the installation.')
- log.warn('See the error message above.')
- finally:
- os.chdir(old_wd)
-
-
-def _build_egg(egg, tarball, to_dir):
- # extracting the tarball
- tmpdir = tempfile.mkdtemp()
- log.warn('Extracting in %s', tmpdir)
- old_wd = os.getcwd()
- try:
- os.chdir(tmpdir)
- tar = tarfile.open(tarball)
- _extractall(tar)
- tar.close()
-
- # going in the directory
- subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
- os.chdir(subdir)
- log.warn('Now working in %s', subdir)
-
- # building an egg
- log.warn('Building a Distribute egg in %s', to_dir)
- _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
-
- finally:
- os.chdir(old_wd)
- # returning the result
- log.warn(egg)
- if not os.path.exists(egg):
- raise IOError('Could not build the egg.')
-
-
-def _do_download(version, download_base, to_dir, download_delay):
- egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
- % (version, sys.version_info[0], sys.version_info[1]))
- if not os.path.exists(egg):
- tarball = download_setuptools(version, download_base,
- to_dir, download_delay)
- _build_egg(egg, tarball, to_dir)
- sys.path.insert(0, egg)
- import setuptools
- setuptools.bootstrap_install_from = egg
-
-
-def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
- to_dir=os.curdir, download_delay=15, no_fake=True):
- # making sure we use the absolute path
- to_dir = os.path.abspath(to_dir)
- was_imported = 'pkg_resources' in sys.modules or \
- 'setuptools' in sys.modules
- try:
- try:
- import pkg_resources
- if not hasattr(pkg_resources, '_distribute'):
- if not no_fake:
- _fake_setuptools()
- raise ImportError
- except ImportError:
- return _do_download(version, download_base, to_dir, download_delay)
- try:
- pkg_resources.require("distribute>="+version)
- return
- except pkg_resources.VersionConflict:
- e = sys.exc_info()[1]
- if was_imported:
- sys.stderr.write(
- "The required version of distribute (>=%s) is not available,\n"
- "and can't be installed while this script is running. Please\n"
- "install a more recent version first, using\n"
- "'easy_install -U distribute'."
- "\n\n(Currently using %r)\n" % (version, e.args[0]))
- sys.exit(2)
- else:
- del pkg_resources, sys.modules['pkg_resources'] # reload ok
- return _do_download(version, download_base, to_dir,
- download_delay)
- except pkg_resources.DistributionNotFound:
- return _do_download(version, download_base, to_dir,
- download_delay)
- finally:
- if not no_fake:
- _create_fake_setuptools_pkg_info(to_dir)
-
-def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
- to_dir=os.curdir, delay=15):
- """Download distribute from a specified location and return its filename
-
- `version` should be a valid distribute version number that is available
- as an egg for download under the `download_base` URL (which should end
- with a '/'). `to_dir` is the directory where the egg will be downloaded.
- `delay` is the number of seconds to pause before an actual download
- attempt.
- """
- # making sure we use the absolute path
- to_dir = os.path.abspath(to_dir)
- try:
- from urllib.request import urlopen
- except ImportError:
- from urllib2 import urlopen
- tgz_name = "distribute-%s.tar.gz" % version
- url = download_base + tgz_name
- saveto = os.path.join(to_dir, tgz_name)
- src = dst = None
- if not os.path.exists(saveto): # Avoid repeated downloads
- try:
- log.warn("Downloading %s", url)
- src = urlopen(url)
- # Read/write all in one block, so we don't create a corrupt file
- # if the download is interrupted.
- data = src.read()
- dst = open(saveto, "wb")
- dst.write(data)
- finally:
- if src:
- src.close()
- if dst:
- dst.close()
- return os.path.realpath(saveto)
-
-def _no_sandbox(function):
- def __no_sandbox(*args, **kw):
- try:
- from setuptools.sandbox import DirectorySandbox
- if not hasattr(DirectorySandbox, '_old'):
- def violation(*args):
- pass
- DirectorySandbox._old = DirectorySandbox._violation
- DirectorySandbox._violation = violation
- patched = True
- else:
- patched = False
- except ImportError:
- patched = False
-
- try:
- return function(*args, **kw)
- finally:
- if patched:
- DirectorySandbox._violation = DirectorySandbox._old
- del DirectorySandbox._old
-
- return __no_sandbox
-
-@_no_sandbox
-def _patch_file(path, content):
- """Will backup the file then patch it"""
- existing_content = open(path).read()
- if existing_content == content:
- # already patched
- log.warn('Already patched.')
- return False
- log.warn('Patching...')
- _rename_path(path)
- f = open(path, 'w')
- try:
- f.write(content)
- finally:
- f.close()
- return True
-
-
-def _same_content(path, content):
- return open(path).read() == content
-
-def _rename_path(path):
- new_name = path + '.OLD.%s' % time.time()
- log.warn('Renaming %s into %s', path, new_name)
- os.rename(path, new_name)
- return new_name
-
-@_no_sandbox
-def _remove_flat_installation(placeholder):
- if not os.path.isdir(placeholder):
- log.warn('Unkown installation at %s', placeholder)
- return False
- found = False
- for file in os.listdir(placeholder):
- if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
- found = True
- break
- if not found:
- log.warn('Could not locate setuptools*.egg-info')
- return
-
- log.warn('Removing elements out of the way...')
- pkg_info = os.path.join(placeholder, file)
- if os.path.isdir(pkg_info):
- patched = _patch_egg_dir(pkg_info)
- else:
- patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
-
- if not patched:
- log.warn('%s already patched.', pkg_info)
- return False
- # now let's move the files out of the way
- for element in ('setuptools', 'pkg_resources.py', 'site.py'):
- element = os.path.join(placeholder, element)
- if os.path.exists(element):
- _rename_path(element)
- else:
- log.warn('Could not find the %s element of the '
- 'Setuptools distribution', element)
- return True
-
-
-def _after_install(dist):
- log.warn('After install bootstrap.')
- placeholder = dist.get_command_obj('install').install_purelib
- _create_fake_setuptools_pkg_info(placeholder)
-
-@_no_sandbox
-def _create_fake_setuptools_pkg_info(placeholder):
- if not placeholder or not os.path.exists(placeholder):
- log.warn('Could not find the install location')
- return
- pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
- setuptools_file = 'setuptools-%s-py%s.egg-info' % \
- (SETUPTOOLS_FAKED_VERSION, pyver)
- pkg_info = os.path.join(placeholder, setuptools_file)
- if os.path.exists(pkg_info):
- log.warn('%s already exists', pkg_info)
- return
-
- log.warn('Creating %s', pkg_info)
- f = open(pkg_info, 'w')
- try:
- f.write(SETUPTOOLS_PKG_INFO)
- finally:
- f.close()
-
- pth_file = os.path.join(placeholder, 'setuptools.pth')
- log.warn('Creating %s', pth_file)
- f = open(pth_file, 'w')
- try:
- f.write(os.path.join(os.curdir, setuptools_file))
- finally:
- f.close()
-
-@_no_sandbox
-def _patch_egg_dir(path):
- # let's check if it's already patched
- pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
- if os.path.exists(pkg_info):
- if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
- log.warn('%s already patched.', pkg_info)
- return False
- _rename_path(path)
- os.mkdir(path)
- os.mkdir(os.path.join(path, 'EGG-INFO'))
- pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
- f = open(pkg_info, 'w')
- try:
- f.write(SETUPTOOLS_PKG_INFO)
- finally:
- f.close()
- return True
-
-
-def _before_install():
- log.warn('Before install bootstrap.')
- _fake_setuptools()
-
-
-def _under_prefix(location):
- if 'install' not in sys.argv:
- return True
- args = sys.argv[sys.argv.index('install')+1:]
- for index, arg in enumerate(args):
- for option in ('--root', '--prefix'):
- if arg.startswith('%s=' % option):
- top_dir = arg.split('root=')[-1]
- return location.startswith(top_dir)
- elif arg == option:
- if len(args) > index:
- top_dir = args[index+1]
- return location.startswith(top_dir)
- elif option == '--user' and USER_SITE is not None:
- return location.startswith(USER_SITE)
- return True
-
-
-def _fake_setuptools():
- log.warn('Scanning installed packages')
- try:
- import pkg_resources
- except ImportError:
- # we're cool
- log.warn('Setuptools or Distribute does not seem to be installed.')
- return
- ws = pkg_resources.working_set
- try:
- setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
- replacement=False))
- except TypeError:
- # old distribute API
- setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
-
- if setuptools_dist is None:
- log.warn('No setuptools distribution found')
- return
- # detecting if it was already faked
- setuptools_location = setuptools_dist.location
- log.warn('Setuptools installation detected at %s', setuptools_location)
-
- # if --root or --preix was provided, and if
- # setuptools is not located in them, we don't patch it
- if not _under_prefix(setuptools_location):
- log.warn('Not patching, --root or --prefix is installing Distribute'
- ' in another location')
- return
-
- # let's see if its an egg
- if not setuptools_location.endswith('.egg'):
- log.warn('Non-egg installation')
- res = _remove_flat_installation(setuptools_location)
- if not res:
- return
- else:
- log.warn('Egg installation')
- pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
- if (os.path.exists(pkg_info) and
- _same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
- log.warn('Already patched.')
- return
- log.warn('Patching...')
- # let's create a fake egg replacing setuptools one
- res = _patch_egg_dir(setuptools_location)
- if not res:
- return
- log.warn('Patched done.')
- _relaunch()
-
-
-def _relaunch():
- log.warn('Relaunching...')
- # we have to relaunch the process
- args = [sys.executable] + sys.argv
- sys.exit(subprocess.call(args))
-
-
-def _extractall(self, path=".", members=None):
- """Extract all members from the archive to the current working
- directory and set owner, modification time and permissions on
- directories afterwards. `path' specifies a different directory
- to extract to. `members' is optional and must be a subset of the
- list returned by getmembers().
- """
- import copy
- import operator
- from tarfile import ExtractError
- directories = []
-
- if members is None:
- members = self
-
- for tarinfo in members:
- if tarinfo.isdir():
- # Extract directories with a safe mode.
- directories.append(tarinfo)
- tarinfo = copy.copy(tarinfo)
- tarinfo.mode = 448 # decimal for oct 0700
- self.extract(tarinfo, path)
-
- # Reverse sort directories.
- if sys.version_info < (2, 4):
- def sorter(dir1, dir2):
- return cmp(dir1.name, dir2.name)
- directories.sort(sorter)
- directories.reverse()
- else:
- directories.sort(key=operator.attrgetter('name'), reverse=True)
-
- # Set correct owner, mtime and filemode on directories.
- for tarinfo in directories:
- dirpath = os.path.join(path, tarinfo.name)
- try:
- self.chown(tarinfo, dirpath)
- self.utime(tarinfo, dirpath)
- self.chmod(tarinfo, dirpath)
- except ExtractError:
- e = sys.exc_info()[1]
- if self.errorlevel > 1:
- raise
- else:
- self._dbg(1, "tarfile: %s" % e)
-
-
-def main(argv, version=DEFAULT_VERSION):
- """Install or upgrade setuptools and EasyInstall"""
- tarball = download_setuptools()
- _install(tarball)
-
-
-if __name__ == '__main__':
- main(sys.argv[1:])
diff --git a/ez_setup.py b/ez_setup.py
new file mode 100644
index 0000000..b02f3f1
--- /dev/null
+++ b/ez_setup.py
@@ -0,0 +1,370 @@
+#!python
+"""Bootstrap setuptools installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+ from ez_setup import use_setuptools
+ use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import os
+import shutil
+import sys
+import tempfile
+import tarfile
+import optparse
+import subprocess
+import platform
+
+from distutils import log
+
+try:
+ from site import USER_SITE
+except ImportError:
+ USER_SITE = None
+
+DEFAULT_VERSION = "1.1.6"
+DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/"
+
+def _python_cmd(*args):
+ args = (sys.executable,) + args
+ return subprocess.call(args) == 0
+
+def _check_call_py24(cmd, *args, **kwargs):
+ res = subprocess.call(cmd, *args, **kwargs)
+ class CalledProcessError(Exception):
+ pass
+ if not res == 0:
+ msg = "Command '%s' return non-zero exit status %d" % (cmd, res)
+ raise CalledProcessError(msg)
+vars(subprocess).setdefault('check_call', _check_call_py24)
+
+def _install(tarball, install_args=()):
+ # extracting the tarball
+ tmpdir = tempfile.mkdtemp()
+ log.warn('Extracting in %s', tmpdir)
+ old_wd = os.getcwd()
+ try:
+ os.chdir(tmpdir)
+ tar = tarfile.open(tarball)
+ _extractall(tar)
+ tar.close()
+
+ # going in the directory
+ subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+ os.chdir(subdir)
+ log.warn('Now working in %s', subdir)
+
+ # installing
+ log.warn('Installing Setuptools')
+ if not _python_cmd('setup.py', 'install', *install_args):
+ log.warn('Something went wrong during the installation.')
+ log.warn('See the error message above.')
+ # exitcode will be 2
+ return 2
+ finally:
+ os.chdir(old_wd)
+ shutil.rmtree(tmpdir)
+
+
+def _build_egg(egg, tarball, to_dir):
+ # extracting the tarball
+ tmpdir = tempfile.mkdtemp()
+ log.warn('Extracting in %s', tmpdir)
+ old_wd = os.getcwd()
+ try:
+ os.chdir(tmpdir)
+ tar = tarfile.open(tarball)
+ _extractall(tar)
+ tar.close()
+
+ # going in the directory
+ subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+ os.chdir(subdir)
+ log.warn('Now working in %s', subdir)
+
+ # building an egg
+ log.warn('Building a Setuptools egg in %s', to_dir)
+ _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
+
+ finally:
+ os.chdir(old_wd)
+ shutil.rmtree(tmpdir)
+ # returning the result
+ log.warn(egg)
+ if not os.path.exists(egg):
+ raise IOError('Could not build the egg.')
+
+
+def _do_download(version, download_base, to_dir, download_delay):
+ egg = os.path.join(to_dir, 'setuptools-%s-py%d.%d.egg'
+ % (version, sys.version_info[0], sys.version_info[1]))
+ if not os.path.exists(egg):
+ tarball = download_setuptools(version, download_base,
+ to_dir, download_delay)
+ _build_egg(egg, tarball, to_dir)
+ sys.path.insert(0, egg)
+
+ # Remove previously-imported pkg_resources if present (see
+ # https://bitbucket.org/pypa/setuptools/pull-request/7/ for details).
+ if 'pkg_resources' in sys.modules:
+ del sys.modules['pkg_resources']
+
+ import setuptools
+ setuptools.bootstrap_install_from = egg
+
+
+def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+ to_dir=os.curdir, download_delay=15):
+ # making sure we use the absolute path
+ to_dir = os.path.abspath(to_dir)
+ was_imported = 'pkg_resources' in sys.modules or \
+ 'setuptools' in sys.modules
+ try:
+ import pkg_resources
+ except ImportError:
+ return _do_download(version, download_base, to_dir, download_delay)
+ try:
+ pkg_resources.require("setuptools>=" + version)
+ return
+ except pkg_resources.VersionConflict:
+ e = sys.exc_info()[1]
+ if was_imported:
+ sys.stderr.write(
+ "The required version of setuptools (>=%s) is not available,\n"
+ "and can't be installed while this script is running. Please\n"
+ "install a more recent version first, using\n"
+ "'easy_install -U setuptools'."
+ "\n\n(Currently using %r)\n" % (version, e.args[0]))
+ sys.exit(2)
+ else:
+ del pkg_resources, sys.modules['pkg_resources'] # reload ok
+ return _do_download(version, download_base, to_dir,
+ download_delay)
+ except pkg_resources.DistributionNotFound:
+ return _do_download(version, download_base, to_dir,
+ download_delay)
+
+def download_file_powershell(url, target):
+ """
+ Download the file at url to target using Powershell (which will validate
+ trust). Raise an exception if the command cannot complete.
+ """
+ target = os.path.abspath(target)
+ cmd = [
+ 'powershell',
+ '-Command',
+ "(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)" % vars(),
+ ]
+ subprocess.check_call(cmd)
+
+def has_powershell():
+ if platform.system() != 'Windows':
+ return False
+ cmd = ['powershell', '-Command', 'echo test']
+ devnull = open(os.path.devnull, 'wb')
+ try:
+ try:
+ subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
+ except:
+ return False
+ finally:
+ devnull.close()
+ return True
+
+download_file_powershell.viable = has_powershell
+
+def download_file_curl(url, target):
+ cmd = ['curl', url, '--silent', '--output', target]
+ subprocess.check_call(cmd)
+
+def has_curl():
+ cmd = ['curl', '--version']
+ devnull = open(os.path.devnull, 'wb')
+ try:
+ try:
+ subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
+ except:
+ return False
+ finally:
+ devnull.close()
+ return True
+
+download_file_curl.viable = has_curl
+
+def download_file_wget(url, target):
+ cmd = ['wget', url, '--quiet', '--output-document', target]
+ subprocess.check_call(cmd)
+
+def has_wget():
+ cmd = ['wget', '--version']
+ devnull = open(os.path.devnull, 'wb')
+ try:
+ try:
+ subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
+ except:
+ return False
+ finally:
+ devnull.close()
+ return True
+
+download_file_wget.viable = has_wget
+
+def download_file_insecure(url, target):
+ """
+ Use Python to download the file, even though it cannot authenticate the
+ connection.
+ """
+ try:
+ from urllib.request import urlopen
+ except ImportError:
+ from urllib2 import urlopen
+ src = dst = None
+ try:
+ src = urlopen(url)
+ # Read/write all in one block, so we don't create a corrupt file
+ # if the download is interrupted.
+ data = src.read()
+ dst = open(target, "wb")
+ dst.write(data)
+ finally:
+ if src:
+ src.close()
+ if dst:
+ dst.close()
+
+download_file_insecure.viable = lambda: True
+
+def get_best_downloader():
+ downloaders = [
+ download_file_powershell,
+ download_file_curl,
+ download_file_wget,
+ download_file_insecure,
+ ]
+
+ for dl in downloaders:
+ if dl.viable():
+ return dl
+
+def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+ to_dir=os.curdir, delay=15,
+ downloader_factory=get_best_downloader):
+ """Download setuptools from a specified location and return its filename
+
+ `version` should be a valid setuptools version number that is available
+ as an egg for download under the `download_base` URL (which should end
+ with a '/'). `to_dir` is the directory where the egg will be downloaded.
+ `delay` is the number of seconds to pause before an actual download
+ attempt.
+
+ ``downloader_factory`` should be a function taking no arguments and
+ returning a function for downloading a URL to a target.
+ """
+ # making sure we use the absolute path
+ to_dir = os.path.abspath(to_dir)
+ tgz_name = "setuptools-%s.tar.gz" % version
+ url = download_base + tgz_name
+ saveto = os.path.join(to_dir, tgz_name)
+ if not os.path.exists(saveto): # Avoid repeated downloads
+ log.warn("Downloading %s", url)
+ downloader = downloader_factory()
+ downloader(url, saveto)
+ return os.path.realpath(saveto)
+
+
+def _extractall(self, path=".", members=None):
+ """Extract all members from the archive to the current working
+ directory and set owner, modification time and permissions on
+ directories afterwards. `path' specifies a different directory
+ to extract to. `members' is optional and must be a subset of the
+ list returned by getmembers().
+ """
+ import copy
+ import operator
+ from tarfile import ExtractError
+ directories = []
+
+ if members is None:
+ members = self
+
+ for tarinfo in members:
+ if tarinfo.isdir():
+ # Extract directories with a safe mode.
+ directories.append(tarinfo)
+ tarinfo = copy.copy(tarinfo)
+ tarinfo.mode = 448 # decimal for oct 0700
+ self.extract(tarinfo, path)
+
+ # Reverse sort directories.
+ if sys.version_info < (2, 4):
+ def sorter(dir1, dir2):
+ return cmp(dir1.name, dir2.name)
+ directories.sort(sorter)
+ directories.reverse()
+ else:
+ directories.sort(key=operator.attrgetter('name'), reverse=True)
+
+ # Set correct owner, mtime and filemode on directories.
+ for tarinfo in directories:
+ dirpath = os.path.join(path, tarinfo.name)
+ try:
+ self.chown(tarinfo, dirpath)
+ self.utime(tarinfo, dirpath)
+ self.chmod(tarinfo, dirpath)
+ except ExtractError:
+ e = sys.exc_info()[1]
+ if self.errorlevel > 1:
+ raise
+ else:
+ self._dbg(1, "tarfile: %s" % e)
+
+
+def _build_install_args(options):
+ """
+ Build the arguments to 'python setup.py install' on the setuptools package
+ """
+ install_args = []
+ if options.user_install:
+ if sys.version_info < (2, 6):
+ log.warn("--user requires Python 2.6 or later")
+ raise SystemExit(1)
+ install_args.append('--user')
+ return install_args
+
+def _parse_args():
+ """
+ Parse the command line for options
+ """
+ parser = optparse.OptionParser()
+ parser.add_option(
+ '--user', dest='user_install', action='store_true', default=False,
+ help='install in user site package (requires Python 2.6 or later)')
+ parser.add_option(
+ '--download-base', dest='download_base', metavar="URL",
+ default=DEFAULT_URL,
+ help='alternative URL from where to download the setuptools package')
+ parser.add_option(
+ '--insecure', dest='downloader_factory', action='store_const',
+ const=lambda: download_file_insecure, default=get_best_downloader,
+ help='Use internal, non-validating downloader'
+ )
+ options, args = parser.parse_args()
+ # positional arguments are ignored
+ return options
+
+def main(version=DEFAULT_VERSION):
+ """Install or upgrade setuptools and EasyInstall"""
+ options = _parse_args()
+ tarball = download_setuptools(download_base=options.download_base,
+ downloader_factory=options.downloader_factory)
+ return _install(tarball, _build_install_args(options))
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/setup.py b/setup.py
index 22751ff..5f1ff5d 100755
--- a/setup.py
+++ b/setup.py
@@ -1,10 +1,12 @@
#!/usr/bin/env python
+import re
import sys
-import distribute_setup
-distribute_setup.use_setuptools()
+import ez_setup
+ez_setup.use_setuptools()
from setuptools import setup, Extension
+
define_macros = []
import ctypes
@@ -14,19 +16,24 @@ if ctypes.sizeof(ctypes.c_double) == 8:
if iv.contents.value == 0x433fff0102030405:
define_macros.append(('BLIST_FLOAT_RADIX_SORT', 1))
+with open('blist/__init__.py') as f:
+ line = f.readline()
+ match = re.search(r'= *[\'"](.*)[\'"]', line)
+ version = match.group(1)
+
setup(name='blist',
- version='1.3.4',
+ version=version,
description='a list-like type with better asymptotic performance and similar performance on small lists',
author='Stutzbach Enterprises, LLC',
author_email='daniel@stutzbachenterprises.com',
url='http://stutzbachenterprises.com/blist/',
license = "BSD",
keywords = "blist list b+tree btree fast copy-on-write sparse array sortedlist sorted sortedset weak weaksortedlist weaksortedset sorteddict btuple",
- ext_modules=[Extension('_blist', ['_blist.c'],
+ ext_modules=[Extension('blist._blist', ['blist/_blist.c'],
define_macros=define_macros,
)],
+ packages=['blist'],
provides = ['blist'],
- py_modules=['blist', '_sortedlist', '_sorteddict', '_btuple'],
test_suite = "test_blist.test_suite",
zip_safe = False, # zips are broken on cygwin for C extension modules
classifiers = [
diff --git a/test/sorteddict_tests.py b/test/sorteddict_tests.py
deleted file mode 100644
index c81436b..0000000
--- a/test/sorteddict_tests.py
+++ /dev/null
@@ -1,81 +0,0 @@
-from . import mapping_tests
-import blist
-
-def CmpToKey(mycmp):
- 'Convert a cmp= function into a key= function'
- class K(object):
- def __init__(self, obj):
- self.obj = obj
- def __lt__(self, other):
- return mycmp(self.obj, other.obj) == -1
- return K
-
-class sorteddict_test(mapping_tests.TestHashMappingProtocol):
- type2test = blist.sorteddict
-
- def _reference(self):
- """Return a dictionary of values which are invariant by storage
- in the object under test."""
- return {1:2, 3:4, 5:6}
-
- def test_repr(self):
- d = self._empty_mapping()
- self.assertEqual(repr(d), 'sorteddict({})')
- d[1] = 2
- self.assertEqual(repr(d), 'sorteddict({1: 2})')
- d = self._empty_mapping()
- d[1] = d
- self.assertEqual(repr(d), 'sorteddict({1: sorteddict({...})})')
-
- class Exc(Exception): pass
-
- class BadRepr(object):
- def __repr__(self):
- raise Exc()
-
- d = self._full_mapping({1: BadRepr()})
- self.assertRaises(Exc, repr, d)
-
- def test_mutatingiteration(self):
- pass
-
- def test_sort(self):
- u = self.type2test.fromkeys([1, 0])
- self.assertEqual(list(u.keys()), [0, 1])
-
- u = self.type2test.fromkeys([2,1,0,-1,-2])
- self.assertEqual(u, self.type2test.fromkeys([-2,-1,0,1,2]))
- self.assertEqual(list(u.keys()), [-2,-1,0,1,2])
-
- a = self.type2test.fromkeys(reversed(list(range(512))))
- self.assertEqual(list(a.keys()), list(range(512)))
-
- def revcmp(a, b): # pragma: no cover
- if a == b:
- return 0
- elif a < b:
- return 1
- else: # a > b
- return -1
- u = self.type2test.fromkeys([2,1,0,-1,-2], key=CmpToKey(revcmp))
- self.assertEqual(list(u.keys()), [2,1,0,-1,-2])
-
- # The following dumps core in unpatched Python 1.5:
- def myComparison(x,y):
- xmod, ymod = x%3, y%7
- if xmod == ymod:
- return 0
- elif xmod < ymod:
- return -1
- else: # xmod > ymod
- return 1
-
- self.type2test.fromkeys(list(range(12)), key=CmpToKey(myComparison))
-
- #def selfmodifyingComparison(x,y):
- # z[x+y] = None
- # return cmp(x, y)
- #z = self.type2test(CmpToKey(selfmodifyingComparison))
- #self.assertRaises(ValueError, z.update, [(i,i) for i in range(12)])
-
- self.assertRaises(TypeError, self.type2test.fromkeys, 42, 42, 42, 42)
diff --git a/test_blist.py b/test_blist.py
index 9a32a42..2028913 100755
--- a/test_blist.py
+++ b/test_blist.py
@@ -37,10 +37,11 @@ import sys
import os
import unittest, operator
-import blist, pickle, _blist
+import blist, pickle
+from blist import _blist
#BList = list
-from test import test_support, list_tests, sortedlist_tests, btuple_tests
-from test import sorteddict_tests, test_set
+from blist.test import test_support, list_tests, sortedlist_tests, btuple_tests
+from blist.test import sorteddict_tests, test_set
limit = _blist._limit
n = 512//8 * limit