Skip to content

Commit e4da82e

Browse files
authored
MRG: Merge pull request #123 from octue/release/0.1.11
Release/0.1.11
2 parents 6b9e4b2 + 858a7d4 commit e4da82e

File tree

11 files changed

+112
-66
lines changed

11 files changed

+112
-66
lines changed

.github/workflows/python-ci.yml

-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ jobs:
3838
env:
3939
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GCP_SERVICE_ACCOUNT }}
4040
TEST_PROJECT_NAME: ${{ secrets.TEST_PROJECT_NAME }}
41-
TEST_BUCKET_NAME: ${{ secrets.TEST_BUCKET_NAME }}
4241
run: |
4342
coverage run --source octue -m unittest discover
4443
coverage report --show-missing

README.md

+27-1
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,35 @@
99

1010
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.
1111

12+
## Installation and usage
13+
For usage as a scientist or engineer, run the following command in your environment:
14+
```shell
15+
pip install octue
16+
```
17+
18+
The command line interface (CLI) can then be accessed via:
19+
```shell
20+
octue-app --help
21+
```
1222

1323
## Developer notes
1424

25+
### Installation
26+
For development, run the following from the repository root, which will editably install the package:
27+
```bash
28+
pip install -r requirements-dev.txt
29+
```
30+
31+
### Testing
32+
These environment variables need to be set to run the tests:
33+
* `GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service/account/file.json`
34+
* `TEST_PROJECT_NAME=<name-of-google-cloud-project-to-run-pub-sub-tests-on>`
35+
36+
Then, from the repository root, run
37+
```bash
38+
python3 -m unittest
39+
```
40+
1541
**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.**
1642

1743
### Pre-Commit
@@ -78,7 +104,7 @@ roadmap, into which you can make your PR. We'll help review the changes and impr
78104
The process for creating a new release is as follows:
79105

80106
1. Check out a branch for the next version, called `vX.Y.Z`
81-
2. Create a Pull Request into the `master` branch.
107+
2. Create a Pull Request into the `main` branch.
82108
3. Undertake your changes, committing and pushing to branch `vX.Y.Z`
83109
4. Ensure that documentation is updated to match changes, and increment the changelog. **Pull requests which do not update documentation will be refused.**
84110
5. Ensure that test coverage is sufficient. **Pull requests that decrease test coverage will be refused.**

octue/utils/cloud/emulators.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class GoogleCloudStorageEmulator:
1313
:return None:
1414
"""
1515

16-
def __init__(self, host="localhost", port=9090, in_memory=True, default_bucket=os.environ["TEST_BUCKET_NAME"]):
16+
def __init__(self, host="localhost", port=9090, in_memory=True, default_bucket=None):
1717
self._server = create_server(host, port, in_memory=in_memory, default_bucket=default_bucket)
1818

1919
def __enter__(self):
@@ -64,7 +64,7 @@ class GoogleCloudStorageEmulatorTestResultModifier:
6464

6565
STORAGE_EMULATOR_HOST_ENVIRONMENT_VARIABLE_NAME = "STORAGE_EMULATOR_HOST"
6666

67-
def __init__(self, host="localhost", in_memory=True, default_bucket_name=os.environ["TEST_BUCKET_NAME"]):
67+
def __init__(self, host="localhost", in_memory=True, default_bucket_name=None):
6868
port = get_free_tcp_port()
6969
self.storage_emulator_host = f"http://{host}:{port}"
7070

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
setup(
1919
name="octue",
20-
version="0.1.10",
20+
version="0.1.11",
2121
py_modules=["cli"],
2222
install_requires=[
2323
"blake3>=0.1.8",

tests/__init__.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55

66

77
TESTS_DIR = os.path.dirname(__file__)
8+
TEST_PROJECT_NAME = os.environ["TEST_PROJECT_NAME"]
9+
TEST_BUCKET_NAME = "octue-test-bucket"
810

9-
10-
test_result_modifier = GoogleCloudStorageEmulatorTestResultModifier()
11+
test_result_modifier = GoogleCloudStorageEmulatorTestResultModifier(default_bucket_name=TEST_BUCKET_NAME)
1112
setattr(unittest.TestResult, "startTestRun", test_result_modifier.startTestRun)
1213
setattr(unittest.TestResult, "stopTestRun", test_result_modifier.stopTestRun)

tests/resources/communication/google_pub_sub/test_service.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import concurrent.futures
2-
import os
32
import time
43
import uuid
54
import google.api_core.exceptions
@@ -8,6 +7,7 @@
87
from octue.resources.communication.google_pub_sub.service import OCTUE_NAMESPACE, Service
98
from octue.resources.communication.service_backends import GCPPubSubBackend
109
from octue.resources.manifest import Manifest
10+
from tests import TEST_PROJECT_NAME
1111
from tests.base import BaseTestCase
1212

1313

@@ -34,7 +34,7 @@ class TestService(BaseTestCase):
3434
(GCP), or a local emulator."""
3535

3636
BACKEND = GCPPubSubBackend(
37-
project_name=os.environ["TEST_PROJECT_NAME"], credentials_environment_variable="GOOGLE_APPLICATION_CREDENTIALS"
37+
project_name=TEST_PROJECT_NAME, credentials_environment_variable="GOOGLE_APPLICATION_CREDENTIALS"
3838
)
3939

4040
@staticmethod

tests/resources/test_datafile.py

+11-12
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
from octue.mixins import MixinBase, Pathable
99
from octue.resources import Datafile
1010
from octue.resources.tag import TagSet
11-
from octue.utils.cloud.storage.client import OCTUE_MANAGED_CREDENTIALS, GoogleCloudStorageClient
11+
from octue.utils.cloud.storage.client import GoogleCloudStorageClient
12+
from tests import TEST_BUCKET_NAME, TEST_PROJECT_NAME
1213
from ..base import BaseTestCase
1314

1415

@@ -135,21 +136,19 @@ def test_hashes_for_the_same_datafile_are_the_same(self):
135136

136137
def test_from_cloud_with_bare_file(self):
137138
"""Test that a Datafile can be constructed from a file on Google Cloud storage with no custom metadata."""
138-
project_name = os.environ["TEST_PROJECT_NAME"]
139-
bucket_name = os.environ["TEST_BUCKET_NAME"]
140139
path_in_bucket = "file_to_upload.txt"
141140

142-
GoogleCloudStorageClient(project_name=project_name, credentials=OCTUE_MANAGED_CREDENTIALS).upload_from_string(
141+
GoogleCloudStorageClient(project_name=TEST_PROJECT_NAME).upload_from_string(
143142
string=json.dumps({"height": 32}),
144-
bucket_name=bucket_name,
143+
bucket_name=TEST_BUCKET_NAME,
145144
path_in_bucket=path_in_bucket,
146145
)
147146

148147
datafile = Datafile.from_cloud(
149-
project_name=project_name, bucket_name=bucket_name, datafile_path=path_in_bucket, timestamp=None
148+
project_name=TEST_PROJECT_NAME, bucket_name=TEST_BUCKET_NAME, datafile_path=path_in_bucket, timestamp=None
150149
)
151150

152-
self.assertEqual(datafile.path, f"gs://{bucket_name}/{path_in_bucket}")
151+
self.assertEqual(datafile.path, f"gs://{TEST_BUCKET_NAME}/{path_in_bucket}")
153152
self.assertEqual(datafile.cluster, 0)
154153
self.assertEqual(datafile.sequence, None)
155154
self.assertEqual(datafile.tags, TagSet())
@@ -159,8 +158,6 @@ def test_from_cloud_with_bare_file(self):
159158

160159
def test_from_cloud_with_datafile(self):
161160
"""Test that a Datafile can be constructed from a file on Google Cloud storage with custom metadata."""
162-
project_name = os.environ["TEST_PROJECT_NAME"]
163-
bucket_name = os.environ["TEST_BUCKET_NAME"]
164161
path_in_bucket = "file_to_upload.txt"
165162

166163
with tempfile.TemporaryDirectory() as temporary_directory:
@@ -172,13 +169,15 @@ def test_from_cloud_with_datafile(self):
172169
datafile = Datafile(
173170
timestamp=None, path=file_0_path, cluster=0, sequence=1, tags={"blah:shah:nah", "blib", "glib"}
174171
)
175-
datafile.to_cloud(project_name=project_name, bucket_name=bucket_name, path_in_bucket=path_in_bucket)
172+
datafile.to_cloud(
173+
project_name=TEST_PROJECT_NAME, bucket_name=TEST_BUCKET_NAME, path_in_bucket=path_in_bucket
174+
)
176175

177176
persisted_datafile = Datafile.from_cloud(
178-
project_name=project_name, bucket_name=bucket_name, datafile_path=path_in_bucket
177+
project_name=TEST_PROJECT_NAME, bucket_name=TEST_BUCKET_NAME, datafile_path=path_in_bucket
179178
)
180179

181-
self.assertEqual(persisted_datafile.path, f"gs://{bucket_name}/{path_in_bucket}")
180+
self.assertEqual(persisted_datafile.path, f"gs://{TEST_BUCKET_NAME}/{path_in_bucket}")
182181
self.assertEqual(persisted_datafile.id, datafile.id)
183182
self.assertEqual(persisted_datafile.hash_value, datafile.hash_value)
184183
self.assertEqual(persisted_datafile.cluster, datafile.cluster)

tests/resources/test_dataset.py

+11-10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from octue.resources.filter_containers import FilterSet
1010
from octue.utils.cloud import storage
1111
from octue.utils.cloud.storage.client import GoogleCloudStorageClient
12+
from tests import TEST_BUCKET_NAME
1213
from tests.base import BaseTestCase
1314

1415

@@ -289,7 +290,6 @@ def test_serialise(self):
289290
def test_from_cloud(self):
290291
"""Test that a Dataset in cloud storage can be accessed."""
291292
project_name = "test-project"
292-
bucket_name = os.environ["TEST_BUCKET_NAME"]
293293

294294
with tempfile.TemporaryDirectory() as output_directory:
295295
file_0_path = os.path.join(output_directory, "file_0.txt")
@@ -309,30 +309,29 @@ def test_from_cloud(self):
309309
},
310310
)
311311

312-
dataset.to_cloud(project_name=project_name, bucket_name=bucket_name, output_directory=output_directory)
312+
dataset.to_cloud(project_name=project_name, bucket_name=TEST_BUCKET_NAME, output_directory=output_directory)
313313

314314
persisted_dataset = Dataset.from_cloud(
315315
project_name=project_name,
316-
bucket_name=bucket_name,
316+
bucket_name=TEST_BUCKET_NAME,
317317
path_to_dataset_directory=storage.path.join(output_directory, dataset.name),
318318
)
319319

320-
self.assertEqual(persisted_dataset.path, f"gs://{bucket_name}{output_directory}/{dataset.name}")
320+
self.assertEqual(persisted_dataset.path, f"gs://{TEST_BUCKET_NAME}{output_directory}/{dataset.name}")
321321
self.assertEqual(persisted_dataset.id, dataset.id)
322322
self.assertEqual(persisted_dataset.name, dataset.name)
323323
self.assertEqual(persisted_dataset.hash_value, dataset.hash_value)
324324
self.assertEqual(persisted_dataset.tags, dataset.tags)
325325
self.assertEqual({file.name for file in persisted_dataset.files}, {file.name for file in dataset.files})
326326

327327
for file in persisted_dataset:
328-
self.assertEqual(file.path, f"gs://{bucket_name}{output_directory}/{dataset.name}/{file.name}")
328+
self.assertEqual(file.path, f"gs://{TEST_BUCKET_NAME}{output_directory}/{dataset.name}/{file.name}")
329329

330330
def test_to_cloud(self):
331331
"""Test that a dataset can be uploaded to the cloud, including all its files and a serialised JSON file of the
332332
Datafile instance.
333333
"""
334334
project_name = "test-project"
335-
bucket_name = os.environ["TEST_BUCKET_NAME"]
336335
output_directory = "my_datasets"
337336

338337
with tempfile.TemporaryDirectory() as temporary_directory:
@@ -352,24 +351,26 @@ def test_to_cloud(self):
352351
}
353352
)
354353

355-
dataset.to_cloud(project_name, bucket_name, output_directory)
354+
dataset.to_cloud(project_name, TEST_BUCKET_NAME, output_directory)
356355

357356
storage_client = GoogleCloudStorageClient(project_name)
358357

359358
persisted_file_0 = storage_client.download_as_string(
360-
bucket_name=bucket_name, path_in_bucket=storage.path.join(output_directory, dataset.name, "file_0.txt")
359+
bucket_name=TEST_BUCKET_NAME,
360+
path_in_bucket=storage.path.join(output_directory, dataset.name, "file_0.txt"),
361361
)
362362

363363
self.assertEqual(persisted_file_0, "[1, 2, 3]")
364364

365365
persisted_file_1 = storage_client.download_as_string(
366-
bucket_name=bucket_name, path_in_bucket=storage.path.join(output_directory, dataset.name, "file_1.txt")
366+
bucket_name=TEST_BUCKET_NAME,
367+
path_in_bucket=storage.path.join(output_directory, dataset.name, "file_1.txt"),
367368
)
368369
self.assertEqual(persisted_file_1, "[4, 5, 6]")
369370

370371
persisted_dataset = json.loads(
371372
storage_client.download_as_string(
372-
bucket_name=bucket_name,
373+
bucket_name=TEST_BUCKET_NAME,
373374
path_in_bucket=storage.path.join(output_directory, dataset.name, "dataset.json"),
374375
)
375376
)

tests/resources/test_manifest.py

+13-11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from octue.resources import Datafile, Dataset, Manifest
77
from octue.utils.cloud import storage
88
from octue.utils.cloud.storage.client import GoogleCloudStorageClient
9+
from tests import TEST_BUCKET_NAME
910
from tests.base import BaseTestCase
1011

1112

@@ -26,7 +27,6 @@ def test_hashes_for_the_same_manifest_are_the_same(self):
2627
def test_to_cloud(self):
2728
"""Test that a manifest can be uploaded to the cloud as a serialised JSON file of the Manifest instance. """
2829
project_name = "test-project"
29-
bucket_name = os.environ["TEST_BUCKET_NAME"]
3030

3131
with tempfile.TemporaryDirectory() as output_directory:
3232
file_0_path = os.path.join(output_directory, "file_0.txt")
@@ -49,12 +49,14 @@ def test_to_cloud(self):
4949
manifest = Manifest(datasets=[dataset], keys={"my-dataset": 0})
5050

5151
manifest.to_cloud(
52-
project_name, bucket_name, path_to_manifest_file=storage.path.join(output_directory, "manifest.json")
52+
project_name,
53+
TEST_BUCKET_NAME,
54+
path_to_manifest_file=storage.path.join(output_directory, "manifest.json"),
5355
)
5456

5557
persisted_manifest = json.loads(
5658
GoogleCloudStorageClient(project_name).download_as_string(
57-
bucket_name=bucket_name,
59+
bucket_name=TEST_BUCKET_NAME,
5860
path_in_bucket=storage.path.join(output_directory, "manifest.json"),
5961
)
6062
)
@@ -65,7 +67,6 @@ def test_to_cloud(self):
6567
def test_to_cloud_without_storing_datasets(self):
6668
"""Test that a manifest can be uploaded to the cloud as a serialised JSON file of the Manifest instance. """
6769
project_name = "test-project"
68-
bucket_name = os.environ["TEST_BUCKET_NAME"]
6970

7071
with tempfile.TemporaryDirectory() as output_directory:
7172
file_0_path = os.path.join(output_directory, "file_0.txt")
@@ -90,14 +91,14 @@ def test_to_cloud_without_storing_datasets(self):
9091

9192
manifest.to_cloud(
9293
project_name,
93-
bucket_name,
94+
TEST_BUCKET_NAME,
9495
path_to_manifest_file=storage.path.join(output_directory, "manifest.json"),
9596
store_datasets=False,
9697
)
9798

9899
persisted_manifest = json.loads(
99100
GoogleCloudStorageClient(project_name).download_as_string(
100-
bucket_name=bucket_name,
101+
bucket_name=TEST_BUCKET_NAME,
101102
path_in_bucket=storage.path.join(output_directory, "manifest.json"),
102103
)
103104
)
@@ -108,7 +109,6 @@ def test_to_cloud_without_storing_datasets(self):
108109
def test_from_cloud(self):
109110
"""Test that a Manifest can be instantiated from the cloud."""
110111
project_name = "test-project"
111-
bucket_name = os.environ["TEST_BUCKET_NAME"]
112112

113113
with tempfile.TemporaryDirectory() as output_directory:
114114
file_0_path = os.path.join(output_directory, "file_0.txt")
@@ -130,16 +130,18 @@ def test_from_cloud(self):
130130

131131
manifest = Manifest(datasets=[dataset], keys={"my-dataset": 0})
132132
manifest.to_cloud(
133-
project_name, bucket_name, path_to_manifest_file=storage.path.join(output_directory, "manifest.json")
133+
project_name,
134+
TEST_BUCKET_NAME,
135+
path_to_manifest_file=storage.path.join(output_directory, "manifest.json"),
134136
)
135137

136138
persisted_manifest = Manifest.from_cloud(
137139
project_name=project_name,
138-
bucket_name=bucket_name,
140+
bucket_name=TEST_BUCKET_NAME,
139141
path_to_manifest_file=storage.path.join(output_directory, "manifest.json"),
140142
)
141143

142-
self.assertEqual(persisted_manifest.path, f"gs://{bucket_name}{output_directory}/manifest.json")
144+
self.assertEqual(persisted_manifest.path, f"gs://{TEST_BUCKET_NAME}{output_directory}/manifest.json")
143145
self.assertEqual(persisted_manifest.id, manifest.id)
144146
self.assertEqual(persisted_manifest.hash_value, manifest.hash_value)
145147
self.assertEqual(persisted_manifest.keys, manifest.keys)
@@ -148,6 +150,6 @@ def test_from_cloud(self):
148150
)
149151

150152
for dataset in persisted_manifest.datasets:
151-
self.assertEqual(dataset.path, f"gs://{bucket_name}{output_directory}/{dataset.name}")
153+
self.assertEqual(dataset.path, f"gs://{TEST_BUCKET_NAME}{output_directory}/{dataset.name}")
152154
self.assertTrue(len(dataset.files), 2)
153155
self.assertTrue(all(isinstance(file, Datafile) for file in dataset.files))

0 commit comments

Comments
 (0)