classification
Title: ElementTree not preserving attribute order
Type: enhancement Stage: patch review
Components: Library (Lib) Versions: Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Mariatta, dfrojas, eli.bendersky, nedbat, rhettinger, scoder, serhiy.storchaka, taleinat, vstinner
Priority: normal Keywords: easy, patch

Created on 2018-07-20 00:42 by rhettinger, last changed 2018-11-16 19:52 by rhettinger.

Pull Requests
URL Status Linked Edit
PR 10163 merged rhettinger, 2018-10-28 04:29
PR 10190 merged serhiy.storchaka, 2018-10-28 18:50
PR 10219 merged dfrojas, 2018-10-29 16:31
PR 10452 open serhiy.storchaka, 2018-11-10 20:07
Messages (43)
msg321973 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-07-20 00:42
Starting with Python3.6, the order of keyword arguments has been guaranteed.  Something in ElementTree is not respecting that order.

    $ python3.7
    Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 26 2018, 23:26:24)
    [Clang 6.0 (clang-600.0.57)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from xml.etree.ElementTree import Element, dump
    >>> dump(Element('cirriculum', status='public', company='example'))
    <cirriculum company="example" status="public" />
    >>> #         ^-----------------^-------------------- These are swapped
msg321976 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-07-20 04:46
Attributes are sorted by name when converted an element to the text representation for making it stable. Changing this may break existing software.

I think it makes sense now to add an optional keyword-only parameter sort_attrs (True by default) for functions tostring() and tostringlist() and method ElementTree.write(). If it is False, attributes will keep the original order.

Since dump() is used for debugging only, it could change the behavior by default, even in maintained releases. But currently it just uses ElementTree.write(), which should sort attributes by default for compatibility.
msg321988 - (view) Author: Stefan Behnel (scoder) * Date: 2018-07-20 07:56
At least for lxml, attributes were never specified to have a sorted order (although attribute dicts are sorted on *input*, to give a *predictable* order as in ET), and the tutorial says: "Attributes are just unordered name-value pairs".

However, I still think that Serhiy is right: this change would break code, and in particular test code that compares XML output. Having to deal with two different "correct" serialisations in tests depending on the Python version is annoying at best. But OTOH, comparing XML output should always be based on C14N and not on an arbitrary serialisation. XML C14N serialisation was specifically designed to provide a deterministic output byte sequence, regardless of how the XML document was created. (This is also used for cryptographic fingerprinting.)

It is interesting that ET sorts the attributes on output. lxml does it only on API *input*, because the underlying tree model is order preserving. Parsed attributes are always written in the original document order, followed by the attributes set through the API in the order in which they were set.

For lxml, a serialisation flag is not going to help, because the serialisation order is always deterministic from the time where an attribute is added to the tree. Given that dicts are order preserving in Python now, ET could follow this path as well. The attributes are already in parse order and could easily be serialised that way, and attributes that were added through the API would end up being serialised last, also preserving the order. This would leave lxml and ET with the same serialisation order, which seems attractive.

In short, I like this change, it's just difficult to see a way how this could preserve full backwards compatibility. And it's difficult to say how important backwards compatibility really is here.
msg328429 - (view) Author: Tal Einat (taleinat) * (Python committer) Date: 2018-10-25 12:17
This doesn't strike me as a bug, or even clearly being a potential improvement.

If this about round-trip parsing/serializing not preserving order, that would be significant. As it is, if this is only intended as a debugging tool, why change it?

Is there a concrete reason to change this and break backwards compatibility? If not I suggest we close this as "won't fix".
msg328456 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-10-25 17:10
Consider this as a feature request.  It is perfectly reasonable for a user to want to generate specific XML output and to want to control the order that the attributes are listed.  It is perfectly reasonable for the API to preserve the order that the user specified rather than change it into some other order that they either don't expect or can't control.  Starting in Python 3.6, the language guarantees that the order of keyword arguments is preserved.  Knowing that, it will be natural for users to start viewing as buggy APIs that discard that order when everything else in the eco-system respects the ordering.

When I teach ElementTree in Python courses, students notice this behavior and ask why the order was swapped.  My only answer is that we didn't used to have a way to control it, so the input order was ignored (i.e. a reason that no longer makes sense).
msg328469 - (view) Author: Tal Einat (taleinat) * (Python committer) Date: 2018-10-25 19:25
Thanks for the clarification, Raymond.

I've spent a few minutes searching for uses of dump(), and have only come up with uses for debugging or printing helpful info in command line tools.  So, it seems that changing this as suggested wouldn't break much existing code, since I couldn't easily find even one such example.
msg328588 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-10-26 18:38
This is an easy issue and I left it for beginning contributors. The PR should include the following changes:

* Add an optional sort_attrs parameter (True by default) in the write() method.

* Make the dump() function passing sort_attrs=False to write().

* Add tests for write() (with sort_attrs=False and sort_attrs=True) and dump() and/or modify existing tests.

* Document change (in the module docs, in What's New, news entry).
msg328632 - (view) Author: Diego Rojas (dfrojas) * Date: 2018-10-27 03:09
I'm working on this issue, but I have some questions:

1. If dump() function is only for debugging purpose, and since from dump() is where we will pass the sort_attrs keyword in False in order to conserve the order, I don't see how from dump() we can handle the order of the keyword arguments. The sorted occurs in line 926 (https://github.com/python/cpython/blob/master/Lib/xml/etree/ElementTree.py#L926) and 982(https://github.com/python/cpython/blob/master/Lib/xml/etree/ElementTree.py#L982) when xml or html are serialized. Or could we pass the sort_attrs to the functions _serialize_html/_serialize_xml and there handle this?

2. Just a comment, maybe sort_attrs is not ambiguous? For a user would be clear that sort_attrs will order the arguments in lexical order or maybe he/she could be confused and take it as that will respect the order of the keywords passed?
msg328633 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-10-27 03:16
Though it is compatible with earlier versions, I don't see any reason to keep sorting at all, especially as a default.  The reasonable default is that whatever order the user specifies is what the tool does.

The backwards compatible argument is specious.  The ordering was never guaranteed.  The only reason that we had sorting was to make the XML generation deterministic, and that is something we would still have.

I vote against the permanent API expansion with an unhelpful default.  The sorting is no longer necessary or desirable.  Appropriately, we never guaranteed it, leaving us the implementation flexibility to make exactly this change.

AFAICT, no XML user has ever expressed an interest in having attributes appear in alphabetical order -- for that matter, I can't recall any HTML user having expressed this preference (instead, they prefer to put class and id tags ahead of other tags for example).
msg328634 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-10-27 03:21
Diego, it would be premature to write an implementation until we've agreed on an API.  

I object to the Serhiy's proposal, and if no one agrees to my proposal to preserve the user's specific actions, then it  would be better to do nothing at all, leaving the current API (deterministic, but with no particular order being guaranteed).
msg328657 - (view) Author: Tal Einat (taleinat) * (Python committer) Date: 2018-10-27 18:12
There is also a middle ground: Keep .write() as it is *and* have .dump() preserve the order in which the parameters were supplied in the constructor.  They could both use a common *internal* method with a flag to select the desired ordering.
msg328659 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-10-27 20:26
Okay, lets just remove sorting.

The method for creating XML file in the minidom module also sorts attributes. It should be changed as well.

XMLGenerator in xml.sax.saxutils doesn't sort attributes.
msg328720 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-10-28 18:17
Diego, I've taken care of the ElementTree case.  Would you like to make a PR for the other occurrences (minidom, html, etc)?
msg328721 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-10-28 18:18
New changeset e3685fd5fdd8808acda81bfc12fb9702d4b59a60 by Raymond Hettinger in branch 'master':
bpo-34160: Preserve user specified order of Element attributes (GH-10163)
https://github.com/python/cpython/commit/e3685fd5fdd8808acda81bfc12fb9702d4b59a60
msg328723 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2018-10-28 18:28
Nice enhancement! I was always annoyed by XML libraries in PHP and Python which don't respect the "insertion order".
msg328763 - (view) Author: Diego Rojas (dfrojas) * Date: 2018-10-28 22:03
Raymond, sure. I could do the rest, I'll start tomorrow Monday.
msg328845 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-10-29 17:31
New changeset 3b05ad7be09af1d4510eb698b0a70d36387f296e by Serhiy Storchaka in branch 'master':
bpo-34160: Preserve user specified order of Element attributes in html. (GH-10190)
https://github.com/python/cpython/commit/3b05ad7be09af1d4510eb698b0a70d36387f296e
msg328846 - (view) Author: Diego Rojas (dfrojas) * Date: 2018-10-29 17:36
Serhiy Storchaka, Raymond. I already made the 10219 PR. Preserves order in html Element attributes and minidom.
msg328881 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-10-30 00:51
Thanks for doing the additional work to finish this up.
msg329416 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-11-07 14:09
New changeset 5598cc90c745dab827e55fadded42dbe85e31d33 by Serhiy Storchaka (Diego Rojas) in branch 'master':
bpo-34160: Preserve order of attributes in minidom. (GH-10219)
https://github.com/python/cpython/commit/5598cc90c745dab827e55fadded42dbe85e31d33
msg329612 - (view) Author: Ned Batchelder (nedbat) * (Python triager) Date: 2018-11-10 14:46
Hi, this broke my tests, just as earlier comments predicted.

Can we get an optional argument to sort the keys?  The json module lets us sort keys even though it's irrelevant to JSON.  Being able to sort attributes would be a very useful addition to the prettyxml method.
msg329613 - (view) Author: Ned Batchelder (nedbat) * (Python triager) Date: 2018-11-10 14:46
(sorry, to sort the attributes.)
msg329614 - (view) Author: Ned Batchelder (nedbat) * (Python triager) Date: 2018-11-10 14:53
To provide a little more context: coverage.py has tests that the XML reports it generates are correct.  It does this by comparing the result to saved XML files.  On Python versions up to 3.7, the file compares correctly.  It has sorted attributes generated by minidom.  Now on Python 3.8, the comparison fails.
msg329616 - (view) Author: Diego Rojas (dfrojas) * Date: 2018-11-10 14:54
Ned, exactly what test fails? I ran all the test suite in local and all was ok, even all passed in the CI build.
msg329618 - (view) Author: Ned Batchelder (nedbat) * (Python triager) Date: 2018-11-10 15:02
Diego, they are my tests in the coverage.py test suite.  I'm checking that my XML generating code is producing the right XML.
msg329619 - (view) Author: Ned Batchelder (nedbat) * (Python triager) Date: 2018-11-10 15:04
This is exactly the situation Stefan was talking about: "However, I still think that Serhiy is right: this change would break code, and in particular test code that compares XML output. Having to deal with two different "correct" serialisations in tests depending on the Python version is annoying at best."

He says comparison should be done with true canonicalization (C14N).  Does that exist in the standard library?  With sorted keys, we had a form of good-enough canonicalization.  Now we don't.
msg329624 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-11-10 16:05
> I'm checking that my XML generating code is producing the right XML.

ISTM that the coverage tests as currently written aren't good tests.  Why not update the tests to check the generated XML is what the code asked it to generate?  Otherwise, the tests are relying on a non-guaranteed implementation detail. 

Alternatively, use c14n.Canonicalize[1] which implements standard compliant cross-language canonicalization (as opposed to non-guaranteed ad-hoc comparison which just happens to work).

[1] https://www.ibm.com/developerworks/xml/library/x-c14n/

Note with attribute order preservation, code now has the ability to produce exactly the XML it wants to produce.  The explicit intention of the user is honored.
msg329626 - (view) Author: Ned Batchelder (nedbat) * (Python triager) Date: 2018-11-10 16:24
I can see that there are ways that I can change my tests.  I see that there are third-party libraries that can help me with this.

But changing the behavior of the standard library, without a way to retain the old behavior, and asking people to adapt by changing their test suites, seems a bit cavalier.

Why not add an option to keep the sorting that the standard library has always had?  I'll even be OK with changing the default behavior to unsorted, just give me a way to explicitly keep the behavior its always had in the past.

The discussion so far has 1) hypothesized that test suites would be broken, and 2) claimed that no one needs the output in sorted order.  I can tell you that my test suite is broken, and that removing the sorted order is what broke it.

The json module has the option to sort keys.  toprettyxml already has options well outside the needs of XML semantics (indent and newl).

Let's honor Python's tradition of standard library stability, and give me a way to keep the behavior I used to have.
msg329627 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-11-10 17:12
> I can see that there are ways that I can change my tests. 
> I see that there are third-party libraries that can help me with this.

Please do that.  That is good design and uses all the tools the way they are meant to be used.


> But changing the behavior of the standard library, without a 
> way to retain the old behavior, and asking people to adapt 
> by changing their test suites, seems a bit cavalier.

Several thoughts:

* We are not cavalier.  We generally work very hard to preserve guaranteed behaviors.  For example, see all the work done on version numbering random seeding or pickle versions.  That said, we cannot be handcuffed by over-reliance on implementation details; otherwise, we wound never be able to improve the library.  The whole point of encapsulation and abstraction is to provide freedom to improve the internals and add capabilities without breaking the API contract.

* It is reasonable for folks to change tests which were flawed from the outset (just like when hash randomization was introduced, it scrambled key order and broke any tests that relied on key order).  FWIW, we remove or fix fragile or ill conceived tests in our own test suite all the time.

* We could add an option to sort attributes but this just clutters the API and turns an old quirk into a permanent fixture.  Instead, I recommend adding a documentation link to a standards compliant canonicalization tool.

> Let's honor Python's tradition of standard library stability, 
> and give me a way to keep the behavior I used to have.

The library IS stable with respect to documented guaranteed behaviors.  With respect to everything else, our tradition is make improvements where we can.  We don't backport these changes so that mirco-releases retain their quirks.  But point releases are allowed and encouraged to make improvements (i.e. this is for 3.8 and later).

In this case, there was never an API contract to sort attributes.  In a way, this is no different than when we improve a repr (see match objects for example).  That would break tests that incorrectly relied on an exact output match.  

When a test stops matching what a tool does, the one that is incorrect is the one that should be changed.  If there is an API contract, the tool needs to change to match.  However, if the test is fundamentally flawed, it should be one to change.
msg329633 - (view) Author: Mariatta Wijaya (Mariatta) * (Python committer) Date: 2018-11-10 18:20
> ISTM that the coverage tests as currently written aren't good tests.

Hi, I'd like to remind everyone to be open, respectful, and considerate. There are ways to describe hos things that can be improved. There is no need to denigrate other people's work.
msg329634 - (view) Author: Mariatta Wijaya (Mariatta) * (Python committer) Date: 2018-11-10 18:30
IMO adding optional keyword argument to make it compatible with previous version is reasonable request, and it seems early on several other core devs also agree with it.
msg329635 - (view) Author: Tal Einat (taleinat) * (Python committer) Date: 2018-11-10 18:37
>> ISTM that the coverage tests as currently written aren't good tests.

> Hi, I'd like to remind everyone to be open, respectful, and considerate. There are ways to describe hos things that can be improved. There is no need to denigrate other people's work.

I find this to be an overreaction in this case.  Sure, it could have been worded more positively, but the negativity was very mild; the tests weren't even being called "bad", not to mention overly negative wording e.g. "horrible".

Further, you omitted the followup explanation of *what about the tests isn't good*:

> Otherwise, the tests are relying on a non-guaranteed implementation detail.

IMO we shouldn't require ourselves to be overly careful in our wording, such as avoiding any negative wording entirely.
msg329637 - (view) Author: Ned Batchelder (nedbat) * (Python triager) Date: 2018-11-10 18:51
Words like flawed from the outset, fundamentally flawed, fragile, and ill-conceived are being thrown around, which does not help the discussion.  Can we focus on the question of whether it's reasonable to add sorted attributes as an option?

This idea exactly parallels the sort_keys option in the json module.  It precisely solves the problem I have.  The code change is small.  I'll even volunteer to make the pull request.

I'm not suggesting that we get rid of the new feature of preserving the user's attributes order. I'm not even suggesting that the new feature needs to be the non-default option. I'd just like a way to sort attributes in XML output.
msg329639 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-11-10 19:32
> Being able to sort attributes would be a very useful addition 
> to the prettyxml method.

+1 This seems reasonable to me.

I misread it and thought it was much broader than prettyxml().
msg329642 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-11-10 20:13
Raymond's words convinced me, but if it is needed for preserving compatibility in tests, here is PR 10452 which adds support for the sort_attrs argument in XML serializing methods.
msg329643 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-11-10 20:47
One other thought:  We should add a note to the docs for all of the serialization formats saying that we specifically disclaim that they will always generate exactly the same output byte-for-byte.  When Serhiy made some small optimizations to the encoding of pickles, it would have broken any test that checked byte-level equality rather than semantic level equality (checked by making sure the pickle/unpickle steps would round-trip without loss of information).
msg329698 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2018-11-12 00:07
I like the idea of having an opt-in option to get Python 3.7 behavior in Python 3.8, sort=True. It would be a new parameter in Python 3.8, right?

It makes sense to me to ask explicitly to sort attributes, especially since Python decided to no longer sort by default :-)

Maybe some people prefer sorting to get a more deterministic output for things like https://reproducible-builds.org/
msg329999 - (view) Author: Stefan Behnel (scoder) * Date: 2018-11-16 14:04
> Maybe some people prefer sorting to get a more deterministic output

Note that those people are much better off with C14N. It is the one tool designed for all of these use cases, even usable for cryptographic signatures. And it's trivial to use, it's just a different serialiser.

The new option would only be for people who want the old behaviour for backwards compatibility reasons, like Ned who wants to keep his existing byte level tests working that were created by the previous version. Understandable, although re-serialising the test samples with C14N would probably still be the better approach, because it guards against more than just changes in the attribute order.

Maybe it's time to think about adding the ET C14N module to the stdlib again, see issue13611.
msg330003 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-11-16 14:38
+1 for adding C14N support for ElementTree.

But the problem will still exist for minidom. We will need either add the sort_attrs parameter in prettyxml() or complete C14N support in minidom.
msg330004 - (view) Author: Ned Batchelder (nedbat) * (Python triager) Date: 2018-11-16 14:38
Stefan, just to clarify: it isn't that I don't feel like re-serializing my gold files with the latest version.  I run my test suite on 2.7, 3.4, 3.5, 3.6, 3.7, 3.8, PyPy2, and PyPy3.  Today, one gold file suffices for all those versions.  Without the sorted attributes, 3.8 fails the test.
msg330011 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-11-16 19:12
> I run my test suite on 2.7, 3.4, 3.5, 3.6, 3.7, 3.8, PyPy2, 
> and PyPy3.  Today, one gold file suffices for all those
> versions.  Without the sorted attributes, 3.8 fails the test.

Would it make sense to rewrite the test to just make sure the XML roundtrips instead of relying on the exact byte sequence that is generated?  IIRC, that is how we test pickling and various codecs -- rather than relying on implement specific details for a particular byte sequence -- the test is roughly "assert decode(encode(thing)) == thing".  That allows the test to survive on-going improvements to serialization.
msg330012 - (view) Author: Ned Batchelder (nedbat) * (Python triager) Date: 2018-11-16 19:21
It seemed like we were close to a consensus about adding back the option to sort the attributes, or did I misunderstand?
msg330013 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-11-16 19:52
> It seemed like we were close to a consensus about adding 
> back the option to sort the attributes, or did I 
> misunderstand?

Adding a sort() option to prettyxml() seems perfectly reasonable.  I wouldn't extend any of the other APIs though.

Also, it is reasonable to consider adding a standards compliant canonicalization tool.

> Without the sorted attributes, 3.8 fails the test.

It seems to me that the test should be improved as well so that it doesn't rely on implementation details.  The usual way to test serialization is to verify that it round trips.

Unless the test is improved to not rely on implementation details, I'm concerned that we'll end-up having this conversation again if any other serialization improvements are made.

So yes, I support adding a sort() option to prettyxml() and adding a canonicalization tool, but no I don't agree with the premise that Py 2.7, 3.4, 3.5, 3.6, 3.7, 3.8 were required to now and forever always produce byte-by-byte identical output -- afaict that was never a promised behavior, so any test that relies on that premise should be improved.

FWIW, when I described the existing test as being "fragile", it wasn't a pejorative, I meant it in the literal sense of "easily broken".
History
Date User Action Args
2018-11-16 19:52:14rhettingersetmessages: + msg330013
2018-11-16 19:21:30nedbatsetmessages: + msg330012
2018-11-16 19:12:49rhettingersetmessages: + msg330011
2018-11-16 14:38:54nedbatsetmessages: + msg330004
2018-11-16 14:38:25serhiy.storchakasetmessages: + msg330003
2018-11-16 14:04:22scodersetmessages: + msg329999
2018-11-12 00:07:13vstinnersetmessages: + msg329698
2018-11-10 20:47:03rhettingersetmessages: + msg329643
2018-11-10 20:13:38serhiy.storchakasetmessages: + msg329642
2018-11-10 20:07:36serhiy.storchakasetpull_requests: + pull_request9727
2018-11-10 19:32:16rhettingersetmessages: + msg329639
2018-11-10 18:51:35nedbatsetmessages: + msg329637
2018-11-10 18:37:10taleinatsetmessages: + msg329635
2018-11-10 18:30:08Mariattasetmessages: + msg329634
2018-11-10 18:20:17Mariattasetnosy: + Mariatta
messages: + msg329633
2018-11-10 17:12:52rhettingersetmessages: + msg329627
2018-11-10 16:24:57nedbatsetmessages: + msg329626
2018-11-10 16:05:07rhettingersetmessages: + msg329624
2018-11-10 15:04:56nedbatsetmessages: + msg329619
2018-11-10 15:02:34nedbatsetmessages: + msg329618
2018-11-10 14:54:57dfrojassetmessages: + msg329616
2018-11-10 14:53:27nedbatsetmessages: + msg329614
2018-11-10 14:46:48nedbatsetmessages: + msg329613
2018-11-10 14:46:27nedbatsetnosy: + nedbat
messages: + msg329612
2018-11-07 14:09:16serhiy.storchakasetmessages: + msg329416
2018-10-30 00:51:53rhettingersetmessages: + msg328881
2018-10-29 17:36:41dfrojassetmessages: + msg328846
2018-10-29 17:31:10serhiy.storchakasetmessages: + msg328845
2018-10-29 16:31:26dfrojassetpull_requests: + pull_request9535
2018-10-28 22:03:37dfrojassetmessages: + msg328763
2018-10-28 18:50:16serhiy.storchakasetpull_requests: + pull_request9508
2018-10-28 18:28:37vstinnersetnosy: + vstinner
messages: + msg328723
2018-10-28 18:18:26rhettingersetmessages: + msg328721
2018-10-28 18:17:54rhettingersetmessages: + msg328720
2018-10-28 04:29:10rhettingersetkeywords: + patch
stage: patch review
pull_requests: + pull_request9486
2018-10-27 20:26:35serhiy.storchakasetmessages: + msg328659
2018-10-27 18:12:49taleinatsetmessages: + msg328657
2018-10-27 03:21:12rhettingersetmessages: + msg328634
2018-10-27 03:16:47rhettingersetmessages: + msg328633
2018-10-27 03:09:43dfrojassetnosy: + dfrojas
messages: + msg328632
2018-10-26 18:38:48serhiy.storchakasetkeywords: + easy

messages: + msg328588
2018-10-25 19:25:01taleinatsetmessages: + msg328469
2018-10-25 17:10:00rhettingersettype: behavior -> enhancement
messages: + msg328456
versions: - Python 3.6, Python 3.7
2018-10-25 12:17:05taleinatsetnosy: + taleinat
messages: + msg328429
2018-07-20 07:56:42scodersetmessages: + msg321988
2018-07-20 04:46:12serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg321976
2018-07-20 00:42:07rhettingercreate