]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Add performance improvement for Enum w/ Python 2 enum library
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 10 Jul 2019 20:12:48 +0000 (16:12 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 11 Jul 2019 04:19:34 +0000 (00:19 -0400)
Adjusted the initialization for :class:`.Enum` to minimize how often it
invokes the ``.__members__`` attribute of a given PEP-435 enumeration
object, to suit the case where this attribute is expensive to invoke, as is
the case for some popular third party enumeration libraries.

Fixes: #4758
Change-Id: Iffeb854c67393bdcb288944fc357a074e20e1325

doc/build/changelog/unreleased_13/4758.rst [new file with mode: 0644]
lib/sqlalchemy/sql/sqltypes.py
test/aaa_profiling/test_misc.py [new file with mode: 0644]
test/profiles.txt

diff --git a/doc/build/changelog/unreleased_13/4758.rst b/doc/build/changelog/unreleased_13/4758.rst
new file mode 100644 (file)
index 0000000..238c741
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: bug, sql
+    :tickets: 4758
+
+    Adjusted the initialization for :class:`.Enum` to minimize how often it
+    invokes the ``.__members__`` attribute of a given PEP-435 enumeration
+    object, to suit the case where this attribute is expensive to invoke, as is
+    the case for some popular third party enumeration libraries.
+
index 6a520a2d59d22799d0e710bee94c57e96cfa2ea7..af19cb05dffb956a215cedbbf5e20a978fb1f608 100644 (file)
@@ -1424,14 +1424,12 @@ class Enum(Emulated, String, SchemaType):
 
         if len(enums) == 1 and hasattr(enums[0], "__members__"):
             self.enum_class = enums[0]
+            members = self.enum_class.__members__
             if self.values_callable:
                 values = self.values_callable(self.enum_class)
             else:
-                values = list(self.enum_class.__members__)
-            objects = [
-                self.enum_class.__members__[k]
-                for k in self.enum_class.__members__
-            ]
+                values = list(members)
+            objects = [members[k] for k in members]
             return values, objects
         else:
             self.enum_class = None
diff --git a/test/aaa_profiling/test_misc.py b/test/aaa_profiling/test_misc.py
new file mode 100644 (file)
index 0000000..c2b6f3d
--- /dev/null
@@ -0,0 +1,37 @@
+from sqlalchemy import Enum
+from sqlalchemy.testing import fixtures
+from sqlalchemy.testing import profiling
+from sqlalchemy.util import classproperty
+
+
+class EnumTest(fixtures.TestBase):
+    __requires__ = ("cpython",)
+
+    def setup(self):
+        class SomeEnum(object):
+            # Implements PEP 435 in the minimal fashion needed by SQLAlchemy
+
+            _members = {}
+
+            @classproperty
+            def __members__(cls):
+                """simulate a very expensive ``__members__`` getter"""
+                for i in range(10):
+                    x = {}
+                    x.update({k: v for k, v in cls._members.items()}.copy())
+                return x.copy()
+
+            def __init__(self, name, value):
+                self.name = name
+                self.value = value
+                self._members[name] = self
+                setattr(self.__class__, name, self)
+
+        for i in range(400):
+            SomeEnum("some%d" % i, i)
+
+        self.SomeEnum = SomeEnum
+
+    @profiling.function_call_count()
+    def test_create_enum_from_pep_435_w_expensive_members(self):
+        Enum(self.SomeEnum)
index d12b3c4ae068bcc6eead58265197af70af7b4dcd..fe6c4368e9698ae6bd21f960acb638c46f81e3ba 100644 (file)
@@ -136,6 +136,11 @@ test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_postgre
 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_sqlite_pysqlite_dbapiunicode_cextensions 158
 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 158
 
+# TEST: test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_members
+
+test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_members 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 4638
+test.aaa_profiling.test_misc.EnumTest.test_create_enum_from_pep_435_w_expensive_members 3.7_sqlite_pysqlite_dbapiunicode_cextensions 942
+
 # TEST: test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation
 
 test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_bundle_w_annotation 2.7_mysql_mysqldb_dbapiunicode_cextensions 51975