Comments (9)
Result is as follows; as you can see the simple_app is called twice;
connect: foo, 80
INTERCEPTING call to foo:80
>>> GET / HTTP/1.1
Host: foo
Accept-Encoding: gzip, deflate, compress
Accept: */*
User-Agent: python-requests/2.2.1 CPython/2.7.3 Linux/3.13-0.bpo.1-amd64
>>>
HEADER: Host foo
HEADER: Accept-Encoding gzip, deflate, compress
HEADER: Accept */*
HEADER: User-Agent python-requests/2.2.1 CPython/2.7.3 Linux/3.13-0.bpo.1-amd64
METHOD LINE: GET / HTTP/1.1
method: GET; script_name: ; path_info: /; query_string:
WSGI environ dictionary: {'wsgi.multithread': 0, 'SCRIPT_NAME': '', 'wsgi.input': <_io.BytesIO object at 0x226e950>, 'REQUEST_METHOD': 'GET', u'HTTP_HOST': u'foo', 'PATH_INFO': '/', 'SERVER_PROTOCOL': 'HTTP/1.1\r\n', u'HTTP_ACCEPT': u'*/*', u'HTTP_USER_AGENT': u'python-requests/2.2.1 CPython/2.7.3 Linux/3.13-0.bpo.1-amd64', 'wsgi.version': (1, 0), 'SERVER_NAME': 'foo', 'REMOTE_ADDR': '127.0.0.1', 'wsgi.run_once': 0, 'wsgi.errors': <_io.BytesIO object at 0x226e9b0>, 'wsgi.multiprocess': 0, 'wsgi.url_scheme': 'http', 'SERVER_PORT': 80, u'HTTP_ACCEPT_ENCODING': u'gzip, deflate, compress'}
HEADER: Host foo
HEADER: Accept-Encoding gzip, deflate, compress
HEADER: Accept */*
HEADER: User-Agent python-requests/2.2.1 CPython/2.7.3 Linux/3.13-0.bpo.1-amd64
METHOD LINE: GET / HTTP/1.1
method: GET; script_name: ; path_info: /; query_string:
WSGI environ dictionary: {'wsgi.multithread': 0, 'SCRIPT_NAME': '', 'wsgi.input': <_io.BytesIO object at 0x226ead0>, 'REQUEST_METHOD': 'GET', u'HTTP_HOST': u'foo', 'PATH_INFO': '/', 'SERVER_PROTOCOL': 'HTTP/1.1\r\n', u'HTTP_ACCEPT': u'*/*', u'HTTP_USER_AGENT': u'python-requests/2.2.1 CPython/2.7.3 Linux/3.13-0.bpo.1-amd64', 'wsgi.version': (1, 0), 'SERVER_NAME': 'foo', 'REMOTE_ADDR': '127.0.0.1', 'wsgi.run_once': 0, 'wsgi.errors': <_io.BytesIO object at 0x226eb30>, 'wsgi.multiprocess': 0, 'wsgi.url_scheme': 'http', 'SERVER_PORT': 80, u'HTTP_ACCEPT_ENCODING': u'gzip, deflate, compress'}
Traceback (most recent call last):
File "except_test.py", line 18, in <module>
print requests.get('http://foo/')
File "/usr/local/lib/python2.7/dist-packages/requests-2.2.1-py2.7.egg/requests/api.py", line 55, in get
return request('get', url, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests-2.2.1-py2.7.egg/requests/api.py", line 44, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests-2.2.1-py2.7.egg/requests/sessions.py", line 383, in request
resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests-2.2.1-py2.7.egg/requests/sessions.py", line 486, in send
r = adapter.send(request, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests-2.2.1-py2.7.egg/requests/adapters.py", line 330, in send
timeout=timeout
File "/usr/local/lib/python2.7/dist-packages/requests-2.2.1-py2.7.egg/requests/packages/urllib3/connectionpool.py", line 480, in urlopen
body=body, headers=headers)
File "/usr/local/lib/python2.7/dist-packages/requests-2.2.1-py2.7.egg/requests/packages/urllib3/connectionpool.py", line 315, in _make_request
httplib_response = conn.getresponse()
File "/usr/lib/python2.7/httplib.py", line 1032, in getresponse
response = self.response_class(*args, **kwds)
File "/usr/lib/python2.7/httplib.py", line 346, in __init__
self.fp = sock.makefile('rb', 0)
File "/usr/local/lib/python2.7/dist-packages/wsgi_intercept-0.6.2-py2.7.egg/wsgi_intercept/__init__.py", line 356, in makefile
app_result = self.app(environ, start_response)
File "except_test.py", line 12, in simple_app
raise TypeError, "bah"
TypeError: bah
from wsgi-intercept.
Trying your code, I locally saw two calls as well (although I don't certify it's the same problem)...
In the tracebacks, I see the calls emitting from requests' vendored urllib3 (for me this is requests/packages/urllib3/connectionpool.py, lines 313 and 315).
try: # Python 2.7+, use buffering of HTTP responses
httplib_response = conn.getresponse(buffering=True)
except TypeError: # Python 2.6 and older
httplib_response = conn.getresponse()
I am getting the intentionally-raised TypeError from conn.getresponse(buffering=True), so this try/except catches it and calls conn.getresponse() a second time, in the except clause.
urllib3 could be patched to detect the version difference in a less corny way (or 2.6 deprecated so it isn't even necessary to use this try/except... ahem) but that will be more trouble to get fixed - and anyway there are going to be other instances of the more abstract problem here. The app's TypeError probably shouldn't be caught by requests' TypeError handler, which can't reasonably suppose that exceptions raised by code in "the server" will reach it, that expectation is being violated by wsgi-intercept of course.
Does solving this require intentionally catching non-profound errors at some barrier before they bubble up to requests?
from wsgi-intercept.
Thanks for the detailed report.
Does solving this require intentionally catching non-profound errors at some barrier before they bubble up to requests?
That makes some sense. That barrier would act in the same capacity as an actual network. Of course the barrier couldn't simply re-raise, it would need to encapsulate the exception as something special to avoid the existing problem.
Thoughts?
from wsgi-intercept.
I agree. I think you would need to re-raise the exception from the WSGI app as a new exception of a different type. This could either just be for TypeError, or perhaps better just wrap all errors from the WSGI app and pass their details along as parameters of a new wsgi_intercept exception.
from wsgi-intercept.
So you are collecting the app's error somewhere, and then at some time after requests.get is not on the stack, you want to raise (so that the exception reaches e.g. the unit test calling requests.get). Some other exception which holds stale traceback info from the app's error. My question is what triggers that. It is overly clever and intrusive to replace requests.get with a wrapper that does the raise right afterward. So now you are somehow relying on the user to somehow trigger a poll for whether an app error just happened, which they are likely to forget.
Here's one brainstorm that doesn't seem optimal to me, but could be a fallback position: use a context manager as recommended API for installing/uninstalling the intercept. User's calls like request.get happen inside the with-block. On exit from the with-block, the context manager can poll for the app exception. This means the user doesn't have to do anything except use recommended API for install/uninstall. If you could guarantee user would run the uninstall thingy, you could poll there.
What bothers me about this is that a lot can happen between the end of requests.get and the uninstall, so then you are in the position of collecting and reporting any number of past app errors... also this is a pretty big change
from wsgi-intercept.
I was thinking that any exceptions from the app would be re-raised immediately as a different type that isn't caught by requests' exception handler. That might be a bit fragile though.
from wsgi-intercept.
A context manager is a good idea (for more than just the reasons stated), but yes would be a quite large change. The original design of wsgi-intercept predates context managers by quite a bit. Probably worth doing in the long run.
In the short term I think wrapping any exception from the app and raising it as a special WSGIInterceptException (or similar) is the way to go. This would be the equivalent of getting a 500 from the server.
I might be able to do this on Sunday, but if anybody wants to get to it before then feel free.
from wsgi-intercept.
Ah, so the idea is to catch TypeError("bah") and then reraise OurOwnError(), knowing that requests.get may catch any normal error but not OurOwnError? That seems simple enough.
from wsgi-intercept.
I believe this is addressed by the merged PR #6.
from wsgi-intercept.
Related Issues (20)
- Including LICENSE file in the code repository and Adding it in the Manifest file HOT 4
- unexpected keyword argument 'source_address' HOT 3
- Please allow to disable internet tests HOT 3
- wsgi_intercept.make_environ turns headers into unicode HOT 3
- When using the url arg to an Interceptor, if there is no port in the url an error happens
- wsgi-intercept should build in some character encoding checks
- Write ignores response body when first item in iterable is an empty string HOT 1
- urllib3 intercept cause TypeError with https URL HOT 8
- Logs / errors are lost due to `wsgi.errors` not extracted HOT 4
- Interceptor.uninstall_interceptor turns off intercept for all intercepts using the same module
- Pypi sdist tarball doesn't have README.rst HOT 3
- Missing 2 required positional arguments: 'environ' and 'start_response' with Django 2.2 HOT 4
- With httplib2 0.14.0 many tests fail HOT 9
- HTTPS connections with Requests library don't support verify=False to outside domains HOT 7
- Support aiohttp HOT 2
- Simple example fails with Python 2 HOT 5
- PEP517 HOT 4
- Incompatibility with pytest 7.2.0 HOT 2
- support urllib3 > 2 HOT 1
- drop support for python 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from wsgi-intercept.