From 1fc5d21788bb2985eb79dc4f34a98d4f37dc25b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Tue, 17 Mar 2026 15:10:01 +0300 Subject: [PATCH 01/13] Update README to use em dash in sentence --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b5e4a0..6a141d2 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ![logo](https://raw.githubusercontent.com/mutating/transfunctions/develop/docs/assets/logo_2.svg) -This library is designed to solve one of the most important problems in python programming - dividing all written code into 2 camps: sync and async. We get rid of code duplication by using templates. +This library is designed to solve one of the most important problems in python programming — dividing all written code into 2 camps: sync and async. We get rid of code duplication by using templates. ## Table of contents From 00900ef3303d316274995834966666cb44260943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Tue, 17 Mar 2026 15:10:14 +0300 Subject: [PATCH 02/13] Update getsources to version 0.0.3 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 36b482c..c32b8c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ readme = "README.md" requires-python = ">=3.8" dependencies = [ 'displayhooks>=0.0.5', - 'getsources>=0.0.2', + 'getsources>=0.0.3', 'typing_extensions ; python_version <= "3.10"', ] From 19b823c3f588047c43189bff9b055812cbaa4db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Tue, 17 Mar 2026 15:11:10 +0300 Subject: [PATCH 03/13] Add Python 3.15 support across configs and classifiers --- .github/workflows/lint.yml | 2 +- .github/workflows/tests_and_coverage.yml | 2 +- pyproject.toml | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 502743a..50c8996 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.14t", "3.15.0-alpha.1"] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/tests_and_coverage.yml b/.github/workflows/tests_and_coverage.yml index ad52407..66e8838 100644 --- a/.github/workflows/tests_and_coverage.yml +++ b/.github/workflows/tests_and_coverage.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: [macos-latest, ubuntu-latest, windows-latest] - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.14t", "3.15.0-alpha.1"] steps: - uses: actions/checkout@v4 diff --git a/pyproject.toml b/pyproject.toml index c32b8c4..305f293 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,7 @@ classifiers = [ 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', 'Programming Language :: Python :: 3.14', + 'Programming Language :: Python :: 3.15', 'Programming Language :: Python :: Free Threading', 'Programming Language :: Python :: Free Threading :: 3 - Stable', 'License :: OSI Approved :: MIT License', From c8384394f73a848145bfd2b6aa4b9b9ef80cc2f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Tue, 17 Mar 2026 15:11:23 +0300 Subject: [PATCH 04/13] Bump version to 0.0.11 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 305f293..0280e71 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "transfunctions" -version = "0.0.10" +version = "0.0.11" authors = [{ name = "Evgeniy Blinov", email = "zheni-b@yandex.ru" }] description = 'Say NO to Python fragmentation on sync and async' readme = "README.md" From 505bcee5b53912fd9430fe5f469af86afd8a8d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Tue, 17 Mar 2026 15:13:32 +0300 Subject: [PATCH 05/13] Fix typos --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6a141d2..b45cb66 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ![logo](https://raw.githubusercontent.com/mutating/transfunctions/develop/docs/assets/logo_2.svg) -This library is designed to solve one of the most important problems in python programming — dividing all written code into 2 camps: sync and async. We get rid of code duplication by using templates. +This library is designed to solve one of the most important problems in Python programming — dividing all written code into two camps: sync and async. We get rid of code duplication by using templates. ## Table of contents @@ -163,7 +163,7 @@ async def template(): print("it's an async function!") ``` -Finally, method `get_generator_function` will return a generator function that looks like this: +Finally, the method `get_generator_function` will return a generator function that looks like this: ```python def template(): @@ -175,7 +175,7 @@ def template(): All generated functions: - Inherit the access to global variables and closures that the original template function had. -- Сan be either ordinary stand-alone functions or bound methods. In the latter case, they will be linked to the same object. +- Can be either ordinary standalone functions or bound methods. In the latter case, they will be linked to the same object. There is only one known limitation: you cannot use any third-party decorators on the template using the decorator syntax, because in some situations this can lead to ambiguous behavior. If you still really need to use a third-party decorator, just generate any of the functions from the template, and then apply your decorator to the result of the generation. @@ -311,7 +311,7 @@ Typing is the most difficult problem we faced when developing this library. In m There are 2 main difficulties in developing typing here: -- Code generation creates code in runtime that is not in the source files of your project. Whereas most type analyzers look at your code statically, at what is actually present in your files. +- Code generation creates code at runtime that is not in the source files of your project. Whereas most type analyzers look at your code statically, at what is actually present in your files. - We mix several types of syntax in a single template function, but the static analyzer does not know that this is a template and part of the code will be deleted from here. In its opinion, this is the final function that will continue to be used in your project. As you can see, typing in Python is not well suited for metaprogramming. However, in this project, almost all the problems with typing turned out to be solved in one way or another. The main reason why this is so is that we mostly *remove* code from functions, but hardly *add* it there during code generation. In other words, we almost never encounter the problem of how to type the *added* code. This makes the solution to most typing problems accessible. However! Unfortunately, we were not able to completely hide all the typing problems under the hood, but you should still be aware of some of them if you use `mypy` or another analyzer. From a20de4f42bd453ad720325e9758fa879bcba653d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Fri, 20 Mar 2026 19:17:12 +0300 Subject: [PATCH 06/13] Update import to use yield_from_it instead of yield_it --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b45cb66..00eb935 100644 --- a/README.md +++ b/README.md @@ -319,7 +319,7 @@ As you can see, typing in Python is not well suited for metaprogramming. However If you use the keyword `yield from`, you need to call the function `yield_from_it` instead: ```python -from transfunctions import yield_it +from transfunctions import yield_from_it @superfunction def my_superfunction(): From 01cfc7daa90dddfd6872eb18ef25a50fcf79da99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Fri, 20 Mar 2026 19:20:55 +0300 Subject: [PATCH 07/13] Fix grammar and wording in README for clarity and consistency --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 00eb935..d8581c5 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ def template(): All generated functions: -- Inherit the access to global variables and closures that the original template function had. +- Inherit access to global variables and closures that the original template function had. - Can be either ordinary standalone functions or bound methods. In the latter case, they will be linked to the same object. There is only one known limitation: you cannot use any third-party decorators on the template using the decorator syntax, because in some situations this can lead to ambiguous behavior. If you still really need to use a third-party decorator, just generate any of the functions from the template, and then apply your decorator to the result of the generation. @@ -202,7 +202,7 @@ async def template(): await sleep(5) ``` -All markers do not need to be imported in order for the generated code to be functional: they are destroyed during the [code generation](#code-generation). However, you can do this if your linter or syntax checker in your IDE requires it: +None of the markers need to be imported in order for the generated code to be functional: they are destroyed during the [code generation](#code-generation). However, you can do this if your linter or syntax checker in your IDE requires it: ```python from transfunctions import ( @@ -282,7 +282,7 @@ list(my_superfunction()) #> so, it's a generator function! ``` -How does it work? In fact, `my_superfunction` returns some kind of intermediate object that can be both a coroutine and a generator and an ordinary function. Depending on how it is handled, it lazily code-generates the desired version of the function from a given template and uses it. +How does it work? In fact, `my_superfunction` returns some kind of intermediate object that can behave as a coroutine, a generator, or a regular callable. Depending on how it is handled, it lazily code-generates the desired version of the function from a given template and uses it. By default, a superfunction is called as a regular function using tilde syntax, but there is another mode. To enable it, use the appropriate flag in the decorator: @@ -333,4 +333,4 @@ def my_superfunction(): yield_from_it([1, 2, 3]) ``` -The keywords `yield` or `yield from` are available to you and work perfectly, but from the point of view of a static type checker, they turn the function into a generator, which should also mean a special type annotation. By replacing this fragment with a function call, we hack it. +The keywords `yield` or `yield from` are available to you and work perfectly, but from the point of view of a static type checker, they turn the function into a generator, which should also mean a special type annotation. Replacing the syntax with a function call avoids confusing the type checker. From a6749366aaeacb7af1b477a3100716a8f76331d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Fri, 20 Mar 2026 19:28:55 +0300 Subject: [PATCH 08/13] Refactor README to use "splitting" and "templates" terminology consistently --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index d8581c5..7c24154 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ![logo](https://raw.githubusercontent.com/mutating/transfunctions/develop/docs/assets/logo_2.svg) -This library is designed to solve one of the most important problems in Python programming — dividing all written code into two camps: sync and async. We get rid of code duplication by using templates. +This library is designed to solve one of the most important problems in Python programming — splitting code into two categories: sync and async. It reduces code duplication by using templates. ## Table of contents @@ -79,13 +79,13 @@ You can also quickly try out this and other packages without having to install u ## The problem -Since the `asyncio` module appeared in Python more than 10 years ago, many well-known libraries have received their asynchronous alternates. A lot of the code in the Python ecosystem has been [duplicated](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself), and you probably know many such examples. +Since the `asyncio` module appeared in Python more than 10 years ago, many well-known libraries have gained asynchronous counterparts. A lot of the code in the Python ecosystem has been [duplicated](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself), and you probably know many such examples. -The reason for this problem is that the Python community has chosen a way to implement asynchrony expressed through syntax. There are new keywords in the language, such as `async` and `await`. Their use makes the code so-called "[multicolored](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/)": all the functions in it can be red or blue, and depending on the color, the rules for calling them are different. You can only call blue functions from red ones, but not vice versa. +The reason for this problem is that the Python community has chosen a syntax-based approach to asynchrony. There are new keywords in the language, such as `async` and `await`. Their use makes the code so-called "[multicolored](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/)": functions become “red” or “blue”, and depending on the color, the rules for calling them are different. You can only call blue functions from red ones, but not vice versa. -I must say that implementing asynchronous calls using a special syntax is not the only solution. There are languages like Go where runtime can independently determine "under the hood" where a function should be asynchronous and where not, and choose the correct way to call it. A programmer does not need to manually "colorize" their functions there. Personally, I think that choosing a different path is the mistake of the Python community, but that's not what we're discussing here. +I must say that implementing asynchronous calls using a special syntax is not the only solution. There are languages like Go where the runtime can determine under the hood where a function should be asynchronous and where not, and choose how to execute them. A programmer does not need to manually "colorize" their functions there. Personally, I think that choosing a different path is the mistake of the Python community, but that's not what we're discussing here. -The solution offered by this library is based on templating. You can take a certain function as a template and generate several others based on it: regular, asynchronous, or generator. This allows you to avoid duplicating code where it was previously impossible. And all this without major changes in Python syntax or in the internal structure of the interpreter. We're just "sweeping under the carpet" syntax differences. Combined with the idea of context-aware functions, this makes for an even more powerful tool: `superfunctions`. This allows you to create a single function object that can be handled as you like: as a regular function, as an asynchronous function, or as a generator. The function will behave the way you use it. Thus, this library solves the problem of code duplication caused by the syntactic approach to marking asynchronous execution sections. +The solution offered by this library is based on templating. You can take a certain function as a template and generate several others based on it: regular, asynchronous, or generator. This allows you to avoid duplicating code where it was previously impossible. And all this without major changes in Python syntax or in the internal structure of the interpreter. We are essentially hiding the syntax differences. Combined with the idea of context-aware functions, this makes for an even more powerful tool: `superfunctions`. This allows you to create a single function object that can be handled as you like: as a regular function, as an asynchronous function, or as a generator. The function will behave the way you use it. Thus, this library solves the problem of code duplication caused by the syntactic approach to marking asynchronous execution sections. ## Code generation @@ -257,7 +257,7 @@ With the `@superfunction` decorator, you no longer need to call special methods If you use it as a regular function, a regular function will be created "under the hood" based on the template and then called: -To call a superfunction like a regular function, you need to use a special tilde syntax: +To call a superfunction like a regular function, you need to use a special tilde-based call syntax: ```python ~my_superfunction() @@ -297,9 +297,9 @@ my_superfunction() #> so, it's just usual function! ``` -However, it is not completely free. The fact is that this mode uses a special trick with a reference counter, a special mechanism inside the interpreter that cleans up memory. When there is no reference to an object, the interpreter deletes it, and you can link your callback to this process. It is inside such a callback that the contents of your function are actually executed. This imposes some restrictions on you: +However, it comes with trade-offs. The fact is that this mode uses a special trick with a reference counter, a special mechanism inside the interpreter that cleans up memory. When there is no reference to an object, the interpreter deletes it, and you can link your callback to this process. It is inside such a callback that the contents of your function are actually executed. This imposes some restrictions on you: -- You cannot use the return values from this function in any way. If you try to save the result of a function call to a variable, the reference counter to the returned object will not reset while this variable exists, and accordingly the function will not actually be called. +- You cannot use the return values from this function in any way. If you try to save the result of a function call to a variable, the reference counter to the returned object will not drop to zero while this variable exists, and accordingly the function will not actually be called. - Exceptions will not work normally inside this function. Rather, they can be picked up and intercepted in [`sys.unraisablehook`](https://docs.python.org/3/library/sys.html#sys.unraisablehook), but they will not go up the stack above this function. This is due to a feature of CPython: exceptions that occur inside callbacks for finalizing objects are completely escaped. This mode is well suited for functions such as logging or sending statistics from your code: simple functions from which no exceptions or return values are expected. In all other cases, I recommend using the tilde syntax. @@ -314,7 +314,7 @@ There are 2 main difficulties in developing typing here: - Code generation creates code at runtime that is not in the source files of your project. Whereas most type analyzers look at your code statically, at what is actually present in your files. - We mix several types of syntax in a single template function, but the static analyzer does not know that this is a template and part of the code will be deleted from here. In its opinion, this is the final function that will continue to be used in your project. -As you can see, typing in Python is not well suited for metaprogramming. However, in this project, almost all the problems with typing turned out to be solved in one way or another. The main reason why this is so is that we mostly *remove* code from functions, but hardly *add* it there during code generation. In other words, we almost never encounter the problem of how to type the *added* code. This makes the solution to most typing problems accessible. However! Unfortunately, we were not able to completely hide all the typing problems under the hood, but you should still be aware of some of them if you use `mypy` or another analyzer. +As you can see, typing in Python is not well suited for metaprogramming. However, in this project, almost all the problems with typing turned out to be solved in one way or another. The main reason why this is so is that we mostly *remove* code from functions, but hardly *add* it there during code generation. In other words, we almost never encounter the problem of how to type the *added* code. This makes the solution to most typing problems accessible. However, we were not able to completely hide all the typing problems under the hood, but you should still be aware of some of them if you use `mypy` or another analyzer. If you use the keyword `yield from`, you need to call the function `yield_from_it` instead: From 351c157ecf9c5fe07b77b00c66692375aee6af53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Fri, 20 Mar 2026 19:31:03 +0300 Subject: [PATCH 09/13] Remove trailing blank line in pyproject.toml --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 0280e71..b4ac496 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,6 @@ dependencies = [ 'getsources>=0.0.3', 'typing_extensions ; python_version <= "3.10"', ] - classifiers = [ "Operating System :: OS Independent", 'Operating System :: MacOS :: MacOS X', From c68f94b69a351a3f013b1b6a618a65289ecee065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Fri, 20 Mar 2026 19:43:10 +0300 Subject: [PATCH 10/13] Update ruff to version 0.14.6 --- requirements_dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_dev.txt b/requirements_dev.txt index 2dd4729..6105320 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -4,6 +4,6 @@ build==1.2.2.post1 twine==6.1.0 mypy==1.14.1 pytest-mypy-testing==0.1.3 -ruff==0.9.9 +ruff==0.14.6 mutmut==3.2.3 full_match==0.0.3 From a3c2bc911bcb15ca35cbf9e345dc6ffb945348e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Fri, 20 Mar 2026 19:44:20 +0300 Subject: [PATCH 11/13] Remove noqa: A005 from transfunctions files --- tests/typing/__init__.py | 1 - transfunctions/__init__.py | 24 +++++++++++----------- transfunctions/decorators/superfunction.py | 4 ++-- transfunctions/transformer.py | 10 ++++----- transfunctions/typing.py | 1 - 5 files changed, 19 insertions(+), 21 deletions(-) diff --git a/tests/typing/__init__.py b/tests/typing/__init__.py index dc9fd4c..e69de29 100644 --- a/tests/typing/__init__.py +++ b/tests/typing/__init__.py @@ -1 +0,0 @@ -# noqa: A005 diff --git a/transfunctions/__init__.py b/transfunctions/__init__.py index 3edddc6..c28f053 100644 --- a/transfunctions/__init__.py +++ b/transfunctions/__init__.py @@ -1,36 +1,36 @@ from transfunctions.decorators.superfunction import ( - superfunction as superfunction, # noqa: PLC0414 + superfunction as superfunction, ) from transfunctions.decorators.transfunction import ( - transfunction as transfunction, # noqa: PLC0414 + transfunction as transfunction, ) from transfunctions.errors import ( - CallTransfunctionDirectlyError as CallTransfunctionDirectlyError, # noqa: PLC0414 + CallTransfunctionDirectlyError as CallTransfunctionDirectlyError, ) from transfunctions.errors import ( - DualUseOfDecoratorError as DualUseOfDecoratorError, # noqa: PLC0414 + DualUseOfDecoratorError as DualUseOfDecoratorError, ) from transfunctions.errors import ( - WrongDecoratorSyntaxError as WrongDecoratorSyntaxError, # noqa: PLC0414 + WrongDecoratorSyntaxError as WrongDecoratorSyntaxError, ) from transfunctions.errors import ( - WrongMarkerSyntaxError as WrongMarkerSyntaxError, # noqa: PLC0414 + WrongMarkerSyntaxError as WrongMarkerSyntaxError, ) from transfunctions.errors import ( - WrongTransfunctionSyntaxError as WrongTransfunctionSyntaxError, # noqa: PLC0414 + WrongTransfunctionSyntaxError as WrongTransfunctionSyntaxError, ) from transfunctions.markers import ( - async_context as async_context, # noqa: PLC0414 + async_context as async_context, ) from transfunctions.markers import ( - await_it as await_it, # noqa: PLC0414 + await_it as await_it, ) from transfunctions.markers import ( - generator_context as generator_context, # noqa: PLC0414 + generator_context as generator_context, ) from transfunctions.markers import ( - sync_context as sync_context, # noqa: PLC0414 + sync_context as sync_context, ) from transfunctions.markers import ( - yield_from_it as yield_from_it, # noqa: PLC0414 + yield_from_it as yield_from_it, ) diff --git a/transfunctions/decorators/superfunction.py b/transfunctions/decorators/superfunction.py index 1d53608..820746c 100644 --- a/transfunctions/decorators/superfunction.py +++ b/transfunctions/decorators/superfunction.py @@ -125,7 +125,7 @@ def decorator(function: Callable[FunctionParams, ReturnType]) -> Callable[Functi if not tilde_syntax: class NoReturns(NodeTransformer): - def visit_Return(self, node: Return) -> Optional[Union[AST, List[AST]]]: # noqa: ARG002, N802 + def visit_Return(self, node: Return) -> Optional[Union[AST, List[AST]]]: # noqa: ARG002 raise WrongTransfunctionSyntaxError('A superfunction cannot contain a return statement.') transformer.get_usual_function(addictional_transformers=[NoReturns()]) @@ -137,7 +137,7 @@ def wrapper(*args: FunctionParams.args, **kwargs: FunctionParams.kwargs) -> Usag return wrapper - if len(args): + if args: return decorator(args[0]) return decorator diff --git a/transfunctions/transformer.py b/transfunctions/transformer.py index fe6ea4e..f0fec29 100644 --- a/transfunctions/transformer.py +++ b/transfunctions/transformer.py @@ -90,7 +90,7 @@ def get_async_function(self) -> Callable[FunctionParams, Coroutine[Any, Any, Ret original_function = self.function class ConvertSyncFunctionToAsync(NodeTransformer): - def visit_FunctionDef(self, node: FunctionDef) -> Union[FunctionDef, AsyncFunctionDef]: # noqa: N802 + def visit_FunctionDef(self, node: FunctionDef) -> Union[FunctionDef, AsyncFunctionDef]: if node.name == original_function.__name__: return AsyncFunctionDef( # type: ignore[no-any-return, call-overload, unused-ignore] name=original_function.__name__, @@ -105,7 +105,7 @@ def visit_FunctionDef(self, node: FunctionDef) -> Union[FunctionDef, AsyncFuncti return node class ExtractAwaitExpressions(NodeTransformer): - def visit_Call(self, node: Call) -> Union[Call, Await]: # noqa: N802 + def visit_Call(self, node: Call) -> Union[Call, Await]: if isinstance(node.func, Name) and node.func.id == 'await_it': if len(node.args) != 1 or node.keywords: raise WrongMarkerSyntaxError('The "await_it" marker can be used with only one positional argument.') @@ -132,7 +132,7 @@ def visit_Call(self, node: Call) -> Union[Call, Await]: # noqa: N802 def get_generator_function(self) -> Callable[FunctionParams, Generator[ReturnType, None, None]]: class ConvertYieldFroms(NodeTransformer): - def visit_Call(self, node: Call) -> Optional[Union[AST, List[AST]]]: # noqa: N802 + def visit_Call(self, node: Call) -> Optional[Union[AST, List[AST]]]: if isinstance(node.func, Name) and node.func.id == 'yield_from_it': if len(node.args) != 1 or node.keywords: raise WrongMarkerSyntaxError('The "yield_from_it" marker can be used with only one positional argument.') @@ -168,7 +168,7 @@ def extract_context(self, context_name: str, addictional_transformers: Optional[ check_decorators = self.check_decorators class RewriteContexts(NodeTransformer): - def visit_With(self, node: With) -> Optional[Union[AST, List[AST]]]: # noqa: N802 + def visit_With(self, node: With) -> Optional[Union[AST, List[AST]]]: if len(node.items) == 1: if isinstance(node.items[0].context_expr, Name): context_expr = node.items[0].context_expr @@ -182,7 +182,7 @@ def visit_With(self, node: With) -> Optional[Union[AST, List[AST]]]: # noqa: N8 return node class DeleteDecorator(NodeTransformer): - def visit_FunctionDef(self, node: FunctionDef) -> Optional[Union[AST, List[AST]]]: # noqa: N802 + def visit_FunctionDef(self, node: FunctionDef) -> Optional[Union[AST, List[AST]]]: if node.name == original_function.__name__: nonlocal transfunction_decorator transfunction_decorator = None diff --git a/transfunctions/typing.py b/transfunctions/typing.py index 695986b..21f7102 100644 --- a/transfunctions/typing.py +++ b/transfunctions/typing.py @@ -1,4 +1,3 @@ -# noqa: A005 import sys from collections.abc import Iterable from typing import TypeVar From 9dc76f307e38a74b1e85a1bf4b0eac175dc7e6f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Fri, 20 Mar 2026 19:50:49 +0300 Subject: [PATCH 12/13] Update pytest to version 8.3.5 --- requirements_dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_dev.txt b/requirements_dev.txt index 6105320..c617929 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,4 +1,4 @@ -pytest==8.0.2 +pytest==8.3.5 coverage==7.6.1 build==1.2.2.post1 twine==6.1.0 From dfa74791559288c6b5d748510678c9519dcecf45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=91=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Fri, 20 Mar 2026 21:22:16 +0300 Subject: [PATCH 13/13] Update displayhooks version to 0.0.6 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b4ac496..7f86ee5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ description = 'Say NO to Python fragmentation on sync and async' readme = "README.md" requires-python = ">=3.8" dependencies = [ - 'displayhooks>=0.0.5', + 'displayhooks>=0.0.6', 'getsources>=0.0.3', 'typing_extensions ; python_version <= "3.10"', ]