summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2020-05-22 00:06:06 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2020-05-23 00:05:13 -0400
commitfcbd03e48af50e301e0dcbade75765a4d3e4999f (patch)
tree8a30c4b9811bb217430c6bafea040753729c80ae /test
parentd45657a2f5b880dc22dda2d1eb1687af5234a470 (diff)
downloadsqlalchemy-fcbd03e48af50e301e0dcbade75765a4d3e4999f.tar.gz
Add immutabledict C code
Start trying to convert fundamental objects to C as we now rely on a fairly small core of things, and 1.4 is having problems with complexity added being slower than the performance gains we are trying to build in. immutabledict here does seem to bench as twice as fast as the Python one, see below. However, it does not appear to be used prominently enough to make any dent in the performance tests. at the very least it may provide us some more lift-and-copy code for more C extensions. import timeit from sqlalchemy.util._collections import not_immutabledict, immutabledict def run(dict_cls): for i in range(1000000): d1 = dict_cls({"x": 5, "y": 4}) d2 = d1.union({"x": 17, "new key": "some other value"}, None) assert list(d2) == ["x", "y", "new key"] print( timeit.timeit( "run(d)", "from __main__ import run, not_immutabledict as d", number=1 ) ) print( timeit.timeit( "run(d)", "from __main__ import run, immutabledict as d", number=1 ) ) output: python: 1.8799766399897635 C code: 0.8880784640205093 Change-Id: I29e7104dc21dcc7cdf895bf274003af2e219bf6d
Diffstat (limited to 'test')
-rw-r--r--test/base/test_utils.py93
-rw-r--r--test/engine/test_execute.py5
-rw-r--r--test/orm/test_options.py6
-rw-r--r--test/orm/test_update_delete.py3
-rw-r--r--test/sql/test_metadata.py1
5 files changed, 100 insertions, 8 deletions
diff --git a/test/base/test_utils.py b/test/base/test_utils.py
index a6d777c61..bba0cc16c 100644
--- a/test/base/test_utils.py
+++ b/test/base/test_utils.py
@@ -141,11 +141,100 @@ class OrderedSetTest(fixtures.TestBase):
eq_(o.union(iter([3, 4, 6])), util.OrderedSet([2, 3, 4, 5, 6]))
-class FrozenDictTest(fixtures.TestBase):
+class ImmutableDictTest(fixtures.TestBase):
+ def test_union_no_change(self):
+ d = util.immutabledict({1: 2, 3: 4})
+
+ d2 = d.union({})
+
+ is_(d2, d)
+
+ def test_merge_with_no_change(self):
+ d = util.immutabledict({1: 2, 3: 4})
+
+ d2 = d.merge_with({}, None)
+
+ eq_(d2, {1: 2, 3: 4})
+ is_(d2, d)
+
+ def test_merge_with_dicts(self):
+ d = util.immutabledict({1: 2, 3: 4})
+
+ d2 = d.merge_with({3: 5, 7: 12}, {9: 18, 15: 25})
+
+ eq_(d, {1: 2, 3: 4})
+ eq_(d2, {1: 2, 3: 5, 7: 12, 9: 18, 15: 25})
+ assert isinstance(d2, util.immutabledict)
+
+ d3 = d.merge_with({17: 42})
+
+ eq_(d3, {1: 2, 3: 4, 17: 42})
+
+ def test_merge_with_tuples(self):
+ d = util.immutabledict({1: 2, 3: 4})
+
+ d2 = d.merge_with([(3, 5), (7, 12)], [(9, 18), (15, 25)])
+
+ eq_(d, {1: 2, 3: 4})
+ eq_(d2, {1: 2, 3: 5, 7: 12, 9: 18, 15: 25})
+
+ def test_union_dictionary(self):
+ d = util.immutabledict({1: 2, 3: 4})
+
+ d2 = d.union({3: 5, 7: 12})
+ assert isinstance(d2, util.immutabledict)
+
+ eq_(d, {1: 2, 3: 4})
+ eq_(d2, {1: 2, 3: 5, 7: 12})
+
+ def test_union_tuples(self):
+ d = util.immutabledict({1: 2, 3: 4})
+
+ d2 = d.union([(3, 5), (7, 12)])
+
+ eq_(d, {1: 2, 3: 4})
+ eq_(d2, {1: 2, 3: 5, 7: 12})
+
+ def test_keys(self):
+ d = util.immutabledict({1: 2, 3: 4})
+
+ eq_(set(d.keys()), {1, 3})
+
+ def test_values(self):
+ d = util.immutabledict({1: 2, 3: 4})
+
+ eq_(set(d.values()), {2, 4})
+
+ def test_items(self):
+ d = util.immutabledict({1: 2, 3: 4})
+
+ eq_(set(d.items()), {(1, 2), (3, 4)})
+
+ def test_contains(self):
+ d = util.immutabledict({1: 2, 3: 4})
+
+ assert 1 in d
+ assert "foo" not in d
+
+ def test_rich_compare(self):
+ d = util.immutabledict({1: 2, 3: 4})
+ d2 = util.immutabledict({1: 2, 3: 4})
+ d3 = util.immutabledict({5: 12})
+ d4 = {5: 12}
+
+ eq_(d, d2)
+ ne_(d, d3)
+ ne_(d, d4)
+ eq_(d3, d4)
+
def test_serialize(self):
d = util.immutabledict({1: 2, 3: 4})
for loads, dumps in picklers():
- print(loads(dumps(d)))
+ d2 = loads(dumps(d))
+
+ eq_(d2, {1: 2, 3: 4})
+
+ assert isinstance(d2, util.immutabledict)
class MemoizedAttrTest(fixtures.TestBase):
diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py
index 285dd2acf..fcf31b826 100644
--- a/test/engine/test_execute.py
+++ b/test/engine/test_execute.py
@@ -49,6 +49,7 @@ from sqlalchemy.testing.schema import Column
from sqlalchemy.testing.schema import Table
from sqlalchemy.testing.util import gc_collect
from sqlalchemy.testing.util import picklers
+from sqlalchemy.util import collections_abc
class SomeException(Exception):
@@ -1414,13 +1415,13 @@ class EngineEventsTest(fixtures.TestBase):
conn, clauseelement, multiparams, params, execution_options
):
assert isinstance(multiparams, (list, tuple))
- assert isinstance(params, dict)
+ assert isinstance(params, collections_abc.Mapping)
def after_execute(
conn, clauseelement, multiparams, params, result, execution_options
):
assert isinstance(multiparams, (list, tuple))
- assert isinstance(params, dict)
+ assert isinstance(params, collections_abc.Mapping)
e1 = testing_engine(config.db_url)
event.listen(e1, "before_execute", before_execute)
diff --git a/test/orm/test_options.py b/test/orm/test_options.py
index 00e1d232b..34fee8470 100644
--- a/test/orm/test_options.py
+++ b/test/orm/test_options.py
@@ -77,7 +77,7 @@ class PathTest(object):
return orm_util.PathRegistry.coerce(self._make_path(path))
def _assert_path_result(self, opt, q, paths):
- q._attributes = q._attributes.copy()
+ q._attributes = dict(q._attributes)
attr = {}
if isinstance(opt, strategy_options._UnboundLoad):
@@ -1569,7 +1569,7 @@ class SubOptionsTest(PathTest, QueryTest):
def _assert_opts(self, q, sub_opt, non_sub_opts):
existing_attributes = q._attributes
- q._attributes = q._attributes.copy()
+ q._attributes = dict(q._attributes)
attr_a = {}
for val in sub_opt._to_bind:
@@ -1580,7 +1580,7 @@ class SubOptionsTest(PathTest, QueryTest):
False,
)
- q._attributes = existing_attributes.copy()
+ q._attributes = dict(existing_attributes)
attr_b = {}
diff --git a/test/orm/test_update_delete.py b/test/orm/test_update_delete.py
index bec4ecd92..9017ca84e 100644
--- a/test/orm/test_update_delete.py
+++ b/test/orm/test_update_delete.py
@@ -23,6 +23,7 @@ from sqlalchemy.testing import fixtures
from sqlalchemy.testing import mock
from sqlalchemy.testing.schema import Column
from sqlalchemy.testing.schema import Table
+from sqlalchemy.util import collections_abc
class UpdateDeleteTest(fixtures.MappedTest):
@@ -681,7 +682,7 @@ class UpdateDeleteTest(fixtures.MappedTest):
q.filter(User.id == 15).update({"name": "foob", "id": 123})
# Confirm that parameters are a dict instead of tuple or list
params = exec_.mock_calls[0][1][0]._values
- assert isinstance(params, dict)
+ assert isinstance(params, collections_abc.Mapping)
def test_update_preserve_parameter_order(self):
User = self.classes.User
diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py
index 07f5b80db..a75aee6e9 100644
--- a/test/sql/test_metadata.py
+++ b/test/sql/test_metadata.py
@@ -178,6 +178,7 @@ class MetaDataTest(fixtures.TestBase, ComparesTables):
eq_(len(metadata.tables), 0)
def test_metadata_tables_immutable(self):
+ # this use case was added due to #1917.
metadata = MetaData()
Table("t1", metadata, Column("x", Integer))