From: Mike Bayer Date: Wed, 10 Jul 2019 20:12:48 +0000 (-0400) Subject: Add performance improvement for Enum w/ Python 2 enum library X-Git-Tag: rel_1_4_0b1~802^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2cc7308c96f5598ba0aea9a240b9a52629042d07;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Add performance improvement for Enum w/ Python 2 enum library 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 --- diff --git a/doc/build/changelog/unreleased_13/4758.rst b/doc/build/changelog/unreleased_13/4758.rst new file mode 100644 index 0000000000..238c74146c --- /dev/null +++ b/doc/build/changelog/unreleased_13/4758.rst @@ -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. + diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py index 6a520a2d59..af19cb05df 100644 --- a/lib/sqlalchemy/sql/sqltypes.py +++ b/lib/sqlalchemy/sql/sqltypes.py @@ -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 index 0000000000..c2b6f3d08e --- /dev/null +++ b/test/aaa_profiling/test_misc.py @@ -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) diff --git a/test/profiles.txt b/test/profiles.txt index d12b3c4ae0..fe6c4368e9 100644 --- a/test/profiles.txt +++ b/test/profiles.txt @@ -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