#208 [PATCH] TypeError:unhashable instance using sqlbuilder.Table

closed-invalid
Oleg Broytman
General (125)
5
2007-01-23
2007-01-23
No

Hi! Maybe this is a pretty weird use case (please let me know if there is a better way to do this).

What I wanted was just to store an ordered list of many-to-many relationships. To achieve this, I used an special intermediate table with an extra field for ordering. Then I write some custom SQL queries to do the join using sqlbuilder.table (Table instance) and friends.

The problem is I'm getting a TypeError ("TypeError: unhashable instance") when doing that, because Table and Field don't have the __hash__ magic method (and for the records, none SQLExpression does either).

Well, long story short, this is fixed by just adding the __hash__ method to SQLExpression class. Here is the patch and a simple testcase.

Again, please tell me if there is a cleaner way to achieve this with SQLObject.

Thanks!

Discussion

  • Testcase

     
    Attachments
  • Patch agains r2229 on the trunk svn.

     
  • Logged In: YES
    user_id=240225
    Originator: YES

    File Added: sqlexpression.hash.patch

     
  • Logged In: YES
    user_id=240225
    Originator: YES

    The patch apply cleanly to the 0.8 branch too. I hope it make it to 0.8 =)

     
  • Oleg Broytman
    Oleg Broytman
    2007-01-23

    • assigned_to: nobody --> phd
     
  • Logged In: YES
    user_id=240225
    Originator: YES

    I know I can create the intermediate table using SQLObject, but I don't want to, because this generates an extra 'id' field in the table that is useless. What I really wanted to do was add an "OrderedRelatedJoin" or something like that but I got lost because RelatedJoin is so tied up with dbconnection module. I expected to be just plan (sqlbuilder) SQL in the join module.

    Another simple solution (but I think not too easy to implement because AFAIK SQLObject is to tied up too to the single primary key) is to let a SQLObject to have a composed primary key and use the two FK as the PK.

    Anyways, I'm not using the Table object as dict, SQLObject is =)

    If you run the testcase, you'll get:

    Traceback (most recent call last):
    File "testcase.py", line 70, in ?
    plan.tasks = (Task(name="task1"), Task(name="task2"), Task(name="task3"))
    File "testcase.py", line 48, in _set_tasks
    old = frozenset([t.id for t in self.tasks])
    File "testcase.py", line 38, in _get_tasks
    orderBy=task_plan_table.pos,
    File "/tmp/0.8/sqlobject/main.py", line 1347, in select
    join=join, forUpdate=forUpdate)
    File "/tmp/0.8/sqlobject/sresults.py", line 20, in __init__
    tablesDict[table] = 1
    TypeError: unhashable instance

    I know I could use plain old strings instead of the Table object instance, but I found the later more pythonic (I feel like I'm not messing arround with raw SQL =D).

    And BTW, it's a very simple patch (3 lines of code, it's 'def __has__(self): return hash(str(self))' inside SQLExpression class declaration. It couldn't hurt anybody. And as plus it completes a little more the SQLExpression in general so you can use SQLExpressions as dict keys in general.

    PS. Sorry about the patch, I've posted some others in the past here and nobody complained, maybe there was a change in the policy, that was about... 2 years ago. Damn! The time pass by... ;-P

     
  • Oleg Broytman
    Oleg Broytman
    2007-01-23

    Logged In: YES
    user_id=4799
    Originator: NO

    No need to make SQLExpresshion hashable. You problem must be fixed this way:

    clauseTables=("task_plan", Plan.sqlmeta.table),

    clauseTables must be a sequence of tables names (strings), not objects.

     
  • Oleg Broytman
    Oleg Broytman
    2007-01-23

    • status: open --> closed-invalid