I've been trying create the extension. Here is the code with a test: http://paste.pocoo.org/show/97502/ - Extension http://paste.pocoo.org/show/97503/ - Test
I need help to solve this little issue: entity._descriptor.add_mapper_extension(BcryptMapperExtension()) AttributeError: 'str' object has no attribute '_descriptor' Does could review the extension code? On 22 dic 2008, 03:40, Michael Bayer <mike...@zzzcomputing.com> wrote: > oh, yeah for that recipe you'd have to use a flag on the mapper() > called "batch=False". But don't use that, its inefficient. > > So you can also create your type to detect a special value from the > mapper extension: > > def before_insert(self, ....): > instance.password = (instance.password, True) > > class MyType(...): > ... > > def process_bind_param(self, value, dialect): > if isinstance(value, tuple): > return hasher.create(value[0], value[1]) > .... > > But since this is really an instance-level business rule, a straight > descriptor and no custom type is definitely how I'd go on this one. > > On Dec 21, 2008, at 6:47 PM, Kless wrote: > > > > > Thank you for detailed answer. > > > Here are any thoughts: > > > 1) The before_insert was being omitted while I was inserting records > > using an insert statement --that's logical because it was bypassing > > the ORM--. > > > 2) It's necessary to use *session.commit()* after of each record > > because else it will have the value of 'instance.admin' of the last > > record which will be used for all records to commit. > > > 3) I believe that it isn't necessary use *after_insert*. > > > On 21 dic, 17:00, Michael Bayer <mike...@zzzcomputing.com> wrote: > >> On Dec 21, 2008, at 6:53 AM, Kless wrote: > >>> I'm trying to build a custom type [1] to manage the bcrypt hashes > >>> [2]. > > >>> --------------- > >>> from bcrypt_wrap import password > >>> from sqlalchemy import types > > >>> class Bcrypt(types.TypeDecorator): > >>> """Stores a bcrypt hash of a password.""" > >>> impl = types.String #(60) > >>> hasher = password.Password() > > >>> def process_bind_param(self, value, dialect): > >>> return hasher.create(value) > >>> --------------- > > >>> And I've any doubts: > > >>> 1) Since that the hash length is always 60, is there that use the > >>> next? > >>> impl = types.String(60) > > >>> 2) The bcryptWrap API [3] (line 53) lets call to 'create' with > >>> arguments 'cost' and 'admin' (boolean). Then, > > >>> a) I would that the cost could be passed from the column > >>> definition, > >>> i.e. > >>> password = sqlalchemy.Column(types.Bcrypt, cost=12) > >>> or > >>> password = sqlalchemy.Column(types.Bcrypt(cost=12)) > > >>> b) This would be more hard, but I would to pass the 'admin' > >>> argument > >>> when an object is created > > >>> u = model.User() > >>> u.login = u'foo' > >>> u.password = u'bar' > >>> u.admin = True > > >>> And sou could be call: > >>> return hasher.create(value, admin=True) > > >> the TypeDecorator's __init__ method just calls the impl class > >> immediately, so the best approach is like: > > >> class Bcrypt(types.TypeDecorator): > >> """Stores a bcrypt hash of a password.""" > >> impl = types.String > >> hasher = password.Password() > > >> def __init__(self, cost): > >> self.cost = cost > >> types.TypeDecorator.__init__(self, 60) > > >> def process_bind_param(self, value, dialect): > >> return hasher.create(value) > > >> then you can instantate like: > > >> Column('foo', Bcrypt(cost=12)) > > >> For b, the type object and the ExecutionContext which ultimately > >> calls > >> its process_bind_param method are unaware of the ORM or the ORM- > >> specific context in which its called during INSERT/UPDATE. If you > >> wanted to keep the logic within your type like that you'd have to > >> integrate to a thread-local variable that is configured within an ORM > >> plugin, something like: > > >> hasher_status = threading.local() > > >> class MyMapperExt(MapperExtension): > >> def before_insert(self, ...): > >> hasher_status.admin = instance.admin > > >> def after_insert(self, ...) > >> del hasher_status.admin > > >> mapper(MyClass, table, ext=MyMapperExt) > > >> class Bcrypt(types.TypeDecorator): > >> ... > > >> def process_bind_param(self, value, dialect): > >> return hasher.create(value, getattr(hasher_status, 'admin', > >> False)) > > >> Alternatively, you could keep the logic within the ORM using either a > >> "valdiator" or a descriptor, as described > >> athttp://www.sqlalchemy.org/docs/05/mappers.html#changing-attribute-beh > >> ... > >> . It depends on if you'd like your Bcrypt type to work with direct > >> SQL expression language use or not. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~----------~----~----~----~------~----~------~--~---