dan -
no need to get defensive, the list has had enough flame wars for one
day.
this session context stuff is so not a big deal. we can go around
and around, its not going to go anywhere until you answer me this
question:
we agree, that there should be some way to turn on this feature:
u = User() # 'u' is now automatically in the session
session.flush() # 'u' is now saved.
question 1. heres the code inside of mapper.py which decorates the
__init__() method of a class, and automatically adds the item to the
session, if available:
def __init__(self):
sess = current_session()
if sess is not None;
sess.save(self)
Now, get rid of current_session. how does it work ? beacuse
honestly, i dont know how you think it should work. no other method
is coming to mind for me right now.
Next question, which is related. while its nice to have a class
associated with a particular sessioncontext, i simply disagree that
the explicit class/sessioncontext association should be required. i
think there should be an option for a session to be locateable,
without the need for an explicit declaration on each individual class
or requiring the classes descend from some common base class. if you
think that feature should not be available, maybe thats why you want
get rid of current_session(). but i want that feature available.
how can that be implemented without a current_session() function ?
as far as the "implicit" layer being optional, i dont understand how
you think its not optional right now. when you download and run SA
0.2, there is no thread local implicit anything going on, anywhere.
you can override pythons thread.get_ident() to throw an exception and
itll never get thrown. there is a current_session() function which
returns None and has essentially no effect on anything. how is that
not optional ?
its also documented pretty thoroughly in the latest docs.
On May 11, 2006, at 12:03 AM, Daniel Miller wrote:
Michael Bayer wrote:
On May 2, 2006, at 10:13 PM, Daniel Miller wrote:
If you're interested, I have lot's of comments like this on
various parts of the SQLAlchemy API.
im sure you do, but one thorny issue of SA is that it supports
multiple programming styles, particularly in 0.2, where you can
use an explicitly maintained Connection object to execute SQL, or
you can use the "implicit" style that SA 0.1 has. I know your SQL
library would only have explicit Connection and nothing else...
You greatly misunderstand my intent. I'm only trying to make it
easier to do things explicitly when I can't live with the implicit
assumptions in SA.
but SA benefits greatly from supporting more succinct programming
styles, the Python audience demands it (as evidenced by early
critiques of SA being "too hard" compared to SQLObject, Guido's
trashing of Myghty because it took more than one line of code to
programmatically call a template, etc.)
I understand you're worry here. Please understand that I don't want
to take away the implicit mode is so nice to use for
experimentation or simple tasks. But you're making it harder for me
to use an explicit coding style by including all this implicit
stuff right in the core of SA.
SA would be more useful if the implicit layer was written as an
optional extension with all of it's implicit behavior explicitly
documented. If someone can't live with some or all of those
assumptions, then they should be able to easily shed the implicit
layer and do stuff explicitly. There should be no "I don't do
anything until you invoke a special mod" methods cluttering up the
core library (case in point
sqlalchemy.orm.session.current_session). Such methods are useless
unless a mod has been installed, and they require monkey-patching
to make them work which is generally frowned upon. I wouldn't
complain if it were the only way to make it work, but there's a
better and much cleaner way to do it.
at its core, cases where a __call__() method does the same thing
as an explicit method is not a perl thing at all, its a Java thing.
I never said *that* was a perl thing. It's not a Java thing either.
It's an interface thing, which is a much more general concept that
has nothing to do with any particular language.
Just take a look at the collections classes, where various objects
need to implement multiple interface contracts; in order to
implement more than one interface, you often need to express the
same functionality with different methods.
I understand the concept of a single object implementing more than
one interface. But why should SessionContext implement two
interfaces for "session context" (i.e. one __call__() interface to
be used internally by SA and one "current" property for humans to
use)? The issue here is defining a clear and consistent interface
for all "session context" objects to be used everywhere. You did
not have one prior to the contribution of the SessionContext
implementation, or at least it was implied in the implementation of
ScopedRegistry and I just thought that was an implementation detail
(not a formalized interface). So I came up with a convenient
interface for people to use and that happened to be a property. As
I have already said, I have no problem changing the interface of
SessionContext if there is a good reason to do so. All I want is
one consistent interface for all "session context" objects.
As I indicated that the interface for a "session context" would be
just a callable, it follows logically that SessionContext would
maintain its explicit API since its clear and consistent for
applications that deal with it explicitly, and also implements
__call__() in order to conform to SA's interface contract for
"session context" objects, which does not deal with SessionContext
explicitly. its no different from a dictionary having both a keys
() and an __iter__() method.
As you mentioned, a property is a really nice, logical thing for
people to use. I would argue that it's even nicer than a callable
because it supports assignment and deletion in a well-known and
easy-to-remember way. If SA internally needs a callable, then why
not just use the get_current() method of SessionContext as that
callable? Or why not change the internals of SA to use the
"current" property of SessionContext instead? There's not that much
to change, and then we'd have a nice, consistent interface for all
"session context" objects.
As I've already said, I object to adding a __call__() method in
addition to the "current" property because it adds confusion about
the "one obvious way" to get the current session. The "reference
implementation" of your "session context" seems to be
ScopedRegistry, which uses three different methods to support the
functionality of the "current" property on SessionContext. I would
argue that three methods are harder to remember than a single
property, and therefore I think a property is better. Convince me
that a callable is better and I will gladly change the
SessionContext interface. But please, let's just have one simple
interface rather than two.
there is also an recurring undercurrent of disagreement here,
which is based on my experience that total rigid adherence to
commonly "accepted" rules is a recipe for disaster...when someone
goes through my code and only looks that it "breaks rules A, B,
C", I dont consider that to be a very deep critique. usually "the
rules" are too open-ended to not be mis-interpretable....such as,
is that TMTOWTDI, or is it just an object that needs to conform to
multiple interface contracts ? Is that "premature optimization",
or is it "failure to write an algorithm in a completely brain
dead way"? is that "a global variable", or is that an
"application-scoped registry" ?
On the "global variable" vs "application-scoped registry" thing, I
do have some input. First, let's avoid euphemisms--if it's an
"application-scoped registry" then it's a global in the application
by definition. I don't think I've ever argued that globals should
never be used (I use them within my own applications). I'm arguing
that the choice to use globals should be left to the application
developer rather than being mandated by the library developer. That
means the global current_session() method within SA needs to go.
Instead, let the application developers create and maintain their
own global SessionContext instance(s). It doesn't require any more
code to use SessionContext than it does to use current_session().
Here's an example using current_session():
# model.py
import sqlalchemy.mods.threadlocal
...
# othermodule.py
from sqlalchemy import current_session
session = current_session()
...
And an equivalent example using SessionContext:
# model.py
context = SessionContext()
...
# othermodule.py
from model import context
session = context.current
...
IMHO the second version is much more desirable because the global
context is created and maintained by the application rather than
the SA library. The act of creating a SessionContext instance is
explicit and intuitive. The act of defining and storing that
context object at the module level is also explicit and intuitive.
And if the user wants to have several separate contexts it's easily
possible and intuitive as well (but not so with current_session()).
The thread-local mod is implied in all the documentation examples
for 0.2; therefore it will be used by most if not all SA users at
least at first. When a project starts to move from simple
experimentation mode into a full-blown complex project where
resource management must be flexible and configurable this will
become a thorn. Trust me, I know from experience. At that point
(using the current_session() method), the user would at best be
forced to monkey-patch the session context logic in SA
(undesirable) and at worst be f
orced to rewrite every piece of code that uses the current_session
() method (painful). If instead they use the SessionContext then
all they need to do is make a new implementation of SessionContext
to suit their needs. Since the global is located in their own code
there is no need to monkey-patch anything since they own it and can
change it as needed.
Finally, I admit I am guilty of playing the "pythonic" card when I
should have kept my mouth shut. However, one of the central themes
of Python is that "There should be one -- and preferably only one
-- obvious way to do it." This is at odds with Perl culture, and
I've seen places in SA where I've wondered why there's more than
one way to do what seems to be the same thing. These are the things
I'd like to point out, not to inflate my ego, but to help make SA
easier for other Python developers to understand. If you're not
interested in my input I'll gladly take my thoughts and
contributions to some other project.
~ Daniel
-------------------------------------------------------
Using Tomcat but need to do more? Need to support web services,
security?
Get stuff done quickly with pre-integrated technology to make your
job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache
Geronimo
http://sel.as-us.falkag.net/sel?
cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Sqlalchemy-users mailing list
Sqlalchemy-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users
-------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Sqlalchemy-users mailing list
Sqlalchemy-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users