Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wx.lib.editor file I/O does not support unicode strings in python 3 #1193

Closed
pkienzle opened this issue Apr 2, 2019 · 3 comments

Comments

Projects
None yet
2 participants
@pkienzle
Copy link
Contributor

commented Apr 2, 2019

Operating system: OS X, but affects all O/S
wxPython version & source: 4.0.4 osx-cocoa (phoenix) wxWidgets 3.0.5, but problem exists in master as of 2019-04-01
Python version & source: 3.6.7 |Anaconda, Inc.| (default, Oct 23 2018, 14:01:38) \n[GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)], but affects all 3.x

Description of the problem:

File load/save in wx.lib.editor fails because file read/write is expecting bytes, not unicode string in python 3.

Run the following, selecting ">File >New", typing some text, then selecting ">File >Save"

app = wx.App()
dlg = editor.EditorFrame()
dlg.Show()
app.MainLoop()

produces error:

Traceback (most recent call last):
  File ".../anaconda/envs/py36/lib/python3.6/site-packages/wx/py/frame.py", line 372, in OnFileSave
    self.bufferSave()
  File ".../anaconda/envs/py36/lib/python3.6/site-packages/wx/py/editor.py", line 215, in bufferSave
    cancel = self.bufferSaveAs()
  File ".../anaconda/envs/py36/lib/python3.6/site-packages/wx/py/editor.py", line 229, in bufferSaveAs
    self.buffer.saveAs(result.path)
  File ".../anaconda/envs/py36/lib/python3.6/site-packages/wx/py/buffer.py", line 100, in saveAs
    self.save()
  File ".../anaconda/envs/py36/lib/python3.6/site-packages/wx/py/buffer.py", line 91, in save
    self.doc.write(self.editor.getText())
  File ".../anaconda/envs/py36/lib/python3.6/site-packages/wx/py/document.py", line 38, in write
    f.write(text)
TypeError: a bytes-like object is required, not 'str'

Need to convert encode/decode bytes from utf8 when working with unicode in binary files, or need to open the file as 'r' or 'w' with the encoding on the open call.

Relevant code:

self.doc.write(self.editor.getText())

Phoenix/wx/py/editor.py

Lines 627 to 630 in 57a7847

def getText(self):
"""Return contents of editor."""
return self.window.GetText()

def read(self):
"""Return contents of file."""
if self.filepath and os.path.exists(self.filepath):
f = open(self.filepath, 'rb')
try:
return f.read()
finally:
f.close()
else:
return ''
def write(self, text):
"""Write text to file."""
try:
f = open(self.filepath, 'wb')
f.write(text)
finally:
if f:
f.close()

@pkienzle

This comment has been minimized.

Copy link
Contributor Author

commented Apr 2, 2019

The following works in python 2.7 and 3.x for wx 4 with the EditorFrame example:

import io

...

def read(self):
    """Return contents of file."""
    if self.filepath and os.path.exists(self.filepath):
        with io.open(self.filepath, 'r', encoding='utf8') as f:
            return f.read()
    else:
        return ''

def write(self, text):
    """Write text to file."""
    with io.open(self.filepath, 'w', encoding='utf8') as f:
        f.write(text)

I guess the text control in wx4 accepts either bytes or unicode?

You may not want to do this change since it changes the interface to Document.

The original open(...,'r').read() returns bytes on 2.7 and 3.x, but the new version returns unicode on both. It should be okay to return unicode on 3.x, but 2.7 should probably return f.read().encode('utf8').

Similarly for writing, the new version requires unicode text, and fails if it receives bytes. This should be fine on 3.x, but 2.7 should probably accept bytes as well as unicode.

@pkienzle

This comment has been minimized.

Copy link
Contributor Author

commented Apr 2, 2019

BInary I/O preserves line endings, so for compatibility maybe want to specify newline='' so that newline characters are left as is:

import io

...

def read(self):
    """Return contents of file."""
    if self.filepath and os.path.exists(self.filepath):
        with io.open(self.filepath, 'r', encoding='utf8', newline='') as f:
            return f.read()
    else:
        return ''

def write(self, text):
    """Write text to file."""
    with io.open(self.filepath, 'w', encoding='utf8', newline='') as f:
        f.write(text)

The best solution depends on the intricacies of newline handling in wx.TextCtrl.

@RobinD42

This comment has been minimized.

Copy link
Member

commented Apr 12, 2019

Can you submit a PR that fixes these issues? wx.lib.editor hasn't really been maintained in a very long time and I don't have much interest in it myself, but I'd be happy to review and apply PRs that somebody else submits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.