summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2023-05-05 15:21:10 +0000
committerCoprDistGit <infra@openeuler.org>2023-05-05 15:21:10 +0000
commite80a7b44e0113ff7a27e1ea8e3ef4a8e7e37b9e5 (patch)
treea87a03e32211f350f3305f127f625efa9532240a
parente445af88a0956ccb6eb2d7a137f7c0c8311cf131 (diff)
automatic import of python-unsyncopeneuler20.03
-rw-r--r--.gitignore1
-rw-r--r--python-unsync.spec594
-rw-r--r--sources1
3 files changed, 596 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..5ccf74d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/unsync-1.4.0.tar.gz
diff --git a/python-unsync.spec b/python-unsync.spec
new file mode 100644
index 0000000..c96fd9f
--- /dev/null
+++ b/python-unsync.spec
@@ -0,0 +1,594 @@
+%global _empty_manifest_terminate_build 0
+Name: python-unsync
+Version: 1.4.0
+Release: 1
+Summary: Unsynchronize asyncio
+License: MIT
+URL: https://github.com/alex-sherman/unsync
+Source0: https://mirrors.nju.edu.cn/pypi/web/packages/ea/6b/8d9699d37fe8c43c76fda4a7f93ae6aef129576f75c3cacfc9a78a7cc984/unsync-1.4.0.tar.gz
+BuildArch: noarch
+
+
+%description
+# unsync
+Unsynchronize `asyncio` by using an ambient event loop, or executing in separate threads or processes.
+
+# Quick Overview
+
+Functions marked with the `@unsync` decorator will behave in one of the following ways:
+* `async` functions will run in the `unsync.loop` event loop executed from `unsync.thread`
+* Regular functions will execute in `unsync.thread_executor`, a `ThreadPoolExecutor`
+ * Useful for IO bounded work that does not support `asyncio`
+* Regular functions marked with `@unsync(cpu_bound=True)` will execute in `unsync.process_executor`, a `ProcessPoolExecutor`
+ * Useful for CPU bounded work
+
+All `@unsync` functions will return an `Unfuture` object.
+This new future type combines the behavior of `asyncio.Future` and `concurrent.Future` with the following changes:
+* `Unfuture.set_result` is threadsafe unlike `asyncio.Future`
+* `Unfuture` instances can be awaited, even if made from `concurrent.Future`
+* `Unfuture.result()` is a blocking operation *except* in `unsync.loop`/`unsync.thread` where
+ it behaves like `asyncio.Future.result` and will throw an exception if the future is not done
+
+# Examples
+## Simple Sleep
+A simple sleeping example with `asyncio`:
+```python
+async def sync_async():
+ await asyncio.sleep(1)
+ return 'I hate event loops'
+
+
+async def main():
+ future1 = asyncio.create_task(sync_async())
+ future2 = asyncio.create_task(sync_async())
+
+ await future1, future2
+
+ print(future1.result() + future2.result())
+
+asyncio.run(main())
+# Takes 1 second to run
+```
+
+Same example with `unsync`:
+```python
+@unsync
+async def unsync_async():
+ await asyncio.sleep(1)
+ return 'I like decorators'
+
+unfuture1 = unsync_async()
+unfuture2 = unsync_async()
+print(unfuture1.result() + unfuture2.result())
+# Takes 1 second to run
+```
+
+## Multi-threading an IO-bound function
+Synchronous functions can be made to run asynchronously by executing them in a `concurrent.ThreadPoolExecutor`.
+This can be easily accomplished by marking the regular function `@unsync`.
+```python
+@unsync
+def non_async_function(seconds):
+ time.sleep(seconds)
+ return 'Run concurrently!'
+
+start = time.time()
+tasks = [non_async_function(0.1) for _ in range(10)]
+print([task.result() for task in tasks])
+print('Executed in {} seconds'.format(time.time() - start))
+```
+Which prints:
+
+ ['Run concurrently!', 'Run concurrently!', ...]
+ Executed in 0.10807514190673828 seconds
+
+## Continuations
+Using `Unfuture.then` chains asynchronous calls and returns an `Unfuture` that wraps both the source, and continuation.
+The continuation is invoked with the source Unfuture as the first argument.
+Continuations can be regular functions (which will execute synchronously), or `@unsync` functions.
+```python
+@unsync
+async def initiate(request):
+ await asyncio.sleep(0.1)
+ return request + 1
+
+@unsync
+async def process(task):
+ await asyncio.sleep(0.1)
+ return task.result() * 2
+
+start = time.time()
+print(initiate(3).then(process).result())
+print('Executed in {} seconds'.format(time.time() - start))
+```
+Which prints:
+
+ 8
+ Executed in 0.20314741134643555 seconds
+
+## Mixing methods
+
+We'll start by converting a regular synchronous function into a threaded `Unfuture` which will begin our request.
+```python
+@unsync
+def non_async_function(num):
+ time.sleep(0.1)
+ return num, num + 1
+```
+We may want to refine the result in another function, so we define the following continuation.
+```python
+@unsync
+async def result_continuation(task):
+ await asyncio.sleep(0.1)
+ num, res = task.result()
+ return num, res * 2
+```
+We then aggregate all the results into a single dictionary in an async function.
+```python
+@unsync
+async def result_processor(tasks):
+ output = {}
+ for task in tasks:
+ num, res = await task
+ output[num] = res
+ return output
+```
+Executing the full chain of `non_async_function`&rightarrow;`result_continuation`&rightarrow;`result_processor` would look like:
+```python
+start = time.time()
+print(result_processor([non_async_function(i).then(result_continuation) for i in range(10)]).result())
+print('Executed in {} seconds'.format(time.time() - start))
+```
+
+Which prints:
+
+ {0: 2, 1: 4, 2: 6, 3: 8, 4: 10, 5: 12, 6: 14, 7: 16, 8: 18, 9: 20}
+ Executed in 0.22115683555603027 seconds
+
+## Preserving typing
+As far as we know it is not possible to change the return type of a method or function using a decorator.
+Therefore, we need a workaround to properly use IntelliSense. You have three options in general:
+
+1. Ignore type warnings.
+2. Use a suppression statement where you reach the type warning.
+
+ A. When defining the unsynced method by changing the return type to an `Unfuture`.
+
+ B. When using the unsynced method.
+
+3. Wrap the function without a decorator. Example:
+ ```python
+ def function_name(x: str) -> Unfuture[str]:
+ async_method = unsync(__function_name_synced)
+ return async_method(x)
+
+ def __function_name_synced(x: str) -> str:
+ return x + 'a'
+
+ future_result = function_name('b')
+ self.assertEqual('ba', future_result.result())
+ ```
+
+## Custom Event Loops
+In order to use custom event loops, be sure to set the event loop policy before calling any `@unsync` methods.
+For example, to use `uvloop` simply:
+
+```python
+import unsync
+import uvloop
+
+@unsync
+async def main():
+ # Main entry-point.
+ ...
+
+uvloop.install() # Equivalent to asyncio.set_event_loop_policy(EventLoopPolicy())
+main()
+```
+
+%package -n python3-unsync
+Summary: Unsynchronize asyncio
+Provides: python-unsync
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pip
+%description -n python3-unsync
+# unsync
+Unsynchronize `asyncio` by using an ambient event loop, or executing in separate threads or processes.
+
+# Quick Overview
+
+Functions marked with the `@unsync` decorator will behave in one of the following ways:
+* `async` functions will run in the `unsync.loop` event loop executed from `unsync.thread`
+* Regular functions will execute in `unsync.thread_executor`, a `ThreadPoolExecutor`
+ * Useful for IO bounded work that does not support `asyncio`
+* Regular functions marked with `@unsync(cpu_bound=True)` will execute in `unsync.process_executor`, a `ProcessPoolExecutor`
+ * Useful for CPU bounded work
+
+All `@unsync` functions will return an `Unfuture` object.
+This new future type combines the behavior of `asyncio.Future` and `concurrent.Future` with the following changes:
+* `Unfuture.set_result` is threadsafe unlike `asyncio.Future`
+* `Unfuture` instances can be awaited, even if made from `concurrent.Future`
+* `Unfuture.result()` is a blocking operation *except* in `unsync.loop`/`unsync.thread` where
+ it behaves like `asyncio.Future.result` and will throw an exception if the future is not done
+
+# Examples
+## Simple Sleep
+A simple sleeping example with `asyncio`:
+```python
+async def sync_async():
+ await asyncio.sleep(1)
+ return 'I hate event loops'
+
+
+async def main():
+ future1 = asyncio.create_task(sync_async())
+ future2 = asyncio.create_task(sync_async())
+
+ await future1, future2
+
+ print(future1.result() + future2.result())
+
+asyncio.run(main())
+# Takes 1 second to run
+```
+
+Same example with `unsync`:
+```python
+@unsync
+async def unsync_async():
+ await asyncio.sleep(1)
+ return 'I like decorators'
+
+unfuture1 = unsync_async()
+unfuture2 = unsync_async()
+print(unfuture1.result() + unfuture2.result())
+# Takes 1 second to run
+```
+
+## Multi-threading an IO-bound function
+Synchronous functions can be made to run asynchronously by executing them in a `concurrent.ThreadPoolExecutor`.
+This can be easily accomplished by marking the regular function `@unsync`.
+```python
+@unsync
+def non_async_function(seconds):
+ time.sleep(seconds)
+ return 'Run concurrently!'
+
+start = time.time()
+tasks = [non_async_function(0.1) for _ in range(10)]
+print([task.result() for task in tasks])
+print('Executed in {} seconds'.format(time.time() - start))
+```
+Which prints:
+
+ ['Run concurrently!', 'Run concurrently!', ...]
+ Executed in 0.10807514190673828 seconds
+
+## Continuations
+Using `Unfuture.then` chains asynchronous calls and returns an `Unfuture` that wraps both the source, and continuation.
+The continuation is invoked with the source Unfuture as the first argument.
+Continuations can be regular functions (which will execute synchronously), or `@unsync` functions.
+```python
+@unsync
+async def initiate(request):
+ await asyncio.sleep(0.1)
+ return request + 1
+
+@unsync
+async def process(task):
+ await asyncio.sleep(0.1)
+ return task.result() * 2
+
+start = time.time()
+print(initiate(3).then(process).result())
+print('Executed in {} seconds'.format(time.time() - start))
+```
+Which prints:
+
+ 8
+ Executed in 0.20314741134643555 seconds
+
+## Mixing methods
+
+We'll start by converting a regular synchronous function into a threaded `Unfuture` which will begin our request.
+```python
+@unsync
+def non_async_function(num):
+ time.sleep(0.1)
+ return num, num + 1
+```
+We may want to refine the result in another function, so we define the following continuation.
+```python
+@unsync
+async def result_continuation(task):
+ await asyncio.sleep(0.1)
+ num, res = task.result()
+ return num, res * 2
+```
+We then aggregate all the results into a single dictionary in an async function.
+```python
+@unsync
+async def result_processor(tasks):
+ output = {}
+ for task in tasks:
+ num, res = await task
+ output[num] = res
+ return output
+```
+Executing the full chain of `non_async_function`&rightarrow;`result_continuation`&rightarrow;`result_processor` would look like:
+```python
+start = time.time()
+print(result_processor([non_async_function(i).then(result_continuation) for i in range(10)]).result())
+print('Executed in {} seconds'.format(time.time() - start))
+```
+
+Which prints:
+
+ {0: 2, 1: 4, 2: 6, 3: 8, 4: 10, 5: 12, 6: 14, 7: 16, 8: 18, 9: 20}
+ Executed in 0.22115683555603027 seconds
+
+## Preserving typing
+As far as we know it is not possible to change the return type of a method or function using a decorator.
+Therefore, we need a workaround to properly use IntelliSense. You have three options in general:
+
+1. Ignore type warnings.
+2. Use a suppression statement where you reach the type warning.
+
+ A. When defining the unsynced method by changing the return type to an `Unfuture`.
+
+ B. When using the unsynced method.
+
+3. Wrap the function without a decorator. Example:
+ ```python
+ def function_name(x: str) -> Unfuture[str]:
+ async_method = unsync(__function_name_synced)
+ return async_method(x)
+
+ def __function_name_synced(x: str) -> str:
+ return x + 'a'
+
+ future_result = function_name('b')
+ self.assertEqual('ba', future_result.result())
+ ```
+
+## Custom Event Loops
+In order to use custom event loops, be sure to set the event loop policy before calling any `@unsync` methods.
+For example, to use `uvloop` simply:
+
+```python
+import unsync
+import uvloop
+
+@unsync
+async def main():
+ # Main entry-point.
+ ...
+
+uvloop.install() # Equivalent to asyncio.set_event_loop_policy(EventLoopPolicy())
+main()
+```
+
+%package help
+Summary: Development documents and examples for unsync
+Provides: python3-unsync-doc
+%description help
+# unsync
+Unsynchronize `asyncio` by using an ambient event loop, or executing in separate threads or processes.
+
+# Quick Overview
+
+Functions marked with the `@unsync` decorator will behave in one of the following ways:
+* `async` functions will run in the `unsync.loop` event loop executed from `unsync.thread`
+* Regular functions will execute in `unsync.thread_executor`, a `ThreadPoolExecutor`
+ * Useful for IO bounded work that does not support `asyncio`
+* Regular functions marked with `@unsync(cpu_bound=True)` will execute in `unsync.process_executor`, a `ProcessPoolExecutor`
+ * Useful for CPU bounded work
+
+All `@unsync` functions will return an `Unfuture` object.
+This new future type combines the behavior of `asyncio.Future` and `concurrent.Future` with the following changes:
+* `Unfuture.set_result` is threadsafe unlike `asyncio.Future`
+* `Unfuture` instances can be awaited, even if made from `concurrent.Future`
+* `Unfuture.result()` is a blocking operation *except* in `unsync.loop`/`unsync.thread` where
+ it behaves like `asyncio.Future.result` and will throw an exception if the future is not done
+
+# Examples
+## Simple Sleep
+A simple sleeping example with `asyncio`:
+```python
+async def sync_async():
+ await asyncio.sleep(1)
+ return 'I hate event loops'
+
+
+async def main():
+ future1 = asyncio.create_task(sync_async())
+ future2 = asyncio.create_task(sync_async())
+
+ await future1, future2
+
+ print(future1.result() + future2.result())
+
+asyncio.run(main())
+# Takes 1 second to run
+```
+
+Same example with `unsync`:
+```python
+@unsync
+async def unsync_async():
+ await asyncio.sleep(1)
+ return 'I like decorators'
+
+unfuture1 = unsync_async()
+unfuture2 = unsync_async()
+print(unfuture1.result() + unfuture2.result())
+# Takes 1 second to run
+```
+
+## Multi-threading an IO-bound function
+Synchronous functions can be made to run asynchronously by executing them in a `concurrent.ThreadPoolExecutor`.
+This can be easily accomplished by marking the regular function `@unsync`.
+```python
+@unsync
+def non_async_function(seconds):
+ time.sleep(seconds)
+ return 'Run concurrently!'
+
+start = time.time()
+tasks = [non_async_function(0.1) for _ in range(10)]
+print([task.result() for task in tasks])
+print('Executed in {} seconds'.format(time.time() - start))
+```
+Which prints:
+
+ ['Run concurrently!', 'Run concurrently!', ...]
+ Executed in 0.10807514190673828 seconds
+
+## Continuations
+Using `Unfuture.then` chains asynchronous calls and returns an `Unfuture` that wraps both the source, and continuation.
+The continuation is invoked with the source Unfuture as the first argument.
+Continuations can be regular functions (which will execute synchronously), or `@unsync` functions.
+```python
+@unsync
+async def initiate(request):
+ await asyncio.sleep(0.1)
+ return request + 1
+
+@unsync
+async def process(task):
+ await asyncio.sleep(0.1)
+ return task.result() * 2
+
+start = time.time()
+print(initiate(3).then(process).result())
+print('Executed in {} seconds'.format(time.time() - start))
+```
+Which prints:
+
+ 8
+ Executed in 0.20314741134643555 seconds
+
+## Mixing methods
+
+We'll start by converting a regular synchronous function into a threaded `Unfuture` which will begin our request.
+```python
+@unsync
+def non_async_function(num):
+ time.sleep(0.1)
+ return num, num + 1
+```
+We may want to refine the result in another function, so we define the following continuation.
+```python
+@unsync
+async def result_continuation(task):
+ await asyncio.sleep(0.1)
+ num, res = task.result()
+ return num, res * 2
+```
+We then aggregate all the results into a single dictionary in an async function.
+```python
+@unsync
+async def result_processor(tasks):
+ output = {}
+ for task in tasks:
+ num, res = await task
+ output[num] = res
+ return output
+```
+Executing the full chain of `non_async_function`&rightarrow;`result_continuation`&rightarrow;`result_processor` would look like:
+```python
+start = time.time()
+print(result_processor([non_async_function(i).then(result_continuation) for i in range(10)]).result())
+print('Executed in {} seconds'.format(time.time() - start))
+```
+
+Which prints:
+
+ {0: 2, 1: 4, 2: 6, 3: 8, 4: 10, 5: 12, 6: 14, 7: 16, 8: 18, 9: 20}
+ Executed in 0.22115683555603027 seconds
+
+## Preserving typing
+As far as we know it is not possible to change the return type of a method or function using a decorator.
+Therefore, we need a workaround to properly use IntelliSense. You have three options in general:
+
+1. Ignore type warnings.
+2. Use a suppression statement where you reach the type warning.
+
+ A. When defining the unsynced method by changing the return type to an `Unfuture`.
+
+ B. When using the unsynced method.
+
+3. Wrap the function without a decorator. Example:
+ ```python
+ def function_name(x: str) -> Unfuture[str]:
+ async_method = unsync(__function_name_synced)
+ return async_method(x)
+
+ def __function_name_synced(x: str) -> str:
+ return x + 'a'
+
+ future_result = function_name('b')
+ self.assertEqual('ba', future_result.result())
+ ```
+
+## Custom Event Loops
+In order to use custom event loops, be sure to set the event loop policy before calling any `@unsync` methods.
+For example, to use `uvloop` simply:
+
+```python
+import unsync
+import uvloop
+
+@unsync
+async def main():
+ # Main entry-point.
+ ...
+
+uvloop.install() # Equivalent to asyncio.set_event_loop_policy(EventLoopPolicy())
+main()
+```
+
+%prep
+%autosetup -n unsync-1.4.0
+
+%build
+%py3_build
+
+%install
+%py3_install
+install -d -m755 %{buildroot}/%{_pkgdocdir}
+if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
+if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
+if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
+if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
+pushd %{buildroot}
+if [ -d usr/lib ]; then
+ find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/lib64 ]; then
+ find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/bin ]; then
+ find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/sbin ]; then
+ find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+touch doclist.lst
+if [ -d usr/share/man ]; then
+ find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst
+fi
+popd
+mv %{buildroot}/filelist.lst .
+mv %{buildroot}/doclist.lst .
+
+%files -n python3-unsync -f filelist.lst
+%dir %{python3_sitelib}/*
+
+%files help -f doclist.lst
+%{_docdir}/*
+
+%changelog
+* Fri May 05 2023 Python_Bot <Python_Bot@openeuler.org> - 1.4.0-1
+- Package Spec generated
diff --git a/sources b/sources
new file mode 100644
index 0000000..f8f7a49
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+6b2119ba4a7e2795dbb544e0cd00705b unsync-1.4.0.tar.gz