diff --git a/django_twined/models/service_revisions.py b/django_twined/models/service_revisions.py index 3f8776a..82fffc2 100644 --- a/django_twined/models/service_revisions.py +++ b/django_twined/models/service_revisions.py @@ -5,6 +5,7 @@ from django.db import models, transaction from django_gcp.events.utils import get_event_url from octue.cloud.pub_sub.service import Service +from octue.cloud.service_id import convert_service_id_to_pub_sub_form from octue.resources.service_backends import get_backend from .service_usage_events import QUESTION_RESPONSE_UPDATED @@ -64,6 +65,8 @@ class AbstractServiceRevision(models.Model): namespace = models.SlugField( max_length=80, default=get_default_namespace, + blank=False, + null=False, help_text="The organisation namespace, eg 'octue'", ) @@ -75,6 +78,7 @@ class AbstractServiceRevision(models.Model): max_length=80, default=get_default_tag, blank=False, + null=False, help_text="The service revision tag that helps to identify the unique deployment", ) @@ -96,52 +100,35 @@ class Meta: ), ] - @property - def has_tag(self): - """Return true if the instance has a tag""" - return (self.tag is not None) and (len(self.tag) > 0) - - @property - def has_namespace(self): - """Return true if the instance has a namespace""" - return (self.namespace is not None) and (len(self.namespace) > 0) - @property def sruid(self): """Return the Service Revision Unique Identifier - Comprises the namespace, name, version, and tag parameters that - together uniquely identify a revision (e.g. for the purposes of - addressing). + Comprises the namespace, name, version, and tag parameters that together uniquely identify a revision (e.g. for + the purposes of addressing). - Using docker image labeling as inspiration, this looks like - octue/example-service:0.1.2 or octue/example-service:my-branch - or octue/example-service:0.1.2-r1 enabling both routing to specific - revisions and things like branches for review + Using docker image labeling as inspiration, this looks like octue/example-service:0.1.2 or + octue/example-service:my-branch or octue/example-service:0.1.2-r1 enabling both routing to specific revisions + and things like branches for review. """ - tag = f":{self.tag}" if self.has_tag else "" - - namespace = f"{self.namespace}/" if self.has_namespace else "" - - return f"{namespace}{self.name}{tag}" - - @property - def _partial_topic(self): - """TODO replace this once the service id has been properly sorted out on the octue side - currently this is used to botch the service_id value so that it comes out with the correct topic name format""" - tag = f".{self.tag.replace('.', '-')}" if self.has_tag else "" - namespace = f"{self.namespace}." if self.has_namespace else "" - return f"{namespace}{self.name}{tag}" + return f"{self.namespace}/{self.name}:{self.tag}" @property def topic(self): - """Return the octue GCP topic address string""" - tag = f".{self.tag}" if self.has_tag else "" - namespace = f"{self.namespace}." if self.has_namespace else "" - return f"octue.services.{namespace}{self.name}{tag}" + """Return the octue GCP topic address string. + + :return str: + """ + return "octue.services." + convert_service_id_to_pub_sub_form(self.sruid) def ask( - self, question_id, input_values=None, input_manifest=None, push_url=None, asker_name="django-twined", **kwargs + self, + question_id, + input_values=None, + input_manifest=None, + push_url=None, + asker_name="django-twined", + **kwargs, ): """Ask a question of this service revision @@ -166,7 +153,6 @@ def ask( ``` """ - if push_url is None: push_url = get_event_url( event_kind=QUESTION_RESPONSE_UPDATED, @@ -178,13 +164,11 @@ def ask( base_url=settings.TWINED_BASE_URL, ) - backend = get_backend()( - project_name=self.project_name, - ) + backend = get_backend()(project_name=self.project_name) + asker = Service(backend=backend, name=asker_name) - asker = Service(backend, name=asker_name) subscription, _ = asker.ask( - service_id=self._partial_topic, # TODO REFACTOR REQUEST Tidy up in newer versions of octue to give to correct topic name + service_id=self.sruid, question_uuid=str(question_id), input_values=input_values, input_manifest=input_manifest, diff --git a/poetry.lock b/poetry.lock index a0fe900..272e109 100644 --- a/poetry.lock +++ b/poetry.lock @@ -459,30 +459,34 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "41.0.1" +version = "41.0.2" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-41.0.1-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:f73bff05db2a3e5974a6fd248af2566134d8981fd7ab012e5dd4ddb1d9a70699"}, - {file = "cryptography-41.0.1-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:1a5472d40c8f8e91ff7a3d8ac6dfa363d8e3138b961529c996f3e2df0c7a411a"}, - {file = "cryptography-41.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fa01527046ca5facdf973eef2535a27fec4cb651e4daec4d043ef63f6ecd4ca"}, - {file = "cryptography-41.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b46e37db3cc267b4dea1f56da7346c9727e1209aa98487179ee8ebed09d21e43"}, - {file = "cryptography-41.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d198820aba55660b4d74f7b5fd1f17db3aa5eb3e6893b0a41b75e84e4f9e0e4b"}, - {file = "cryptography-41.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:948224d76c4b6457349d47c0c98657557f429b4e93057cf5a2f71d603e2fc3a3"}, - {file = "cryptography-41.0.1-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:059e348f9a3c1950937e1b5d7ba1f8e968508ab181e75fc32b879452f08356db"}, - {file = "cryptography-41.0.1-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:b4ceb5324b998ce2003bc17d519080b4ec8d5b7b70794cbd2836101406a9be31"}, - {file = "cryptography-41.0.1-cp37-abi3-win32.whl", hash = "sha256:8f4ab7021127a9b4323537300a2acfb450124b2def3756f64dc3a3d2160ee4b5"}, - {file = "cryptography-41.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:1fee5aacc7367487b4e22484d3c7e547992ed726d14864ee33c0176ae43b0d7c"}, - {file = "cryptography-41.0.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9a6c7a3c87d595608a39980ebaa04d5a37f94024c9f24eb7d10262b92f739ddb"}, - {file = "cryptography-41.0.1-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5d092fdfedaec4cbbffbf98cddc915ba145313a6fdaab83c6e67f4e6c218e6f3"}, - {file = "cryptography-41.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a8e6c2de6fbbcc5e14fd27fb24414507cb3333198ea9ab1258d916f00bc3039"}, - {file = "cryptography-41.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cb33ccf15e89f7ed89b235cff9d49e2e62c6c981a6061c9c8bb47ed7951190bc"}, - {file = "cryptography-41.0.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f0ff6e18d13a3de56f609dd1fd11470918f770c6bd5d00d632076c727d35485"}, - {file = "cryptography-41.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7bfc55a5eae8b86a287747053140ba221afc65eb06207bedf6e019b8934b477c"}, - {file = "cryptography-41.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:eb8163f5e549a22888c18b0d53d6bb62a20510060a22fd5a995ec8a05268df8a"}, - {file = "cryptography-41.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8dde71c4169ec5ccc1087bb7521d54251c016f126f922ab2dfe6649170a3b8c5"}, - {file = "cryptography-41.0.1.tar.gz", hash = "sha256:d34579085401d3f49762d2f7d6634d6b6c2ae1242202e860f4d26b046e3a1006"}, + {file = "cryptography-41.0.2-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:01f1d9e537f9a15b037d5d9ee442b8c22e3ae11ce65ea1f3316a41c78756b711"}, + {file = "cryptography-41.0.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:079347de771f9282fbfe0e0236c716686950c19dee1b76240ab09ce1624d76d7"}, + {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:439c3cc4c0d42fa999b83ded80a9a1fb54d53c58d6e59234cfe97f241e6c781d"}, + {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f14ad275364c8b4e525d018f6716537ae7b6d369c094805cae45300847e0894f"}, + {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:84609ade00a6ec59a89729e87a503c6e36af98ddcd566d5f3be52e29ba993182"}, + {file = "cryptography-41.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:49c3222bb8f8e800aead2e376cbef687bc9e3cb9b58b29a261210456a7783d83"}, + {file = "cryptography-41.0.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d73f419a56d74fef257955f51b18d046f3506270a5fd2ac5febbfa259d6c0fa5"}, + {file = "cryptography-41.0.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:2a034bf7d9ca894720f2ec1d8b7b5832d7e363571828037f9e0c4f18c1b58a58"}, + {file = "cryptography-41.0.2-cp37-abi3-win32.whl", hash = "sha256:d124682c7a23c9764e54ca9ab5b308b14b18eba02722b8659fb238546de83a76"}, + {file = "cryptography-41.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:9c3fe6534d59d071ee82081ca3d71eed3210f76ebd0361798c74abc2bcf347d4"}, + {file = "cryptography-41.0.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a719399b99377b218dac6cf547b6ec54e6ef20207b6165126a280b0ce97e0d2a"}, + {file = "cryptography-41.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:182be4171f9332b6741ee818ec27daff9fb00349f706629f5cbf417bd50e66fd"}, + {file = "cryptography-41.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7a9a3bced53b7f09da251685224d6a260c3cb291768f54954e28f03ef14e3766"}, + {file = "cryptography-41.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f0dc40e6f7aa37af01aba07277d3d64d5a03dc66d682097541ec4da03cc140ee"}, + {file = "cryptography-41.0.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:674b669d5daa64206c38e507808aae49904c988fa0a71c935e7006a3e1e83831"}, + {file = "cryptography-41.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7af244b012711a26196450d34f483357e42aeddb04128885d95a69bd8b14b69b"}, + {file = "cryptography-41.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9b6d717393dbae53d4e52684ef4f022444fc1cce3c48c38cb74fca29e1f08eaa"}, + {file = "cryptography-41.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:192255f539d7a89f2102d07d7375b1e0a81f7478925b3bc2e0549ebf739dae0e"}, + {file = "cryptography-41.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f772610fe364372de33d76edcd313636a25684edb94cee53fd790195f5989d14"}, + {file = "cryptography-41.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b332cba64d99a70c1e0836902720887fb4529ea49ea7f5462cf6640e095e11d2"}, + {file = "cryptography-41.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9a6673c1828db6270b76b22cc696f40cde9043eb90373da5c2f8f2158957f42f"}, + {file = "cryptography-41.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:342f3767e25876751e14f8459ad85e77e660537ca0a066e10e75df9c9e9099f0"}, + {file = "cryptography-41.0.2.tar.gz", hash = "sha256:7d230bf856164de164ecb615ccc14c7fc6de6906ddd5b491f3af90d3514c925c"}, ] [package.dependencies] @@ -754,13 +758,13 @@ doc = ["Sphinx", "sphinx-rtd-theme", "sphinxcontrib-spelling"] [[package]] name = "faker" -version = "18.13.0" +version = "19.1.0" description = "Faker is a Python package that generates fake data for you." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Faker-18.13.0-py3-none-any.whl", hash = "sha256:801d1a2d71f1fc54d332de2ab19de7452454309937233ea2f7485402882d67b3"}, - {file = "Faker-18.13.0.tar.gz", hash = "sha256:84bcf92bb725dd7341336eea4685df9a364f16f2470c4d29c1d7e6c5fd5a457d"}, + {file = "Faker-19.1.0-py3-none-any.whl", hash = "sha256:4b7d5cd0c898f0b64f88fbf0a35aac66762f2273446ba4a4e459985a2e5c8f8c"}, + {file = "Faker-19.1.0.tar.gz", hash = "sha256:d1eb772faf4a7c458c90b19d3626c40ae3460bd665ad7f5fb7b089e31d1a6dcf"}, ] [package.dependencies] @@ -858,13 +862,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-api-python-client" -version = "2.92.0" +version = "2.93.0" description = "Google API Client Library for Python" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-python-client-2.92.0.tar.gz", hash = "sha256:f38a6e106a7417719715506d36f0a233ec253335e422bda311352866a86c4187"}, - {file = "google_api_python_client-2.92.0-py2.py3-none-any.whl", hash = "sha256:e0b74ed5fa9bdb07a66fb030d3f4cae550ed1c07e23600d86450d3c3c5efae51"}, + {file = "google-api-python-client-2.93.0.tar.gz", hash = "sha256:62ee28e96031a10a1c341f226a75ac6a4f16bdb1d888dc8222b2cdca133d0031"}, + {file = "google_api_python_client-2.93.0-py2.py3-none-any.whl", hash = "sha256:f34abb671afd488bd19d30721ea20fb30d3796ddd825d6f91f26d8c718a9f07d"}, ] [package.dependencies] @@ -876,13 +880,13 @@ uritemplate = ">=3.0.1,<5" [[package]] name = "google-auth" -version = "2.21.0" +version = "2.22.0" description = "Google Authentication Library" optional = false python-versions = ">=3.6" files = [ - {file = "google-auth-2.21.0.tar.gz", hash = "sha256:b28e8048e57727e7cf0e5bd8e7276b212aef476654a09511354aa82753b45c66"}, - {file = "google_auth-2.21.0-py2.py3-none-any.whl", hash = "sha256:da3f18d074fa0f5a7061d99b9af8cee3aa6189c987af7c1b07d94566b6b11268"}, + {file = "google-auth-2.22.0.tar.gz", hash = "sha256:164cba9af4e6e4e40c3a4f90a1a6c12ee56f14c0b4868d1ca91b32826ab334ce"}, + {file = "google_auth-2.22.0-py2.py3-none-any.whl", hash = "sha256:d61d1b40897407b574da67da1a833bdc10d5a11642566e506565d1b1a46ba873"}, ] [package.dependencies] @@ -1658,26 +1662,26 @@ setuptools = "*" [[package]] name = "octue" -version = "0.47.0" +version = "0.47.2" description = "A package providing template applications for data services, and a python SDK to the Octue API." optional = false python-versions = ">=3.7.1,<4.0.0" files = [ - {file = "octue-0.47.0-py3-none-any.whl", hash = "sha256:cbc8f80cc6665718b557cc977b80ad3ee35a23662063b648b444a23b37fcecdd"}, - {file = "octue-0.47.0.tar.gz", hash = "sha256:ffa559f4b2ddc1bc211b749e7e41b0d809cd36554f0e218735e5c717247adc44"}, + {file = "octue-0.47.2-py3-none-any.whl", hash = "sha256:13a22cf613137e0ade12aa46f0242d8dae7f58ca47b85a9a8d76631beb302c59"}, + {file = "octue-0.47.2.tar.gz", hash = "sha256:5077e1fb47c9bb63ca5f55b2e9457b096552c37a029dc8e2df0e2d69ea72531a"}, ] [package.dependencies] click = ">=7,<9" coolname = ">=1.1,<2.0" -Flask = ">=2.2.5,<3" +Flask = ">=2,<3" google-auth = ">=1.27.0,<3" google-cloud-pubsub = ">=2.5,<3.0" google-cloud-secret-manager = ">=2.3,<3.0" google-cloud-storage = ">=1.35.1,<3" google-crc32c = ">=1.1,<2.0" gunicorn = ">=20.1,<21.0" -packaging = ">=20.4,<22" +packaging = ">=20.4" python-dateutil = ">=2.8,<3.0" pyyaml = ">=6,<7" twined = ">=0.5.1,<0.6.0" @@ -1688,18 +1692,15 @@ hdf5 = ["h5py (>=3.6,<4.0)"] [[package]] name = "packaging" -version = "21.3" +version = "23.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, ] -[package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" - [[package]] name = "pika" version = "1.3.2" @@ -1766,13 +1767,13 @@ virtualenv = ">=20.10.0" [[package]] name = "prometheus-client" -version = "0.17.0" +version = "0.17.1" description = "Python client for the Prometheus monitoring system." optional = false python-versions = ">=3.6" files = [ - {file = "prometheus_client-0.17.0-py3-none-any.whl", hash = "sha256:a77b708cf083f4d1a3fb3ce5c95b4afa32b9c521ae363354a4a910204ea095ce"}, - {file = "prometheus_client-0.17.0.tar.gz", hash = "sha256:9c3b26f1535945e85b8934fb374678d263137b78ef85f305b1156c7c881cd11b"}, + {file = "prometheus_client-0.17.1-py3-none-any.whl", hash = "sha256:e537f37160f6807b8202a6fc4764cdd19bac5480ddd3e0d463c3002b34462101"}, + {file = "prometheus_client-0.17.1.tar.gz", hash = "sha256:21e674f39831ae3f8acde238afd9a27a37d0d2fb5a28ea094f0ce25d2cbf2091"}, ] [package.extras] @@ -2976,4 +2977,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.11" -content-hash = "d68144824fed26211e228916ef717e2aee72912bb3902beac83086ae11eadc4e" +content-hash = "23d396cc1bdbff4bbb87105213e31a043941035f212d4a1aa48c2dcf4b768bff" diff --git a/pyproject.toml b/pyproject.toml index 091ade8..7e1dab3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "django-twined" -version = "0.5.1" +version = "0.6.0" description = "A django app to manage octue services" authors = ["Tom Clark "] license = "MIT" @@ -23,7 +23,7 @@ packages = [{ include = "django_twined" },] python = ">=3.9,<3.11" django = ">=3.0,<4.0" channels = ">=3.0,<4.0" -octue = ">=0.39.0,<1" +octue = ">=0.40.0,<1" pika = "^1.2.0" django-gcp = ">=0.7.3,<0.11" django-jsoneditor = "^0.2.2" diff --git a/tests/test_models/test_service_revisions.py b/tests/test_models/test_service_revisions.py index edef7b7..aadda7b 100644 --- a/tests/test_models/test_service_revisions.py +++ b/tests/test_models/test_service_revisions.py @@ -1,7 +1,7 @@ # Disables for testing: # pylint: disable=missing-docstring -from django.test import TestCase, override_settings +from django.test import TestCase from django_twined.models.service_revisions import ServiceRevision, service_revision_is_latest_semantic_version @@ -74,14 +74,6 @@ def test_topic(self): self.assertEqual(sr.topic, "octue.services.large-gibbons.gibbon-analyser.latest") - def test_topic_with_blank_namespace_and_tag(self): - """Ensure that a service revision's topic is correct if there is no namespace or tag.""" - with override_settings(TWINED_DEFAULT_NAMESPACE=""): - with override_settings(TWINED_DEFAULT_TAG=""): - sr = ServiceRevision.objects.create(project_name="gargantuan-gibbons", name="gibbon-analyser") - - self.assertEqual(sr.topic, "octue.services.gibbon-analyser") - def test_create_with_defaults(self): """Ensure that default settings are read for creating default entries in the db""" sr = ServiceRevision.objects.create(name="gibbon-analyser")