On Dec 28, 2011, at 1:36 AM, Mike Orr wrote:

> On Tue, Dec 27, 2011 at 8:05 AM, Michael Bayer <[email protected]> 
> wrote:
>> What's the use case for a Base being shared to a third party module that 
>> doesn't know about your application?  This sounds like a bad idea.   A Base 
>> might have any number of behaviors on it, like certain columns, naming 
>> conventions, __mapper_args__(), attribute names, that can't be anticipated 
>> by a third party library.
> 
> The problem is that applications and libraries are all creating their
> own Bases and Sessions, and then it becomes complicated to make them
> work together.

Regarding Session, if someone builds a third party library that works on some 
tables of it's own, and the author made the system use its own Session with no 
way to plug into the main transaction of the calling application, that's just 
bad design.  If it calls session.commit() on its own yet is designed to work 
inline with the same database and within a series of events inside of a view, 
also bad design.   It shouldn't assume transactional scope.

I would think if the plugin is designed for Pyramid, it would be based around 
ZopeSQLAlchemy, which provides a master transaction for everyone to integrate 
towards.  Do the third party plugins at least integrate with that ?

I would say that's just something library authors would need to know how to do. 
 They need to understand that transactions are defined by the calling 
application, and how a Session relates to that.   It's just one click more 
complicated than having to know nothing at all about how transactions work.     
A convention here, a "how to" document of best practices for 3rd party stuff, 
would make it clear how these should be done.    Using the transaction manager 
recommended with Pyramid would be best, assuming the transaction manager is 
capable of this.

Also, just as a note, I've never seen a 3rd party plugin that uses SQLAlchemy 
before, which is using a Session, defining tables, etc.   Can I see one ?   Are 
there a lot , or like half a dozen ?

Regarding Base, Base corresponds to a class hierarchy, meaning it's how your 
class structure is designed.   SQLAHelper doesn't need to change here, it if 
course can expose the default "Base" to everyone, and that's great.   A shop 
that has multiple apps of its own but are designed to work together can 
certainly have them all call into SQLAHelper's "Base" and that is fine.

As far as a 3rd party thing, like "download this library and now you have a 
standalone auth model/schema" (is there at least *one* 3rd party thing that is 
*not* about auth?), that probably shouldn't use the same Base, as it implies 
the app can't assume any kinds of conventions or behaviors on the Base class, 
or if it does it means my own app now can't do X, Y, or Z because it will break 
the 3rd party library.    So I'd rather the standard practice is to share 
configuration and namespaces, but not class structure except for mixins.    But 
if someone shows me an example here why they really want to share out the Base 
that of course can make me more aware.

The sharing of configuration can integrate with the schema of the target system 
by sharing MetaData().    It can integrate at the relationship() level using 
real class objects, or by sharing _decl_class_registry, which has always been 
something that could be monkeypatched, but not public...so r76d872dc77b9 now 
contains this feature:

from sqlalchemy.ext.declarative import declarative_base

reg = {}
Base1 = declarative_base(class_registry = reg)
Base2 = declarative_base(class_registry = reg)

class A(Base1):
    __tablename__ = 'a'
    id = Column(Integer, primary_key=True)

class B(Base2):
    __tablename__ = 'b'
    id = Column(Integer, primary_key=True)
    aid = Column(Integer, ForeignKey(A.id))
    as_ = relationship("A")

assert B.as_.property.mapper.class_ is A

If you additionally share a MetaData() between two bases, now those two will 
entirely share the same class name and table name registry.

Also note ticket 2338: http://www.sqlalchemy.org/trac/ticket/2338 , which I'm 
leaning towards, would add the full module path of things to the registry, so 
you could say:

group = relationship("myauth.classes.Group")

> 
> Well, I'm inclined to do whatever MikeB suggests. But what would the
> module contain in this case; i.e., what would its globals be? You'd
> still need a module with globals in order to be a well-known rendevous
> point. 'helper = SQLAHelper()' as a variable in the application
> doesn't do that. Or would 'helper' be the global in the package?

never mind that part here, if it's a module global already that's fine.

> 
> One thing SQLAHelper does is that if you call ``add_engine(engine)``
> without an engine name, it becomes the default engine, and the Session
> and Base.metadata are automatically bound to it. This is so that
> applications with a single database only need to make one function
> call to set everything up. It looks like the only way to do that in
> your 'helper' structure would be a 'helper.set_default_engine()'
> method? And 'helper.engines.default' would be None initially, because
> the engine is not known at import time?

perhaps helper.engine = some_engine would be the equivalent of 
add_engine(engine) - or do we think using a "setter" approach belies that 
nothing more than just a simple assignment is going on ?    


-- 
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.

Reply via email to