1

I have been trying out (for my own personal use) some peoples' solutions to timed keyboard inputs and the only one that has worked was one by Alex Martelli/martineau here. I used their second block of code (starting with import msvcrt) and it worked great for pretty much everything but comparisons. I replaced the return of None with an empty string if no input is entered in time and I used some test lines as shown below:

import msvcrt
import time 

def raw_input_with_timeout(prompt, timeout):
    print prompt,    
    finishat = time.time() + timeout
    result = []
    while True:
        if msvcrt.kbhit():
            result.append(msvcrt.getche())
            if result[-1] == '\r':   # or \n, whatever Win returns;-)
                return ''.join(result)
            time.sleep(0.1)          # just to yield to other processes/threads
        else:
            if time.time() > finishat:
                return ""

textVar = raw_input_with_timeout("Enter here: \n", 5)
print str(textVar)    # to make sure the string is being stored
print type(str(textVar))   # to make sure it is of type string and can be compared
print str(str(textVar) == "test")
time.sleep(10)   # so I can see the output

After I compile that with pyinstaller, run it, and type test into the window, I get this output:

Enter here:
test
test
<type 'str'>
False

I originally thought the comparison was returning False because the function appends characters to an array and that may have had something to do with it not doing a proper comparison with a string, but after looking further into the way Python works (namely, SilentGhost's response here), I really have no idea why the comparison will not return True. Any response is appreciated. Thank you!

Community
  • 1
  • 1
  • 1
    use `print repr(textVar)` and I'm sure a difference will emerge. `print str("some string with unprintable bytes like \x00")` is functionally equivalent to `print "some string with unprintable bytes like \x00"`; neither will make that null byte visible (on most terminals or consoles). `repr()` produces a *debugging representation*, one that uses Python string literal syntax to create an ASCII-safe reproduceable value using escape sequences for anything not printable. – Martijn Pieters Aug 12 '16 at 08:20
  • Isn't it redundant to convert the `input` to a `str`? `input` is always interpreted as string. – Ian Aug 12 '16 at 08:22
  • Note that `print` already calls `str` on anything you try to print, making all your `str()` calls redundant, even for the boolean and `str` type object results. – Martijn Pieters Aug 12 '16 at 08:24
  • Maybe you've got some hidden white space or newlines, try stripping it off with `textVar.strip()` – Chris_Rands Aug 12 '16 at 08:26

3 Answers3

2

You won't be able to see why the strings are different just by printing. String values can contain bytes that are not (easily) visible on a console when printed.

Use the repr() function to produce a debugging-friendly representation instead. This representation will format the string as a Python string literal, using only printable ASCII characters and escape sequences:

>>> foo = 'test\t\n'
>>> print foo
test

>>> foo == 'test'
False
>>> print repr(foo)
'test\t\n'

In your case, you are including the \r carriage return character in your return value:

if result[-1] == '\r':
    return ''.join(result)

That last \r is still there, so you get, at the very least, the value 'test\r', but \r won't show up when printing:

>>> print 'test\r'
test
>>> print repr('test\r')
'test\r'

You could just exclude that last character when joining, by slicing the string:

return ''.join(result[:-1])

or you could use str.strip() to remove all whitespace characters from both the start and end of the string (including that \r character):

return ''.join(result).strip()

Note that there is no point in using str() calls here. You return a str object, so str(textVar) is redundant. Moreover, print will call str() on anything not a string object yet.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
1

If you consider this fragment of code:

result = []
while True:
    if msvcrt.kbhit():
        result.append(msvcrt.getche())
        if result[-1] == '\r':   # or \n, whatever Win returns;-)
            return ''.join(result)

You can see that when building the input string, the final character that the user enters must be \r, which is an unprintable character corresponding to the carriage return. Therefore, the returned input string looks like:

test\r

I think you need to rework to the code to discard the final unprintable character from the input.

Oliver
  • 11,297
  • 18
  • 71
  • 121
0

You probably have some unseen bytes after the string. Try to print([c for c in textVar]) and if it shows characters lie '\r' and \n try str(textVar).strip() == "test" or remove those chars manually.

Fma
  • 362
  • 1
  • 11
  • `bytes` is an alias for `str` in Python 2. – Martijn Pieters Aug 12 '16 at 08:27
  • 1
    Printing a container will show the contents converted with `repr()` function. You are creating a very verbose `repr(textVar)` here. There is *no point* in passing a string object to `str()` again; here, `textVar` is *always* a string already. – Martijn Pieters Aug 12 '16 at 08:33