Skip to content

Commit 7bc5f01

Browse files
authored
Merge pull request #68 from octue/release/0.1.8
Release 0.1.8 - Child Services and Documentation
2 parents 5bcf2b7 + d4ddf5a commit 7bc5f01

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1918
-111
lines changed

.github/workflows/python-ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ jobs:
1919

2020
tests:
2121
runs-on: ubuntu-latest
22+
if: "!contains(github.event.head_commit.message, '#skip_ci_tests')"
2223
env:
2324
USING_COVERAGE: '3.8'
2425
strategy:
@@ -34,6 +35,8 @@ jobs:
3435
- name: Install Tox and any other packages
3536
run: pip install tox
3637
- name: Run Tox
38+
env:
39+
GCP_SERVICE_ACCOUNT: ${{ secrets.GCP_SERVICE_ACCOUNT }}
3740
run: tox -e py
3841
- name: Upload coverage to Codecov
3942
uses: codecov/codecov-action@v1

.pre-commit-config.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ repos:
3333
rev: 0.0.1
3434
hooks:
3535
- id: build-docs
36+
language_version: python3
3637
additional_dependencies:
38+
- 'Sphinx>=2,<3'
39+
- 'sphinx-rtd-theme==0.5.0'
40+
- 'sphinx-tabs==1.2.1'
3741
- 'scipy~=1.5.2'
3842
- 'jsonschema~=3.2.0'
3943

README.md

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,18 @@
11
[![PyPI version](https://badge.fury.io/py/octue.svg)](https://badge.fury.io/py/octue)
22
[![codecov](https://codecov.io/gh/octue/octue-sdk-python/branch/main/graph/badge.svg?token=4KdR7fmwcT)](https://codecov.io/gh/octue/octue-sdk-python)
3-
[![Documentation Status](https://readthedocs.org/projects/octue/badge/?version=latest)](https://octue.readthedocs.io/en/latest/?badge=latest)
3+
[![Documentation Status](https://readthedocs.org/projects/octue-python-sdk/badge/?version=latest)](https://octue-python-sdk.readthedocs.io/en/latest/?badge=latest)
44
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)
55
[![black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)
66
[![black-girls-code](https://img.shields.io/badge/black%20girls-code-f64279.svg)](https://www.blackgirlscode.com/)
77

88
# octue-sdk-python <span><img src="http://slurmed.com/fanart/javier/213_purple-fruit-snake.gif" alt="Purple Fruit Snake" width="100"/></span>
99

10-
Utilities for running python based data services, digital twins and applications with the Octue toolkit and [twined](https://www.twined.readthedocs.io) SDK for python based apps running within octue.
11-
12-
[See documentation.](https://octue.readthedocs.io/en/latest)
10+
Utilities for running python based data services, digital twins and applications with the Octue toolkit and [twined](https://twined.readthedocs.io/en/latest/?badge=latest) SDK for python based apps running within octue.
1311

1412

1513
## Developer notes
1614

17-
**Documentation for use of the library is [here](https://{{library_name}}.readthedocs.io). You don't need to pay attention to the following unless you plan to develop {{library_name}} itself.**
18-
19-
### Getting started
20-
21-
1. Click 'use this template' to the top right, and away you go.
22-
2. Search for `{{` in your new repository. Do search and replace for the various terms - it's obvious what they are, like replace `{{github_username}}` with your github username!
23-
3. Set up the license you need in `LICENSE`.
24-
4. If you need to deploy to pypi, you have to do the first deploy manually - travis can't do that for you. [See the packaging instructions](https://packaging.python.org/tutorials/distributing-packages/#uploading-your-project-to-pypi).
15+
**Documentation for use of the library is [here](https://octue-python-sdk.readthedocs.io). You don't need to pay attention to the following unless you plan to develop `octue-sdk-python` itself.**
2516

2617
### Pre-Commit
2718

docs/requirements.txt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11

22
# Required by the python script for building documentation
3-
Sphinx==1.8.3
4-
sphinx-rtd-theme==0.4.2
5-
sphinx-tabs==1.1.10
6-
breathe==4.11.1
7-
exhale==0.2.1
3+
Sphinx>=2,<3
4+
sphinx-rtd-theme==0.5.0
5+
sphinx-tabs==1.2.1

docs/source/child_services.rst

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
.. _child_services:
2+
3+
==============
4+
Child services
5+
==============
6+
7+
When a Twine file is written, there is the option to include children (i.e. child services or child digital twins) so
8+
the main or parent service can communicate with them to ask them "questions". A question is a set of input
9+
values and/or an input manifest in the form the child's Twine specifies. When a question is asked, the parent can expect
10+
an answer, which is a set of output values and/or an output manifest, again in the form specified by the child's Twine.
11+
12+
There can be:
13+
14+
- Any number of children
15+
- Any number of questions asked to each child
16+
17+
Further, a child can have its own children that it asks questions to. There is no limit to this as long as the tree of
18+
services forms a directed acyclical graph (DAG) - i.e. there are no loops and no children ask their parents any
19+
questions.
20+
21+
22+
-------------------------
23+
Example usage in your app
24+
-------------------------
25+
26+
Assuming you have specified which children you would like to use in your ``twine.json`` file (see below for an example),
27+
you can ask children questions in your ``app.py`` file as follows:
28+
29+
.. code-block:: python
30+
31+
answer_1 = analysis.children["child_1"].ask(input_values=analysis.input_values, timeout=None)
32+
answer_2 = analysis.children["child_2"].ask(input_values=analysis.input_values, timeout=None)
33+
34+
>>> answer_1
35+
{
36+
'output_values': <output values in form specified by child twine.json>,
37+
'output_manifest': <output manifest in form specified by child twine.json>
38+
}
39+
40+
41+
A timeout (measured in seconds) can be set for how long you are willing to wait for an answer, but bear in mind that the
42+
question has to reach the child, the child has to run its own analysis on the inputs sent to it (this most likely
43+
corresponds to the dominant part of the wait time), and the answer has to be send back to the parent. If you are not
44+
sure how long a particular analysis might take, it's best to set the timeout to ``None`` or ask the owner/maintainer of
45+
the child for an estimate.
46+
47+
48+
--------
49+
Backends
50+
--------
51+
52+
The backend specifies which method of communication the child uses (e.g. Google Cloud Pub/Sub), as well as providing
53+
pointers to the credentials and any other parameters necessary to access it. Each child must have its backend
54+
specified explicitly, even if all children use the same one. This is to support the use case where each child uses a
55+
different backend.
56+
57+
To make use of a certain child in ``app.py``, its backend configuration must be specified in ``children.json``. The only
58+
backend currently supported is ``GCPPubSubBackend``, which uses Google Cloud Platform's publisher/subscriber service.
59+
60+
61+
--------------------------
62+
Example children.json file
63+
--------------------------
64+
65+
To access children in ``app.py``, they must be specified in ``children.json``, which is by default looked for in
66+
``<data_dir>/configuration/children.json``:
67+
68+
.. code-block:: javascript
69+
70+
[
71+
{
72+
"key": "wind_speed",
73+
"id": "7b9d07fa-6bcd-4ec3-a331-69f737a15751",
74+
"backend": {
75+
"name": "GCPPubSubBackend",
76+
"project_name": "<google_cloud_project_name>",
77+
"credentials_filename": "<absolute/path/to/credentials_file.json>"
78+
}
79+
},
80+
{
81+
"key": "elevation",
82+
"id": "8dgd07fa-6bcd-4ec3-a331-69f737a15332",
83+
"backend": {
84+
"name": "GCPPubSubBackend",
85+
"project_name": "<google_cloud_project_name>",
86+
"credentials_filename": "<absolute/path/to/credentials_file.json>"
87+
}
88+
}
89+
]
90+
91+
92+
-------------------------------------------
93+
Example children field in a twine.json file
94+
-------------------------------------------
95+
96+
The children field must also be present in the ``twine.json`` file:
97+
98+
.. code-block:: javascript
99+
100+
{
101+
...
102+
"children": [
103+
{
104+
"key": "wind_speed",
105+
"purpose": "A service that returns the average wind speed for a given latitude and longitude.",
106+
"notes": "Some notes.",
107+
"filters": "tags:wind_speed"
108+
},
109+
{
110+
"key": "elevation",
111+
"purpose": "A service that returns the elevation for a given latitude and longitude.",
112+
"notes": "Some notes.",
113+
"filters": "tags:elevation"
114+
}
115+
],
116+
...
117+
}
118+
119+
120+
------------------------------------
121+
Starting a child/service as a server
122+
------------------------------------
123+
124+
For a parent to ask a child questions, the child must already be running as a server. The person/organisation
125+
responsible for the child must start it as a server if it is to be able to answer questions.
126+
127+
To start a service as a server, the command line interface (CLI) can be used:
128+
129+
.. code-block:: bash
130+
131+
octue-app start \
132+
--app-dir=<path/to/app_directory> \
133+
--twine=<path/to/twine.json> \
134+
--config-dir=<path/to/configuration> \
135+
--service-id=<UUID of service>
136+
137+
You can choose a random UUID for the service ID, but it must be unique across all services. It must also stay the same
138+
once it has been created so that Scientists and other services can know which service is which and communicate with the
139+
correct ones. We recommend registering your service with Octue if you want others to be able to use it easily (and, if
140+
allowed, look it up), and also so that its ID is reserved permanently.
141+
142+
**Note:** We will be automating this process soon. In the meantime, please contact us to register service IDs.
143+
144+
145+
--------------------------------------------------------------------------
146+
See services communicate in real time: running the child services template
147+
--------------------------------------------------------------------------
148+
149+
1. Contact Octue to request a Google Cloud Platform service account credentials file.
150+
151+
2. Save this file locally and create a ``GCP_SERVICE_ACCOUNT`` environment variable whose value is the file's absolute path. This variable must be available to all three terminal windows used to run the template - see below for one method of doing this. **IMPORTANT**: Do not commit this or any other credentials or credentials file to git, GitHub, or any other version control software or website - doing so opens you, your systems and equipment, and our systems and equipment up to hackers and cyber attack.
152+
153+
3. From the repository root, start the elevation service as a server in a terminal window:
154+
155+
.. code-block:: bash
156+
157+
GCP_SERVICE_ACCOUNT=</absolute/path/to/gcp_credentials.json> octue-app --log-level=debug --show-twined-logs
158+
start \
159+
--app-dir=octue/templates/template-child-services/elevation_service \
160+
--twine=octue/templates/template-child-services/elevation_service/twine.json \
161+
--config-dir=octue/templates/template-child-services/elevation_service/data/configuration \
162+
--service-id=8dgd07fa-6bcd-4ec3-a331-69f737a15332
163+
164+
4. In another terminal window, start the wind speeds service as a server:
165+
166+
.. code-block:: bash
167+
168+
GCP_SERVICE_ACCOUNT=</absolute/path/to/gcp_credentials.json> octue-app --log-level=debug --show-twined-logs \
169+
start \
170+
--app-dir=octue/templates/template-child-services/wind_speed_service \
171+
--twine=octue/templates/template-child-services/wind_speed_service/twine.json \
172+
--config-dir=octue/templates/template-child-services/wind_speed_service/data/configuration \
173+
--service-id=7b9d07fa-6bcd-4ec3-a331-69f737a15751
174+
175+
5. In a third terminal window, run the parent app (don't start it as a server):
176+
177+
.. code-block:: bash
178+
179+
GCP_SERVICE_ACCOUNT=</absolute/path/to/gcp_credentials.json> octue-app --log-level=debug --show-twined-logs \
180+
run \
181+
--app-dir=octue/templates/template-child-services/parent_service \
182+
--twine=octue/templates/template-child-services/parent_service/twine.json \
183+
--data-dir=octue/templates/template-child-services/parent_service/data
184+
185+
6. Watch the logs to observe the three services communicate with each other via the cloud in real time. When finished, you will find the output values of the parent in ``octue/templates/template-child-services/parent_service/data/output/values.json``

docs/source/dataset.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Filtering files in a ``Dataset``
2020
You can filter a ``Dataset``'s files as follows:
2121

2222
.. code-block:: python
23+
2324
dataset = Dataset(
2425
files=[
2526
Datafile(path="path-within-dataset/my_file.csv", tags="one a:2 b:3 all"),
@@ -37,6 +38,7 @@ You can filter a ``Dataset``'s files as follows:
3738
You can also chain filters indefinitely:
3839

3940
.. code-block:: python
41+
4042
dataset.files.filter(filter_name="name__ends_with", filter_value=".csv").filter("tags__contains", filter_value="a:2")
4143
>>> <FilterSet({<Datafile('my_file.csv')>})>
4244

docs/source/filter_containers.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ Filtering
3030

3131
Filters are named as ``"<name_of_attribute_to_check>__<filter_action>"``, and any attribute of a member of the
3232
``FilterSet`` whose type or interface is supported can be filtered.
33+
3334
.. code-block:: python
35+
3436
filter_set = FilterSet(
3537
{Datafile(path="my_file.csv"), Datafile(path="your_file.txt"), Datafile(path="another_file.csv")}
3638
)
@@ -119,7 +121,9 @@ Ordering
119121
As sets are inherently orderless, ordering a ``FilterSet`` results in a new ``FilterList``, which has the same extra
120122
methods and behaviour as a ``FilterSet``, but is based on the ``list`` type instead - meaning it can be ordered and
121123
indexed etc. A ``FilterSet`` or ``FilterList`` can be ordered by any of the attributes of its members:
124+
122125
.. code-block:: python
126+
123127
filter_set.order_by("name")
124128
>>> <FilterList([<Datafile('another_file.csv')>, <Datafile('my_file.csv')>, <Datafile(path="your_file.txt")>])>
125129

docs/source/index.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
=================
1+
==================
22
Octue SDK (Python)
3-
=================
3+
==================
44

55

66
We use the `GitHub Issue Tracker <https://github.com/octue/octue-sdk-python>`_
@@ -17,6 +17,7 @@ Not all of Octue's API functionality is implemented in the SDK yet, we're active
1717
dataset
1818
filter_containers
1919
analysis_objects
20+
child_services
2021
license
2122
version_history
2223
bibliography

docs/source/installation.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Installation
77
To use the Octue SDK from within your Octue Python application, simply add:
88

99
.. code-block::
10+
1011
octue==x.y.z
1112
1213
to your ``requirements.txt`` file, where x.y.z. is your preferred (we recommend the latest stable) version of the SDK.

octue/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import logging
2+
13
from .cli import octue_cli
24
from .logging_handlers import LOG_FORMAT
35
from .runner import Runner
46

57

68
__all__ = "LOG_FORMAT", "octue_cli", "Runner"
9+
package_logger = logging.getLogger(__name__)

0 commit comments

Comments
 (0)