diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a68020af..11d86db0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,9 +9,9 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Set up Python 3.7 - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: 3.7 - name: Install dependencies @@ -30,9 +30,9 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Set up Python 3.7 - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: 3.7 - name: Install dependencies @@ -46,9 +46,9 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Set up Python 3.7 - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: 3.7 - name: Install dependencies @@ -57,24 +57,55 @@ jobs: - name: Build the docs run: nox -s docs + ubuntu: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + python-version: [3.5, 3.6, 3.7, 3.8] + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + - name: Set Up Python 3.7 to run nox + uses: actions/setup-python@v2 + with: + python-version: 3.7 + - name: Set Up Python - ${{ matrix.python-version }} + if: matrix.python_version != '3.7' + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install Dependencies + run: | + python3.7 -m pip install nox unasync + - name: Run Tests + run: | + nox -s test-${{ matrix.python-version }} + - name: Upload Coverage + run: ./ci/upload_coverage.sh + env: + JOB_NAME: "ubuntu (${{ matrix.python-version }})" + macOS: runs-on: macos-latest - + strategy: fail-fast: false matrix: - python-version: [2.7, 3.5, 3.6, 3.7, 3.8] + python-version: [3.5, 3.6, 3.7, 3.8] steps: - name: Checkout Repository - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Set Up Python 3.7 to run nox - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: 3.7 - name: Set Up Python - ${{ matrix.python-version }} if: matrix.python_version != '3.7' - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install Dependencies @@ -86,26 +117,26 @@ jobs: - name: Upload Coverage run: ./ci/upload_coverage.sh env: - JOB_NAME: 'macOS (${{ matrix.python-version }})' + JOB_NAME: "macOS (${{ matrix.python-version }})" Windows: runs-on: windows-latest - + strategy: fail-fast: false matrix: - python-version: [2.7, 3.5, 3.6, 3.7, 3.8] + python-version: [3.5, 3.6, 3.7, 3.8] steps: - name: Checkout Repository - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Set Up Python 3.7 to run nox - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: 3.7 - name: Set Up Python - ${{ matrix.python-version }} if: matrix.python_version != '3.7' - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies (Windows) @@ -120,4 +151,4 @@ jobs: run: ./ci/upload_coverage.sh shell: bash env: - JOB_NAME: 'Windows (${{ matrix.python-version }})' + JOB_NAME: "Windows (${{ matrix.python-version }})" diff --git a/.travis.yml b/.travis.yml index 38283e91..ebef8185 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,8 +31,6 @@ env: jobs: include: # Unit tests - - python: 2.7 - env: NOX_SESSION=test-2.7 - python: 3.5 env: NOX_SESSION=test-3.5 - python: 3.6 diff --git a/dummyserver/handlers.py b/dummyserver/handlers.py index 06ad3a0f..54ff24d6 100644 --- a/dummyserver/handlers.py +++ b/dummyserver/handlers.py @@ -252,7 +252,7 @@ def headers(self, request): return Response(json.dumps(dict(request.headers))) def successful_retry(self, request): - """ Handler which will return an error and then success + """Handler which will return an error and then success It's not currently very flexible as the number of retries is hard-coded. """ diff --git a/dummyserver/testcase.py b/dummyserver/testcase.py index cc609d98..12dda006 100644 --- a/dummyserver/testcase.py +++ b/dummyserver/testcase.py @@ -112,7 +112,7 @@ def _start_server(cls, socket_handler): class HTTPDummyServerTestCase(object): - """ A simple HTTP server that runs when your test class runs + """A simple HTTP server that runs when your test class runs Have your test class inherit from this one, and then a simple server will start when your tests run, and automatically shut down when they diff --git a/noxfile.py b/noxfile.py index c009da00..f19c3b8f 100644 --- a/noxfile.py +++ b/noxfile.py @@ -61,7 +61,7 @@ def tests_impl(session, extras="socks,brotli"): _clean_coverage("coverage.xml") -@nox.session(python=["2.7", "3.5", "3.6", "3.7", "3.8", "pypy", "pypy3"]) +@nox.session(python=["3.5", "3.6", "3.7", "3.8", "3.9", "pypy", "pypy3"]) def test(session): tests_impl(session) diff --git a/src/ahip/_collections.py b/src/ahip/_collections.py index 4d013e05..41334187 100644 --- a/src/ahip/_collections.py +++ b/src/ahip/_collections.py @@ -189,7 +189,7 @@ def __iter__(self): def pop(self, key, default=__marker): """D.pop(k[,d]) -> v, remove specified key and return the corresponding value. - If key is not found, d is returned if given, otherwise KeyError is raised. + If key is not found, d is returned if given, otherwise KeyError is raised. """ # Using the MutableMapping function directly fails due to the private marker. # Using ordinary dict.pop would expose the internal structures. diff --git a/src/ahip/exceptions.py b/src/ahip/exceptions.py index 3f770004..58829eac 100644 --- a/src/ahip/exceptions.py +++ b/src/ahip/exceptions.py @@ -89,7 +89,7 @@ class TimeoutStateError(HTTPError): class TimeoutError(HTTPError): - """ Raised when a socket timeout error occurs. + """Raised when a socket timeout error occurs. Catching this error will catch both :exc:`ReadTimeoutErrors ` and :exc:`ConnectTimeoutErrors `. diff --git a/src/ahip/util/retry.py b/src/ahip/util/retry.py index 2924d22b..feb4e594 100644 --- a/src/ahip/util/retry.py +++ b/src/ahip/util/retry.py @@ -27,7 +27,7 @@ class Retry(object): - """ Retry configuration. + """Retry configuration. Each retry attempt will create a new Retry object with updated values, so they can be safely reused. @@ -230,7 +230,7 @@ def from_int(cls, retries, redirect=True, default=None): return new_retries def get_backoff_time(self): - """ Formula for computing the current backoff + """Formula for computing the current backoff :rtype: float """ @@ -287,7 +287,7 @@ def _sleep_backoff(self): time.sleep(backoff) def sleep(self, response=None): - """ Sleep between retry attempts. + """Sleep between retry attempts. This method will respect a server's ``Retry-After`` response header and sleep the duration of the time requested. If that is not present, it @@ -303,19 +303,19 @@ def sleep(self, response=None): self._sleep_backoff() def _is_connection_error(self, err): - """ Errors when we're fairly sure that the server did not receive the + """Errors when we're fairly sure that the server did not receive the request, so it should be safe to retry. """ return isinstance(err, ConnectTimeoutError) def _is_read_error(self, err): - """ Errors that occur after the request has been started, so we should + """Errors that occur after the request has been started, so we should assume that the server began processing it. """ return isinstance(err, (ReadTimeoutError, ProtocolError)) def _is_method_retryable(self, method): - """ Checks if a given HTTP method should be retried upon, depending if + """Checks if a given HTTP method should be retried upon, depending if it is included on the method whitelist. """ if self.method_whitelist and method.upper() not in self.method_whitelist: @@ -324,7 +324,7 @@ def _is_method_retryable(self, method): return True def is_retry(self, method, status_code, has_retry_after=False): - """ Is this method/status code retryable? (Based on whitelists and control + """Is this method/status code retryable? (Based on whitelists and control variables such as the number of total retries to allow, whether to respect the Retry-After header, whether this header is present, and whether the returned status code is on the list of status codes to @@ -361,7 +361,7 @@ def increment( _pool=None, _stacktrace=None, ): - """ Return a new Retry object with incremented retry counters. + """Return a new Retry object with incremented retry counters. :param response: A response object, or None, if the server did not return a response. diff --git a/src/ahip/util/timeout.py b/src/ahip/util/timeout.py index 856ea892..2e1d9770 100644 --- a/src/ahip/util/timeout.py +++ b/src/ahip/util/timeout.py @@ -16,7 +16,7 @@ class Timeout(object): - """ Timeout configuration. + """Timeout configuration. Timeouts can be defined as a default for a pool:: @@ -107,7 +107,7 @@ def __str__(self): @classmethod def _validate_timeout(cls, value, name): - """ Check that a timeout attribute is valid. + """Check that a timeout attribute is valid. :param value: The timeout value to validate :param name: The name of the timeout attribute to validate. This is @@ -153,7 +153,7 @@ def _validate_timeout(cls, value, name): @classmethod def from_float(cls, timeout): - """ Create a new Timeout from a legacy timeout value. + """Create a new Timeout from a legacy timeout value. The timeout value used by httplib.py sets the same timeout on the connect(), and recv() socket requests. This creates a :class:`Timeout` @@ -168,7 +168,7 @@ def from_float(cls, timeout): return Timeout(read=timeout, connect=timeout) def clone(self): - """ Create a copy of the timeout object + """Create a copy of the timeout object Timeout properties are stored per-pool but each request needs a fresh Timeout object to ensure each one has its own start/stop configured. @@ -182,7 +182,7 @@ def clone(self): return Timeout(connect=self._connect, read=self._read, total=self.total) def start_connect(self): - """ Start the timeout clock, used during a connect() attempt + """Start the timeout clock, used during a connect() attempt :raises hip.exceptions.TimeoutStateError: if you attempt to start a timer that has been started already. @@ -193,7 +193,7 @@ def start_connect(self): return self._start_connect def get_connect_duration(self): - """ Gets the time elapsed since the call to :meth:`start_connect`. + """Gets the time elapsed since the call to :meth:`start_connect`. :return: Elapsed time in seconds. :rtype: float @@ -208,7 +208,7 @@ def get_connect_duration(self): @property def connect_timeout(self): - """ Get the value to use when setting a connection timeout. + """Get the value to use when setting a connection timeout. This will be a positive float or integer, the value None (never timeout), or the default system timeout. @@ -226,7 +226,7 @@ def connect_timeout(self): @property def read_timeout(self): - """ Get the value for the read timeout. + """Get the value for the read timeout. This assumes some time has elapsed in the connection timeout and computes the read timeout appropriately. diff --git a/src/ahip/util/wait.py b/src/ahip/util/wait.py index fafda669..cb12b70e 100644 --- a/src/ahip/util/wait.py +++ b/src/ahip/util/wait.py @@ -138,14 +138,14 @@ def wait_for_socket(*args, **kwargs): def wait_for_read(sock, timeout=None): - """ Waits for reading to be available on a given socket. + """Waits for reading to be available on a given socket. Returns True if the socket is readable, or False if the timeout expired. """ return wait_for_socket(sock, read=True, timeout=timeout) def wait_for_write(sock, timeout=None): - """ Waits for writing to be available on a given socket. + """Waits for writing to be available on a given socket. Returns True if the socket is readable, or False if the timeout expired. """ return wait_for_socket(sock, write=True, timeout=timeout)