OK so I'll just walk through how I do this:

1. first I run it in py3K where the "random" hash behavior is, until python 3.6, in effect.

2. I can see the attributes are there or not on each run.

3. next I want to whack the monkeypatched thing, because that's a lot of code that I don't want to be involved in the issue. Fortunately, just taking it out, behavior still reproduces. This means it's not part of the issue.

4. Next, I see the attributes aren't there on the query side, but that skips ahead, how do we know they were persisted? Turn on echo=True (the whole ORM / Core tutorials illustrate an echo=True kind of workflow which is the best way to understand things)

5. echo=True reveals the problem way at the beginning.  Good run:

INSERT INTO tags ("key", value) VALUES (?, ?)
2016-09-10 10:18:22,503 INFO sqlalchemy.engine.base.Engine ('foo', 'bar')
2016-09-10 10:18:22,504 INFO sqlalchemy.engine.base.Engine INSERT INTO tags ("key", value) VALUES (?, ?)
2016-09-10 10:18:22,504 INFO sqlalchemy.engine.base.Engine ('bang', 'baz')


bad run:

 INSERT INTO tags ("key", value) VALUES (?, ?)
2016-09-10 10:18:25,567 INFO sqlalchemy.engine.base.Engine ('bang', '')
2016-09-10 10:18:25,568 INFO sqlalchemy.engine.base.Engine INSERT INTO tags ("key", value) VALUES (?, ?)
2016-09-10 10:18:25,568 INFO sqlalchemy.engine.base.Engine ('foo', '')


(note I haven't begun to look at the models here at all. Way too time consuming )


6. having a Tag with no "value" is definitely wrong, let's ensure those are present so we can get a stack trace where they are not. First I just did a naive "assert value" in the constructor, but OK this is association proxy trying to set "value" after the fact, OK

7. it looks like getting the "value" there is dependent on the ElementsTags.tag_value proxy working. Also we observe that the two objects either both work, or both fail. At this point it's obvious that the bug has to do with the initialization of the ElementsTags class, the dictionary ordering issue here probably has to do with the two association proxy elements getting set up differently.

8. Where do we get a Tag() from? Weird, there is no call to Tag() anywhere at all. Is this relying on some behavior of association proxy? The only assocs that could do this are the tag_key and tag_value...but....which one sets up Tag()? I have no idea how the association proxy handles this.

9. after testing a few things (is it creating two Tag() objects for each one? it's not. changing order of attributes affects it? not really) it looks like I still don't know why value is set or not.


10. Well let's at least confirm this is where the issue originates:

    tags = association_proxy("elements_tags", "tag_value",
creator=lambda k, v: ElementsTags(tag=Tag(key=k, value=v)))

that is, don't try to challenge the association proxy to work in multiple levels of nesting, just keep it simple. bug is gone. OK, so association proxy definitely tripping up on setting up via two association proxies inside the constructor of another (not too surprising). We know it isn't creating two Tag objects. So, assoc proxy just doesn't want to set "value" sometimes.

11. let's revisit what we wanted to do in #6 but more appropriately:

class ElementsTags(base):

    def __init__(self, **kw):
        super(ElementsTags, self).__init__(**kw)
        assert self.tag.value

    # ...

Now I can get the real stack trace on alternate runs:

Traceback (most recent call last):
  File "test.py", line 58, in <module>
    e.tags[u"foo"] = u"bar"
File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/ext/associationproxy.py", line 742, in __setitem__
    self.col[key] = self._create(key, value)
File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/ext/associationproxy.py", line 727, in _create
    return self.creator(key, value)
  File "test.py", line 31, in <lambda>
    creator=lambda k, v: ElementsTags(tag_key=k, tag_value=v))
  File "<string>", line 4, in __init__
File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/state.py", line 406, in _initialize_instance
    manager.dispatch.init_failure(self, args, kwargs)
File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/util/langhelpers.py", line 60, in __exit__
    compat.reraise(exc_type, exc_value, exc_tb)
File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/util/compat.py", line 186, in reraise
    raise value
File "/home/classic/dev/sqlalchemy/lib/sqlalchemy/orm/state.py", line 403, in _initialize_instance
    return manager.original_init(*mixed[1:], **kwargs)
  File "test.py", line 53, in __init__
    assert self.tag.value

So somewhere in assoc proxy, something is happening. I don't know where the bug is yet, but I have to go. Maybe you can keep pdbing into association proxy and see where this might be happening.














On 09/10/2016 03:04 AM, Dominik George wrote:


Am Samstag, 10. September 2016 09:02:32 UTC+2 schrieb Dominik George:

    Hi Mike,

    here it is. See attached mwe.py.



Which is here ;).

-nik

--
You received this message because you are subscribed to the Google
Groups "sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send
an email to [email protected]
<mailto:[email protected]>.
To post to this group, send email to [email protected]
<mailto:[email protected]>.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to