def generate_table_schema_interface(ti): '''!+DO_NOT_REORDER_USER_APPLIED_INTERFACES def get_domain_interfaces(domain_model): """Return the domain bases for an interface as well as a filtered implements only list (base interfaces removed). Note that for 2nd level (mapped) domain classes i.e. those that inherit from another domain class e.g. Event(Doc), Office(Group), OfficeMember(GroupMembership), an IIModelInterface-providing I*TableSchema interface had already been created (for base class) and assigned to the super class--and that interface will match as one of the domain_base interfaces here. """ domain_bases = [] domain_implements = [] for iface in interface.implementedBy(domain_model): if IIModelInterface.providedBy(iface): domain_bases.append(iface) else: domain_implements.append(iface) domain_bases = tuple(domain_bases) or (IAlchemistContent,) return domain_bases, domain_implements bases, implements = get_domain_interfaces(ti.domain_model) ''' # derived_table_schema: # - ALWAYS dynamically generated # - directlyProvides IIModelInterface (by virtue of IAlchemistContent) type_key = naming.polymorphic_identity(ti.domain_model) # use the class's mapper select table as input for the transformation table_schema_interface_name = naming.table_schema_interface_name(type_key) domain_table = utils.get_local_table(ti.domain_model) derived_table_schema = transmute( domain_table, annotation=ti.descriptor_model, interface_name=table_schema_interface_name, __module__=INTERFACE_MODULE.__name__, #_generated_by="bungeni.alchemist.catalyst.generate_table_schema_interface" #bases=bases) bases=(IAlchemistContent,)) # apply, register on type_info, set on module interface.classImplements(ti.domain_model, derived_table_schema) utils.inisetattr(ti, "derived_table_schema", derived_table_schema) setattr(INTERFACE_MODULE, table_schema_interface_name, derived_table_schema) log.info("generate_table_schema_interface: %s", derived_table_schema) # defensive sanity check - that derived_table_schema is precisely the FIRST # resolving IIModelInterface-providing interface implemented by domain_model # !+ this failing does not necessarily mean an incorrectness for iface in interface.implementedBy(ti.domain_model): if IIModelInterface.providedBy(iface): assert iface is derived_table_schema, (ti.domain_model, iface, id(iface), derived_table_schema, id(derived_table_schema)) break '''!+DO_NOT_REORDER_USER_APPLIED_INTERFACES
def testSA2ZS(self): iusers = transmute(users) self.assertEqual(tuple(schema.getFieldNamesInOrder(iusers)), ("user_id", "user_name")) fields = dict(schema.getFieldsInOrder(iusers)) # assert types and constraints self.assertTrue(isinstance(fields["user_id"], schema.Int)) self.assertTrue(fields["user_id"].required) self.assertTrue(isinstance(fields["user_name"], schema.TextLine)) self.assertEqual(fields["user_name"].max_length, 40) self.assertEqual(fields["user_name"].default, u"hello world")
def testInheritance( self ): class IUserBase( IContained ): def hello( ): pass iusers = transmute( users, bases=(IUserBase,) ) class bar( object ): interface.implements( iusers ) containers( IUserContainer ) b = bar() self.assertTrue( IUserBase.providedBy( b ) ) fields = schema.getFieldsInOrder( iusers ) for i in fields: print i
def GenerateDomainInterface( ctx, interface_name=None ): # when called from zcml, most likely we'll get a class not an instance # if it is a class go ahead and call instantiate it if isinstance( ctx.descriptor, type): ctx.descriptor = ctx.descriptor() # if the interface module is none, then use the nearest one to the domain class if ctx.interface_module is None: ispec = ctx.domain_model.__module__.rsplit('.',1)[0]+'.interfaces' ctx.interface_module = resolve( ispec ) # interface for domain model if not interface_name: interface_name = "I%s"%( ctx.domain_model.__name__) msg = ( ctx.domain_model.__name__, ctx.interface_module.__name__, interface_name ) if ctx.echo: ctx.logger.debug("%s: generated interface %s.%s"%msg ) bases, implements = getDomainInterfaces( ctx.domain_model ) # use the class's mapper select table as input for the transformation domain_mapper = orm.class_mapper( ctx.domain_model ) # 0.4 and 0.5 compatibility, 0.5 has the table as local_table (select_table) is none lazy gen? domain_table = getattr( domain_mapper, 'local_table', domain_mapper.select_table ) domain_interface = sa2zs.transmute( domain_table, annotation=ctx.descriptor, interface_name = interface_name, __module__ = ctx.interface_module.__name__, bases=bases ) implements.insert(0, domain_interface) # if we're replacing an existing interface, make sure the new # interface implements it old = getattr( ctx.interface_module, interface_name, None) if old is not None: implements.append(old) interface.classImplementsOnly( ctx.domain_model, *implements ) setattr( ctx.interface_module, interface_name, domain_interface ) ctx.domain_interface = domain_interface
def testSA2ZS( self ): metadata = rdb.DynamicMetaData("principals") users = rdb.Table('users', metadata, rdb.Column('user_id', rdb.Integer, rdb.Sequence('user_id_seq', optional=True), primary_key = True), rdb.Column('user_name', rdb.String(40), default=u'hello world' ) ) iusers = transmute( users ) self.assertEqual( tuple(schema.getFieldNamesInOrder( iusers )), ('user_id', 'user_name') ) fields = dict( schema.getFieldsInOrder(iusers) ) # assert types and constraints self.assertTrue( isinstance(fields['user_id'], schema.Int ) ) self.assertTrue( fields['user_id'].required ) self.assertTrue( isinstance(fields['user_name'], schema.TextLine ) ) self.assertEqual( fields['user_name'].max_length, 40 ) self.assertEqual( fields['user_name'].default, u'hello world')
def testInvariants(self): def validate(ob): return False iusers = transmute(users, invariants=[validate]) self.assertTrue(validate in iusers.getTaggedValue("invariants"))
dict( name="email", label = "Email Address", table_column=True ), dict( name="phone_number", label = "Home Phone Number"), ] ) AddressAnnotation = TableAnnotation( "Address", columns = [ dict( name="address_id", omit = True ), dict( name="address_1", label = "address line 1"), dict( name="address_2", label = "address line 2"), ] ) from vocabulary import StateVocabulary IAddressTable = transmute( schema.AddressTable, AddressAnnotation, properties = {'state':zschema.Choice( title=u"state", vocabulary=StateVocabulary() ) }, __module__="Products.orgperson.interfaces" ) IPersonTable = transmute( schema.PersonTable, PersonAnnotation, properties = {'address':zschema.Object( IAddressTable, required=False ) }, __module__="Products.orgperson.interfaces" ) class IPersonContainer( Interface ): """ marker interface for adding app specific views and adapters to generic containers """
import schema from vocabulary import StateVocabulary AddressAnnotation = TableAnnotation( "Address", columns = [ dict( name="address_id", omit = True ), # omit means that the we never see the id in the schema dict( name="address_1", label = "address line 1"), dict( name="address_2", label = "address line 2"), ], properties = {'state':zschema.Choice( title=u"state", vocabulary=StateVocabulary() ) } ) IAddressTable = transmute( schema.AddressTable, AddressAnnotation, __module__="Products.orgperson.interfaces" ) PersonAnnotation = TableAnnotation( "Person", columns = [ dict( name="first_name", label = "First Name" ), dict( name="middle_initial", label = "Middle Initial" ), dict( name="last_name", label = "Last Name" ), dict( name="email", label = "Email Address" ), dict( name="phone_number", label = "Home Phone Number" ), dict( name="address_id", omit = True ), dict( name="person_id", omit = True ) ], # you can specify which columns should be in the container listing view via this, first column
def GenerateDomainInterface(ctx, interface_name=None): # when called from zcml, most likely we'll get a class not an instance # if it is a class go ahead and call instantiate it if isinstance(ctx.descriptor, type): ctx.descriptor = ctx.descriptor() # if the interface module is none, then use the nearest one to the domain class if ctx.interface_module is None: ispec = ctx.domain_model.__module__.rsplit(".",1)[0]+".interfaces" ctx.interface_module = resolve(ispec) # interface for domain model if not interface_name: interface_name = "I%s"%(ctx.domain_model.__name__) if ctx.echo: ctx.logger.debug("%s: generated interface %s.%s " % ( ctx.domain_model.__name__, ctx.interface_module.__name__, interface_name)) from alchemist.catalyst.domain import getDomainInterfaces bases, implements = getDomainInterfaces(ctx.domain_model) # use the class"s mapper select table as input for the transformation domain_mapper = orm.class_mapper(ctx.domain_model) ## 0.4 and 0.5 compatibility, 0.5 has the table as local_table (select_table) is none lazy gen? #domain_table = getattr(domain_mapper, "local_table", domain_mapper.select_table) # The 0.6 has no attribute select_table attribute. We still have 0.4 # compitability thought domain_table = (domain_mapper.local_table if sa_version[1] >= 5 else domain_mapper.select_table) # if the domain model already implements a model interface, use it # instead of generating a new one for iface in interface.implementedBy(ctx.domain_model): if (interfaces.IIModelInterface.providedBy(iface) and iface.__name__ == interface_name): domain_interface = iface break else: domain_interface = sa2zs.transmute( domain_table, annotation=ctx.descriptor, interface_name = interface_name, __module__ = ctx.interface_module.__name__, bases=bases) # if we're replacing an existing interface, make sure the new # interface implements it old = getattr(ctx.interface_module, interface_name, None) if old is not None: implements.append(old) implements.insert(0, domain_interface) # ensure interfaces are unique, preserving the order #implements = [ ifc for i,ifc in enumerate(implements) # if implements.index(ifc)==i ] # # XXX: Oooh, strangely the above does not work... it turns out that # implements contains seemingly repeated interfaces e.g. the first and last # interfaces are both "<InterfaceClass bungeni.models.interfaces.IReport>" # but, they are not the same! So, to compare unique we use the string # representation of each interface: # str_implements = map(str, implements) # implements = [ ifc for i,ifc in enumerate(implements) # if str_implements.index(str(ifc))==i ] # Ooops making the interfaces unique breaks other things downstream :( interface.classImplementsOnly(ctx.domain_model, *implements) setattr(ctx.interface_module, interface_name, domain_interface) ctx.domain_interface = domain_interface