Skip to content

Commit

Permalink
remove until_not_interrupted() (#612)
Browse files Browse the repository at this point in the history
* remove until_not_interrupted

Retry is not needed since Python 3.5.
https://peps.python.org/pep-0475/

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
methane and pre-commit-ci[bot] authored Apr 2, 2024
1 parent 1456456 commit 5abf7b5
Show file tree
Hide file tree
Showing 4 changed files with 9 additions and 84 deletions.
12 changes: 5 additions & 7 deletions src/structlog/_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
from sys import stderr, stdout
from typing import IO, Any, BinaryIO, TextIO

from structlog._utils import until_not_interrupted


WRITE_LOCKS: dict[IO[Any], threading.Lock] = {}

Expand Down Expand Up @@ -109,7 +107,7 @@ def msg(self, message: str) -> None:
"""
f = self._file if self._file is not stdout else None
with self._lock:
until_not_interrupted(print, message, file=f, flush=True)
print(message, file=f, flush=True)

log = debug = info = warn = warning = msg
fatal = failure = err = error = critical = exception = msg
Expand Down Expand Up @@ -216,8 +214,8 @@ def msg(self, message: str) -> None:
Write and flush *message*.
"""
with self._lock:
until_not_interrupted(self._write, message + "\n")
until_not_interrupted(self._flush)
self._write(message + "\n")
self._flush()

log = debug = info = warn = warning = msg
fatal = failure = err = error = critical = exception = msg
Expand Down Expand Up @@ -320,8 +318,8 @@ def msg(self, message: bytes) -> None:
Write *message*.
"""
with self._lock:
until_not_interrupted(self._write, message + b"\n")
until_not_interrupted(self._flush)
self._write(message + b"\n")
self._flush()

log = debug = info = warn = warning = msg
fatal = failure = err = error = critical = exception = msg
Expand Down
31 changes: 1 addition & 30 deletions src/structlog/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,10 @@

from __future__ import annotations

import errno
import sys

from contextlib import suppress
from typing import Any, Callable, TypeVar


T = TypeVar("T")


def until_not_interrupted(
f: Callable[..., T], *args: object, **kw: object
) -> T:
"""
Retry until *f* succeeds or an exception that isn't caused by EINTR occurs.
Args:
f: A callable like a function.
*args: Positional arguments for *f*.
**kw: Keyword arguments for *f*.
Returns:
Whatever *f* returns.
"""
while True:
try:
return f(*args, **kw)
except OSError as e: # noqa: PERF203
if e.args[0] == errno.EINTR:
continue
raise
from typing import Any


def get_processname() -> str:
Expand Down
6 changes: 2 additions & 4 deletions src/structlog/twisted.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

from ._base import BoundLoggerBase
from ._config import _BUILTIN_DEFAULT_PROCESSORS
from ._utils import until_not_interrupted
from .processors import JSONRenderer as GenericJSONRenderer
from .typing import EventDict, WrappedLogger

Expand Down Expand Up @@ -215,12 +214,11 @@ def __init__(self, file: TextIO) -> None:
self._flush = file.flush

def __call__(self, eventDict: EventDict) -> None:
until_not_interrupted(
self._write,
self._write(
textFromEventDict(eventDict) # type: ignore[arg-type, operator]
+ "\n",
)
until_not_interrupted(self._flush)
self._flush()


@implementer(ILogObserver)
Expand Down
44 changes: 1 addition & 43 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,12 @@
# 2.0, and the MIT License. See the LICENSE file in the root of this
# repository for complete details.

import errno
import multiprocessing
import sys

import pytest

from pretend import raiser

from structlog._utils import get_processname, until_not_interrupted


class TestUntilNotInterrupted:
def test_passes_arguments_and_returns_return_value(self):
"""
until_not_interrupted() passes arguments to the wrapped function and
returns its return value.
"""

def returner(*args, **kw):
assert (42,) == args
assert {"x": 23} == kw

return "foo"

assert "foo" == until_not_interrupted(returner, 42, x=23)

def test_leaves_unrelated_exceptions_through(self):
"""
Exceptions that are not an EINTR OSError are not intercepted/retried.
"""
exc = IOError
with pytest.raises(exc):
until_not_interrupted(raiser(exc("not EINTR")))

def test_retries_on_EINTR(self):
"""
Wrapped functions that raise EINTR OSErrors are retried.
"""
calls = [0]

def raise_on_first_three():
if calls[0] < 3:
calls[0] += 1
raise OSError(errno.EINTR)

until_not_interrupted(raise_on_first_three)

assert 3 == calls[0]
from structlog._utils import get_processname


class TestGetProcessname:
Expand Down

0 comments on commit 5abf7b5

Please sign in to comment.