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

Reply via email to