Browse Source

Make from_dict extensible

Some of our consumers define additional members on the context class
that they want included in to_dict and from_dict.  While it is
possible to do this today via overrides of those functions, the
from_dict implementation in particular is a little non-obvious.
This has led to bugs when the base class's to_dict behavior changes.

This change moves the logic around extending the keys recognized by
from_dict into from_dict itself and allows consumers to simply
provide a list of those keys by overriding a class member.

Change-Id: Ib143f8a5c129dbf6711800c4d87c8830a8aa3365
Related-Bug: 1721432
tags/2.19.2^0
Ben Nemec 1 year ago
parent
commit
e75f4c5ad9
2 changed files with 30 additions and 0 deletions
  1. 5
    0
      oslo_context/context.py
  2. 25
    0
      oslo_context/tests/test_context.py

+ 5
- 0
oslo_context/context.py View File

@@ -180,6 +180,9 @@ class RequestContext(object):
180 180
     """
181 181
 
182 182
     user_idt_format = u'{user} {tenant} {domain} {user_domain} {p_domain}'
183
+    # Can be overridden in subclasses to specify extra keys that should be
184
+    # read when constructing a context using from_dict.
185
+    FROM_DICT_EXTRA_KEYS = []
183 186
 
184 187
     @_renamed_kwarg('user', 'user_id')
185 188
     @_renamed_kwarg('tenant', 'project_id')
@@ -391,6 +394,8 @@ class RequestContext(object):
391 394
                           values.get('project_domain_name'))
392 395
         kwargs.setdefault('is_admin_project',
393 396
                           values.get('is_admin_project', True))
397
+        for key in cls.FROM_DICT_EXTRA_KEYS:
398
+            kwargs.setdefault(key, values.get(key))
394 399
         return cls(**kwargs)
395 400
 
396 401
     @classmethod

+ 25
- 0
oslo_context/tests/test_context.py View File

@@ -54,6 +54,24 @@ class Object(object):
54 54
     pass
55 55
 
56 56
 
57
+class TestContext(context.RequestContext):
58
+    """A test context with additional members
59
+
60
+    This is representative of how at least some of our consumers use the
61
+    RequestContext class in their projects.
62
+    """
63
+    FROM_DICT_EXTRA_KEYS = ['foo']
64
+
65
+    def __init__(self, foo=None, **kwargs):
66
+        super(TestContext, self).__init__(**kwargs)
67
+        self.foo = foo
68
+
69
+    def to_dict(self):
70
+        d = super(TestContext, self).to_dict()
71
+        d['foo'] = self.foo
72
+        return d
73
+
74
+
57 75
 class ContextTest(test_base.BaseTestCase):
58 76
 
59 77
     def setUp(self):
@@ -182,6 +200,13 @@ class ContextTest(test_base.BaseTestCase):
182 200
         self.assertFalse(ctx.is_admin)
183 201
         self.assertTrue(ctx.read_only)
184 202
 
203
+    def test_from_dict_extended(self):
204
+        initial = TestContext(foo='bar')
205
+        dct = initial.to_dict()
206
+        final = TestContext.from_dict(dct)
207
+        self.assertEqual('bar', final.foo)
208
+        self.assertEqual(dct, final.to_dict())
209
+
185 210
     def test_is_user_context(self):
186 211
         self.assertFalse(context.is_user_context(None))
187 212
         ctx = context.RequestContext(is_admin=True)

Loading…
Cancel
Save