diff --git a/.github/workflows/style.yaml b/.github/workflows/style.yaml index d3f6384f8..59fd1c95a 100644 --- a/.github/workflows/style.yaml +++ b/.github/workflows/style.yaml @@ -37,4 +37,6 @@ jobs: - name: install tox run: pip install tox - name: run tests - run: tox --verbose -e pep8 + run: | + tox --verbose -e pep8 + tox --verbose -e lint diff --git a/.gitignore b/.gitignore index a90ba86f5..fc2a632f8 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ dist/ doc/changelog.rst venv* website-build/ +.ruff_cache/ # auto-generated by hatch eventlet/_version.py diff --git a/eventlet/backdoor.py b/eventlet/backdoor.py index c72ac1e87..3f3887fce 100644 --- a/eventlet/backdoor.py +++ b/eventlet/backdoor.py @@ -2,8 +2,6 @@ import errno import socket import sys -import errno -import traceback import eventlet from eventlet import hubs diff --git a/eventlet/greenio/py2.py b/eventlet/greenio/py2.py deleted file mode 100644 index a6fdca774..000000000 --- a/eventlet/greenio/py2.py +++ /dev/null @@ -1,229 +0,0 @@ -import errno -import os - -from eventlet.greenio.base import ( - _operation_on_closed_file, - greenpipe_doc, - set_nonblocking, - socket, - SOCKET_BLOCKING, -) -from eventlet.hubs import trampoline, notify_close, notify_opened, IOClosed -from eventlet.support import get_errno - -__all__ = ['_fileobject', 'GreenPipe'] - -_fileobject = socket._fileobject - - -class GreenPipe(_fileobject): - - __doc__ = greenpipe_doc - - def __init__(self, f, mode='r', bufsize=-1): - if not isinstance(f, (str,) + (int, file)): - raise TypeError('f(ile) should be int, str, unicode or file, not %r' % f) - - if isinstance(f, str): - f = open(f, mode, 0) - - if isinstance(f, int): - fileno = f - self._name = "" % fileno - else: - fileno = os.dup(f.fileno()) - self._name = f.name - if f.mode != mode: - raise ValueError('file.mode %r does not match mode parameter %r' % (f.mode, mode)) - self._name = f.name - f.close() - - super().__init__(_SocketDuckForFd(fileno), mode, bufsize) - set_nonblocking(self) - self.softspace = 0 - - @property - def name(self): - return self._name - - def __repr__(self): - return "<%s %s %r, mode %r at 0x%x>" % ( - self.closed and 'closed' or 'open', - self.__class__.__name__, - self.name, - self.mode, - (id(self) < 0) and (sys.maxint + id(self)) or id(self)) - - def close(self): - super().close() - for method in [ - 'fileno', 'flush', 'isatty', 'next', 'read', 'readinto', - 'readline', 'readlines', 'seek', 'tell', 'truncate', - 'write', 'xreadlines', '__iter__', '__next__', 'writelines']: - setattr(self, method, _operation_on_closed_file) - - def __enter__(self): - return self - - def __exit__(self, *args): - self.close() - - def _get_readahead_len(self): - return len(self._rbuf.getvalue()) - - def _clear_readahead_buf(self): - len = self._get_readahead_len() - if len > 0: - self.read(len) - - def tell(self): - self.flush() - try: - return os.lseek(self.fileno(), 0, 1) - self._get_readahead_len() - except OSError as e: - raise OSError(*e.args) - - def seek(self, offset, whence=0): - self.flush() - if whence == 1 and offset == 0: # tell synonym - return self.tell() - if whence == 1: # adjust offset by what is read ahead - offset -= self._get_readahead_len() - try: - rv = os.lseek(self.fileno(), offset, whence) - except OSError as e: - raise OSError(*e.args) - else: - self._clear_readahead_buf() - return rv - - if getattr(file, "truncate", None): # not all OSes implement truncate - def truncate(self, size=-1): - self.flush() - if size == -1: - size = self.tell() - try: - rv = os.ftruncate(self.fileno(), size) - except OSError as e: - raise OSError(*e.args) - else: - self.seek(size) # move position&clear buffer - return rv - - def isatty(self): - try: - return os.isatty(self.fileno()) - except OSError as e: - raise OSError(*e.args) - - -class _SocketDuckForFd: - """Class implementing all socket method used by _fileobject - in cooperative manner using low level os I/O calls. - """ - _refcount = 0 - - def __init__(self, fileno): - self._fileno = fileno - notify_opened(fileno) - self._closed = False - - def _trampoline(self, fd, read=False, write=False, timeout=None, timeout_exc=None): - if self._closed: - # Don't trampoline if we're already closed. - raise IOClosed() - try: - return trampoline(fd, read=read, write=write, timeout=timeout, - timeout_exc=timeout_exc, - mark_as_closed=self._mark_as_closed) - except IOClosed: - # Our fileno has been obsoleted. Defang ourselves to - # prevent spurious closes. - self._mark_as_closed() - raise - - def _mark_as_closed(self): - current = self._closed - self._closed = True - return current - - @property - def _sock(self): - return self - - def fileno(self): - return self._fileno - - def recv(self, buflen): - while True: - try: - data = os.read(self._fileno, buflen) - return data - except OSError as e: - if get_errno(e) not in SOCKET_BLOCKING: - raise OSError(*e.args) - self._trampoline(self, read=True) - - def recv_into(self, buf, nbytes=0, flags=0): - if nbytes == 0: - nbytes = len(buf) - data = self.recv(nbytes) - buf[:nbytes] = data - return len(data) - - def send(self, data): - while True: - try: - return os.write(self._fileno, data) - except OSError as e: - if get_errno(e) not in SOCKET_BLOCKING: - raise OSError(*e.args) - else: - trampoline(self, write=True) - - def sendall(self, data): - len_data = len(data) - os_write = os.write - fileno = self._fileno - try: - total_sent = os_write(fileno, data) - except OSError as e: - if get_errno(e) != errno.EAGAIN: - raise OSError(*e.args) - total_sent = 0 - while total_sent < len_data: - self._trampoline(self, write=True) - try: - total_sent += os_write(fileno, data[total_sent:]) - except OSError as e: - if get_errno(e) != errno. EAGAIN: - raise OSError(*e.args) - - def __del__(self): - self._close() - - def _close(self): - was_closed = self._mark_as_closed() - if was_closed: - return - if notify_close: - # If closing from __del__, notify_close may have - # already been cleaned up and set to None - notify_close(self._fileno) - try: - os.close(self._fileno) - except: - # os.close may fail if __init__ didn't complete - # (i.e file dscriptor passed to popen was invalid - pass - - def __repr__(self): - return "%s:%d" % (self.__class__.__name__, self._fileno) - - def _reuse(self): - self._refcount += 1 - - def _drop(self): - self._refcount -= 1 - if self._refcount == 0: - self._close() diff --git a/eventlet/patcher.py b/eventlet/patcher.py index 366de161d..660866131 100644 --- a/eventlet/patcher.py +++ b/eventlet/patcher.py @@ -265,7 +265,7 @@ def monkey_patch(**on): raise TypeError("monkey_patch() got an unexpected " "keyword argument %r" % k) if default_on is None: - default_on = not (True in on.values()) + default_on = True not in on.values() for modname in accepted_args: if modname == 'MySQLdb': # MySQLdb is only on when explicitly patched for the moment diff --git a/eventlet/zipkin/api.py b/eventlet/zipkin/api.py index 8a33a4b2b..8edde5c61 100644 --- a/eventlet/zipkin/api.py +++ b/eventlet/zipkin/api.py @@ -155,10 +155,11 @@ def build_span(name, trace_id, span_id, parent_id, @staticmethod def build_annotation(value, endpoint=None): - if isinstance(value, unicode): + if isinstance(value, str): value = value.encode('utf-8') + assert isinstance(value, bytes) return ttypes.Annotation(time.time() * 1000 * 1000, - str(value), endpoint) + value, endpoint) @staticmethod def build_binary_annotation(key, value, endpoint=None): diff --git a/pyproject.toml b/pyproject.toml index 6f152287b..29beb5c01 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,3 +61,25 @@ version.source = "vcs" [tool.hatch.build.hooks.vcs] version-file = "eventlet/_version.py" + +[tool.ruff] +# Might eventually want to add evenetlet/green/, but it's a pain... +exclude = ["eventlet/green/", "eventlet/zipkin/_thrift", "tests/mock.py", "doc/"] +line-length = 123 + +[tool.ruff.lint] +# Too many to fix as first pass, but should perhaps go back and fix these: +ignore = [ + # Ambiguous variable name + "E741", + # Local variable assigned but unused + "F841", + # Imported but unused + "F401", + # Bare except: + "E722", + # Module-level import not at top of file + "E402", + # Using a lambda expression with a name instead of just def + "E731", +] diff --git a/tests/greenio_test.py b/tests/greenio_test.py index 36d0030a0..ce87cf54e 100644 --- a/tests/greenio_test.py +++ b/tests/greenio_test.py @@ -84,7 +84,7 @@ def test_connect_timeout(self): expect_socket_timeout(gs.connect, ('192.0.2.1', 80)) except OSError as e: # unreachable is also a valid outcome - if not get_errno(e) in (errno.EHOSTUNREACH, errno.ENETUNREACH): + if get_errno(e) not in (errno.EHOSTUNREACH, errno.ENETUNREACH): raise def test_accept_timeout(self): diff --git a/tests/greenpool_test.py b/tests/greenpool_test.py index 6ff9aa0c9..7d0207411 100644 --- a/tests/greenpool_test.py +++ b/tests/greenpool_test.py @@ -7,11 +7,6 @@ import tests -def passthru(a): - eventlet.sleep(0.01) - return a - - def passthru2(a, b): eventlet.sleep(0.01) return a, b diff --git a/tests/isolated/patcher_builtin.py b/tests/isolated/patcher_builtin.py index 56b2dbe21..c0c002186 100644 --- a/tests/isolated/patcher_builtin.py +++ b/tests/isolated/patcher_builtin.py @@ -1,14 +1,10 @@ if __name__ == '__main__': from tests.mock import patch - import sys import eventlet from eventlet import hubs with patch.object(hubs, 'notify_opened') as mock_func: eventlet.monkey_patch(builtins=True) with open(__file__) as f: mock_func.assert_called_with(f.fileno()) - if sys.version_info.major == 2: - with file(__file__, 'r') as f: - mock_func.assert_called_with(f.fileno()) print('pass') diff --git a/tests/parse_results.py b/tests/parse_results.py index d865d10cf..ba6a960d4 100644 --- a/tests/parse_results.py +++ b/tests/parse_results.py @@ -111,4 +111,4 @@ def main(db): sys.argv.append(latest_db) for db in sys.argv[1:]: main(db) - execfile('generate_report.py') + exec(open('generate_report.py').read()) diff --git a/tests/ssl_test.py b/tests/ssl_test.py index 1ce338ca7..56bf7b27b 100644 --- a/tests/ssl_test.py +++ b/tests/ssl_test.py @@ -1,6 +1,4 @@ -import contextlib import random -import socket import sys import warnings diff --git a/tox.ini b/tox.ini index 06f0b5b82..debe7dcc5 100644 --- a/tox.ini +++ b/tox.ini @@ -1,10 +1,5 @@ # The flake8 and pep8 sections just contain configuration for corresponding tools. # Checkers are not run implicitly. -[flake8] -exclude = *.egg*,.env,.git,.hg,.tox,_*,build*,dist*,venv*,mock.py,eventlet/green/http/* -ignore = E261,E402,E731,W503 -max-line-length = 123 - [pycodestyle] count = 1 exclude = *.egg*,.env,.git,.hg,.tox,_*,build*,dist*,venv*,mock.py,eventlet/green/http/* @@ -49,6 +44,15 @@ usedevelop = False commands = pycodestyle benchmarks/ eventlet/ tests/ +[testenv:lint] +basepython = python3 +setenv = + {[testenv]setenv} +deps = + ruff==0.1.13 +commands = + ruff eventlet/ tests/ + [testenv] passenv = CI