On 11/4/06, Michael Bayer <[EMAIL PROTECTED]> wrote: > > Shannon - > > im trying to figure a way to make create_engine() behave the way you > want. but let me show you a highly simplified version of how > create_engine() works. how would you change it ? > > def create_engine(url, **kwargs): > pool = pool.Pool(**kwargs) > dialect = module.Dialect(url, **kwargs) > engine = Engine(dialect, pool, **kwargs) > return engine > > As you can see, the returned Engine is composed of itself, a connection > pool, and a Dialect. the **kwargs you pass to create_engine() can be > used by any three of those objects. Also, there are many different > types of Pool, Dialect, and Engine which take different arguments..so > placing explicit awareness of every argument within create_engine > itself is excessively brittle. > > since the constructors of all the classes declare their keyword > arguments as normal inline arguments, we need to pass them around using > "**" and therefore the kwargs dictionary cannot be "consumed". if they > could be consumed, we could then check at the end that the kwargs dict > is in fact empty so we know that no unknown arguments were sent. > > but as it is, the full dict gets passed to all three types of objects > where they have to just "ignore" the kwargs they dont know about. this > is not unlike WSGI where it passes around an "environ" dictionary, and > its fully likely that many erroneous keyword arguments could be present > in that dictionary as well. > > the only way i can see to fix this is to modify the constructors of all > the objects to take a single dictionary argument from which they > "consume" their arguments, and we dont pass the arguments with the ** > operator anymore. which means the nice constructors we have which > clearly lay out the arguments they take now will just have one > non-self-documenting "arguments" dictionary. is that the only option ?
The one bad thing about overloading the kwargs in this way is that it's really easy for there to be a namespace collision. What happens if suddenly the dialect and the engine both accepted a keyword argument named foo? As a general rule, I think it's safe to wrap one function and pass through the kwargs, but you're asking for trouble if you wrap more than one. I don't think it's asking too much for the user to have to do something like: create_engine(url, Pool(arg="foo"), dialect=Dialect(otherarg="bar")) However, you can't change the API now. Hence, how can we make it "safer"? I was playing around in the shell. Here's a start: >>> def f(a=None, b="foo"): ... pass ... >>> f.func_code.co_varnames ('a', 'b') Now, write a function: def pass_and_strip_kwargs(f, kwargs): """Pass the correct keyword arguments to f and remove them from kwargs.""" ... Now you can do: def create_engine(url, **kwargs): pool = pass_and_strip_kwargs(pool.Pool, kwargs) kwargs['url'] = url dialect = pass_and_strip_kwargs(module.Dialect, kwargs) kwargs['dialect'] = dialect kwargs['pool'] = pool engine = pass_and_strip_kwargs(Engine, kwargs) return engine Without too much work, I'm sure you could update it so that you can also pass positional arguments which will make things cleaner. I'm sure you get the idea. By the way, don't let this one little nitpick take away from the fact that I really like SQLAlchemy as a whole! ;) Best Regards, -jj -- http://jjinux.blogspot.com/ --~--~---------~--~----~------------~-------~--~----~ 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 [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~----------~----~----~----~------~----~------~--~---