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

Reply via email to