appose 0.1.0__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.
- appose-0.1.0/LICENSE.txt +24 -0
- appose-0.1.0/PKG-INFO +160 -0
- appose-0.1.0/README.md +128 -0
- appose-0.1.0/pyproject.toml +78 -0
- appose-0.1.0/setup.cfg +4 -0
- appose-0.1.0/src/appose/__init__.py +152 -0
- appose-0.1.0/src/appose/environment.py +209 -0
- appose-0.1.0/src/appose/paths.py +56 -0
- appose-0.1.0/src/appose/python_worker.py +176 -0
- appose-0.1.0/src/appose/service.py +344 -0
- appose-0.1.0/src/appose/types.py +41 -0
- appose-0.1.0/src/appose.egg-info/PKG-INFO +160 -0
- appose-0.1.0/src/appose.egg-info/SOURCES.txt +15 -0
- appose-0.1.0/src/appose.egg-info/dependency_links.txt +1 -0
- appose-0.1.0/src/appose.egg-info/requires.txt +13 -0
- appose-0.1.0/src/appose.egg-info/top_level.txt +1 -0
- appose-0.1.0/tests/test_appose.py +126 -0
appose-0.1.0/LICENSE.txt
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Copyright (c) 2023, Appose developers.
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
12
|
+
and/or other materials provided with the distribution.
|
13
|
+
|
14
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
15
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
16
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
17
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
18
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
19
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
20
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
21
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
22
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
23
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
24
|
+
POSSIBILITY OF SUCH DAMAGE.
|
appose-0.1.0/PKG-INFO
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: appose
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: Appose: multi-language interprocess cooperation with shared memory.
|
5
|
+
Author: Appose developers
|
6
|
+
License: Simplified BSD License
|
7
|
+
Project-URL: homepage, https://github.com/apposed/appose-python
|
8
|
+
Project-URL: documentation, https://github.com/apposed/appose-python/blob/main/README.md
|
9
|
+
Project-URL: source, https://github.com/apposed/appose-python
|
10
|
+
Project-URL: download, https://pypi.org/project/appose-python
|
11
|
+
Project-URL: tracker, https://github.com/apposed/appose-python/issues
|
12
|
+
Keywords: java,javascript,python,cross-language,interprocess
|
13
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
14
|
+
Classifier: Intended Audience :: Developers
|
15
|
+
Classifier: Intended Audience :: Education
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
20
|
+
Classifier: License :: OSI Approved :: BSD License
|
21
|
+
Classifier: Operating System :: Microsoft :: Windows
|
22
|
+
Classifier: Operating System :: Unix
|
23
|
+
Classifier: Operating System :: MacOS
|
24
|
+
Classifier: Topic :: Scientific/Engineering
|
25
|
+
Classifier: Topic :: Software Development :: Libraries :: Java Libraries
|
26
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
27
|
+
Classifier: Topic :: Utilities
|
28
|
+
Requires-Python: >=3.10
|
29
|
+
Description-Content-Type: text/markdown
|
30
|
+
Provides-Extra: dev
|
31
|
+
License-File: LICENSE.txt
|
32
|
+
|
33
|
+
# Appose Python
|
34
|
+
|
35
|
+
***WARNING: Appose is currently in incubation.
|
36
|
+
Not all features described below are functional.
|
37
|
+
This document has some aspirational aspects!***
|
38
|
+
|
39
|
+
## What is Appose?
|
40
|
+
|
41
|
+
Appose is a library for interprocess cooperation with shared memory.
|
42
|
+
The guiding principles are *simplicity* and *efficiency*.
|
43
|
+
|
44
|
+
Appose was written to enable **easy execution of Python-based deep learning
|
45
|
+
from Java without copying tensors**, but its utility extends beyond that.
|
46
|
+
The steps for using Appose are:
|
47
|
+
|
48
|
+
* Build an Environment with the dependencies you need.
|
49
|
+
* Create a Service linked to a *worker*, which runs in its own process.
|
50
|
+
* Execute scripts on the worker by launching Tasks.
|
51
|
+
* Receive status updates from the task asynchronously via callbacks.
|
52
|
+
|
53
|
+
For more about Appose as a whole, see https://apposed.org.
|
54
|
+
|
55
|
+
## What is this project?
|
56
|
+
|
57
|
+
This is the **Python implementation of Appose**.
|
58
|
+
|
59
|
+
## How do I use it?
|
60
|
+
|
61
|
+
The name of the package is `appose`.
|
62
|
+
|
63
|
+
### Conda/Mamba
|
64
|
+
|
65
|
+
To use [the conda-forge package](https://anaconda.org/conda-forge/appose),
|
66
|
+
add `appose` to your `environment.yml`'s `dependencies` section:
|
67
|
+
|
68
|
+
```yaml
|
69
|
+
dependencies:
|
70
|
+
- appose
|
71
|
+
```
|
72
|
+
|
73
|
+
### PyPI/Pip
|
74
|
+
|
75
|
+
To use [the PyPI package](https://pypi.org/project/appose),
|
76
|
+
add `appose` to your project dependencies.
|
77
|
+
|
78
|
+
Depending on how your project is set up, this might entail editing
|
79
|
+
`requirements.txt`, `setup.py`, `setup.cfg`, and/or `pyproject.toml`.
|
80
|
+
|
81
|
+
If you are just starting out, we recommend using `pyproject.toml` (see
|
82
|
+
[this guide](https://packaging.python.org/en/latest/tutorials/packaging-projects/#creating-pyproject-toml)):
|
83
|
+
|
84
|
+
```toml
|
85
|
+
dependencies = [
|
86
|
+
"appose"
|
87
|
+
]
|
88
|
+
```
|
89
|
+
|
90
|
+
## Examples
|
91
|
+
|
92
|
+
Here is a minimal example for calling into Java from Python:
|
93
|
+
|
94
|
+
```python
|
95
|
+
import appose
|
96
|
+
env = appose.java(vendor="zulu", version="17").build()
|
97
|
+
with env.groovy() as groovy:
|
98
|
+
task = groovy.task("5 + 6")
|
99
|
+
task.waitFor()
|
100
|
+
result = task.outputs.get("result")
|
101
|
+
assert 11 == result
|
102
|
+
```
|
103
|
+
|
104
|
+
*Note: The `Appose.java` builder is planned, but not yet implemented.*
|
105
|
+
|
106
|
+
Here is an example using a few more of Appose's features:
|
107
|
+
|
108
|
+
```python
|
109
|
+
import appose
|
110
|
+
from time import sleep
|
111
|
+
|
112
|
+
golden_ratio_in_groovy = """
|
113
|
+
// Approximate the golden ratio using the Fibonacci sequence.
|
114
|
+
previous = 0
|
115
|
+
current = 1
|
116
|
+
for (i=0; i<iterations; i++) {
|
117
|
+
if (task.cancelRequested) {
|
118
|
+
task.cancel()
|
119
|
+
break
|
120
|
+
}
|
121
|
+
task.update(null, i, iterations)
|
122
|
+
v = current
|
123
|
+
current += previous
|
124
|
+
previous = v
|
125
|
+
}
|
126
|
+
task.outputs["numer"] = current
|
127
|
+
task.outputs["denom"] = previous
|
128
|
+
"""
|
129
|
+
|
130
|
+
env = appose.java(vendor="zulu", version="17").build()
|
131
|
+
with env.groovy() as groovy:
|
132
|
+
task = groovy.task(golden_ratio_in_groovy)
|
133
|
+
|
134
|
+
def task_listener(event):
|
135
|
+
match event.responseType:
|
136
|
+
case ResponseType.UPDATE:
|
137
|
+
print(f"Progress {task.current}/{task.maximum}")
|
138
|
+
case ResponseType.COMPLETION:
|
139
|
+
numer = task.outputs["numer"]
|
140
|
+
denom = task.outputs["denom"]
|
141
|
+
ratio = numer / denom
|
142
|
+
print(f"Task complete. Result: {numer}/{denom} =~ {ratio}");
|
143
|
+
case ResponseType.CANCELATION:
|
144
|
+
print("Task canceled")
|
145
|
+
case ResponseType.FAILURE:
|
146
|
+
print(f"Task failed: {task.error}")
|
147
|
+
|
148
|
+
task.listen(task_listener)
|
149
|
+
|
150
|
+
task.start()
|
151
|
+
sleep(1)
|
152
|
+
if not task.status.is_finished():
|
153
|
+
# Task is taking too long; request a cancelation.
|
154
|
+
task.cancel()
|
155
|
+
|
156
|
+
task.wait_for()
|
157
|
+
```
|
158
|
+
|
159
|
+
Of course, the above examples could have been done all in one language. But
|
160
|
+
hopefully they hint at the possibilities of easy cross-language integration.
|
appose-0.1.0/README.md
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
# Appose Python
|
2
|
+
|
3
|
+
***WARNING: Appose is currently in incubation.
|
4
|
+
Not all features described below are functional.
|
5
|
+
This document has some aspirational aspects!***
|
6
|
+
|
7
|
+
## What is Appose?
|
8
|
+
|
9
|
+
Appose is a library for interprocess cooperation with shared memory.
|
10
|
+
The guiding principles are *simplicity* and *efficiency*.
|
11
|
+
|
12
|
+
Appose was written to enable **easy execution of Python-based deep learning
|
13
|
+
from Java without copying tensors**, but its utility extends beyond that.
|
14
|
+
The steps for using Appose are:
|
15
|
+
|
16
|
+
* Build an Environment with the dependencies you need.
|
17
|
+
* Create a Service linked to a *worker*, which runs in its own process.
|
18
|
+
* Execute scripts on the worker by launching Tasks.
|
19
|
+
* Receive status updates from the task asynchronously via callbacks.
|
20
|
+
|
21
|
+
For more about Appose as a whole, see https://apposed.org.
|
22
|
+
|
23
|
+
## What is this project?
|
24
|
+
|
25
|
+
This is the **Python implementation of Appose**.
|
26
|
+
|
27
|
+
## How do I use it?
|
28
|
+
|
29
|
+
The name of the package is `appose`.
|
30
|
+
|
31
|
+
### Conda/Mamba
|
32
|
+
|
33
|
+
To use [the conda-forge package](https://anaconda.org/conda-forge/appose),
|
34
|
+
add `appose` to your `environment.yml`'s `dependencies` section:
|
35
|
+
|
36
|
+
```yaml
|
37
|
+
dependencies:
|
38
|
+
- appose
|
39
|
+
```
|
40
|
+
|
41
|
+
### PyPI/Pip
|
42
|
+
|
43
|
+
To use [the PyPI package](https://pypi.org/project/appose),
|
44
|
+
add `appose` to your project dependencies.
|
45
|
+
|
46
|
+
Depending on how your project is set up, this might entail editing
|
47
|
+
`requirements.txt`, `setup.py`, `setup.cfg`, and/or `pyproject.toml`.
|
48
|
+
|
49
|
+
If you are just starting out, we recommend using `pyproject.toml` (see
|
50
|
+
[this guide](https://packaging.python.org/en/latest/tutorials/packaging-projects/#creating-pyproject-toml)):
|
51
|
+
|
52
|
+
```toml
|
53
|
+
dependencies = [
|
54
|
+
"appose"
|
55
|
+
]
|
56
|
+
```
|
57
|
+
|
58
|
+
## Examples
|
59
|
+
|
60
|
+
Here is a minimal example for calling into Java from Python:
|
61
|
+
|
62
|
+
```python
|
63
|
+
import appose
|
64
|
+
env = appose.java(vendor="zulu", version="17").build()
|
65
|
+
with env.groovy() as groovy:
|
66
|
+
task = groovy.task("5 + 6")
|
67
|
+
task.waitFor()
|
68
|
+
result = task.outputs.get("result")
|
69
|
+
assert 11 == result
|
70
|
+
```
|
71
|
+
|
72
|
+
*Note: The `Appose.java` builder is planned, but not yet implemented.*
|
73
|
+
|
74
|
+
Here is an example using a few more of Appose's features:
|
75
|
+
|
76
|
+
```python
|
77
|
+
import appose
|
78
|
+
from time import sleep
|
79
|
+
|
80
|
+
golden_ratio_in_groovy = """
|
81
|
+
// Approximate the golden ratio using the Fibonacci sequence.
|
82
|
+
previous = 0
|
83
|
+
current = 1
|
84
|
+
for (i=0; i<iterations; i++) {
|
85
|
+
if (task.cancelRequested) {
|
86
|
+
task.cancel()
|
87
|
+
break
|
88
|
+
}
|
89
|
+
task.update(null, i, iterations)
|
90
|
+
v = current
|
91
|
+
current += previous
|
92
|
+
previous = v
|
93
|
+
}
|
94
|
+
task.outputs["numer"] = current
|
95
|
+
task.outputs["denom"] = previous
|
96
|
+
"""
|
97
|
+
|
98
|
+
env = appose.java(vendor="zulu", version="17").build()
|
99
|
+
with env.groovy() as groovy:
|
100
|
+
task = groovy.task(golden_ratio_in_groovy)
|
101
|
+
|
102
|
+
def task_listener(event):
|
103
|
+
match event.responseType:
|
104
|
+
case ResponseType.UPDATE:
|
105
|
+
print(f"Progress {task.current}/{task.maximum}")
|
106
|
+
case ResponseType.COMPLETION:
|
107
|
+
numer = task.outputs["numer"]
|
108
|
+
denom = task.outputs["denom"]
|
109
|
+
ratio = numer / denom
|
110
|
+
print(f"Task complete. Result: {numer}/{denom} =~ {ratio}");
|
111
|
+
case ResponseType.CANCELATION:
|
112
|
+
print("Task canceled")
|
113
|
+
case ResponseType.FAILURE:
|
114
|
+
print(f"Task failed: {task.error}")
|
115
|
+
|
116
|
+
task.listen(task_listener)
|
117
|
+
|
118
|
+
task.start()
|
119
|
+
sleep(1)
|
120
|
+
if not task.status.is_finished():
|
121
|
+
# Task is taking too long; request a cancelation.
|
122
|
+
task.cancel()
|
123
|
+
|
124
|
+
task.wait_for()
|
125
|
+
```
|
126
|
+
|
127
|
+
Of course, the above examples could have been done all in one language. But
|
128
|
+
hopefully they hint at the possibilities of easy cross-language integration.
|
@@ -0,0 +1,78 @@
|
|
1
|
+
[build-system]
|
2
|
+
requires = ["setuptools>=61.2"]
|
3
|
+
build-backend = "setuptools.build_meta"
|
4
|
+
|
5
|
+
[project]
|
6
|
+
name = "appose"
|
7
|
+
version = "0.1.0"
|
8
|
+
description = "Appose: multi-language interprocess cooperation with shared memory."
|
9
|
+
license = {text = "Simplified BSD License"}
|
10
|
+
authors = [{name = "Appose developers"}]
|
11
|
+
readme = "README.md"
|
12
|
+
keywords = ["java", "javascript", "python", "cross-language", "interprocess"]
|
13
|
+
classifiers = [
|
14
|
+
"Development Status :: 2 - Pre-Alpha",
|
15
|
+
"Intended Audience :: Developers",
|
16
|
+
"Intended Audience :: Education",
|
17
|
+
"Intended Audience :: Science/Research",
|
18
|
+
"Programming Language :: Python :: 3 :: Only",
|
19
|
+
"Programming Language :: Python :: 3.10",
|
20
|
+
"Programming Language :: Python :: 3.11",
|
21
|
+
"License :: OSI Approved :: BSD License",
|
22
|
+
"Operating System :: Microsoft :: Windows",
|
23
|
+
"Operating System :: Unix",
|
24
|
+
"Operating System :: MacOS",
|
25
|
+
"Topic :: Scientific/Engineering",
|
26
|
+
"Topic :: Software Development :: Libraries :: Java Libraries",
|
27
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
28
|
+
"Topic :: Utilities",
|
29
|
+
]
|
30
|
+
|
31
|
+
# NB: Keep this in sync with environment.yml AND dev-environment.yml!
|
32
|
+
requires-python = ">=3.10"
|
33
|
+
dependencies = [
|
34
|
+
]
|
35
|
+
|
36
|
+
[project.optional-dependencies]
|
37
|
+
# NB: Keep this in sync with dev-environment.yml!
|
38
|
+
dev = [
|
39
|
+
"autopep8",
|
40
|
+
"black",
|
41
|
+
"build",
|
42
|
+
"flake8",
|
43
|
+
"flake8-pyproject",
|
44
|
+
"flake8-typing-imports",
|
45
|
+
"isort",
|
46
|
+
"pytest",
|
47
|
+
"numpy",
|
48
|
+
"toml",
|
49
|
+
"validate-pyproject[all]",
|
50
|
+
]
|
51
|
+
|
52
|
+
[project.urls]
|
53
|
+
homepage = "https://github.com/apposed/appose-python"
|
54
|
+
documentation = "https://github.com/apposed/appose-python/blob/main/README.md"
|
55
|
+
source = "https://github.com/apposed/appose-python"
|
56
|
+
download = "https://pypi.org/project/appose-python"
|
57
|
+
tracker = "https://github.com/apposed/appose-python/issues"
|
58
|
+
|
59
|
+
[tool.setuptools]
|
60
|
+
package-dir = {"" = "src"}
|
61
|
+
include-package-data = true
|
62
|
+
|
63
|
+
[tool.setuptools.packages.find]
|
64
|
+
where = ["src"]
|
65
|
+
|
66
|
+
# Thanks to Flake8-pyproject, we can configure flake8 here!
|
67
|
+
[tool.flake8]
|
68
|
+
exclude = ["bin", "build", "dist"]
|
69
|
+
extend-ignore = ["E203"]
|
70
|
+
# See https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html#flake8
|
71
|
+
max-line-length = 88
|
72
|
+
min_python_version = "3.10"
|
73
|
+
|
74
|
+
[tool.isort]
|
75
|
+
profile = "black"
|
76
|
+
|
77
|
+
[tool.pytest.ini_options]
|
78
|
+
addopts = "-s -p no:faulthandler"
|
appose-0.1.0/setup.cfg
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
###
|
2
|
+
# #%L
|
3
|
+
# Appose: multi-language interprocess cooperation with shared memory.
|
4
|
+
# %%
|
5
|
+
# Copyright (C) 2023 Appose developers.
|
6
|
+
# %%
|
7
|
+
# Redistribution and use in source and binary forms, with or without
|
8
|
+
# modification, are permitted provided that the following conditions are met:
|
9
|
+
#
|
10
|
+
# 1. Redistributions of source code must retain the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer.
|
12
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
13
|
+
# this list of conditions and the following disclaimer in the documentation
|
14
|
+
# and/or other materials provided with the distribution.
|
15
|
+
#
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
19
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
20
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
21
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
22
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
23
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
24
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
25
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
26
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
# #L%
|
28
|
+
###
|
29
|
+
|
30
|
+
'''
|
31
|
+
Appose is a library for interprocess cooperation with shared memory.
|
32
|
+
The guiding principles are *simplicity* and *efficiency*.
|
33
|
+
|
34
|
+
Appose was written to enable **easy execution of Python-based deep learning
|
35
|
+
from Java without copying tensors**, but its utility extends beyond that.
|
36
|
+
The steps for using Appose are:
|
37
|
+
|
38
|
+
* Build an *environment* with the dependencies you need.
|
39
|
+
* Create a *service* linked to a *worker*, which runs in its own process.
|
40
|
+
* Execute scripts on the worker by launching *tasks*.
|
41
|
+
* Receive status updates from the task asynchronously via callbacks.
|
42
|
+
|
43
|
+
## Examples
|
44
|
+
|
45
|
+
* TODO - move the below code somewhere linkable, for succinctness here.
|
46
|
+
|
47
|
+
Here is a very simple example written in Python:
|
48
|
+
|
49
|
+
import appose
|
50
|
+
env = appose.java(vendor="zulu", version="17").build()
|
51
|
+
groovy = env.groovy()
|
52
|
+
Task task = groovy.task("""
|
53
|
+
5 + 6
|
54
|
+
""")
|
55
|
+
task.waitFor()
|
56
|
+
result = task.outputs.get("result")
|
57
|
+
assert 11 == result
|
58
|
+
|
59
|
+
And here is an example using a few more of Appose's features:
|
60
|
+
|
61
|
+
import appose
|
62
|
+
from time import sleep
|
63
|
+
|
64
|
+
env = appose.java(vendor="zulu", version="17").build()
|
65
|
+
groovy = env.groovy()
|
66
|
+
task = groovy.task("""
|
67
|
+
// Approximate the golden ratio using the Fibonacci sequence.
|
68
|
+
previous = 0
|
69
|
+
current = 1
|
70
|
+
for (i = 0; i < iterations; i++) {
|
71
|
+
if (task.cancelRequested) {
|
72
|
+
task.cancel()
|
73
|
+
break
|
74
|
+
}
|
75
|
+
task.status(null, i, iterations)
|
76
|
+
v = current
|
77
|
+
current += previous
|
78
|
+
previous = v
|
79
|
+
}
|
80
|
+
task.outputs["numer"] = current
|
81
|
+
task.outputs["denom"] = previous
|
82
|
+
""")
|
83
|
+
|
84
|
+
def task_listener(event):
|
85
|
+
match event.responseType:
|
86
|
+
case UPDATE:
|
87
|
+
print(f"Progress {task.current}/{task.maximum}")
|
88
|
+
case COMPLETION:
|
89
|
+
numer = task.outputs["numer"]
|
90
|
+
denom = task.outputs["denom"]
|
91
|
+
ratio = numer / denom
|
92
|
+
print(f"Task complete. Result: {numer}/{denom} =~ {ratio}");
|
93
|
+
case CANCELATION:
|
94
|
+
print("Task canceled")
|
95
|
+
case FAILURE:
|
96
|
+
print(f"Task failed: {task.error}")
|
97
|
+
|
98
|
+
task.listen(task_listener)
|
99
|
+
|
100
|
+
task.start()
|
101
|
+
sleep(1)
|
102
|
+
if not task.status.isFinished():
|
103
|
+
# Task is taking too long; request a cancelation.
|
104
|
+
task.cancel()
|
105
|
+
|
106
|
+
task.waitFor()
|
107
|
+
|
108
|
+
Of course, the above examples could have been done all in Python. But
|
109
|
+
hopefully they hint at the possibilities of easy cross-language integration.
|
110
|
+
|
111
|
+
## Workers
|
112
|
+
|
113
|
+
A *worker* is a separate process created by Appose to do asynchronous
|
114
|
+
computation on behalf of the calling process. The calling process interacts
|
115
|
+
with a worker via its associated *service*.
|
116
|
+
|
117
|
+
Appose comes with built-in support for two worker implementations:
|
118
|
+
`python_worker` to run Python scripts, and `GroovyWorker` to run Groovy
|
119
|
+
scripts. These workers can be created easily by invoking the environment
|
120
|
+
object's `python()` and `groovy()` methods respectively.
|
121
|
+
|
122
|
+
But Appose is compatible with any program that abides by the
|
123
|
+
*Appose worker process contract*:
|
124
|
+
|
125
|
+
1. The worker must accept requests in Appose's request format on its
|
126
|
+
standard input (stdin) stream.
|
127
|
+
2. The worker must issue responses in Appose's response format on its
|
128
|
+
standard output (stdout) stream.
|
129
|
+
|
130
|
+
TODO - write up the request and response formats in detail here!
|
131
|
+
JSON, one line per request/response.
|
132
|
+
'''
|
133
|
+
|
134
|
+
from pathlib import Path
|
135
|
+
|
136
|
+
from .environment import Builder, Environment
|
137
|
+
|
138
|
+
|
139
|
+
def base(directory: Path) -> Builder:
|
140
|
+
return Builder().base(directory)
|
141
|
+
|
142
|
+
|
143
|
+
def java(vendor: str, version: str) -> Builder:
|
144
|
+
return Builder().java(vendor=vendor, version=version)
|
145
|
+
|
146
|
+
|
147
|
+
def conda(environment_yaml: Path) -> Builder:
|
148
|
+
return Builder().conda(environment_yaml=environment_yaml)
|
149
|
+
|
150
|
+
|
151
|
+
def system(directory: Path = Path(".")) -> Environment:
|
152
|
+
return Builder().base(directory).use_system_path().build()
|