peritus/bumpversion

Under python3.3 --help throws TypeError

kernowcastellan opened this issue · 11 comments

Running in a python 3.3 virtualenv environ, with 0.4.0 installed from pip/pypi. It throws a TypeError if invoked with --help

~/dev$ bumpversion --help
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "./bumpversion/__init__.py", line 580, in main
    args = parser3.parse_args(remaining_argv + positionals)
  File "/usr/lib/python3.3/argparse.py", line 1714, in parse_args
    args, argv = self.parse_known_args(args, namespace)
  File "/usr/lib/python3.3/argparse.py", line 1746, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
  File "/usr/lib/python3.3/argparse.py", line 1952, in _parse_known_args
    start_index = consume_optional(start_index)
  File "/usr/lib/python3.3/argparse.py", line 1892, in consume_optional
    take_action(action, args, option_string)
  File "/usr/lib/python3.3/argparse.py", line 1820, in take_action
    action(self, namespace, argument_values, option_string)
  File "/usr/lib/python3.3/argparse.py", line 1024, in __call__
    parser.print_help()
  File "/usr/lib/python3.3/argparse.py", line 2348, in print_help
    self._print_message(self.format_help(), file)
  File "/usr/lib/python3.3/argparse.py", line 2354, in _print_message
    file.write(message)
  File "/usr/lib/python3.3/codecs.py", line 356, in write
    self.stream.write(data)
TypeError: must be str, not bytes

Same is true if I clone the repo and invoke directly

~/dev$ git clone -q https://github.com/peritus/bumpversion.git && cd bumpversion
~/dev/bumpversion (master)$ python3 -c 'import bumpversion;bumpversion.main()' --help
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "./bumpversion/__init__.py", line 580, in main
    args = parser3.parse_args(remaining_argv + positionals)
  File "/usr/lib/python3.3/argparse.py", line 1714, in parse_args
    args, argv = self.parse_known_args(args, namespace)
  File "/usr/lib/python3.3/argparse.py", line 1746, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
  File "/usr/lib/python3.3/argparse.py", line 1952, in _parse_known_args
    start_index = consume_optional(start_index)
  File "/usr/lib/python3.3/argparse.py", line 1892, in consume_optional
    take_action(action, args, option_string)
  File "/usr/lib/python3.3/argparse.py", line 1820, in take_action
    action(self, namespace, argument_values, option_string)
  File "/usr/lib/python3.3/argparse.py", line 1024, in __call__
    parser.print_help()
  File "/usr/lib/python3.3/argparse.py", line 2348, in print_help
    self._print_message(self.format_help(), file)
  File "/usr/lib/python3.3/argparse.py", line 2354, in _print_message
    file.write(message)
  File "/home/alan/env/dev/lib/python3.3/codecs.py", line 356, in write
    self.stream.write(data)
TypeError: must be str, not bytes

Thanks!

Also: interesting.

Seems like I need to write proper integration tests that start an individual python process.

Did you just sign up for GitHub to file this issue ? Thank you so much and enjoy your stay!

I did indeed. I am late to Python, and so missed the whole 2->3 str vs unicode vs bytes psychodrama - all my code is python 3, and you just assume that stdin/stdout/argv are all in unicode, as are text & config files.

It works if I comment out

sys.stdout = codecs.getwriter('utf8')(sys.stdout)

but I have no idea what other impact that has. (No other direct uses of sys.stdout or print that I could immediately see, and logging.log shouldn't need a bespoke encoder, but I don't use 2.7)

Regardless, the tool still works fine (and is jolly useful). For entirely sensible reasons, the test harness is about making sure the version numbers are bumped correctly!

I stumbled upon that line aswell, @peritus, could you explain why it's needed?

Seems to originate from here: 027137a and is supposed to be a fix for #13

fnl commented

Hi; To chime in: If that line was introduced by 027137a #13, then you have a problem. The bug reported in #13 is a problem the OP there has, having his terminal malconfigured to use a Unicode-incompatible encoding and/or Python falls back to ASCII (he should check, e.g., "sys.defaultencoding()" after opening a REPL), and was not a problem of bumpversion in the first place. Ergo, that commit adding the getwriter line @kernowcastellan found should be reverted... (BTW, I, too cannot see the help output in the current stable version 0.4.0 when using Py3k)

EDIT: BTW, kudos to you @peritus, for this nice library; a real life saver :)

fnl commented

Well, actually, the issue is deeper, I just realized the OP of #11 seems to use Py2.x, which in turn uses ASCII as its default encoding, not the actual terminal encoding (BTW, yet another GREAT reason to stop using these outdated 2.x Python series: Py3 does actually realize the environment it is running in, Py2 defaults to ASCII always). So what you were seeing in #13 and #11 is actually an issue that you are tring to write a string containing non-ASCII chars to an ASCII-only file handle (stdout). In essence, the problem is here that if you are using Py2, you should make sure your output streams are all UTF-8-enabled, but if you are using Py3 you are golden already and any change is bad (thus, the problem we see here). So, in summary, you should hedge the above change 027137a to only be encoding stdout to UTF-8 instead of ASCII when using Py2.

Thanks for the kind words and the write-up @fnl! Finally had some time to play with it, here's a branch that adds s regression test: 7846265

However, I wasn't able to make it work in py3, might correlate to this: http://bugs.python.org/issue9779

Need to investigate some more.

Travis likes it though. Seems like I rather need to fix the terminal encoding in my vagrant box. If there are no objections, I'll merge this to master.

fnl commented

No objections, this is exactly what I argument is the "correctest" fix [other than telling everybody (especially on HN...) to stop the whining and start using Py3k]

released in v0.4.1