Skip to content
This repository has been archived by the owner on Jan 13, 2021. It is now read-only.

Commit

Permalink
Merge pull request #226 from Lukasa/linting
Browse files Browse the repository at this point in the history
Add linting to the project.
  • Loading branch information
Lukasa committed Apr 19, 2016
2 parents 08b0c98 + 13374a8 commit 11e0f2a
Show file tree
Hide file tree
Showing 34 changed files with 485 additions and 244 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ matrix:

install:
- ".travis/install.sh"
before_script: "flake8 --max-complexity 15 --exclude 'hyper/packages/*' hyper test"

script:
- >
if [[ "$TEST_RELEASE" == true ]]; then
Expand Down
1 change: 1 addition & 0 deletions .travis/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,4 @@ fi

pip install .
pip install -r test_requirements.txt
pip install flake8
11 changes: 7 additions & 4 deletions hyper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
A module for providing an abstraction layer over the differences between
HTTP/1.1 and HTTP/2.
"""
__version__ = '0.5.0'
import logging

from .common.connection import HTTPConnection
from .http20.connection import HTTP20Connection
Expand All @@ -16,8 +16,10 @@

# Throw import errors on Python <2.7 and 3.0-3.2.
import sys as _sys
if _sys.version_info < (2,7) or (3,0) <= _sys.version_info < (3,3):
raise ImportError("hyper only supports Python 2.7 and Python 3.3 or higher.")
if _sys.version_info < (2, 7) or (3, 0) <= _sys.version_info < (3, 3):
raise ImportError(
"hyper only supports Python 2.7 and Python 3.3 or higher."
)

__all__ = [
HTTPConnection,
Expand All @@ -29,5 +31,6 @@
]

# Set default logging handler.
import logging
logging.getLogger(__name__).addHandler(logging.NullHandler())

__version__ = '0.5.0'
40 changes: 21 additions & 19 deletions hyper/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,23 +111,25 @@ def make_troubleshooting_argument(parser):
help="Do HTTP/2 directly in plaintext: skip plaintext upgrade")


def set_url_info(args):
def split_host_and_port(hostname):
if ':' in hostname:
return to_host_port_tuple(hostname, default_port=443)
return hostname, None

class UrlInfo(object):
def __init__(self):
self.fragment = None
self.host = 'localhost'
self.netloc = None
self.path = '/'
self.port = 443
self.query = None
self.scheme = 'https'
self.secure = False
def split_host_and_port(hostname):
if ':' in hostname:
return to_host_port_tuple(hostname, default_port=443)
return hostname, None


class UrlInfo(object):
def __init__(self):
self.fragment = None
self.host = 'localhost'
self.netloc = None
self.path = '/'
self.port = 443
self.query = None
self.scheme = 'https'
self.secure = False


def set_url_info(args):
info = UrlInfo()
_result = urlsplit(args._url)
for attr in vars(info).keys():
Expand Down Expand Up @@ -167,9 +169,9 @@ def set_request_data(args):
if i.key:
headers[i.key] = i.value
else:
# when overriding a HTTP/2 special header there will be a leading
# colon, which tricks the command line parser into thinking
# the header is empty
# when overriding a HTTP/2 special header there will be a
# leading colon, which tricks the command line parser into
# thinking the header is empty
k, v = i.value.split(':', 1)
headers[':' + k] = v
elif i.sep == SEP_QUERY:
Expand Down
5 changes: 2 additions & 3 deletions hyper/common/bufsocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import select
from .exceptions import ConnectionResetError, LineTooLongError


class BufferedSocket(object):
"""
A buffered socket wrapper.
Expand Down Expand Up @@ -137,8 +138,7 @@ def recv(self, amt):
else:
should_read = True

if ((self._remaining_capacity > self._bytes_in_buffer) and
(should_read)):
if (self._remaining_capacity > self._bytes_in_buffer and should_read):
count = self._sck.recv_into(self._buffer_view[self._buffer_end:])

# The socket just got closed. We should throw an exception if we
Expand Down Expand Up @@ -172,7 +172,6 @@ def fill(self):

return


def readline(self):
"""
Read up to a newline from the network and returns it. The implicit
Expand Down
16 changes: 9 additions & 7 deletions hyper/common/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from ..http20.connection import HTTP20Connection
from ..tls import H2_NPN_PROTOCOLS, H2C_PROTOCOL


class HTTPConnection(object):
"""
An object representing a single HTTP connection to a server.
Expand All @@ -24,26 +25,27 @@ class HTTPConnection(object):
:param host: The host to connect to. This may be an IP address or a
hostname, and optionally may include a port: for example,
``'http2bin.org'``, ``'http2bin.org:443'`` or ``'127.0.0.1'``.
:param port: (optional) The port to connect to. If not provided and one also
isn't provided in the ``host`` parameter, defaults to 80.
:param port: (optional) The port to connect to. If not provided and one
also isn't provided in the ``host`` parameter, defaults to 80.
:param secure: (optional) Whether the request should use TLS.
Defaults to ``False`` for most requests, but to ``True`` for any
request issued to port 443.
:param window_manager: (optional) The class to use to manage flow control
windows. This needs to be a subclass of the
:class:`BaseFlowControlManager <hyper.http20.window.BaseFlowControlManager>`.
If not provided,
:class:`BaseFlowControlManager
<hyper.http20.window.BaseFlowControlManager>`. If not provided,
:class:`FlowControlManager <hyper.http20.window.FlowControlManager>`
will be used.
:param enable_push: (optional) Whether the server is allowed to push
resources to the client (see
:meth:`get_pushes() <hyper.HTTP20Connection.get_pushes>`).
:param ssl_context: (optional) A class with custom certificate settings.
If not provided then hyper's default ``SSLContext`` is used instead.
:param proxy_host: (optional) The proxy to connect to. This can be an IP address
or a host name and may include a port.
:param proxy_host: (optional) The proxy to connect to. This can be an IP
address or a host name and may include a port.
:param proxy_port: (optional) The proxy port to connect to. If not provided
and one also isn't provided in the ``proxy`` parameter, defaults to 8080.
and one also isn't provided in the ``proxy`` parameter, defaults to
8080.
"""
def __init__(self,
host,
Expand Down
4 changes: 4 additions & 0 deletions hyper/common/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
Contains hyper's exceptions.
"""


class ChunkedDecodeError(Exception):
"""
An error was encountered while decoding a chunked response.
Expand Down Expand Up @@ -43,6 +45,7 @@ class ConnectionResetError(Exception):
A HTTP connection was unexpectedly reset.
"""


class TLSUpgrade(Exception):
"""
We upgraded to a new protocol in the NPN/ALPN handshake.
Expand All @@ -52,6 +55,7 @@ def __init__(self, negotiated, sock):
self.negotiated = negotiated
self.sock = sock


class HTTPUpgrade(Exception):
"""
We upgraded to a new protocol via the HTTP Upgrade response.
Expand Down
1 change: 0 additions & 1 deletion hyper/common/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from hyper.compat import unicode, bytes, imap
from ..packages.rfc3986.uri import URIReference
from ..compat import is_py3
import re


def to_bytestring(element):
Expand Down
4 changes: 3 additions & 1 deletion hyper/compat.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-
# flake8: noqa
"""
hyper/compat
~~~~~~~~~
~~~~~~~~~~~~
Normalizes the Python 2/3 API for internal use.
"""
Expand All @@ -21,6 +22,7 @@
is_py3 = _ver[0] == 3
is_py3_3 = is_py3 and _ver[1] == 3


@contextmanager
def ignore_missing():
try:
Expand Down
1 change: 0 additions & 1 deletion hyper/contrib.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ def get_all(self, name, default=None):
def getheaders(self, name):
return self.get_all(name, [])


response.raw._original_response = orig = FakeOriginalResponse(None)
orig.version = 20
orig.status = resp.status
Expand Down
84 changes: 57 additions & 27 deletions hyper/http11/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ class HTTP11Connection(object):
:param host: The host to connect to. This may be an IP address or a
hostname, and optionally may include a port: for example,
``'twitter.com'``, ``'twitter.com:443'`` or ``'127.0.0.1'``.
:param port: (optional) The port to connect to. If not provided and one also
isn't provided in the ``host`` parameter, defaults to 80.
:param port: (optional) The port to connect to. If not provided and one
also isn't provided in the ``host`` parameter, defaults to 80.
:param secure: (optional) Whether the request should use TLS. Defaults to
``False`` for most requests, but to ``True`` for any request issued to
port 443.
Expand Down Expand Up @@ -82,7 +82,9 @@ def __init__(self, host, port=None, secure=None, ssl_context=None,
# Setup proxy details if applicable.
if proxy_host:
if proxy_port is None:
self.proxy_host, self.proxy_port = to_host_port_tuple(proxy_host, default_port=8080)
self.proxy_host, self.proxy_port = to_host_port_tuple(
proxy_host, default_port=8080
)
else:
self.proxy_host, self.proxy_port = proxy_host, proxy_port
else:
Expand Down Expand Up @@ -118,7 +120,7 @@ def connect(self):
proto = None

if self.secure:
assert not self.proxy_host, "Using a proxy with HTTPS not yet supported."
assert not self.proxy_host, "Proxy with HTTPS not supported."
sock, proto = wrap_socket(sock, host, self.ssl_context)

log.debug("Selected protocol: %s", proto)
Expand All @@ -142,8 +144,8 @@ def request(self, method, url, body=None, headers=None):
:param method: The request method, e.g. ``'GET'``.
:param url: The URL to contact, e.g. ``'/path/segment'``.
:param body: (optional) The request body to send. Must be a bytestring, an iterable of bytestring
or a file-like object.
:param body: (optional) The request body to send. Must be a bytestring,
an iterable of bytestring, or a file-like object.
:param headers: (optional) The headers to send on the request.
:returns: Nothing.
"""
Expand All @@ -159,7 +161,9 @@ def request(self, method, url, body=None, headers=None):
elif isinstance(headers, Iterable):
headers = HTTPHeaderMap(headers)
else:
raise ValueError('Header argument must be a dictionary or an iterable')
raise ValueError(
'Header argument must be a dictionary or an iterable'
)

if self._sock is None:
self.connect()
Expand Down Expand Up @@ -205,8 +209,8 @@ def get_response(self):
self._sock.advance_buffer(response.consumed)

if (response.status == 101 and
b'upgrade' in headers['connection'] and
H2C_PROTOCOL.encode('utf-8') in headers['upgrade']):
b'upgrade' in headers['connection'] and
H2C_PROTOCOL.encode('utf-8') in headers['upgrade']):
raise HTTPUpgrade(H2C_PROTOCOL, self._sock)

return HTTP11Response(
Expand Down Expand Up @@ -265,10 +269,13 @@ def _add_upgrade_headers(self, headers):
headers[b'connection'] = b'Upgrade, HTTP2-Settings'
headers[b'upgrade'] = H2C_PROTOCOL

# Encode SETTINGS frame payload in Base64 and put into the HTTP-2 Settings header.
# Encode SETTINGS frame payload in Base64 and put into the HTTP-2
# Settings header.
http2_settings = SettingsFrame(0)
http2_settings.settings[SettingsFrame.INITIAL_WINDOW_SIZE] = 65535
encoded_settings = base64.urlsafe_b64encode(http2_settings.serialize_body())
encoded_settings = base64.urlsafe_b64encode(
http2_settings.serialize_body()
)
headers[b'HTTP2-Settings'] = encoded_settings.rstrip(b'=')

def _send_body(self, body, body_type):
Expand All @@ -279,17 +286,7 @@ def _send_body(self, body, body_type):
if body_type == BODY_FLAT:
# Special case for files and other 'readable' objects.
if hasattr(body, 'read'):
while True:
block = body.read(16*1024)
if not block:
break

try:
self._sock.send(block)
except TypeError:
raise ValueError("File-like bodies must return bytestrings. Got: {}".format(type(block)))

return
return self._send_file_like_obj(body)

# Case for bytestrings.
elif isinstance(body, bytes):
Expand All @@ -303,14 +300,26 @@ def _send_body(self, body, body_type):
try:
self._sock.send(item)
except TypeError:
raise ValueError("Elements in iterable body must be bytestrings. "
"Illegal element: {}".format(item))
raise ValueError(
"Elements in iterable body must be bytestrings. "
"Illegal element: {}".format(item)
)
return

else:
raise ValueError('Request body must be a bytestring, a file-like object returning bytestrings '
'or an iterable of bytestrings. Got: {}'.format(type(body)))
raise ValueError(
'Request body must be a bytestring, a file-like object '
'returning bytestrings or an iterable of bytestrings. '
'Got: {}'.format(type(body))
)

# Chunked!
return self._send_chunked(body)

def _send_chunked(self, body):
"""
Handles the HTTP/1.1 logic for sending a chunk-encoded body.
"""
# Chunked! For chunked bodies we don't special-case, we just iterate
# over what we have and send stuff out.
for chunk in body:
Expand All @@ -324,11 +333,32 @@ def _send_body(self, body, body_type):
self._sock.send(chunk)
self._sock.send(b'\r\n')
except TypeError:
raise ValueError("Iterable bodies must always iterate in bytestrings")
raise ValueError(
"Iterable bodies must always iterate in bytestrings"
)

self._sock.send(b'0\r\n\r\n')
return

def _send_file_like_obj(self, fobj):
"""
Handles streaming a file-like object to the network.
"""
while True:
block = fobj.read(16*1024)
if not block:
break

try:
self._sock.send(block)
except TypeError:
raise ValueError(
"File-like bodies must return bytestrings. Got: "
"{}".format(type(block))
)

return

def close(self):
"""
Closes the connection. This closes the socket and then abandons the
Expand Down

0 comments on commit 11e0f2a

Please sign in to comment.