)]}'
{".bzrignore":[{"author":{"_account_id":2475,"name":"Antoine Musso","email":"hashar@free.fr","username":"hashar"},"change_message_id":"885be10e8fc460abd1a24fcef4035bed645fe599","unresolved":false,"context_lines":[{"line_number":7,"context_line":"build"},{"line_number":8,"context_line":"dist"},{"line_number":9,"context_line":".coverage"},{"line_number":10,"context_line":"coverage.xml"}],"source_content_type":"application/octet-stream","patch_set":6,"id":"AAAAXX%2F%2F16Y%3D","line":10,"updated":"2014-04-25 20:49:05.000000000","message":"I am sure you can drop that .bzrignore file :]  Though your local copy probably has both bzr and git.","commit_id":"293f230f41d38bd71bdb0e6a9f1a01c51ec60bb1"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"3f495769cac4799c667c99a6d3e052058db5007a","unresolved":false,"context_lines":[{"line_number":7,"context_line":"build"},{"line_number":8,"context_line":"dist"},{"line_number":9,"context_line":".coverage"},{"line_number":10,"context_line":"coverage.xml"}],"source_content_type":"application/octet-stream","patch_set":6,"id":"AAAAXX%2F%2F0iI%3D","line":10,"in_reply_to":"AAAAXX%2F%2F16Y%3D","updated":"2014-04-26 03:58:50.000000000","message":"Done","commit_id":"293f230f41d38bd71bdb0e6a9f1a01c51ec60bb1"}],".gitignore":[{"author":{"_account_id":7156,"name":"Mathieu Gagné","email":"mgagne@calavera.ca","username":"mgagne"},"change_message_id":"00a1a70da1ef61a3469a4a8475934de19d218085","unresolved":false,"context_lines":[{"line_number":7,"context_line":"/MANIFEST"},{"line_number":8,"context_line":"/dist/*"},{"line_number":9,"context_line":"/doc/build/*"},{"line_number":10,"context_line":"/.test"},{"line_number":11,"context_line":"/.testrepository"},{"line_number":12,"context_line":"/MANIFEST"},{"line_number":13,"context_line":".coverage"}],"source_content_type":"application/octet-stream","patch_set":11,"id":"9ad9bd40_c3ce062e","line":10,"updated":"2014-05-05 17:43:34.000000000","message":"Could those changes be dropped? They are unrelated to Python 3 support","commit_id":"0173f1afc446548a58fb4a0e05474c72fd8281b4"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"6fa6af7c5b52f7f646729b65a089614cccf4d452","unresolved":false,"context_lines":[{"line_number":7,"context_line":"/MANIFEST"},{"line_number":8,"context_line":"/dist/*"},{"line_number":9,"context_line":"/doc/build/*"},{"line_number":10,"context_line":"/.test"},{"line_number":11,"context_line":"/.testrepository"},{"line_number":12,"context_line":"/MANIFEST"},{"line_number":13,"context_line":".coverage"}],"source_content_type":"application/octet-stream","patch_set":11,"id":"9ad9bd40_697519f9","line":10,"in_reply_to":"9ad9bd40_c3ce062e","updated":"2014-05-05 18:46:08.000000000","message":"Oops. I can take those out.","commit_id":"0173f1afc446548a58fb4a0e05474c72fd8281b4"}],"jenkins/__init__.py":[{"author":{"_account_id":2475,"name":"Antoine Musso","email":"hashar@free.fr","username":"hashar"},"change_message_id":"885be10e8fc460abd1a24fcef4035bed645fe599","unresolved":false,"context_lines":[{"line_number":624,"context_line":"            raise JenkinsException("},{"line_number":625,"context_line":"                \u0027Could not parse JSON info for job[%s] number[%d]\u0027"},{"line_number":626,"context_line":"                % (name, number)"},{"line_number":627,"context_line":"            )"}],"source_content_type":"text/x-python","patch_set":6,"id":"AAAAXX%2F%2F13s%3D","side":"PARENT","line":627,"updated":"2014-04-25 20:49:05.000000000","message":"In get_build_console_output() you removed the handling of ValueError exception.  I guess it is a mistake since it is at the very end of the file.","commit_id":"0760bcb0e5c0b13a0e55ed0049d1dc7c56a06147"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"a598dab34ae0f7bfc3275b5f407853a5f49be744","unresolved":false,"context_lines":[{"line_number":624,"context_line":"            raise JenkinsException("},{"line_number":625,"context_line":"                \u0027Could not parse JSON info for job[%s] number[%d]\u0027"},{"line_number":626,"context_line":"                % (name, number)"},{"line_number":627,"context_line":"            )"}],"source_content_type":"text/x-python","patch_set":6,"id":"AAAAXX%2F%2F0i4%3D","side":"PARENT","line":627,"in_reply_to":"AAAAXX%2F%2F13s%3D","updated":"2014-04-26 03:57:48.000000000","message":"Actually, this was intentional (though it took me a couple of minutes to remember why, as it\u0027s a little subtle).\n\nThe reason why is that this catches ValueError and you can tell from the message string that it\u0027s designed to catch a ValueError that occurs when trying to parse JSON (e.g.: calling `json.loads()`), but this function has no `json.loads()`.\n\nI suspect that this except clause was only here because it was copied from another function that does have `json.loads()`. Most of the functions retrieve something via HTTP and then calls `json.loads()` to parse the JSON, but in the case of console output, Jenkins just returns the straight text verbatim; it\u0027s not wrapped in JSON. So there is no `json.loads()` and therefore it should never fail to parse JSON! :-)\n\nThis is the kind of change that I feel would be easier to understand if it were in a very simple atomic changeset that just did this. And that\u0027s normally the way I work. But I feel that the Gerrit system and the overhead involved in getting reviews encourages much larger changesets. I\u0027m not sure how to handle these things. With GitHub, I would use more commits, but Gerrit doesn\u0027t seem to like that sort of workflow.","commit_id":"0760bcb0e5c0b13a0e55ed0049d1dc7c56a06147"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"a598dab34ae0f7bfc3275b5f407853a5f49be744","unresolved":false,"context_lines":[{"line_number":148,"context_line":"    \u0027Authentication\u0027 header value."},{"line_number":149,"context_line":"    \u0027\u0027\u0027"},{"line_number":150,"context_line":"    auth \u003d \u0027%s:%s\u0027 % (username, password)"},{"line_number":151,"context_line":"    auth \u003d auth[:-1]"},{"line_number":152,"context_line":"    auth \u003d auth.encode(\u0027ascii\u0027)"},{"line_number":153,"context_line":"    return b\u0027Basic \u0027 + base64.encodestring(auth)"},{"line_number":154,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"AAAAXX%2F%2F0jc%3D","line":151,"updated":"2014-04-26 03:57:48.000000000","message":"This is wrong. I corrected it though in the next changeset.","commit_id":"293f230f41d38bd71bdb0e6a9f1a01c51ec60bb1"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"3118d4a458d977a1dd06e471dcaf0cb289e7e1d9","unresolved":false,"context_lines":[{"line_number":55,"context_line":"try:"},{"line_number":56,"context_line":"    # Python 2"},{"line_number":57,"context_line":"    from urllib import quote, urlencode"},{"line_number":58,"context_line":"except ImportError:  # pragma: no cover"},{"line_number":59,"context_line":"    # Python 3"},{"line_number":60,"context_line":"    from urllib.parse import quote, urlencode"},{"line_number":61,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"7adec928_994bc12a","line":58,"updated":"2014-05-12 12:59:24.000000000","message":"You should merge these two try/except into a single try/except.","commit_id":"391d6a93280c5a653fe6ab05f2e4daa3fd558d5f"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"af2c60754759fd8b74752e225b0fe073dde70c0a","unresolved":false,"context_lines":[{"line_number":55,"context_line":"try:"},{"line_number":56,"context_line":"    # Python 2"},{"line_number":57,"context_line":"    from urllib import quote, urlencode"},{"line_number":58,"context_line":"except ImportError:  # pragma: no cover"},{"line_number":59,"context_line":"    # Python 3"},{"line_number":60,"context_line":"    from urllib.parse import quote, urlencode"},{"line_number":61,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"7adec928_fd4bc784","line":58,"in_reply_to":"7adec928_994bc12a","updated":"2014-05-13 06:24:46.000000000","message":"I think in the next version, I might use six and then this will be even simpler.","commit_id":"391d6a93280c5a653fe6ab05f2e4daa3fd558d5f"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"3118d4a458d977a1dd06e471dcaf0cb289e7e1d9","unresolved":false,"context_lines":[{"line_number":148,"context_line":"    \u0027Authentication\u0027 header value."},{"line_number":149,"context_line":"    \u0027\u0027\u0027"},{"line_number":150,"context_line":"    auth \u003d \u0027%s:%s\u0027 % (username, password)"},{"line_number":151,"context_line":"    return b\u0027Basic \u0027 + base64.encodestring(auth.encode(\u0027ascii\u0027))[:-1]"},{"line_number":152,"context_line":""},{"line_number":153,"context_line":""},{"line_number":154,"context_line":"class Jenkins(object):"}],"source_content_type":"text/x-python","patch_set":12,"id":"7adec928_59105901","line":151,"range":{"start_line":151,"start_character":30,"end_line":151,"end_character":42},"updated":"2014-05-12 12:59:24.000000000","message":"What are the types of username and password? If they are bytes strings, it doesn\u0027t make sense to call .encode(\u0027ascii\u0027) here, you should write:\n\nif six.PY3:\n  auth \u003d auth.encode(\u0027ascii\u0027)\nreturn ...","commit_id":"391d6a93280c5a653fe6ab05f2e4daa3fd558d5f"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"af2c60754759fd8b74752e225b0fe073dde70c0a","unresolved":false,"context_lines":[{"line_number":148,"context_line":"    \u0027Authentication\u0027 header value."},{"line_number":149,"context_line":"    \u0027\u0027\u0027"},{"line_number":150,"context_line":"    auth \u003d \u0027%s:%s\u0027 % (username, password)"},{"line_number":151,"context_line":"    return b\u0027Basic \u0027 + base64.encodestring(auth.encode(\u0027ascii\u0027))[:-1]"},{"line_number":152,"context_line":""},{"line_number":153,"context_line":""},{"line_number":154,"context_line":"class Jenkins(object):"}],"source_content_type":"text/x-python","patch_set":12,"id":"7adec928_1d4f9393","line":151,"in_reply_to":"7adec928_59105901","updated":"2014-05-13 06:24:46.000000000","message":"Think I\u0027ll change to `six.b` which converts to bytes when needed.","commit_id":"391d6a93280c5a653fe6ab05f2e4daa3fd558d5f"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"3118d4a458d977a1dd06e471dcaf0cb289e7e1d9","unresolved":false,"context_lines":[{"line_number":444,"context_line":"        :returns: job configuration (XML format)"},{"line_number":445,"context_line":"        \u0027\u0027\u0027"},{"line_number":446,"context_line":"        request \u003d Request("},{"line_number":447,"context_line":"            self.server + CONFIG_JOB % {\"name\": quote(name)})"},{"line_number":448,"context_line":"        return self.jenkins_open(request)"},{"line_number":449,"context_line":""},{"line_number":450,"context_line":"    def reconfig_job(self, name, config_xml):"}],"source_content_type":"text/x-python","patch_set":12,"id":"7adec928_b9f4fdcf","line":447,"range":{"start_line":447,"start_character":23,"end_line":447,"end_character":24},"updated":"2014-05-12 12:59:24.000000000","message":"The indentation here is surprising. Keep the original format or add some more spaces to align to \"(\" of \"Request(\".","commit_id":"391d6a93280c5a653fe6ab05f2e4daa3fd558d5f"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"af2c60754759fd8b74752e225b0fe073dde70c0a","unresolved":false,"context_lines":[{"line_number":444,"context_line":"        :returns: job configuration (XML format)"},{"line_number":445,"context_line":"        \u0027\u0027\u0027"},{"line_number":446,"context_line":"        request \u003d Request("},{"line_number":447,"context_line":"            self.server + CONFIG_JOB % {\"name\": quote(name)})"},{"line_number":448,"context_line":"        return self.jenkins_open(request)"},{"line_number":449,"context_line":""},{"line_number":450,"context_line":"    def reconfig_job(self, name, config_xml):"}],"source_content_type":"text/x-python","patch_set":12,"id":"7adec928_bd305f02","line":447,"in_reply_to":"7adec928_b9f4fdcf","updated":"2014-05-13 06:24:46.000000000","message":"Done","commit_id":"391d6a93280c5a653fe6ab05f2e4daa3fd558d5f"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"93fe03b823dacd4a0317b1ca6adb7a6a54f95ba2","unresolved":false,"context_lines":[{"line_number":133,"context_line":"    \u0027Authentication\u0027 header value."},{"line_number":134,"context_line":"    \u0027\u0027\u0027"},{"line_number":135,"context_line":"    auth \u003d \u0027%s:%s\u0027 % (username, password)"},{"line_number":136,"context_line":"    return b\u0027Basic \u0027 + base64.encodestring(b(auth))[:-1]"},{"line_number":137,"context_line":""},{"line_number":138,"context_line":""},{"line_number":139,"context_line":"class Jenkins(object):"}],"source_content_type":"text/x-python","patch_set":13,"id":"7adec928_83b18091","line":136,"updated":"2014-05-13 08:50:16.000000000","message":"bytes(str) is invalid in Python 3: it raises a BytesWarning exception if python3 is started with -bb. You must encode the string explicitly. Example:\n\nauth \u003d ...\nif isinstance(auth, six.text_type):\n    auth \u003d auth.encode(\u0027utf-8\u0027)\nreturn ...\n\nAnother question unrelated to your change: Why the last character of the base64 encoded string is dropped?","commit_id":"683e07d1935be50653f49f6ef43a4eb2ca4e1fe7"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"25cb52134642d320bcb81874bc0e0ec2717d4ddc","unresolved":false,"context_lines":[{"line_number":133,"context_line":"    \u0027Authentication\u0027 header value."},{"line_number":134,"context_line":"    \u0027\u0027\u0027"},{"line_number":135,"context_line":"    auth \u003d \u0027%s:%s\u0027 % (username, password)"},{"line_number":136,"context_line":"    return b\u0027Basic \u0027 + base64.encodestring(b(auth))[:-1]"},{"line_number":137,"context_line":""},{"line_number":138,"context_line":""},{"line_number":139,"context_line":"class Jenkins(object):"}],"source_content_type":"text/x-python","patch_set":13,"id":"7adec928_f764bb4a","line":136,"in_reply_to":"7adec928_83b18091","updated":"2014-05-13 15:39:26.000000000","message":"six.b(str) is not the same as bytes(str).\n\n    ? .tox/py33/bin/python -bb\n    \u003e\u003e\u003e bytes(\u0027foo\u0027)\n    Traceback (most recent call last):\n      File \"\u003cstdin\u003e\", line 1, in \u003cmodule\u003e\n    TypeError: string argument without an encoding\n    \u003e\u003e\u003e import six\n    \u003e\u003e\u003e six.b(\u0027foo\u0027)\n    b\u0027foo\u0027\n\nHere\u0027s the definition:\n\n    if PY3:\n        def b(s):\n            return s.encode(\"latin-1\")\n\nMaybe encoding to UTF-8 is better? But I have no idea how Jenkins will deal with encodings.\n\nI don\u0027t know why the last character is dropped. I\u0027m preserving the existing behavior because it seems to work.\n\nOne of the original authors might know why the character is dropped.","commit_id":"683e07d1935be50653f49f6ef43a4eb2ca4e1fe7"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"e2186b5df293aebefc7867b53da793c07221fe75","unresolved":false,"context_lines":[{"line_number":133,"context_line":"    \u0027Authentication\u0027 header value."},{"line_number":134,"context_line":"    \u0027\u0027\u0027"},{"line_number":135,"context_line":"    auth \u003d \u0027%s:%s\u0027 % (username, password)"},{"line_number":136,"context_line":"    return b\u0027Basic \u0027 + base64.encodestring(b(auth))[:-1]"},{"line_number":137,"context_line":""},{"line_number":138,"context_line":""},{"line_number":139,"context_line":"class Jenkins(object):"}],"source_content_type":"text/x-python","patch_set":19,"id":"7adec928_bc9ccfc1","line":136,"range":{"start_line":136,"start_character":43,"end_line":136,"end_character":44},"updated":"2014-05-14 08:58:39.000000000","message":"This is a strange usage of the six.b function. This function is written to be used with string literals: b(\"abc\").\n\nYou wrote that six.b(text) calls text.encode(\u0027utf8\u0027) on Python 3. Latin1 (ISO 8859-1) is a subset of Unicode: 256 code points, whereas the Unicode Character Set contains 1,114,112 code points. For example, chinese or the euro sign cannot be encoded to ISO-8859-1.\n\nI suggest to use an explicit conversion to UTF-8 if the auth type is six.text_type.","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"f7c415ac3b1a3f7e6d95098353c5ebdeb78867f2","unresolved":false,"context_lines":[{"line_number":133,"context_line":"    \u0027Authentication\u0027 header value."},{"line_number":134,"context_line":"    \u0027\u0027\u0027"},{"line_number":135,"context_line":"    auth \u003d \u0027%s:%s\u0027 % (username, password)"},{"line_number":136,"context_line":"    return b\u0027Basic \u0027 + base64.encodestring(b(auth))[:-1]"},{"line_number":137,"context_line":""},{"line_number":138,"context_line":""},{"line_number":139,"context_line":"class Jenkins(object):"}],"source_content_type":"text/x-python","patch_set":19,"id":"7adec928_b2d4f320","line":136,"in_reply_to":"7adec928_bc9ccfc1","updated":"2014-05-14 16:18:20.000000000","message":"Done.\n\nHowever...\n\nNote that Unicode characters and HTTP Basic Auth are known to not work very well, because HTTP doesn\u0027t provide a way to specify what the encoding is and different browsers do different things. So this may not be worth a ton of effort, though this fix does no harm.\n\n- http://tools.ietf.org/id/draft-reschke-basicauth-enc-00.html\n- http://stackoverflow.com/questions/702629/utf-8-characters-mangled-in-http-basic-auth-username\n\nFrom the first link:\n\n The \"Basic\" authentication scheme defined in RFC 2617 does not \n properly define how to treat non-ASCII characters. This has lead to a \n situation where user agent implementations disagree, and servers make\n different assumptions based on the locales they are running in. There is\n little interoperability for characters in the ISO-8859-1 character set, and\n even less interoperability for any characters beyond that.","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"}],"setup.py":[{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"93fe03b823dacd4a0317b1ca6adb7a6a54f95ba2","unresolved":false,"context_lines":[{"line_number":9,"context_line":"      author_email\u003d\u0027kwc@willowgarage.com\u0027,"},{"line_number":10,"context_line":"      url\u003d\u0027http://launchpad.net/python-jenkins\u0027,"},{"line_number":11,"context_line":"      packages\u003d[\u0027jenkins\u0027],"},{"line_number":12,"context_line":"      install_requires\u003d[\u0027six\u0027],"},{"line_number":13,"context_line":"      )"}],"source_content_type":"text/x-python","patch_set":13,"id":"7adec928_23650c45","line":12,"range":{"start_line":12,"start_character":22,"end_line":12,"end_character":25},"updated":"2014-05-13 08:50:16.000000000","message":"You should not use setup.py to install dependencies. The list of dependencies is incomplete and depends on the Python version. If you really want to improve the management of dependencies, modify setup.py to use pbr instead.","commit_id":"683e07d1935be50653f49f6ef43a4eb2ca4e1fe7"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"25cb52134642d320bcb81874bc0e0ec2717d4ddc","unresolved":false,"context_lines":[{"line_number":9,"context_line":"      author_email\u003d\u0027kwc@willowgarage.com\u0027,"},{"line_number":10,"context_line":"      url\u003d\u0027http://launchpad.net/python-jenkins\u0027,"},{"line_number":11,"context_line":"      packages\u003d[\u0027jenkins\u0027],"},{"line_number":12,"context_line":"      install_requires\u003d[\u0027six\u0027],"},{"line_number":13,"context_line":"      )"}],"source_content_type":"text/x-python","patch_set":13,"id":"7adec928_17b84775","line":12,"in_reply_to":"7adec928_23650c45","updated":"2014-05-13 15:39:26.000000000","message":"Done","commit_id":"683e07d1935be50653f49f6ef43a4eb2ca4e1fe7"}],"test-requirements-py3.txt":[{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"3118d4a458d977a1dd06e471dcaf0cb289e7e1d9","unresolved":false,"context_lines":[{"line_number":1,"context_line":"discover"},{"line_number":2,"context_line":"flake8"},{"line_number":3,"context_line":"mock"},{"line_number":4,"context_line":"unittest2py3k"}],"source_content_type":"text/plain","patch_set":12,"id":"7adec928_39938d50","line":3,"updated":"2014-05-12 12:59:24.000000000","message":"These 3 dependencies are already present in test-requirements.txt, you should not repeat them here. See my comment in tox.ini.","commit_id":"391d6a93280c5a653fe6ab05f2e4daa3fd558d5f"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"3118d4a458d977a1dd06e471dcaf0cb289e7e1d9","unresolved":false,"context_lines":[{"line_number":1,"context_line":"discover"},{"line_number":2,"context_line":"flake8"},{"line_number":3,"context_line":"mock"},{"line_number":4,"context_line":"unittest2py3k"}],"source_content_type":"text/plain","patch_set":12,"id":"7adec928_599a1964","line":4,"range":{"start_line":4,"start_character":0,"end_line":4,"end_character":13},"updated":"2014-05-12 12:59:24.000000000","message":"I don\u0027t see where unittest2 is used in your patch. Why only using unittest2 on Python 3.2 and not in Python 2.7?\n\nIf you don\u0027t use unittest2, just drop the whole test-requirements-py3.txt file.","commit_id":"391d6a93280c5a653fe6ab05f2e4daa3fd558d5f"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"af2c60754759fd8b74752e225b0fe073dde70c0a","unresolved":false,"context_lines":[{"line_number":1,"context_line":"discover"},{"line_number":2,"context_line":"flake8"},{"line_number":3,"context_line":"mock"},{"line_number":4,"context_line":"unittest2py3k"}],"source_content_type":"text/plain","patch_set":12,"id":"7adec928_bd077f1b","line":4,"in_reply_to":"7adec928_599a1964","updated":"2014-05-13 06:24:46.000000000","message":"It is used here:\n\n    ? grep -Hn --after\u003d2 unittest2 tests/test_jenkins.py\n    tests/test_jenkins.py:5:    import unittest2 as unittest\n    tests/test_jenkins.py-6-except ImportError:\n    tests/test_jenkins.py-7-    if sys.version_info \u003c (2, 7):\n    --\n    tests/test_jenkins.py:8:        # On Pythons 2.6 and older, we must have unittest2, because the\n    tests/test_jenkins.py-9-        # standard library doesn\u0027t have what we need\n    tests/test_jenkins.py-10-        raise  # pragma: no cover\n\nThe reason for unittest2 is that I use self.assertRaises as a context manager. This feature is built into Python 2.7 but for Python 2.6 you need to install unittest2 to get it.","commit_id":"391d6a93280c5a653fe6ab05f2e4daa3fd558d5f"}],"test-requirements.txt":[{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"93fe03b823dacd4a0317b1ca6adb7a6a54f95ba2","unresolved":false,"context_lines":[{"line_number":1,"context_line":"discover"},{"line_number":2,"context_line":"flake8"},{"line_number":3,"context_line":"mock"},{"line_number":4,"context_line":"pytest"}],"source_content_type":"text/plain","patch_set":13,"id":"7adec928_a3d75cbe","line":4,"updated":"2014-05-13 08:50:16.000000000","message":"You should not change different things in the same patch, it makes it harder to review.","commit_id":"683e07d1935be50653f49f6ef43a4eb2ca4e1fe7"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"25cb52134642d320bcb81874bc0e0ec2717d4ddc","unresolved":false,"context_lines":[{"line_number":1,"context_line":"discover"},{"line_number":2,"context_line":"flake8"},{"line_number":3,"context_line":"mock"},{"line_number":4,"context_line":"pytest"}],"source_content_type":"text/plain","patch_set":13,"id":"7adec928_d7641f24","line":4,"in_reply_to":"7adec928_a3d75cbe","updated":"2014-05-13 15:39:26.000000000","message":"OK, eliminating pytest and putting unittest2 back.","commit_id":"683e07d1935be50653f49f6ef43a4eb2ca4e1fe7"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"e2186b5df293aebefc7867b53da793c07221fe75","unresolved":false,"context_lines":[{"line_number":1,"context_line":"discover"},{"line_number":2,"context_line":"flake8"},{"line_number":3,"context_line":"mock"},{"line_number":4,"context_line":"unittest2six"},{"line_number":5,"context_line":"six"}],"source_content_type":"text/plain","patch_set":19,"id":"7adec928_bcd12f59","line":4,"updated":"2014-05-14 08:58:39.000000000","message":"I didn\u0027t know this module. It looks like you still need unitest2 on Python 2 and unittest2py3k on Python 3:\n\n\"On Python 2, [unitest2six] imports unittest2. On Python 3, this imports unittest2py3k.\"\n\nYou should try to keep the patch simple and try to support more Python 3 versions in a different patch.\n\nBy the way, why do you focus on unittest2py3k? This module helps to support Python 3.1, but unitest.TestCase of Python 3.2 already has all new assertXXX() methods. OpenStack doesn\u0027t support Python 3.1. Python 3.1 is old, has many bugs, and no more Linux distribution uses it.\n\nIn short: you don\u0027t need unittest2py3k.\n\nIf you really want to do something, you can avoid installing unittest2 on Python 3, because it is no more needed. But it can be done in a second patch because it is a little bit tricky and it is not directly related to this patch.","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"1db5fc7ea351fcd17c94a69b20cbe1c9e95d7810","unresolved":false,"context_lines":[{"line_number":1,"context_line":"discover"},{"line_number":2,"context_line":"flake8"},{"line_number":3,"context_line":"mock"},{"line_number":4,"context_line":"unittest2six"},{"line_number":5,"context_line":"six"}],"source_content_type":"text/plain","patch_set":19,"id":"7adec928_c808ee93","line":4,"in_reply_to":"7adec928_523baf37","updated":"2014-05-14 16:43:43.000000000","message":"Oh, I didn\u0027t know that unittest2 raises SyntaxError on Python 3.\n\nI sent a pull request to pip to be able to specify markers on dependencies, so I would be possible to only install unittest2 on python \u003c\u003d 2.6:\nhttps://github.com/pypa/pip/pull/1472\n\nBut my pull request was not accepted yet... The workaround is to use test-requirements-py2.txt which should now be used automatically by PBR.","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"f7c415ac3b1a3f7e6d95098353c5ebdeb78867f2","unresolved":false,"context_lines":[{"line_number":1,"context_line":"discover"},{"line_number":2,"context_line":"flake8"},{"line_number":3,"context_line":"mock"},{"line_number":4,"context_line":"unittest2six"},{"line_number":5,"context_line":"six"}],"source_content_type":"text/plain","patch_set":19,"id":"7adec928_523baf37","line":4,"in_reply_to":"7adec928_bcd12f59","updated":"2014-05-14 16:18:20.000000000","message":"I just pushed this module to PyPI yesterday :-)\n\nAnd just now I corrected the docs for it, because the language that you quoted is confusing. It doesn\u0027t *import* unittest2 or unittest2py3k. Rather, it *install_requires* them. So you don\u0027t need either one. It picks the right one for you. The package has no code actually. It\u0027s just a \"meta package\" that pulls in the right dependency, depending on the Python version in use.\n\nI think I wasn\u0027t clear about why I did this. It\u0027s not because of Python 3.1. It\u0027s because of Python 2.6 (which I think OpenStack is still supporting?) \n\nPython 2.6 doesn\u0027t have all the unittest goodness that we all love in Python 2.7. So the natural thing to do is to add \"unittest2\" to test-requirements.txt in order to make Python 2.6 work. But then when porting to Python 3, one realizes that the mere act of trying to pip install unittest2 causes an error in Python 3 (including Python 3.3 and 3.4) and breaks everything. Which is really unfortunate, because Python 3.3 doesn\u0027t need the unittest2 stuff actually. One can solve this by having separate test-requirements files and separate tox targets for Python 2 and Python 3, but this strikes me as a lot of hoops to jump through to account for that fact that \"unittest2\" doesn\u0027t work on Python 3.\n\nThis is why I did the following:\n\n- https://github.com/msabramo/unittest2/pull/1\n- https://pypi.python.org/pypi/unittest2six\n\nSo really this is for Python 2.6, because that version needs this functionality and I see it tested in OpenStack projects. If Python 2.6 support were dropped, then this wouldn\u0027t be necessary.\n\nHopefully, this is clear now. Perhaps the fact that we had this exchange about unittest2 and unittest2py3k shows that it\u0027s confusing and is a good reason for unittest2six :-)","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"48370c2db3c22af8b6ad73b4046ad97b9ce23770","unresolved":false,"context_lines":[{"line_number":1,"context_line":"discover"},{"line_number":2,"context_line":"flake8"},{"line_number":3,"context_line":"mock"},{"line_number":4,"context_line":"unittest2six"},{"line_number":5,"context_line":"six"}],"source_content_type":"text/plain","patch_set":19,"id":"7adec928_a832c20d","line":4,"in_reply_to":"7adec928_c808ee93","updated":"2014-05-14 20:37:46.000000000","message":"Cool. I like your PR; I just +1\u0027d it. Maybe that will help get some attention on it, since no one has commented on it in a while.\n\nYour PR would also solve the unittest2 problem and it\u0027s more general. Though it\u0027s nice I think to have one package for unittest2 that works on all Python versions.","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"ebe16ab1e1f02a84adfbfab1adeadbf7468aabbc","unresolved":false,"context_lines":[{"line_number":1,"context_line":"discover"},{"line_number":2,"context_line":"flake8"},{"line_number":3,"context_line":"mock"},{"line_number":4,"context_line":"unittest2six"},{"line_number":5,"context_line":"six"}],"source_content_type":"text/plain","patch_set":21,"id":"7adec928_cbf53a58","line":4,"updated":"2014-05-15 15:19:29.000000000","message":"I\u0027m still not sure that your idea of \"meta package\" works in OpenStack. OpenStack uses its own private PyPI with a limited list of packages. If unitttest2py3k is not part of the private PyPI, the installation will fail.\n\nAnyway, installing unittest2py3k in OpenStack is useless. It is not needed for Python 3.2+ and OpenStack doesn\u0027t support Python 3.1.","commit_id":"1111a7e043970919cfee4ad74afa903b261e01d3"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"e38568485183591862b8589f04aac9ae701192be","unresolved":false,"context_lines":[{"line_number":1,"context_line":"discover"},{"line_number":2,"context_line":"flake8"},{"line_number":3,"context_line":"mock"},{"line_number":4,"context_line":"unittest2six"},{"line_number":5,"context_line":"six"}],"source_content_type":"text/plain","patch_set":21,"id":"7adec928_a4157be6","line":4,"in_reply_to":"7adec928_cbf53a58","updated":"2014-05-15 17:40:08.000000000","message":"Oh, didn\u0027t realize OpenStack has its own PyPI. The Jenkins job for this change succeeded though...doesn\u0027t that mean that this is okay?\n\nunittest2six is more in this case for Python 2.6 then for Python 3. The idea is that you can put this in test-requirements.txt and it will not break Python 3 tests. Unlike \"unittest2\", which WILL break Python 3 tests because pip installing it will fail with syntax errors.\n\nI could put \"unittest2\" in test-requirements-py2.txt and add that to tox.ini - it\u0027s a little annoying to have to do that. Your pip requirements marker PR would be useful here. Then we could have one requirements file that says to only install unittest2 when Python \u003c 2.7.\n\nAlso useful here would be if Michael Foord incorporated into unittest2 the changes that I have here: \n\nhttps://github.com/msabramo/unittest2/pull/1\n\nI\u0027d love your feedback on that change if you\u0027re inclined to review it and have the time.","commit_id":"1111a7e043970919cfee4ad74afa903b261e01d3"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"ffa83accec41a13b9737f6bdbc43831e25bc0bf1","unresolved":false,"context_lines":[{"line_number":1,"context_line":"discover"},{"line_number":2,"context_line":"flake8"},{"line_number":3,"context_line":"mock"},{"line_number":4,"context_line":"unittest2"}],"source_content_type":"text/plain","patch_set":22,"id":"7adec928_dca33fb0","side":"PARENT","line":4,"updated":"2014-05-15 20:34:04.000000000","message":"Did you try \"tox -e py26\"? You need this dependency for Python 2.6. If it doesn\u0027t work on Python 3, use test-requirements-py2.txt.","commit_id":"2c9951c9a070368506b7dabf005e52d620dad69d"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"434cecc67eabda2c6c14a0dd0b900bf05e1f04ec","unresolved":false,"context_lines":[{"line_number":1,"context_line":"discover"},{"line_number":2,"context_line":"flake8"},{"line_number":3,"context_line":"mock"},{"line_number":4,"context_line":"unittest2"}],"source_content_type":"text/plain","patch_set":22,"id":"7adec928_5c048f49","side":"PARENT","line":4,"in_reply_to":"7adec928_dca33fb0","updated":"2014-05-15 20:51:52.000000000","message":"Yep.\n\n    $ tox\n    ...\n      pep8: commands succeeded\n      py26: commands succeeded\n      py27: commands succeeded\n      pypy: commands succeeded\n      py33: commands succeeded\n      py34: commands succeeded\n      congratulations :)\n\nBecause I added unittest2 to line 15 of tox.ini:\n\n    $ grep -Hn --before\u003d2 unittest2 tox.ini\n    tox.ini-13-[testenv:py26]\n    tox.ini-14-deps \u003d -r{toxinidir}/test-requirements.txt\n    tox.ini:15:       unittest2","commit_id":"2c9951c9a070368506b7dabf005e52d620dad69d"}],"tests/helper.py":[{"author":{"_account_id":2475,"name":"Antoine Musso","email":"hashar@free.fr","username":"hashar"},"change_message_id":"885be10e8fc460abd1a24fcef4035bed645fe599","unresolved":false,"context_lines":[{"line_number":9,"context_line":"    from StringIO import StringIO  # noqa"},{"line_number":10,"context_line":"except ImportError:  # pragma: nocover"},{"line_number":11,"context_line":"    # Python 3"},{"line_number":12,"context_line":"    from io import StringIO  # noqa"}],"source_content_type":"text/x-python","patch_set":6,"id":"AAAAXX%2F%2F11k%3D","line":12,"updated":"2014-04-25 20:49:05.000000000","message":"That seems legit though we can use python six module that transparently achieve the same thing.\n\nhttp://pythonhosted.org/six/#six.StringIO\n\nIe something like:\n\n from six import StringIO","commit_id":"293f230f41d38bd71bdb0e6a9f1a01c51ec60bb1"},{"author":{"_account_id":1297,"name":"Joshua Harlow","email":"jxharlow@godaddy.com","username":"harlowja"},"change_message_id":"d09879c82332863b7093e845f6009857089cd645","unresolved":false,"context_lines":[{"line_number":4,"context_line":""},{"line_number":5,"context_line":"import jenkins  # noqa"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"try:"},{"line_number":8,"context_line":"    # Python 2"},{"line_number":9,"context_line":"    from StringIO import StringIO  # noqa"},{"line_number":10,"context_line":"except ImportError:  # pragma: nocover"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAXX%2F%2FzSM%3D","line":7,"updated":"2014-04-26 20:28:01.000000000","message":"Why not just use six?","commit_id":"62a542bdd314e663e41224b292654937c2e4dd64"},{"author":{"_account_id":1297,"name":"Joshua Harlow","email":"jxharlow@godaddy.com","username":"harlowja"},"change_message_id":"8db418347fb8768ad0df8c1ed35b2cd78bca2bfb","unresolved":false,"context_lines":[{"line_number":4,"context_line":""},{"line_number":5,"context_line":"import jenkins  # noqa"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"try:"},{"line_number":8,"context_line":"    # Python 2"},{"line_number":9,"context_line":"    from StringIO import StringIO  # noqa"},{"line_number":10,"context_line":"except ImportError:  # pragma: nocover"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAXX%2F%2FzOM%3D","line":7,"in_reply_to":"AAAAXX%2F%2FzQQ%3D","updated":"2014-04-26 21:57:05.000000000","message":"Six is a pretty tiny dependency, and afaik its everywhere by now (all distributions likely have it installable), so might as well use it.","commit_id":"62a542bdd314e663e41224b292654937c2e4dd64"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"c802b8a9eb6453c0c29d587ca70c7c7153ca1fa1","unresolved":false,"context_lines":[{"line_number":4,"context_line":""},{"line_number":5,"context_line":"import jenkins  # noqa"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"try:"},{"line_number":8,"context_line":"    # Python 2"},{"line_number":9,"context_line":"    from StringIO import StringIO  # noqa"},{"line_number":10,"context_line":"except ImportError:  # pragma: nocover"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAXX%2F%2FzQQ%3D","line":7,"in_reply_to":"AAAAXX%2F%2FzSM%3D","updated":"2014-04-26 20:48:50.000000000","message":"I totally could. I love six and usually I do use it my own projects.\n\nSometimes if a project doesn\u0027t have a lot of dependencies and/or doesn\u0027t need a lot of six stuff, I\u0027ll just include stuff inline, because folks will often balk at adding a dependency.\n\nBut since two people have mentioned six already, I\u0027ll probably use it.","commit_id":"62a542bdd314e663e41224b292654937c2e4dd64"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"3118d4a458d977a1dd06e471dcaf0cb289e7e1d9","unresolved":false,"context_lines":[{"line_number":7,"context_line":"try:"},{"line_number":8,"context_line":"    # Python 2"},{"line_number":9,"context_line":"    from StringIO import StringIO  # noqa"},{"line_number":10,"context_line":"except ImportError:  # pragma: nocover"},{"line_number":11,"context_line":"    # Python 3"},{"line_number":12,"context_line":"    from io import StringIO  # noqa"}],"source_content_type":"text/x-python","patch_set":12,"id":"7adec928_f9ecc5f5","line":10,"updated":"2014-05-12 12:59:24.000000000","message":"six.StringIO might be used directly in tests instead of this helper, but your change is fine.","commit_id":"391d6a93280c5a653fe6ab05f2e4daa3fd558d5f"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"af2c60754759fd8b74752e225b0fe073dde70c0a","unresolved":false,"context_lines":[{"line_number":7,"context_line":"try:"},{"line_number":8,"context_line":"    # Python 2"},{"line_number":9,"context_line":"    from StringIO import StringIO  # noqa"},{"line_number":10,"context_line":"except ImportError:  # pragma: nocover"},{"line_number":11,"context_line":"    # Python 3"},{"line_number":12,"context_line":"    from io import StringIO  # noqa"}],"source_content_type":"text/x-python","patch_set":12,"id":"7adec928_206342b2","line":10,"in_reply_to":"7adec928_f9ecc5f5","updated":"2014-05-13 06:24:46.000000000","message":"I think I will switch to using six. There are a few things that could benefit from it.","commit_id":"391d6a93280c5a653fe6ab05f2e4daa3fd558d5f"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"e2186b5df293aebefc7867b53da793c07221fe75","unresolved":false,"context_lines":[{"line_number":4,"context_line":""},{"line_number":5,"context_line":"import jenkins  # noqa"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"from six import StringIO  # noqa"}],"source_content_type":"text/x-python","patch_set":19,"id":"7adec928_1c878310","line":7,"updated":"2014-05-14 08:58:39.000000000","message":"I don\u0027t think that six.StringIO is the right object on Python 3 (io.StringIO) because you use it to mock urlopen() function. urlopen() should returns a binary file, so BytesIO.\n\nUse six.BytesIO instead.","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"f7c415ac3b1a3f7e6d95098353c5ebdeb78867f2","unresolved":false,"context_lines":[{"line_number":4,"context_line":""},{"line_number":5,"context_line":"import jenkins  # noqa"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"from six import StringIO  # noqa"}],"source_content_type":"text/x-python","patch_set":19,"id":"7adec928_85ffafa9","line":7,"in_reply_to":"7adec928_1c878310","updated":"2014-05-14 16:18:20.000000000","message":"I think you\u0027re right, but it\u0027s not as simple as just changing it to a BytesIO. \n\n    from six import BytesIO as StringIO  # noqa\n\nFor one thing, the jenkins_open function is calling maybe_add_crumb which calls json.loads(response); if this gets binary, it fails with `TypeError: can\u0027t use a string pattern on a bytes-like object`.\n\nI also don\u0027t like that what I wrote above in that it import BytesIO and calls it StringIO which is very confusing from a Python 3 perspective. This means to me that we should probably go through the code and change a bunch of instances of StringIO to BytesIO.\n\nWhich is all well and good, but it might make this patch get rather complicated and you have made good points before about trying to keep patches fairly simple so they are easy to review and then doing more refinements later.\n\nWould you be okay with doing that here? Leaving as-is and then doing a review of all the StringIO/BytesIO stuff after this is merged and making that stuff right?\n\nI could do it here; it just might get a bit messy :-)","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"e5e3d6f28b4450e99fb270aaec432d3887a7de96","unresolved":false,"context_lines":[{"line_number":4,"context_line":""},{"line_number":5,"context_line":"import jenkins  # noqa"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"from six import StringIO  # noqa"}],"source_content_type":"text/x-python","patch_set":19,"id":"7adec928_94619f3b","line":7,"in_reply_to":"7adec928_28f95280","updated":"2014-05-14 21:44:19.000000000","message":"OK, you\u0027re right and it turned out to not be that much code to change actually. See patch set 21...","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"1db5fc7ea351fcd17c94a69b20cbe1c9e95d7810","unresolved":false,"context_lines":[{"line_number":4,"context_line":""},{"line_number":5,"context_line":"import jenkins  # noqa"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"from six import StringIO  # noqa"}],"source_content_type":"text/x-python","patch_set":19,"id":"7adec928_28f95280","line":7,"in_reply_to":"7adec928_85ffafa9","updated":"2014-05-14 16:43:43.000000000","message":"IMO you should move the import where it is used directly. And yes, you should replace StringIO with BytesIO. If there are failures, you should fix them.\n\nUsing io.StringIO for urlopen() is just wrong in Python 3.","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"}],"tests/test_jenkins.py":[{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"3118d4a458d977a1dd06e471dcaf0cb289e7e1d9","unresolved":false,"context_lines":[{"line_number":217,"context_line":""},{"line_number":218,"context_line":"        j.reconfig_job(u\u0027TestJob\u0027, config_xml)"},{"line_number":219,"context_line":""},{"line_number":220,"context_line":"        self.assertEqual("},{"line_number":221,"context_line":"            jenkins_mock.call_args[0][0].get_full_url(),"},{"line_number":222,"context_line":"            u\u0027http://example.com/job/TestJob/config.xml\u0027)"},{"line_number":223,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"7adec928_99ce6182","line":220,"updated":"2014-05-12 12:59:24.000000000","message":"This change looks useless (and I prefer the orignal formatting).\n\n(Same comment for the 2 changes below.)","commit_id":"391d6a93280c5a653fe6ab05f2e4daa3fd558d5f"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"af2c60754759fd8b74752e225b0fe073dde70c0a","unresolved":false,"context_lines":[{"line_number":217,"context_line":""},{"line_number":218,"context_line":"        j.reconfig_job(u\u0027TestJob\u0027, config_xml)"},{"line_number":219,"context_line":""},{"line_number":220,"context_line":"        self.assertEqual("},{"line_number":221,"context_line":"            jenkins_mock.call_args[0][0].get_full_url(),"},{"line_number":222,"context_line":"            u\u0027http://example.com/job/TestJob/config.xml\u0027)"},{"line_number":223,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"7adec928_60254aaa","line":220,"in_reply_to":"7adec928_99ce6182","updated":"2014-05-13 06:24:46.000000000","message":"Done","commit_id":"391d6a93280c5a653fe6ab05f2e4daa3fd558d5f"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"137193bb3821dbd4d748a4c9a9e1eb9d5485f42f","unresolved":false,"context_lines":[{"line_number":335,"context_line":"            \u0027job[TestJob] number[52] does not exist\u0027)"},{"line_number":336,"context_line":""},{"line_number":337,"context_line":"    @patch.object(jenkins.Jenkins, \u0027jenkins_open\u0027)"},{"line_number":338,"context_line":"    def test_get_build_console_output__invalid_json(self, jenkins_mock):"},{"line_number":339,"context_line":"        \"\"\""},{"line_number":340,"context_line":"        The job name parameter specified should be urlencoded properly."},{"line_number":341,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":14,"id":"7adec928_1a7eae6b","line":338,"updated":"2014-05-13 15:56:26.000000000","message":"Hmmm, this method is odd in this PR. I probably should put it in my other changeset that adds testing (https://review.openstack.org/90500)...","commit_id":"3d8528caa91c367b55d0b6ac820a33cfca71a15e"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"e5fee8f1206a8f6233e887887bfafa14d388955a","unresolved":false,"context_lines":[{"line_number":335,"context_line":"            \u0027job[TestJob] number[52] does not exist\u0027)"},{"line_number":336,"context_line":""},{"line_number":337,"context_line":"    @patch.object(jenkins.Jenkins, \u0027jenkins_open\u0027)"},{"line_number":338,"context_line":"    def test_get_build_console_output__invalid_json(self, jenkins_mock):"},{"line_number":339,"context_line":"        \"\"\""},{"line_number":340,"context_line":"        The job name parameter specified should be urlencoded properly."},{"line_number":341,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":14,"id":"7adec928_ba4a1aaa","line":338,"in_reply_to":"7adec928_1a7eae6b","updated":"2014-05-13 16:21:05.000000000","message":"Done","commit_id":"3d8528caa91c367b55d0b6ac820a33cfca71a15e"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"e2186b5df293aebefc7867b53da793c07221fe75","unresolved":false,"context_lines":[{"line_number":34,"context_line":"        self.assertEqual(j.server, \u0027http://example.com/\u0027)"},{"line_number":35,"context_line":"        self.assertEqual(j.auth, None)"},{"line_number":36,"context_line":"        self.assertEqual(j.crumb, None)"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":"    @patch.object(jenkins.Jenkins, \u0027jenkins_open\u0027)"},{"line_number":39,"context_line":"    def test_get_job_config_encodes_job_name(self, jenkins_mock):"},{"line_number":40,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":19,"id":"7adec928_bc068fcc","line":37,"updated":"2014-05-14 08:58:39.000000000","message":"You may add a test with unicode credentials (login and password) to test the encoding. For example:\n\nj \u003d jenkins.Jenkins(\u0027http://example.com\u0027, six.u(\u0027nonascii\u0027), six.u(\u0027\\xe9\\u20ac\u0027))","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"1db5fc7ea351fcd17c94a69b20cbe1c9e95d7810","unresolved":false,"context_lines":[{"line_number":34,"context_line":"        self.assertEqual(j.server, \u0027http://example.com/\u0027)"},{"line_number":35,"context_line":"        self.assertEqual(j.auth, None)"},{"line_number":36,"context_line":"        self.assertEqual(j.crumb, None)"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":"    @patch.object(jenkins.Jenkins, \u0027jenkins_open\u0027)"},{"line_number":39,"context_line":"    def test_get_job_config_encodes_job_name(self, jenkins_mock):"},{"line_number":40,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":19,"id":"7adec928_c82f0ef5","line":37,"in_reply_to":"7adec928_080e5634","updated":"2014-05-14 16:43:43.000000000","message":"I know that HTTP standards are underspecified for non-ASCII characters, but OpenStack can have a well-defined behaviour, and UTF-8 is the expected encoding.","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"f7c415ac3b1a3f7e6d95098353c5ebdeb78867f2","unresolved":false,"context_lines":[{"line_number":34,"context_line":"        self.assertEqual(j.server, \u0027http://example.com/\u0027)"},{"line_number":35,"context_line":"        self.assertEqual(j.auth, None)"},{"line_number":36,"context_line":"        self.assertEqual(j.crumb, None)"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":"    @patch.object(jenkins.Jenkins, \u0027jenkins_open\u0027)"},{"line_number":39,"context_line":"    def test_get_job_config_encodes_job_name(self, jenkins_mock):"},{"line_number":40,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":19,"id":"7adec928_080e5634","line":37,"in_reply_to":"7adec928_bc068fcc","updated":"2014-05-14 16:18:20.000000000","message":"Sure I can add this.\n\nHowever, I will note that Unicode characters and HTTP Basic Auth are known to not work very well, because HTTP doesn\u0027t provide a way to specify what the encoding is and different browsers do different things. So this may not be worth a ton of effort, though maybe adding the test does no harm.\n\n- http://tools.ietf.org/id/draft-reschke-basicauth-enc-00.html\n- http://stackoverflow.com/questions/702629/utf-8-characters-mangled-in-http-basic-auth-username\n\nFrom the first link:\n\n The \"Basic\" authentication scheme defined in RFC 2617 does not \n properly define how to treat non-ASCII characters. This has lead to a \n situation where user agent implementations disagree, and servers make\n different assumptions based on the locales they are running in. There is\n little interoperability for characters in the ISO-8859-1 character set, and\n even less interoperability for any characters beyond that.","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"}],"tox.ini":[{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"3118d4a458d977a1dd06e471dcaf0cb289e7e1d9","unresolved":false,"context_lines":[{"line_number":11,"context_line":"commands \u003d python -m discover"},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"[testenv:py33]"},{"line_number":14,"context_line":"deps \u003d -r{toxinidir}/test-requirements-py3.txt"},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"[testenv:py34]"},{"line_number":17,"context_line":"deps \u003d -r{toxinidir}/test-requirements-py3.txt"}],"source_content_type":"text/x-properties","patch_set":12,"id":"7adec928_19909142","line":14,"updated":"2014-05-12 12:59:24.000000000","message":"You should use the common dependencies and py3 specific dependencies like that:\n\ndeps \u003d -r{toxinidir}/test-requirements.txt -r{toxinidir}/test-requirements-py3.txt","commit_id":"391d6a93280c5a653fe6ab05f2e4daa3fd558d5f"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"af2c60754759fd8b74752e225b0fe073dde70c0a","unresolved":false,"context_lines":[{"line_number":11,"context_line":"commands \u003d python -m discover"},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"[testenv:py33]"},{"line_number":14,"context_line":"deps \u003d -r{toxinidir}/test-requirements-py3.txt"},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"[testenv:py34]"},{"line_number":17,"context_line":"deps \u003d -r{toxinidir}/test-requirements-py3.txt"}],"source_content_type":"text/x-properties","patch_set":12,"id":"7adec928_c04c5e73","line":14,"in_reply_to":"7adec928_19909142","updated":"2014-05-13 06:24:46.000000000","message":"This won\u0027t work because neither of the requirement sets are a subset of the other. Each has something that the other doesn\u0027t have.\n\nFor Python 2, we need unittest2. For Python 3, we need unittest2py3k because trying to install unittest2 on Python 3 will bomb out with an error.\n\nI could have 3 files, but maybe that\u0027s a bit complex:\n\n    # test-requirements.txt\n    discover\n    flake8\n    mock\n\n    # test-requirements-py2.txt\n    unittest2\n\n    # test-requirements-py3.txt\n    unittest2py3k\n\nHaving to have multiple requirements file is because unittest2 does not work on Python 3. I might just rip out unittest2 and instead use the assertRaises function in pytest, as pytest works on both Python 2 and Python 3.","commit_id":"391d6a93280c5a653fe6ab05f2e4daa3fd558d5f"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"e2186b5df293aebefc7867b53da793c07221fe75","unresolved":false,"context_lines":[{"line_number":1,"context_line":"[tox]"},{"line_number":2,"context_line":"minversion \u003d 1.6"},{"line_number":3,"context_line":"skipsdist \u003d True"},{"line_number":4,"context_line":"envlist \u003d pep8, py26, py27, pypy, py33, py34"},{"line_number":5,"context_line":""},{"line_number":6,"context_line":"[testenv]"},{"line_number":7,"context_line":"setenv VIRTUAL_ENV\u003d{envdir}"}],"source_content_type":"text/x-properties","patch_set":19,"id":"7adec928_dc30bba0","line":4,"updated":"2014-05-14 08:58:39.000000000","message":"Does tox 1.6 supports Python 3.4? If you don\u0027t know, it\u0027s maybe safer to not add this young Python version.","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"1db5fc7ea351fcd17c94a69b20cbe1c9e95d7810","unresolved":false,"context_lines":[{"line_number":1,"context_line":"[tox]"},{"line_number":2,"context_line":"minversion \u003d 1.6"},{"line_number":3,"context_line":"skipsdist \u003d True"},{"line_number":4,"context_line":"envlist \u003d pep8, py26, py27, pypy, py33, py34"},{"line_number":5,"context_line":""},{"line_number":6,"context_line":"[testenv]"},{"line_number":7,"context_line":"setenv VIRTUAL_ENV\u003d{envdir}"}],"source_content_type":"text/x-properties","patch_set":19,"id":"7adec928_e8368a51","line":4,"in_reply_to":"7adec928_05ec7fc6","updated":"2014-05-14 16:43:43.000000000","message":"Cool.","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"},{"author":{"_account_id":11011,"name":"Marc Abramowitz","email":"marc@marc-abramowitz.com","username":"msabramo"},"change_message_id":"f7c415ac3b1a3f7e6d95098353c5ebdeb78867f2","unresolved":false,"context_lines":[{"line_number":1,"context_line":"[tox]"},{"line_number":2,"context_line":"minversion \u003d 1.6"},{"line_number":3,"context_line":"skipsdist \u003d True"},{"line_number":4,"context_line":"envlist \u003d pep8, py26, py27, pypy, py33, py34"},{"line_number":5,"context_line":""},{"line_number":6,"context_line":"[testenv]"},{"line_number":7,"context_line":"setenv VIRTUAL_ENV\u003d{envdir}"}],"source_content_type":"text/x-properties","patch_set":19,"id":"7adec928_05ec7fc6","line":4,"in_reply_to":"7adec928_dc30bba0","updated":"2014-05-14 16:18:20.000000000","message":"Yes, it does:\n\n ? tox --version\n1.6.0 imported from /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/tox/__init__.pyc\n\n ? tox\n    ...\n      pep8: commands succeeded\n      py26: commands succeeded\n      py27: commands succeeded\n      pypy: commands succeeded\n      py33: commands succeeded\n      py34: commands succeeded\n      congratulations :)","commit_id":"89f98ebe9a59e0f858477c73fb13f3453c6d28bd"}]}
