gabrielfalcao / HTTPretty

Intercept HTTP requests at the Python socket level. Fakes the whole socket module

Home Page:https://httpretty.readthedocs.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ValueError: write to closed file when emulating timeouts

davetapley opened this issue · comments

I am emulating a timeout per here, however when I use this approach with a requests timeout I get this error:

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/threading.py", line 973, in _bootstrap_inner
    self.run()
  File "/usr/local/lib/python3.9/threading.py", line 910, in run
    self._target(*self._args, **self._kwargs)
  File "/home/vscode/.local/lib/python3.9/site-packages/httpretty/core.py", line 1133, in fill_filekind
    fk.write(utf8(item) + b'\n')
ValueError: write to closed file

I assume it would be safe to just catch the ValueError: write to closed file in ⬇️ because it should only happen when emulating a timeout in this way?

HTTPretty/httpretty/core.py

Lines 1132 to 1135 in a11874a

for item in string_list:
fk.write(utf8(item) + b'\n')
fk.write(b'\r\n')

Hey @davetapley, thanks for reporting this issue.

I assume it would be safe to just catch the ValueError: write to closed file in ⬇️ because it should only happen when emulating a timeout in this way?
This could be a last resort, but first I would like to reproduce the issue and try to fix the root cause.

Would you be able to share some piece of code to reproduce the issue?

Hi @gabrielfalcao, how are you?

I have the same issue and an example to help you.

Python version and dependencies:

python==3.8.10
httpretty==1.1.4
pytest==6.2.5
requests==2.26.0

A little piece of code to test

def request():
    requests.get('https://www.google.com.br', timeout=0.5)

Test

import httpretty
import pytest

from app import request
from requests.exceptions import Timeout
from threading import Event


@httpretty.activate(allow_net_connect=False)
def test_httpretty_timeout_error():
    # arrange
    event = Event()

    def slow_callback(request, url, headers):
        event.wait(1)
        return 200, headers, 'OK'

    httpretty.register_uri(httpretty.GET, 'https://www.google.com.br', body=slow_callback)

    # act/assert
    with pytest.raises(Timeout):
        request()

Execution

================================= test session starts =================================
platform darwin -- Python 3.8.10, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: /Users/c90362a/Study/python/httpretty
collected 1 item                                                                      

tests/test_app.py .                                                             [100%]

================================== 1 passed in 0.73s ==================================
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/Users/c90362a/.pyenv/versions/3.8.10/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/Users/c90362a/.pyenv/versions/3.8.10/lib/python3.8/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/c90362a/.local/share/virtualenvs/httpretty-NVzm-QW2/lib/python3.8/site-packages/httpretty/core.py", line 1133, in fill_filekind
    fk.write(utf8(item) + b'\n')
ValueError: write to closed file

I hope this helps you.

Got the same issue using the same example here: https://httpretty.readthedocs.io/en/latest/guides.html?highlight=timeout#emulating-timeouts

I'm using python3.11

Any follow up on this?

For anyone else who comes across this issue, I've worked around the issue be wrapping the threading.excepthook to suppress the exception:

import threading

def _excepthook_wrapper():      
    _orig_excepthook = threading.excepthook      
      
    def _excepthook(args):      
        if isinstance(args.exc_value, ValueError) and args.exc_value.args == (
            'write to closed file',  
        ):    
            return      
      
        return _orig_excepthook(args)      
      
    return _excepthook      
      
      
# suppress exceptions in httpretty thread for timeout test      
threading.excepthook = _excepthook_wrapper()

Just place the above code somewhere before your tests run and it should help.