macobo / python-grader

Python >= 3.3 automatic grader
MIT License
11 stars 5 forks source link

Can't input single newline to process under test #39

Open aivarannamaa opened 10 years ago

aivarannamaa commented 10 years ago

When my demo_solution.py is

input()

and demo_tester.py is

from grader import *

@test
def do_test(m):
    m.stdin.put("")

Then python -m grader demo_tester.py demo_solution.py gives me

{
    "success": true,
    "results": [
        {
            "traceback": "Traceback (most recent call last):\n  File \"C:\\Python34\\lib\\site-packages\\grader-0.0.1-py3.4.egg\\grader\\execution_base.py\", line 63, in call_test_function\n    **pre_hook_info[\"extra_kwargs\"]\n  File \"C:\\Python34\\lib\\site-packages\\grader-0.0.1-py3.4.egg\\grader\\core.py\", line 48, in wrapper\n    raise module.caughtException\n  File \"C:\\Python34\\lib\\site-packages\\grader-0.0.1-py3.4.egg\\grader\\program_container.py\", line 38, in run\n    self._exec_code()\n  File \"C:\\Python34\\lib\\site-packages\\grader-0.0.1-py3.4.egg\\grader\\program_container.py\", line 53, in _exec_code\n    exec(code, mod.__dict__)\n  File \"<tested-program>\", line 1, in <module>\nEOFError: EOF when reading a line\n",
            "description": "do_test",
            "error_message": "EOFError: EOF when reading a line",
            "log": [],
            "time": "0.212",
            "success": false
        }
    ]
}
macobo commented 10 years ago

Not able to test this at the moment, but I figure this has to do with some assumptions that the built in sys.stdin that we are mocking operates on - it not receiving anything is assumed to be the same as entering EOF.

A workaround for this should be to m.stdin.put("\n") which I would expect to behave much the same.

You can also dig into the python stdio implementation or spec and fix it yourself - I can give you commit access. :)

aivarannamaa commented 10 years ago

A workaround for this should be to m.stdin.put("\n")

Nope, this results in "\n\n" being sent to stdin.

macobo commented 10 years ago

While digging I arrived here - https://github.com/akheron/cpython/blob/d04cd9a21a22a56ec3cb577229808c019217b8e0/Objects/fileobject.c#L107. Not sure what the fix is, but perhaps will help you.

aivarannamaa commented 10 years ago

A workaround for this should be to m.stdin.put("\n")

Nope, this results in "\n\n" being sent to stdin.

My mistake, I tested it incorrectly. The workaround actually works.

But I also noticed that you're using the same m.stdin object as spoofed stdin (I thought this is just a convenience wrapper). The problem is that it doesn't follow the normal stream contract which says that method readline reads up to and including next newline in the stream (or up to EOF). Current code works as long as one doesn't put a string with newline in the middle and when stdin is read only with input (which strips the (possibly non-existing) trailing newline anyway).

My plan is to replace everywhere in my fork m.stdin.write-s with m.stdin.put-s, redefine SpoofedStdin.write and SpoofedStdin.readline according to stream contract and leave SpoofedStdin.put as a conveniece method which appends "\n"to input automatically.

macobo commented 10 years ago

That sounds like a plausibleplan - I'd prefer if you work directly on this repo (gave you access).