[sqlalchemy] relationship trouble when using UsageRecipes/Views

2011-09-07 Thread werner
I am working on my localization stuff and run into a problem when I want 
to add an relationship to a class.


I based my code on 
http://www.sqlalchemy.org/trac/wiki/UsageRecipes/Views , but maybe I 
messed something up.


The following works:

r1 = session.query(db.Region_LV).get(175)
print type(result.country_lv)
print r1
print r1.country_lv.name

with this output:
Region_LV(centralkey=175, country_lv=Country_LV(centralkey=83, 
created_at=datetime.datetime(2011, 9, 7, 9, 39, 10, 702000), 
created_by=None, dialcode=30, fk_language_id=2, id=83, is2code=u'GR', 
iswinecountry=1, name=u'Gr\xe8ce', shortname=None, un3code=u'GRC', 
updated_at=datetime.datetime(2011, 9, 7, 9, 39, 10, 702000), 
updated_by=None, website1=None, website2=None), 
created_at=datetime.datetime(2011, 9, 7, 9, 39, 11, 452000), 
created_by=None, fk_country_id=83, fk_language_id=2, id=175, 
name=u'Sud-Ouest', shortname=u'Sud-Ouest', 
updated_at=datetime.datetime(2011, 9, 7, 9, 39, 11, 452000), 
updated_by=None)

Grèce

The model for all this is:

class Region(DeclarativeBase, mix.StandardColumnMixin):
__tablename__ = u'region'

centralkey = sa.Column(sa.BigInteger())
name = sa.Column(sa.Unicode(length=50), nullable=False)
shortname = sa.Column(sa.Unicode(length=10))
fk_country_id = sautils.reference_col('country')

__localize_columns__ = ['name', 'shortname']


Region_L, Region_LV = sautils.CreateLocalized(Region())

Region_LV.country_lv = sao.relationship('Country_LV')

CreateLocalized creates the Region_LV based on the usage recipe.

Now if I add:
Region_LV.language = sao.relationship('Language')

I get:
sqlalchemy.exc.ArgumentError: Could not determine join condition between 
parent/child tables on relationship Region_LV.language.  Specify a 
'primaryjoin' expression.  If 'secondary' is present, 'secondaryjoin' is 
needed as well.


or:
Region_LV.language = sao.relationship('Language',
primaryjoin=Region_LV.fk_language_id==Language.id)

I get:
sqlalchemy.exc.ArgumentError: Could not determine relationship direction 
for primaryjoin condition 'country_lv.fk_language_id = language.id', on 
relationship Region_LV.language. Ensure that the referencing Column 
objects have a ForeignKey present, or are otherwise part of a 
ForeignKeyConstraint on their parent Table, or specify the foreign_keys 
parameter to this relationship.


or:
Region_LV.language = sao.relationship('Language',
   primaryjoin=Country_LV.fk_language_id==Language.id,
   foreign_keys=[Country_LV.__table__.c.fk_language_id])

I get:
sqlalchemy.exc.ArgumentError: Column-based expression object expected 
for argument 'foreign_keys'; got: 'Country_LV.fk_language_id', type 
type 'str'


sqlalchemy.exc.ArgumentError: Could not locate any foreign-key-equated, 
locally mapped column pairs for primaryjoin condition 
'country_lv.fk_language_id = language.id' on relationship 
Region_LV.language.  For more relaxed rules on join conditions, the 
relationship may be marked as viewonly=True.


Tried with viewonly but couldn't make that work either.

I guess/think my problem is that I don't define a ForeignKeyConstraint 
for the fk_language_id column but I haven't found how this is done as 
the Country_LV view is created using from sqlalchemy.sql import table.


I'd appreciate any tips on how to get this to work.

Werner

--
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 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] subqueryload for a ColumnProperty?

2011-09-07 Thread Michael Bayer
For a deferred() itself, we don't have an option that does this.Though this 
is an unusual request.   If you definitely want the deferreds to load, what's 
the issue having them render inline into the original query ?The advantage 
to subqueryload is primarily in that it loads multiple rows per parent object 
efficiently, without re-fetching the full parent row many times,  or needing to 
use a less efficient OUTER JOIN.   A deferred is always one row per parent - 
and no join is needed anyway.




On Sep 6, 2011, at 6:49 PM, Sumeet Agarwal wrote:

 I have a collection of deferred `ColumnProperty`s that I'd like to
 start loading in subsequent queries. I know you can get this to happen
 on the first access of a `ColumnProperty` that is deferred, but I
 wonder if there's any way to specify this in the query.
 
 For relationships, `joinedload[_all()]` has a counterpart
 `subqueryload[_all()]`. Is there nothing similar we can do for
 `ColumnProperty`?
 
 -- 
 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 
 sqlalchemy+unsubscr...@googlegroups.com.
 For more options, visit this group at 
 http://groups.google.com/group/sqlalchemy?hl=en.
 

-- 
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 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] relationship trouble when using UsageRecipes/Views

2011-09-07 Thread Michael Bayer

On Sep 7, 2011, at 4:40 AM, werner wrote:

 or:
 Region_LV.language = sao.relationship('Language',
   primaryjoin=Country_LV.fk_language_id==Language.id,
   foreign_keys=[Country_LV.__table__.c.fk_language_id])
 
 I get:
 sqlalchemy.exc.ArgumentError: Column-based expression object expected for 
 argument 'foreign_keys'; got: 'Country_LV.fk_language_id', type type 'str'

this one above is the one that doesn't make any sense (also its probably how 
the relationship should be set up).   Clearly x.__table__.c.somename is a 
Column object, not a string.   Something is up with what you're sending it. 
I've tried to reproduce with no luck.  See attached.   Also I don't even need 
the primaryjoin/foreignkeys if the originating Table upon which the view is 
based has foreign keys to the parent.



from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.schema import DDLElement
from sqlalchemy.sql import table
from sqlalchemy.ext import compiler

Base= declarative_base()

# first the view stuff as it is on the wiki
class CreateView(DDLElement):
def __init__(self, name, selectable):
self.name = name
self.selectable = selectable

class DropView(DDLElement):
def __init__(self, name):
self.name = name

@compiler.compiles(CreateView)
def compile(element, compiler, **kw):
return CREATE VIEW %s AS %s % (element.name, compiler.sql_compiler.process(element.selectable)) 

@compiler.compiles(DropView)
def compile(element, compiler, **kw):
return DROP VIEW %s % (element.name)

def view(name, metadata, selectable):
t = table(name)

for c in selectable.c:
c._make_proxy(t)

CreateView(name, selectable).execute_at('after-create', metadata)
DropView(name).execute_at('before-drop', metadata)
return t


# now do an example using declartive

Base = declarative_base()

class MoreStuff(Base):
__tablename__ = 'morestuff'
id = Column(Integer, primary_key=True)

# if you use this one, then we don't even need the primaryjoin/foriegn_keys
# on the view, the FK propagates out
# stuff_id = Column(Integer, ForeignKey('stuff.id'))

# ... but lets say it wasn't there
stuff_id = Column(Integer)
data = Column(String(50))

class MSView(Base):
__table__ = view(msview, Base.metadata,
MoreStuff.__table__.select()
)
__mapper_args__ = {primary_key:__table__.c.id}

# cannot reproduce your error.

class Stuff(Base):
__tablename__ = 'stuff'
id = Column(Integer, primary_key=True)
data = Column(String(50))

# works
#msview = relationship(MSView, primaryjoin=Stuff.id==MSView.stuff_id, foreign_keys=[MSView.stuff_id])

# works
#msview = relationship(MSView, primaryjoin=Stuff.id==MSView.stuff_id, foreign_keys=MSView.stuff_id)

# doesn't work, tries to resolve __table__ as a column
#msview = relationship(MSView, primaryjoin=Stuff.id==MSView.stuff_id, foreign_keys=[MSView.__table__.c.stuff_id])

# doesn't work, tries to resolve __table__ as a column
#msview = relationship(MSView, primaryjoin=Stuff.id==MSView.stuff_id, foreign_keys=MSView.__table__.c.stuff_id)

# works
#msview = relationship(MSView, primaryjoin=Stuff.id==MSView.stuff_id, foreign_keys=[MSView.stuff_id])

# works
msview = relationship(MSView, primaryjoin=Stuff.id==MSView.stuff_id, foreign_keys=[MSView.__table__.c.stuff_id])


# all is well

e = create_engine('sqlite://', echo=True)


Base.metadata.create_all(e)

e.execute(Stuff.__table__.insert(),
{'data':'apples'},
{'data':'pears'},
{'data':'oranges'},
{'data':'orange julius'},
{'data':'apple jacks'},
)

e.execute(MoreStuff.__table__.insert(),
{'stuff_id':3, 'data':'foobar'},
{'stuff_id':4, 'data':'foobar'}
)

s = Session(e)

print s.query(Stuff).options(eagerload(msview)).all()-- 
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 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] relationship trouble when using UsageRecipes/Views

2011-09-07 Thread werner

Michael,

On 09/07/2011 05:10 PM, Michael Bayer wrote:

On Sep 7, 2011, at 4:40 AM, werner wrote:


or:
Region_LV.language = sao.relationship('Language',
   primaryjoin=Country_LV.fk_language_id==Language.id,
   foreign_keys=[Country_LV.__table__.c.fk_language_id])

I get:
sqlalchemy.exc.ArgumentError: Column-based expression object expected for argument 
'foreign_keys'; got: 'Country_LV.fk_language_id', typetype 'str'

this one above is the one that doesn't make any sense (also its probably how 
the relationship should be set up).

Sorry that was a copy/paste error on my part.

Clearly x.__table__.c.somename is a Column object, not a string.   
Something is up with what you're sending it. I've tried to reproduce with 
no luck.  See attached.   Also I don't even need the primaryjoin/foreignkeys if 
the originating Table upon which the view is based has foreign keys to the 
parent.

The additional column is in my case added in to the view as the base 
table doesn't have it and it is filled by the stored procedure (which 
combines the base table plus the localized table ...) , i.e.:


def view(name, metadata, selectable):
t = table(name)

for c in selectable.c:
c._make_proxy(t)

lc = sasql.column(stuff_id, sa.Integer)
t.append_column(lc)

But what I had overlooked/forgotten to include was the __mapper_args__ 
= {primary_key:__table__.c.id} line.


After adding this the relationship as shown at the beginning it works.

Thanks a lot for your answer and your patience.

Werner

--
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 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] relationship trouble when using UsageRecipes/Views

2011-09-07 Thread Michael Bayer

On Sep 7, 2011, at 11:53 AM, werner wrote:

 Michael,
 
 On 09/07/2011 05:10 PM, Michael Bayer wrote:
 On Sep 7, 2011, at 4:40 AM, werner wrote:
 
 or:
 Region_LV.language = sao.relationship('Language',
   primaryjoin=Country_LV.fk_language_id==Language.id,
   foreign_keys=[Country_LV.__table__.c.fk_language_id])
 
 I get:
 sqlalchemy.exc.ArgumentError: Column-based expression object expected for 
 argument 'foreign_keys'; got: 'Country_LV.fk_language_id', typetype 'str'
 this one above is the one that doesn't make any sense (also its probably how 
 the relationship should be set up).
 Sorry that was a copy/paste error on my part.
Clearly x.__table__.c.somename is a Column object, not a string.   
 Something is up with what you're sending it. I've tried to reproduce 
 with no luck.  See attached.   Also I don't even need the 
 primaryjoin/foreignkeys if the originating Table upon which the view is 
 based has foreign keys to the parent.
 
 The additional column is in my case added in to the view as the base table 
 doesn't have it and it is filled by the stored procedure (which combines the 
 base table plus the localized table ...) , i.e.:
 
 def view(name, metadata, selectable):
t = table(name)
 
for c in selectable.c:
c._make_proxy(t)
 
lc = sasql.column(stuff_id, sa.Integer)
t.append_column(lc)
 
 But what I had overlooked/forgotten to include was the __mapper_args__ = 
 {primary_key:__table__.c.id} line.
 
 After adding this the relationship as shown at the beginning it works.

well that's also strange.   If the mapper is not able to find a primary key, 
the error is very clear:

sqlalchemy.exc.ArgumentError: Mapper Mapper|MSView|msview could not assemble 
any primary key columns for mapped table 'msview'

not sure why that isn't what you were seeing.

-- 
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 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



[sqlalchemy] CircularDependencyError, why?

2011-09-07 Thread Erkan Özgür Yılmaz
The following gives CircularDependencyError

where I think there isn't, but you know I don't know that much the internals
of SQLAlchemy and maybe (and it is a strong possibility) I'm wrong. I've
ripped of the classes causing the error (copy/paste will re-produce the
error).

from sqlalchemy import orm, create_engine
from sqlalchemy.orm import relationship, synonym, validates
from sqlalchemy import (Table, Column, ForeignKey, Boolean, Integer, String)
from sqlalchemy.ext.declarative import (declarative_base, synonym_for,
declared_attr)


Base = declarative_base()



class SimpleEntity(Base):
__tablename__ = SimpleEntities
id = Column(id, Integer, primary_key=True)

entity_type = Column(db_entity_type, String(128), nullable=False)
__mapper_args__ = {
polymorphic_on: entity_type,
polymorphic_identity: SimpleEntity,
}


class Entity(SimpleEntity):
__tablename__ = Entities
__mapper_args__ = {polymorphic_identity: Entity}
entity_id = Column(id, Integer, ForeignKey(SimpleEntities.id),
   primary_key=True)


class Task(Entity):
__tablename__ = Tasks
__mapper_args__ = {polymorphic_identity: Task}
task_id = Column(id, Integer, ForeignKey(Entities.id),
 primary_key=True)
task_of_id = Column(Integer, ForeignKey(TaskableEntities.id))


class ProjectMixin(object):
#--
@declared_attr
def project_id(cls):
return Column(
project_id,
Integer,
ForeignKey(Projects.id),
)

#--
@declared_attr
def project(cls):
return relationship(
Project,
primaryjoin=\
cls.__name__ + .project_id==Project.project_id_local,
post_update=True, # for project itself
uselist=False
)

#--
def __init__(self,
 project=None,
 **kwargs):

self.project = project


class TaskableEntity(Entity, ProjectMixin):
__tablename__ = TaskableEntities
__mapper_args__ = {polymorphic_identity: TaskableEntity}
taskableEntity_id = Column(id, Integer, ForeignKey(Entities.id),
   primary_key=True)
tasks = relationship(
Task,
primaryjoin=taskableEntity_id==Task.task_of_id,
backref=task_of,
post_update=True,
)


class Project(TaskableEntity):
__tablename__ = Projects
project_id_local = Column(id, Integer,
ForeignKey(TaskableEntities.id),
  primary_key=True)
__mapper_args__ = {polymorphic_identity: Project,
   inherit_condition:
   project_id_local==TaskableEntity.taskableEntity_id}


engine = create_engine(sqlite:///:memory:)
Base.metadata.create_all(engine)
Session = sqlalchemy.orm.sessionmaker(bind=dengine)

session = Session()




The Error message:
sqlalchemy.exc.CircularDependencyError: Circular dependency detected:
cycles:
set([
Table('TaskableEntities', MetaData(None),
  Column('id', Integer(), ForeignKey('Entities.id'),
table=TaskableEntities, primary_key=True, nullable=False),
  Column('project_id', Integer(), ForeignKey('Projects.id'),
table=TaskableEntities), schema=None),
Table('Projects', MetaData(None),
  Column('id', Integer(), ForeignKey('TaskableEntities.id'),
table=Projects, primary_key=True, nullable=False), schema=None)]
) all edges:
set(
[
(Table('TaskableEntities', MetaData(None),
   Column('id', Integer(), ForeignKey('Entities.id'),
table=TaskableEntities, primary_key=True, nullable=False),
   Column('project_id', Integer(), ForeignKey('Projects.id'),
table=TaskableEntities), schema=None),
 Table('Projects', MetaData(None),
   Column('id', Integer(), ForeignKey('TaskableEntities.id'),
table=Projects, primary_key=True, nullable=False), schema=None)),
(Table('SimpleEntities', MetaData(None),
   Column('id', Integer(), table=SimpleEntities,
primary_key=True, nullable=False),
   Column('db_entity_type', String(length=128),
table=SimpleEntities, nullable=False), schema=None),
 Table('Entities', MetaData(None),
   Column('id', Integer(), ForeignKey('SimpleEntities.id'),
table=Entities, 

Re: [sqlalchemy] CircularDependencyError, why?

2011-09-07 Thread Michael Bayer

On Sep 7, 2011, at 12:36 PM, Erkan Özgür Yılmaz wrote:

 The following gives CircularDependencyError
 
 where I think there isn't, but you know I don't know that much the internals 
 of SQLAlchemy and maybe (and it is a strong possibility) I'm wrong. I've 
 ripped of the classes causing the error (copy/paste will re-produce the 
 error).

According to the error message, TaskableEntity has a foreign key to Projects 
and Projects has a foreign key to TaskableEntity, thus creating a cycle.  
TaskableEntity would appear to have this Project foreign key via the 
ProjectMixin class.So I'd add a use_alter=True to one of those ForeignKey 
objects.



 

 
 from sqlalchemy import orm, create_engine
 from sqlalchemy.orm import relationship, synonym, validates
 from sqlalchemy import (Table, Column, ForeignKey, Boolean, Integer, String)
 from sqlalchemy.ext.declarative import (declarative_base, synonym_for,
 declared_attr)
 
 
 Base = declarative_base()
 
 
 
 class SimpleEntity(Base):
 __tablename__ = SimpleEntities
 id = Column(id, Integer, primary_key=True)
 
 entity_type = Column(db_entity_type, String(128), nullable=False)
 __mapper_args__ = {
 polymorphic_on: entity_type,
 polymorphic_identity: SimpleEntity,
 }
 
 
 class Entity(SimpleEntity):
 __tablename__ = Entities
 __mapper_args__ = {polymorphic_identity: Entity}
 entity_id = Column(id, Integer, ForeignKey(SimpleEntities.id),
primary_key=True)
 
 
 class Task(Entity):
 __tablename__ = Tasks
 __mapper_args__ = {polymorphic_identity: Task}
 task_id = Column(id, Integer, ForeignKey(Entities.id),
  primary_key=True)
 task_of_id = Column(Integer, ForeignKey(TaskableEntities.id))
 
 
 class ProjectMixin(object):
 #--
 @declared_attr
 def project_id(cls):
 return Column(
 project_id,
 Integer,
 ForeignKey(Projects.id),
 )
 
 #--
 @declared_attr
 def project(cls):
 return relationship(
 Project,
 primaryjoin=\
 cls.__name__ + .project_id==Project.project_id_local,
 post_update=True, # for project itself
 uselist=False
 )
 
 #--
 def __init__(self,
  project=None,
  **kwargs):
 
 self.project = project
 
 
 class TaskableEntity(Entity, ProjectMixin):
 __tablename__ = TaskableEntities
 __mapper_args__ = {polymorphic_identity: TaskableEntity}
 taskableEntity_id = Column(id, Integer, ForeignKey(Entities.id),
primary_key=True)
 tasks = relationship(
 Task,
 primaryjoin=taskableEntity_id==Task.task_of_id,
 backref=task_of,
 post_update=True,
 )
 
 
 class Project(TaskableEntity):
 __tablename__ = Projects
 project_id_local = Column(id, Integer, 
 ForeignKey(TaskableEntities.id),
   primary_key=True)
 __mapper_args__ = {polymorphic_identity: Project,
inherit_condition:
project_id_local==TaskableEntity.taskableEntity_id}
 
 
 engine = create_engine(sqlite:///:memory:)
 Base.metadata.create_all(engine)
 Session = sqlalchemy.orm.sessionmaker(bind=dengine)
 
 session = Session()
 
 
 
 
 The Error message:
 sqlalchemy.exc.CircularDependencyError: Circular dependency detected:
 cycles:
 set([
 Table('TaskableEntities', MetaData(None),
   Column('id', Integer(), ForeignKey('Entities.id'), 
 table=TaskableEntities, primary_key=True, nullable=False),
   Column('project_id', Integer(), ForeignKey('Projects.id'), 
 table=TaskableEntities), schema=None),
 Table('Projects', MetaData(None),
   Column('id', Integer(), ForeignKey('TaskableEntities.id'), 
 table=Projects, primary_key=True, nullable=False), schema=None)]
 ) all edges:
 set(
 [
 (Table('TaskableEntities', MetaData(None),
Column('id', Integer(), ForeignKey('Entities.id'), 
 table=TaskableEntities, primary_key=True, nullable=False),
Column('project_id', Integer(), ForeignKey('Projects.id'), 
 table=TaskableEntities), schema=None),
  Table('Projects', MetaData(None),
 

Re: [sqlalchemy] CircularDependencyError, why?

2011-09-07 Thread Erkan Özgür Yılmaz
Oh, that worked very well, thank you very much...

E.Ozgur Yilmaz
Lead Technical Director
eoyilmaz.blogspot.com



On Wed, Sep 7, 2011 at 8:04 PM, Michael Bayer mike...@zzzcomputing.comwrote:


 On Sep 7, 2011, at 12:36 PM, Erkan Özgür Yılmaz wrote:

 The following gives CircularDependencyError

 where I think there isn't, but you know I don't know that much the
 internals of SQLAlchemy and maybe (and it is a strong possibility) I'm
 wrong. I've ripped of the classes causing the error (copy/paste will
 re-produce the error).


 According to the error message, TaskableEntity has a foreign key to
 Projects and Projects has a foreign key to TaskableEntity, thus creating a
 cycle.  TaskableEntity would appear to have this Project foreign key via the
 ProjectMixin class.So I'd add a use_alter=True to one of those
 ForeignKey objects.






 from sqlalchemy import orm, create_engine
 from sqlalchemy.orm import relationship, synonym, validates
 from sqlalchemy import (Table, Column, ForeignKey, Boolean, Integer,
 String)
 from sqlalchemy.ext.declarative import (declarative_base, synonym_for,
 declared_attr)


 Base = declarative_base()


 
 class SimpleEntity(Base):
 __tablename__ = SimpleEntities
 id = Column(id, Integer, primary_key=True)

 entity_type = Column(db_entity_type, String(128), nullable=False)
 __mapper_args__ = {
 polymorphic_on: entity_type,
 polymorphic_identity: SimpleEntity,
 }

 
 class Entity(SimpleEntity):
 __tablename__ = Entities
 __mapper_args__ = {polymorphic_identity: Entity}
 entity_id = Column(id, Integer, ForeignKey(SimpleEntities.id),
primary_key=True)

 
 class Task(Entity):
 __tablename__ = Tasks
 __mapper_args__ = {polymorphic_identity: Task}
 task_id = Column(id, Integer, ForeignKey(Entities.id),
  primary_key=True)
 task_of_id = Column(Integer, ForeignKey(TaskableEntities.id))

 
 class ProjectMixin(object):
 #--
 @declared_attr
 def project_id(cls):
 return Column(
 project_id,
 Integer,
 ForeignKey(Projects.id),
 )

 #--
 @declared_attr
 def project(cls):
 return relationship(
 Project,
 primaryjoin=\
 cls.__name__ + .project_id==Project.project_id_local,
 post_update=True, # for project itself
 uselist=False
 )

 #--
 def __init__(self,
  project=None,
  **kwargs):

 self.project = project

 
 class TaskableEntity(Entity, ProjectMixin):
 __tablename__ = TaskableEntities
 __mapper_args__ = {polymorphic_identity: TaskableEntity}
 taskableEntity_id = Column(id, Integer, ForeignKey(Entities.id),
primary_key=True)
 tasks = relationship(
 Task,
 primaryjoin=taskableEntity_id==Task.task_of_id,
 backref=task_of,
 post_update=True,
 )

 
 class Project(TaskableEntity):
 __tablename__ = Projects
 project_id_local = Column(id, Integer,
 ForeignKey(TaskableEntities.id),
   primary_key=True)
 __mapper_args__ = {polymorphic_identity: Project,
inherit_condition:
project_id_local==TaskableEntity.taskableEntity_id}


 engine = create_engine(sqlite:///:memory:)
 Base.metadata.create_all(engine)
 Session = sqlalchemy.orm.sessionmaker(bind=dengine)

 session = Session()




 The Error message:
 sqlalchemy.exc.CircularDependencyError: Circular dependency detected:
 cycles:
 set([
 Table('TaskableEntities', MetaData(None),
   Column('id', Integer(), ForeignKey('Entities.id'),
 table=TaskableEntities, primary_key=True, nullable=False),
   Column('project_id', Integer(), ForeignKey('Projects.id'),
 table=TaskableEntities), schema=None),
 Table('Projects', MetaData(None),
   Column('id', Integer(), ForeignKey('TaskableEntities.id'),
 table=Projects, primary_key=True, nullable=False), schema=None)]
 ) all edges:
 set(
 [
 (Table('TaskableEntities', MetaData(None),
Column('id', Integer(), ForeignKey('Entities.id'),
 table=TaskableEntities, primary_key=True, nullable=False),

Re: [sqlalchemy] one-to-many with mixins in inherited classes

2011-09-07 Thread Erkan Özgür Yılmaz
I forgot to say thank you, I've solved it as you suggested and created a
TaskableEntity for task related entities...

E.Ozgur Yilmaz
Lead Technical Director
eoyilmaz.blogspot.com



On Sun, Sep 4, 2011 at 11:35 PM, Michael Bayer mike...@zzzcomputing.comwrote:

 TaskMixin.tasks places a relationship named task_of onto the Task class
 via the backref directive.   Only one relationship of this name can exist on
 the parent class, and a relationship is only configurable against a single
 class.   This single class can be of course a common base for many
 subclasses, but in this case you're attempting to create two task_of
 relationships, one hardwired to TaskableClassA and the other hardwired to
 TaskableClassB.

 It seems likely you'd like task_of to link to both classes and load
 polymorphically - so TaskableClassA and TaskableClassB should both inherit
 from a common base, with no __tablename__, such as TaskableClassBase - that
 class then uses TaskMixin to establish behavior common to both.

 Of course you don't really need the TaskMixin here since it can only be
 used once with that backref on it.

 you can try the modified versions attached - the first uses TaskMixin the
 second removes it.


 --
 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
 sqlalchemy+unsubscr...@googlegroups.com.
 For more options, visit this group at
 http://groups.google.com/group/sqlalchemy?hl=en.





 On Sep 4, 2011, at 3:18 PM, Erkan Özgür Yılmaz wrote:

 from sqlalchemy import Column, ForeignKey, Integer, String
 from sqlalchemy.orm import relationship, validates
 from sqlalchemy.ext import declarative
 from sqlalchemy.ext.declarative import declarative_base, declared_attr

 Base = declarative_base()

 # The Base Class
 
 class SimpleEntity(Base):
 __tablename__ = SimpleEntities
 id = Column(id, Integer, primary_key=True)

 entity_type = Column(db_entity_type, String(128), nullable=False)
 __mapper_args__ = {
 polymorphic_on: entity_type,
 polymorphic_identity: SimpleEntity,
 }

 name = Column(String(256), nullable=False)

 #--
 def __init__(self, name=None, **kwargs):

 self.name = name

 
 class Task(SimpleEntity):
 __tablename__ = Tasks
 task_id = Column(id, Integer, ForeignKey(SimpleEntities.id),
  primary_key=True)
 __mapper_args__ = {polymorphic_identity: Task,
inherit_condition: task_id==SimpleEntity.id}

 task_of_id = Column(Integer,
 ForeignKey(SimpleEntities.id)
 )

 #--
 def __init__(self, task_of=None, **kwargs):
 super(Task, self).__init__(**kwargs)
 self.task_of = task_of

 
 class TaskMixin(object): # The mixin
 def __init__(self, tasks=None, **kwargs):
 if tasks is None:
 tasks = []
 self.tasks = tasks

 #--
 @declared_attr
 def tasks(cls):
 return relationship(
 Task,
 primaryjoin=Tasks.c.task_of_id==SimpleEntities.c.id,
 backref=task_of,
 )


 
 # example class 1 - defining only one class with TaskMixin doesn't create
 # any problem
 class TaskableClassA(SimpleEntity, TaskMixin):
 __tablename__ = TaskableAs
 __mapper_args__ = {polymorphic_identity: TaskableClassA}
 taskableClass_id = Column(id, Integer,
 ForeignKey(SimpleEntities.id),
   primary_key=True)

 #--
 def __init__(self, **kwargs):
 super(SimpleEntity, self).__init__(**kwargs)
 TaskMixin.__init__(self, **kwargs)

 ###
 # example class 2 - which creates the problem
 class TaskableClassB(SimpleEntity, TaskMixin):
 __tablename__ = TaskableBs
 __mapper_args__ = {polymorphic_identity: TaskableClassB}
 taskableClass_id = Column(id, Integer,
 ForeignKey(SimpleEntities.id),
   primary_key=True)

 #--
 def __init__(self, **kwargs):
 super(SimpleEntity, self).__init__(**kwargs)
 TaskMixin.__init__(self, **kwargs)

 a_taskable_object = TaskableClassA(name=taskable test object)
 task1 = Task(name=Test Task1, 

Re: [sqlalchemy] relationship trouble when using UsageRecipes/Views

2011-09-07 Thread werner

On 09/07/2011 05:58 PM, Michael Bayer wrote:

On Sep 7, 2011, at 11:53 AM, werner wrote:


Michael,

On 09/07/2011 05:10 PM, Michael Bayer wrote:

On Sep 7, 2011, at 4:40 AM, werner wrote:


or:
Region_LV.language = sao.relationship('Language',
   primaryjoin=Country_LV.fk_language_id==Language.id,
   foreign_keys=[Country_LV.__table__.c.fk_language_id])

I get:
sqlalchemy.exc.ArgumentError: Column-based expression object expected for argument 
'foreign_keys'; got: 'Country_LV.fk_language_id', typetype 'str'

this one above is the one that doesn't make any sense (also its probably how 
the relationship should be set up).

Sorry that was a copy/paste error on my part.

Clearly x.__table__.c.somename is a Column object, not a string.   
Something is up with what you're sending it. I've tried to reproduce with 
no luck.  See attached.   Also I don't even need the primaryjoin/foreignkeys if 
the originating Table upon which the view is based has foreign keys to the 
parent.


The additional column is in my case added in to the view as the base table 
doesn't have it and it is filled by the stored procedure (which combines the 
base table plus the localized table ...) , i.e.:

def view(name, metadata, selectable):
t = table(name)

for c in selectable.c:
c._make_proxy(t)

lc = sasql.column(stuff_id, sa.Integer)
t.append_column(lc)

But what I had overlooked/forgotten to include was the __mapper_args__ = 
{primary_key:__table__.c.id} line.

After adding this the relationship as shown at the beginning it works.

well that's also strange.   If the mapper is not able to find a primary key, 
the error is very clear:

sqlalchemy.exc.ArgumentError: Mapper Mapper|MSView|msview could not assemble 
any primary key columns for mapped table 'msview'

not sure why that isn't what you were seeing.
Just tried to step back and see what other change I have done which 
would explain my problem, but I missed to commit to source control 
(didn't bother as it didn't work - should have known better).


Werner

Werner


--
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 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



[sqlalchemy] order_by on model property

2011-09-07 Thread Tim Black
What is the right way to use .order_by() to order by the values returned
by a model object property?  My model object is like this:

class Project(DeclarativeBase):
__tablename__ = 'project'
id = Column(Integer, primary_key=True)
...
@property
def remainderDue(self):
return self.totalDue - float(self.totalPaid)

The query I'm trying to run is:

projects =
DBSession.query(model.Project).order_by(desc(model.Project.remainderDue))

This returns the following error:

Module sqlalchemy.sql.expression:1279 in _literal_as_text
ArgumentError: SQL expression object or string expected.

Tim


-- 
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 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] order_by on model property

2011-09-07 Thread Michael Bayer
You'd use a hybrid for this case, and due to the usage of float() you'd 
probably want to produce a separate @expression that doesn't rely on a Python 
function.

Docs and examples for hybrid are at  
http://www.sqlalchemy.org/docs/orm/extensions/hybrid.html

Separate @expression:

http://www.sqlalchemy.org/docs/orm/extensions/hybrid.html#defining-expression-behavior-distinct-from-attribute-behavior

The float() call in SQL would likely be using CAST, so take a look at 
http://www.sqlalchemy.org/docs/core/expression_api.html?highlight=cast#sqlalchemy.sql.expression.cast
 for that.



On Sep 7, 2011, at 2:27 PM, Tim Black wrote:

 What is the right way to use .order_by() to order by the values returned by a 
 model object property?  My model object is like this:
 
 class Project(DeclarativeBase):
 __tablename__ = 'project'
 id = Column(Integer, primary_key=True)
 ...
 @property
 def remainderDue(self):
 return self.totalDue - float(self.totalPaid)
 
 The query I'm trying to run is:
 
 projects = 
 DBSession.query(model.Project).order_by(desc(model.Project.remainderDue))
 
 This returns the following error:
 
 Module sqlalchemy.sql.expression:1279 in _literal_as_text
 ArgumentError: SQL expression object or string expected.
 
 Tim
 
 
 
 -- 
 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 
 sqlalchemy+unsubscr...@googlegroups.com.
 For more options, visit this group at 
 http://groups.google.com/group/sqlalchemy?hl=en.

-- 
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 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] subqueryload for a ColumnProperty?

2011-09-07 Thread Sumeet Agarwal
Still getting the hang of SQLAlchemy terminology.

I didn't mean a simple deferred() column, but a deferred column_property()
which defines a scalar select(). Like in the example here
http://www.sqlalchemy.org/docs/orm/mapper_config.html#sql-expressions-as-mapped-attributes
.

My goal is to, instead of including a correlated subquery in the SELECT. The
column_property looks like

Customer.num_orders = orm.column_property(
select([func.count(Order.id)])\
.where(Order.customer_id == Customer.id)\
.correlate(Customer.__table__),
deferred=True
)


I'd rather do a separate query to load num_orders, rather than getting it
lazily or by using undefer(). It almost feels like I might want to define
num_orders as a relationship somehow? I dunno if what I would like to do
maps cleanly to a SQLAlchemy pattern.

On Wed, Sep 7, 2011 at 7:51 AM, Michael Bayer mike...@zzzcomputing.comwrote:

 For a deferred() itself, we don't have an option that does this.Though
 this is an unusual request.   If you definitely want the deferreds to load,
 what's the issue having them render inline into the original query ?The
 advantage to subqueryload is primarily in that it loads multiple rows per
 parent object efficiently, without re-fetching the full parent row many
 times,  or needing to use a less efficient OUTER JOIN.   A deferred is
 always one row per parent - and no join is needed anyway.




 On Sep 6, 2011, at 6:49 PM, Sumeet Agarwal wrote:

  I have a collection of deferred `ColumnProperty`s that I'd like to
  start loading in subsequent queries. I know you can get this to happen
  on the first access of a `ColumnProperty` that is deferred, but I
  wonder if there's any way to specify this in the query.
 
  For relationships, `joinedload[_all()]` has a counterpart
  `subqueryload[_all()]`. Is there nothing similar we can do for
  `ColumnProperty`?
 
  --
  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
 sqlalchemy+unsubscr...@googlegroups.com.
  For more options, visit this group at
 http://groups.google.com/group/sqlalchemy?hl=en.
 

 --
 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
 sqlalchemy+unsubscr...@googlegroups.com.
 For more options, visit this group at
 http://groups.google.com/group/sqlalchemy?hl=en.



-- 
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 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] subqueryload for a ColumnProperty?

2011-09-07 Thread Michael Bayer

On Sep 7, 2011, at 5:09 PM, Sumeet Agarwal wrote:

 Still getting the hang of SQLAlchemy terminology.
 
 I didn't mean a simple deferred() column, but a deferred column_property() 
 which defines a scalar select(). Like in the example here 
 http://www.sqlalchemy.org/docs/orm/mapper_config.html#sql-expressions-as-mapped-attributes.
 
 My goal is to, instead of including a correlated subquery in the SELECT. The 
 column_property looks like

My goal is to..., missing a verb there :). If it were me, I'd think 
you're asking to unwrap the correlated subquery into a plain JOIN.   Since that 
works more efficiently.   

 
 I'd rather do a separate query to load num_orders, rather than getting it 
 lazily or by using undefer(). It almost feels like I might want to define 
 num_orders as a relationship somehow? I dunno if what I would like to do maps 
 cleanly to a SQLAlchemy pattern.

Using relationship() is kind of the old school approach, but yup I think that 
actually allows you to get exactly subqueryload() for an attribute, so good 
idea !  a rare moment that SQLAlchemy amazes even me.   here's that since its 
faster for me to just illustrate

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base= declarative_base()

class Customer(Base):
__tablename__ = 'customer'
id = Column(Integer, primary_key=True)
orders = relationship(Order)

@property
def num_orders(self):
return self._num_orders.count if self._num_orders else 0

class Order(Base):
__tablename__ = 'order'
id = Column(Integer, primary_key=True)
customer_id = Column(Integer, ForeignKey('customer.id'))

class OrderCount(object):
pass
order_counts = select([Order.customer_id, 
func.count(Order.id).label('count')]).\
group_by(Order.customer_id).alias()

mapper(
OrderCount, 
order_counts,
primary_key=order_counts.c.customer_id
)

Customer._num_orders = relationship(OrderCount, uselist=False)

e = create_engine('sqlite://', echo=True)

Base.metadata.create_all(e)

s = Session(e)
s.add_all([
Customer(orders=[Order(), Order(), Order()]),
Customer(orders=[Order(), Order()]),
Customer(orders=[]),
])
s.commit()

for c in s.query(Customer).options(subqueryload(_num_orders)):
print c.id, c.num_orders










 
 On Wed, Sep 7, 2011 at 7:51 AM, Michael Bayer mike...@zzzcomputing.com 
 wrote:
 For a deferred() itself, we don't have an option that does this.Though 
 this is an unusual request.   If you definitely want the deferreds to load, 
 what's the issue having them render inline into the original query ?The 
 advantage to subqueryload is primarily in that it loads multiple rows per 
 parent object efficiently, without re-fetching the full parent row many 
 times,  or needing to use a less efficient OUTER JOIN.   A deferred is always 
 one row per parent - and no join is needed anyway.
 
 
 
 
 On Sep 6, 2011, at 6:49 PM, Sumeet Agarwal wrote:
 
  I have a collection of deferred `ColumnProperty`s that I'd like to
  start loading in subsequent queries. I know you can get this to happen
  on the first access of a `ColumnProperty` that is deferred, but I
  wonder if there's any way to specify this in the query.
 
  For relationships, `joinedload[_all()]` has a counterpart
  `subqueryload[_all()]`. Is there nothing similar we can do for
  `ColumnProperty`?
 
  --
  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 
  sqlalchemy+unsubscr...@googlegroups.com.
  For more options, visit this group at 
  http://groups.google.com/group/sqlalchemy?hl=en.
 
 
 --
 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 
 sqlalchemy+unsubscr...@googlegroups.com.
 For more options, visit this group at 
 http://groups.google.com/group/sqlalchemy?hl=en.
 
 
 
 -- 
 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 
 sqlalchemy+unsubscr...@googlegroups.com.
 For more options, visit this group at 
 http://groups.google.com/group/sqlalchemy?hl=en.

-- 
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 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Question on session.expunge.all()

2011-09-07 Thread Vlad K.


Great, thanks!


.oO V Oo.


On 09/06/2011 04:48 PM, Michael Bayer wrote:

On Sep 6, 2011, at 10:40 AM, Vlad K. wrote:


I have a products database which is daily syncronized with an external source 
via a csv file. There are several thousand rows in question. The 
synchronization does two things:

1. Update only price if changed for existing products
2. Insert new products if they don't exist with all fields from csv

But basically, for each row in the csv, after the row is processed (one of the 
above two things is done), I don't need the object in session anymore. Memory 
and performance are of course an issue, and I can't find a way to test memory 
consumption with or without expunge_all() so my questions are:

1. Do I need to session.expunge_all() after each csv row is processed, or are 
they automatically garbage collected?
2. Is there any significant overhead inherent in expunge_all() that I'm not 
seeing right now?

Performance-wise, it seems the task is complete in more or less same time with 
or without expunge_all()

In modern SQLAlchemy, the Session maintains only weak references to objects that are 
clean, that is, are persistent in the database and have no pending changes to 
be flushed.As all references to them are lost, they are garbage collected by the 
Python interpreter.Note that objects are strongly referenced when they are present in 
the collection or attribute of a parent object, until that parent is also garbage 
collected.There is an overhead to process which occurs when the object is 
dereferenced and removed from the session (weakref callbacks handle the accounting).  But 
calling expunge_all() probably isn't doing much here as the objects are likely being 
cleaned out in the same way regardless.


While I'm at it, I also need to delete rows in the database that do not have 
corresponding row in the csv file (say linked by csv_key field), the first 
solution that comes to mind is building a list of keys in the csv file (few 
thousand keys) and then doing:

session.query(Product).filter(not_(Product.product_id.in_(csv_keys))).delete()

I believe there is less overhead in sending such a large (but single!) query to 
the database and leaving it to determine what to delete by itself, than 
selecting each row in the database and checking if its csv_key exists in the 
csv_keys list on the application side and then issuing delete statements for 
rows that matched the criteria. Am I wrong?

That's definitely a dramatically faster way to do things, rather than to load each record 
individually and mark as deleted - it's the primary reason delete() and update() are 
there.   You'll probably want to send False as the value of 
synchronize_session to the delete() call so that it doesn't go through the effort of 
locating local records that were affected (unless you need that feature).



--
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 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



[sqlalchemy] PyODBCConnector, possible wrong assumption re Unicode in bind parameters

2011-09-07 Thread Victor Olex
Using SQLAlchemy 0.7.2 with pyodbc 2.1.9, FreeTDS 0.91, unixODBC 2.3.0
and SQL Server 2008 I find that the supports_unicode_bind may be
incorrectly set to False in the PyODBCConnector.initialize. As a
result a unicode parameter gets encoded as str and to make matters
worse the value gets silently overridden with empty Unicode string
(u'').

Consider a simple table (IDENTITY, NTEXT, VARCHAR(255)) with one
record:
ID, col1, col2
1, 'Łódź', 'abc'.

We will update existing value in col1 to 'Łódź!'.

 from sqlalchemy import Column, Sequence, create_engine
 from sqlalchemy.types import UnicodeText, Integer, VARCHAR
 from sqlalchemy.orm import sessionmaker
 from sqlalchemy.ext.declarative import declarative_base

 Base = declarative_base()
 metadata = Base.metadata

 class A(Base):
... __tablename__ = 'A'
... id = Column(u'ID', Integer, Sequence('A_PK'),
primary_key=True)
... col1 = Column(u'col1', UnicodeText())
... col2 = Column(u'col2', VARCHAR(255))
...
 e = 
 create_engine('mssql://user:pwd@sqlserverhost:2431/MYDB?driver=FreeTDSTDS_Version=8.0',
  echo=True)
 Session=sessionmaker()
 s = Session(bind=e)
 lodz = u'\u0141\xf3d\u017a'
 oa = s.query(A).one()
2011-09-07 17:22:25,260 INFO sqlalchemy.engine.base.Engine SELECT
user_name() as user_name;
2011-09-07 17:22:25,261 INFO sqlalchemy.engine.base.Engine ()
2011-09-07 17:22:25,270 INFO sqlalchemy.engine.base.Engine
SELECT default_schema_name FROM
sys.database_principals
WHERE name = ?
AND type = 'S'

2011-09-07 17:22:25,271 INFO sqlalchemy.engine.base.Engine
(u'SPEED_IT',)
2011-09-07 17:22:25,291 INFO sqlalchemy.engine.base.Engine BEGIN
(implicit)
2011-09-07 17:22:25,292 INFO sqlalchemy.engine.base.Engine SELECT [A].
[ID]
AS [A_ID], [A].col1 AS [A_col1], [A].col2 AS [A_col2]
FROM [A]
2011-09-07 17:22:25,292 INFO sqlalchemy.engine.base.Engine ()
 oa.col1
u'\u0141\xf3d\u017a'
 oa.col2
'abc'
 oa.col1 = u'\u0141\xf3d\u017a!'
 s.commit()
2011-09-07 17:23:17,016 INFO sqlalchemy.engine.base.Engine UPDATE [A]
SET
col1=? WHERE [A].[ID] = ?
2011-09-07 17:23:17,016 INFO sqlalchemy.engine.base.Engine
('\xc5\x81\xc3\xb3d\xc5\xba!', 1)
2011-09-07 17:23:17,061 INFO sqlalchemy.engine.base.Engine COMMIT
 oa.col1
2011-09-07 17:23:24,226 INFO sqlalchemy.engine.base.Engine BEGIN
(implicit)
2011-09-07 17:23:24,227 INFO sqlalchemy.engine.base.Engine SELECT [A].
[ID]
AS [A_ID], [A].col1 AS [A_col1], [A].col2 AS [A_col2]
FROM [A]
WHERE [A].[ID] = ?
2011-09-07 17:23:24,227 INFO sqlalchemy.engine.base.Engine (1,)
u''

Using a patched initialize method with the supports_unicode_binds line
#110 removed the parameter gets passed as Unicode and the database
updates correctly as does the in memory object. Different version
combinations of pyodbc, FreeTDS and SQL may likely yield a different
result so unless a deterministic factor is found I would like to
propose adding parameter bind_unicode to dialect class and connection
url.

Regards and respect,

Victor Olex
http://linkedin.com/in/victorolex
http://twitter.com/agilevic

-- 
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 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] PyODBCConnector, possible wrong assumption re Unicode in bind parameters

2011-09-07 Thread Michael Bayer
I can't actually make that string work at all with FreeTDS, but I am on 0.82.   
If I turn on Python unicodes with FreeTDS 0.82, which until recently was the 
FreeTDS release for years, everything breaks immediately - the CREATE TABLE 
statements won't even work, as you can see below just the strings u'A', u'dbo' 
blow it up:

sqlalchemy.exc.DBAPIError: (Error) ('HY004', '[HY004] [FreeTDS][SQL 
Server]Invalid data type (0) (SQLBindParameter)') 'SELECT 
[COLUMNS_1].[TABLE_SCHEMA], [COLUMNS_1].[TABLE_NAME], 
[COLUMNS_1].[COLUMN_NAME], [COLUMNS_1].[IS_NULLABLE], [COLUMNS_1].[DATA_TYPE], 
[COLUMNS_1].[ORDINAL_POSITION], [COLUMNS_1].[CHARACTER_MAXIMUM_LENGTH], 
[COLUMNS_1].[NUMERIC_PRECISION], [COLUMNS_1].[NUMERIC_SCALE], 
[COLUMNS_1].[COLUMN_DEFAULT], [COLUMNS_1].[COLLATION_NAME] \nFROM 
[INFORMATION_SCHEMA].[COLUMNS] AS [COLUMNS_1] \nWHERE [COLUMNS_1].[TABLE_NAME] 
= ? AND [COLUMNS_1].[TABLE_SCHEMA] = ?' (u'A', u'dbo')

You can be assured that the code you see in pyodbc.py is not by accident - 
dozens of hours went into making this thing work with Pyodbc + FreeTDS, and I 
would vastly prefer that it just accept u'' strings - but on 0.82, it does not. 
  

So I'm just thrilled that A. FreeTDS has apparently broken compatibility with 
all of that effort and B. I can't barely even get FreeTDS 0.91 to work, nor can 
I C. get pyodbc 2.1.9 to build.

FreeTDS 0.91 doesn't appear to work for me period.   Your exact query *does* 
work, but if I try to create or drop tables, I get either:

MemoryError:

or an erroneously blank result set, when trying to query from 
INFORMATION_SCHEMA.COLUMNS, depending on how I set up that flag.

So I can't really test or do anything with FreeTDS 0.91. 

Can you please try a metadata.drop_all() and metadata.create_all() for me 
and tell me if it works as expected, both with and without the patch ?

Your flag is not a big deal but the much more ominous issue is a whole new set 
of users installing 0.91 and not being able to do simple checks for table 
existence.

What OS you're on would be helpful here as well, as it appears I'm at least 
going to have to test from a linux VM to a windows VM to even get this going.




On Sep 7, 2011, at 7:12 PM, Victor Olex wrote:

 Using SQLAlchemy 0.7.2 with pyodbc 2.1.9, FreeTDS 0.91, unixODBC 2.3.0
 and SQL Server 2008 I find that the supports_unicode_bind may be
 incorrectly set to False in the PyODBCConnector.initialize. As a
 result a unicode parameter gets encoded as str and to make matters
 worse the value gets silently overridden with empty Unicode string
 (u'').
 
 Consider a simple table (IDENTITY, NTEXT, VARCHAR(255)) with one
 record:
 ID, col1, col2
 1, 'Łódź', 'abc'.
 
 We will update existing value in col1 to 'Łódź!'.
 
 from sqlalchemy import Column, Sequence, create_engine
 from sqlalchemy.types import UnicodeText, Integer, VARCHAR
 from sqlalchemy.orm import sessionmaker
 from sqlalchemy.ext.declarative import declarative_base
 
 Base = declarative_base()
 metadata = Base.metadata
 
 class A(Base):
 ... __tablename__ = 'A'
 ... id = Column(u'ID', Integer, Sequence('A_PK'),
 primary_key=True)
 ... col1 = Column(u'col1', UnicodeText())
 ... col2 = Column(u'col2', VARCHAR(255))
 ...
 e = 
 create_engine('mssql://user:pwd@sqlserverhost:2431/MYDB?driver=FreeTDSTDS_Version=8.0',
  echo=True)
 Session=sessionmaker()
 s = Session(bind=e)
 lodz = u'\u0141\xf3d\u017a'
 oa = s.query(A).one()
 2011-09-07 17:22:25,260 INFO sqlalchemy.engine.base.Engine SELECT
 user_name() as user_name;
 2011-09-07 17:22:25,261 INFO sqlalchemy.engine.base.Engine ()
 2011-09-07 17:22:25,270 INFO sqlalchemy.engine.base.Engine
SELECT default_schema_name FROM
sys.database_principals
WHERE name = ?
AND type = 'S'
 
 2011-09-07 17:22:25,271 INFO sqlalchemy.engine.base.Engine
 (u'SPEED_IT',)
 2011-09-07 17:22:25,291 INFO sqlalchemy.engine.base.Engine BEGIN
 (implicit)
 2011-09-07 17:22:25,292 INFO sqlalchemy.engine.base.Engine SELECT [A].
 [ID]
 AS [A_ID], [A].col1 AS [A_col1], [A].col2 AS [A_col2]
 FROM [A]
 2011-09-07 17:22:25,292 INFO sqlalchemy.engine.base.Engine ()
 oa.col1
 u'\u0141\xf3d\u017a'
 oa.col2
 'abc'
 oa.col1 = u'\u0141\xf3d\u017a!'
 s.commit()
 2011-09-07 17:23:17,016 INFO sqlalchemy.engine.base.Engine UPDATE [A]
 SET
 col1=? WHERE [A].[ID] = ?
 2011-09-07 17:23:17,016 INFO sqlalchemy.engine.base.Engine
 ('\xc5\x81\xc3\xb3d\xc5\xba!', 1)
 2011-09-07 17:23:17,061 INFO sqlalchemy.engine.base.Engine COMMIT
 oa.col1
 2011-09-07 17:23:24,226 INFO sqlalchemy.engine.base.Engine BEGIN
 (implicit)
 2011-09-07 17:23:24,227 INFO sqlalchemy.engine.base.Engine SELECT [A].
 [ID]
 AS [A_ID], [A].col1 AS [A_col1], [A].col2 AS [A_col2]
 FROM [A]
 WHERE [A].[ID] = ?
 2011-09-07 17:23:24,227 INFO sqlalchemy.engine.base.Engine (1,)
 u''
 
 Using a patched initialize method with the supports_unicode_binds line
 #110 removed the parameter gets passed as Unicode and the database
 updates correctly as does the in 

Re: [sqlalchemy] PyODBCConnector, possible wrong assumption re Unicode in bind parameters

2011-09-07 Thread Michael Bayer
The ticket for SQLAlchemy is:

http://www.sqlalchemy.org/trac/ticket/2273

For Pyodbc I've opened:

http://code.google.com/p/pyodbc/issues/detail?id=209
http://code.google.com/p/pyodbc/issues/detail?id=210

as you can see, issue 210 is quite serious.Would be curious what results 
you get for the script there.



On Sep 7, 2011, at 11:25 PM, Michael Bayer wrote:

 I can't actually make that string work at all with FreeTDS, but I am on 0.82. 
   If I turn on Python unicodes with FreeTDS 0.82, which until recently was 
 the FreeTDS release for years, everything breaks immediately - the CREATE 
 TABLE statements won't even work, as you can see below just the strings u'A', 
 u'dbo' blow it up:
 
 sqlalchemy.exc.DBAPIError: (Error) ('HY004', '[HY004] [FreeTDS][SQL 
 Server]Invalid data type (0) (SQLBindParameter)') 'SELECT 
 [COLUMNS_1].[TABLE_SCHEMA], [COLUMNS_1].[TABLE_NAME], 
 [COLUMNS_1].[COLUMN_NAME], [COLUMNS_1].[IS_NULLABLE], 
 [COLUMNS_1].[DATA_TYPE], [COLUMNS_1].[ORDINAL_POSITION], 
 [COLUMNS_1].[CHARACTER_MAXIMUM_LENGTH], [COLUMNS_1].[NUMERIC_PRECISION], 
 [COLUMNS_1].[NUMERIC_SCALE], [COLUMNS_1].[COLUMN_DEFAULT], 
 [COLUMNS_1].[COLLATION_NAME] \nFROM [INFORMATION_SCHEMA].[COLUMNS] AS 
 [COLUMNS_1] \nWHERE [COLUMNS_1].[TABLE_NAME] = ? AND 
 [COLUMNS_1].[TABLE_SCHEMA] = ?' (u'A', u'dbo')
 
 You can be assured that the code you see in pyodbc.py is not by accident - 
 dozens of hours went into making this thing work with Pyodbc + FreeTDS, and I 
 would vastly prefer that it just accept u'' strings - but on 0.82, it does 
 not.   
 
 So I'm just thrilled that A. FreeTDS has apparently broken compatibility with 
 all of that effort and B. I can't barely even get FreeTDS 0.91 to work, nor 
 can I C. get pyodbc 2.1.9 to build.
 
 FreeTDS 0.91 doesn't appear to work for me period.   Your exact query *does* 
 work, but if I try to create or drop tables, I get either:
 
 MemoryError:
 
 or an erroneously blank result set, when trying to query from 
 INFORMATION_SCHEMA.COLUMNS, depending on how I set up that flag.
 
 So I can't really test or do anything with FreeTDS 0.91. 
 
 Can you please try a metadata.drop_all() and metadata.create_all() for me 
 and tell me if it works as expected, both with and without the patch ?
 
 Your flag is not a big deal but the much more ominous issue is a whole new 
 set of users installing 0.91 and not being able to do simple checks for table 
 existence.
 
 What OS you're on would be helpful here as well, as it appears I'm at least 
 going to have to test from a linux VM to a windows VM to even get this going.
 
 
 
 
 On Sep 7, 2011, at 7:12 PM, Victor Olex wrote:
 
 Using SQLAlchemy 0.7.2 with pyodbc 2.1.9, FreeTDS 0.91, unixODBC 2.3.0
 and SQL Server 2008 I find that the supports_unicode_bind may be
 incorrectly set to False in the PyODBCConnector.initialize. As a
 result a unicode parameter gets encoded as str and to make matters
 worse the value gets silently overridden with empty Unicode string
 (u'').
 
 Consider a simple table (IDENTITY, NTEXT, VARCHAR(255)) with one
 record:
 ID, col1, col2
 1, 'Łódź', 'abc'.
 
 We will update existing value in col1 to 'Łódź!'.
 
 from sqlalchemy import Column, Sequence, create_engine
 from sqlalchemy.types import UnicodeText, Integer, VARCHAR
 from sqlalchemy.orm import sessionmaker
 from sqlalchemy.ext.declarative import declarative_base
 
 Base = declarative_base()
 metadata = Base.metadata
 
 class A(Base):
 ... __tablename__ = 'A'
 ... id = Column(u'ID', Integer, Sequence('A_PK'),
 primary_key=True)
 ... col1 = Column(u'col1', UnicodeText())
 ... col2 = Column(u'col2', VARCHAR(255))
 ...
 e = 
 create_engine('mssql://user:pwd@sqlserverhost:2431/MYDB?driver=FreeTDSTDS_Version=8.0',
  echo=True)
 Session=sessionmaker()
 s = Session(bind=e)
 lodz = u'\u0141\xf3d\u017a'
 oa = s.query(A).one()
 2011-09-07 17:22:25,260 INFO sqlalchemy.engine.base.Engine SELECT
 user_name() as user_name;
 2011-09-07 17:22:25,261 INFO sqlalchemy.engine.base.Engine ()
 2011-09-07 17:22:25,270 INFO sqlalchemy.engine.base.Engine
   SELECT default_schema_name FROM
   sys.database_principals
   WHERE name = ?
   AND type = 'S'
 
 2011-09-07 17:22:25,271 INFO sqlalchemy.engine.base.Engine
 (u'SPEED_IT',)
 2011-09-07 17:22:25,291 INFO sqlalchemy.engine.base.Engine BEGIN
 (implicit)
 2011-09-07 17:22:25,292 INFO sqlalchemy.engine.base.Engine SELECT [A].
 [ID]
 AS [A_ID], [A].col1 AS [A_col1], [A].col2 AS [A_col2]
 FROM [A]
 2011-09-07 17:22:25,292 INFO sqlalchemy.engine.base.Engine ()
 oa.col1
 u'\u0141\xf3d\u017a'
 oa.col2
 'abc'
 oa.col1 = u'\u0141\xf3d\u017a!'
 s.commit()
 2011-09-07 17:23:17,016 INFO sqlalchemy.engine.base.Engine UPDATE [A]
 SET
 col1=? WHERE [A].[ID] = ?
 2011-09-07 17:23:17,016 INFO sqlalchemy.engine.base.Engine
 ('\xc5\x81\xc3\xb3d\xc5\xba!', 1)
 2011-09-07 17:23:17,061 INFO sqlalchemy.engine.base.Engine COMMIT
 oa.col1
 2011-09-07 17:23:24,226 INFO sqlalchemy.engine.base.Engine BEGIN