[sqlalchemy] Help with DeferredReflection and setting up an engine at runtime?

2014-02-17 Thread Rob Crowell
I am having a bit of trouble getting DeferredReflection working the way I 
want; not sure if I am overlooking something obvious or if I just don't 
really understand how it's supposed to work.  

I'm trying to define my models before creating my engine (this does not 
work):

Base = declarative_base(cls=*DeferredReflection*)

class CityStats(Base):
__tablename__ = 'city_stats'
__table_args__ = {'schema': 'prod', *'autoload': True*}

if __name__ == '__main__':
engine = create_engine('...')
Base.metadata.bind = engine
Base.prepare(engine)


When I run this I get an error creating the CityStats class: 
sqlalchemy.exc.UnboundExecutionError: 
No engine is bound to this Table's MetaData. Pass an engine to the Table 
via autoload_with=someengine, or associate the MetaData with an engine 
via metadata.bind=someengine

Of course it does work if I create my engine and set Base.metadata.bind 
BEFORE I define the CityStats model (this works):

engine = create_engine('...')
Base.metadata.bind = engine

class CityStats(Base):
__tablename__ = 'city_stats'
__table_args__ = {'schema': 'prod', *'autoload': True*}

Base.prepare(engine)


I'm trying to avoid some kind of model_init() function that everyone who 
imports my models.py file will have to remember to call before importing my 
models.  Is this possible?

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


[sqlalchemy] Cannot use pgbouncer's statement mode

2014-02-17 Thread Claudio Freire
Hello there. I'm using SQLAlchemy 0.7.10 with postgres+pgbouncer, and
I'm trying to move from a transaction-mode pool towards a
statement-mode pool.

The reason for this move, is that I've got quite a high volume of
reads that cannot be quickly serviced in transaction mode, since many
connections are left idling in a transaction for perhaps up to 1
second. A combination of network roundtrips and GIL-related delays
conspire to get me into this position.

So, I've been refactoring my application so that I can use two kinds
of sessions, read-write normal transactional ones, and read-only ones
that use autocommit and a different pgbouncer configured for statement
pooling.

Problem I run into, is that even in autocommit mode, SQLAlchemy itself
issues multi-statement transactions, like this:

 s = get_slave_session(autocommit=True)
 c = s.connection()
Traceback (most recent call last):
  File stdin, line 1, in module
  File /opt/jampp/analytics/matlogbrowser/model/base.py, line 80, in
connection
return sqlalchemy.orm.Session.connection(self, *p, **kw)
  File build/bdist.linux-x86_64/egg/sqlalchemy/orm/session.py, line
784, in connection
  File build/bdist.linux-x86_64/egg/sqlalchemy/orm/session.py, line
788, in _connection_for_bind
  File build/bdist.linux-x86_64/egg/sqlalchemy/orm/session.py, line
313, in _connection_for_bind
  File build/bdist.linux-x86_64/egg/sqlalchemy/engine/base.py, line
2489, in contextual_connect
  File build/bdist.linux-x86_64/egg/sqlalchemy/pool.py, line 236, in connect
  File build/bdist.linux-x86_64/egg/sqlalchemy/pool.py, line 401, in __init__
  File build/bdist.linux-x86_64/egg/sqlalchemy/pool.py, line 746, in _do_get
  File build/bdist.linux-x86_64/egg/sqlalchemy/pool.py, line 189, in
_create_connection
  File build/bdist.linux-x86_64/egg/sqlalchemy/pool.py, line 287, in __init__
  File build/bdist.linux-x86_64/egg/sqlalchemy/event.py, line 380,
in exec_once
  File build/bdist.linux-x86_64/egg/sqlalchemy/event.py, line 389, in __call__
  File build/bdist.linux-x86_64/egg/sqlalchemy/engine/strategies.py,
line 167, in first_connect
  File build/bdist.linux-x86_64/egg/sqlalchemy/dialects/postgresql/base.py,
line 1000, in initialize
  File build/bdist.linux-x86_64/egg/sqlalchemy/engine/default.py,
line 171, in initialize
  File build/bdist.linux-x86_64/egg/sqlalchemy/dialects/postgresql/base.py,
line 1184, in _get_server_version_info
  File build/bdist.linux-x86_64/egg/sqlalchemy/engine/base.py, line
1449, in execute
  File build/bdist.linux-x86_64/egg/sqlalchemy/engine/base.py, line
1628, in _execute_text
  File build/bdist.linux-x86_64/egg/sqlalchemy/engine/base.py, line
1698, in _execute_context
  File build/bdist.linux-x86_64/egg/sqlalchemy/engine/base.py, line
1691, in _execute_context
  File build/bdist.linux-x86_64/egg/sqlalchemy/engine/default.py,
line 331, in do_execute
sqlalchemy.exc.DatabaseError: (DatabaseError) Long transactions not allowed
ERROR:  Long transactions not allowed
 'select version()' {}


Here, get_slave_session returns a subclass of Session that will
override connection() to return a connection that has
execution_options(autocommit=True) applied (because for pgbouncer,
even the implicit transaction for selects is a transaction). The
session itself is also built with a autocommit=True.

Now, it seems the session is using a connection that is indepepndent
of what connection() returns. What do I have to override to get the
desired behavior? (that is: one query per transaction no matter which
type of query).

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


Re: [sqlalchemy] Help with DeferredReflection and setting up an engine at runtime?

2014-02-17 Thread Michael Bayer

On Feb 17, 2014, at 6:23 PM, Rob Crowell robccrow...@gmail.com wrote:

 I am having a bit of trouble getting DeferredReflection working the way I 
 want; not sure if I am overlooking something obvious or if I just don't 
 really understand how it's supposed to work. 
 
 I'm trying to define my models before creating my engine (this does not work):
 
 Base = declarative_base(cls=DeferredReflection)
 
 class CityStats(Base):
 __tablename__ = 'city_stats'
 __table_args__ = {'schema': 'prod', 'autoload': True}
 
 if __name__ == '__main__':
 engine = create_engine('...')
 Base.metadata.bind = engine
 Base.prepare(engine)
 
 
 When I run this I get an error creating the CityStats class: 
 sqlalchemy.exc.UnboundExecutionError: No engine is bound to this Table's 
 MetaData. Pass an engine to the Table via autoload_with=someengine, or 
 associate the MetaData with an engine via metadata.bind=someengine”

its all about the stack trace, lets look:

Traceback (most recent call last):
  File test.py, line 8, in module
class CityStats(Base):
  File /Users/classic/dev/sqlalchemy/lib/sqlalchemy/ext/declarative/api.py, 
line 53, in __init__
_as_declarative(cls, classname, cls.__dict__)
  File /Users/classic/dev/sqlalchemy/lib/sqlalchemy/ext/declarative/base.py, 
line 251, in _as_declarative
**table_kw)
  File /Users/classic/dev/sqlalchemy/lib/sqlalchemy/sql/schema.py, line 350, 
in __new__
table._init(name, metadata, *args, **kw)
  File /Users/classic/dev/sqlalchemy/lib/sqlalchemy/sql/schema.py, line 423, 
in _init
self._autoload(metadata, autoload_with, include_columns)
  File /Users/classic/dev/sqlalchemy/lib/sqlalchemy/sql/schema.py, line 439, 
in _autoload
msg=No engine is bound to this Table's MetaData. 
  File /Users/classic/dev/sqlalchemy/lib/sqlalchemy/sql/base.py, line 459, in 
_bind_or_error

what we see here is that this script doesn’t get to create_engine() at all, 
it’s trying to hit the database as soon as you say “CityStats(Base)”.  Why is 
that?  Because you have “autoload=True” in your table args, which means, 
“reflect this table *right now*”.  That is, you are defeating the purpose of 
using DeferredReflection.

The solution is just take out that autoload=True.  Any class which descends 
from the Base here is automatically part of the “classes to reflect” since you 
have DeferredReflection at the base.

Also, if you’re on 0.9 take a look at the new “automap” extension, I’ve been 
using it and it’s pretty keen.  There’s one fix for it in not-yet-released 
0.9.3 but it’s only needed if you’re dealing with inheritance structures.




signature.asc
Description: Message signed with OpenPGP using GPGMail


Re: [sqlalchemy] Cannot use pgbouncer's statement mode

2014-02-17 Thread Michael Bayer

On Feb 17, 2014, at 7:31 PM, Michael Bayer mike...@zzzcomputing.com wrote:

 
 O
 from sqlalchemy import event, create_engine
 
 eng = create_engine(postgresql+psycopg2://scott:tiger@localhost/test, 
 echo=True)
 
 @event.listens_for(eng, first_connect, insert=True)
 @event.listens_for(eng, connect, insert=True)
 def setup_autocommit(dbapi_conn, rec):
dbapi_conn.autocommit = True
 
 conn = eng.connect()
 print conn.execute(select 1).fetchall()


oh and also if you are on 0.8 (not 0.7), you can just send AUTOCOMMIT to 
create_engine:

eng = create_engine(postgresql+psycopg2://scott:tiger@localhost/test,
echo=True,
isolation_level='AUTOCOMMIT'
)

much easier




signature.asc
Description: Message signed with OpenPGP using GPGMail


Re: [sqlalchemy] Help with DeferredReflection and setting up an engine at runtime?

2014-02-17 Thread Rob Crowell
Interesting, thanks Michael.  I didn't realize autoload was implied when 
using DeferredReflection but that makes sense.

Thanks!

On Monday, February 17, 2014 7:17:34 PM UTC-5, Michael Bayer wrote:


 On Feb 17, 2014, at 6:23 PM, Rob Crowell robcc...@gmail.com javascript: 
 wrote:

 I am having a bit of trouble getting DeferredReflection working the way I 
 want; not sure if I am overlooking something obvious or if I just don't 
 really understand how it's supposed to work.  

 I'm trying to define my models before creating my engine (this does not 
 work):

 Base = declarative_base(cls=*DeferredReflection*)

 class CityStats(Base):
 __tablename__ = 'city_stats'
 __table_args__ = {'schema': 'prod', *'autoload': True*}

 if __name__ == '__main__':
 engine = create_engine('...')
 Base.metadata.bind = engine
 Base.prepare(engine)


 When I run this I get an error creating the CityStats class: 
 sqlalchemy.exc.UnboundExecutionError: 
 No engine is bound to this Table's MetaData. Pass an engine to the Table 
 via autoload_with=someengine, or associate the MetaData with an engine 
 via metadata.bind=someengine”


 its all about the stack trace, lets look:

 Traceback (most recent call last):
   File test.py, line 8, in module
 class CityStats(Base):
   File 
 /Users/classic/dev/sqlalchemy/lib/sqlalchemy/ext/declarative/api.py, line 
 53, in __init__
 _as_declarative(cls, classname, cls.__dict__)
   File 
 /Users/classic/dev/sqlalchemy/lib/sqlalchemy/ext/declarative/base.py, 
 line 251, in _as_declarative
 **table_kw)
   File /Users/classic/dev/sqlalchemy/lib/sqlalchemy/sql/schema.py, line 
 350, in __new__
 table._init(name, metadata, *args, **kw)
   File /Users/classic/dev/sqlalchemy/lib/sqlalchemy/sql/schema.py, line 
 423, in _init
 self._autoload(metadata, autoload_with, include_columns)
   File /Users/classic/dev/sqlalchemy/lib/sqlalchemy/sql/schema.py, line 
 439, in _autoload
 msg=No engine is bound to this Table's MetaData. 
   File /Users/classic/dev/sqlalchemy/lib/sqlalchemy/sql/base.py, line 
 459, in _bind_or_error

 what we see here is that this script doesn’t get to create_engine() at 
 all, it’s trying to hit the database as soon as you say “CityStats(Base)”. 
  Why is that?  Because you have “autoload=True” in your table args, which 
 means, “reflect this table *right now*”.  That is, you are defeating the 
 purpose of using DeferredReflection.

 The solution is just take out that autoload=True.  Any class which 
 descends from the Base here is automatically part of the “classes to 
 reflect” since you have DeferredReflection at the base.

 Also, if you’re on 0.9 take a look at the new “automap” extension, I’ve 
 been using it and it’s pretty keen.  There’s one fix for it in 
 not-yet-released 0.9.3 but it’s only needed if you’re dealing with 
 inheritance structures.




-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


Re: [sqlalchemy] Cannot use pgbouncer's statement mode

2014-02-17 Thread Claudio Freire
On Mon, Feb 17, 2014 at 9:31 PM, Michael Bayer mike...@zzzcomputing.com wrote:
 the Python DBAPI as you know returns a connection that's in a transaction. So 
 if you are using an environment that has zero tolerance for even two 
 statements in one transaction, you should turn on autocommit at the 
 psycopg2 level, using the connection.autocommit flag.   you can achieve 
 this with an on-connect event, with some tricks currently needed to 
 absolutely force it as the first thing that happens (I need to either 
 document this or make a nicer API, but this works for now), like this:

 from sqlalchemy import event, create_engine

 eng = create_engine(postgresql+psycopg2://scott:tiger@localhost/test, 
 echo=True)

 @event.listens_for(eng, first_connect, insert=True)
 @event.listens_for(eng, connect, insert=True)
 def setup_autocommit(dbapi_conn, rec):
 dbapi_conn.autocommit = True

 conn = eng.connect()
 print conn.execute(select 1).fetchall()

This is exactly what I need, thanks. Furthermore, with psycopg2 level
autocommit, I don't think I even need a second statement-based pool,
it will decrease idle-in-transaction time on its own. In fact, I
thought this is what execution_options(autocommit=True) did, though
looking at the code, now I realize it wasn't.

Many thanks :)

PS: Yeah, I know I have to update to 8.x ;-)

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


Re: [sqlalchemy] Cannot use pgbouncer's statement mode

2014-02-17 Thread Michael Bayer

On Feb 17, 2014, at 9:27 PM, Claudio Freire klaussfre...@gmail.com wrote:

 
 This is exactly what I need, thanks. Furthermore, with psycopg2 level
 autocommit, I don't think I even need a second statement-based pool,
 it will decrease idle-in-transaction time on its own. In fact, I
 thought this is what execution_options(autocommit=True) did, though
 looking at the code, now I realize it wasn’t.

right, we currently don’t link the SQLAlchemy-level “autocommit” things with a 
DBAPI-level autocommit.  Not all DBAPIs have an autocommit option as it isn’t 
in the spec and I’m generally just concerned about how wide of a behavioral 
difference there’d be between different backends if we sometimes used their 
autocommit, sometimes, ours, etc.   


signature.asc
Description: Message signed with OpenPGP using GPGMail