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
-~----------~----~----~----~------~----~------~--~---

Reply via email to