мой файл parametrized_deco

def format_kwargs(kwargs):
    return "{%s}" % ", ".join(
        f'"{key}": {repr(value)}' for key, value in kwargs.items()
    )


def format_args(args, kwargs):
    parts = []
    if args:
        parts.append(f"positional args = {args}")
    if kwargs:
        kwargs_str = format_kwargs(kwargs)
        parts.append(f"keyword kwargs = {kwargs_str}")
    return ", ".join(parts) if parts else "no arguments"


def retry_deco(amount_of_retries, exceptions=None):

    if amount_of_retries < 1:
        raise ValueError("amount_of_retries can not be less than 1")

    if exceptions is None:
        exceptions = ()
    elif not isinstance(exceptions, (list, tuple)):
        exceptions = (exceptions,)
    else:
        exceptions = tuple(exceptions)

    def deco(function):
        def wrapper(*args, **kwargs):
            arguments_str = format_args(args, kwargs)
            function_name = getattr(function, "__name__", "<unnamed>")
            for attempt in range(1, amount_of_retries + 1):
                try:
                    result = function(*args, **kwargs)
                    print(
                        f'run "{function.__name__}" with {arguments_str}, '
                        f"attempt = {attempt}, result = {result}"
                    )
                    return result
                except Exception as e:
                    print(
                        f'run "{function.__name__}" with {arguments_str}, '
                        f"attempt = {attempt}, "
                        f"exception = {type(e).__name__}: {e}"
                    )
                    if isinstance(e, exceptions):
                        raise e
                    if attempt == amount_of_retries:
                        raise e

        return wrapper

    return deco

мой файл с тестами

import unittest
from unittest.mock import patch
from parametrized_deco import retry_deco


class TestRetryDecorator(unittest.TestCase):

    @patch("builtins.print")
    def test_function_succeeds(self, mock_print):
        call_count = 0

        @retry_deco(3)
        def func():
            nonlocal call_count
            call_count += 1
            return "success"

        result = func()
        self.assertEqual(result, "success")
        self.assertEqual(call_count, 1)
        mock_print.assert_called_once_with(
            'run "func" with no arguments, attempt = 1, result = success'
        )

    @patch("builtins.print")
    def test_function_fails(self, mock_print):
        call_count = 0

        @retry_deco(3)
        def func():
            nonlocal call_count
            call_count += 1
            raise Exception("failure")

        with self.assertRaises(Exception) as context:
            func()

        self.assertEqual(str(context.exception), "failure")
        self.assertEqual(call_count, 3)
        self.assertEqual(mock_print.call_count, 3)
        expected_calls = [
            unittest.mock.call(
                'run "func" with no arguments, '
                "attempt = 1, "
                "exception = Exception: failure"
            ),
            unittest.mock.call(
                'run "func" with no arguments, '
                "attempt = 2, "
                "exception = Exception: failure"
            ),
            unittest.mock.call(
                'run "func" with no arguments, '
                "attempt = 3, "
                "exception = Exception: failure"
            ),
        ]
        mock_print.assert_has_calls(expected_calls)

    @patch("builtins.print")
    def test_function_succeeds_with_attempts(self, mock_print):
        call_count = 0

        @retry_deco(5)
        def func():
            nonlocal call_count
            call_count += 1
            if call_count < 3:
                raise Exception("failure")
            return "success"

        result = func()
        self.assertEqual(result, "success")
        self.assertEqual(call_count, 3)
        self.assertEqual(mock_print.call_count, 3)
        expected_calls = [
            unittest.mock.call(
                'run "func" with no arguments, '
                "attempt = 1, "
                "exception = Exception: failure"
            ),
            unittest.mock.call(
                'run "func" with no arguments, '
                "attempt = 2, "
                "exception = Exception: failure"
            ),
            unittest.mock.call(
                'run "func" with no arguments, '
                "attempt = 3, "
                "result = success"
            ),
        ]
        mock_print.assert_has_calls(expected_calls)

    @patch("builtins.print")
    def test_exception_in_exceptions(self, mock_print):
        call_count = 0

        @retry_deco(3, exceptions=[ValueError])
        def func():
            nonlocal call_count
            call_count += 1
            raise ValueError("error")

        with self.assertRaises(ValueError) as context:
            func()

        self.assertEqual(str(context.exception), "error")
        self.assertEqual(call_count, 1)
        mock_print.assert_called_once_with(
            'run "func" with no arguments, '
            "attempt = 1, "
            "exception = ValueError: error"
        )

    @patch("builtins.print")
    def test_function_with_args_and_kwargs(self, mock_print):

        @retry_deco(3)
        def func(a, b, c=0):
            return a + b + c

        result = func(1, 2, c=3)
        self.assertEqual(result, 6)
        mock_print.assert_called_once_with(
            'run "func" with positional args = (1, 2), '
            'keyword kwargs = {"c": 3}, '
            "attempt = 1, result = 6"
        )

    @patch("builtins.print")
    def test_function_raises_exceptions(self, mock_print):
        call_count = 0

        @retry_deco(3)
        def func():
            nonlocal call_count
            call_count += 1
            if call_count == 1:
                raise ValueError("value error")
            elif call_count == 2:
                raise TypeError("type error")
            else:
                raise Exception("exception")

        with self.assertRaises(Exception) as context:
            func()

        self.assertEqual(str(context.exception), "exception")
        self.assertEqual(call_count, 3)
        expected_calls = [
            unittest.mock.call(
                'run "func" with no arguments, '
                "attempt = 1, "
                "exception = ValueError: value error"
            ),
            unittest.mock.call(
                'run "func" with no arguments, '
                "attempt = 2, "
                "exception = TypeError: type error"
            ),
            unittest.mock.call(
                'run "func" with no arguments, '
                "attempt = 3, "
                "exception = Exception: exception"
            ),
        ]
        mock_print.assert_has_calls(expected_calls)

    @patch("builtins.print")
    def test_function_returns_none(self, mock_print):
        call_count = 0

        @retry_deco(3)
        def func():
            nonlocal call_count
            call_count += 1
            if call_count == 1:
                raise Exception("failure")
            return None

        result = func()
        self.assertIsNone(result)
        self.assertEqual(call_count, 2)
        expected_calls = [
            unittest.mock.call(
                'run "func" with no arguments, '
                "attempt = 1, "
                "exception = Exception: failure"
            ),
            unittest.mock.call(
                'run "func" with no arguments, ' "attempt = 2, " "result = None"
            ),
        ]
        mock_print.assert_has_calls(expected_calls)

    @patch("builtins.print")
    def test_exception_subclass_in_exceptions(self, mock_print):

        class BaseCustomException(Exception):
            pass

        class SubCustomException(BaseCustomException):
            pass

        call_count = 0

        @retry_deco(3, exceptions=[BaseCustomException])
        def func():
            nonlocal call_count
            call_count += 1
            raise SubCustomException("sub custom error")

        with self.assertRaises(SubCustomException) as context:
            func()

        self.assertEqual(str(context.exception), "sub custom error")
        self.assertEqual(call_count, 1)
        mock_print.assert_called_once_with(
            'run "func" with no arguments, attempt = 1, '
            "exception = SubCustomException: sub custom error"
        )

    @patch("builtins.print")
    def test_function_non_exception(self, mock_print):
        call_count = 0

        @retry_deco(3)
        def func():
            nonlocal call_count
            call_count += 1
            raise KeyboardInterrupt("keyboard interrupt")

        with self.assertRaises(KeyboardInterrupt) as context:
            func()

        self.assertEqual(str(context.exception), "keyboard interrupt")
        self.assertEqual(call_count, 1)
        mock_print.assert_not_called()

    @patch("builtins.print")
    def test_function_max_attempts(self, mock_print):
        call_count = 0

        @retry_deco(3)
        def func():
            nonlocal call_count
            call_count += 1
            if call_count <= 3:
                raise Exception("failure")
            return "success"

        with self.assertRaises(Exception) as context:
            func()

        self.assertEqual(str(context.exception), "failure")
        self.assertEqual(call_count, 3)
        expected_calls = [
            unittest.mock.call(
                'run "func" with no arguments, '
                "attempt = 1, "
                "exception = Exception: failure"
            ),
            unittest.mock.call(
                'run "func" with no arguments, '
                "attempt = 2, "
                "exception = Exception: failure"
            ),
            unittest.mock.call(
                'run "func" with no arguments, '
                "attempt = 3, "
                "exception = Exception: failure"
            ),
        ]
        mock_print.assert_has_calls(expected_calls)


if __name__ == "__main__":
    unittest.main()

ошибки: pylint ./*/*.py
************* Module parametrized_deco
02/parametrized_deco.py:41:23: W0718: Catching too general exception Exception (broad-exception-caught)
02/parametrized_deco.py:30:8: R1710: Either all return statements in a function should return an expression, or none of them should. (inconsistent-return-statements)
02/parametrized_deco.py:32:12: W0612: Unused variable 'function_name' (unused-variable)
************* Module test_decorator
02/test_decorator.py:33:12: W0719: Raising too general exception: Exception (broad-exception-raised)
02/test_decorator.py:69:16: W0719: Raising too general exception: Exception (broad-exception-raised)
02/test_decorator.py:139:12: R1720: Unnecessary "elif" after "raise", remove the leading "el" from "elif" (no-else-raise)
02/test_decorator.py:144:16: W0719: Raising too general exception: Exception (broad-exception-raised)
02/test_decorator.py:179:16: W0719: Raising too general exception: Exception (broad-exception-raised)
02/test_decorator.py:175:8: R1711: Useless return at end of function or method (useless-return)
02/test_decorator.py:192:0: W1404: Implicit string concatenation found in call (implicit-str-concat)
02/test_decorator.py:250:16: W0719: Raising too general exception: Exception (broad-exception-raised)
************* Module test_json_function
02/test_json_function.py:2:0: W0611: Unused import json (unused-import)
02/test_json_function.py:3:0: W0611: Unused Callable imported from typing (unused-import)
02/test_json_function.py:3:0: W0611: Unused Optional imported from typing (unused-import)
02/test_json_function.py:3:0: W0611: Unused List imported from typing (unused-import)