diff --git a/.pylintrc b/.pylintrc index af99b3e1..bc2046c0 100644 --- a/.pylintrc +++ b/.pylintrc @@ -12,7 +12,6 @@ ignore= disable= attribute-defined-outside-init, - bad-continuation, bad-mcs-classmethod-argument, bare-except, broad-except, @@ -25,12 +24,10 @@ disable= import-self, inconsistent-return-statements, invalid-name, - misplaced-comparison-constant, missing-docstring, no-else-return, no-member, no-self-argument, - no-self-use, no-staticmethod-decorator, not-callable, protected-access, @@ -53,3 +50,6 @@ disable= useless-import-alias, comparison-with-callable, try-except-raise, + consider-using-with, + consider-using-f-string, + unspecified-encoding diff --git a/gunicorn/config.py b/gunicorn/config.py index 97c12588..84e7619e 100644 --- a/gunicorn/config.py +++ b/gunicorn/config.py @@ -1510,7 +1510,8 @@ class LogConfigDict(Setting): Format: https://docs.python.org/3/library/logging.config.html#logging.config.dictConfig - For more context you can look at the default configuration dictionary for logging, which can be found at ``gunicorn.glogging.CONFIG_DEFAULTS``. + For more context you can look at the default configuration dictionary for logging, + which can be found at ``gunicorn.glogging.CONFIG_DEFAULTS``. .. versionadded:: 19.8 """ @@ -1993,6 +1994,7 @@ class OnExit(Setting): The callable needs to accept a single instance variable for the Arbiter. """ + class NewSSLContext(Setting): name = "ssl_context" section = "Server Hooks" @@ -2027,6 +2029,7 @@ class NewSSLContext(Setting): .. versionadded:: 20.2 """ + class ProxyProtocol(Setting): name = "proxy_protocol" section = "Server Mechanics" diff --git a/gunicorn/glogging.py b/gunicorn/glogging.py index e5cda196..b552e26a 100644 --- a/gunicorn/glogging.py +++ b/gunicorn/glogging.py @@ -45,12 +45,11 @@ SYSLOG_FACILITIES = { "local7": 23 } -CONFIG_DEFAULTS = dict( - version=1, - disable_existing_loggers=False, - - root={"level": "INFO", "handlers": ["console"]}, - loggers={ +CONFIG_DEFAULTS = { + "version": 1, + "disable_existing_loggers": False, + "root": {"level": "INFO", "handlers": ["console"]}, + "loggers": { "gunicorn.error": { "level": "INFO", "handlers": ["error_console"], @@ -65,7 +64,7 @@ CONFIG_DEFAULTS = dict( "qualname": "gunicorn.access" } }, - handlers={ + "handlers": { "console": { "class": "logging.StreamHandler", "formatter": "generic", @@ -77,14 +76,14 @@ CONFIG_DEFAULTS = dict( "stream": "ext://sys.stderr" }, }, - formatters={ + "formatters": { "generic": { "format": "%(asctime)s [%(process)d] [%(levelname)s] %(message)s", "datefmt": "[%Y-%m-%d %H:%M:%S %z]", "class": "logging.Formatter" } } -) +} def loggers(): @@ -418,7 +417,7 @@ class Logger(object): if output == "-": h = logging.StreamHandler(stream) else: - util.check_is_writeable(output) + util.check_is_writable(output) h = logging.FileHandler(output) # make sure the user can reopen the file try: diff --git a/gunicorn/http/wsgi.py b/gunicorn/http/wsgi.py index 5d91706c..25715eab 100644 --- a/gunicorn/http/wsgi.py +++ b/gunicorn/http/wsgi.py @@ -12,7 +12,7 @@ import sys from gunicorn.http.message import HEADER_RE from gunicorn.http.errors import InvalidHeader, InvalidHeaderName from gunicorn import SERVER_SOFTWARE, SERVER -import gunicorn.util as util +from gunicorn import util # Send files in at most 1GB blocks as some operating systems can have problems # with sending files in blocks over 2GB. diff --git a/gunicorn/sock.py b/gunicorn/sock.py index 22e25b33..7700146a 100644 --- a/gunicorn/sock.py +++ b/gunicorn/sock.py @@ -204,6 +204,7 @@ def create_sockets(conf, log, fds=None): return listeners + def close_sockets(listeners, unlink=True): for sock in listeners: sock_name = sock.getsockname() @@ -211,6 +212,7 @@ def close_sockets(listeners, unlink=True): if unlink and _sock_type(sock_name) is UnixSocket: os.unlink(sock_name) + def ssl_context(conf): def default_ssl_context_factory(): context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile=conf.ca_certs) @@ -222,7 +224,9 @@ def ssl_context(conf): return conf.ssl_context(conf, default_ssl_context_factory) + def ssl_wrap_socket(sock, conf): - return ssl_context(conf).wrap_socket(sock, server_side=True, - suppress_ragged_eofs=conf.suppress_ragged_eofs, - do_handshake_on_connect=conf.do_handshake_on_connect) + return ssl_context(conf).wrap_socket(sock, + server_side=True, + suppress_ragged_eofs=conf.suppress_ragged_eofs, + do_handshake_on_connect=conf.do_handshake_on_connect) diff --git a/gunicorn/util.py b/gunicorn/util.py index b4a2d6ee..1b39ba73 100644 --- a/gunicorn/util.py +++ b/gunicorn/util.py @@ -562,12 +562,12 @@ def seed(): random.seed('%s.%s' % (time.time(), os.getpid())) -def check_is_writeable(path): +def check_is_writable(path): try: - f = open(path, 'a') + with open(path, 'a') as f: + f.close() except IOError as e: raise RuntimeError("Error: '%s' isn't writable [%r]" % (path, e)) - f.close() def to_bytestring(value, encoding="utf8"): diff --git a/gunicorn/workers/base_async.py b/gunicorn/workers/base_async.py index ec5d7644..b059a7cb 100644 --- a/gunicorn/workers/base_async.py +++ b/gunicorn/workers/base_async.py @@ -9,10 +9,10 @@ import socket import ssl import sys -import gunicorn.http as http -import gunicorn.http.wsgi as wsgi -import gunicorn.util as util -import gunicorn.workers.base as base +from gunicorn import http +from gunicorn.http import wsgi +from gunicorn import util +from gunicorn.workers import base ALREADY_HANDLED = object() diff --git a/gunicorn/workers/geventlet.py b/gunicorn/workers/geventlet.py index 64595b53..c42ed118 100644 --- a/gunicorn/workers/geventlet.py +++ b/gunicorn/workers/geventlet.py @@ -173,6 +173,7 @@ class EventletWorker(AsyncWorker): eventlet.sleep(1.0) self.notify() + t = None try: with eventlet.Timeout(self.cfg.graceful_timeout) as t: for a in acceptors: diff --git a/gunicorn/workers/ggevent.py b/gunicorn/workers/ggevent.py index 9ece3b60..2125a32d 100644 --- a/gunicorn/workers/ggevent.py +++ b/gunicorn/workers/ggevent.py @@ -59,7 +59,7 @@ class GeventWorker(AsyncWorker): ssl_args = {} if self.cfg.is_ssl: - ssl_args = dict(ssl_context=ssl_context(self.cfg)) + ssl_args = {"ssl_context": ssl_context(self.cfg)} for s in self.sockets: s.setblocking(1) diff --git a/gunicorn/workers/gthread.py b/gunicorn/workers/gthread.py index 9a6ad006..fb37fd3f 100644 --- a/gunicorn/workers/gthread.py +++ b/gunicorn/workers/gthread.py @@ -11,7 +11,7 @@ # closed. # pylint: disable=no-else-break -import concurrent.futures as futures +from concurrent import futures import errno import os import selectors @@ -124,7 +124,7 @@ class ThreadWorker(base.Worker): conn = TConn(self.cfg, sock, client, server) # set timeout to ensure it will not be in the loop too long conn.set_timeout() - + self.nr_conns += 1 # wait until socket is readable with self._lock: diff --git a/gunicorn/workers/gtornado.py b/gunicorn/workers/gtornado.py index 9f593753..28506119 100644 --- a/gunicorn/workers/gtornado.py +++ b/gunicorn/workers/gtornado.py @@ -3,7 +3,6 @@ # This file is part of gunicorn released under the MIT license. # See the NOTICE for more information. -import copy import os import sys @@ -112,7 +111,7 @@ class TornadoWorker(Worker): isinstance(app, tornado.wsgi.WSGIApplication): app = WSGIContainer(app) elif not isinstance(app, WSGIContainer) and \ - not isinstance(app, tornado.web.Application): + not isinstance(app, tornado.web.Application): app = WSGIContainer(app) # Monkey-patching HTTPConnection.finish to count the diff --git a/gunicorn/workers/sync.py b/gunicorn/workers/sync.py index d68d15cb..39a209f0 100644 --- a/gunicorn/workers/sync.py +++ b/gunicorn/workers/sync.py @@ -12,11 +12,11 @@ import socket import ssl import sys -import gunicorn.http as http -import gunicorn.http.wsgi as wsgi -import gunicorn.sock as sock -import gunicorn.util as util -import gunicorn.workers.base as base +from gunicorn import http +from gunicorn.http import wsgi +from gunicorn import sock +from gunicorn import util +from gunicorn.workers import base class StopWaiting(Exception): diff --git a/tests/test_arbiter.py b/tests/test_arbiter.py index dc059edb..e856282c 100644 --- a/tests/test_arbiter.py +++ b/tests/test_arbiter.py @@ -4,7 +4,7 @@ # See the NOTICE for more information. import os -import unittest.mock as mock +from unittest import mock import gunicorn.app.base import gunicorn.arbiter diff --git a/tests/test_http.py b/tests/test_http.py index 33481266..b6ca46b2 100644 --- a/tests/test_http.py +++ b/tests/test_http.py @@ -3,7 +3,7 @@ import io import t import pytest -import unittest.mock as mock +from unittest import mock from gunicorn import util from gunicorn.http.body import Body, LengthReader, EOFReader diff --git a/tests/test_pidfile.py b/tests/test_pidfile.py index fdcd0a24..ecbc052f 100644 --- a/tests/test_pidfile.py +++ b/tests/test_pidfile.py @@ -4,7 +4,7 @@ # See the NOTICE for more information. import errno -import unittest.mock as mock +from unittest import mock import gunicorn.pidfile diff --git a/tests/test_sock.py b/tests/test_sock.py index 36205d84..adc348c6 100644 --- a/tests/test_sock.py +++ b/tests/test_sock.py @@ -3,7 +3,7 @@ # This file is part of gunicorn released under the MIT license. # See the NOTICE for more information. -import unittest.mock as mock +from unittest import mock from gunicorn import sock diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 7d15de17..a31c1fe0 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -8,7 +8,7 @@ import pytest from gunicorn.config import ( - KeyFile, CertFile, SSLVersion, CACerts, SuppressRaggedEOFs, + KeyFile, CertFile, CACerts, SuppressRaggedEOFs, DoHandshakeOnConnect, Setting, Ciphers, ) diff --git a/tests/test_systemd.py b/tests/test_systemd.py index d2c78aa2..ff8b959a 100644 --- a/tests/test_systemd.py +++ b/tests/test_systemd.py @@ -5,7 +5,7 @@ from contextlib import contextmanager import os -import unittest.mock as mock +from unittest import mock import pytest diff --git a/tox.ini b/tox.ini index 64f58d66..080a43f5 100644 --- a/tox.ini +++ b/tox.ini @@ -12,6 +12,7 @@ deps = [testenv:lint] commands = pylint -j0 \ + --max-line-length=120 \ gunicorn \ tests/test_arbiter.py \ tests/test_config.py \ @@ -26,7 +27,7 @@ commands = tests/test_util.py \ tests/test_valid_requests.py deps = - pylint<2.7 + pylint=2.17.4 [testenv:docs-lint] allowlist_externals =