sqlalchemy-tickets Mailing List for SQLAlchemy (Page 80)
Brought to you by:
zzzeek
You can subscribe to this list here.
| 2006 |
Jan
|
Feb
|
Mar
(174) |
Apr
(50) |
May
(71) |
Jun
(129) |
Jul
(113) |
Aug
(141) |
Sep
(82) |
Oct
(142) |
Nov
(97) |
Dec
(72) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2007 |
Jan
(159) |
Feb
(213) |
Mar
(156) |
Apr
(151) |
May
(58) |
Jun
(166) |
Jul
(296) |
Aug
(198) |
Sep
(89) |
Oct
(133) |
Nov
(150) |
Dec
(122) |
| 2008 |
Jan
(144) |
Feb
(65) |
Mar
(71) |
Apr
(69) |
May
(143) |
Jun
(111) |
Jul
(113) |
Aug
(159) |
Sep
(81) |
Oct
(135) |
Nov
(107) |
Dec
(200) |
| 2009 |
Jan
(168) |
Feb
(109) |
Mar
(141) |
Apr
(128) |
May
(119) |
Jun
(132) |
Jul
(136) |
Aug
(154) |
Sep
(151) |
Oct
(181) |
Nov
(223) |
Dec
(169) |
| 2010 |
Jan
(103) |
Feb
(209) |
Mar
(201) |
Apr
(183) |
May
(134) |
Jun
(113) |
Jul
(110) |
Aug
(159) |
Sep
(138) |
Oct
(96) |
Nov
(116) |
Dec
(94) |
| 2011 |
Jan
(97) |
Feb
(188) |
Mar
(157) |
Apr
(158) |
May
(118) |
Jun
(102) |
Jul
(137) |
Aug
(113) |
Sep
(104) |
Oct
(108) |
Nov
(91) |
Dec
(162) |
| 2012 |
Jan
(189) |
Feb
(136) |
Mar
(153) |
Apr
(142) |
May
(90) |
Jun
(141) |
Jul
(67) |
Aug
(77) |
Sep
(113) |
Oct
(68) |
Nov
(101) |
Dec
(122) |
| 2013 |
Jan
(60) |
Feb
(77) |
Mar
(77) |
Apr
(129) |
May
(189) |
Jun
(155) |
Jul
(106) |
Aug
(123) |
Sep
(53) |
Oct
(142) |
Nov
(78) |
Dec
(102) |
| 2014 |
Jan
(143) |
Feb
(93) |
Mar
(35) |
Apr
(26) |
May
(27) |
Jun
(41) |
Jul
(45) |
Aug
(27) |
Sep
(37) |
Oct
(24) |
Nov
(22) |
Dec
(20) |
| 2015 |
Jan
(17) |
Feb
(15) |
Mar
(34) |
Apr
(55) |
May
(33) |
Jun
(31) |
Jul
(27) |
Aug
(17) |
Sep
(22) |
Oct
(26) |
Nov
(27) |
Dec
(22) |
| 2016 |
Jan
(20) |
Feb
(24) |
Mar
(23) |
Apr
(13) |
May
(17) |
Jun
(14) |
Jul
(31) |
Aug
(23) |
Sep
(24) |
Oct
(31) |
Nov
(23) |
Dec
(16) |
| 2017 |
Jan
(24) |
Feb
(20) |
Mar
(27) |
Apr
(24) |
May
(28) |
Jun
(18) |
Jul
(18) |
Aug
(23) |
Sep
(30) |
Oct
(17) |
Nov
(12) |
Dec
(12) |
| 2018 |
Jan
(27) |
Feb
(23) |
Mar
(13) |
Apr
(19) |
May
(21) |
Jun
(29) |
Jul
(11) |
Aug
(22) |
Sep
(14) |
Oct
(9) |
Nov
(24) |
Dec
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-28 21:33:21
|
#2811: cannot change column.key in reflect event without corrupting primary key
-----------------------------------+----------------------------------
Reporter: zzzeek | Owner: zzzeek
Type: defect | Status: closed
Priority: highest | Milestone: 0.8.xx
Component: schema | Severity: minor - half an hour
Resolution: fixed | Keywords:
Progress State: completed/closed |
-----------------------------------+----------------------------------
Changes (by zzzeek):
* status: new => closed
* resolution: => fixed
* severity: major - 1-3 hours => minor - half an hour
* status_field: in queue => completed/closed
Comment:
r2008344aab70a9152ed23adb2b4c768fcb6103a4
r573b542747103cd427db6770d29441dade4a278e 0.8
rfe66951f5de6a2b201dc3ecc2261f4f8b8888e9f
r97168dbf69f8aa21de2e764a4a4993215cb9b726 master
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2811#comment:1>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-28 16:43:44
|
#2812: has_table/drop/etc. not really checking the "quote" flag for an uppercase
engine and it probably cant
-----------------------------------+-------------------------------
Reporter: zzzeek | Owner: zzzeek
Type: defect | Status: closed
Priority: high | Milestone: 0.9.0
Component: schema | Severity: major - 1-3 hours
Resolution: fixed | Keywords:
Progress State: completed/closed |
-----------------------------------+-------------------------------
Changes (by zzzeek):
* status: new => closed
* status_field: in queue => completed/closed
* resolution: => fixed
* milestone: 0.8.xx => 0.9.0
Comment:
the quoted_name workaround is possible to use in 0.8, so this doesn't need
to be backported.
the primary merge is in r031ef0807838842a827135dbace760.
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2812#comment:2>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-28 11:29:27
|
#2813: Buglette with annotated join condition
------------------------------+----------------------------------
Reporter: dairiki | Owner: zzzeek
Type: defect | Status: new
Priority: high | Milestone: 0.8.xx
Component: orm | Severity: minor - half an hour
Resolution: | Keywords:
Progress State: needs tests |
------------------------------+----------------------------------
Comment (by dairiki):
Thanks Mike.
I've tried the above patch on rel_0_8. It does appear to fix the problem
(and the tests pass here too).
(Here's your patch adapted for rel_0_8. It's on util.py rather than
elements.py.)
{{{#!patch
diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py
index 61730f1..2799d8c 100644
--- a/lib/sqlalchemy/sql/util.py
+++ b/lib/sqlalchemy/sql/util.py
@@ -497,7 +497,7 @@ class Annotated(object):
class AnnotatedColumnElement(Annotated):
def __init__(self, element, values):
Annotated.__init__(self, element, values)
- for attr in ('name', 'key'):
+ for attr in ('name', 'key', 'table'):
if self.__dict__.get(attr, False) is None:
self.__dict__.pop(attr)
@@ -512,6 +512,10 @@ class AnnotatedColumnElement(Annotated):
return self._Annotated__element.key
@util.memoized_property
+ def table(self):
+ return self._Annotated__element.table
+
+ @util.memoized_property
def info(self):
return self._Annotated__element.info
}}}
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2813#comment:4>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-27 18:38:42
|
#2813: Buglette with annotated join condition
------------------------------+----------------------------------
Reporter: dairiki | Owner: zzzeek
Type: defect | Status: new
Priority: high | Milestone: 0.8.xx
Component: orm | Severity: minor - half an hour
Resolution: | Keywords:
Progress State: needs tests |
------------------------------+----------------------------------
Changes (by zzzeek):
* priority: lowest => high
* severity: no triage selected yet => minor - half an hour
* status_field: awaiting triage => needs tests
Comment:
OK tests pass with that I can go with that.
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2813#comment:3>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-27 18:37:23
|
#2813: Buglette with annotated join condition
----------------------------------+------------------------------------
Reporter: dairiki | Owner: zzzeek
Type: defect | Status: new
Priority: lowest | Milestone: 0.8.xx
Component: orm | Severity: no triage selected yet
Resolution: | Keywords:
Progress State: awaiting triage |
----------------------------------+------------------------------------
Comment (by zzzeek):
well I guess we can do this, seems to be an approach we're taking already:
{{{
#!diff
diff --git a/lib/sqlalchemy/sql/elements.py
b/lib/sqlalchemy/sql/elements.py
index 17fb406..4263e82 100644
--- a/lib/sqlalchemy/sql/elements.py
+++ b/lib/sqlalchemy/sql/elements.py
@@ -2355,7 +2355,7 @@ class AnnotatedColumnElement(Annotated):
def __init__(self, element, values):
Annotated.__init__(self, element, values)
ColumnElement.comparator._reset(self)
- for attr in ('name', 'key'):
+ for attr in ('name', 'key', 'table'):
if self.__dict__.get(attr, False) is None:
self.__dict__.pop(attr)
@@ -2375,6 +2375,10 @@ class AnnotatedColumnElement(Annotated):
return self._Annotated__element.key
@util.memoized_property
+ def table(self):
+ return self._Annotated__element.table
+
+ @util.memoized_property
def info(self):
return self._Annotated__element.info
}}}
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2813#comment:2>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-27 18:34:27
|
#2813: Buglette with annotated join condition
----------------------------------+------------------------------------
Reporter: dairiki | Owner: zzzeek
Type: defect | Status: new
Priority: lowest | Milestone: 0.8.xx
Component: orm | Severity: no triage selected yet
Resolution: | Keywords:
Progress State: awaiting triage |
----------------------------------+------------------------------------
Comment (by zzzeek):
yeah not sure how to handle this, annotation() makes a copy of the Column,
and in this case it's copying it before it gets a table assigned.
If you use this patch:
{{{
#!diff
diff --git a/lib/sqlalchemy/orm/relationships.py
b/lib/sqlalchemy/orm/relationships.py
index f37bb8a..7d8a97d 100644
--- a/lib/sqlalchemy/orm/relationships.py
+++ b/lib/sqlalchemy/orm/relationships.py
@@ -1866,6 +1866,8 @@ class JoinCondition(object):
def _has_annotation(self, clause, annotation):
for col in visitors.iterate(clause, {}):
if annotation in col._annotations:
+ if col.table is None:
+ raise sa_exc.ArgumentError("column %s doesn't have a
Table" % col)
return True
else:
}}}
it raises an error, but this isn't great.
the workaround is to use a string, `primaryjoin="(remote(TableOne.x) ==
foreign(TableTwo.x))"`.
i might have realized this issue a while back but i dont have a good idea
how to deal with it.
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2813#comment:1>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-27 18:20:58
|
#2810: Single Item support for Association Proxy
---------------------------+----------------------------------
Reporter: jonathan | Owner: zzzeek
Type: defect | Status: new
Priority: high | Milestone: 0.9.0
Component: ext | Severity: minor - half an hour
Resolution: | Keywords:
Progress State: in queue |
---------------------------+----------------------------------
Changes (by zzzeek):
* priority: medium => high
* status_field: awaiting triage => in queue
* component: cextensions => ext
* severity: no triage selected yet => minor - half an hour
* milestone: => 0.9.0
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2810#comment:7>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-27 15:21:11
|
#2814: support for overriding existing @compiles directives
-------------------------+------------------------------------
Reporter: zzzeek | Owner: zzzeek
Type: enhancement | Status: new
Priority: medium | Milestone: 0.9.xx
Component: ext | Severity: major - 1-3 hours
Keywords: | Progress State: in queue
-------------------------+------------------------------------
perhaps sending it in as a **kw.
{{{
#!python
from sqlalchemy.ext.compiler import compiles
from alembic.ddl.base import AddColumn
# ideally, the @compiles system would have some way of getting
# us the "existing" @compiles decorator, so this part is the
# hack
specs = AddColumn.__dict__.get('_compiler_dispatcher').specs
existing_dispatch = specs.get('mysql', specs['default'])
@compiles(AddColumn, "mysql")
def add_column(element, compiler, **kw):
text = existing_dispatch(element, compiler, **kw)
if "after" in element.column.info:
text += " AFTER %s" % element.column.info['after']
return text
from sqlalchemy import Column, Integer
from alembic.migration import MigrationContext
from alembic.operations import Operations
ctx = MigrationContext.configure(dialect_name="mysql", opts={"as_sql":
True})
op = Operations(ctx)
op.add_column("t", Column('y', Integer))
op.add_column("t", Column('x', Integer, info={"after": "y"}))
}}}
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2814>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-27 00:51:40
|
#2813: Buglette with annotated join condition
---------------------+-----------------------------------------
Reporter: dairiki | Owner: zzzeek
Type: defect | Status: new
Priority: lowest | Milestone: 0.8.xx
Component: orm | Severity: no triage selected yet
Keywords: | Progress State: awaiting triage
---------------------+-----------------------------------------
Here's the crux (full test script attached below).
I have an explicitly annotated join condition. One of the columns in the
ON clause is
not having its name qualified with its table.
{{{
class TableTwo(Base):
...
x = Column(Integer)
r = relationship(TableOne,
primaryjoin=remote(TableOne.x)==foreign(x))
print sess.query(TableTwo).join('r')
>>> SELECT ... FROM Two JOIN One ON One.x = x
}}}
Executing this query results in an "ambiguous column name" operational
error.
This behavior seems to pertain to 0.8.2, rel_0_8 and master (atm).
Specifying the join condition as a string (so that it get evalled later)
works correctly.
Using the {{{foreign_keys}}} arg instead of the {{{foreign()}}} annotation
work correctly.
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2813>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 22:53:51
|
#2812: has_table/drop/etc. not really checking the "quote" flag for an uppercase
engine and it probably cant
---------------------------+-------------------------------
Reporter: zzzeek | Owner: zzzeek
Type: defect | Status: new
Priority: high | Milestone: 0.8.xx
Component: schema | Severity: major - 1-3 hours
Resolution: | Keywords:
Progress State: in queue |
---------------------------+-------------------------------
Comment (by zzzeek):
here's a quick proof of concept that's making me wonder, do we just create
a "case sensitive" string object right as we create Table, Sequence,
Column, Index, and just leave it at that? we'd need to see how
identifierpreparer and others feel about that. this allows PG and
Oracle to work:
{{{
#!diff
diff --git a/lib/sqlalchemy/engine/default.py
b/lib/sqlalchemy/engine/default.py
index 90c7f59..f7dc3e0 100644
--- a/lib/sqlalchemy/engine/default.py
+++ b/lib/sqlalchemy/engine/default.py
@@ -27,6 +27,13 @@ AUTOCOMMIT_REGEXP = re.compile(
re.I | re.UNICODE)
+class quoted_name(util.text_type):
+ def lower(self):
+ return self
+
+ def upper(self):
+ return self
+
class DefaultDialect(interfaces.Dialect):
"""Default implementation of Dialect"""
@@ -160,6 +167,12 @@ class DefaultDialect(interfaces.Dialect):
self._encoder = codecs.getencoder(self.encoding)
self._decoder =
processors.to_unicode_processor_factory(self.encoding)
+ def _as_quoted(self, name, quote):
+ if quote:
+ return quoted_name(name)
+ else:
+ return name
+
@util.memoized_property
def _type_memos(self):
return weakref.WeakKeyDictionary()
diff --git a/lib/sqlalchemy/sql/ddl.py b/lib/sqlalchemy/sql/ddl.py
index a17c8ee..4d0de05 100644
--- a/lib/sqlalchemy/sql/ddl.py
+++ b/lib/sqlalchemy/sql/ddl.py
@@ -667,7 +667,9 @@ class SchemaGenerator(DDLBase):
self.dialect.validate_identifier(table.schema)
return not self.checkfirst or \
not self.dialect.has_table(self.connection,
- table.name, schema=table.schema)
+ self.dialect._as_quoted(table.name,
table.quote),
+
schema=self.dialect._as_quoted(table.schema, table.quote_schema)
+ )
def _can_create_sequence(self, sequence):
return self.dialect.supports_sequences and \
@@ -678,8 +680,9 @@ class SchemaGenerator(DDLBase):
not self.checkfirst or
not self.dialect.has_sequence(
self.connection,
- sequence.name,
- schema=sequence.schema)
+ self.dialect._as_quoted(sequence.name,
sequence.quote),
+
schema=self.dialect._as_quoted(sequence.schema, sequence.quote_schema)
+ )
)
)
@@ -787,18 +790,23 @@ class SchemaDropper(DDLBase):
self.dialect.validate_identifier(table.name)
if table.schema:
self.dialect.validate_identifier(table.schema)
- return not self.checkfirst or
self.dialect.has_table(self.connection,
- table.name,
schema=table.schema)
+ return not self.checkfirst or \
+ self.dialect.has_table(self.connection,
+ self.dialect._as_quoted(table.name, table.quote),
+ schema=self.dialect._as_quoted(table.schema,
table.quote_schema)
+ )
def _can_drop_sequence(self, sequence):
return self.dialect.supports_sequences and \
((not self.dialect.sequences_optional or
not sequence.optional) and
(not self.checkfirst or
- self.dialect.has_sequence(
- self.connection,
- sequence.name,
- schema=sequence.schema))
+ self.dialect.has_sequence(
+ self.connection,
+ self.dialect._as_quoted(sequence.name,
sequence.quote),
+ schema=self.dialect._as_quoted(sequence.schema,
sequence.quote_schema)
+ )
+ )
)
def visit_index(self, index):
diff --git a/test/sql/test_quote.py b/test/sql/test_quote.py
index c92f1ac..ae9602e 100644
--- a/test/sql/test_quote.py
+++ b/test/sql/test_quote.py
@@ -61,6 +61,42 @@ class QuoteTest(fixtures.TestBase, AssertsCompiledSQL):
assert 'MixedCase' in t2.c
+ @testing.provide_metadata
+ def test_has_table_case_sensitive(self):
+ if testing.db.dialect.requires_name_normalize:
+ testing.db.execute("CREATE TABLE TAB1 (id INTEGER)")
+ testing.db.execute('CREATE TABLE "tab2" (id INTEGER)')
+ testing.db.execute('CREATE TABLE "TAB3" (id INTEGER)')
+ testing.db.execute('CREATE TABLE "TAB4" (id INTEGER)')
+ else:
+ testing.db.execute("CREATE TABLE tab1 (id INTEGER)")
+ testing.db.execute('CREATE TABLE "tab2" (id INTEGER)')
+ testing.db.execute('CREATE TABLE "TAB3" (id INTEGER)')
+ testing.db.execute('CREATE TABLE "TAB4" (id INTEGER)')
+
+ t1 = Table('tab1', self.metadata,
+ Column('id', Integer, primary_key=True),
+ #quote=False
+ )
+ t2 = Table('tab2', self.metadata,
+ Column('id', Integer, primary_key=True),
+ quote=True
+ )
+ t3 = Table('TAB3', self.metadata,
+ Column('id', Integer, primary_key=True),
+ #quote=False
+ )
+ t4 = Table('TAB4', self.metadata,
+ Column('id', Integer, primary_key=True),
+ quote=True)
+
+ quoted_rule = testing.db.dialect._as_quoted
+ assert testing.db.has_table(quoted_rule(t1.name, t1.quote))
+ assert testing.db.has_table(quoted_rule(t2.name, t2.quote))
+ assert testing.db.has_table(quoted_rule(t3.name, t3.quote))
+ assert testing.db.has_table(quoted_rule(t4.name, t4.quote))
+
+
def test_basic(self):
table1.insert().execute(
{'lowercase': 1, 'UPPERCASE': 2, 'MixedCase': 3, 'a123': 4},
}}}
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2812#comment:1>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 22:27:15
|
#2812: has_table/drop/etc. not really checking the "quote" flag for an uppercase
engine and it probably cant
--------------------+------------------------------------
Reporter: zzzeek | Owner: zzzeek
Type: defect | Status: new
Priority: high | Milestone: 0.8.xx
Component: schema | Severity: major - 1-3 hours
Keywords: | Progress State: in queue
--------------------+------------------------------------
{{{
#!diff
diff --git a/test/sql/test_quote.py b/test/sql/test_quote.py
index c92f1ac..78c1743 100644
--- a/test/sql/test_quote.py
+++ b/test/sql/test_quote.py
@@ -61,6 +61,48 @@ class QuoteTest(fixtures.TestBase, AssertsCompiledSQL):
assert 'MixedCase' in t2.c
+ @testing.provide_metadata
+ def test_has_table_case_sensitive(self):
+ # get it to work on oracle...
+ m = MetaData(testing.db)
+ Table("tab1", m).drop(checkfirst=True)
+ #Table("tab2", m).drop(checkfirst=True)
+ Table("tab2", m, quote=True).drop()
+ #######
+
+ if testing.db.dialect.requires_name_normalize:
+ testing.db.execute("CREATE TABLE TAB1 (id INTEGER)")
+ testing.db.execute('CREATE TABLE "tab2" (id INTEGER)')
+ testing.db.execute('CREATE TABLE "TAB3" (id INTEGER)')
+ testing.db.execute('CREATE TABLE "TAB4" (id INTEGER)')
+ else:
+ testing.db.execute("CREATE TABLE tab1 (id INTEGER)")
+ testing.db.execute('CREATE TABLE "tab2" (id INTEGER)')
+ testing.db.execute('CREATE TABLE "TAB3" (id INTEGER)')
+ testing.db.execute('CREATE TABLE "TAB4" (id INTEGER)')
+
+ t1 = Table('tab1', self.metadata,
+ Column('id', Integer, primary_key=True),
+ #quote=False
+ )
+ t2 = Table('tab2', self.metadata,
+ Column('id', Integer, primary_key=True),
+ quote=True
+ )
+ t3 = Table('TAB3', self.metadata,
+ Column('id', Integer, primary_key=True),
+ #quote=False
+ )
+ t4 = Table('TAB4', self.metadata,
+ Column('id', Integer, primary_key=True),
+ quote=True)
+
+ assert testing.db.has_table(t1.name)
+ assert testing.db.has_table(t2.name)
+ assert testing.db.has_table(t3.name)
+ assert testing.db.has_table(t4.name)
+
+
def test_basic(self):
table1.insert().execute(
{'lowercase': 1, 'UPPERCASE': 2, 'MixedCase': 3, 'a123': 4},
}}}
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2812>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 21:31:02
|
#2811: cannot change column.key in reflect event without corrupting primary key
---------------------+------------------------------------
Reporter: zzzeek | Owner: zzzeek
Type: defect | Status: new
Priority: highest | Milestone: 0.8.xx
Component: schema | Severity: major - 1-3 hours
Keywords: | Progress State: in queue
---------------------+------------------------------------
{{{
#!python
from sqlalchemy import *
from sqlalchemy import event
e = create_engine("sqlite://", echo=True)
e.execute("""
create table sample (
Id integer primary key,
Name varchar,
Description varchar,
IsActive varchar
)
""")
@event.listens_for(Table, "column_reflect")
def new_col(inspector, table, column_info):
column_info['key'] = column_info['name'].lower()
m = MetaData()
t = Table('sample', m, autoload=True, autoload_with=e)
assert t.c.id in set(t.primary_key)
}}}
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2811>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 16:42:41
|
#2810: Single Item support for Association Proxy
----------------------------------+------------------------------------
Reporter: jonathan | Owner: zzzeek
Type: defect | Status: new
Priority: medium | Milestone:
Component: cextensions | Severity: no triage selected yet
Resolution: | Keywords:
Progress State: awaiting triage |
----------------------------------+------------------------------------
Comment (by zzzeek):
Oh, it took me like 10 minutes, sorry :). the fails are corrected in
r99732dd29bd69a4a3808b rd64ab47d7693e27ecebec201a
r8f8522b4d1433475920674e272 back to 0.7.
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2810#comment:6>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 16:29:06
|
#2810: Single Item support for Association Proxy
----------------------------------+------------------------------------
Reporter: jonathan | Owner: zzzeek
Type: defect | Status: new
Priority: medium | Milestone:
Component: cextensions | Severity: no triage selected yet
Resolution: | Keywords:
Progress State: awaiting triage |
----------------------------------+------------------------------------
Comment (by jonathan):
if you can point to a file to fix, and a file to use as a styleguide, i'll
block out an hour or two this afternoon.
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2810#comment:5>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 16:19:09
|
#2810: Single Item support for Association Proxy
----------------------------------+------------------------------------
Reporter: jonathan | Owner: zzzeek
Type: defect | Status: new
Priority: medium | Milestone:
Component: cextensions | Severity: no triage selected yet
Resolution: | Keywords:
Progress State: awaiting triage |
----------------------------------+------------------------------------
Comment (by zzzeek):
the tests here seem to make some old assumptions and also aren't handling
the "fail" case correctly (i.e. fail() inside an open try: except: will
never "fail"). so all those broken fails need to be changed to
assert_raises() at least.
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2810#comment:4>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 15:57:43
|
#2810: Single Item support for Association Proxy
----------------------------------+------------------------------------
Reporter: jonathan | Owner: zzzeek
Type: defect | Status: new
Priority: medium | Milestone:
Component: cextensions | Severity: no triage selected yet
Resolution: | Keywords:
Progress State: awaiting triage |
----------------------------------+------------------------------------
Comment (by jonathan):
sorry about that.
here's my example, reformatted into a testcase, + your test case in a
single example.
{{{
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
Base = declarative_base()
class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
name = Column(String)
a2b_single = relationship("A2B", uselist=False)
a2b_list = relationship("A2B", uselist=True)
b_single = association_proxy("a2b_single", "b")
b_list = association_proxy("a2b_list", "b")
a2b_name = association_proxy("a2b_single", "name")
class A2B(Base):
__tablename__ = 'a2b'
id = Column(Integer, primary_key=True)
id_a = Column(Integer, ForeignKey('a.id'))
id_b = Column(Integer, ForeignKey('b.id'))
name = Column(String)
a = relationship("A", primaryjoin="A2B.id_a==A.id")
b = relationship("B", primaryjoin="A2B.id_b==B.id")
class B(Base):
__tablename__ = 'b'
id = Column(Integer, primary_key=True)
name = Column(String)
a1 = A()
assert a1.a2b_name is None
assert a1.b_single is None
assert a1.b_list == []
}}}
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2810#comment:3>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 15:43:48
|
#2810: Single Item support for Association Proxy
----------------------------------+------------------------------------
Reporter: jonathan | Owner: zzzeek
Type: defect | Status: new
Priority: medium | Milestone:
Component: cextensions | Severity: no triage selected yet
Resolution: | Keywords:
Progress State: awaiting triage |
----------------------------------+------------------------------------
Comment (by zzzeek):
and there we have it
{{{
#!python
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
Base = declarative_base()
class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
bs = relationship("B", uselist=False)
bname = association_proxy("bs", "name")
class B(Base):
__tablename__ = 'b'
id = Column(Integer, primary_key=True)
a_id = Column(Integer, ForeignKey('a.id'))
name = Column(String)
a1 = A()
assert a1.bname is None
}}}
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2810#comment:2>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 15:42:06
|
#2810: Single Item support for Association Proxy
----------------------------------+------------------------------------
Reporter: jonathan | Owner: zzzeek
Type: defect | Status: new
Priority: medium | Milestone:
Component: cextensions | Severity: no triage selected yet
Resolution: | Keywords:
Progress State: awaiting triage |
----------------------------------+------------------------------------
Comment (by zzzeek):
I guess I'm creating the test case here, huh.
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2810#comment:1>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 15:26:54
|
#2809: Strange effect with association proxy and event listener
-----------------------------------+------------------------------------
Reporter: schlamar | Owner: zzzeek
Type: defect | Status: closed
Priority: medium | Milestone: 0.8.xx
Component: (none) | Severity: no triage selected yet
Resolution: worksforme | Keywords:
Progress State: completed/closed |
-----------------------------------+------------------------------------
Changes (by zzzeek):
* status: new => closed
* resolution: => worksforme
* status_field: awaiting triage => completed/closed
Comment:
the traceback has "autoflush" inside of it, which occurs each time the
Session needs to go to the database to get some data. In this traceback,
as append() is called, the collection to which it is appending is
unloaded, so has to be loaded first, triggering autoflush.
Issues where autoflush gets in the way in some object mutation scenarios
are common. Use the
[http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html?highlight=no_autoflush#sqlalchemy.orm.session.Session.no_autoflush
no_autoflush] context manager to temporarily turn it off.
also since there's no specific "bug" defined here (no test case) this is
more of a mailing list issue for the moment, can we please move it over
there? thanks.
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2809#comment:3>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 15:21:22
|
#2808: AssociationProxy should use keywords on create
-----------------------------------+----------------------------------
Reporter: schlamar | Owner: zzzeek
Type: enhancement | Status: reopened
Priority: medium | Milestone: 0.8.xx
Component: ext | Severity: minor - half an hour
Resolution: | Keywords:
Progress State: completed/closed |
-----------------------------------+----------------------------------
Comment (by zzzeek):
a post regarding the "explicit, but you can automate it!" nature of
SQLAlchemy is here:
http://techspot.zzzeek.org/2011/05/17/magic-a-new-orm/
as far as "creator", I will grant that given the nature of Declarative
(which came after association proxy), it would have been better if it
assumed keyword arguments to start with, rather than positional. I'd be
willing to examine an approach that uses inspect() to make simple
deductions here as to if named arguments can be used.
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2808#comment:14>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 15:20:33
|
#2810: Single Item support for Association Proxy
-------------------------+-----------------------------------------
Reporter: jonathan | Owner: zzzeek
Type: defect | Status: new
Priority: medium | Milestone:
Component: cextensions | Severity: no triage selected yet
Keywords: | Progress State: awaiting triage
-------------------------+-----------------------------------------
Originally posted in the mailing list (
https://groups.google.com/forum/#!topic/sqlalchemy/Yehg9PIMQ_E )
Related to existing ticket "Scalar Support for Association Proxy"
http://www.sqlalchemy.org/trac/ticket/2751
An AttributeError is raised when an association proxy exists for an
relationship where `uselist=False`, there is no intermediary object, and
the objects association proxy is accessed.
This behavior makes it impossible to even check for an association proxy.
The expected behavior would be to return None, signifying there is no
currently proxied attribute.
given this example:
{{{
class Person:
# orm relationships are preceded by (o)ne or (l)ist
o_Person2Address_ActiveShipping = sa.orm.relationship(
"Person2Address",
primaryjoin="""and_( Person2Address.person_id==Person.id ,
Person2Address.role_id=='active-shipping' )""",
uselist=False )
active_shipping_address =
association_proxy('o_Person2Address_ActiveShipping', 'address')
class Person2Address:
address = sa.orm.relationship("Address",
primaryjoin="Person2Address.address_id==Address.id")
class Address:
pass
}}}
this works perfect when i have a Person2Address and address . I'd imagine
it works fine if the proxy is for an empty list too.
the problem is when o_Person2Address_ActiveShipping is an empty item (from
the uselist=False argument).
{{{
jim = dbSession.query( Person )
active_shipping = jim.o_Person2Address_ActiveShipping
type(active_shipping)
>> None
# this will raise an error
if jim.active_shipping_address :
# this will raise an error too
if jim.active_shipping_address and
jim.active_shipping_address.address :
print jim.active_shipping_address
}}}
that raises an error on the .active_shipping_address
{{{
File "/Users/jvanasco/webserver/environments/project-2.7.5/lib/python2.7
/site-packages/sqlalchemy/ext/associationproxy.py", line 241, in __get__
return self._scalar_get(getattr(obj, self.target_collection))
AttributeError: 'NoneType' object has no attribute 'media_asset'
}}}
i think a simple fix could be something like this ( line 240,
sqlalchemy/ext/associationproxy.py )
{{{
if self.scalar:
- if not getattr(obj, self.target_collection)
- return self._scalar_get(getattr(obj, self.target_collection))
else:
if self.scalar:
+ proxied = getattr(obj, self.target_collection)
+ if not proxied :
+ return None
+ return self._scalar_get(proxied)
else:
}}}
On the list, another person has reported encountering this and
monkeypatching with the same fix since 0.5.x
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2810>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 15:17:03
|
#2808: AssociationProxy should use keywords on create
-----------------------------------+----------------------------------
Reporter: schlamar | Owner: zzzeek
Type: enhancement | Status: reopened
Priority: medium | Milestone: 0.8.xx
Component: ext | Severity: minor - half an hour
Resolution: | Keywords:
Progress State: completed/closed |
-----------------------------------+----------------------------------
Comment (by zzzeek):
Replying to [comment:11 schlamar]:
> Plus, your example (with creator) doesn't work because !UserKeyword is
not yet defined for the User class. So you would have to refactor the
complete example to make it work (which could be really messy if you have
to use this solution in production code).
The my_association_proxy() function doesn't need access to the UserKeyword
class. Feel free to actually run the recipe in context of your original
example:
{{{
#!python
from sqlalchemy import Column, Integer, ForeignKey, String
from sqlalchemy.orm import relationship, backref
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
def my_association_proxy(src, target):
def create(value):
target_cls = prox.target_class
return target_cls(**{target: value})
prox = association_proxy(src, target, creator=create)
return prox
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(64))
keywords = my_association_proxy('user_keywords', 'keyword')
class UserKeyword(Base):
__tablename__ = 'user_keyword'
user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
keyword_id = Column(Integer, ForeignKey('keyword.id'),
primary_key=True)
# bidirectional attribute/collection of "user"/"user_keywords"
user = relationship(User, backref=backref("user_keywords",
cascade="all, delete-orphan"))
# reference to the "Keyword" object
keyword = relationship("Keyword")
class Keyword(Base):
__tablename__ = 'keyword'
id = Column(Integer, primary_key=True)
keyword = Column(String(64))
user = User(name='log')
for kw in (Keyword(keyword='new_from_blammo'),
Keyword(keyword='its_big')):
user.keywords.append(kw)
print(user.keywords)
}}}
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2808#comment:13>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 15:13:47
|
#2808: AssociationProxy should use keywords on create
-----------------------------------+----------------------------------
Reporter: schlamar | Owner: zzzeek
Type: enhancement | Status: reopened
Priority: medium | Milestone: 0.8.xx
Component: ext | Severity: minor - half an hour
Resolution: | Keywords:
Progress State: completed/closed |
-----------------------------------+----------------------------------
Comment (by zzzeek):
Replying to [comment:10 schlamar]:
> I think this is rather a workaround than a solution in case of an
association object because it is really unintuitive.
>
> From a user point of view the "association proxy" pattern shouldn't be
this complex. Essentially you say: proxy this attribute as a collection
via a many-to-many mapping. When a user pass an object to this collection,
SQLAlchemy should know how to build the many-to-many relationship without
requiring manual configuration from the user.
The reason we don't do things like that is because the user sees it as
"magic", and when things go wrong, even simple things, they have
absolutely no idea where to look. A many-to-many mapping has lots of
options - the secondary table, the join condition, backrefs, it has an
attribute name of its own, the user needs to specify these things
explicitly.
The reason SQLAlchemy's patterns are so explicit is because they get
intricate really fast, and we prefer the user to work out the individual
links in the chain. There are always ways to automate these patterns,
so the issue is not "too much typing" - you can automate that.
If you want to see the opposite, look at sqlalchemy-elixir, which hides
everything and creates attribute names and all that behind the scenes.
When something goes wrong with that, the user is lost. Hence
declarative's explicit approach has proven to be more popular.
>
> So IMO the creation process in case of an association object should
behave something like this (with !User/Keyword example)
>
> {{{
> #!python
>
> def _create(keyword):
> # create association object (UserKeyword)
> # do not pass the value (or pass the value
> # but the default creator shouldn't pass it
> # further to UserKeyword)
> uk = self.creator()
> # automatically find out how Keyword is related with
> # UserKeyword and set the correct attribute
> uk.find_relationship_and_set(keyword)
>
> }}}
This is possible for simple cases but then is not feasible for complex
cases, so as the scenario grows more complex, the easy magic starts to
make mistakes and we get bug reports. It's better to ask the user to
explicitly tell us what to do rather than guessing.
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2808#comment:12>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 12:27:15
|
#2809: Strange effect with association proxy and event listener
----------------------------------+------------------------------------
Reporter: schlamar | Owner: zzzeek
Type: defect | Status: new
Priority: medium | Milestone: 0.8.xx
Component: (none) | Severity: no triage selected yet
Resolution: | Keywords:
Progress State: awaiting triage |
----------------------------------+------------------------------------
Changes (by schlamar):
* cc: marc.schlaich@… (added)
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2809#comment:2>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|
|
From: sqlalchemy <mi...@zz...> - 2013-08-26 12:26:53
|
#2809: Strange effect with association proxy and event listener
----------------------------------+------------------------------------
Reporter: schlamar | Owner: zzzeek
Type: defect | Status: new
Priority: medium | Milestone: 0.8.xx
Component: (none) | Severity: no triage selected yet
Resolution: | Keywords:
Progress State: awaiting triage |
----------------------------------+------------------------------------
Comment (by schlamar):
However, the most strange thing for me is that there is an SQL execution
at all at the point of `proxy.append`. Shouldn't there be SQL execution
only on `commit`?
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2809#comment:1>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|