classification
Title: code_richcompare() don't use constant type when comparing code constants
Type: behavior Stage: patch review
Components: Versions: Python 3.6, Python 3.5, Python 2.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: David MacIver, Kevin Shweh, Tijs Van Oevelen, arigo, donmez, ebarry, ezio.melotti, fijall, haypo, larry, mark.dickinson, ncoghlan, python-dev, r.david.murray, rhettinger, serhiy.storchaka, torsten
Priority: normal Keywords: patch

Created on 2015-12-11 19:23 by Tijs Van Oevelen, last changed 2016-06-14 22:44 by larry. This issue is now closed.

Files
File name Uploaded Description Edit
code_richcompare.patch haypo, 2015-12-14 17:04 review
code_richcompare-2.patch haypo, 2015-12-14 17:31 review
code_eq.py haypo, 2015-12-14 17:31
code_richcompare-3.patch haypo, 2016-01-20 14:15 review
code_richcompare-4.patch haypo, 2016-01-20 23:05 review
code_richcompare-5.patch haypo, 2016-01-21 12:49 review
Messages (53)
msg256229 - (view) Author: Tijs Van Oevelen (Tijs Van Oevelen) Date: 2015-12-11 19:23
The bug is described on Stack Overflow in length:

http://stackoverflow.com/questions/34100732/unexpected-output-using-pythons-ternary-operator-in-combination-with-lambda
msg256230 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2015-12-11 19:33
For reference, the minimal reproducer is:

>>> f1, f2 = lambda: 1, lambda: 1.0
>>> f2()
1

The cause (according to the answer in the link) is that the two lambda's incorrectly compare as equal and end up sharing the same code object...one of the inequality checks is line number, so this only happens when the lambdas are on the same line.

Aside: it would be helpful if people would post bug summaries instead of just linking to an outside article.  The link is of course very valuable information, but it saves us time if the poster summarizes the bug so the right people know to look at it.
msg256233 - (view) Author: Tijs Van Oevelen (Tijs Van Oevelen) Date: 2015-12-11 20:05
Apologies for not posting a summary of the bug. I really had no idea how to describe the problem, as it is over my head. I could only refer to my question on Stack Overflow that triggered the discovery of the bug.
msg256234 - (view) Author: Tijs Van Oevelen (Tijs Van Oevelen) Date: 2015-12-11 20:08
It's definitely also in 3.4 by the way.
msg256235 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2015-12-11 20:13
Thanks for posting the bug.  I added the aside because this is the third or fourth of these reference-only things I've seen in the past couple weeks and I finally figured out what bothered me about them.  We should put something about this in the devguide on bug reporting, but of course most people reporting bugs will for good reason not read that.  So, I just have to live with it :)

And yes, the reproducer reproduces the problem in all python versions currently under maintenance.

I've now changed the title to reflect the underlying bug.
msg256245 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2015-12-11 23:29
The equality of code objects is determined by the code_richcompare() logic in Objects/codeobject.c.

Two code objects are equal if all of their attributes compare equal.  That includes co_name, co_argcount, co_kwonlyargcount, co_nlocals, co_flags, co_firstlineno, co_code, co_consts, co_names, co_varnames, co_freevars, and co_cellvars.

At the heart of David Murray's minimal example, the reason the two distinct code objects compare equal is that their co_consts compare as equal.

If you wanted to fix this, code objects would need to recursively check for both normal equality and type equality.

>>> f1 = lambda: 1
>>> f2 = lambda: 1.0
>>> f1.__code__.co_consts == f2.__code__.co_consts
True
>>> map(type, f1.__code__.co_consts) == map(type, f2.__code__.co_consts)
False
msg256250 - (view) Author: Kevin Shweh (Kevin Shweh) Date: 2015-12-12 02:51
A type-based check runs into problems with 0.0 vs -0.0. For example, on Python 2.7.11:

>>> x, y = lambda: 0.0, lambda: -0.0
>>> y()
0.0

I wasn't able to reproduce the -0.0 problem with Python 3.4 on Ideone; y.__code__.co_consts seems to have an unused 0.0 in it on 3.4. I don't have access to Python 3.5, so I don't know what the situation is like on that version.
msg256251 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2015-12-12 02:52
Here's another variant (courtesy of Nick Coghlan):

python3.5 -c "seq1 = [1.0 for x in range(5)]; seq2 = [True for x in range(5)]; print(seq1); print(seq2)"
msg256252 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2015-12-12 02:55
One possible solution for all these variants is to let code objects track both the co.firstlineno and co.firstrowno.
msg256274 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2015-12-12 08:45
FWIW, the bug is present in PyPy as well.
msg256285 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2015-12-12 13:38
From what I can see:

* checking constant types in addition to their values should be a two line change (plus tests)
* checking the column number in addition to the line number would be a more comprehensive fix, but also a constructor API change (since PyCode_New doesn't currently accept a column parameter)

The "values of the same constant type that are distinct but equivalent may still compare equal" case is obscure enough that I think the lower impact change is likely a better option, especially as 3.x currently "handles" the "lambda: -0.0" case by having both the unfolded 0.0 and the folded -0.0 in the constant list.

------------
Additional detail for those interested:

The lowest impact fix from a code change would be to add a type equivalence check for constants as Raymond first suggested, as that only involves adding an extra check to code_richcompare: https://hg.python.org/cpython/file/tip/Objects/codeobject.c#l416

However, the idea of tracking "co_firstcolno" in addition to "co_firstlineno" is a more robust fix, as it means any lexically distinct code objects will necessarily be considered distinct by the interpreter. The downside is that it means touching more code and adding a new public API, since PyCode_New doesn't currently accept a "firstcolno" parameter - code objects are implicitly assumed to be one-per-line.

Out of curiosity, I also went looking for the code in the code generator that collapses the "equivalent" code objects together. The issue is that constants are stored in a dict (mapping them to their co_consts index) during compilation and assembly, so equivalent objects will be merged together (and refer to the index of the first one defined).
msg256290 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2015-12-12 19:28
Interestingly, co_filename is not used as part of the equivalence criteria, so code object equivalence can be fooled across multiple input files.  Fortunately in this case, the false equivalence isn't relied on by the code generator.

  $ cat a.py
  def f():
      return 1

  $ cat b.py
  def f():
      return 1.0

  $ ./python.exe -q
  >>> import a, b
  >>> a.f.__code__ == b.f.__code__  # False equivalence
  True
  >>> a.f()
  1
  >>> b.f()                         # Generated code is correct
  1.0

Besides aliasing int/float/decimal/fraction/complex/bool, codeobj.__eq__() can also alias str/unicode on Python 2.7.  Likewise, 0.0 and -0.0 can be conflated.  NaNs don't seem to be a problem.

I think we should focus on fixing the spec for code object equivalents.  Perhaps the test can be simplified to use (co_firstlineno, co_firstrowno, co_filename).
msg256317 - (view) Author: Armin Rigo (arigo) * (Python committer) Date: 2015-12-13 07:51
Other possible minimal fixes:

* compile.c:compiler_addop(): special-case code objects too, and stick their identity in the tuple 't'.

* or, in compile.c:makecode(), append the first row number to co_consts.
msg256318 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2015-12-13 08:54
> The lowest impact fix from a code change would be to add a type equivalence check for constants as Raymond first suggested, as that only involves adding an extra check to code_richcompare: https://hg.python.org/cpython/file/tip/Objects/codeobject.c#l416

It is not so easy. (1,) and (1.0,) are equal and have the same type. To make correct type-sensitive equivalence check, you need to introduce new protocol, new special method on low level and new operator/function on high level.
msg256320 - (view) Author: David MacIver (David MacIver) * Date: 2015-12-13 09:47
Note that 3.x does not correctly handle -0.0, you just have to work a bit harder:

>>> (lambda: (-0.0, 0.0), lambda: (0.0, -0.0))[1]()
(-0.0, 0.0)
msg256321 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2015-12-13 10:53
> I think we should focus on fixing the spec for code object equivalents.  Perhaps the test can be simplified to use (co_firstlineno, co_firstrowno, co_filename).

This is not enough if the code was compiled from a string.

>>> x = eval('lambda: 1')
>>> y = eval('lambda: 1.0')
>>> x.__code__ == y.__code__
True
>>> x.__code__.co_filename == y.__code__.co_filename
True
msg256323 - (view) Author: Emanuel Barry (ebarry) * Date: 2015-12-13 16:53
Nobody seems to have asked this, so I'll be that guy. In which circumstances does comparing two code objects (at function creation time, what's more) make any sense? I mean, I'm fine with being able to compare two code objects, but I don't think that's something that should be automated.

Is there any particular reason why this is so? The only reason I could think of was that small, identical functions could use the same code object -- but then Raymond proved that different files will not share the code object, and identical functions on different lines will not, either.

As functions grow in size and complexity, having two virtually identical functions is probably bad design to begin with. So, seeing as this causes more harm than good (and I doubt it's of any use nowadays - it might have been back then, I don't know), I suggest we simply drop the implcit code objects compare-and-replace that's happening here.
msg256327 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2015-12-13 18:24
I suppose this is needed above all for testing. test_compile, test_codeop, test_marshal, and few other tests compare code objects.
msg256330 - (view) Author: Emanuel Barry (ebarry) * Date: 2015-12-13 19:40
I'm not suggesting to get rid of the rich compare ability of code objects, which makes sense to me. What doesn't make sense to me, however, is when a function's code object is replaced by another one because it compares equal. I see no use case for this, and only leads to head-scratching.

I believe code objects should not be touched at all.
msg256332 - (view) Author: Armin Rigo (arigo) * (Python committer) Date: 2015-12-13 19:56
That's what I suggested ("compile.c:compiler_addop(): special-case code objects too, and stick their identity in the tuple 't'.") and how I fixed the same bug in PyPy (https://bitbucket.org/pypy/pypy/commits/7ec3e1d02197).
msg256381 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2015-12-14 15:28
[Emanuel Barry]
> In which circumstances does comparing two code objects
> (at function creation time, what's more) make any sense?

It makes closures efficient:

    >>> def f(x):
            def g(y):
                    return x + y
            return g

    >>> h = f(1)
    >>> i = f(2)
    >>> h.__code__ is i.__code__
    True
msg256382 - (view) Author: Mark Lawrence (BreamoreBoy) * Date: 2015-12-14 15:47
http://code.activestate.com/recipes/578353-code-to-source-and-back/ compares code objects as part of round trip testing.
msg256383 - (view) Author: Emanuel Barry (ebarry) * Date: 2015-12-14 15:54
I see. Is there any to special-case those so that only closures use that? Maybe by checking on the function object itself - the function itself would be quite similar, as well.

@Mark - I think you've misunderstood me (others did too, so I'm going to assume I just explained poorly) - I'm not debating the use of comparing code objects, I'm talking about the implicit replacement of code objects in functions. However, it seems to be of use, so outright removing the behaviour isn't an option.
msg256386 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2015-12-14 16:07
> It makes closures efficient:

No, code objects are not compared here. The code object is constant, and f() returns different closure objects using the same code object.

AFAIK the comparison of different code objects is used exclusively in testing.
msg256390 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2015-12-14 16:30
Serhiy: that can't be entirely true, since we have here a bug where two lambdas on the same line are getting the same code object incorrectly, and that is not a testing context.
msg256398 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2015-12-14 16:52
Ah, haypo explained the code to me, and now I understand your comment Serhiy.

So, the replacement happens because of (a) an optimizer general rule and (b) the fact that code object *can* be compared.

So it sounds like Armin's suggestion of making an exception for code objects in the optimizer is the correct solution.

The issue with code objects that aren't really equal comparing equal would then be a separate bug that affects, as Serhiy said, only testing (that we know of...who knows what people like PJE might be doing with comparing code objects :)
msg256399 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2015-12-14 16:55
Indeed. My answer actually is an answer to implicit question: could we make different code objects be always non-equal? Answer: no, because we use the comparison of different code objects to test compiler and marshaller.

May be we can get rid of code objects comparability and provide separate function specially for testing. Of course this likely will break tests in third-party packages that do low-level hacking on code objects.
msg256400 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2015-12-14 16:55
compiler_add_o() uses an heuristic to compare and merge duplicated constants. It has special cases for float and complex numbers, but it's not designed to handle more types.

Funny, I had the same isue last week why I added support for tuple and frozenset "constants" in AST. I had to explicitly support these types in compiler_add_o().

I see two options:

(1) share code between compiler_add_o() and code_richcompare() to ensure that 1 and 1.0 constants are not seen as equal
(2) modify compiler_add_o() to never merge code objects, always considere them as unequal

For (2), there is a minor technical issue: you have to generate an unique key for the dictionary.

I prefer option (1) for consistency.
msg256401 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2015-12-14 17:03
Would option (1) work if wrap 1 and 1.0 in a tuple? In a list? In a custom collection?
msg256402 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2015-12-14 17:04
code_richcompare.patch: fix code_richcompare() to not consider that constants (1,) and (1.0,) are equal.

The patch lacks an unit test.

We may use the new _PyCode_ConstantKey() function to compare other code attributes?
msg256403 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2015-12-14 17:07
> Would option (1) work if wrap 1 and 1.0 in a tuple? In a list? In a custom collection?

Right now, the Python compiler is quite limited. It only produces constants for integers and strings, not complex types. The peephole optimizers is responsible to produce tuple and frozenset constants, and the optimizer is more naive. It doesn't try to merge constants, nor remove items from co_consts to only keep the new container. Example:

>>> def f():
...  return (1,2,3)
... 
>>> f.__code__.co_consts
(None, 1, 2, 3, (1, 2, 3))

1, 2, 3 constants are kept, whereas only (1, 2, 3) constant is used.

Test with my patch:

>>> f1, f2 = lambda x: x in {1,}, lambda x: x in {1.0,}
>>> 
>>> f1.__code__ is f2.__code__
False
>>> f1.__code__.co_consts
(None, 1, frozenset({1}))
>>> f2.__code__.co_consts
(None, 1.0, frozenset({1.0}))

The frozenset are different are expected.
msg256404 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2015-12-14 17:12
> The frozenset are different are expected.

Oh wait, in this example, it works, but not because of the expected reason. frozenset({1}) is equal to frozenset({1.0}) and code_richcompare() doesn't create a special key to make them different.

The example only works because the peephole optimizer is lazy and leave 1 and 1.0 in co_consts which are seen as different by the patched code_richcompare().
msg256405 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2015-12-14 17:31
code_richcompare-2.patch: Updated patch to handle also frozenset, the other constant type generated by the peephole optimizer.
msg256406 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2015-12-14 17:31
code_eq.py: code to test that frozenset() are inequal. The code hacks constants, don't run the code with new constants or it will crash!
msg256409 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2015-12-14 19:32
If go this way, I would add explicit support of all types supported in marshal, and include id(obj) into the key of all other types.
msg258532 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2016-01-18 17:22
FYI this issue is linked to the issue #26146 which allows to emit constants from an AST optimizer (see also the PEP 511).
msg258683 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2016-01-20 14:15
Let me try to explain this issue again.

"f1, f2 = lambda: 1, lambda: 1.0" is compiled to two MAKE_FUNCTION instructions, MAKE_FUNCTION takes a code object as parameter (and a name). The Python compiler merges constants which are seen as "equal", with exceptions to not merge values of different types, or float of different sign.

Merging duplicate code objects is a cool micro optimization, I prefer to keep it. My patch keeps this micro optimization, but fix the bug: it ensures that equal constants having different types are not seen as equal. For example, 0 is equal to 0.0, but if when used for code constants, the code objects are seen a different.

Patch version 3:

* as suggested by Armin Rigo & Serhiy Storchaka: use id(obj) in the constant key for unknown constant types -- in practice, this patch is never taken, it's just to be extra safe (I checked manually by running the whole test suite when an assertion, assertion not in the posted patch)
* add a lot of unit tests
* add a documentation to _PyCode_ConstantKey()

@Serhiy: does it look good to you now?

> Would option (1) work if wrap 1 and 1.0 in a tuple? In a list? In a custom collection?

My patch now uses id(obj) in the "constant key" for unknown types. The compiler only emits simple type (int, str, ...), tuple, frozenset and code objects.

You *can* other types if you patch manually constants with custom objects, since code_richcomp() now uses the "constant key" function to compare constants. For example, my fat project has a replace_consts() function to inject builtin functions in constants:
http://fatoptimizer.readthedocs.org/en/latest/fat.html#replace_consts

There is also @asconstants decorator of codetransformer which allow to inject arbitrary types in function constants:
https://pypi.python.org/pypi/codetransformer
msg258707 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2016-01-20 18:19
It looks to me that the patch makes set and frozenset constants to be equal, but makes sets with different order (as {2**62, 1} and {1, 2**62}) differ. And looks you had missed my comments to previous patches.
msg258724 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2016-01-20 23:05
Patch version 4:

Fix _PyCode_ConstantKey:

* always return a tuple
* create a frozenset/set if input is a set/frozenset, items are unordered
* enhance unit tests: compare values using repr() to compare value + type at once
* fix reference leak

Other minor changes to take Serhiy's comments in account.

Thanks Serhiy for good suggestions!
msg258725 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2016-01-20 23:05
And sorry, I missed your comments, it looks like some emails were seen as spam :-/
msg258753 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2016-01-21 10:22
I meant that set shouldn't be handled in _PyCode_ConstantKey at all. Only frozenset constants can be considered equal. Sets as well as lists all should be different.

There is yet one issue with string and bytes literals. When run Python with the -b option:

>>> a, b = lambda: 'a', lambda: b'a'
sys:1: BytesWarning: Comparison between bytes and string
sys:1: BytesWarning: Comparison between bytes and string

May be the type should be the first item in the key.
msg258756 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2016-01-21 12:49
Updated patch version 5.

> I meant that set shouldn't be handled in _PyCode_ConstantKey at all. Only frozenset constants can be considered equal. Sets as well as lists all should be different.

Ok, I dropped support for set type to only keep support for frozenset. set are now always considered as different, as list and other "unsupported types".

> There is yet one issue with string and bytes literals. When run Python with the -b option:
> (...)
> May be the type should be the first item in the key.

Oh, good catch. It's an old bug.

Yeah, putting the type as the first parameter fixes the issue. I made this change. I had to update compile.c to exchange the type and the value in the tuple.
msg258795 - (view) Author: Roundup Robot (python-dev) Date: 2016-01-22 11:37
New changeset 6c33d4cc9b8f by Victor Stinner in branch 'default':
code_richcompare() now uses the constants types
https://hg.python.org/cpython/rev/6c33d4cc9b8f
msg258796 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2016-01-22 11:40
I pushed my latest patch with minor changes in comments.

I will wait for buildbots before backporting the change to Python 2.7 and 3.5. For the backport, I will probably remove the optimization on frozenset since it's only useful for AST optimizers (the optimization is a new feature, I considered that it was worth it to add it Python 3.6 as part of my work on the PEP 511).
msg258814 - (view) Author: Roundup Robot (python-dev) Date: 2016-01-22 14:59
New changeset 8e0a736b82ff by Victor Stinner in branch '3.5':
code_richcompare() now uses the constants types
https://hg.python.org/cpython/rev/8e0a736b82ff
msg258815 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2016-01-22 15:17
> I will probably remove the optimization on frozenset since it's only useful for AST optimizers (the optimization is a new feature, I considered that it was worth it to add it Python 3.6 as part of my work on the PEP 511).

Hum, it doesn't work: test_compile_ast() of test_compile fails without this code. The test relies (indirectly) on the fact that two code objects using a frozenset constant are equal.
msg258817 - (view) Author: Roundup Robot (python-dev) Date: 2016-01-22 15:51
New changeset 9e13d97ceca2 by Victor Stinner in branch '2.7':
code_richcompare() now uses the constants types
https://hg.python.org/cpython/rev/9e13d97ceca2
msg258818 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2016-01-22 15:54
Ok, the fix is now pushed to Python 2.7, 3.5 and 3.6.

Thanks Tijs Van Oevelen for your bug report ;-)

A workaround look to define the two lambda functions on two different lines. Or maybe cast explicitly to float? I don't think that it's a common bug so you should be able to survive with it until the next bugfix version is released :-)
msg259016 - (view) Author: Roundup Robot (python-dev) Date: 2016-01-27 11:20
New changeset 16f60cd918e0 by Victor Stinner in branch 'default':
PEP 511
https://hg.python.org/peps/rev/16f60cd918e0
msg268555 - (view) Author: Larry Hastings (larry) * (Python committer) Date: 2016-06-14 12:53
Someone asked on reddit.  The Misc/NEWS entry for this reads:

Issue #25843: When compiling code, don’t merge constants if they are equal but have a different types. For example, f1, f2 = lambda: 1, lambda: 1.0 is now correctly compiled to two different functions: f1() returns 1 (int) and f2() returns 1.0 (int), even if 1 and 1.0 are equal.

Shouldn't that last part read
 
"and f2() returns 1.0 (float), even if 1 and 1.0 are equal."
                       ^^^^^

As in, f2 returns a float, not an int.

If this is a mistake, let me fix it for 3.5.2 final and I'll merge it back into trunk etc.  If you fix it it wouldn't ship in 3.5.2 final.
msg268556 - (view) Author: Roundup Robot (python-dev) Date: 2016-06-14 13:05
New changeset a36238de31ae by Victor Stinner in branch '3.5':
Issue #25843: Fix the NEWS entry
https://hg.python.org/cpython/rev/a36238de31ae
msg268557 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2016-06-14 13:06
Oh, I fixed the typo in the Misc/NEWS in 3.5 and default branches.
msg268588 - (view) Author: Larry Hastings (larry) * (Python committer) Date: 2016-06-14 22:44
Yes, which doesn't help 3.5.2 final as I don't pull revisions by default after rc1.  :p
History
Date User Action Args
2016-06-14 22:44:29larrysetmessages: + msg268588
2016-06-14 13:06:03hayposetmessages: + msg268557
2016-06-14 13:05:47python-devsetmessages: + msg268556
2016-06-14 12:53:48larrysetnosy: + larry
messages: + msg268555
2016-01-27 11:20:21python-devsetmessages: + msg259016
2016-01-22 15:54:05hayposetstatus: open -> closed
resolution: fixed
messages: + msg258818
2016-01-22 15:51:28python-devsetmessages: + msg258817
2016-01-22 15:17:29hayposetmessages: + msg258815
2016-01-22 14:59:49python-devsetmessages: + msg258814
2016-01-22 11:40:37hayposetmessages: + msg258796
2016-01-22 11:37:50python-devsetnosy: + python-dev
messages: + msg258795
2016-01-21 17:00:14haypolinkissue26146 dependencies
2016-01-21 12:49:06hayposetfiles: + code_richcompare-5.patch

messages: + msg258756
2016-01-21 10:22:10serhiy.storchakasetmessages: + msg258753
2016-01-20 23:05:43hayposetmessages: + msg258725
2016-01-20 23:05:23hayposetfiles: + code_richcompare-4.patch

messages: + msg258724
2016-01-20 18:19:47serhiy.storchakasetstage: patch review
messages: + msg258707
versions: - Python 3.4
2016-01-20 14:16:14hayposettitle: lambdas on the same line may incorrectly share code objects -> code_richcompare() don't use constant type when comparing code constants
2016-01-20 14:15:04hayposetfiles: + code_richcompare-3.patch

messages: + msg258683
2016-01-20 08:42:37mark.dickinsonsetnosy: + mark.dickinson
2016-01-18 18:26:52BreamoreBoysetnosy: - BreamoreBoy
2016-01-18 17:22:14hayposetmessages: + msg258532
2015-12-14 19:32:23serhiy.storchakasetmessages: + msg256409
2015-12-14 17:31:48hayposetfiles: + code_eq.py

messages: + msg256406
2015-12-14 17:31:03hayposetfiles: + code_richcompare-2.patch

messages: + msg256405
2015-12-14 17:12:14hayposetmessages: + msg256404
2015-12-14 17:07:43hayposetmessages: + msg256403
2015-12-14 17:04:16hayposetfiles: + code_richcompare.patch
keywords: + patch
messages: + msg256402
2015-12-14 17:03:04serhiy.storchakasetmessages: + msg256401
2015-12-14 16:55:30hayposetmessages: + msg256400
2015-12-14 16:55:25serhiy.storchakasetmessages: + msg256399
2015-12-14 16:52:39r.david.murraysetmessages: + msg256398
2015-12-14 16:37:48hayposetnosy: + haypo
2015-12-14 16:30:37r.david.murraysetmessages: + msg256390
2015-12-14 16:07:55serhiy.storchakasetmessages: + msg256386
2015-12-14 15:54:45ebarrysetmessages: + msg256383
2015-12-14 15:47:15BreamoreBoysetnosy: + BreamoreBoy
messages: + msg256382
2015-12-14 15:28:03rhettingersetmessages: + msg256381
2015-12-13 19:56:19arigosetmessages: + msg256332
2015-12-13 19:40:15ebarrysetmessages: + msg256330
2015-12-13 18:24:40serhiy.storchakasetmessages: + msg256327
2015-12-13 16:53:27ebarrysetnosy: + ebarry
messages: + msg256323
2015-12-13 10:53:11serhiy.storchakasetmessages: + msg256321
2015-12-13 09:47:45David MacIversetnosy: + David MacIver
messages: + msg256320
2015-12-13 08:54:12serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg256318
2015-12-13 07:51:13arigosetmessages: + msg256317
2015-12-12 23:28:20torstensetnosy: + torsten
2015-12-12 19:28:09rhettingersetnosy: + arigo, fijall
messages: + msg256290
2015-12-12 13:38:40ncoghlansetnosy: + ncoghlan
messages: + msg256285
2015-12-12 13:02:38donmezsetnosy: + donmez
2015-12-12 10:41:33ezio.melottisetnosy: + ezio.melotti
2015-12-12 08:45:29rhettingersetmessages: + msg256274
2015-12-12 02:55:18rhettingersetmessages: + msg256252
2015-12-12 02:52:01rhettingersetmessages: + msg256251
2015-12-12 02:51:33Kevin Shwehsetnosy: + Kevin Shweh
messages: + msg256250
2015-12-11 23:29:54rhettingersetnosy: + rhettinger
messages: + msg256245
2015-12-11 20:13:29r.david.murraysetmessages: + msg256235
title: unexpected output using pythons ternary operator in combination with lambda -> lambdas on the same line may incorrectly share code objects
2015-12-11 20:08:16Tijs Van Oevelensetmessages: + msg256234
versions: + Python 3.4
2015-12-11 20:05:46Tijs Van Oevelensetmessages: + msg256233
2015-12-11 19:36:19ethan.furmansettitle: unexpected-output-using-pythons-ternary-operator-in-combination-with-lambda -> unexpected output using pythons ternary operator in combination with lambda
2015-12-11 19:33:49r.david.murraysetnosy: + r.david.murray, Tijs Van Oevelen

messages: + msg256230
versions: + Python 2.7, Python 3.5, Python 3.6, - Python 3.4
2015-12-11 19:24:04Tijs Van Oevelensetnosy: - Tijs Van Oevelen
-> (no value)
2015-12-11 19:23:13Tijs Van Oevelencreate