Masked controls out of control

Hello List,

long time no see…

I am porting an old, large wxPython application to Python 3 and to Phoenix, and I am having a hell of a time with masked controls. Starting to hate them to be honest.

This piece of code:

import wx
import wx.lib.masked as masked

app = wx.App(0)
frame = wx.Frame(None, -1, 'Test Masked')
panel = wx.Panel(frame)

ctrl = masked.NumCtrl(panel, -1, 1.0, pos=(10, 10))
ctrl.SetParameters(min=0.0, max=10.0, integerWidth=2, fractionWidth=2, limited=True,
                   allowNone=False, autoSize=False)
frame.Show()
app.MainLoop()

Breaks for me with this:

C:\Users\J0514162\MyProjects\PY3_PORT\Installation>python test_masked.py
Traceback (most recent call last):
  File "C:\Users\J0514162\MyProjects\PY3_PORT\Installation\test_masked.py", line 9, in <module>
    ctrl.SetParameters(min=0.0, max=10.0, integerWidth=2, fractionWidth=2, limited=True,
  File "C:\Users\J0514162\WinPython39\WPy64-39100\python-3.9.10.amd64\lib\site-packages\wx\lib\masked\numctrl.py", line 913, in SetParameters
    if self.IsLimited() and self._min is not None and value < self._min:
TypeError: '<' not supported between instances of 'NoneType' and 'float'

And it doesn’t appear to matter what I pass as an input to that wicked control. This is on Windows 10 64 bit, Python 3.9.10 64 bit, wxPython Phoenix 4.2.0 msw (phoenix) wxWidgets 3.2.0.

Suggestions most welcome :slight_smile: .

Thank you in advance.

Andrea.

Hi Andrea,

Good to hear from you. Your many great contributions to wxPython are not forgotten!

I don’t use masked.NumCtrl myself - I guess not many people do, or these issues with SetParameters would have been discovered sooner. I get the impression of something that broke in the Python 2->3 transition and hasn’t been revisited since.

I suggest you omit SetParameters and consolidate your parameter values into the constructor call, that seems to work:

ctrl = masked.NumCtrl(panel, -1, 1.0, pos=(10, 10),
                      min=0.0, max=10.0, integerWidth=2, fractionWidth=2, limited=True,
                      allowNone=False, autoSize=False)

If you need to change parameters later, then I guess you will have to destroy the control and recreate it.

in numctrl.py of lib.masked line 840 is no good: min is a built-in function and is assigned to, even python’s magic is exhausted here (I think :rofl:)

Shadowing the min built-in is perfectly legal (if not good style), and does not break anything. This code just might be older than the built-in.

if you want to see your ‘Test Masked’ (sometimes one has the urge), put this into numctrl.py at 1724 as the first statement in _fromGUI(self, value): :crazy_face:

        if isinstance(value, str):
            value = value[:value.rfind(' ')]

It can fix the problem, however, I feel the cause is still deep in the dark…
The code is too big (wx.lib.masked package: numctrl, maskededit, and textctrl) to explore with one hand. We need a bivouac.

this fits at least the original comment ‘clean up a text value’ much better (line 929) & is more succinct (almost a flood light for the bivouac :stuck_out_tongue_closed_eyes:)

    def _GetNumValue(self, value):
        """
        This function attempts to "clean up" a text value, providing a regularized
        convertible string, via atol() or atof(), for any well-formed numeric text value.
        """
        return value.strip().partition(' ')[0].replace(
            self._groupChar, '').replace(self._decimalChar, '.').replace(
            '(', '-').replace(')','')

I traced the code and it looks like the problem is at:

The debug log is like this:

(Pdb) > C:\Python310\lib\site-packages\wx\lib\masked\maskededit.py:5063:_eraseSelection
--Call--
(Pdb) a
self = <BaseMaskedTextCtrl: 1.0>
value = None
sel_start = None
sel_to = None
(Pdb) --> C:\Python310\lib\site-packages\wx\lib\masked\maskededit.py:5067:_eraseSelection
(Pdb) value
'          1'
(Pdb) --> C:\Python310\lib\site-packages\wx\lib\masked\maskededit.py:5072:_eraseSelection
(Pdb) sel_start, sel_to
(0, 6)
(Pdb) self._template
'   .00'
(Pdb) newvalue
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '1']
(Pdb) --> C:\Python310\lib\site-packages\wx\lib\masked\maskededit.py:5100:_eraseSelection
(Pdb) newvalue
[' ', ' ', ' ', ' ', '0', '0', ' ', ' ', ' ', ' ', '1']
(Pdb) $(retval) = '    00    1'
--Return--

Then, the caller gets the return value:

(Pdb) sel_start, replace_to
(0, 6)
(Pdb) text
'    00    1'
(Pdb) replacement_text
'  1.00'
(Pdb) new_text
'  1.00    1'

Here new_text is broken.
So @da-dda’s patch works, but I’m not sure it will always work. :sleeping: