[BUG]: Requests post is blocking in python code, but server is receiving the data (Not sure if it is bug)

Code:
Below post request is run from separate thread with `daemon=True` set
```
print("Sending request to: ", LOG_AUTH_SERVER_URL)
r = requests.post(url=LOG_AUTH_SERVER_URL, json={
    "clientid":  "a12hello",
}, timeout=5, headers={
    'Connection': 'close'
}) 
print("After request ...")
```

After sending the request, the print statement 
```
print("After request ...")
```
is never executed at all. I could see the url is hit to server as it clearly logged and sent 200. However, in python code the print statement is never executed.


After debugging for hours, I could see that I am importing `pygame` in one of the python file as shown below,
```
try:
    import contextlib
    os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
    with contextlib.redirect_stdout(None):
        import pygame.camera
        import pygame
        import pygame.image

    is_pygame = True
except ImportError:
    is_pygame = False
    raise Exception(
        "pygame import error, install pygame and linux/windows dev dependencies. "
    )
```
When I have removed `import contextlib` and only imported `pygame`, the code has worked without blocking and the print statement got executed successfully.

After modifcation:
```
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
import pygame.camera
import pygame
import pygame.image
```

it has worked, But i am not sure what exaclty is happening and why the code got blocked.  If I sleep for 1 second before post request it does work if `contextlib` was used earlier.


## Bug details
### Code: the name of the file `httpcore.py`

![Screenshot (651)](https://user-images.githubusercontent.com/43678329/219650320-30f575c3-9b81-48c9-b9d1-577962beeecd.png)

-------------
### Code for pygame is in another file, `main.py` as shown below,

![Screenshot (652)](https://user-images.githubusercontent.com/43678329/219650480-658197db-3cf9-4756-aa35-6dbe42c5f316.png)


----------
### Now running the project, which puts the post request, the output is:

![Screenshot (653)](https://user-images.githubusercontent.com/43678329/219650678-11bf5d5a-47d5-4826-a836-0761ba00ad6d.png)

It shows request is sent, but the next print statement is never executed.
```
print("Request Send successfully", r.status_code, r.text)
```


----------------
### After Editing pygame import as shown below, (commented contextlib)
![Screenshot (654)](https://user-images.githubusercontent.com/43678329/219650883-e2ee1f4c-6f82-4a4e-a0e1-dcd0ad57d47f.png)

and then reran the code, the output is,

![Screenshot (655)](https://user-images.githubusercontent.com/43678329/219651119-ab8ececb-87db-4694-9637-547a3c4afcc0.png)

Clearly the next print statement is executed with status code and the response data.
```
print("Request Send successfully", r.status_code, r.text)

```


----------
### If sleep used, as shown below,
![Screenshot (657)](https://user-images.githubusercontent.com/43678329/219651339-2dc59b00-738d-4690-b934-1f85cb483afd.png)

even if `contextlib` used, i could get the response

-----------

## Observations
- Is it  bug, surely it is something to do with `contextlib`
- The code was ran many times to reproduce the issue and using context lib indeed reproduced the issue of blocking many times (out of 10 consider 7 to 8)
- However removing contextlib did not reproduce issue, but i am not sure is it really the cause
- using sleep before post request when contextlib used indeed worked but again not sure if it fixes all time
- Any one with internals of request module, is there some sort of locking which had caused the requests to block forever instead of returning due to contextlib usage or some GIL Lock not sure what exactly it is ??


@kennethreitz 

@mai1x9
It's likely that the contextlib.redirect_stdout(None) call is the source of the problem. This call is redirecting the output of stdout to None, effectively suppressing any output to the console. Since print() statements write to stdout, they are being blocked as well.

<edit> though why the first print statement before the request is still working...

when you add the sleep WITH contextlib are you still using it with redirect_stdout(None)?

@michaeltempesta thank you for quick reply. I was worried if my question gets unanswered and I need to hurdle around. A sign of relief since `contextlib` could be an issue. 


> though why the first print statement before the request is still working...


Not just first print statement, all print statements in main thread works.  In other words the requests post runs on daemon thread-A but gets blocked. The contextlib with `redirect_sdtout(None)` runs on main thread. In fact main thread will lauch multiple processes using multi processing so we used multi processing spawn and freezed app (just in case if this info might be useful. I have come across scenario where **multiprocessing sometimes blocks logging module forever when written to logs**)

I could see print statements written in main thread even after contextlib redirect was called all of them executed. However the thread-A with requests post got blocked strangely. 


> when you add the sleep WITH contextlib are you still using it with redirect_stdout(None)?

True, initially when I didn't knew contextlib could be culprit, I tried out sleeping for second before post request and it did worked even if contextlib with redirect_stdout(None) used. Then after debugging and figuring out contextlib was culprit, I could sense that possibly since requests running on thread-A and contextlib running on Main thread looks like some sort of locking might be happening such that when contextlib std out called from main thread, exaclty then from thread A, requests post is called and a lock (not sure if lock or what else??) might be occurred freezing the subsequent request module. 


@michaeltempesta Found out, after you have hinted

> This call is redirecting the output of stdout to None, effectively suppressing any output to the console. Since print() statements write to stdout, they are being blocked as well


I can conclude `redirect_stdout(None)` is culprit, after digging into documentation, https://docs.python.org/3/library/contextlib.html?highlight=context#contextlib.redirect_stdout I could see 3 important points

> Context manager for temporarily redirecting [sys.stdout](https://docs.python.org/3/library/sys.html#sys.stdout) to another file or file-like object.

> Note that the global side effect on [sys.stdout](https://docs.python.org/3/library/sys.html#sys.stdout) means that this context manager is not suitable for use in library code and most threaded applications. and

and

> This context manager is [reentrant](https://docs.python.org/3/library/contextlib.html?highlight=context#reentrant-cms).

So clearly, when 
```
    with contextlib.redirect_stdout(None):
        import pygame.camera
        import pygame
        import pygame.image
```
`with` blocked called, during the same time requests post have given output and all print statements got suppressed since `with`  block is not released yet, I could not see print statements after request post giving false **output that the code is blocking.**.  Once the `with` block is executed the print statements are executed as usual hence I could see other print statements.  I have tried to keep sleep after requests posts,
```
r = requests.post(url=LOG_AUTH_SERVER_URL, json={
                "clientid": self.clientid
            }, timeout=5, headers={
                'Connection': 'close'
            })  # timeout 60 seconds
            sleep(1)
            print("======\n", r.status_code)
```
Now clearly the `with` block as been executed and hence sleeping for a second indeed printed the output. Overall It has just suppressed the output while `with` block is executed. 

Also the doc mentioned,

> Note also that being reentrant is not the same thing as being thread safe. [redirect_stdout()](https://docs.python.org/3/library/contextlib.html?highlight=context#contextlib.redirect_stdout), for example, is definitely not thread safe, as it makes a global modification to the system state by binding [sys.stdout](https://docs.python.org/3/library/sys.html#sys.stdout) to a different stream.


**Concluding, it was just the sys stdout got suppressed globally throughout the application blocking all print statements not to print until the `with` block is finished and subsequently other print calls were made and output is visible.**


Let me know if I am wrong anywhere in justifying the answer.

Thank you very much.




(looks like i took too long with my reply ^_^) here's my guess for what may be useful to you, cheers

i'm going to guess that your threading is creating a race condition between the contextlib imports and the request, std_out(none) kicking in after the pre request print statement and and post request being nullified because of it. 
im not confident i can help with this but (i think) your sleep solution is working because it gives the imports time to finish and re-open std_out.

print statements on main working because they process after the with context block is closed.

the request is working just not printing. 
if it really is just a matter of time to wait for the with context block to finish and this is an isolated otherwise incident... make the request in main after the with block?

my apologizes but this is me regurgitating chatgpt for using threading.Lock (im not well versed):
`import threading
import contextlib
import requests

# Create a lock object
lock = threading.Lock()

def main():
    # Acquire the lock before the contextlib block
    lock.acquire()

    with contextlib.redirect_stdout(None):
        # Perform some output suppression
        print("This output will not be printed")

    # Release the lock after the contextlib block
    lock.release()

def thread_a():
    # Acquire the lock before making the request
    lock.acquire()

    # Make the request
    r = requests.post(url=LOG_AUTH_SERVER_URL, json={
        "clientid":  "a12hello",
    }, timeout=5, headers={
        'Connection': 'close'
    })

    # Release the lock after the request is done
    lock.release()

if __name__ == '__main__':
    t = threading.Thread(target=thread_a)
    t.start()

    main()

    t.join()
`

drop a lock.acquire() in main before the with block and lock.release() after... same for before and after the request?

hope this helps


Hi there! Thanks for opening this issue. Unfortunately, it seems this is a request for help instead of a report of a defect in the project. Please use [StackOverflow](https://stackoverflow.com) for general usage questions instead and only report defects here.