From 89166cf951030cf61241983337fd7ffd2536878a Mon Sep 17 00:00:00 2001 From: Will Rouesnel Date: Mon, 16 Mar 2015 21:09:25 +1100 Subject: [PATCH 1/8] Improve the monkey-patching library to replicate requests more closely This patch modifies the monkey-patch library to properly patch all the requests built-in methods, providing a complete drop-in replacement. --- requests_unixsocket/__init__.py | 51 ++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/requests_unixsocket/__init__.py b/requests_unixsocket/__init__.py index b3ba152..a970fb9 100644 --- a/requests_unixsocket/__init__.py +++ b/requests_unixsocket/__init__.py @@ -3,25 +3,27 @@ import sys from .adapters import UnixAdapter -__all__ = ['monkeypatch', 'Session'] - DEFAULT_SCHEME = 'http+unix://' - class Session(requests.Session): def __init__(self, url_scheme=DEFAULT_SCHEME, *args, **kwargs): super(Session, self).__init__(*args, **kwargs) self.mount(url_scheme, UnixAdapter()) - class monkeypatch(object): def __init__(self, url_scheme=DEFAULT_SCHEME): self.session = Session() requests = self._get_global_requests_module() - self.orig_requests_get = requests.get - requests.get = self.session.get - self.orig_requests_request = requests.request - requests.request = self.session.request + + # Methods to replace + self.methods = ('request', 'get', 'head', 'post', + 'patch', 'put', 'delete', 'options') + # Store the original methods + self.orig_methods = dict( (m,requests.__dict__[m]) for m in self.methods ) + # Monkey patch + g = globals() + for m in self.methods: + requests.__dict__[m] = g[m] def _get_global_requests_module(self): return sys.modules['requests'] @@ -31,5 +33,34 @@ class monkeypatch(object): def __exit__(self, *args): requests = self._get_global_requests_module() - requests.get = self.orig_requests_get - requests.request = self.orig_requests_request + for m in self.methods: + requests.__dict__[m] = self.orig_methods[m] + +# These are the same methods defined for the global requests object +def request(method, url, **kwargs): + session = Session() + return session.request(method=method, url=url, **kwargs) + +def get(url, **kwargs): + kwargs.setdefault('allow_redirects', True) + return request('get', url, **kwargs) + +def head(url, **kwargs): + kwargs.setdefault('allow_redirects', False) + return request('head', url, **kwargs) + +def post(url, **kwargs): + return request('post', url, data=data, **kwargs) + +def patch(url, **kwargs): + return request('patch', url, data=data, **kwargs) + +def put(url, **kwargs): + return request('put', url, data=data, **kwargs) + +def delete(url, **kwargs): + return request('delete', url, **kwargs) + +def options(url, **kwargs): + kwargs.setdefault('allow_redirects', True) + return request('options', url, **kwargs) From acbf964a0c5df40db581b24ad858501bfe3e722c Mon Sep 17 00:00:00 2001 From: William Rouesnel Date: Thu, 9 Apr 2015 10:58:05 +1000 Subject: [PATCH 2/8] Make PEP8 compliant with autopep8. --- requests_unixsocket/adapters.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/requests_unixsocket/adapters.py b/requests_unixsocket/adapters.py index 356d59d..5888453 100644 --- a/requests_unixsocket/adapters.py +++ b/requests_unixsocket/adapters.py @@ -13,6 +13,7 @@ except ImportError: # The following was adapted from some code from docker-py # https://github.com/docker/docker-py/blob/master/docker/unixconn/unixconn.py class UnixHTTPConnection(HTTPConnection): + def __init__(self, unix_socket_url, timeout=60): """Create an HTTP connection to a unix domain socket @@ -33,6 +34,7 @@ class UnixHTTPConnection(HTTPConnection): class UnixHTTPConnectionPool(HTTPConnectionPool): + def __init__(self, socket_path, timeout=60): HTTPConnectionPool.__init__(self, 'localhost', timeout=timeout) self.socket_path = socket_path @@ -43,6 +45,7 @@ class UnixHTTPConnectionPool(HTTPConnectionPool): class UnixAdapter(HTTPAdapter): + def __init__(self, timeout=60): super(UnixAdapter, self).__init__() self.timeout = timeout From 0e53c1a2494ae94dbea40c2c851ba2c41166317a Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Thu, 9 Apr 2015 10:21:34 -0700 Subject: [PATCH 3/8] Tweak a few things in PR 12 Tweak a few things in https://github.com/msabramo/requests-unixsocket/pull/12 --- requests_unixsocket/__init__.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/requests_unixsocket/__init__.py b/requests_unixsocket/__init__.py index a970fb9..4f27e6b 100644 --- a/requests_unixsocket/__init__.py +++ b/requests_unixsocket/__init__.py @@ -5,21 +5,24 @@ from .adapters import UnixAdapter DEFAULT_SCHEME = 'http+unix://' + class Session(requests.Session): def __init__(self, url_scheme=DEFAULT_SCHEME, *args, **kwargs): super(Session, self).__init__(*args, **kwargs) self.mount(url_scheme, UnixAdapter()) + class monkeypatch(object): def __init__(self, url_scheme=DEFAULT_SCHEME): self.session = Session() requests = self._get_global_requests_module() - + # Methods to replace - self.methods = ('request', 'get', 'head', 'post', + self.methods = ('request', 'get', 'head', 'post', 'patch', 'put', 'delete', 'options') # Store the original methods - self.orig_methods = dict( (m,requests.__dict__[m]) for m in self.methods ) + self.orig_methods = dict( + (m, requests.__dict__[m]) for m in self.methods) # Monkey patch g = globals() for m in self.methods: @@ -36,31 +39,39 @@ class monkeypatch(object): for m in self.methods: requests.__dict__[m] = self.orig_methods[m] + # These are the same methods defined for the global requests object def request(method, url, **kwargs): session = Session() return session.request(method=method, url=url, **kwargs) + def get(url, **kwargs): kwargs.setdefault('allow_redirects', True) return request('get', url, **kwargs) + def head(url, **kwargs): kwargs.setdefault('allow_redirects', False) return request('head', url, **kwargs) + def post(url, **kwargs): - return request('post', url, data=data, **kwargs) + return request('post', url, **kwargs) + def patch(url, **kwargs): - return request('patch', url, data=data, **kwargs) + return request('patch', url, **kwargs) + def put(url, **kwargs): - return request('put', url, data=data, **kwargs) + return request('put', url, **kwargs) + def delete(url, **kwargs): return request('delete', url, **kwargs) + def options(url, **kwargs): kwargs.setdefault('allow_redirects', True) return request('options', url, **kwargs) From a379fb204a289d6d0de857b9bdfc03afe8bdc3f8 Mon Sep 17 00:00:00 2001 From: Will Rouesnel Date: Thu, 30 Apr 2015 04:59:23 +1000 Subject: [PATCH 4/8] Fix up some oversights in method parsing. This corrects the style to exactly follow the requests library. --- requests_unixsocket/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/requests_unixsocket/__init__.py b/requests_unixsocket/__init__.py index a970fb9..5c87a3b 100644 --- a/requests_unixsocket/__init__.py +++ b/requests_unixsocket/__init__.py @@ -49,13 +49,13 @@ def head(url, **kwargs): kwargs.setdefault('allow_redirects', False) return request('head', url, **kwargs) -def post(url, **kwargs): - return request('post', url, data=data, **kwargs) +def post(url, data=None, json=None, **kwargs): + return request('post', url, data=data, json=json, **kwargs) -def patch(url, **kwargs): +def patch(url, data=None, **kwargs): return request('patch', url, data=data, **kwargs) -def put(url, **kwargs): +def put(url, data=None, **kwargs): return request('put', url, data=data, **kwargs) def delete(url, **kwargs): From 12b31c0f49f14dd43c15dc43770b715c93c98038 Mon Sep 17 00:00:00 2001 From: Will Rouesnel Date: Thu, 30 Apr 2015 05:39:43 +1000 Subject: [PATCH 5/8] More PEP8 compliance refactoring. --- requests_unixsocket/__init__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/requests_unixsocket/__init__.py b/requests_unixsocket/__init__.py index cc2a09c..0fb5e1f 100644 --- a/requests_unixsocket/__init__.py +++ b/requests_unixsocket/__init__.py @@ -55,19 +55,23 @@ def head(url, **kwargs): kwargs.setdefault('allow_redirects', False) return request('head', url, **kwargs) + def post(url, data=None, json=None, **kwargs): return request('post', url, data=data, json=json, **kwargs) + def patch(url, data=None, **kwargs): - return request('patch', url, data=data, **kwargs) + return request('patch', url, data=data, **kwargs) + def put(url, data=None, **kwargs): return request('put', url, data=data, **kwargs) + def delete(url, **kwargs): return request('delete', url, **kwargs) + def options(url, **kwargs): kwargs.setdefault('allow_redirects', True) return request('options', url, **kwargs) - From 206e7bf83cdaf91bc3b56ba51f394c70a7c910ba Mon Sep 17 00:00:00 2001 From: Will Rouesnel Date: Thu, 30 Apr 2015 05:40:08 +1000 Subject: [PATCH 6/8] Add basic tests for all supported methods. --- .../tests/test_requests_unixsocket.py | 148 ++++++++++-------- 1 file changed, 86 insertions(+), 62 deletions(-) diff --git a/requests_unixsocket/tests/test_requests_unixsocket.py b/requests_unixsocket/tests/test_requests_unixsocket.py index 81b3fdf..304736a 100755 --- a/requests_unixsocket/tests/test_requests_unixsocket.py +++ b/requests_unixsocket/tests/test_requests_unixsocket.py @@ -20,67 +20,11 @@ def test_unix_domain_adapter_ok(): session = requests_unixsocket.Session('http+unix://') urlencoded_usock = requests.compat.quote_plus(usock_thread.usock) url = 'http+unix://%s/path/to/page' % urlencoded_usock - logger.debug('Calling session.get(%r) ...', url) - r = session.get(url) - logger.debug( - 'Received response: %r with text: %r and headers: %r', - r, r.text, r.headers) - assert r.status_code == 200 - assert r.headers['server'] == 'waitress' - assert r.headers['X-Transport'] == 'unix domain socket' - assert r.headers['X-Requested-Path'] == '/path/to/page' - assert r.headers['X-Socket-Path'] == usock_thread.usock - assert isinstance(r.connection, requests_unixsocket.UnixAdapter) - assert r.url == url - assert r.text == 'Hello world!' - -def test_unix_domain_adapter_url_with_query_params(): - with UnixSocketServerThread() as usock_thread: - session = requests_unixsocket.Session('http+unix://') - urlencoded_usock = requests.compat.quote_plus(usock_thread.usock) - url = ('http+unix://%s' - '/containers/nginx/logs?timestamp=true' % urlencoded_usock) - logger.debug('Calling session.get(%r) ...', url) - r = session.get(url) - logger.debug( - 'Received response: %r with text: %r and headers: %r', - r, r.text, r.headers) - assert r.status_code == 200 - assert r.headers['server'] == 'waitress' - assert r.headers['X-Transport'] == 'unix domain socket' - assert r.headers['X-Requested-Path'] == '/containers/nginx/logs' - assert r.headers['X-Requested-Query-String'] == 'timestamp=true' - assert r.headers['X-Socket-Path'] == usock_thread.usock - assert isinstance(r.connection, requests_unixsocket.UnixAdapter) - assert r.url == url - assert r.text == 'Hello world!' - - -def test_unix_domain_adapter_connection_error(): - session = requests_unixsocket.Session('http+unix://') - - with pytest.raises(requests.ConnectionError): - session.get('http+unix://socket_does_not_exist/path/to/page') - - -def test_unix_domain_adapter_connection_proxies_error(): - session = requests_unixsocket.Session('http+unix://') - - with pytest.raises(ValueError) as excinfo: - session.get('http+unix://socket_does_not_exist/path/to/page', - proxies={"http": "http://10.10.1.10:1080"}) - assert ('UnixAdapter does not support specifying proxies' - in str(excinfo.value)) - - -def test_unix_domain_adapter_monkeypatch(): - with UnixSocketServerThread() as usock_thread: - with requests_unixsocket.monkeypatch('http+unix://'): - urlencoded_usock = requests.compat.quote_plus(usock_thread.usock) - url = 'http+unix://%s/path/to/page' % urlencoded_usock - logger.debug('Calling requests.get(%r) ...', url) - r = requests.get(url) + for method in ['get', 'post', 'head', 'patch', 'put', 'delete', + 'options']: + logger.debug('Calling session.%s(%r) ...', method, url) + r = getattr(session, method)(url) logger.debug( 'Received response: %r with text: %r and headers: %r', r, r.text, r.headers) @@ -91,7 +35,87 @@ def test_unix_domain_adapter_monkeypatch(): assert r.headers['X-Socket-Path'] == usock_thread.usock assert isinstance(r.connection, requests_unixsocket.UnixAdapter) assert r.url == url - assert r.text == 'Hello world!' + if method == 'head': + assert r.text == '' + else: + assert r.text == 'Hello world!' + +def test_unix_domain_adapter_url_with_query_params(): + with UnixSocketServerThread() as usock_thread: + session = requests_unixsocket.Session('http+unix://') + urlencoded_usock = requests.compat.quote_plus(usock_thread.usock) + url = ('http+unix://%s' + '/containers/nginx/logs?timestamp=true' % urlencoded_usock) + + for method in ['get', 'post', 'head', 'patch', 'put', 'delete', + 'options']: + logger.debug('Calling session.%s(%r) ...', method, url) + r = getattr(session, method)(url) + logger.debug( + 'Received response: %r with text: %r and headers: %r', + r, r.text, r.headers) + assert r.status_code == 200 + assert r.headers['server'] == 'waitress' + assert r.headers['X-Transport'] == 'unix domain socket' + assert r.headers['X-Requested-Path'] == '/containers/nginx/logs' + assert r.headers['X-Requested-Query-String'] == 'timestamp=true' + assert r.headers['X-Socket-Path'] == usock_thread.usock + assert isinstance(r.connection, requests_unixsocket.UnixAdapter) + assert r.url == url + if method == 'head': + assert r.text == '' + else: + assert r.text == 'Hello world!' + + +def test_unix_domain_adapter_connection_error(): + session = requests_unixsocket.Session('http+unix://') + + for method in ['get', 'post', 'head', 'patch', 'put', 'delete', 'options']: + with pytest.raises(requests.ConnectionError): + getattr(session, method)( + 'http+unix://socket_does_not_exist/path/to/page') + + +def test_unix_domain_adapter_connection_proxies_error(): + session = requests_unixsocket.Session('http+unix://') + + for method in ['get', 'post', 'head', 'patch', 'put', 'delete', 'options']: + with pytest.raises(ValueError) as excinfo: + getattr(session, method)( + 'http+unix://socket_does_not_exist/path/to/page', + proxies={"http": "http://10.10.1.10:1080"}) + assert ('UnixAdapter does not support specifying proxies' + in str(excinfo.value)) + + +def test_unix_domain_adapter_monkeypatch(): + with UnixSocketServerThread() as usock_thread: + with requests_unixsocket.monkeypatch('http+unix://'): + urlencoded_usock = requests.compat.quote_plus(usock_thread.usock) + url = 'http+unix://%s/path/to/page' % urlencoded_usock + + for method in ['get', 'post', 'head', 'patch', 'put', 'delete', + 'options']: + logger.debug('Calling session.%s(%r) ...', method, url) + r = getattr(requests, method)(url) + logger.debug( + 'Received response: %r with text: %r and headers: %r', + r, r.text, r.headers) + assert r.status_code == 200 + assert r.headers['server'] == 'waitress' + assert r.headers['X-Transport'] == 'unix domain socket' + assert r.headers['X-Requested-Path'] == '/path/to/page' + assert r.headers['X-Socket-Path'] == usock_thread.usock + assert isinstance(r.connection, + requests_unixsocket.UnixAdapter) + assert r.url == url + if method == 'head': + assert r.text == '' + else: + assert r.text == 'Hello world!' + + for method in ['get', 'post', 'head', 'patch', 'put', 'delete', 'options']: with pytest.raises(requests.exceptions.InvalidSchema): - requests.get(url) + getattr(requests, method)(url) From 20f4324fc9e0401b7f505f457c8570e6a787716f Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 6 Aug 2015 22:09:49 +0100 Subject: [PATCH 7/8] Only reject proxies if they are relevant (which should be never) --- requests_unixsocket/adapters.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/requests_unixsocket/adapters.py b/requests_unixsocket/adapters.py index 356d59d..0033694 100644 --- a/requests_unixsocket/adapters.py +++ b/requests_unixsocket/adapters.py @@ -48,7 +48,10 @@ class UnixAdapter(HTTPAdapter): self.timeout = timeout def get_connection(self, socket_path, proxies=None): - if proxies: + proxies = proxies or {} + proxy = proxies.get(urlparse(socket_path.lower()).scheme) + + if proxy: raise ValueError('%s does not support specifying proxies' % self.__class__.__name__) return UnixHTTPConnectionPool(socket_path, self.timeout) From 4a029131e4af0b7fcb0c4c32171a4a969dda03be Mon Sep 17 00:00:00 2001 From: Esben Haabendal Date: Wed, 20 Jan 2016 09:01:09 +0100 Subject: [PATCH 8/8] Fix test_unix_domain_adapter_connection_proxies_error Signed-off-by: Esben Haabendal --- requests_unixsocket/tests/test_requests_unixsocket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requests_unixsocket/tests/test_requests_unixsocket.py b/requests_unixsocket/tests/test_requests_unixsocket.py index 304736a..34151b2 100755 --- a/requests_unixsocket/tests/test_requests_unixsocket.py +++ b/requests_unixsocket/tests/test_requests_unixsocket.py @@ -85,7 +85,7 @@ def test_unix_domain_adapter_connection_proxies_error(): with pytest.raises(ValueError) as excinfo: getattr(session, method)( 'http+unix://socket_does_not_exist/path/to/page', - proxies={"http": "http://10.10.1.10:1080"}) + proxies={"http+unix": "http://10.10.1.10:1080"}) assert ('UnixAdapter does not support specifying proxies' in str(excinfo.value))