transfunctions 0.0.2__tar.gz → 0.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {transfunctions-0.0.2/transfunctions.egg-info → transfunctions-0.0.4}/PKG-INFO +2 -2
- {transfunctions-0.0.2 → transfunctions-0.0.4}/pyproject.toml +5 -1
- {transfunctions-0.0.2 → transfunctions-0.0.4}/transfunctions/decorators/superfunction.py +3 -6
- transfunctions-0.0.4/transfunctions/markers.py +24 -0
- {transfunctions-0.0.2 → transfunctions-0.0.4}/transfunctions/transformer.py +10 -10
- {transfunctions-0.0.2 → transfunctions-0.0.4/transfunctions.egg-info}/PKG-INFO +2 -2
- transfunctions-0.0.4/transfunctions.egg-info/requires.txt +5 -0
- transfunctions-0.0.2/transfunctions/markers.py +0 -24
- transfunctions-0.0.2/transfunctions.egg-info/requires.txt +0 -2
- {transfunctions-0.0.2 → transfunctions-0.0.4}/LICENSE +0 -0
- {transfunctions-0.0.2 → transfunctions-0.0.4}/README.md +0 -0
- {transfunctions-0.0.2 → transfunctions-0.0.4}/setup.cfg +0 -0
- {transfunctions-0.0.2 → transfunctions-0.0.4}/transfunctions/__init__.py +0 -0
- {transfunctions-0.0.2 → transfunctions-0.0.4}/transfunctions/decorators/__init__.py +0 -0
- {transfunctions-0.0.2 → transfunctions-0.0.4}/transfunctions/decorators/transfunction.py +0 -0
- {transfunctions-0.0.2 → transfunctions-0.0.4}/transfunctions/errors.py +0 -0
- {transfunctions-0.0.2 → transfunctions-0.0.4}/transfunctions/py.typed +0 -0
- {transfunctions-0.0.2 → transfunctions-0.0.4}/transfunctions.egg-info/SOURCES.txt +0 -0
- {transfunctions-0.0.2 → transfunctions-0.0.4}/transfunctions.egg-info/dependency_links.txt +0 -0
- {transfunctions-0.0.2 → transfunctions-0.0.4}/transfunctions.egg-info/top_level.txt +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: transfunctions
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Say NO to Python fragmentation on sync and async
|
|
5
5
|
Author-email: Evgeniy Blinov <zheni-b@yandex.ru>
|
|
6
6
|
Project-URL: Source, https://github.com/pomponchik/transfunctions
|
|
7
7
|
Project-URL: Tracker, https://github.com/pomponchik/transfunctions/issues
|
|
8
|
-
Keywords: async,sync to async,async to sync
|
|
8
|
+
Keywords: async,sync to async,async to sync,code generation,ast manipulation,magic
|
|
9
9
|
Classifier: Operating System :: OS Independent
|
|
10
10
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
11
11
|
Classifier: Operating System :: Microsoft :: Windows
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "transfunctions"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.4"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Evgeniy Blinov", email="zheni-b@yandex.ru" },
|
|
10
10
|
]
|
|
@@ -14,6 +14,7 @@ requires-python = ">=3.8"
|
|
|
14
14
|
dependencies = [
|
|
15
15
|
'displayhooks>=0.0.4',
|
|
16
16
|
'dill==0.4.0',
|
|
17
|
+
'typing_extensions ; python_version <= "3.10"',
|
|
17
18
|
]
|
|
18
19
|
classifiers = [
|
|
19
20
|
"Operating System :: OS Independent",
|
|
@@ -37,6 +38,9 @@ keywords = [
|
|
|
37
38
|
'async',
|
|
38
39
|
'sync to async',
|
|
39
40
|
'async to sync',
|
|
41
|
+
'code generation',
|
|
42
|
+
'ast manipulation',
|
|
43
|
+
'magic',
|
|
40
44
|
]
|
|
41
45
|
|
|
42
46
|
[tool.setuptools.package-data]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
import weakref
|
|
3
|
-
from ast import NodeTransformer,
|
|
3
|
+
from ast import NodeTransformer, Return, AST
|
|
4
4
|
from inspect import currentframe
|
|
5
5
|
from functools import wraps
|
|
6
6
|
from typing import Dict, Any, Optional, Union, List
|
|
@@ -42,10 +42,7 @@ class UsageTracer(CoroutineClass):
|
|
|
42
42
|
return self.coroutine.__await__()
|
|
43
43
|
|
|
44
44
|
def __invert__(self):
|
|
45
|
-
print(self.finalizer)
|
|
46
|
-
print(self.finalizer.alive)
|
|
47
45
|
result = self.finalizer()
|
|
48
|
-
print('result:', result)
|
|
49
46
|
return result
|
|
50
47
|
|
|
51
48
|
def send(self, value: Any) -> Any:
|
|
@@ -66,14 +63,14 @@ class UsageTracer(CoroutineClass):
|
|
|
66
63
|
@staticmethod
|
|
67
64
|
async def async_sleep_option(flags: Dict[str, bool], args, kwargs, transformer) -> None:
|
|
68
65
|
flags['used'] = True
|
|
69
|
-
await transformer.get_async_function()(*args, **kwargs)
|
|
66
|
+
return await transformer.get_async_function()(*args, **kwargs)
|
|
70
67
|
|
|
71
68
|
|
|
72
69
|
not_display(UsageTracer)
|
|
73
70
|
|
|
74
71
|
def superfunction(function):
|
|
75
72
|
class NoReturns(NodeTransformer):
|
|
76
|
-
def visit_Return(self, node:
|
|
73
|
+
def visit_Return(self, node: Return) -> Optional[Union[AST, List[AST]]]:
|
|
77
74
|
raise WrongTransfunctionSyntaxError('A superfunction cannot contain a return statement.')
|
|
78
75
|
|
|
79
76
|
transformer = FunctionTransformer(
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from typing import Any, NoReturn, Generator
|
|
2
|
+
from contextlib import contextmanager
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@contextmanager
|
|
6
|
+
def create_async_context() -> Generator[NoReturn, None, None]:
|
|
7
|
+
yield # type: ignore[misc] # pragma: no cover
|
|
8
|
+
|
|
9
|
+
@contextmanager
|
|
10
|
+
def create_sync_context() -> Generator[NoReturn, None, None]:
|
|
11
|
+
yield # type: ignore[misc] # pragma: no cover
|
|
12
|
+
|
|
13
|
+
@contextmanager
|
|
14
|
+
def create_generator_context() -> Generator[NoReturn, None, None]:
|
|
15
|
+
yield # type: ignore[misc] # pragma: no cover
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
async_context = create_async_context()
|
|
19
|
+
sync_context = create_sync_context()
|
|
20
|
+
generator_context = create_generator_context()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def await_it(some_expression: Any) -> Any:
|
|
24
|
+
pass # pragma: no cover
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from sys import version_info
|
|
2
|
-
from typing import Optional, Union, List, Any
|
|
2
|
+
from typing import Optional, Union, List, Dict, Any
|
|
3
3
|
from types import MethodType, FunctionType
|
|
4
4
|
from collections.abc import Callable
|
|
5
5
|
from inspect import isfunction, iscoroutinefunction, getsource, getfile
|
|
6
|
-
from ast import parse, NodeTransformer,
|
|
6
|
+
from ast import parse, NodeTransformer, AST, FunctionDef, AsyncFunctionDef, increment_lineno, Await, Call, With, Return, Name, Load, Assign, Constant, Store, arguments
|
|
7
7
|
from functools import wraps, update_wrapper
|
|
8
8
|
|
|
9
|
-
from dill.source import getsource as dill_getsource
|
|
9
|
+
from dill.source import getsource as dill_getsource # type: ignore[import-untyped]
|
|
10
10
|
|
|
11
11
|
from transfunctions.errors import CallTransfunctionDirectlyError, DualUseOfDecoratorError, WrongDecoratorSyntaxError
|
|
12
12
|
|
|
@@ -27,7 +27,7 @@ class FunctionTransformer:
|
|
|
27
27
|
self.decorator_name = decorator_name
|
|
28
28
|
self.extra_transformers = extra_transformers
|
|
29
29
|
self.base_object = None
|
|
30
|
-
self.cache = {}
|
|
30
|
+
self.cache: Dict[str, Callable] = {}
|
|
31
31
|
|
|
32
32
|
def __call__(self, *args: Any, **kwargs: Any) -> None:
|
|
33
33
|
raise CallTransfunctionDirectlyError("You can't call a transfunction object directly, create a function, a generator function or a coroutine function from it.")
|
|
@@ -49,7 +49,7 @@ class FunctionTransformer:
|
|
|
49
49
|
original_function = self.function
|
|
50
50
|
|
|
51
51
|
class ConvertSyncFunctionToAsync(NodeTransformer):
|
|
52
|
-
def visit_FunctionDef(self, node:
|
|
52
|
+
def visit_FunctionDef(self, node: FunctionDef) -> Optional[Union[AST, List[AST]]]:
|
|
53
53
|
if node.name == original_function.__name__:
|
|
54
54
|
return AsyncFunctionDef(
|
|
55
55
|
name=original_function.__name__,
|
|
@@ -62,7 +62,7 @@ class FunctionTransformer:
|
|
|
62
62
|
return node
|
|
63
63
|
|
|
64
64
|
class ExtractAwaitExpressions(NodeTransformer):
|
|
65
|
-
def visit_Call(self, node:
|
|
65
|
+
def visit_Call(self, node: Call) -> Optional[Union[AST, List[AST]]]:
|
|
66
66
|
if node.func.id == 'await_it':
|
|
67
67
|
return Await(
|
|
68
68
|
value=node.args[0],
|
|
@@ -102,7 +102,7 @@ class FunctionTransformer:
|
|
|
102
102
|
if context_name in self.cache:
|
|
103
103
|
return self.cache[context_name]
|
|
104
104
|
try:
|
|
105
|
-
source_code = getsource(self.function)
|
|
105
|
+
source_code: str = getsource(self.function)
|
|
106
106
|
except OSError:
|
|
107
107
|
source_code = dill_getsource(self.function)
|
|
108
108
|
|
|
@@ -119,7 +119,7 @@ class FunctionTransformer:
|
|
|
119
119
|
decorator_name = self.decorator_name
|
|
120
120
|
|
|
121
121
|
class RewriteContexts(NodeTransformer):
|
|
122
|
-
def visit_With(self, node:
|
|
122
|
+
def visit_With(self, node: With) -> Optional[Union[AST, List[AST]]]:
|
|
123
123
|
if len(node.items) == 1 and node.items[0].context_expr.id == context_name:
|
|
124
124
|
return node.body
|
|
125
125
|
elif len(node.items) == 1 and node.items[0].context_expr.id != context_name and context_name in ('async_context', 'sync_context', 'generator_context'):
|
|
@@ -127,7 +127,7 @@ class FunctionTransformer:
|
|
|
127
127
|
return node
|
|
128
128
|
|
|
129
129
|
class DeleteDecorator(NodeTransformer):
|
|
130
|
-
def visit_FunctionDef(self, node:
|
|
130
|
+
def visit_FunctionDef(self, node: FunctionDef) -> Optional[Union[AST, List[AST]]]:
|
|
131
131
|
if node.name == original_function.__name__:
|
|
132
132
|
nonlocal transfunction_decorator
|
|
133
133
|
transfunction_decorator = None
|
|
@@ -161,7 +161,7 @@ class FunctionTransformer:
|
|
|
161
161
|
increment_lineno(tree, n=(self.decorator_lineno - transfunction_decorator.lineno - 1))
|
|
162
162
|
|
|
163
163
|
code = compile(tree, filename=getfile(self.function), mode='exec')
|
|
164
|
-
namespace = {}
|
|
164
|
+
namespace: Dict[str, Callable] = {}
|
|
165
165
|
exec(code, namespace)
|
|
166
166
|
function_factory = namespace['wrapper']
|
|
167
167
|
result = function_factory()
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: transfunctions
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Say NO to Python fragmentation on sync and async
|
|
5
5
|
Author-email: Evgeniy Blinov <zheni-b@yandex.ru>
|
|
6
6
|
Project-URL: Source, https://github.com/pomponchik/transfunctions
|
|
7
7
|
Project-URL: Tracker, https://github.com/pomponchik/transfunctions/issues
|
|
8
|
-
Keywords: async,sync to async,async to sync
|
|
8
|
+
Keywords: async,sync to async,async to sync,code generation,ast manipulation,magic
|
|
9
9
|
Classifier: Operating System :: OS Independent
|
|
10
10
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
11
11
|
Classifier: Operating System :: Microsoft :: Windows
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
from contextlib import contextmanager
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
@contextmanager
|
|
6
|
-
def create_async_context():
|
|
7
|
-
yield
|
|
8
|
-
|
|
9
|
-
@contextmanager
|
|
10
|
-
def create_sync_context():
|
|
11
|
-
yield
|
|
12
|
-
|
|
13
|
-
@contextmanager
|
|
14
|
-
def create_generator_context():
|
|
15
|
-
yield
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
async_context = create_async_context()
|
|
19
|
-
sync_context = create_sync_context()
|
|
20
|
-
generator_context = create_generator_context()
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def await_it(some_expression: Any):
|
|
24
|
-
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|