Merge ~cjwatson/launchpad:remove-enumcol into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 0c5e3b3ea2b9fb1f224945fa95079185cc8ce618
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:remove-enumcol
Merge into: launchpad:master
Diff against target: 192 lines (+40/-50)
2 files modified
lib/lp/services/database/doc/enumcol.txt (+31/-22)
lib/lp/services/database/enumcol.py (+9/-28)
Reviewer Review Type Date Requested Status
Ioana Lasc (community) Approve
Review via email: mp+412134@code.launchpad.net

Commit message

Remove now-unused EnumCol

Description of the change

All call sites now use the Storm-style `DBEnum` instead.

In the process of updating tests for this, I noticed that DBEnum only checks the type of the `enum` parameter when the property is used (thus constructing the associated variable), rather than when the property is constructed; and it also failed to actually do the type check in practice due to a Python 3 porting bug. This seems inconvenient, so I moved the type check earlier and fixed it for Python 3.

To post a comment you must log in.
Revision history for this message
Ioana Lasc (ilasc) wrote :

looks good and nice catch on the type check!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/lib/lp/services/database/doc/enumcol.txt b/lib/lp/services/database/doc/enumcol.txt
index ac5ad80..4685182 100644
--- a/lib/lp/services/database/doc/enumcol.txt
+++ b/lib/lp/services/database/doc/enumcol.txt
@@ -1,9 +1,8 @@
1An example of EnumCol with EnumeratedTypes1An example of DBEnum with EnumeratedTypes
2==========================================2=========================================
33
4EnumCol is a type of column that is used in SQLBase classes where the4DBEnum is a type of column that is used in Storm classes where the database
5database representation is an integer and the code uses an enumerated5representation is an integer and the code uses an enumerated type.
6type.
76
8Firstly we need an example table.7Firstly we need an example table.
98
@@ -20,10 +19,10 @@ Firstly we need an example table.
20 >>> import transaction19 >>> import transaction
21 >>> transaction.commit()20 >>> transaction.commit()
2221
23The enumerated type that is used with the EnumCol must be a22The enumerated type that is used with the DBEnum must be a
24DBEnumeratedType, with items that are instances of DBItem.23DBEnumeratedType, with items that are instances of DBItem.
2524
26Attempting to use a normal enumerated type for an enumcol will25Attempting to use a normal enumerated type for a DBEnum will
27result in an error.26result in an error.
2827
29 >>> from lazr.enum import EnumeratedType, Item, use_template28 >>> from lazr.enum import EnumeratedType, Item, use_template
@@ -32,11 +31,15 @@ result in an error.
32 ... ONE = Item("One")31 ... ONE = Item("One")
33 ... TWO = Item("Two")32 ... TWO = Item("Two")
3433
34 >>> from storm.locals import Int
35 >>> from lp.services.database.constants import DEFAULT35 >>> from lp.services.database.constants import DEFAULT
36 >>> from lp.services.database.enumcol import EnumCol36 >>> from lp.services.database.enumcol import DBEnum
37 >>> from lp.services.database.sqlbase import SQLBase37 >>> from lp.services.database.interfaces import IStore
38 >>> class BadFooTest(SQLBase):38 >>> from lp.services.database.stormbase import StormBase
39 ... foo = EnumCol(enum=PlainFooType, default=DEFAULT)39 >>> class BadFooTest(StormBase):
40 ... __storm_table__ = "footest"
41 ... id = Int(primary=True)
42 ... foo = DBEnum(enum=PlainFooType, default=DEFAULT)
40 Traceback (most recent call last):43 Traceback (most recent call last):
41 ...44 ...
42 TypeError: <EnumeratedType 'PlainFooType'> must be a45 TypeError: <EnumeratedType 'PlainFooType'> must be a
@@ -59,12 +62,15 @@ result in an error.
5962
60The database implementation class then refers to the enumerated type.63The database implementation class then refers to the enumerated type.
6164
62 >>> class FooTest(SQLBase):65 >>> class FooTest(StormBase):
63 ... foo = EnumCol(enum=FooType, default=DEFAULT)66 ... __storm_table__ = "footest"
67 ... id = Int(primary=True)
68 ... foo = DBEnum(enum=FooType, default=DEFAULT)
6469
65Create a row in the table.70Create a row in the table.
6671
67 >>> t = FooTest()72 >>> store = IStore(FooTest)
73 >>> t = store.add(FooTest())
6874
69The value of the foo column has been set to the default defined in the75The value of the foo column has been set to the default defined in the
70database, because we didn't specify one in the constructor.76database, because we didn't specify one in the constructor.
@@ -72,7 +78,7 @@ database, because we didn't specify one in the constructor.
72 >>> t.foo == FooType.ONE78 >>> t.foo == FooType.ONE
73 True79 True
7480
75You cannot use integers or strings as EnumCol values:81You cannot use integers or strings as DBEnum values:
7682
77 >>> t.foo = 283 >>> t.foo = 2
78 Traceback (most recent call last):84 Traceback (most recent call last):
@@ -130,24 +136,27 @@ schemas into one table. This works if you tell the column about both enums:
130136
131Redefine the table with awareness of BarType:137Redefine the table with awareness of BarType:
132138
133 >>> class FooTest(SQLBase):139 >>> class FooTest(StormBase):
134 ... foo = EnumCol(schema=[FooType, BarType], default=DEFAULT)140 ... __storm_table__ = "footest"
141 ... id = Int(primary=True)
142 ... foo = DBEnum(enum=[FooType, BarType], default=DEFAULT)
135143
136We can assign items from either schema to the table;144We can assign items from either schema to the table;
137145
138 >>> t = FooTest()146 >>> t = store.add(FooTest())
139 >>> t.foo = FooType.ONE147 >>> t.foo = FooType.ONE
148 >>> store.flush()
140 >>> t_id = t.id149 >>> t_id = t.id
141 >>> b = FooTest()150 >>> b = store.add(FooTest())
142 >>> b.foo = BarType.THREE151 >>> b.foo = BarType.THREE
152 >>> store.flush()
143 >>> b_id = b.id153 >>> b_id = b.id
144154
145And reading back from the database correctly finds things from the schemas in155And reading back from the database correctly finds things from the schemas in
146the order given.156the order given.
147157
148 >>> from storm.store import AutoReload158 >>> store.autoreload(b)
149 >>> b.foo = AutoReload159 >>> store.autoreload(t)
150 >>> t.foo = AutoReload
151 >>> b.foo == BarType.THREE160 >>> b.foo == BarType.THREE
152 True161 True
153 >>> t.foo == FooType.ONE162 >>> t.foo == FooType.ONE
diff --git a/lib/lp/services/database/enumcol.py b/lib/lp/services/database/enumcol.py
index cf4867c..3da2741 100644
--- a/lib/lp/services/database/enumcol.py
+++ b/lib/lp/services/database/enumcol.py
@@ -1,13 +1,10 @@
1# Copyright 2009-2021 Canonical Ltd. This software is licensed under the1# Copyright 2009-2021 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4import warnings
5
6from lazr.enum import (4from lazr.enum import (
7 DBEnumeratedType,5 DBEnumeratedType,
8 DBItem,6 DBItem,
9 )7 )
10from storm import sqlobject
11from storm.properties import SimpleProperty8from storm.properties import SimpleProperty
12from storm.variables import Variable9from storm.variables import Variable
13from zope.security.proxy import isinstance as zope_isinstance10from zope.security.proxy import isinstance as zope_isinstance
@@ -15,7 +12,6 @@ from zope.security.proxy import isinstance as zope_isinstance
1512
16__all__ = [13__all__ = [
17 'DBEnum',14 'DBEnum',
18 'EnumCol',
19 ]15 ]
2016
2117
@@ -27,7 +23,8 @@ def check_enum_type(enum):
2723
28def check_type(enum):24def check_type(enum):
29 if type(enum) in (list, tuple):25 if type(enum) in (list, tuple):
30 map(check_enum_type, enum)26 for element in enum:
27 check_enum_type(element)
31 else:28 else:
32 check_enum_type(enum)29 check_enum_type(enum)
3330
@@ -37,12 +34,8 @@ class DBEnumVariable(Variable):
37 __slots__ = ("_enum",)34 __slots__ = ("_enum",)
3835
39 def __init__(self, *args, **kwargs):36 def __init__(self, *args, **kwargs):
40 enum = kwargs.pop("enum")37 self._enum = kwargs.pop("enum")
41 if type(enum) not in (list, tuple):38 super().__init__(*args, **kwargs)
42 enum = (enum,)
43 self._enum = enum
44 check_type(self._enum)
45 super(DBEnumVariable, self).__init__(*args, **kwargs)
4639
47 def parse_set(self, value, from_db):40 def parse_set(self, value, from_db):
48 if from_db:41 if from_db:
@@ -71,21 +64,9 @@ class DBEnumVariable(Variable):
71class DBEnum(SimpleProperty):64class DBEnum(SimpleProperty):
72 variable_class = DBEnumVariable65 variable_class = DBEnumVariable
7366
7467 def __init__(self, *args, **kwargs):
75class EnumCol(sqlobject.PropertyAdapter, DBEnum):68 enum = kwargs.pop("enum")
76 def __init__(self, **kw):69 if type(enum) not in (list, tuple):
77 # We want to end up using only the Storm style, not a mix of70 enum = (enum,)
78 # SQLObject and Storm.
79 warnings.warn(
80 "The SQLObject property EnumCol is deprecated; use the Storm "
81 "property DBEnum instead.",
82 DeprecationWarning, stacklevel=2)
83 try:
84 enum = kw.pop('enum')
85 except KeyError:
86 enum = kw.pop('schema')
87 check_type(enum)71 check_type(enum)
88 self._kwargs = {72 super().__init__(enum=enum, *args, **kwargs)
89 'enum': enum,
90 }
91 super().__init__(**kw)

Subscribers

People subscribed via source and target branches

to status/vote changes: