2

を発射に失敗した私は、私は与えられたグループに同じユーザーを追加しないことを保証しようとしています私のNDBモデルバリデータは、ここで

from google.appengine.ext import ndb 
from mainsite.rainbow.models.CFCSocialUser import CFCSocialUser 


class CFCSocialGroup(ndb.Model): 

    def remove_duplicate(self, value): 
     raise Exception("Duplicate user detected") 

    name = ndb.StringProperty(required=True) 
    created_on = ndb.DateTimeProperty(auto_now_add=True) 
    updated_on = ndb.DateTimeProperty(auto_now=True) 
    created_by = ndb.StructuredProperty(CFCSocialUser) 
    members = ndb.StructuredProperty(CFCSocialUser, repeated=True, validator=remove_duplicate) 

    @staticmethod 
    def create_group(name): 
     """Create a new group""" 
     group = CFCSocialGroup(name=name) 
     return group 

    def add_member(self, social_user): 
     """Add a member to the local group""" 
     self.members.append(social_user) 

です。だから私はメンバのプロパティ(StructuredProperty)の値を検証しようとしています。

私のテストでは、テストが例外を発生させるために失敗した

from unittest import TestCase 
from mainsite.rainbow.models.CFCSocialGroup import CFCSocialGroup 
from tests.test_CFCSocialUser import create_user 
from tests.cfcsocialtests.testbase import CFCTestBase_NDB 
from nose.tools import * 
from nose.plugins.attrib import attr 


class TestCFCSocialGroup(CFCTestBase_NDB): 
    @attr("CRUD") 
    @raises(Exception) 
    def test_duplicate_addition(self): 
     """Test to detect duplicate users in groups""" 
     user1 = create_user() 
     user2 = create_user() 
     group = CFCSocialGroup.create_group('Group1') 
     group.add_member(user1) 
     group.add_member(user2) 

です。ここで

は、デバッグコード

FAILED (errors=1) 
MacBook-Pro:tests vinay$ nosetests -v test_CFCSocialGroup.py 
Test to detect duplicate users in groups ... FAIL 

====================================================================== 
FAIL: Test to detect duplicate users in groups 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "/Library/Python/2.7/site-packages/nose/tools/nontrivial.py", line 67, in newfunc 
    raise AssertionError(message) 
AssertionError: test_duplicate_addition() did not raise Exception 
-------------------- >> begin captured logging << -------------------- 
root: DEBUG: Using threading.local 
root: WARNING: No ssl package found. urlfetch will not be able to validate SSL certificates. 
root: DEBUG: all_pending: add <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending> 
root: DEBUG: nowevent: _help_tasklet_along 
root: DEBUG: Sending None to initial generator put(context.py:787) 
root: DEBUG: all_pending: add <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); pending> 
root: DEBUG: AutoBatcher(_memcache_set_tasklet): creating new queue for ('set', 32, '', None) 
root: DEBUG: initial generator put(context.py:787) yielded <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); pending> 
root: DEBUG: <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787) suspended generator put(context.py:810); pending> is now blocked waiting for <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); pending> 
root: DEBUG: idler: _on_idle 
root: DEBUG: AutoBatcher(_memcache_set_tasklet): 1 items 
root: DEBUG: all_pending: add <Future 10d0ec250 created by run_queue(context.py:185) for tasklet _memcache_set_tasklet(context.py:1111); pending> 
root: DEBUG: nowevent: _help_tasklet_along 
root: DEBUG: Sending None to initial generator _memcache_set_tasklet(context.py:1111) 
root: DEBUG: initial generator _memcache_set_tasklet(context.py:1111) yielded <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x10d0ec490> 
root: DEBUG: idler: _on_idle 
root: DEBUG: idler _on_idle removed 
root: DEBUG: rpc: memcache.Set 
root: DEBUG: Sending {'NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw': 1} to suspended generator _memcache_set_tasklet(context.py:1122) 
root: DEBUG: all_pending: success: remove <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); result True> 
root: DEBUG: suspended generator _memcache_set_tasklet(context.py:1122) returned None 
root: DEBUG: all_pending: success: remove <Future 10d0ec250 created by run_queue(context.py:185) for tasklet _memcache_set_tasklet(context.py:1111); result None> 
root: DEBUG: nowevent: _on_future_completion 
root: DEBUG: <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending> is no longer blocked waiting for <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); result True> 
root: DEBUG: Sending True to suspended generator put(context.py:810) 
root: DEBUG: all_pending: add <Future 10d0ec510 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='[email protected]', username='Vinay Joseph'), None); pending> 
root: DEBUG: AutoBatcher(_put_tasklet): creating new queue for None 
root: DEBUG: suspended generator put(context.py:810) yielded <Future 10d0ec510 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='[email protected]', username='Vinay Joseph'), None); pending> 
root: DEBUG: <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787) suspended generator put(context.py:824); pending> is now blocked waiting for <Future 10d0ec510 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='[email protected]', username='Vinay Joseph'), None); pending> 
root: DEBUG: nowevent: _finished_callback 
root: DEBUG: idler: _on_idle 
root: DEBUG: AutoBatcher(_put_tasklet): 1 items 
root: DEBUG: all_pending: add <Future 10d0ec610 created by run_queue(context.py:185) for tasklet _put_tasklet(context.py:348); pending> 
root: DEBUG: nowevent: _help_tasklet_along 
root: DEBUG: Sending None to initial generator _put_tasklet(context.py:348) 
root: DEBUG: initial generator _put_tasklet(context.py:348) yielded <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x10d0ec890> 
root: DEBUG: idler: _on_idle 
root: DEBUG: idler _on_idle removed 
root: DEBUG: rpc: datastore_v3.Put 
root: DEBUG: Sending [Key('CFCSocialUser', 'Vinay Joseph')] to suspended generator _put_tasklet(context.py:358) 
root: DEBUG: all_pending: success: remove <Future 10d0ec510 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='[email protected]', username='Vinay Joseph'), None); result Key('CFCSocialUser', 'Vinay Joseph')> 
root: DEBUG: suspended generator _put_tasklet(context.py:358) returned None 
root: DEBUG: all_pending: success: remove <Future 10d0ec610 created by run_queue(context.py:185) for tasklet _put_tasklet(context.py:348); result None> 
root: DEBUG: nowevent: _on_future_completion 
root: DEBUG: <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending> is no longer blocked waiting for <Future 10d0ec510 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='[email protected]', username='Vinay Joseph'), None); result Key('CFCSocialUser', 'Vinay Joseph')> 
root: DEBUG: Sending Key('CFCSocialUser', 'Vinay Joseph') to suspended generator put(context.py:824) 
root: DEBUG: all_pending: add <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); pending> 
root: DEBUG: AutoBatcher(_memcache_del_tasklet): creating new queue for (0, '', None) 
root: DEBUG: suspended generator put(context.py:824) yielded <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); pending> 
root: DEBUG: <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787) suspended generator put(context.py:833); pending> is now blocked waiting for <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); pending> 
root: DEBUG: nowevent: _finished_callback 
root: DEBUG: idler: _on_idle 
root: DEBUG: AutoBatcher(_memcache_del_tasklet): 1 items 
root: DEBUG: all_pending: add <Future 10d0ec850 created by run_queue(context.py:185) for tasklet _memcache_del_tasklet(context.py:1130); pending> 
root: DEBUG: nowevent: _help_tasklet_along 
root: DEBUG: Sending None to initial generator _memcache_del_tasklet(context.py:1130) 
root: DEBUG: initial generator _memcache_del_tasklet(context.py:1130) yielded <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x10d0ec210> 
root: DEBUG: idler: _on_idle 
root: DEBUG: idler _on_idle removed 
root: DEBUG: rpc: memcache.Delete 
root: DEBUG: Sending [2] to suspended generator _memcache_del_tasklet(context.py:1141) 
root: DEBUG: all_pending: success: remove <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); result 2> 
root: DEBUG: suspended generator _memcache_del_tasklet(context.py:1141) returned None 
root: DEBUG: all_pending: success: remove <Future 10d0ec850 created by run_queue(context.py:185) for tasklet _memcache_del_tasklet(context.py:1130); result None> 
root: DEBUG: nowevent: _on_future_completion 
root: DEBUG: <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending> is no longer blocked waiting for <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); result 2> 
root: DEBUG: Sending 2 to suspended generator put(context.py:833) 
root: DEBUG: suspended generator put(context.py:833) returned Key('CFCSocialUser', 'Vinay Joseph') 
root: DEBUG: all_pending: success: remove <Future 10d0d2e90 created by _put_async(model.py:3467) for tasklet put(context.py:787); result Key('CFCSocialUser', 'Vinay Joseph')> 
root: DEBUG: all_pending: add <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending> 
root: DEBUG: nowevent: _finished_callback 
root: DEBUG: nowevent: _help_tasklet_along 
root: DEBUG: Sending None to initial generator put(context.py:787) 
root: DEBUG: all_pending: add <Future 10d0ec990 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); pending> 
root: DEBUG: AutoBatcher(_memcache_set_tasklet): creating new queue for ('set', 32, '', None) 
root: DEBUG: initial generator put(context.py:787) yielded <Future 10d0ec990 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); pending> 
root: DEBUG: <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787) suspended generator put(context.py:810); pending> is now blocked waiting for <Future 10d0ec990 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); pending> 
root: DEBUG: idler: _on_idle 
root: DEBUG: AutoBatcher(_memcache_set_tasklet): 1 items 
root: DEBUG: all_pending: add <Future 10d0ecd10 created by run_queue(context.py:185) for tasklet _memcache_set_tasklet(context.py:1111); pending> 
root: DEBUG: nowevent: _help_tasklet_along 
root: DEBUG: Sending None to initial generator _memcache_set_tasklet(context.py:1111) 
root: DEBUG: initial generator _memcache_set_tasklet(context.py:1111) yielded <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x10d0ecf50> 
root: DEBUG: idler: _on_idle 
root: DEBUG: idler _on_idle removed 
root: DEBUG: rpc: memcache.Set 
root: DEBUG: Sending {'NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw': 1} to suspended generator _memcache_set_tasklet(context.py:1122) 
root: DEBUG: all_pending: success: remove <Future 10d0ec990 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); result True> 
root: DEBUG: suspended generator _memcache_set_tasklet(context.py:1122) returned None 
root: DEBUG: all_pending: success: remove <Future 10d0ecd10 created by run_queue(context.py:185) for tasklet _memcache_set_tasklet(context.py:1111); result None> 
root: DEBUG: nowevent: _on_future_completion 
root: DEBUG: <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending> is no longer blocked waiting for <Future 10d0ec990 created by add(context.py:211) for AutoBatcher(_memcache_set_tasklet).add(('NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw', 0), ('set', 32, '', None)); result True> 
root: DEBUG: Sending True to suspended generator put(context.py:810) 
root: DEBUG: all_pending: add <Future 10d0ecfd0 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='[email protected]', username='Vinay Joseph'), None); pending> 
root: DEBUG: AutoBatcher(_put_tasklet): creating new queue for None 
root: DEBUG: suspended generator put(context.py:810) yielded <Future 10d0ecfd0 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='[email protected]', username='Vinay Joseph'), None); pending> 
root: DEBUG: <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787) suspended generator put(context.py:824); pending> is now blocked waiting for <Future 10d0ecfd0 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='[email protected]', username='Vinay Joseph'), None); pending> 
root: DEBUG: nowevent: _finished_callback 
root: DEBUG: idler: _on_idle 
root: DEBUG: AutoBatcher(_put_tasklet): 1 items 
root: DEBUG: all_pending: add <Future 10d132110 created by run_queue(context.py:185) for tasklet _put_tasklet(context.py:348); pending> 
root: DEBUG: nowevent: _help_tasklet_along 
root: DEBUG: Sending None to initial generator _put_tasklet(context.py:348) 
root: DEBUG: initial generator _put_tasklet(context.py:348) yielded <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x10d132450> 
root: DEBUG: idler: _on_idle 
root: DEBUG: idler _on_idle removed 
root: DEBUG: rpc: datastore_v3.Put 
root: DEBUG: Sending [Key('CFCSocialUser', 'Vinay Joseph')] to suspended generator _put_tasklet(context.py:358) 
root: DEBUG: all_pending: success: remove <Future 10d0ecfd0 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='[email protected]', username='Vinay Joseph'), None); result Key('CFCSocialUser', 'Vinay Joseph')> 
root: DEBUG: suspended generator _put_tasklet(context.py:358) returned None 
root: DEBUG: all_pending: success: remove <Future 10d132110 created by run_queue(context.py:185) for tasklet _put_tasklet(context.py:348); result None> 
root: DEBUG: nowevent: _on_future_completion 
root: DEBUG: <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending> is no longer blocked waiting for <Future 10d0ecfd0 created by add(context.py:211) for AutoBatcher(_put_tasklet).add(CFCSocialUser(key=Key('CFCSocialUser', 'Vinay Joseph'), date_of_birth=datetime.date(1900, 3, 2), email='[email protected]', username='Vinay Joseph'), None); result Key('CFCSocialUser', 'Vinay Joseph')> 
root: DEBUG: Sending Key('CFCSocialUser', 'Vinay Joseph') to suspended generator put(context.py:824) 
root: DEBUG: all_pending: add <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); pending> 
root: DEBUG: AutoBatcher(_memcache_del_tasklet): creating new queue for (0, '', None) 
root: DEBUG: suspended generator put(context.py:824) yielded <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); pending> 
root: DEBUG: <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787) suspended generator put(context.py:833); pending> is now blocked waiting for <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); pending> 
root: DEBUG: nowevent: _finished_callback 
root: DEBUG: idler: _on_idle 
root: DEBUG: AutoBatcher(_memcache_del_tasklet): 1 items 
root: DEBUG: all_pending: add <Future 10d0eca10 created by run_queue(context.py:185) for tasklet _memcache_del_tasklet(context.py:1130); pending> 
root: DEBUG: nowevent: _help_tasklet_along 
root: DEBUG: Sending None to initial generator _memcache_del_tasklet(context.py:1130) 
root: DEBUG: initial generator _memcache_del_tasklet(context.py:1130) yielded <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x10d0ece10> 
root: DEBUG: idler: _on_idle 
root: DEBUG: idler _on_idle removed 
root: DEBUG: rpc: memcache.Delete 
root: DEBUG: Sending [2] to suspended generator _memcache_del_tasklet(context.py:1141) 
root: DEBUG: all_pending: success: remove <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); result 2> 
root: DEBUG: suspended generator _memcache_del_tasklet(context.py:1141) returned None 
root: DEBUG: all_pending: success: remove <Future 10d0eca10 created by run_queue(context.py:185) for tasklet _memcache_del_tasklet(context.py:1130); result None> 
root: DEBUG: nowevent: _on_future_completion 
root: DEBUG: <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787); pending> is no longer blocked waiting for <Future 10b0ae1d0 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:agx0ZXN0YmVkLXRlc3RyHwsSDUNGQ1NvY2lhbFVzZXIiDFZpbmF5IEpvc2VwaAw, (0, '', None)); result 2> 
root: DEBUG: Sending 2 to suspended generator put(context.py:833) 
root: DEBUG: suspended generator put(context.py:833) returned Key('CFCSocialUser', 'Vinay Joseph') 
root: DEBUG: all_pending: success: remove <Future 10d0ec150 created by _put_async(model.py:3467) for tasklet put(context.py:787); result Key('CFCSocialUser', 'Vinay Joseph')> 
--------------------- >> end captured logging << --------------------- 

---------------------------------------------------------------------- 
Ran 1 test in 0.035s 

FAILED (failures=1) 

答えて

1

models.pyにこのコードを与えられます。

class Member(ndb.Model): 

    name = ndb.StringProperty() 


def remove_duplicates(prop, value): 
    raise Exception('Duplicate') 


class Club1(ndb.Model): 

    members = ndb.StructuredProperty(Member, repeated=True, validator=remove_duplicates) 

私は

Club1インスタンスを作成

> m = Member(name='Alice')

Memberインスタンスを作成することができますこのMemberインスタンスは、検証をトリガー:しかし

> c1 = models.Club1(members=[m]) 
Traceback (most recent call last): 
    <snip> 
    File "models.py", line 60, in remove_duplicates 
    raise Exception('Duplicate') 
Exception: Duplicate 

、空Club1インスタンスを作成し、Memberを追加することはしません。これは効果的にあなたのテストケースです。

> c1 = models.Club1() 
> c1.members.append(m) 
> c1.put() 
Key('Club1', 6682831673622528) 

我々はndb.StructuredPropertyをサブクラス化し、サブクラスで検証を置くことができます:MemberClub2インスタンスを作成

class MembersStructuredProperty(ndb.StructuredProperty): 

    def _validate(self, value): 
     raise Exception('Duplicate') 


class Club2(ndb.Model): 

    members = MembersStructuredProperty(Member, repeated=True) 

は、以前のように検証をトリガー:

> c2 = models.Club2(members=[m]) 
Traceback (most recent call last): 
    <snip> 
    File "models.py", line 56, in _validate 
    raise Exception('Duplicate') 
Exception: Duplicate 

そして今、そうしますMemberを追加してデータストアに書き込もうとしています:

> c2 = models.Club2() 
> c2.members.append(m) 
> c2.put() 
Traceback (most recent call last): 
    <snip> 
    File "models.py", line 56, in _validate 
    raise Exception('Duplicate') 
Exception: Duplicate 

したがって、ndb.StructuredPropertyをサブクラス化すると、テストに合格するはずです。

ndbのプロパティ検証がこのように動作する理由はわかりませんが、おそらくそれはバグか、少なくともドキュメント化されていない動作です。

EDIT:

@DanCornilescuはコメントで観察するように、これは多分に関連したSDKでknown bug

+0

です:「繰り返しプロパティを更新する場合、あなたはそれを新しいリストを割り当てることができますいずれか既存のリストを変更する」(https://cloud.google.com/appengine/docs/python/ndb/entity-property-reference#repeated) –

+0

私は彼らが私たちにすべてをサブクラス化させたいと思うと思います。 –

+0

ちょうど好奇心の理由から、授業の外で妥当性検証メソッドを移動したのはなぜですか? –

関連する問題