diff --git a/docs/nitric/proto/index.html b/docs/nitric/api/const.html
similarity index 91%
rename from docs/nitric/proto/index.html
rename to docs/nitric/api/const.html
index 185a8d4..d5b298f 100644
--- a/docs/nitric/proto/index.html
+++ b/docs/nitric/api/const.html
@@ -4,7 +4,7 @@
-
nitric.proto API documentation
+nitric.api.const API documentation
@@ -19,7 +19,7 @@
-
Module nitric.proto
+
Module nitric.api.const
@@ -43,17 +43,14 @@
Module nitric.proto
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-#
+#
+
+# The maximum number of parent collections a sub-collection can have.
+# This is implemented in the Membrane, but reinforced here for immediate exceptions without a server connection.
+MAX_SUB_COLLECTION_DEPTH = 1
-
@staticmethod
+def from_collection_ref(collectionRef: CollectionRef, documents: Documents) -> CollectionGroupRef:
+ """Return a collection ref as a collection group."""
+ if collectionRef.parent is not None:
+ return CollectionGroupRef(
+ documents,
+ collectionRef.name,
+ CollectionGroupRef.from_collection_ref(
+ collectionRef.parent,
+ documents,
+ ),
+ )
+
+
+
+
Methods
+
+
+def is_sub_collection(self)
+
+
+
Return True if this collection is a sub-collection of a document in another collection.
+
+
+Expand source code
+
+
def is_sub_collection(self):
+ """Return True if this collection is a sub-collection of a document in another collection."""
+ return self.parent is not None
+
+
+
+def query(self, paging_token: Any = None, limit: int = 0, expressions: Union[Expression, List[Expression]] = None) ‑> QueryBuilder
+
+
+
Return a query builder scoped to this collection.
+
+
+Expand source code
+
+
def query(
+ self,
+ paging_token: Any = None,
+ limit: int = 0,
+ expressions: Union[Expression, List[Expression]] = None,
+) -> QueryBuilder:
+ """Return a query builder scoped to this collection."""
+ return QueryBuilder(
+ documents=self._documents,
+ collection=self.to_collection_ref(),
+ paging_token=paging_token,
+ limit=limit,
+ expressions=[expressions] if isinstance(expressions, Expression) else expressions,
+ )
+
+
+
+def sub_collection_depth(self) ‑> int
+
+
+
Return the depth of this collection group, which is a count of the parents above this collection.
+
+
+Expand source code
+
+
def sub_collection_depth(self) -> int:
+ """Return the depth of this collection group, which is a count of the parents above this collection."""
+ if not self.is_sub_collection():
+ return 0
+ else:
+ return self.parent.sub_collection_depth() + 1
+
+
+
+def to_collection_ref(self)
+
+
+
Return this collection group as a collection ref.
+
+
+Expand source code
+
+
def to_collection_ref(self):
+ """Return this collection group as a collection ref."""
+ return CollectionRef(
+ self._documents,
+ self.name,
+ DocumentRef(
+ self._documents,
+ self.parent,
+ NIL_DOC_ID,
+ ),
+ )
class CollectionRef:
+ """A reference to a collection of documents."""
+
+ _documents: Documents
+ name: str
+ parent: Union[DocumentRef, None] = field(default_factory=lambda: None)
+
+ def doc(self, doc_id: str) -> DocumentRef:
+ """Return a reference to a document in the collection."""
+ return DocumentRef(_documents=self._documents, parent=self, id=doc_id)
+
+ def collection(self, name: str) -> CollectionGroupRef:
+ """
+ Return a reference to a sub-collection of this document.
+
+ This is currently only supported to one level of depth.
+ e.g. Documents().collection('a').collection('b').doc('c') is valid,
+ Documents().collection('a').doc('b').collection('c').collection('d') is invalid (1 level too deep).
+ """
+ current_depth = self.sub_collection_depth()
+ if current_depth >= MAX_SUB_COLLECTION_DEPTH:
+ # Collection nesting is only supported to a maximum depth.
+ raise CollectionDepthException(
+ f"sub-collections supported to a depth of {MAX_SUB_COLLECTION_DEPTH}, "
+ f"attempted to create new collection with depth {current_depth + 1}"
+ )
+ return CollectionGroupRef(_documents=self._documents, name=name, parent=self)
+
+ def query(
+ self,
+ paging_token: Any = None,
+ limit: int = 0,
+ expressions: Union[Expression, List[Expression]] = None,
+ ) -> QueryBuilder:
+ """Return a query builder scoped to this collection."""
+ return QueryBuilder(
+ documents=self._documents,
+ collection=self,
+ paging_token=paging_token,
+ limit=limit,
+ expressions=[expressions] if isinstance(expressions, Expression) else expressions,
+ )
+
+ def sub_collection_depth(self) -> int:
+ """Return the depth of this collection, which is a count of the parents above this collection."""
+ if not self.is_sub_collection():
+ return 0
+ else:
+ return self.parent.parent.sub_collection_depth() + 1
+
+ def is_sub_collection(self):
+ """Return True if this collection is a sub-collection of a document in another collection."""
+ return self.parent is not None
Return a reference to a sub-collection of this document.
+
This is currently only supported to one level of depth.
+e.g. Documents().collection('a').collection('b').doc('c') is valid,
+Documents().collection('a').doc('b').collection('c').collection('d') is invalid (1 level too deep).
+
+
+Expand source code
+
+
def collection(self, name: str) -> CollectionGroupRef:
+ """
+ Return a reference to a sub-collection of this document.
+
+ This is currently only supported to one level of depth.
+ e.g. Documents().collection('a').collection('b').doc('c') is valid,
+ Documents().collection('a').doc('b').collection('c').collection('d') is invalid (1 level too deep).
+ """
+ current_depth = self.sub_collection_depth()
+ if current_depth >= MAX_SUB_COLLECTION_DEPTH:
+ # Collection nesting is only supported to a maximum depth.
+ raise CollectionDepthException(
+ f"sub-collections supported to a depth of {MAX_SUB_COLLECTION_DEPTH}, "
+ f"attempted to create new collection with depth {current_depth + 1}"
+ )
+ return CollectionGroupRef(_documents=self._documents, name=name, parent=self)
Return a reference to a document in the collection.
+
+
+Expand source code
+
+
def doc(self, doc_id: str) -> DocumentRef:
+ """Return a reference to a document in the collection."""
+ return DocumentRef(_documents=self._documents, parent=self, id=doc_id)
+
+
+
+def is_sub_collection(self)
+
+
+
Return True if this collection is a sub-collection of a document in another collection.
+
+
+Expand source code
+
+
def is_sub_collection(self):
+ """Return True if this collection is a sub-collection of a document in another collection."""
+ return self.parent is not None
+
+
+
+def query(self, paging_token: Any = None, limit: int = 0, expressions: Union[Expression, List[Expression]] = None) ‑> QueryBuilder
+
+
+
Return a query builder scoped to this collection.
+
+
+Expand source code
+
+
def query(
+ self,
+ paging_token: Any = None,
+ limit: int = 0,
+ expressions: Union[Expression, List[Expression]] = None,
+) -> QueryBuilder:
+ """Return a query builder scoped to this collection."""
+ return QueryBuilder(
+ documents=self._documents,
+ collection=self,
+ paging_token=paging_token,
+ limit=limit,
+ expressions=[expressions] if isinstance(expressions, Expression) else expressions,
+ )
+
+
+
+def sub_collection_depth(self) ‑> int
+
+
+
Return the depth of this collection, which is a count of the parents above this collection.
+
+
+Expand source code
+
+
def sub_collection_depth(self) -> int:
+ """Return the depth of this collection, which is a count of the parents above this collection."""
+ if not self.is_sub_collection():
+ return 0
+ else:
+ return self.parent.parent.sub_collection_depth() + 1
Return the CollectionRef for the collection that contains this document.
+
+
+Expand source code
+
+
@property
+def collection(self) -> CollectionRef:
+ """Return the CollectionRef for the collection that contains this document."""
+ return self._ref.parent
class DocumentRef:
+ """A reference to a document in a collection."""
+
+ _documents: Documents
+ parent: CollectionRef
+ id: str
+
+ def collection(self, name: str) -> CollectionRef:
+ """
+ Return a reference to a sub-collection of this document.
+
+ This is currently only supported to one level of depth.
+ e.g. Documents().collection('a').doc('b').collection('c').doc('d') is valid,
+ Documents().collection('a').doc('b').collection('c').doc('d').collection('e') is invalid (1 level too deep).
+ """
+ current_depth = self.parent.sub_collection_depth()
+ if current_depth >= MAX_SUB_COLLECTION_DEPTH:
+ # Collection nesting is only supported to a maximum depth.
+ raise CollectionDepthException(
+ f"sub-collections supported to a depth of {MAX_SUB_COLLECTION_DEPTH}, "
+ f"attempted to create new collection with depth {current_depth + 1}"
+ )
+ return CollectionRef(_documents=self._documents, name=name, parent=self)
+
+ async def get(self) -> Document:
+ """Retrieve the contents of this document, if it exists."""
+ try:
+ response = await self._documents._stub.get(key=_doc_ref_to_wire(self))
+ return _document_from_wire(documents=self._documents, message=response.document)
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
+
+ async def set(self, content: dict):
+ """
+ Set the contents of this document.
+
+ If the document exists it will be updated, otherwise a new document will be created.
+ """
+ try:
+ await self._documents._stub.set(
+ key=_doc_ref_to_wire(self),
+ content=_struct_from_dict(content),
+ )
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
+
+ async def delete(self):
+ """Delete this document, if it exists."""
+ try:
+ await self._documents._stub.delete(
+ key=_doc_ref_to_wire(self),
+ )
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
Return a reference to a sub-collection of this document.
+
This is currently only supported to one level of depth.
+e.g. Documents().collection('a').doc('b').collection('c').doc('d') is valid,
+Documents().collection('a').doc('b').collection('c').doc('d').collection('e') is invalid (1 level too deep).
+
+
+Expand source code
+
+
def collection(self, name: str) -> CollectionRef:
+ """
+ Return a reference to a sub-collection of this document.
+
+ This is currently only supported to one level of depth.
+ e.g. Documents().collection('a').doc('b').collection('c').doc('d') is valid,
+ Documents().collection('a').doc('b').collection('c').doc('d').collection('e') is invalid (1 level too deep).
+ """
+ current_depth = self.parent.sub_collection_depth()
+ if current_depth >= MAX_SUB_COLLECTION_DEPTH:
+ # Collection nesting is only supported to a maximum depth.
+ raise CollectionDepthException(
+ f"sub-collections supported to a depth of {MAX_SUB_COLLECTION_DEPTH}, "
+ f"attempted to create new collection with depth {current_depth + 1}"
+ )
+ return CollectionRef(_documents=self._documents, name=name, parent=self)
+
+
+
+async def delete(self)
+
+
+
Delete this document, if it exists.
+
+
+Expand source code
+
+
async def delete(self):
+ """Delete this document, if it exists."""
+ try:
+ await self._documents._stub.delete(
+ key=_doc_ref_to_wire(self),
+ )
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
Retrieve the contents of this document, if it exists.
+
+
+Expand source code
+
+
async def get(self) -> Document:
+ """Retrieve the contents of this document, if it exists."""
+ try:
+ response = await self._documents._stub.get(key=_doc_ref_to_wire(self))
+ return _document_from_wire(documents=self._documents, message=response.document)
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
+
+
+
+async def set(self, content: dict)
+
+
+
Set the contents of this document.
+
If the document exists it will be updated, otherwise a new document will be created.
+
+
+Expand source code
+
+
async def set(self, content: dict):
+ """
+ Set the contents of this document.
+
+ If the document exists it will be updated, otherwise a new document will be created.
+ """
+ try:
+ await self._documents._stub.set(
+ key=_doc_ref_to_wire(self),
+ content=_struct_from_dict(content),
+ )
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
+
+
+
+
+
+class Documents
+
+
+
Nitric client for interacting with document collections.
+
This client insulates application code from stack specific event operations or SDKs.
+
Construct a Nitric Document Client.
+
+
+Expand source code
+
+
class Documents(object):
+ """
+ Nitric client for interacting with document collections.
+
+ This client insulates application code from stack specific event operations or SDKs.
+ """
+
+ _stub: DocumentServiceStub
+
+ def __init__(self):
+ """Construct a Nitric Document Client."""
+ self._channel = new_default_channel()
+ self._stub = DocumentServiceStub(channel=self._channel)
+
+ def __del__(self):
+ # close the channel when this client is destroyed
+ if self._channel is not None:
+ self._channel.close()
+
+ def collection(self, name: str) -> CollectionRef:
+ """Return a reference to a document collection."""
+ return CollectionRef(_documents=self, name=name)
+class QueryBuilder
+(documents: Documents, collection: CollectionRef, paging_token: Any = None, limit: int = 0, expressions: List[Expression] = None)
+
+
+
Document query builder for retrieving documents from a collection based on filters.
+
Construct a new QueryBuilder.
+
+
+Expand source code
+
+
class QueryBuilder:
+ """Document query builder for retrieving documents from a collection based on filters."""
+
+ _documents: Documents
+ _collection: CollectionRef
+ _paging_token: Any
+ _limit: int
+ _expressions: List[Expression]
+
+ def __init__(
+ self,
+ documents: Documents,
+ collection: CollectionRef,
+ paging_token: Any = None,
+ limit: int = 0,
+ expressions: List[Expression] = None,
+ ):
+ """Construct a new QueryBuilder."""
+ self._documents = documents
+ self._collection = collection
+ self._paging_token = paging_token
+ self._limit = limit # default to unlimited.
+ if expressions is None:
+ self._expressions = []
+ else:
+ self._expressions = expressions
+
+ def _flat_expressions(self, expressions) -> List[Expression]:
+ """Process possible inputs for .where() into a flattened list of expressions."""
+ if isinstance(expressions, tuple) and len(expressions) == 3 and isinstance(expressions[0], str):
+ # handle the special case where an expression was passed in as its component arguments.
+ # e.g. .where('age', '<', 30) instead of .where(condition('age') > 30)
+ return [Expression(*expressions)]
+ if isinstance(expressions, Expression):
+ # when a single expression is received, wrap in a list and return it
+ return [expressions]
+ else:
+ # flatten lists of lists into single dimension list of expressions
+ exps = []
+ for exp in expressions:
+ exps = exps + self._flat_expressions(exp)
+ return exps
+
+ def where(
+ self,
+ *expressions: Union[
+ Expression, List[Expression], Union[str, Operator, int, bool, Tuple[str, Union[str, Operator], Any]]
+ ],
+ ) -> QueryBuilder:
+ """
+ Add a filter expression to the query.
+
+ :param expressions: a single expression or a set of expression args or a variadic/tuple/list of expressions.
+
+ Examples
+ --------
+ .where('age', '>', 20)
+ .where(condition('age') > 20)
+ .where(condition('age').gt(20))
+ .where(
+ condition('age') > 20,
+ condition('age') < 50,
+ )
+ .where(
+ [
+ condition('age') > 20,
+ condition('age') < 50,
+ ]
+ )
+ .where(
+ ('age', '>', 20),
+ ('age', '<', 50),
+ )
+
+ """
+ for expression in self._flat_expressions(expressions):
+ self._expressions.append(expression)
+ return self
+
+ def page_from(self, token) -> QueryBuilder:
+ """
+ Set the paging token for the query.
+
+ Used when requesting subsequent pages from a query.
+ """
+ self._paging_token = token
+ return self
+
+ def limit(self, limit: int) -> QueryBuilder:
+ """Set the maximum number of results returned by this query."""
+ if limit is None or not isinstance(limit, int) or limit < 0:
+ raise ValueError("limit must be a positive integer or 0 for unlimited.")
+ self._limit = limit
+ return self
+
+ def _expressions_to_wire(self) -> List[ExpressionMessage]:
+ """Return this queries' expressions as a list of their protobuf message representation."""
+ return [expressions._to_wire() for expressions in self._expressions]
+
+ async def stream(self) -> AsyncIterator[Document]:
+ """Return all query results as a stream."""
+ # TODO: add limit, expressions and paging token to query.
+ if self._paging_token is not None:
+ raise ValueError("page_from() should not be used with streamed queries.")
+
+ try:
+ async for result in self._documents._stub.query_stream(
+ collection=_collection_to_wire(self._collection),
+ expressions=self._expressions_to_wire(),
+ limit=self._limit,
+ ):
+ yield _document_from_wire(documents=self._documents, message=result.document)
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
+
+ async def fetch(self) -> QueryResultsPage:
+ """
+ Fetch a single page of results.
+
+ If a page has been fetched previously, a token can be provided via paging_from(), to fetch the subsequent pages.
+ """
+ try:
+ results = await self._documents._stub.query(
+ collection=_collection_to_wire(self._collection),
+ expressions=self._expressions_to_wire(),
+ limit=self._limit,
+ paging_token=self._paging_token,
+ )
+
+ return QueryResultsPage(
+ paging_token=results.paging_token if results.paging_token else None,
+ documents=[
+ _document_from_wire(documents=self._documents, message=result) for result in results.documents
+ ],
+ )
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
+
+ def __eq__(self, other):
+ return self.__repr__() == other.__repr__()
+
+ def __str__(self):
+ repr_str = "from {0}".format(str(self._collection))
+ if self._paging_token:
+ repr_str += ", paging token {0}".format(str(self._paging_token))
+ if len(self._expressions):
+ repr_str += ", where " + " and ".join([str(exp) for exp in self._expressions])
+ if self._limit != 1:
+ repr_str += ", limit to {0} results".format(self._limit)
+
+ return "Query({0})".format(repr_str)
+
+ def __repr__(self):
+ repr_str = "Documents.collection({0}).query()".format(self._collection)
+ if self._paging_token:
+ repr_str += ".page_from({0})".format(self._paging_token)
+ if len(self._expressions):
+ repr_str += "".join([".where({0})".format(str(exp)) for exp in self._expressions])
+ if self._limit != 1:
+ repr_str += ".limit({0})".format(self._limit)
+
+ return repr_str
If a page has been fetched previously, a token can be provided via paging_from(), to fetch the subsequent pages.
+
+
+Expand source code
+
+
async def fetch(self) -> QueryResultsPage:
+ """
+ Fetch a single page of results.
+
+ If a page has been fetched previously, a token can be provided via paging_from(), to fetch the subsequent pages.
+ """
+ try:
+ results = await self._documents._stub.query(
+ collection=_collection_to_wire(self._collection),
+ expressions=self._expressions_to_wire(),
+ limit=self._limit,
+ paging_token=self._paging_token,
+ )
+
+ return QueryResultsPage(
+ paging_token=results.paging_token if results.paging_token else None,
+ documents=[
+ _document_from_wire(documents=self._documents, message=result) for result in results.documents
+ ],
+ )
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
Set the maximum number of results returned by this query.
+
+
+Expand source code
+
+
def limit(self, limit: int) -> QueryBuilder:
+ """Set the maximum number of results returned by this query."""
+ if limit is None or not isinstance(limit, int) or limit < 0:
+ raise ValueError("limit must be a positive integer or 0 for unlimited.")
+ self._limit = limit
+ return self
Used when requesting subsequent pages from a query.
+
+
+Expand source code
+
+
def page_from(self, token) -> QueryBuilder:
+ """
+ Set the paging token for the query.
+
+ Used when requesting subsequent pages from a query.
+ """
+ self._paging_token = token
+ return self
async def stream(self) -> AsyncIterator[Document]:
+ """Return all query results as a stream."""
+ # TODO: add limit, expressions and paging token to query.
+ if self._paging_token is not None:
+ raise ValueError("page_from() should not be used with streamed queries.")
+
+ try:
+ async for result in self._documents._stub.query_stream(
+ collection=_collection_to_wire(self._collection),
+ expressions=self._expressions_to_wire(),
+ limit=self._limit,
+ ):
+ yield _document_from_wire(documents=self._documents, message=result.document)
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
class QueryResultsPage:
+ """Represents a page of results from a query."""
+
+ paging_token: any = field(default_factory=lambda: None)
+ documents: List[Document] = field(default_factory=lambda: [])
+
+ def has_more_pages(self) -> bool:
+ """Return false if the page token is None or empty (both represent no more pages)."""
+ return bool(self.paging_token)
Return false if the page token is None or empty (both represent no more pages).
+
+
+Expand source code
+
+
def has_more_pages(self) -> bool:
+ """Return false if the page token is None or empty (both represent no more pages)."""
+ return bool(self.paging_token)
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/nitric/api/event.html b/docs/nitric/api/event.html
deleted file mode 100644
index 9a64413..0000000
--- a/docs/nitric/api/event.html
+++ /dev/null
@@ -1,355 +0,0 @@
-
-
-
-
-
-
-nitric.api.event API documentation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Module nitric.api.event
-
-
-
-
-Expand source code
-
-
#
-# Copyright (c) 2021 Nitric Technologies Pty Ltd.
-#
-# This file is part of Nitric Python 3 SDK.
-# See https://github.com/nitrictech/python-sdk for further info.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-from typing import List
-
-from nitric.proto import event as event_model, event
-from nitric.proto import event_service
-from nitric.proto.event.v1.event_pb2 import NitricEvent
-from nitric.api._base_client import BaseClient
-from google.protobuf.struct_pb2 import Struct
-
-from nitric.api.models import Topic
-
-
-class EventClient(BaseClient):
- """
- Nitric generic publish/subscribe event client.
-
- This client insulates application code from stack specific event operations or SDKs.
- """
-
- def __init__(self):
- """Construct a Nitric Event Client."""
- super(self.__class__, self).__init__()
- self._stub = event_service.EventStub(self._channel)
-
- def publish(
- self,
- topic_name: str,
- payload: dict = None,
- payload_type: str = "",
- event_id: str = None,
- ) -> str:
- """
- Publish an event/message to a topic, which can be subscribed to by other services.
-
- :param topic_name: the name of the topic to publish to
- :param payload: content of the message to send
- :param payload_type: fully qualified name of the event payload type, e.g. io.nitric.example.customer.created
- :param event_id: a unique id, used to ensure idempotent processing of events. Defaults to a version 4 UUID.
- :return: the request id on successful publish
- """
- if payload is None:
- payload = {}
- payload_struct = Struct()
- payload_struct.update(payload)
- nitric_event = NitricEvent(id=event_id, payload_type=payload_type, payload=payload_struct)
- request = event_model.EventPublishRequest(topic=topic_name, event=nitric_event)
- self._exec("Publish", request)
- return event_id
-
-
-class TopicClient(BaseClient):
- """
- Nitric generic event topic client.
-
- This client insulates application code from stack specific topic operations or SDKs.
- """
-
- def __init__(self):
- """Construct a Nitric Topic Client."""
- super(self.__class__, self).__init__()
- self._stub = event_service.TopicStub(self._channel)
-
- def get_topics(self) -> List[Topic]:
- """Get a list of topics available for publishing or subscription."""
- response: event.TopicListResponse = self._exec("List")
- topics = [Topic(name=topic.name) for topic in response.topics]
- return topics
-
-
-
-
-
-
-
-
-
-
Classes
-
-
-class EventClient
-
-
-
Nitric generic publish/subscribe event client.
-
This client insulates application code from stack specific event operations or SDKs.
-
Construct a Nitric Event Client.
-
-
-Expand source code
-
-
class EventClient(BaseClient):
- """
- Nitric generic publish/subscribe event client.
-
- This client insulates application code from stack specific event operations or SDKs.
- """
-
- def __init__(self):
- """Construct a Nitric Event Client."""
- super(self.__class__, self).__init__()
- self._stub = event_service.EventStub(self._channel)
-
- def publish(
- self,
- topic_name: str,
- payload: dict = None,
- payload_type: str = "",
- event_id: str = None,
- ) -> str:
- """
- Publish an event/message to a topic, which can be subscribed to by other services.
-
- :param topic_name: the name of the topic to publish to
- :param payload: content of the message to send
- :param payload_type: fully qualified name of the event payload type, e.g. io.nitric.example.customer.created
- :param event_id: a unique id, used to ensure idempotent processing of events. Defaults to a version 4 UUID.
- :return: the request id on successful publish
- """
- if payload is None:
- payload = {}
- payload_struct = Struct()
- payload_struct.update(payload)
- nitric_event = NitricEvent(id=event_id, payload_type=payload_type, payload=payload_struct)
- request = event_model.EventPublishRequest(topic=topic_name, event=nitric_event)
- self._exec("Publish", request)
- return event_id
Publish an event/message to a topic, which can be subscribed to by other services.
-
:param topic_name: the name of the topic to publish to
-:param payload: content of the message to send
-:param payload_type: fully qualified name of the event payload type, e.g. io.nitric.example.customer.created
-:param event_id: a unique id, used to ensure idempotent processing of events. Defaults to a version 4 UUID.
-:return: the request id on successful publish
-
-
-Expand source code
-
-
def publish(
- self,
- topic_name: str,
- payload: dict = None,
- payload_type: str = "",
- event_id: str = None,
-) -> str:
- """
- Publish an event/message to a topic, which can be subscribed to by other services.
-
- :param topic_name: the name of the topic to publish to
- :param payload: content of the message to send
- :param payload_type: fully qualified name of the event payload type, e.g. io.nitric.example.customer.created
- :param event_id: a unique id, used to ensure idempotent processing of events. Defaults to a version 4 UUID.
- :return: the request id on successful publish
- """
- if payload is None:
- payload = {}
- payload_struct = Struct()
- payload_struct.update(payload)
- nitric_event = NitricEvent(id=event_id, payload_type=payload_type, payload=payload_struct)
- request = event_model.EventPublishRequest(topic=topic_name, event=nitric_event)
- self._exec("Publish", request)
- return event_id
-
-
-
-
-
-class NitricEvent
-(*args, **kwargs)
-
-
-
A ProtocolMessage
-
Ancestors
-
-
google.protobuf.pyext._message.CMessage
-
google.protobuf.message.Message
-
-
Class variables
-
-
var DESCRIPTOR
-
-
-
-
-
Instance variables
-
-
var id
-
-
Field nitric.event.v1.NitricEvent.id
-
-
var payload
-
-
Field nitric.event.v1.NitricEvent.payload
-
-
var payload_type
-
-
Field nitric.event.v1.NitricEvent.payload_type
-
-
-
-
-class TopicClient
-
-
-
Nitric generic event topic client.
-
This client insulates application code from stack specific topic operations or SDKs.
-
Construct a Nitric Topic Client.
-
-
-Expand source code
-
-
class TopicClient(BaseClient):
- """
- Nitric generic event topic client.
-
- This client insulates application code from stack specific topic operations or SDKs.
- """
-
- def __init__(self):
- """Construct a Nitric Topic Client."""
- super(self.__class__, self).__init__()
- self._stub = event_service.TopicStub(self._channel)
-
- def get_topics(self) -> List[Topic]:
- """Get a list of topics available for publishing or subscription."""
- response: event.TopicListResponse = self._exec("List")
- topics = [Topic(name=topic.name) for topic in response.topics]
- return topics
Get a list of topics available for publishing or subscription.
-
-
-Expand source code
-
-
def get_topics(self) -> List[Topic]:
- """Get a list of topics available for publishing or subscription."""
- response: event.TopicListResponse = self._exec("List")
- topics = [Topic(name=topic.name) for topic in response.topics]
- return topics
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/nitric/api/events.html b/docs/nitric/api/events.html
index b1af7bd..ea153c2 100644
--- a/docs/nitric/api/events.html
+++ b/docs/nitric/api/events.html
@@ -44,15 +44,21 @@
Module nitric.api.events
# See the License for the specific language governing permissions and
# limitations under the License.
#
+from __future__ import annotations
+
from typing import List, Union
+
+from grpclib import GRPCError
+
+from nitric.api.exception import exception_from_grpc_error
from nitric.utils import new_default_channel, _struct_from_dict
-from nitric.proto.nitric.event.v1 import EventStub, NitricEvent, TopicStub
+from nitricapi.nitric.event.v1 import EventServiceStub, NitricEvent, TopicServiceStub
from dataclasses import dataclass, field
@dataclass(frozen=True, order=True)
class Event(object):
- """Represents a NitricEvent."""
+ """Eventing client, providing access to Topic and Event references and operations on those entities."""
payload: dict = field(default_factory=dict)
id: str = field(default=None)
@@ -71,7 +77,7 @@
Module nitric.api.events
class Topic(object):
"""A reference to a topic on an event service, used to perform operations on that topic."""
- _stub: EventStub
+ _events: Events
name: str
async def publish(
@@ -91,11 +97,14 @@
Eventing client, providing access to Topic and Event references and operations on those entities.
Expand source code
class Event(object):
- """Represents a NitricEvent."""
+ """Eventing client, providing access to Topic and Event references and operations on those entities."""
payload: dict = field(default_factory=dict)
id: str = field(default=None)
@@ -160,8 +177,8 @@
def __init__(self):
"""Construct a Nitric Event Client."""
- channel = new_default_channel()
- self._stub = EventStub(channel=channel)
- self._topic_stub = TopicStub(channel=channel)
->>>>>>> feat: port faas.start to bi-di streaming with membrane:docs/nitric/api/events.html
+ self.channel = new_default_channel()
+ self._stub = EventServiceStub(channel=self.channel)
+ self._topic_stub = TopicServiceStub(channel=self.channel)
+
+ def __del__(self):
+ # close the channel when this client is destroyed
+ if self.channel is not None:
+ self.channel.close()
async def topics(self) -> List[Topic]:
"""Get a list of topics available for publishing or subscription."""
- response = await self._topic_stub.list()
- return [self.topic(topic.name) for topic in response.topics]
+ try:
+ response = await self._topic_stub.list()
+ return [self.topic(topic.name) for topic in response.topics]
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
def topic(self, name: str) -> Topic:
- """Return a reference a topic from the connected event service."""
- return Topic(_stub=self._stub, name=name)
+ """Return a reference to a topic."""
+ return Topic(_events=self, name=name)
async def topics(self) -> List[Topic]:
"""Get a list of topics available for publishing or subscription."""
- response = await self._topic_stub.list()
- return [self.topic(topic.name) for topic in response.topics]
+ try:
+ response = await self._topic_stub.list()
+ return [self.topic(topic.name) for topic in response.topics]
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
class Topic
-(_stub: EventStub, name: str)
+(_events: Events, name: str)
A reference to a topic on an event service, used to perform operations on that topic.
class Task(object):
- """Represents a NitricTask."""
-=======
class Topic(object):
"""A reference to a topic on an event service, used to perform operations on that topic."""
- _stub: EventStub
+ _events: Events
name: str
async def publish(
@@ -267,10 +286,12 @@
Methods
if isinstance(event, dict):
# TODO: handle events that are just a payload
event = Event(**event)
->>>>>>> feat: port faas.start to bi-di streaming with membrane:docs/nitric/api/events.html
- response = await self._stub.publish(topic=self.name, event=_event_to_wire(event))
- return Event(**{**event.__dict__.copy(), **{"id": response.id}})
if isinstance(event, dict):
# TODO: handle events that are just a payload
event = Event(**event)
->>>>>>> feat: port faas.start to bi-di streaming with membrane:docs/nitric/api/events.html
- response = await self._stub.publish(topic=self.name, event=_event_to_wire(event))
- return Event(**{**event.__dict__.copy(), **{"id": response.id}})
# See the License for the specific language governing permissions and
# limitations under the License.
#
+from grpclib import GRPCError
-class UnimplementedException(Exception):
- """Exception raised when the requested operation isn't supported by the server."""
+class NitricServiceException(Exception):
+ """Base exception for all errors returned by Nitric API methods."""
pass
-class AlreadyExistsException(Exception):
- """Exception raised when an entity already exist during a request to create a new entity."""
+class AbortedException(NitricServiceException):
+ """The operation was aborted, typically due to a concurrency issue such as a transaction abort."""
pass
-class UnavailableException(Exception):
- """Exception raised when a gRPC service is unavailable."""
+class AlreadyExistsException(NitricServiceException):
+ """The entity that a client attempted to create (e.g., file or directory) already exists."""
- pass
+ pass
+
+
+class CancelledException(NitricServiceException):
+ """The operation was cancelled, typically by the caller."""
+
+ pass
+
+
+class DataLossException(NitricServiceException):
+ """Unrecoverable data loss or corruption."""
+
+ pass
+
+
+class DeadlineExceededException(NitricServiceException):
+ """The deadline expired before the operation could complete."""
+
+ pass
+
+
+class FailedPreconditionException(NitricServiceException):
+ """
+ The operation was rejected because the system is not in a state required for the operation's execution.
+
+ For example, the document collection to be deleted is not empty.
+ """
+
+ pass
+
+
+class InternalException(NitricServiceException):
+ """Internal errors."""
+
+ pass
+
+
+class InvalidArgumentException(NitricServiceException):
+ """
+ The client specified an invalid argument.
+
+ Note that this differs from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are problematic
+ regardless of the state of the system (e.g., a malformed file name).
+ """
+
+ pass
+
+
+class OutOfRangeException(NitricServiceException):
+ """
+ The operation was attempted past the valid range.
+
+ E.g. reading past the end of a file.
+ """
+
+ pass
+
+
+class NotFoundException(NitricServiceException):
+ """Some requested entity was not found."""
+
+ pass
+
+
+class PermissionDeniedException(NitricServiceException):
+ """The caller does not have permission to execute the specified operation."""
+
+ pass
+
+
+class ResourceExhaustedException(NitricServiceException):
+ """Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space."""
+
+ pass
+
+
+class UnauthenticatedException(NitricServiceException):
+ """The request does not have valid authentication credentials for the operation."""
+
+ pass
+
+
+class UnavailableException(NitricServiceException):
+ """
+ The service is currently unavailable.
+
+ This is most likely a transient condition, which can be corrected by retrying with a backoff.
+ """
+
+ pass
+
+
+class UnimplementedException(NitricServiceException):
+ """
+ The operation is not implemented or is not supported/enabled in this service.
+
+ May appear when using an older version of the Membrane with a newer SDK.
+ """
+
+ pass
+
+
+class UnknownException(NitricServiceException):
+ """Unknown error."""
+
+ pass
+
+
+def exception_from_grpc_error(error: GRPCError):
+ """Translate a gRPC error to a nitric api exception."""
+ return exception_from_grpc_code(error.status.value, error.message)
+
+
+def exception_from_grpc_code(code: int, message: str = None):
+ """
+ Return a new instance of the appropriate exception for the given status code.
+
+ If an unknown or unexpected status code value is provided an UnknownException will be returned.
+ """
+ if code not in _exception_code_map:
+ return UnknownException()
+
+ return _exception_code_map[code](message)
+
+
+# Map of gRPC status codes to the appropriate exception class.
+_exception_code_map = {
+ 0: lambda message: Exception("Error returned with status 0, which is a success status"),
+ 1: CancelledException,
+ 2: UnknownException,
+ 3: InvalidArgumentException,
+ 4: DeadlineExceededException,
+ 5: NotFoundException,
+ 6: AlreadyExistsException,
+ 7: PermissionDeniedException,
+ 8: ResourceExhaustedException,
+ 9: FailedPreconditionException,
+ 10: AbortedException,
+ 11: OutOfRangeException,
+ 12: UnimplementedException,
+ 13: InternalException,
+ 14: UnavailableException,
+ 15: DataLossException,
+ 16: UnauthenticatedException,
+}
@@ -69,27 +214,388 @@
Return a new instance of the appropriate exception for the given status code.
+
If an unknown or unexpected status code value is provided an UnknownException will be returned.
+
+
+Expand source code
+
+
def exception_from_grpc_code(code: int, message: str = None):
+ """
+ Return a new instance of the appropriate exception for the given status code.
+
+ If an unknown or unexpected status code value is provided an UnknownException will be returned.
+ """
+ if code not in _exception_code_map:
+ return UnknownException()
+
+ return _exception_code_map[code](message)
def exception_from_grpc_error(error: GRPCError):
+ """Translate a gRPC error to a nitric api exception."""
+ return exception_from_grpc_code(error.status.value, error.message)
+
+
+
Classes
+
+class AbortedException
+(*args, **kwargs)
+
+
+
The operation was aborted, typically due to a concurrency issue such as a transaction abort.
+
+
+Expand source code
+
+
class AbortedException(NitricServiceException):
+ """The operation was aborted, typically due to a concurrency issue such as a transaction abort."""
+
+ pass
Exception raised when an entity already exist during a request to create a new entity.
+
The entity that a client attempted to create (e.g., file or directory) already exists.
+
+
+Expand source code
+
+
class AlreadyExistsException(NitricServiceException):
+ """The entity that a client attempted to create (e.g., file or directory) already exists."""
+
+ pass
The operation was rejected because the system is not in a state required for the operation's execution.
+
For example, the document collection to be deleted is not empty.
+
+
+Expand source code
+
+
class FailedPreconditionException(NitricServiceException):
+ """
+ The operation was rejected because the system is not in a state required for the operation's execution.
+
+ For example, the document collection to be deleted is not empty.
+ """
+
+ pass
Note that this differs from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are problematic
+regardless of the state of the system (e.g., a malformed file name).
+
+
+Expand source code
+
+
class InvalidArgumentException(NitricServiceException):
+ """
+ The client specified an invalid argument.
+
+ Note that this differs from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are problematic
+ regardless of the state of the system (e.g., a malformed file name).
+ """
+
+ pass
class OutOfRangeException(NitricServiceException):
+ """
+ The operation was attempted past the valid range.
+
+ E.g. reading past the end of a file.
+ """
+
+ pass
Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space.
+
+
+Expand source code
+
+
class ResourceExhaustedException(NitricServiceException):
+ """Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space."""
+
+ pass
Exception raised when a gRPC service is unavailable.
+
The service is currently unavailable.
+
This is most likely a transient condition, which can be corrected by retrying with a backoff.
Expand source code
-
class UnavailableException(Exception):
- """Exception raised when a gRPC service is unavailable."""
+
class UnavailableException(NitricServiceException):
+ """
+ The service is currently unavailable.
+
+ This is most likely a transient condition, which can be corrected by retrying with a backoff.
+ """
pass
Exception raised when the requested operation isn't supported by the server.
+
The operation is not implemented or is not supported/enabled in this service.
+
May appear when using an older version of the Membrane with a newer SDK.
+
+
+Expand source code
+
+
class UnimplementedException(NitricServiceException):
+ """
+ The operation is not implemented or is not supported/enabled in this service.
+
+ May appear when using an older version of the Membrane with a newer SDK.
+ """
+
+ pass
Nitric client for interacting with document collections.
+
This client insulates application code from stack specific event operations or SDKs.
+
Construct a Nitric Document Client.
+
+
+Expand source code
+
+
class Documents(object):
+ """
+ Nitric client for interacting with document collections.
+
+ This client insulates application code from stack specific event operations or SDKs.
+ """
+
+ _stub: DocumentServiceStub
+
+ def __init__(self):
+ """Construct a Nitric Document Client."""
+ self._channel = new_default_channel()
+ self._stub = DocumentServiceStub(channel=self._channel)
+
+ def __del__(self):
+ # close the channel when this client is destroyed
+ if self._channel is not None:
+ self._channel.close()
+
+ def collection(self, name: str) -> CollectionRef:
+ """Return a reference to a document collection."""
+ return CollectionRef(_documents=self, name=name)
Eventing client, providing access to Topic and Event references and operations on those entities.
Expand source code
class Event(object):
- """Represents a NitricEvent."""
+ """Eventing client, providing access to Topic and Event references and operations on those entities."""
payload: dict = field(default_factory=dict)
id: str = field(default=None)
@@ -128,8 +190,8 @@
async def topics(self) -> List[Topic]:
"""Get a list of topics available for publishing or subscription."""
- response = await self._topic_stub.list()
- return [self.topic(topic.name) for topic in response.topics]
+ try:
+ response = await self._topic_stub.list()
+ return [self.topic(topic.name) for topic in response.topics]
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
class FailedTask(Task):
- """Represents a failed queue publish for an event."""
+ """Represents a failed queue publish."""
- lease_id: str = None # failed tasks should never have a lease id.
message: str = field(default="")
This client insulates application code from stack specific document CRUD operations or SDKs.
-
Construct a new DocumentClient.
-
:param collection: name of the key/value collection
+
Queueing client, providing access to Queue and Task references and operations on those entities.
+
Construct a Nitric Queue Client.
Expand source code
-
class KeyValueClient(object):
- """
- Nitric generic document store/db client.
-
- This client insulates application code from stack specific document CRUD operations or SDKs.
- """
+
class Queues(object):
+ """Queueing client, providing access to Queue and Task references and operations on those entities."""
- def __init__(self, collection: str):
- """
- Construct a new DocumentClient.
-
- :param collection: name of the key/value collection
- """
- self.collection = collection
- self._stub = KeyValueStub(channel=new_default_channel())
-
- async def put(self, key: str, value: dict):
- """Create a new document with the specified key."""
- await self._stub.put(collection=self.collection, key=key, value=_struct_from_dict(value))
+ def __init__(self):
+ """Construct a Nitric Queue Client."""
+ self.channel = new_default_channel()
+ self._queue_stub = QueueServiceStub(channel=self.channel)
- async def get(self, key: str) -> dict:
- """Retrieve a document from the specified key."""
- response = await self._stub.get(collection=self.collection, key=key)
- return response.value.to_dict()
+ def __del__(self):
+ # close the channel when this client is destroyed
+ if self.channel is not None:
+ self.channel.close()
- async def delete(self, key: str):
- """Delete the specified document from the collection."""
- await self._stub.delete(collection=self.collection, key=key)
+ def queue(self, name: str):
+ """Return a reference to a queue from the connected queue service."""
+ return Queue(_queueing=self, name=name)
Methods
-
-async def delete(self, key: str)
-
-
-
Delete the specified document from the collection.
-
-
-Expand source code
-
-
async def delete(self, key: str):
- """Delete the specified document from the collection."""
- await self._stub.delete(collection=self.collection, key=key)
-
-
-
-async def get(self, key: str) ‑> dict
-
-
-
Retrieve a document from the specified key.
-
-
-Expand source code
-
-
async def get(self, key: str) -> dict:
- """Retrieve a document from the specified key."""
- response = await self._stub.get(collection=self.collection, key=key)
- return response.value.to_dict()
-
-
-
-async def put(self, key: str, value: dict)
+
+def queue(self, name: str)
-
Create a new document with the specified key.
+
Return a reference to a queue from the connected queue service.
Expand source code
-
async def put(self, key: str, value: dict):
- """Create a new document with the specified key."""
- await self._stub.put(collection=self.collection, key=key, value=_struct_from_dict(value))
+
def queue(self, name: str):
+ """Return a reference to a queue from the connected queue service."""
+ return Queue(_queueing=self, name=name)
-
-class QueueClient
+
+class Secrets
-
Nitric generic publish/subscribe tasking client.
-
This client insulates application code from stack specific task/topic operations or SDKs.
-
Construct a Nitric Queue Client.
+
Nitric secrets management client.
+
This client insulates application code from stack specific secrets managements services.
+
Construct a Nitric Storage Client.
Expand source code
-
class QueueClient(object):
+
class Secrets(object):
"""
- Nitric generic publish/subscribe tasking client.
+ Nitric secrets management client.
- This client insulates application code from stack specific task/topic operations or SDKs.
+ This client insulates application code from stack specific secrets managements services.
"""
def __init__(self):
- """Construct a Nitric Queue Client."""
- self._queue_stub = QueueStub(channel=new_default_channel())
+ """Construct a Nitric Storage Client."""
+ self._channel = new_default_channel()
+ self._secrets_stub = SecretServiceStub(channel=self._channel)
- def queue(self, name: str):
- """Return a reference to a queue from the connected queue service."""
- return Queue(_queue_stub=self._queue_stub, name=name)
+ def __del__(self):
+ # close the channel when this client is destroyed
+ if self._channel is not None:
+ self._channel.close()
+
+ def secret(self, name: str):
+ """Return a reference to a secret container from the connected secrets management service."""
+ return SecretContainer(_secrets=self, name=name)
Methods
-
-def queue(self, name: str)
+
+def secret(self, name: str)
-
Return a reference to a queue from the connected queue service.
+
Return a reference to a secret container from the connected secrets management service.
Expand source code
-
def queue(self, name: str):
- """Return a reference to a queue from the connected queue service."""
- return Queue(_queue_stub=self._queue_stub, name=name)
+
def secret(self, name: str):
+ """Return a reference to a secret container from the connected secrets management service."""
+ return SecretContainer(_secrets=self, name=name)
def __init__(self):
"""Construct a Nitric Storage Client."""
- self._storage_stub = StorageStub(channel=new_default_channel())
+ self._channel = new_default_channel()
+ self._storage_stub = StorageServiceStub(channel=self._channel)
+
+ def __del__(self):
+ # close the channel when this client is destroyed
+ if self._channel is not None:
+ self._channel.close()
def bucket(self, name: str):
"""Return a reference to a bucket from the connected storage service."""
- return Bucket(_storage_stub=self._storage_stub, name=name)
+ return Bucket(_storage=self, name=name)
Methods
-
+
def bucket(self, name: str)
@@ -406,41 +434,27 @@
Methods
def bucket(self, name: str):
"""Return a reference to a bucket from the connected storage service."""
- return Bucket(_storage_stub=self._storage_stub, name=name)
class Task(object):
- """Represents a NitricTask."""
+ """A task to be sent to a Queue."""
id: str = field(default=None)
payload_type: str = field(default=None)
- payload: dict = field(default_factory=dict)
- lease_id: str = field(default=None)
- _queue_stub: QueueStub = field(default=None)
- _queue: str = field(default=None)
-
- async def complete(self):
- """Mark this task as complete and remove it from the queue."""
- if self._queue_stub is None or self._queue is None or self._queue == "":
- raise Exception("Task was not created via Queue.")
- if self.lease_id is None:
- raise Exception(
- "No lease_id available for task. Tasks must be received using Queue.receive to have a "
- "valid lease_id."
- )
- await self._queue_stub.complete(queue=self._queue, lease_id=self.lease_id)
+ payload: dict = field(default_factory=dict)
Subclasses
@@ -452,10 +466,6 @@
Class variables
-
var lease_id : str
-
-
-
var payload : dict
@@ -465,34 +475,10 @@
Class variables
-
Methods
-
-
-async def complete(self)
-
-
-
Mark this task as complete and remove it from the queue.
-
-
-Expand source code
-
-
async def complete(self):
- """Mark this task as complete and remove it from the queue."""
- if self._queue_stub is None or self._queue is None or self._queue == "":
- raise Exception("Task was not created via Queue.")
- if self.lease_id is None:
- raise Exception(
- "No lease_id available for task. Tasks must be received using Queue.receive to have a "
- "valid lease_id."
- )
- await self._queue_stub.complete(queue=self._queue, lease_id=self.lease_id)
-
-
-
class Topic
-(_stub: EventStub, name: str)
+(_events: Events, name: str)
A reference to a topic on an event service, used to perform operations on that topic.
@@ -501,12 +487,9 @@
Methods
Expand source code
class Topic(object):
-<<<<<<< refs/remotes/origin/main
- """Represents event topic metadata."""
-=======
"""A reference to a topic on an event service, used to perform operations on that topic."""
- _stub: EventStub
+ _events: Events
name: str
async def publish(
@@ -525,10 +508,12 @@
Methods
if isinstance(event, dict):
# TODO: handle events that are just a payload
event = Event(**event)
->>>>>>> feat: port faas.start to bi-di streaming with membrane
- response = await self._stub.publish(topic=self.name, event=_event_to_wire(event))
- return Event(**{**event.__dict__.copy(), **{"id": response.id}})
#
-# Copyright (c) 2021 Nitric Technologies Pty Ltd.
-#
-# This file is part of Nitric Python 3 SDK.
-# See https://github.com/nitrictech/python-sdk for further info.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-from nitric.utils import new_default_channel, _struct_from_dict
-from nitric.proto.nitric.kv.v1 import KeyValueStub
-
-
-class KeyValueClient(object):
- """
- Nitric generic document store/db client.
-
- This client insulates application code from stack specific document CRUD operations or SDKs.
- """
-
- def __init__(self, collection: str):
- """
- Construct a new DocumentClient.
-
- :param collection: name of the key/value collection
- """
- self.collection = collection
- self._stub = KeyValueStub(channel=new_default_channel())
-
- async def put(self, key: str, value: dict):
- """Create a new document with the specified key."""
- await self._stub.put(collection=self.collection, key=key, value=_struct_from_dict(value))
-
- async def get(self, key: str) -> dict:
- """Retrieve a document from the specified key."""
- response = await self._stub.get(collection=self.collection, key=key)
- return response.value.to_dict()
-
- async def delete(self, key: str):
- """Delete the specified document from the collection."""
- await self._stub.delete(collection=self.collection, key=key)
-
-
-
-
-
-
-
-
-
-
Classes
-
-
-class KeyValueClient
-(collection: str)
-
-
-
Nitric generic document store/db client.
-
This client insulates application code from stack specific document CRUD operations or SDKs.
-
Construct a new DocumentClient.
-
:param collection: name of the key/value collection
-
-
-Expand source code
-
-
class KeyValueClient(object):
- """
- Nitric generic document store/db client.
-
- This client insulates application code from stack specific document CRUD operations or SDKs.
- """
-
- def __init__(self, collection: str):
- """
- Construct a new DocumentClient.
-
- :param collection: name of the key/value collection
- """
- self.collection = collection
- self._stub = KeyValueStub(channel=new_default_channel())
-
- async def put(self, key: str, value: dict):
- """Create a new document with the specified key."""
- await self._stub.put(collection=self.collection, key=key, value=_struct_from_dict(value))
-
- async def get(self, key: str) -> dict:
- """Retrieve a document from the specified key."""
- response = await self._stub.get(collection=self.collection, key=key)
- return response.value.to_dict()
-
- async def delete(self, key: str):
- """Delete the specified document from the collection."""
- await self._stub.delete(collection=self.collection, key=key)
-
-
Methods
-
-
-async def delete(self, key: str)
-
-
-
Delete the specified document from the collection.
-
-
-Expand source code
-
-
async def delete(self, key: str):
- """Delete the specified document from the collection."""
- await self._stub.delete(collection=self.collection, key=key)
-
-
-
-async def get(self, key: str) ‑> dict
-
-
-
Retrieve a document from the specified key.
-
-
-Expand source code
-
-
async def get(self, key: str) -> dict:
- """Retrieve a document from the specified key."""
- response = await self._stub.get(collection=self.collection, key=key)
- return response.value.to_dict()
->>>>>>> feat: port faas.start to bi-di streaming with membrane
-
-
-Expand source code
-
-<<<<<<< refs/remotes/origin/main
-
def put(self, collection: str, key: str, value: dict):
- """Create a new document with the specified key in the specified collection."""
- value_struct = Struct()
- value_struct.update(value)
- request = key_value.KeyValuePutRequest(collection=collection, key=key, value=value_struct)
- return self._exec("Put", request)
-
-
-
-
-
-class KeyValueGetResponse
-(*args, **kwargs)
-
-
-
A ProtocolMessage
-
Ancestors
-
-
google.protobuf.pyext._message.CMessage
-
google.protobuf.message.Message
-
-
Class variables
-
-
var DESCRIPTOR
-
-
-
-
-
Instance variables
-
-
var value
-
-
Field nitric.kv.v1.KeyValueGetResponse.value
-=======
-
async def put(self, key: str, value: dict):
- """Create a new document with the specified key."""
- await self._stub.put(collection=self.collection, key=key, value=_struct_from_dict(value))
-
->>>>>>> feat: port faas.start to bi-di streaming with membrane
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/nitric/api/queues.html b/docs/nitric/api/queues.html
index 0eb1f2a..5f0fd44 100644
--- a/docs/nitric/api/queues.html
+++ b/docs/nitric/api/queues.html
@@ -44,40 +44,58 @@
Module nitric.api.queues
# See the License for the specific language governing permissions and
# limitations under the License.
#
+from __future__ import annotations
+
from typing import List, Union
-from nitric.utils import new_default_channel, _struct_from_dict
-from nitric.proto.nitric.queue.v1 import QueueStub, NitricTask, FailedTask as WireFailedTask
+
+from grpclib import GRPCError
+
+from nitric.api.exception import FailedPreconditionException, exception_from_grpc_error, InvalidArgumentException
+from nitric.utils import new_default_channel, _struct_from_dict, _dict_from_struct
+from nitricapi.nitric.queue.v1 import QueueServiceStub, NitricTask, FailedTask as WireFailedTask
from dataclasses import dataclass, field
@dataclass(frozen=True, order=True)
class Task(object):
- """Represents a NitricTask."""
+ """A task to be sent to a Queue."""
+
+ id: str = field(default=None)
+ payload_type: str = field(default=None)
+ payload: dict = field(default_factory=dict)
+
+
+@dataclass(frozen=True, order=True)
+class ReceivedTask(object):
+ """A reference to a task received from a Queue, with a lease."""
id: str = field(default=None)
payload_type: str = field(default=None)
payload: dict = field(default_factory=dict)
lease_id: str = field(default=None)
- _queue_stub: QueueStub = field(default=None)
- _queue: str = field(default=None)
+ _queueing: Queues = field(default=None)
+ _queue: Queue = field(default=None)
async def complete(self):
- """Mark this task as complete and remove it from the queue."""
- if self._queue_stub is None or self._queue is None or self._queue == "":
- raise Exception("Task was not created via Queue.")
- if self.lease_id is None:
- raise Exception(
- "No lease_id available for task. Tasks must be received using Queue.receive to have a "
- "valid lease_id."
+ """
+ Mark this task as complete and remove it from the queue.
+
+ Only callable for tasks that have been received from a Queue.
+ """
+ if self._queueing is None or self._queue is None or self.lease_id is None:
+ raise FailedPreconditionException(
+ "Task is missing internal client or lease id, was it returned from " "queue.receive?"
)
- await self._queue_stub.complete(queue=self._queue, lease_id=self.lease_id)
+ try:
+ await self._queueing._queue_stub.complete(queue=self._queue.name, lease_id=self.lease_id)
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
@dataclass(frozen=True, order=True)
class FailedTask(Task):
- """Represents a failed queue publish for an event."""
+ """Represents a failed queue publish."""
- lease_id: str = None # failed tasks should never have a lease id.
message: str = field(default="")
@@ -95,18 +113,20 @@
class Queue(object):
"""A reference to a queue from a queue service, used to perform operations on that queue."""
- _queue_stub: QueueStub
+ _queueing: Queues
name: str
async def send(
@@ -157,11 +176,12 @@
Module nitric.api.queues
# TODO: handle tasks that are just a payload
task = Task(**task)
- await self._queue_stub.send(queue=self.name, task=_task_to_wire(task))
+ try:
+ await self._queueing._queue_stub.send(queue=self.name, task=_task_to_wire(task))
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
- async def _send_batch(
- self, tasks: List[Union[Task, dict]] = None, raise_on_failure: bool = True
- ) -> List[FailedTask]:
+ async def _send_batch(self, tasks: List[Union[Task, dict]], raise_on_failure: bool = True) -> List[FailedTask]:
"""
Push a collection of tasks to a queue, which can be retrieved by other services.
@@ -169,14 +189,16 @@
Module nitric.api.queues
:param raise_on_failure: Whether to raise an exception when one or more tasks fails to send
:return: PushResponse containing a list containing details of any messages that failed to publish.
"""
- if tasks is None:
- tasks = []
+ if tasks is None or len(tasks) < 1:
+ raise InvalidArgumentException("No tasks provided, nothing to send.")
wire_tasks = [_task_to_wire(Task(**task) if isinstance(task, dict) else task) for task in tasks]
- response = await self._queue_stub.send_batch(queue=self.name, tasks=wire_tasks)
-
- return [_wire_to_failed_task(failed_task) for failed_task in response.failed_tasks]
+ try:
+ response = await self._queueing._queue_stub.send_batch(queue=self.name, tasks=wire_tasks)
+ return [_wire_to_failed_task(failed_task) for failed_task in response.failed_tasks]
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
async def receive(self, limit: int = None) -> List[Task]:
"""
@@ -195,26 +217,30 @@
Module nitric.api.queues
if limit is None or limit < 1:
limit = 1
- response = await self._queue_stub.receive(queue=self.name, depth=limit)
-
- # Map the response protobuf response items to Python SDK Nitric Tasks
- return [_wire_to_task(task) for task in response.tasks]
+ try:
+ response = await self._queueing._queue_stub.receive(queue=self.name, depth=limit)
+ # Map the response protobuf response items to Python SDK Nitric Tasks
+ return [_wire_to_received_task(task=task, queueing=self._queueing, queue=self) for task in response.tasks]
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
-class QueueClient(object):
- """
- Nitric generic publish/subscribe tasking client.
-
- This client insulates application code from stack specific task/topic operations or SDKs.
- """
+class Queues(object):
+ """Queueing client, providing access to Queue and Task references and operations on those entities."""
def __init__(self):
"""Construct a Nitric Queue Client."""
- self._queue_stub = QueueStub(channel=new_default_channel())
+ self.channel = new_default_channel()
+ self._queue_stub = QueueServiceStub(channel=self.channel)
+
+ def __del__(self):
+ # close the channel when this client is destroyed
+ if self.channel is not None:
+ self.channel.close()
def queue(self, name: str):
"""Return a reference to a queue from the connected queue service."""
- return Queue(_queue_stub=self._queue_stub, name=name)
+ return Queue(_queueing=self, name=name)
@@ -228,18 +254,17 @@
class FailedTask(Task):
- """Represents a failed queue publish for an event."""
+ """Represents a failed queue publish."""
- lease_id: str = None # failed tasks should never have a lease id.
message: str = field(default="")
class Queue
-(_queue_stub: QueueStub, name: str)
+(_queueing: Queues, name: str)
A reference to a queue from a queue service, used to perform operations on that queue.
@@ -279,7 +292,7 @@
Inherited members
class Queue(object):
"""A reference to a queue from a queue service, used to perform operations on that queue."""
- _queue_stub: QueueStub
+ _queueing: Queues
name: str
async def send(
@@ -304,11 +317,12 @@
Inherited members
# TODO: handle tasks that are just a payload
task = Task(**task)
- await self._queue_stub.send(queue=self.name, task=_task_to_wire(task))
+ try:
+ await self._queueing._queue_stub.send(queue=self.name, task=_task_to_wire(task))
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
- async def _send_batch(
- self, tasks: List[Union[Task, dict]] = None, raise_on_failure: bool = True
- ) -> List[FailedTask]:
+ async def _send_batch(self, tasks: List[Union[Task, dict]], raise_on_failure: bool = True) -> List[FailedTask]:
"""
Push a collection of tasks to a queue, which can be retrieved by other services.
@@ -316,14 +330,16 @@
Inherited members
:param raise_on_failure: Whether to raise an exception when one or more tasks fails to send
:return: PushResponse containing a list containing details of any messages that failed to publish.
"""
- if tasks is None:
- tasks = []
+ if tasks is None or len(tasks) < 1:
+ raise InvalidArgumentException("No tasks provided, nothing to send.")
wire_tasks = [_task_to_wire(Task(**task) if isinstance(task, dict) else task) for task in tasks]
- response = await self._queue_stub.send_batch(queue=self.name, tasks=wire_tasks)
-
- return [_wire_to_failed_task(failed_task) for failed_task in response.failed_tasks]
+ try:
+ response = await self._queueing._queue_stub.send_batch(queue=self.name, tasks=wire_tasks)
+ return [_wire_to_failed_task(failed_task) for failed_task in response.failed_tasks]
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
async def receive(self, limit: int = None) -> List[Task]:
"""
@@ -342,10 +358,12 @@
Inherited members
if limit is None or limit < 1:
limit = 1
- response = await self._queue_stub.receive(queue=self.name, depth=limit)
-
- # Map the response protobuf response items to Python SDK Nitric Tasks
- return [_wire_to_task(task) for task in response.tasks]
+ try:
+ response = await self._queueing._queue_stub.receive(queue=self.name, depth=limit)
+ # Map the response protobuf response items to Python SDK Nitric Tasks
+ return [_wire_to_received_task(task=task, queueing=self._queueing, queue=self) for task in response.tasks]
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
Class variables
@@ -388,10 +406,12 @@
Methods
if limit is None or limit < 1:
limit = 1
- response = await self._queue_stub.receive(queue=self.name, depth=limit)
-
- # Map the response protobuf response items to Python SDK Nitric Tasks
- return [_wire_to_task(task) for task in response.tasks]
+ try:
+ response = await self._queueing._queue_stub.receive(queue=self.name, depth=limit)
+ # Map the response protobuf response items to Python SDK Nitric Tasks
+ return [_wire_to_received_task(task=task, queueing=self._queueing, queue=self) for task in response.tasks]
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
@@ -428,40 +448,44 @@
Methods
# TODO: handle tasks that are just a payload
task = Task(**task)
- await self._queue_stub.send(queue=self.name, task=_task_to_wire(task))
+ try:
+ await self._queueing._queue_stub.send(queue=self.name, task=_task_to_wire(task))
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
-
-class QueueClient
+
+class Queues
-
Nitric generic publish/subscribe tasking client.
-
This client insulates application code from stack specific task/topic operations or SDKs.
+
Queueing client, providing access to Queue and Task references and operations on those entities.
Construct a Nitric Queue Client.
Expand source code
-
class QueueClient(object):
- """
- Nitric generic publish/subscribe tasking client.
-
- This client insulates application code from stack specific task/topic operations or SDKs.
- """
+
class Queues(object):
+ """Queueing client, providing access to Queue and Task references and operations on those entities."""
def __init__(self):
"""Construct a Nitric Queue Client."""
- self._queue_stub = QueueStub(channel=new_default_channel())
+ self.channel = new_default_channel()
+ self._queue_stub = QueueServiceStub(channel=self.channel)
+
+ def __del__(self):
+ # close the channel when this client is destroyed
+ if self.channel is not None:
+ self.channel.close()
def queue(self, name: str):
"""Return a reference to a queue from the connected queue service."""
- return Queue(_queue_stub=self._queue_stub, name=name)
+ return Queue(_queueing=self, name=name)
Methods
-
+
def queue(self, name: str)
@@ -472,90 +496,132 @@
Methods
def queue(self, name: str):
"""Return a reference to a queue from the connected queue service."""
- return Queue(_queue_stub=self._queue_stub, name=name)
A reference to a task received from a Queue, with a lease.
Expand source code
-
class Task(object):
- """Represents a NitricTask."""
+
class ReceivedTask(object):
+ """A reference to a task received from a Queue, with a lease."""
id: str = field(default=None)
payload_type: str = field(default=None)
payload: dict = field(default_factory=dict)
lease_id: str = field(default=None)
- _queue_stub: QueueStub = field(default=None)
- _queue: str = field(default=None)
+ _queueing: Queues = field(default=None)
+ _queue: Queue = field(default=None)
async def complete(self):
- """Mark this task as complete and remove it from the queue."""
- if self._queue_stub is None or self._queue is None or self._queue == "":
- raise Exception("Task was not created via Queue.")
- if self.lease_id is None:
- raise Exception(
- "No lease_id available for task. Tasks must be received using Queue.receive to have a "
- "valid lease_id."
+ """
+ Mark this task as complete and remove it from the queue.
+
+ Only callable for tasks that have been received from a Queue.
+ """
+ if self._queueing is None or self._queue is None or self.lease_id is None:
+ raise FailedPreconditionException(
+ "Task is missing internal client or lease id, was it returned from " "queue.receive?"
)
- await self._queue_stub.complete(queue=self._queue, lease_id=self.lease_id)
Mark this task as complete and remove it from the queue.
+
Mark this task as complete and remove it from the queue.
+
Only callable for tasks that have been received from a Queue.
Expand source code
async def complete(self):
- """Mark this task as complete and remove it from the queue."""
- if self._queue_stub is None or self._queue is None or self._queue == "":
- raise Exception("Task was not created via Queue.")
- if self.lease_id is None:
- raise Exception(
- "No lease_id available for task. Tasks must be received using Queue.receive to have a "
- "valid lease_id."
+ """
+ Mark this task as complete and remove it from the queue.
+
+ Only callable for tasks that have been received from a Queue.
+ """
+ if self._queueing is None or self._queue is None or self.lease_id is None:
+ raise FailedPreconditionException(
+ "Task is missing internal client or lease id, was it returned from " "queue.receive?"
)
- await self._queue_stub.complete(queue=self._queue, lease_id=self.lease_id)
class Task(object):
+ """A task to be sent to a Queue."""
+
+ id: str = field(default=None)
+ payload_type: str = field(default=None)
+ payload: dict = field(default_factory=dict)
#
+# Copyright (c) 2021 Nitric Technologies Pty Ltd.
+#
+# This file is part of Nitric Python 3 SDK.
+# See https://github.com/nitrictech/python-sdk for further info.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+from __future__ import annotations
+from dataclasses import dataclass
+from typing import Union
+
+from grpclib import GRPCError
+
+from nitric.api.exception import exception_from_grpc_error
+from nitric.utils import new_default_channel
+from nitricapi.nitric.secret.v1 import SecretServiceStub, Secret as SecretMessage, SecretVersion as VersionMessage
+
+
+class Secrets(object):
+ """
+ Nitric secrets management client.
+
+ This client insulates application code from stack specific secrets managements services.
+ """
+
+ def __init__(self):
+ """Construct a Nitric Storage Client."""
+ self._channel = new_default_channel()
+ self._secrets_stub = SecretServiceStub(channel=self._channel)
+
+ def __del__(self):
+ # close the channel when this client is destroyed
+ if self._channel is not None:
+ self._channel.close()
+
+ def secret(self, name: str):
+ """Return a reference to a secret container from the connected secrets management service."""
+ return SecretContainer(_secrets=self, name=name)
+
+
+def _secret_to_wire(secret: SecretContainer) -> SecretMessage:
+ return SecretMessage(name=secret.name)
+
+
+@dataclass(frozen=True)
+class SecretContainer(object):
+ """A reference to a secret container, used to store and retrieve secret versions."""
+
+ _secrets: Secrets
+ name: str
+
+ async def put(self, value: Union[str, bytes]) -> SecretVersion:
+ """
+ Create a new secret version, making it the latest and storing the provided value.
+
+ :param value: the secret value to store
+ """
+ if isinstance(value, str):
+ value = bytes(value, "utf-8")
+
+ secret_message = _secret_to_wire(self)
+
+ try:
+ response = await self._secrets._secrets_stub.put(secret=secret_message, value=value)
+ return self.version(version=response.secret_version.version)
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
+
+ def version(self, version: str):
+ """
+ Return a reference to a specific version of a secret.
+
+ Can be used to retrieve the secret value associated with the version.
+ """
+ return SecretVersion(_secrets=self._secrets, secret=self, id=version)
+
+ def latest(self):
+ """
+ Return a reference to the 'latest' secret version.
+
+ Note: using 'access' on this reference may return different values between requests if a
+ new version is created between access calls.
+ """
+ return self.version("latest")
+
+
+def _secret_version_to_wire(version: SecretVersion) -> VersionMessage:
+ return VersionMessage(_secret_to_wire(version.secret), version=version.id)
+
+
+@dataclass(frozen=True)
+class SecretVersion(object):
+ """A reference to a version of a secret, used to access the value of the version."""
+
+ _secrets: Secrets
+ secret: SecretContainer
+ id: str
+
+ async def access(self) -> SecretValue:
+ """Return the value stored against this version of the secret."""
+ version_message = _secret_version_to_wire(self)
+ try:
+ response = await self._secrets._secrets_stub.access(secret_version=version_message)
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
+
+ # Construct a new SecretVersion if the response version id doesn't match this reference.
+ # This ensures calls to access from the 'latest' version return new version objects
+ # with a fixed version id.
+ static_version = (
+ self
+ if response.secret_version.version == self.id
+ else SecretVersion(_secrets=self._secrets, secret=self.secret, id=response.secret_version.version)
+ )
+
+ return SecretValue(version=static_version, value=response.value)
+
+
+@dataclass(frozen=True)
+class SecretValue(object):
+ """Represents the value of a secret, tied to a specific version."""
+
+ # The version containing this value. Never 'latest', always a specific version.
+ version: SecretVersion
+ value: bytes
+
+ def __str__(self) -> str:
+ return self.value.decode("utf-8")
+
+ def __bytes__(self) -> bytes:
+ return self.value
+
+ def as_string(self):
+ """Return the content of this secret value as a string."""
+ return str(self)
+
+ def as_bytes(self):
+ """Return the content of this secret value."""
+ return bytes(self)
A reference to a secret container, used to store and retrieve secret versions.
+
+
+Expand source code
+
+
class SecretContainer(object):
+ """A reference to a secret container, used to store and retrieve secret versions."""
+
+ _secrets: Secrets
+ name: str
+
+ async def put(self, value: Union[str, bytes]) -> SecretVersion:
+ """
+ Create a new secret version, making it the latest and storing the provided value.
+
+ :param value: the secret value to store
+ """
+ if isinstance(value, str):
+ value = bytes(value, "utf-8")
+
+ secret_message = _secret_to_wire(self)
+
+ try:
+ response = await self._secrets._secrets_stub.put(secret=secret_message, value=value)
+ return self.version(version=response.secret_version.version)
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
+
+ def version(self, version: str):
+ """
+ Return a reference to a specific version of a secret.
+
+ Can be used to retrieve the secret value associated with the version.
+ """
+ return SecretVersion(_secrets=self._secrets, secret=self, id=version)
+
+ def latest(self):
+ """
+ Return a reference to the 'latest' secret version.
+
+ Note: using 'access' on this reference may return different values between requests if a
+ new version is created between access calls.
+ """
+ return self.version("latest")
+
+
Class variables
+
+
var name : str
+
+
+
+
+
Methods
+
+
+def latest(self)
+
+
+
Return a reference to the 'latest' secret version.
+
Note: using 'access' on this reference may return different values between requests if a
+new version is created between access calls.
+
+
+Expand source code
+
+
def latest(self):
+ """
+ Return a reference to the 'latest' secret version.
+
+ Note: using 'access' on this reference may return different values between requests if a
+ new version is created between access calls.
+ """
+ return self.version("latest")
Create a new secret version, making it the latest and storing the provided value.
+
:param value: the secret value to store
+
+
+Expand source code
+
+
async def put(self, value: Union[str, bytes]) -> SecretVersion:
+ """
+ Create a new secret version, making it the latest and storing the provided value.
+
+ :param value: the secret value to store
+ """
+ if isinstance(value, str):
+ value = bytes(value, "utf-8")
+
+ secret_message = _secret_to_wire(self)
+
+ try:
+ response = await self._secrets._secrets_stub.put(secret=secret_message, value=value)
+ return self.version(version=response.secret_version.version)
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
+
+
+
+def version(self, version: str)
+
+
+
Return a reference to a specific version of a secret.
+
Can be used to retrieve the secret value associated with the version.
+
+
+Expand source code
+
+
def version(self, version: str):
+ """
+ Return a reference to a specific version of a secret.
+
+ Can be used to retrieve the secret value associated with the version.
+ """
+ return SecretVersion(_secrets=self._secrets, secret=self, id=version)
Represents the value of a secret, tied to a specific version.
+
+
+Expand source code
+
+
class SecretValue(object):
+ """Represents the value of a secret, tied to a specific version."""
+
+ # The version containing this value. Never 'latest', always a specific version.
+ version: SecretVersion
+ value: bytes
+
+ def __str__(self) -> str:
+ return self.value.decode("utf-8")
+
+ def __bytes__(self) -> bytes:
+ return self.value
+
+ def as_string(self):
+ """Return the content of this secret value as a string."""
+ return str(self)
+
+ def as_bytes(self):
+ """Return the content of this secret value."""
+ return bytes(self)
A reference to a version of a secret, used to access the value of the version.
+
+
+Expand source code
+
+
class SecretVersion(object):
+ """A reference to a version of a secret, used to access the value of the version."""
+
+ _secrets: Secrets
+ secret: SecretContainer
+ id: str
+
+ async def access(self) -> SecretValue:
+ """Return the value stored against this version of the secret."""
+ version_message = _secret_version_to_wire(self)
+ try:
+ response = await self._secrets._secrets_stub.access(secret_version=version_message)
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
+
+ # Construct a new SecretVersion if the response version id doesn't match this reference.
+ # This ensures calls to access from the 'latest' version return new version objects
+ # with a fixed version id.
+ static_version = (
+ self
+ if response.secret_version.version == self.id
+ else SecretVersion(_secrets=self._secrets, secret=self.secret, id=response.secret_version.version)
+ )
+
+ return SecretValue(version=static_version, value=response.value)
Return the value stored against this version of the secret.
+
+
+Expand source code
+
+
async def access(self) -> SecretValue:
+ """Return the value stored against this version of the secret."""
+ version_message = _secret_version_to_wire(self)
+ try:
+ response = await self._secrets._secrets_stub.access(secret_version=version_message)
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
+
+ # Construct a new SecretVersion if the response version id doesn't match this reference.
+ # This ensures calls to access from the 'latest' version return new version objects
+ # with a fixed version id.
+ static_version = (
+ self
+ if response.secret_version.version == self.id
+ else SecretVersion(_secrets=self._secrets, secret=self.secret, id=response.secret_version.version)
+ )
+
+ return SecretValue(version=static_version, value=response.value)
+
+
+
+
+
+class Secrets
+
+
+
Nitric secrets management client.
+
This client insulates application code from stack specific secrets managements services.
+
Construct a Nitric Storage Client.
+
+
+Expand source code
+
+
class Secrets(object):
+ """
+ Nitric secrets management client.
+
+ This client insulates application code from stack specific secrets managements services.
+ """
+
+ def __init__(self):
+ """Construct a Nitric Storage Client."""
+ self._channel = new_default_channel()
+ self._secrets_stub = SecretServiceStub(channel=self._channel)
+
+ def __del__(self):
+ # close the channel when this client is destroyed
+ if self._channel is not None:
+ self._channel.close()
+
+ def secret(self, name: str):
+ """Return a reference to a secret container from the connected secrets management service."""
+ return SecretContainer(_secrets=self, name=name)
+
+
Methods
+
+
+def secret(self, name: str)
+
+
+
Return a reference to a secret container from the connected secrets management service.
+
+
+Expand source code
+
+
def secret(self, name: str):
+ """Return a reference to a secret container from the connected secrets management service."""
+ return SecretContainer(_secrets=self, name=name)
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/nitric/api/storage.html b/docs/nitric/api/storage.html
index 4b78a51..40ec8d1 100644
--- a/docs/nitric/api/storage.html
+++ b/docs/nitric/api/storage.html
@@ -46,11 +46,14 @@
def __init__(self):
"""Construct a Nitric Storage Client."""
- self._storage_stub = StorageStub(channel=new_default_channel())
+ self._channel = new_default_channel()
+ self._storage_stub = StorageServiceStub(channel=self._channel)
+
+ def __del__(self):
+ # close the channel when this client is destroyed
+ if self._channel is not None:
+ self._channel.close()
def bucket(self, name: str):
"""Return a reference to a bucket from the connected storage service."""
- return Bucket(_storage_stub=self._storage_stub, name=name)
+ return Bucket(_storage=self, name=name)
@dataclass(frozen=True, order=True)
class Bucket(object):
"""A reference to a bucket in a storage service, used to the perform operations on that bucket."""
- _storage_stub: StorageStub
+ _storage: Storage
name: str
def file(self, key: str):
"""Return a reference to a file in this bucket."""
- return File(_storage_stub=self._storage_stub, _bucket=self.name, key=key)
+ return File(_storage=self._storage, _bucket=self.name, key=key)
@dataclass(frozen=True, order=True)
class File(object):
"""A reference to a file in a bucket, used to perform operations on that file."""
- _storage_stub: StorageStub
+ _storage: Storage
_bucket: str
key: str
@@ -92,16 +101,25 @@
Module nitric.api.storage
Will create the file if it doesn't already exist.
"""
- await self._storage_stub.write(bucket_name=self._bucket, key=self.key, body=body)
+ try:
+ await self._storage._storage_stub.write(bucket_name=self._bucket, key=self.key, body=body)
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
async def read(self) -> bytes:
"""Read this files contents from the bucket."""
- response = await self._storage_stub.read(bucket_name=self._bucket, key=self.key)
- return response.body
+ try:
+ response = await self._storage._storage_stub.read(bucket_name=self._bucket, key=self.key)
+ return response.body
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
async def delete(self):
"""Delete this file from the bucket."""
- await self._storage_stub.delete(bucket_name=self._bucket, key=self.key)
class Bucket
-(_storage_stub: StorageStub, name: str)
+(_storage: Storage, name: str)
A reference to a bucket in a storage service, used to the perform operations on that bucket.
@@ -126,12 +144,12 @@
Classes
class Bucket(object):
"""A reference to a bucket in a storage service, used to the perform operations on that bucket."""
- _storage_stub: StorageStub
+ _storage: Storage
name: str
def file(self, key: str):
"""Return a reference to a file in this bucket."""
- return File(_storage_stub=self._storage_stub, _bucket=self.name, key=key)
def file(self, key: str):
"""Return a reference to a file in this bucket."""
- return File(_storage_stub=self._storage_stub, _bucket=self.name, key=key)
A reference to a file in a bucket, used to perform operations on that file.
@@ -171,7 +189,7 @@
Methods
class File(object):
"""A reference to a file in a bucket, used to perform operations on that file."""
- _storage_stub: StorageStub
+ _storage: Storage
_bucket: str
key: str
@@ -181,16 +199,25 @@
Methods
Will create the file if it doesn't already exist.
"""
- await self._storage_stub.write(bucket_name=self._bucket, key=self.key, body=body)
+ try:
+ await self._storage._storage_stub.write(bucket_name=self._bucket, key=self.key, body=body)
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
async def read(self) -> bytes:
"""Read this files contents from the bucket."""
- response = await self._storage_stub.read(bucket_name=self._bucket, key=self.key)
- return response.body
+ try:
+ response = await self._storage._storage_stub.read(bucket_name=self._bucket, key=self.key)
+ return response.body
+ except GRPCError as grpc_err:
+ raise exception_from_grpc_error(grpc_err)
async def delete(self):
"""Delete this file from the bucket."""
- await self._storage_stub.delete(bucket_name=self._bucket, key=self.key)
def __init__(self):
"""Construct a Nitric Storage Client."""
- self._storage_stub = StorageStub(channel=new_default_channel())
+ self._channel = new_default_channel()
+ self._storage_stub = StorageServiceStub(channel=self._channel)
+
+ def __del__(self):
+ # close the channel when this client is destroyed
+ if self._channel is not None:
+ self._channel.close()
def bucket(self, name: str):
"""Return a reference to a bucket from the connected storage service."""
- return Bucket(_storage_stub=self._storage_stub, name=name)
+ return Bucket(_storage=self, name=name)
Methods
-
+
def bucket(self, name: str)
@@ -290,7 +332,7 @@
Methods
def bucket(self, name: str):
"""Return a reference to a bucket from the connected storage service."""
- return Bucket(_storage_stub=self._storage_stub, name=name)
from __future__ import annotations
+
+import functools
+import json
+import traceback
+from typing import Dict, Union, List, TypeVar, Callable, Coroutine, Any
+
+import betterproto
+from betterproto.grpc.util.async_channel import AsyncChannel
+from nitric.utils import new_default_channel
+from nitricapi.nitric.faas.v1 import (
+ FaasServiceStub,
+ InitRequest,
+ ClientMessage,
+ TriggerRequest,
+ TriggerResponse,
+ HttpResponseContext,
+ TopicResponseContext,
+)
+import asyncio
+from abc import ABC
+
+Record = Dict[str, Union[str, List[str]]]
+
+
+class Request(ABC):
+ """Represents an abstract trigger request."""
+
+ def __init__(self, data: bytes):
+ """Construct a new Request."""
+ self.data = data
+
+
+class Response(ABC):
+ """Represents an abstract trigger response."""
+
+ pass
+
+
+class TriggerContext(ABC):
+ """Represents an abstract request/response context for any trigger."""
+
+ def http(self) -> Union[HttpContext, None]:
+ """Return this context as an HttpContext if it is one, otherwise returns None."""
+ return None
+
+ def event(self) -> Union[EventContext, None]:
+ """Return this context as an EventContext if it is one, otherwise returns None."""
+ return None
+
+
+def _ctx_from_grpc_trigger_request(trigger_request: TriggerRequest):
+ """Return a TriggerContext from a TriggerRequest."""
+ context_type, context = betterproto.which_one_of(trigger_request, "context")
+ if context_type == "http":
+ return HttpContext.from_grpc_trigger_request(trigger_request)
+ elif context_type == "topic":
+ return EventContext.from_grpc_trigger_request(trigger_request)
+ else:
+ print(f"Trigger with unknown context received, context type: {context_type}")
+ raise Exception(f"Unknown trigger context, type: {context_type}")
+
+
+def _grpc_response_from_ctx(ctx: TriggerContext) -> TriggerResponse:
+ """
+ Create a GRPC TriggerResponse from a TriggerContext.
+
+ The ctx is used to determine the appropriate TriggerResponse content,
+ the ctx.res is then used to construct the response.
+ """
+ if ctx.http():
+ ctx = ctx.http()
+ return TriggerResponse(
+ data=ctx.res.body,
+ http=HttpResponseContext(
+ status=ctx.res.status,
+ headers=ctx.res.headers,
+ ),
+ )
+ elif ctx.event():
+ ctx = ctx.event()
+ return TriggerResponse(
+ topic=TopicResponseContext(
+ success=ctx.res.success,
+ ),
+ )
+ else:
+ raise Exception("Unknown Trigger Context type, unable to return valid response")
+
+
+# ====== HTTP ======
+
+
+class HttpRequest(Request):
+ """Represents a translated Http Request forwarded from the Nitric Membrane."""
+
+ def __init__(self, data: bytes, method: str, path: str, query: Record, headers: Record):
+ """Construct a new HttpRequest."""
+ super().__init__(data)
+ self.method = method
+ self.path = path
+ self.query = query
+ self.headers = headers
+
+ @property
+ def body(self):
+ """Get the body of the request as text."""
+ return self.data.decode("utf-8")
+
+
+class HttpResponse(Response):
+ """Represents an Http Response to be generated by the Nitric Membrane in response to an Http Request Trigger."""
+
+ def __init__(self, status: int = 200, headers: Record = None, body: bytes = None):
+ """Construct a new HttpResponse."""
+ self.status = status
+ self.headers = headers if headers else {}
+ self.body = body if body else bytes()
+
+
+class HttpContext(TriggerContext):
+ """Represents the full request/response context for an Http based trigger."""
+
+ def __init__(self, request: HttpRequest, response: HttpResponse = None):
+ """Construct a new HttpContext."""
+ super().__init__()
+ self.req = request
+ self.res = response if response else HttpResponse()
+
+ def http(self) -> HttpContext:
+ """Return this HttpContext, used when determining the context type of a trigger."""
+ return self
+
+ @staticmethod
+ def from_grpc_trigger_request(trigger_request: TriggerRequest) -> HttpContext:
+ """Construct a new HttpContext from an Http trigger from the Nitric Membrane."""
+ if len(trigger_request.http.headers.keys()) > 0:
+ headers = {k: v[0].value for (k, v) in trigger_request.http.headers.items()}
+ else:
+ headers = trigger_request.http.headers_old
+
+ return HttpContext(
+ request=HttpRequest(
+ data=trigger_request.data,
+ method=trigger_request.http.method,
+ query=trigger_request.http.query_params,
+ path=trigger_request.http.path,
+ headers=headers,
+ )
+ )
+
+
+# ====== Events ======
+
+
+class EventRequest(Request):
+ """Represents a translated Event, from a Subscribed Topic, forwarded from the Nitric Membrane."""
+
+ def __init__(self, data: bytes, topic: str):
+ """Construct a new EventRequest."""
+ super().__init__(data)
+ self.topic = topic
+
+ @property
+ def payload(self) -> bytes:
+ """Return the payload of this request as text."""
+ return json.loads(self.data.decode("utf-8"))
+
+
+class EventResponse(Response):
+ """Represents the response to a trigger from an Event as a result of a Topic subscription."""
+
+ def __init__(self, success: bool = True):
+ """Construct a new EventResponse."""
+ self.success = success
+
+
+class EventContext(TriggerContext):
+ """Represents the full request/response context for an Event based trigger."""
+
+ def __init__(self, request: EventRequest, response: EventResponse = None):
+ """Construct a new EventContext."""
+ super().__init__()
+ self.req = request
+ self.res = response if response else EventResponse()
+
+ def event(self) -> EventContext:
+ """Return this EventContext, used when determining the context type of a trigger."""
+ return self
+
+ @staticmethod
+ def from_grpc_trigger_request(trigger_request: TriggerRequest):
+ """Construct a new EventContext from an Event trigger from the Nitric Membrane."""
+ return EventContext(request=EventRequest(data=trigger_request.data, topic=trigger_request.topic.topic))
+
+
+# async def face(inpp: int) -> str:
+# return "thing"
+
+
+# ====== Function Handlers ======
+
+C = TypeVar("C", TriggerContext, HttpContext, EventContext)
+Middleware = Callable
+Handler = Coroutine[Any, Any, C]
+HttpHandler = Coroutine[Any, Any, HttpContext]
+EventHandler = Coroutine[Any, Any, EventContext]
+Middleware = Callable[[C, Middleware], Handler]
+# HttpMiddleware = Middleware[[HttpContext, Middleware], HttpHandler]
+# EventMiddleware = Middleware[[EventContext, Middleware], EventHandler]
+
+
+def compose_middleware(*middlewares: Union[Middleware, List[Middleware]]) -> Middleware:
+ """
+ Compose multiple middleware functions into a single middleware function.
+
+ The resulting middleware will effectively be a chain of the provided middleware,
+ where each calls the next in the chain when they're successful.
+ """
+ if len(middlewares) == 1 and not isinstance(middlewares[0], list):
+ return middlewares[0]
+
+ middlewares = [compose_middleware(m) if isinstance(m, list) else m for m in middlewares]
+
+ async def handler(ctx, next_middleware=lambda ctx: ctx):
+ middleware_chain = functools.reduce(
+ lambda acc_next, cur: lambda context: cur(context, acc_next), reversed(middlewares + (next_middleware,))
+ )
+ return middleware_chain(ctx)
+
+ return handler
+
+
+# ====== Function Server ======
+
+
+def _create_internal_error_response(req: TriggerRequest) -> TriggerResponse:
+ """Create a general error response based on the trigger request type."""
+ context_type, context = betterproto.which_one_of(req, "context")
+ if context_type == "http":
+ return TriggerResponse(data=bytes(), http=HttpResponseContext(status=500))
+ elif context_type == "topic":
+ return TriggerResponse(data=bytes(), topic=TopicResponseContext(success=False))
+ else:
+ raise Exception(f"Unknown trigger type: {context_type}, unable to generate expected response")
+
+
+class FunctionServer:
+ """A Function as a Service server, which acts as a faas handler for the Nitric Membrane."""
+
+ def __init__(self):
+ """Construct a new function server."""
+ self.__http_handler = None
+ self.__event_handler = None
+ self._any_handler = None
+
+ def http(self, *handlers: Union[Middleware, List[Middleware]]) -> FunctionServer:
+ """
+ Register one or more HTTP Trigger Handlers or Middleware.
+
+ When multiple handlers are provided, they will be called in order.
+ """
+ self.__http_handler = compose_middleware(*handlers)
+ return self
+
+ def event(self, *handlers: Union[Middleware, List[Middleware]]) -> FunctionServer:
+ """
+ Register one or more Event Trigger Handlers or Middleware.
+
+ When multiple handlers are provided, they will be called in order.
+ """
+ self.__event_handler = compose_middleware(*handlers)
+ return self
+
+ def start(self, *handlers: Union[Middleware, List[Middleware]]):
+ """Start the function server using the provided trigger handlers."""
+ self._any_handler = compose_middleware(*handlers) if len(handlers) > 0 else None
+ # TODO: implement the server
+ if not self._any_handler and not self._http_handler and not self._event_handler:
+ raise Exception("At least one handler function must be provided.")
+
+ asyncio.run(self.run())
+
+ @property
+ def _http_handler(self):
+ return self.__http_handler if self.__http_handler else self._any_handler
+
+ @property
+ def _event_handler(self):
+ return self.__event_handler if self.__event_handler else self._any_handler
+
+ async def run(self):
+ """Register a new FaaS worker with the Membrane, using the provided function as the handler."""
+ channel = new_default_channel()
+ client = FaasServiceStub(channel)
+ request_channel = AsyncChannel(close=True)
+ # We can start be sending all the requests we already have
+ try:
+ await request_channel.send(ClientMessage(init_request=InitRequest()))
+ async for srv_msg in client.trigger_stream(request_channel):
+ # The response iterator will remain active until the connection is closed
+ msg_type, val = betterproto.which_one_of(srv_msg, "content")
+
+ if msg_type == "init_response":
+ print("function connected to Membrane")
+ # We don't need to reply
+ # proceed to the next available message
+ continue
+ if msg_type == "trigger_request":
+ ctx = _ctx_from_grpc_trigger_request(srv_msg.trigger_request)
+
+ try:
+ if ctx.http():
+ func = self._http_handler
+ elif ctx.event():
+ func = self._event_handler
+ else:
+ func = self._any_handler
+ response_ctx = (await func(ctx)) if asyncio.iscoroutinefunction(func) else func(ctx)
+ # Send function response back to server
+ await request_channel.send(
+ ClientMessage(
+ id=srv_msg.id,
+ trigger_response=_grpc_response_from_ctx(response_ctx),
+ )
+ )
+ except Exception:
+ # Any unhandled exceptions in the above code will end the loop
+ # and stop processing future triggers, we catch them here as a last resort.
+ print("An unexpected error occurred processing trigger or response")
+ traceback.print_exc()
+ response = _create_internal_error_response(srv_msg.trigger_request)
+ await request_channel.send(ClientMessage(id=srv_msg.id, trigger_response=response))
+ else:
+ print(f"unhandled message type {msg_type}, skipping")
+ continue
+ if request_channel.done():
+ break
+ except ConnectionRefusedError as cre:
+ traceback.print_exc()
+ raise ConnectionRefusedError("Failed to register function with Membrane") from cre
+ except Exception as e:
+ traceback.print_exc()
+ raise Exception("An unexpected error occurred.") from e
+ finally:
+ print("stream from Membrane closed, closing client stream")
+ # The channel must be closed to complete the gRPC connection
+ request_channel.close()
+ channel.close()
+
+
+# Convenience functions to create function servers
+
+
+def http(*handlers: Union[Middleware, List[Middleware]]) -> FunctionServer:
+ """
+ Create a new Function Server and Register one or more HTTP Trigger Handlers or Middleware.
+
+ When multiple handlers are provided, they will be called in order.
+ """
+ return FunctionServer().http(*handlers)
+
+
+def event(*handlers: Union[Middleware, List[Middleware]]) -> FunctionServer:
+ """
+ Create a new Function Server and Register one or more Event Trigger Handlers or Middleware.
+
+ When multiple handlers are provided, they will be called in order.
+ """
+ return FunctionServer().event(*handlers)
+
+
+def start(*handlers: Union[Middleware, List[Middleware]]):
+ """Create a new Function Server and start it using the provided trigger handlers."""
+ if len(handlers) < 1:
+ raise Exception("At least one handler must be provided.")
+ return FunctionServer().start(*handlers)
Compose multiple middleware functions into a single middleware function.
+
The resulting middleware will effectively be a chain of the provided middleware,
+where each calls the next in the chain when they're successful.
+
+
+Expand source code
+
+
def compose_middleware(*middlewares: Union[Middleware, List[Middleware]]) -> Middleware:
+ """
+ Compose multiple middleware functions into a single middleware function.
+
+ The resulting middleware will effectively be a chain of the provided middleware,
+ where each calls the next in the chain when they're successful.
+ """
+ if len(middlewares) == 1 and not isinstance(middlewares[0], list):
+ return middlewares[0]
+
+ middlewares = [compose_middleware(m) if isinstance(m, list) else m for m in middlewares]
+
+ async def handler(ctx, next_middleware=lambda ctx: ctx):
+ middleware_chain = functools.reduce(
+ lambda acc_next, cur: lambda context: cur(context, acc_next), reversed(middlewares + (next_middleware,))
+ )
+ return middleware_chain(ctx)
+
+ return handler
Create a new Function Server and Register one or more Event Trigger Handlers or Middleware.
+
When multiple handlers are provided, they will be called in order.
+
+
+Expand source code
+
+
def event(*handlers: Union[Middleware, List[Middleware]]) -> FunctionServer:
+ """
+ Create a new Function Server and Register one or more Event Trigger Handlers or Middleware.
+
+ When multiple handlers are provided, they will be called in order.
+ """
+ return FunctionServer().event(*handlers)
Create a new Function Server and Register one or more HTTP Trigger Handlers or Middleware.
+
When multiple handlers are provided, they will be called in order.
+
+
+Expand source code
+
+
def http(*handlers: Union[Middleware, List[Middleware]]) -> FunctionServer:
+ """
+ Create a new Function Server and Register one or more HTTP Trigger Handlers or Middleware.
+
+ When multiple handlers are provided, they will be called in order.
+ """
+ return FunctionServer().http(*handlers)
Create a new Function Server and start it using the provided trigger handlers.
+
+
+Expand source code
+
+
def start(*handlers: Union[Middleware, List[Middleware]]):
+ """Create a new Function Server and start it using the provided trigger handlers."""
+ if len(handlers) < 1:
+ raise Exception("At least one handler must be provided.")
+ return FunctionServer().start(*handlers)
Represents the full request/response context for an Event based trigger.
+
Construct a new EventContext.
+
+
+Expand source code
+
+
class EventContext(TriggerContext):
+ """Represents the full request/response context for an Event based trigger."""
+
+ def __init__(self, request: EventRequest, response: EventResponse = None):
+ """Construct a new EventContext."""
+ super().__init__()
+ self.req = request
+ self.res = response if response else EventResponse()
+
+ def event(self) -> EventContext:
+ """Return this EventContext, used when determining the context type of a trigger."""
+ return self
+
+ @staticmethod
+ def from_grpc_trigger_request(trigger_request: TriggerRequest):
+ """Construct a new EventContext from an Event trigger from the Nitric Membrane."""
+ return EventContext(request=EventRequest(data=trigger_request.data, topic=trigger_request.topic.topic))
Construct a new EventContext from an Event trigger from the Nitric Membrane.
+
+
+Expand source code
+
+
@staticmethod
+def from_grpc_trigger_request(trigger_request: TriggerRequest):
+ """Construct a new EventContext from an Event trigger from the Nitric Membrane."""
+ return EventContext(request=EventRequest(data=trigger_request.data, topic=trigger_request.topic.topic))
Represents a translated Event, from a Subscribed Topic, forwarded from the Nitric Membrane.
+
Construct a new EventRequest.
+
+
+Expand source code
+
+
class EventRequest(Request):
+ """Represents a translated Event, from a Subscribed Topic, forwarded from the Nitric Membrane."""
+
+ def __init__(self, data: bytes, topic: str):
+ """Construct a new EventRequest."""
+ super().__init__(data)
+ self.topic = topic
+
+ @property
+ def payload(self) -> bytes:
+ """Return the payload of this request as text."""
+ return json.loads(self.data.decode("utf-8"))
@property
+def payload(self) -> bytes:
+ """Return the payload of this request as text."""
+ return json.loads(self.data.decode("utf-8"))
+
+
+
+
+
+class EventResponse
+(success: bool = True)
+
+
+
Represents the response to a trigger from an Event as a result of a Topic subscription.
+
Construct a new EventResponse.
+
+
+Expand source code
+
+
class EventResponse(Response):
+ """Represents the response to a trigger from an Event as a result of a Topic subscription."""
+
+ def __init__(self, success: bool = True):
+ """Construct a new EventResponse."""
+ self.success = success
A Function as a Service server, which acts as a faas handler for the Nitric Membrane.
+
Construct a new function server.
+
+
+Expand source code
+
+
class FunctionServer:
+ """A Function as a Service server, which acts as a faas handler for the Nitric Membrane."""
+
+ def __init__(self):
+ """Construct a new function server."""
+ self.__http_handler = None
+ self.__event_handler = None
+ self._any_handler = None
+
+ def http(self, *handlers: Union[Middleware, List[Middleware]]) -> FunctionServer:
+ """
+ Register one or more HTTP Trigger Handlers or Middleware.
+
+ When multiple handlers are provided, they will be called in order.
+ """
+ self.__http_handler = compose_middleware(*handlers)
+ return self
+
+ def event(self, *handlers: Union[Middleware, List[Middleware]]) -> FunctionServer:
+ """
+ Register one or more Event Trigger Handlers or Middleware.
+
+ When multiple handlers are provided, they will be called in order.
+ """
+ self.__event_handler = compose_middleware(*handlers)
+ return self
+
+ def start(self, *handlers: Union[Middleware, List[Middleware]]):
+ """Start the function server using the provided trigger handlers."""
+ self._any_handler = compose_middleware(*handlers) if len(handlers) > 0 else None
+ # TODO: implement the server
+ if not self._any_handler and not self._http_handler and not self._event_handler:
+ raise Exception("At least one handler function must be provided.")
+
+ asyncio.run(self.run())
+
+ @property
+ def _http_handler(self):
+ return self.__http_handler if self.__http_handler else self._any_handler
+
+ @property
+ def _event_handler(self):
+ return self.__event_handler if self.__event_handler else self._any_handler
+
+ async def run(self):
+ """Register a new FaaS worker with the Membrane, using the provided function as the handler."""
+ channel = new_default_channel()
+ client = FaasServiceStub(channel)
+ request_channel = AsyncChannel(close=True)
+ # We can start be sending all the requests we already have
+ try:
+ await request_channel.send(ClientMessage(init_request=InitRequest()))
+ async for srv_msg in client.trigger_stream(request_channel):
+ # The response iterator will remain active until the connection is closed
+ msg_type, val = betterproto.which_one_of(srv_msg, "content")
+
+ if msg_type == "init_response":
+ print("function connected to Membrane")
+ # We don't need to reply
+ # proceed to the next available message
+ continue
+ if msg_type == "trigger_request":
+ ctx = _ctx_from_grpc_trigger_request(srv_msg.trigger_request)
+
+ try:
+ if ctx.http():
+ func = self._http_handler
+ elif ctx.event():
+ func = self._event_handler
+ else:
+ func = self._any_handler
+ response_ctx = (await func(ctx)) if asyncio.iscoroutinefunction(func) else func(ctx)
+ # Send function response back to server
+ await request_channel.send(
+ ClientMessage(
+ id=srv_msg.id,
+ trigger_response=_grpc_response_from_ctx(response_ctx),
+ )
+ )
+ except Exception:
+ # Any unhandled exceptions in the above code will end the loop
+ # and stop processing future triggers, we catch them here as a last resort.
+ print("An unexpected error occurred processing trigger or response")
+ traceback.print_exc()
+ response = _create_internal_error_response(srv_msg.trigger_request)
+ await request_channel.send(ClientMessage(id=srv_msg.id, trigger_response=response))
+ else:
+ print(f"unhandled message type {msg_type}, skipping")
+ continue
+ if request_channel.done():
+ break
+ except ConnectionRefusedError as cre:
+ traceback.print_exc()
+ raise ConnectionRefusedError("Failed to register function with Membrane") from cre
+ except Exception as e:
+ traceback.print_exc()
+ raise Exception("An unexpected error occurred.") from e
+ finally:
+ print("stream from Membrane closed, closing client stream")
+ # The channel must be closed to complete the gRPC connection
+ request_channel.close()
+ channel.close()
Register one or more Event Trigger Handlers or Middleware.
+
When multiple handlers are provided, they will be called in order.
+
+
+Expand source code
+
+
def event(self, *handlers: Union[Middleware, List[Middleware]]) -> FunctionServer:
+ """
+ Register one or more Event Trigger Handlers or Middleware.
+
+ When multiple handlers are provided, they will be called in order.
+ """
+ self.__event_handler = compose_middleware(*handlers)
+ return self
Register one or more HTTP Trigger Handlers or Middleware.
+
When multiple handlers are provided, they will be called in order.
+
+
+Expand source code
+
+
def http(self, *handlers: Union[Middleware, List[Middleware]]) -> FunctionServer:
+ """
+ Register one or more HTTP Trigger Handlers or Middleware.
+
+ When multiple handlers are provided, they will be called in order.
+ """
+ self.__http_handler = compose_middleware(*handlers)
+ return self
+
+
+
+async def run(self)
+
+
+
Register a new FaaS worker with the Membrane, using the provided function as the handler.
+
+
+Expand source code
+
+
async def run(self):
+ """Register a new FaaS worker with the Membrane, using the provided function as the handler."""
+ channel = new_default_channel()
+ client = FaasServiceStub(channel)
+ request_channel = AsyncChannel(close=True)
+ # We can start be sending all the requests we already have
+ try:
+ await request_channel.send(ClientMessage(init_request=InitRequest()))
+ async for srv_msg in client.trigger_stream(request_channel):
+ # The response iterator will remain active until the connection is closed
+ msg_type, val = betterproto.which_one_of(srv_msg, "content")
+
+ if msg_type == "init_response":
+ print("function connected to Membrane")
+ # We don't need to reply
+ # proceed to the next available message
+ continue
+ if msg_type == "trigger_request":
+ ctx = _ctx_from_grpc_trigger_request(srv_msg.trigger_request)
+
+ try:
+ if ctx.http():
+ func = self._http_handler
+ elif ctx.event():
+ func = self._event_handler
+ else:
+ func = self._any_handler
+ response_ctx = (await func(ctx)) if asyncio.iscoroutinefunction(func) else func(ctx)
+ # Send function response back to server
+ await request_channel.send(
+ ClientMessage(
+ id=srv_msg.id,
+ trigger_response=_grpc_response_from_ctx(response_ctx),
+ )
+ )
+ except Exception:
+ # Any unhandled exceptions in the above code will end the loop
+ # and stop processing future triggers, we catch them here as a last resort.
+ print("An unexpected error occurred processing trigger or response")
+ traceback.print_exc()
+ response = _create_internal_error_response(srv_msg.trigger_request)
+ await request_channel.send(ClientMessage(id=srv_msg.id, trigger_response=response))
+ else:
+ print(f"unhandled message type {msg_type}, skipping")
+ continue
+ if request_channel.done():
+ break
+ except ConnectionRefusedError as cre:
+ traceback.print_exc()
+ raise ConnectionRefusedError("Failed to register function with Membrane") from cre
+ except Exception as e:
+ traceback.print_exc()
+ raise Exception("An unexpected error occurred.") from e
+ finally:
+ print("stream from Membrane closed, closing client stream")
+ # The channel must be closed to complete the gRPC connection
+ request_channel.close()
+ channel.close()
Start the function server using the provided trigger handlers.
+
+
+Expand source code
+
+
def start(self, *handlers: Union[Middleware, List[Middleware]]):
+ """Start the function server using the provided trigger handlers."""
+ self._any_handler = compose_middleware(*handlers) if len(handlers) > 0 else None
+ # TODO: implement the server
+ if not self._any_handler and not self._http_handler and not self._event_handler:
+ raise Exception("At least one handler function must be provided.")
+
+ asyncio.run(self.run())
@property
+def body(self):
+ """Get the body of the request as text."""
+ return self.data.decode("utf-8")
+
+
+
+
+
+class HttpResponse
+(status: int = 200, headers: Record = None, body: bytes = None)
+
+
+
Represents an Http Response to be generated by the Nitric Membrane in response to an Http Request Trigger.
+
Construct a new HttpResponse.
+
+
+Expand source code
+
+
class HttpResponse(Response):
+ """Represents an Http Response to be generated by the Nitric Membrane in response to an Http Request Trigger."""
+
+ def __init__(self, status: int = 200, headers: Record = None, body: bytes = None):
+ """Construct a new HttpResponse."""
+ self.status = status
+ self.headers = headers if headers else {}
+ self.body = body if body else bytes()
class Request(ABC):
+ """Represents an abstract trigger request."""
+
+ def __init__(self, data: bytes):
+ """Construct a new Request."""
+ self.data = data
Represents an abstract request/response context for any trigger.
+
+
+Expand source code
+
+
class TriggerContext(ABC):
+ """Represents an abstract request/response context for any trigger."""
+
+ def http(self) -> Union[HttpContext, None]:
+ """Return this context as an HttpContext if it is one, otherwise returns None."""
+ return None
+
+ def event(self) -> Union[EventContext, None]:
+ """Return this context as an EventContext if it is one, otherwise returns None."""
+ return None
Return this context as an HttpContext if it is one, otherwise returns None.
+
+
+Expand source code
+
+
def http(self) -> Union[HttpContext, None]:
+ """Return this context as an HttpContext if it is one, otherwise returns None."""
+ return None
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/nitric/faas/faas.html b/docs/nitric/faas/faas.html
deleted file mode 100644
index 09e23be..0000000
--- a/docs/nitric/faas/faas.html
+++ /dev/null
@@ -1,348 +0,0 @@
-
-
-
-
-
-
-nitric.faas.faas API documentation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Module nitric.faas.faas
-
-
-
-
-Expand source code
-
-
#
-# Copyright (c) 2021 Nitric Technologies Pty Ltd.
-#
-# This file is part of Nitric Python 3 SDK.
-# See https://github.com/nitrictech/python-sdk for further info.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-import traceback
-from typing import Callable, Union, Coroutine, Any
-
-import betterproto
-from betterproto.grpc.util.async_channel import AsyncChannel
-
-from nitric.utils import new_default_channel
-from nitric.faas import Trigger, Response
-from nitric.proto.nitric.faas.v1 import FaasStub, InitRequest, ClientMessage
-import asyncio
-
-
-async def _register_faas_worker(
- func: Callable[[Trigger], Union[Coroutine[Any, Any, Union[Response, None, dict]], Union[Response, None, dict]]]
-):
- """
- Register a new FaaS worker with the Membrane, using the provided function as the handler.
-
- :param func: handler function for incoming triggers. Can be sync or async, async is preferred.
- """
- channel = new_default_channel()
- client = FaasStub(channel)
- request_channel = AsyncChannel(close=True)
- # We can start be sending all the requests we already have
- try:
- await request_channel.send(ClientMessage(init_request=InitRequest()))
- async for srv_msg in client.trigger_stream(request_channel):
- # The response iterator will remain active until the connection is closed
- msg_type, val = betterproto.which_one_of(srv_msg, "content")
-
- if msg_type == "init_response":
- print("function connected to Membrane")
- # We don't need to reply
- # proceed to the next available message
- continue
- if msg_type == "trigger_request":
- trigger = Trigger.from_trigger_request(srv_msg.trigger_request)
- try:
- response = await func(trigger) if asyncio.iscoroutinefunction(func) else func(trigger)
- except Exception:
- print("Error calling handler function")
- traceback.print_exc()
- response = trigger.default_response()
- if response.context.is_http():
- response.context.as_http().status = 500
- else:
- response.context.as_topic().success = False
-
- # Handle lite responses with just data, assume a success in these cases
- if not isinstance(response, Response):
- full_response = trigger.default_response()
- full_response.data = bytes(str(response), "utf-8")
- response = full_response
-
- # Send function response back to server
- await request_channel.send(
- ClientMessage(id=srv_msg.id, trigger_response=response.to_grpc_trigger_response_context())
- )
- else:
- print("unhandled message type {0}, skipping".format(msg_type))
- continue
- if request_channel.done():
- break
- except Exception:
- traceback.print_exc()
- finally:
- print("stream from Membrane closed, closing client stream")
- # The channel must be closed to complete the gRPC connection
- request_channel.close()
- channel.close()
-
-
-def start(handler: Callable[[Trigger], Coroutine[Any, Any, Union[Response, None, dict]]]):
- """
- Register the provided function as the trigger handler and starts handling new trigger requests.
-
- :param handler: handler function for incoming triggers. Can be sync or async, async is preferred.
- """
- asyncio.run(_register_faas_worker(handler))
Register the provided function as the trigger handler and starts handling new trigger requests.
-
:param handler: handler function for incoming triggers. Can be sync or async, async is preferred.
-
-
-Expand source code
-
-
def start(handler: Callable[[Trigger], Coroutine[Any, Any, Union[Response, None, dict]]]):
- """
- Register the provided function as the trigger handler and starts handling new trigger requests.
-
- :param handler: handler function for incoming triggers. Can be sync or async, async is preferred.
- """
- asyncio.run(_register_faas_worker(handler))
Construct a new handler using the provided function to handle new requests.
-
-
-Expand source code
-
-
class Handler(object):
- """Nitric Function handler."""
-
- def __init__(self, func: Callable[[Trigger], Union[Response, str]]):
- """Construct a new handler using the provided function to handle new requests."""
- self.func = func
-
- def __call__(self, path="", *args):
- """Construct Nitric Request from HTTP Request."""
- trigger_request = construct_request()
-
- grpc_trigger_response: TriggerResponse
-
- # convert it to a trigger
- trigger = Trigger.from_trigger_request(trigger_request)
-
- try:
- # Execute the handler function
- response: Union[Response, str] = self.func(trigger)
-
- final_response: Response
- if isinstance(response, str):
- final_response = trigger.default_response()
- final_response.data = response.encode()
- elif isinstance(response, Response):
- final_response = response
- else:
- # assume None
- final_response = trigger.default_response()
- final_response.data = "".encode()
-
- grpc_trigger_response = final_response.to_grpc_trigger_response_context()
-
- except Exception:
- trigger_response = trigger.default_response()
- if trigger_response.context.is_http():
- trigger_response.context.as_http().status = 500
- trigger_response.context.as_http().headers = {"Content-Type": "text/html"}
- trigger_response.data = exception_to_html().encode()
- elif trigger_response.context.is_topic():
- trigger_response.data = "Error processing message"
- trigger_response.context.as_topic().success = False
-
- grpc_trigger_response = trigger_response.to_grpc_trigger_response_context()
-
- return http_response(grpc_trigger_response)
-
-
-
-class TriggerRequest
-(*args, **kwargs)
-
-
-
A ProtocolMessage
-
Ancestors
-
-
google.protobuf.pyext._message.CMessage
-
google.protobuf.message.Message
-
-
Class variables
-
-
var DESCRIPTOR
-
-
-
-
-
Instance variables
-
-
var data
-
-
Field nitric.faas.v1.TriggerRequest.data
-
-
var http
-
-
Field nitric.faas.v1.TriggerRequest.http
-
-
var mime_type
-
-
Field nitric.faas.v1.TriggerRequest.mime_type
-
-
var topic
-
-
Field nitric.faas.v1.TriggerRequest.topic
-
-
-
-
-class TriggerResponse
-(*args, **kwargs)
-
-
-
A ProtocolMessage
-
Ancestors
-
-
google.protobuf.pyext._message.CMessage
-
google.protobuf.message.Message
-
-
Class variables
-
-
var DESCRIPTOR
-
-
-
-
-
Instance variables
-
-
var data
-
-
Field nitric.faas.v1.TriggerResponse.data
-
-
var http
-
-
Field nitric.faas.v1.TriggerResponse.http
-
-
var topic
-
-
Field nitric.faas.v1.TriggerResponse.topic
-
-
-
-
-=======
->>>>>>> feat: port faas.start to bi-di streaming with membrane
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/nitric/faas/index.html b/docs/nitric/faas/index.html
deleted file mode 100644
index e74007e..0000000
--- a/docs/nitric/faas/index.html
+++ /dev/null
@@ -1,874 +0,0 @@
-
-
-
-
-
-
-nitric.faas API documentation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Module nitric.faas
-
-
-
Nitric Function as a Service (FaaS) Package.
-
-
-Expand source code
-
-
#
-# Copyright (c) 2021 Nitric Technologies Pty Ltd.
-#
-# This file is part of Nitric Python 3 SDK.
-# See https://github.com/nitrictech/python-sdk for further info.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-"""Nitric Function as a Service (FaaS) Package."""
-from nitric.faas.trigger import Trigger, TriggerContext
-from nitric.faas.response import Response, ResponseContext, HttpResponseContext, TopicResponseContext
-from nitric.faas.faas import start
-
-__all__ = [
- "Trigger",
- "Response",
- "ResponseContext",
- "HttpResponseContext",
- "TopicResponseContext",
- "TriggerContext",
- "start",
-]
Register the provided function as the trigger handler and starts handling new trigger requests.
-
:param handler: handler function for incoming triggers. Can be sync or async, async is preferred.
-
-
-Expand source code
-
-
def start(handler: Callable[[Trigger], Coroutine[Any, Any, Union[Response, None, dict]]]):
- """
- Register the provided function as the trigger handler and starts handling new trigger requests.
-
- :param handler: handler function for incoming triggers. Can be sync or async, async is preferred.
- """
- asyncio.run(_register_faas_worker(handler))
Represents HTTP specific response context data such as an HTTP status and headers.
-
-
-Expand source code
-
-
class HttpResponseContext(object):
- """Represents HTTP specific response context data such as an HTTP status and headers."""
-
- headers: dict = field(default_factory=lambda: {})
- status: int = 200
-
- def to_grpc_http_response_context(self) -> v1.HttpResponseContext:
- """Reformat this http response context for on the wire transfer."""
- return v1.HttpResponseContext(headers=self.headers, status=self.status)
Reformat this http response context for on the wire transfer.
-
-
-Expand source code
-
-
def to_grpc_http_response_context(self) -> v1.HttpResponseContext:
- """Reformat this http response context for on the wire transfer."""
- return v1.HttpResponseContext(headers=self.headers, status=self.status)
Additional context data for a trigger response, specific to the original trigger type.
-
-
-Expand source code
-
-
class ResponseContext(object):
- """Additional context data for a trigger response, specific to the original trigger type."""
-
- context: Union[TopicResponseContext, HttpResponseContext]
-
- def is_http(self):
- """Indicate whether the trigger was from an HTTP request."""
- return isinstance(self.context, HttpResponseContext)
-
- def is_topic(self):
- """Indicate whether the trigger was from a topic (event)."""
- return isinstance(self.context, TopicResponseContext)
-
- def as_http(self) -> Union[HttpResponseContext, None]:
- """
- Return this context as an HTTP context type.
-
- If the trigger wasn't an HTTP request, this function returns None.
- is_http() should be used first to determine if this was an HTTP request trigger.
- """
- if not self.is_http():
- return None
-
- return self.context
-
- def as_topic(self) -> Union[TopicResponseContext, None]:
- """
- Return this context as a topic context type.
-
- If the trigger wasn't an event from a topic, this function returns None.
- is_topic() should be used first to determine if this was a topic trigger.
- """
- if not self.is_topic():
- return None
-
- return self.context
If the trigger wasn't an HTTP request, this function returns None.
-is_http() should be used first to determine if this was an HTTP request trigger.
-
-
-Expand source code
-
-
def as_http(self) -> Union[HttpResponseContext, None]:
- """
- Return this context as an HTTP context type.
-
- If the trigger wasn't an HTTP request, this function returns None.
- is_http() should be used first to determine if this was an HTTP request trigger.
- """
- if not self.is_http():
- return None
-
- return self.context
If the trigger wasn't an event from a topic, this function returns None.
-is_topic() should be used first to determine if this was a topic trigger.
-
-
-Expand source code
-
-
def as_topic(self) -> Union[TopicResponseContext, None]:
- """
- Return this context as a topic context type.
-
- If the trigger wasn't an event from a topic, this function returns None.
- is_topic() should be used first to determine if this was a topic trigger.
- """
- if not self.is_topic():
- return None
-
- return self.context
-
-
-
-def is_http(self)
-
-
-
Indicate whether the trigger was from an HTTP request.
-
-
-Expand source code
-
-
def is_http(self):
- """Indicate whether the trigger was from an HTTP request."""
- return isinstance(self.context, HttpResponseContext)
-
-
-
-def is_topic(self)
-
-
-
Indicate whether the trigger was from a topic (event).
-
-
-Expand source code
-
-
def is_topic(self):
- """Indicate whether the trigger was from a topic (event)."""
- return isinstance(self.context, TopicResponseContext)
Represents a topic/event specific response context data such as whether the event was processed successfully.
-
-
-Expand source code
-
-
class TopicResponseContext(object):
- """Represents a topic/event specific response context data such as whether the event was processed successfully."""
-
- success: bool = True
-
- def to_grpc_topic_response_context(self) -> v1.TopicResponseContext:
- """Reformat this topic response context for on the wire transfer."""
- return v1.TopicResponseContext(success=self.success)
Reformat this topic response context for on the wire transfer.
-
-
-Expand source code
-
-
def to_grpc_topic_response_context(self) -> v1.TopicResponseContext:
- """Reformat this topic response context for on the wire transfer."""
- return v1.TopicResponseContext(success=self.success)
These requests are normalized from their original stack-specific structures.
-
-
-Expand source code
-
-
class Trigger(object):
- """
- Represents a standard Nitric function request.
-
- These requests are normalized from their original stack-specific structures.
- """
-
- context: TriggerContext
- data: bytes = field(default_factory=bytes)
-
- def get_body(self) -> bytes:
- """Return the bytes of the body of the request."""
- return self.data
-
- def get_object(self) -> dict:
- """
- Assume the payload is JSON and return the content deserialized into a dictionary.
-
- :raises JSONDecodeError: raised when the request payload (body) is not valid JSON.
-
- :return: the deserialized JSON request body as a dictionary
- """
- import json
-
- return json.loads(self.data)
-
- def default_response(self) -> Response:
- """
- Return the trigger response, based on the trigger context type.
-
- The returned response can be interrogated with its context to determine the appropriate
- response context e.g. response.context.is_http() or response.context.is_topic().
- """
- response_ctx = None
-
- if self.context.is_http():
- response_ctx = ResponseContext(context=HttpResponseContext())
- elif self.context.is_topic():
- response_ctx = ResponseContext(context=TopicResponseContext())
-
- return Response(context=response_ctx)
-
- @staticmethod
- def from_trigger_request(trigger_request: TriggerRequest):
- """Return the python SDK implementation of a Trigger from a protobuf representation."""
- context = TriggerContext.from_trigger_request(trigger_request)
-
- return Trigger(context=context, data=trigger_request.data)
Return the trigger response, based on the trigger context type.
-
The returned response can be interrogated with its context to determine the appropriate
-response context e.g. response.context.is_http() or response.context.is_topic().
-
-
-Expand source code
-
-
def default_response(self) -> Response:
- """
- Return the trigger response, based on the trigger context type.
-
- The returned response can be interrogated with its context to determine the appropriate
- response context e.g. response.context.is_http() or response.context.is_topic().
- """
- response_ctx = None
-
- if self.context.is_http():
- response_ctx = ResponseContext(context=HttpResponseContext())
- elif self.context.is_topic():
- response_ctx = ResponseContext(context=TopicResponseContext())
-
- return Response(context=response_ctx)
-
-
-
-def get_body(self) ‑> bytes
-
-
-
Return the bytes of the body of the request.
-
-
-Expand source code
-
-
def get_body(self) -> bytes:
- """Return the bytes of the body of the request."""
- return self.data
-
-
-
-def get_object(self) ‑> dict
-
-
-
Assume the payload is JSON and return the content deserialized into a dictionary.
-
:raises JSONDecodeError: raised when the request payload (body) is not valid JSON.
-
:return: the deserialized JSON request body as a dictionary
-
-
-Expand source code
-
-
def get_object(self) -> dict:
- """
- Assume the payload is JSON and return the content deserialized into a dictionary.
-
- :raises JSONDecodeError: raised when the request payload (body) is not valid JSON.
-
- :return: the deserialized JSON request body as a dictionary
- """
- import json
-
- return json.loads(self.data)
Represents the contextual metadata for a Nitric function request.
-
-
-Expand source code
-
-
class TriggerContext(object):
- """Represents the contextual metadata for a Nitric function request."""
-
- context: typing.Union[TopicTriggerContext, HttpTriggerContext]
-
- def is_http(self) -> bool:
- """
- Indicate whether the trigger was from an HTTP request.
-
- This indicates the availability of additional HTTP specific context such as path, query parameters and headers.
- """
- return isinstance(self.context, HttpTriggerContext)
-
- def as_http(self) -> typing.Union[HttpTriggerContext, None]:
- """
- Return this context as an HTTP context type.
-
- If the trigger wasn't an HTTP request, this function returns None.
- is_http() should be used first to determine if this was an HTTP request trigger.
- """
- if not self.is_http():
- return None
-
- return self.context
-
- def is_topic(self) -> bool:
- """
- Indicate whether the trigger was from a topic (event).
-
- This indicates the availability of additional topic/event specific context such as the topic name.
- """
- return isinstance(self.context, TriggerContext)
-
- def as_topic(self) -> typing.Union[TopicTriggerContext, None]:
- """
- Return this context as a topic context type.
-
- If the trigger wasn't an event from a topic, this function returns None.
- is_topic() should be used first to determine if this was a topic trigger.
- """
- if not self.is_topic():
- return None
-
- return self.context
-
- @staticmethod
- def from_trigger_request(trigger_request: TriggerRequest):
- """Return a TriggerContext from a TriggerRequest."""
- if trigger_request.http is not None:
- return TriggerContext(
- context=HttpTriggerContext(
-<<<<<<< refs/remotes/origin/main
- headers=dict(trigger_request.http.headers),
- path=trigger_request.http.path,
- method=trigger_request.http.method,
- query_params=dict(trigger_request.http.query_params),
-=======
- headers=trigger_request.http.headers,
- method=trigger_request.http.method,
- query_params=trigger_request.http.query_params,
- path=trigger_request.http.path,
->>>>>>> feat: port faas.start to bi-di streaming with membrane
- )
- )
- elif trigger_request.topic is not None:
- return TriggerContext(context=TopicTriggerContext(topic=trigger_request.topic.topic))
- else:
- # We have an error
- # should probably raise an exception
- return None
If the trigger wasn't an HTTP request, this function returns None.
-is_http() should be used first to determine if this was an HTTP request trigger.
-
-
-Expand source code
-
-
def as_http(self) -> typing.Union[HttpTriggerContext, None]:
- """
- Return this context as an HTTP context type.
-
- If the trigger wasn't an HTTP request, this function returns None.
- is_http() should be used first to determine if this was an HTTP request trigger.
- """
- if not self.is_http():
- return None
-
- return self.context
If the trigger wasn't an event from a topic, this function returns None.
-is_topic() should be used first to determine if this was a topic trigger.
-
-
-Expand source code
-
-
def as_topic(self) -> typing.Union[TopicTriggerContext, None]:
- """
- Return this context as a topic context type.
-
- If the trigger wasn't an event from a topic, this function returns None.
- is_topic() should be used first to determine if this was a topic trigger.
- """
- if not self.is_topic():
- return None
-
- return self.context
-
-
-
-def is_http(self) ‑> bool
-
-
-
Indicate whether the trigger was from an HTTP request.
-
This indicates the availability of additional HTTP specific context such as path, query parameters and headers.
-
-
-Expand source code
-
-
def is_http(self) -> bool:
- """
- Indicate whether the trigger was from an HTTP request.
-
- This indicates the availability of additional HTTP specific context such as path, query parameters and headers.
- """
- return isinstance(self.context, HttpTriggerContext)
-
-
-
-def is_topic(self) ‑> bool
-
-
-
Indicate whether the trigger was from a topic (event).
-
This indicates the availability of additional topic/event specific context such as the topic name.
-
-
-Expand source code
-
-
def is_topic(self) -> bool:
- """
- Indicate whether the trigger was from a topic (event).
-
- This indicates the availability of additional topic/event specific context such as the topic name.
- """
- return isinstance(self.context, TriggerContext)
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/nitric/faas/response.html b/docs/nitric/faas/response.html
deleted file mode 100644
index a39fad2..0000000
--- a/docs/nitric/faas/response.html
+++ /dev/null
@@ -1,545 +0,0 @@
-
-
-
-
-
-
-nitric.faas.response API documentation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Module nitric.faas.response
-
-
-
-
-Expand source code
-
-
#
-# Copyright (c) 2021 Nitric Technologies Pty Ltd.
-#
-# This file is part of Nitric Python 3 SDK.
-# See https://github.com/nitrictech/python-sdk for further info.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-from dataclasses import dataclass, field
-from typing import Union
-from nitric.proto.nitric.faas import v1
-from nitric.proto.nitric.faas.v1 import TriggerResponse
-
-
-@dataclass(order=True)
-class TopicResponseContext(object):
- """Represents a topic/event specific response context data such as whether the event was processed successfully."""
-
- success: bool = True
-
- def to_grpc_topic_response_context(self) -> v1.TopicResponseContext:
- """Reformat this topic response context for on the wire transfer."""
- return v1.TopicResponseContext(success=self.success)
-
-
-@dataclass(order=True)
-class HttpResponseContext(object):
- """Represents HTTP specific response context data such as an HTTP status and headers."""
-
- headers: dict = field(default_factory=lambda: {})
- status: int = 200
-
- def to_grpc_http_response_context(self) -> v1.HttpResponseContext:
- """Reformat this http response context for on the wire transfer."""
- return v1.HttpResponseContext(headers=self.headers, status=self.status)
-
-
-@dataclass(order=True)
-class ResponseContext(object):
- """Additional context data for a trigger response, specific to the original trigger type."""
-
- context: Union[TopicResponseContext, HttpResponseContext]
-
- def is_http(self):
- """Indicate whether the trigger was from an HTTP request."""
- return isinstance(self.context, HttpResponseContext)
-
- def is_topic(self):
- """Indicate whether the trigger was from a topic (event)."""
- return isinstance(self.context, TopicResponseContext)
-
- def as_http(self) -> Union[HttpResponseContext, None]:
- """
- Return this context as an HTTP context type.
-
- If the trigger wasn't an HTTP request, this function returns None.
- is_http() should be used first to determine if this was an HTTP request trigger.
- """
- if not self.is_http():
- return None
-
- return self.context
-
- def as_topic(self) -> Union[TopicResponseContext, None]:
- """
- Return this context as a topic context type.
-
- If the trigger wasn't an event from a topic, this function returns None.
- is_topic() should be used first to determine if this was a topic trigger.
- """
- if not self.is_topic():
- return None
-
- return self.context
-
-
-@dataclass(order=True)
-class Response(object):
- """Nitric Function as a Service (FaaS) response class."""
-
- context: ResponseContext
- data: bytes = field(default_factory=bytes)
-
- def to_grpc_trigger_response_context(self) -> TriggerResponse:
- """Translate a response object ready for on the wire transport."""
- response = TriggerResponse(data=self.data)
-
- if self.context.is_http():
- ctx = self.context.as_http()
- response.http = ctx.to_grpc_http_response_context()
- elif self.context.is_topic():
- ctx = self.context.as_topic()
- response.topic = ctx.to_grpc_topic_response_context()
-
- return response
Represents HTTP specific response context data such as an HTTP status and headers.
-
-
-Expand source code
-
-
class HttpResponseContext(object):
- """Represents HTTP specific response context data such as an HTTP status and headers."""
-
- headers: dict = field(default_factory=lambda: {})
- status: int = 200
-
- def to_grpc_http_response_context(self) -> v1.HttpResponseContext:
- """Reformat this http response context for on the wire transfer."""
- return v1.HttpResponseContext(headers=self.headers, status=self.status)
Reformat this http response context for on the wire transfer.
-
-
-Expand source code
-
-
def to_grpc_http_response_context(self) -> v1.HttpResponseContext:
- """Reformat this http response context for on the wire transfer."""
- return v1.HttpResponseContext(headers=self.headers, status=self.status)
Additional context data for a trigger response, specific to the original trigger type.
-
-
-Expand source code
-
-
class ResponseContext(object):
- """Additional context data for a trigger response, specific to the original trigger type."""
-
- context: Union[TopicResponseContext, HttpResponseContext]
-
- def is_http(self):
- """Indicate whether the trigger was from an HTTP request."""
- return isinstance(self.context, HttpResponseContext)
-
- def is_topic(self):
- """Indicate whether the trigger was from a topic (event)."""
- return isinstance(self.context, TopicResponseContext)
-
- def as_http(self) -> Union[HttpResponseContext, None]:
- """
- Return this context as an HTTP context type.
-
- If the trigger wasn't an HTTP request, this function returns None.
- is_http() should be used first to determine if this was an HTTP request trigger.
- """
- if not self.is_http():
- return None
-
- return self.context
-
- def as_topic(self) -> Union[TopicResponseContext, None]:
- """
- Return this context as a topic context type.
-
- If the trigger wasn't an event from a topic, this function returns None.
- is_topic() should be used first to determine if this was a topic trigger.
- """
- if not self.is_topic():
- return None
-
- return self.context
If the trigger wasn't an HTTP request, this function returns None.
-is_http() should be used first to determine if this was an HTTP request trigger.
-
-
-Expand source code
-
-
def as_http(self) -> Union[HttpResponseContext, None]:
- """
- Return this context as an HTTP context type.
-
- If the trigger wasn't an HTTP request, this function returns None.
- is_http() should be used first to determine if this was an HTTP request trigger.
- """
- if not self.is_http():
- return None
-
- return self.context
If the trigger wasn't an event from a topic, this function returns None.
-is_topic() should be used first to determine if this was a topic trigger.
-
-
-Expand source code
-
-
def as_topic(self) -> Union[TopicResponseContext, None]:
- """
- Return this context as a topic context type.
-
- If the trigger wasn't an event from a topic, this function returns None.
- is_topic() should be used first to determine if this was a topic trigger.
- """
- if not self.is_topic():
- return None
-
- return self.context
-
-
-
-def is_http(self)
-
-
-
Indicate whether the trigger was from an HTTP request.
-
-
-Expand source code
-
-
def is_http(self):
- """Indicate whether the trigger was from an HTTP request."""
- return isinstance(self.context, HttpResponseContext)
-
-
-
-def is_topic(self)
-
-
-
Indicate whether the trigger was from a topic (event).
-
-
-Expand source code
-
-
def is_topic(self):
- """Indicate whether the trigger was from a topic (event)."""
- return isinstance(self.context, TopicResponseContext)
Represents a topic/event specific response context data such as whether the event was processed successfully.
-
-
-Expand source code
-
-
class TopicResponseContext(object):
- """Represents a topic/event specific response context data such as whether the event was processed successfully."""
-
- success: bool = True
-
- def to_grpc_topic_response_context(self) -> v1.TopicResponseContext:
- """Reformat this topic response context for on the wire transfer."""
- return v1.TopicResponseContext(success=self.success)
-
-<<<<<<< refs/remotes/origin/main
-
-
-
-
-class TriggerResponse
-(*args, **kwargs)
-
-
-
A ProtocolMessage
-
Ancestors
-
-
google.protobuf.pyext._message.CMessage
-
google.protobuf.message.Message
-
-
Class variables
-
-
var DESCRIPTOR
-=======
-
Class variables
-
-
var success : bool
->>>>>>> feat: port faas.start to bi-di streaming with membrane
-
Reformat this topic response context for on the wire transfer.
-
-
-Expand source code
-
-
def to_grpc_topic_response_context(self) -> v1.TopicResponseContext:
- """Reformat this topic response context for on the wire transfer."""
- return v1.TopicResponseContext(success=self.success)
-
->>>>>>> feat: port faas.start to bi-di streaming with membrane
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/nitric/faas/trigger.html b/docs/nitric/faas/trigger.html
deleted file mode 100644
index b3d8c70..0000000
--- a/docs/nitric/faas/trigger.html
+++ /dev/null
@@ -1,760 +0,0 @@
-
-
-
-
-
-
-nitric.faas.trigger API documentation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Module nitric.faas.trigger
-
-
-
-
-Expand source code
-
-
#
-# Copyright (c) 2021 Nitric Technologies Pty Ltd.
-#
-# This file is part of Nitric Python 3 SDK.
-# See https://github.com/nitrictech/python-sdk for further info.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-import typing
-from dataclasses import dataclass, field
-
-import nitric.faas
-from nitric.proto.nitric.faas.v1 import TriggerRequest
-
-from nitric.faas.response import Response, TopicResponseContext, HttpResponseContext, ResponseContext
-
-
-@dataclass(order=True)
-class HttpTriggerContext(object):
- """Represents Trigger metadata from a HTTP subscription."""
-
- method: str
- path: str
- headers: typing.Dict[str, str]
- query_params: typing.Dict[str, str]
-
-
-class TopicTriggerContext(object):
- """Represents Trigger metadata from a topic subscription."""
-
- def __init__(self, topic: str):
- """Construct a new TopicTriggerContext, including the name of the source topic for this trigger."""
- self.topic = topic
-
-
-@dataclass(order=True)
-class TriggerContext(object):
- """Represents the contextual metadata for a Nitric function request."""
-
- context: typing.Union[TopicTriggerContext, HttpTriggerContext]
-
- def is_http(self) -> bool:
- """
- Indicate whether the trigger was from an HTTP request.
-
- This indicates the availability of additional HTTP specific context such as path, query parameters and headers.
- """
- return isinstance(self.context, HttpTriggerContext)
-
- def as_http(self) -> typing.Union[HttpTriggerContext, None]:
- """
- Return this context as an HTTP context type.
-
- If the trigger wasn't an HTTP request, this function returns None.
- is_http() should be used first to determine if this was an HTTP request trigger.
- """
- if not self.is_http():
- return None
-
- return self.context
-
- def is_topic(self) -> bool:
- """
- Indicate whether the trigger was from a topic (event).
-
- This indicates the availability of additional topic/event specific context such as the topic name.
- """
- return isinstance(self.context, TriggerContext)
-
- def as_topic(self) -> typing.Union[TopicTriggerContext, None]:
- """
- Return this context as a topic context type.
-
- If the trigger wasn't an event from a topic, this function returns None.
- is_topic() should be used first to determine if this was a topic trigger.
- """
- if not self.is_topic():
- return None
-
- return self.context
-
- @staticmethod
- def from_trigger_request(trigger_request: TriggerRequest):
- """Return a TriggerContext from a TriggerRequest."""
- if trigger_request.http is not None:
- return TriggerContext(
- context=HttpTriggerContext(
-<<<<<<< refs/remotes/origin/main
- headers=dict(trigger_request.http.headers),
- path=trigger_request.http.path,
- method=trigger_request.http.method,
- query_params=dict(trigger_request.http.query_params),
-=======
- headers=trigger_request.http.headers,
- method=trigger_request.http.method,
- query_params=trigger_request.http.query_params,
- path=trigger_request.http.path,
->>>>>>> feat: port faas.start to bi-di streaming with membrane
- )
- )
- elif trigger_request.topic is not None:
- return TriggerContext(context=TopicTriggerContext(topic=trigger_request.topic.topic))
- else:
- # We have an error
- # should probably raise an exception
- return None
-
-
-def _clean_header(header_name: str):
- """Convert a Nitric HTTP request header name into the equivalent Context property name."""
- return header_name.lower().replace("x-nitric-", "").replace("-", "_")
-
-
-@dataclass(order=True)
-class Trigger(object):
- """
- Represents a standard Nitric function request.
-
- These requests are normalized from their original stack-specific structures.
- """
-
- context: TriggerContext
- data: bytes = field(default_factory=bytes)
-
- def get_body(self) -> bytes:
- """Return the bytes of the body of the request."""
- return self.data
-
- def get_object(self) -> dict:
- """
- Assume the payload is JSON and return the content deserialized into a dictionary.
-
- :raises JSONDecodeError: raised when the request payload (body) is not valid JSON.
-
- :return: the deserialized JSON request body as a dictionary
- """
- import json
-
- return json.loads(self.data)
-
- def default_response(self) -> Response:
- """
- Return the trigger response, based on the trigger context type.
-
- The returned response can be interrogated with its context to determine the appropriate
- response context e.g. response.context.is_http() or response.context.is_topic().
- """
- response_ctx = None
-
- if self.context.is_http():
- response_ctx = ResponseContext(context=HttpResponseContext())
- elif self.context.is_topic():
- response_ctx = ResponseContext(context=TopicResponseContext())
-
- return Response(context=response_ctx)
-
- @staticmethod
- def from_trigger_request(trigger_request: TriggerRequest):
- """Return the python SDK implementation of a Trigger from a protobuf representation."""
- context = TriggerContext.from_trigger_request(trigger_request)
-
- return Trigger(context=context, data=trigger_request.data)
Represents Trigger metadata from a HTTP subscription.
-
-
-Expand source code
-
-
class HttpTriggerContext(object):
- """Represents Trigger metadata from a HTTP subscription."""
-
- method: str
- path: str
- headers: typing.Dict[str, str]
- query_params: typing.Dict[str, str]
-
-
Class variables
-
-
var headers : Dict[str, str]
-
-
-
-
var method : str
-
-
-
-
var path : str
-
-
-
-
var query_params : Dict[str, str]
-
-
-
-
-
-
-class TopicTriggerContext
-(topic: str)
-
-
-
Represents Trigger metadata from a topic subscription.
-
Construct a new TopicTriggerContext, including the name of the source topic for this trigger.
-
-
-Expand source code
-
-
class TopicTriggerContext(object):
- """Represents Trigger metadata from a topic subscription."""
-
- def __init__(self, topic: str):
- """Construct a new TopicTriggerContext, including the name of the source topic for this trigger."""
- self.topic = topic
These requests are normalized from their original stack-specific structures.
-
-
-Expand source code
-
-
class Trigger(object):
- """
- Represents a standard Nitric function request.
-
- These requests are normalized from their original stack-specific structures.
- """
-
- context: TriggerContext
- data: bytes = field(default_factory=bytes)
-
- def get_body(self) -> bytes:
- """Return the bytes of the body of the request."""
- return self.data
-
- def get_object(self) -> dict:
- """
- Assume the payload is JSON and return the content deserialized into a dictionary.
-
- :raises JSONDecodeError: raised when the request payload (body) is not valid JSON.
-
- :return: the deserialized JSON request body as a dictionary
- """
- import json
-
- return json.loads(self.data)
-
- def default_response(self) -> Response:
- """
- Return the trigger response, based on the trigger context type.
-
- The returned response can be interrogated with its context to determine the appropriate
- response context e.g. response.context.is_http() or response.context.is_topic().
- """
- response_ctx = None
-
- if self.context.is_http():
- response_ctx = ResponseContext(context=HttpResponseContext())
- elif self.context.is_topic():
- response_ctx = ResponseContext(context=TopicResponseContext())
-
- return Response(context=response_ctx)
-
- @staticmethod
- def from_trigger_request(trigger_request: TriggerRequest):
- """Return the python SDK implementation of a Trigger from a protobuf representation."""
- context = TriggerContext.from_trigger_request(trigger_request)
-
- return Trigger(context=context, data=trigger_request.data)
Return the trigger response, based on the trigger context type.
-
The returned response can be interrogated with its context to determine the appropriate
-response context e.g. response.context.is_http() or response.context.is_topic().
-
-
-Expand source code
-
-
def default_response(self) -> Response:
- """
- Return the trigger response, based on the trigger context type.
-
- The returned response can be interrogated with its context to determine the appropriate
- response context e.g. response.context.is_http() or response.context.is_topic().
- """
- response_ctx = None
-
- if self.context.is_http():
- response_ctx = ResponseContext(context=HttpResponseContext())
- elif self.context.is_topic():
- response_ctx = ResponseContext(context=TopicResponseContext())
-
- return Response(context=response_ctx)
-
-
-
-def get_body(self) ‑> bytes
-
-
-
Return the bytes of the body of the request.
-
-
-Expand source code
-
-
def get_body(self) -> bytes:
- """Return the bytes of the body of the request."""
- return self.data
-
-
-
-def get_object(self) ‑> dict
-
-
-
Assume the payload is JSON and return the content deserialized into a dictionary.
-
:raises JSONDecodeError: raised when the request payload (body) is not valid JSON.
-
:return: the deserialized JSON request body as a dictionary
-
-
-Expand source code
-
-
def get_object(self) -> dict:
- """
- Assume the payload is JSON and return the content deserialized into a dictionary.
-
- :raises JSONDecodeError: raised when the request payload (body) is not valid JSON.
-
- :return: the deserialized JSON request body as a dictionary
- """
- import json
-
- return json.loads(self.data)
Represents the contextual metadata for a Nitric function request.
-
-
-Expand source code
-
-
class TriggerContext(object):
- """Represents the contextual metadata for a Nitric function request."""
-
- context: typing.Union[TopicTriggerContext, HttpTriggerContext]
-
- def is_http(self) -> bool:
- """
- Indicate whether the trigger was from an HTTP request.
-
- This indicates the availability of additional HTTP specific context such as path, query parameters and headers.
- """
- return isinstance(self.context, HttpTriggerContext)
-
- def as_http(self) -> typing.Union[HttpTriggerContext, None]:
- """
- Return this context as an HTTP context type.
-
- If the trigger wasn't an HTTP request, this function returns None.
- is_http() should be used first to determine if this was an HTTP request trigger.
- """
- if not self.is_http():
- return None
-
- return self.context
-
- def is_topic(self) -> bool:
- """
- Indicate whether the trigger was from a topic (event).
-
- This indicates the availability of additional topic/event specific context such as the topic name.
- """
- return isinstance(self.context, TriggerContext)
-
- def as_topic(self) -> typing.Union[TopicTriggerContext, None]:
- """
- Return this context as a topic context type.
-
- If the trigger wasn't an event from a topic, this function returns None.
- is_topic() should be used first to determine if this was a topic trigger.
- """
- if not self.is_topic():
- return None
-
- return self.context
-
- @staticmethod
- def from_trigger_request(trigger_request: TriggerRequest):
- """Return a TriggerContext from a TriggerRequest."""
- if trigger_request.http is not None:
- return TriggerContext(
- context=HttpTriggerContext(
-<<<<<<< refs/remotes/origin/main
- headers=dict(trigger_request.http.headers),
- path=trigger_request.http.path,
- method=trigger_request.http.method,
- query_params=dict(trigger_request.http.query_params),
-=======
- headers=trigger_request.http.headers,
- method=trigger_request.http.method,
- query_params=trigger_request.http.query_params,
- path=trigger_request.http.path,
->>>>>>> feat: port faas.start to bi-di streaming with membrane
- )
- )
- elif trigger_request.topic is not None:
- return TriggerContext(context=TopicTriggerContext(topic=trigger_request.topic.topic))
- else:
- # We have an error
- # should probably raise an exception
- return None
If the trigger wasn't an HTTP request, this function returns None.
-is_http() should be used first to determine if this was an HTTP request trigger.
-
-
-Expand source code
-
-
def as_http(self) -> typing.Union[HttpTriggerContext, None]:
- """
- Return this context as an HTTP context type.
-
- If the trigger wasn't an HTTP request, this function returns None.
- is_http() should be used first to determine if this was an HTTP request trigger.
- """
- if not self.is_http():
- return None
-
- return self.context
If the trigger wasn't an event from a topic, this function returns None.
-is_topic() should be used first to determine if this was a topic trigger.
-
-
-Expand source code
-
-
def as_topic(self) -> typing.Union[TopicTriggerContext, None]:
- """
- Return this context as a topic context type.
-
- If the trigger wasn't an event from a topic, this function returns None.
- is_topic() should be used first to determine if this was a topic trigger.
- """
- if not self.is_topic():
- return None
-
- return self.context
-
-
-
-def is_http(self) ‑> bool
-
-
-
Indicate whether the trigger was from an HTTP request.
-
This indicates the availability of additional HTTP specific context such as path, query parameters and headers.
-
-
-Expand source code
-
-
def is_http(self) -> bool:
- """
- Indicate whether the trigger was from an HTTP request.
-
- This indicates the availability of additional HTTP specific context such as path, query parameters and headers.
- """
- return isinstance(self.context, HttpTriggerContext)
-
-
-
-def is_topic(self) ‑> bool
-
-
-
Indicate whether the trigger was from a topic (event).
-
This indicates the availability of additional topic/event specific context such as the topic name.
-
-
-Expand source code
-
-
def is_topic(self) -> bool:
- """
- Indicate whether the trigger was from a topic (event).
-
- This indicates the availability of additional topic/event specific context such as the topic name.
- """
- return isinstance(self.context, TriggerContext)
-
-
-
-
-<<<<<<< refs/remotes/origin/main
-
-class TriggerRequest
-(*args, **kwargs)
-
-
-
A ProtocolMessage
-
Ancestors
-
-
google.protobuf.pyext._message.CMessage
-
google.protobuf.message.Message
-
-
Class variables
-
-
var DESCRIPTOR
-
-
-
-
-
Instance variables
-
-
var data
-
-
Field nitric.faas.v1.TriggerRequest.data
-
-
var http
-
-
Field nitric.faas.v1.TriggerRequest.http
-
-
var mime_type
-
-
Field nitric.faas.v1.TriggerRequest.mime_type
-
-
var topic
-
-
Field nitric.faas.v1.TriggerRequest.topic
-
-
-
-=======
->>>>>>> feat: port faas.start to bi-di streaming with membrane
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/nitric/index.html b/docs/nitric/index.html
index 4db1f09..2fbcc5a 100644
--- a/docs/nitric/index.html
+++ b/docs/nitric/index.html
@@ -59,11 +59,7 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/nitric/proto/nitric/event/index.html b/docs/nitric/proto/nitric/event/index.html
deleted file mode 100644
index 29bdace..0000000
--- a/docs/nitric/proto/nitric/event/index.html
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
-
-
-
-nitric.proto.nitric.event API documentation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Module nitric.proto.nitric.event
-
-
-
-
-Expand source code
-
-
#
-# Copyright (c) 2021 Nitric Technologies Pty Ltd.
-#
-# This file is part of Nitric Python 3 SDK.
-# See https://github.com/nitrictech/python-sdk for further info.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
class EventPublishRequest(betterproto.Message):
- """Request to publish an event to a topic"""
-
- # The name of the topic to publish the event to
- topic: str = betterproto.string_field(1)
- # The event to be published
- event: "NitricEvent" = betterproto.message_field(2)
class EventPublishResponse(betterproto.Message):
- """Result of publishing an event"""
-
- # The id of the published message When an id was not supplied one should be
- # automatically generated
- id: str = betterproto.string_field(1)
class NitricEvent(betterproto.Message):
- """Nitric Event Model"""
-
- # A Unique ID for the Nitric Event
- id: str = betterproto.string_field(1)
- # A content hint for the events payload
- payload_type: str = betterproto.string_field(2)
- # The payload of the event
- payload: "betterproto_lib_google_protobuf.Struct" = betterproto.message_field(3)
-
-
Ancestors
-
-
betterproto.Message
-
abc.ABC
-
-
Class variables
-
-
var id : str
-
-
-
-
var payload : betterproto.lib.google.protobuf.Struct
class NitricTopic(betterproto.Message):
- """Represents an event topic"""
-
- # The Nitric name for the topic
- name: str = betterproto.string_field(1)
class TopicListResponse(betterproto.Message):
- """Topic List Response"""
-
- # The list of found topics
- topics: List["NitricTopic"] = betterproto.message_field(1)
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/nitric/proto/nitric/faas/index.html b/docs/nitric/proto/nitric/faas/index.html
deleted file mode 100644
index 47bf2b3..0000000
--- a/docs/nitric/proto/nitric/faas/index.html
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
-
-
-
-nitric.proto.nitric.faas API documentation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Module nitric.proto.nitric.faas
-
-
-
-
-Expand source code
-
-
#
-# Copyright (c) 2021 Nitric Technologies Pty Ltd.
-#
-# This file is part of Nitric Python 3 SDK.
-# See https://github.com/nitrictech/python-sdk for further info.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
#
-# Copyright (c) 2021 Nitric Technologies Pty Ltd.
-#
-# This file is part of Nitric Python 3 SDK.
-# See https://github.com/nitrictech/python-sdk for further info.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# Generated by the protocol buffer compiler. DO NOT EDIT!
-# sources: faas/v1/faas.proto
-# plugin: python-betterproto
-from dataclasses import dataclass
-from typing import AsyncIterable, AsyncIterator, Dict, Iterable, Union
-
-import betterproto
-from betterproto.grpc.grpclib_server import ServiceBase
-import grpclib
-
-
-@dataclass(eq=False, repr=False)
-class ClientMessage(betterproto.Message):
- """Messages the client is able to send to the server"""
-
- # Client message ID, used to pair requests/responses
- id: str = betterproto.string_field(1)
- # Client initialisation request
- init_request: "InitRequest" = betterproto.message_field(2, group="content")
- # Client responsding with result of a trigger
- trigger_response: "TriggerResponse" = betterproto.message_field(3, group="content")
-
-
-@dataclass(eq=False, repr=False)
-class ServerMessage(betterproto.Message):
- """Messages the server is able to send to the client"""
-
- # Server message ID, used to pair requests/responses
- id: str = betterproto.string_field(1)
- # Server responding with client configuration details to an InitRequest
- init_response: "InitResponse" = betterproto.message_field(2, group="content")
- # Server requesting client to process a trigger
- trigger_request: "TriggerRequest" = betterproto.message_field(3, group="content")
-
-
-@dataclass(eq=False, repr=False)
-class InitRequest(betterproto.Message):
- """Placeholder message"""
-
- pass
-
-
-@dataclass(eq=False, repr=False)
-class InitResponse(betterproto.Message):
- """Placeholder message"""
-
- pass
-
-
-@dataclass(eq=False, repr=False)
-class TriggerRequest(betterproto.Message):
- """The server has a trigger for the client to handle"""
-
- # The data in the trigger
- data: bytes = betterproto.bytes_field(1)
- # Should we supply a mime type for the data? Or rely on context?
- mime_type: str = betterproto.string_field(2)
- http: "HttpTriggerContext" = betterproto.message_field(3, group="context")
- topic: "TopicTriggerContext" = betterproto.message_field(4, group="context")
-
-
-@dataclass(eq=False, repr=False)
-class HttpTriggerContext(betterproto.Message):
- # The request method
- method: str = betterproto.string_field(1)
- # The path of the request
- path: str = betterproto.string_field(2)
- # The request headers
- headers: Dict[str, str] = betterproto.map_field(3, betterproto.TYPE_STRING, betterproto.TYPE_STRING)
- # The query params (if parseable by the membrane)
- query_params: Dict[str, str] = betterproto.map_field(4, betterproto.TYPE_STRING, betterproto.TYPE_STRING)
-
-
-@dataclass(eq=False, repr=False)
-class TopicTriggerContext(betterproto.Message):
- # The topic the message was published for
- topic: str = betterproto.string_field(1)
-
-
-@dataclass(eq=False, repr=False)
-class TriggerResponse(betterproto.Message):
- """The worker has successfully processed a trigger"""
-
- # The data returned in the response
- data: bytes = betterproto.bytes_field(1)
- # response to a http request
- http: "HttpResponseContext" = betterproto.message_field(10, group="context")
- # response to a topic trigger
- topic: "TopicResponseContext" = betterproto.message_field(11, group="context")
-
-
-@dataclass(eq=False, repr=False)
-class HttpResponseContext(betterproto.Message):
- """
- Specific HttpResponse message Note this does not have to be handled by the
- User at all but they will have the option of control If they choose...
- """
-
- # The request headers...
- headers: Dict[str, str] = betterproto.map_field(1, betterproto.TYPE_STRING, betterproto.TYPE_STRING)
- # The HTTP status of the request
- status: int = betterproto.int32_field(2)
-
-
-@dataclass(eq=False, repr=False)
-class TopicResponseContext(betterproto.Message):
- """
- Specific event response message We do not accept responses for events only
- whether or not they were successfully processed
- """
-
- # Success status of the handled event
- success: bool = betterproto.bool_field(1)
-
-
-class FaasStub(betterproto.ServiceStub):
- async def trigger_stream(
- self,
- request_iterator: Union[AsyncIterable["ClientMessage"], Iterable["ClientMessage"]],
- ) -> AsyncIterator["ServerMessage"]:
-
- async for response in self._stream_stream(
- "/nitric.faas.v1.Faas/TriggerStream",
- request_iterator,
- ClientMessage,
- ServerMessage,
- ):
- yield response
-
-
-class FaasBase(ServiceBase):
- async def trigger_stream(self, request_iterator: AsyncIterator["ClientMessage"]) -> AsyncIterator["ServerMessage"]:
- raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
-
- async def __rpc_trigger_stream(self, stream: grpclib.server.Stream) -> None:
- request_kwargs = {"request_iterator": stream.__aiter__()}
-
- await self._call_rpc_handler_server_stream(
- self.trigger_stream,
- stream,
- request_kwargs,
- )
-
- def __mapping__(self) -> Dict[str, grpclib.const.Handler]:
- return {
- "/nitric.faas.v1.Faas/TriggerStream": grpclib.const.Handler(
- self.__rpc_trigger_stream,
- grpclib.const.Cardinality.STREAM_STREAM,
- ClientMessage,
- ServerMessage,
- ),
- }
class ClientMessage(betterproto.Message):
- """Messages the client is able to send to the server"""
-
- # Client message ID, used to pair requests/responses
- id: str = betterproto.string_field(1)
- # Client initialisation request
- init_request: "InitRequest" = betterproto.message_field(2, group="content")
- # Client responsding with result of a trigger
- trigger_response: "TriggerResponse" = betterproto.message_field(3, group="content")
Specific HttpResponse message Note this does not have to be handled by the
-User at all but they will have the option of control If they choose…
-
-
-Expand source code
-
-
class HttpResponseContext(betterproto.Message):
- """
- Specific HttpResponse message Note this does not have to be handled by the
- User at all but they will have the option of control If they choose...
- """
-
- # The request headers...
- headers: Dict[str, str] = betterproto.map_field(1, betterproto.TYPE_STRING, betterproto.TYPE_STRING)
- # The HTTP status of the request
- status: int = betterproto.int32_field(2)
class ServerMessage(betterproto.Message):
- """Messages the server is able to send to the client"""
-
- # Server message ID, used to pair requests/responses
- id: str = betterproto.string_field(1)
- # Server responding with client configuration details to an InitRequest
- init_response: "InitResponse" = betterproto.message_field(2, group="content")
- # Server requesting client to process a trigger
- trigger_request: "TriggerRequest" = betterproto.message_field(3, group="content")
Specific event response message We do not accept responses for events only
-whether or not they were successfully processed
-
-
-Expand source code
-
-
class TopicResponseContext(betterproto.Message):
- """
- Specific event response message We do not accept responses for events only
- whether or not they were successfully processed
- """
-
- # Success status of the handled event
- success: bool = betterproto.bool_field(1)
class TriggerRequest(betterproto.Message):
- """The server has a trigger for the client to handle"""
-
- # The data in the trigger
- data: bytes = betterproto.bytes_field(1)
- # Should we supply a mime type for the data? Or rely on context?
- mime_type: str = betterproto.string_field(2)
- http: "HttpTriggerContext" = betterproto.message_field(3, group="context")
- topic: "TopicTriggerContext" = betterproto.message_field(4, group="context")
class TriggerResponse(betterproto.Message):
- """The worker has successfully processed a trigger"""
-
- # The data returned in the response
- data: bytes = betterproto.bytes_field(1)
- # response to a http request
- http: "HttpResponseContext" = betterproto.message_field(10, group="context")
- # response to a topic trigger
- topic: "TopicResponseContext" = betterproto.message_field(11, group="context")
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/nitric/proto/nitric/index.html b/docs/nitric/proto/nitric/index.html
deleted file mode 100644
index 6b92d37..0000000
--- a/docs/nitric/proto/nitric/index.html
+++ /dev/null
@@ -1,108 +0,0 @@
-
-
-
-
-
-
-nitric.proto.nitric API documentation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Module nitric.proto.nitric
-
-
-
-
-Expand source code
-
-
#
-# Copyright (c) 2021 Nitric Technologies Pty Ltd.
-#
-# This file is part of Nitric Python 3 SDK.
-# See https://github.com/nitrictech/python-sdk for further info.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
#
-# Copyright (c) 2021 Nitric Technologies Pty Ltd.
-#
-# This file is part of Nitric Python 3 SDK.
-# See https://github.com/nitrictech/python-sdk for further info.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
class KeyValueDeleteRequest(betterproto.Message):
- # The collection containing the existing keyValue to be deleted
- collection: str = betterproto.string_field(1)
- # The unique key of the keyValue to delete
- key: str = betterproto.string_field(2)
-
-
Ancestors
-
-
betterproto.Message
-
abc.ABC
-
-
Class variables
-
-
var collection : str
-
-
-
-
var key : str
-
-
-
-
-
-
-class KeyValueDeleteResponse
-
-
-
KeyValueDeleteResponse()
-
-
-Expand source code
-
-
class KeyValueDeleteResponse(betterproto.Message):
- pass
class KeyValueGetRequest(betterproto.Message):
- # The collection to retrieve the keyValue from
- collection: str = betterproto.string_field(1)
- # The unique key of the keyValue to retrieve
- key: str = betterproto.string_field(2)
class KeyValueGetResponse(betterproto.Message):
- # The retrieved value
- value: "betterproto_lib_google_protobuf.Struct" = betterproto.message_field(1)
-
-
Ancestors
-
-
betterproto.Message
-
abc.ABC
-
-
Class variables
-
-
var value : betterproto.lib.google.protobuf.Struct
class KeyValuePutRequest(betterproto.Message):
- # The collection containing the existing keyValue to be inserted or updated.
- collection: str = betterproto.string_field(1)
- # The unique key of the keyValue to put
- key: str = betterproto.string_field(2)
- # A simple JSON object
- value: "betterproto_lib_google_protobuf.Struct" = betterproto.message_field(3)
-
-
Ancestors
-
-
betterproto.Message
-
abc.ABC
-
-
Class variables
-
-
var collection : str
-
-
-
-
var key : str
-
-
-
-
var value : betterproto.lib.google.protobuf.Struct
-
-
-
-
-
-
-class KeyValuePutResponse
-
-
-
KeyValuePutResponse()
-
-
-Expand source code
-
-
class KeyValuePutResponse(betterproto.Message):
- pass
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/nitric/proto/nitric/queue/index.html b/docs/nitric/proto/nitric/queue/index.html
deleted file mode 100644
index de96adb..0000000
--- a/docs/nitric/proto/nitric/queue/index.html
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
-
-
-
-nitric.proto.nitric.queue API documentation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Module nitric.proto.nitric.queue
-
-
-
-
-Expand source code
-
-
#
-# Copyright (c) 2021 Nitric Technologies Pty Ltd.
-#
-# This file is part of Nitric Python 3 SDK.
-# See https://github.com/nitrictech/python-sdk for further info.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
class FailedTask(betterproto.Message):
- # The task that failed to be pushed
- task: "NitricTask" = betterproto.message_field(1)
- # A message describing the failure
- message: str = betterproto.string_field(2)
class NitricTask(betterproto.Message):
- """A task to be sent or received from a queue."""
-
- # A unique id for the task
- id: str = betterproto.string_field(1)
- # The lease id unique to the pop request, this must be used to complete,
- # extend the lease or release the task.
- lease_id: str = betterproto.string_field(2)
- # A content hint for the tasks payload
- payload_type: str = betterproto.string_field(3)
- # The payload of the task
- payload: "betterproto_lib_google_protobuf.Struct" = betterproto.message_field(4)
-
-
Ancestors
-
-
betterproto.Message
-
abc.ABC
-
-
Class variables
-
-
var id : str
-
-
-
-
var lease_id : str
-
-
-
-
var payload : betterproto.lib.google.protobuf.Struct
class QueueCompleteRequest(betterproto.Message):
- # The nitric name for the queue this will automatically be resolved to the
- # provider specific queue identifier.
- queue: str = betterproto.string_field(1)
- # Lease id of the task to be completed
- lease_id: str = betterproto.string_field(2)
-
-
Ancestors
-
-
betterproto.Message
-
abc.ABC
-
-
Class variables
-
-
var lease_id : str
-
-
-
-
var queue : str
-
-
-
-
-
-
-class QueueCompleteResponse
-
-
-
QueueCompleteResponse()
-
-
-Expand source code
-
-
class QueueCompleteResponse(betterproto.Message):
- pass
class QueueReceiveRequest(betterproto.Message):
- # The nitric name for the queue this will automatically be resolved to the
- # provider specific queue identifier.
- queue: str = betterproto.string_field(1)
- # The max number of items to pop off the queue, may be capped by provider
- # specific limitations
- depth: int = betterproto.int32_field(2)
class QueueSendBatchRequest(betterproto.Message):
- # The Nitric name for the queue this will automatically be resolved to the
- # provider specific queue identifier.
- queue: str = betterproto.string_field(1)
- # Array of tasks to push to the queue
- tasks: List["NitricTask"] = betterproto.message_field(2)
class QueueSendBatchResponse(betterproto.Message):
- """Response for sending a collection of tasks"""
-
- # A list of tasks that failed to be queued
- failed_tasks: List["FailedTask"] = betterproto.message_field(1)
class QueueSendRequest(betterproto.Message):
- """Request to push a single event to a queue"""
-
- # The Nitric name for the queue this will automatically be resolved to the
- # provider specific queue identifier.
- queue: str = betterproto.string_field(1)
- # The task to push to the queue
- task: "NitricTask" = betterproto.message_field(2)
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/nitric/proto/nitric/storage/index.html b/docs/nitric/proto/nitric/storage/index.html
deleted file mode 100644
index d936a53..0000000
--- a/docs/nitric/proto/nitric/storage/index.html
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
-
-
-
-nitric.proto.nitric.storage API documentation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Module nitric.proto.nitric.storage
-
-
-
-
-Expand source code
-
-
#
-# Copyright (c) 2021 Nitric Technologies Pty Ltd.
-#
-# This file is part of Nitric Python 3 SDK.
-# See https://github.com/nitrictech/python-sdk for further info.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
class StorageDeleteRequest(betterproto.Message):
- """Request to delete a storage item"""
-
- # Name of the bucket to delete from
- bucket_name: str = betterproto.string_field(1)
- # Key of item to delete
- key: str = betterproto.string_field(2)
-
-
Ancestors
-
-
betterproto.Message
-
abc.ABC
-
-
Class variables
-
-
var bucket_name : str
-
-
-
-
var key : str
-
-
-
-
-
-
-class StorageDeleteResponse
-
-
-
Result of deleting a storage item
-
-
-Expand source code
-
-
class StorageDeleteResponse(betterproto.Message):
- """Result of deleting a storage item"""
-
- pass
class StorageReadRequest(betterproto.Message):
- """Request to retrieve a storage item"""
-
- # Nitric name of the bucket to retrieve from this will be automatically
- # resolved to the provider specific bucket identifier.
- bucket_name: str = betterproto.string_field(1)
- # Key of item to retrieve
- key: str = betterproto.string_field(2)
class StorageReadResponse(betterproto.Message):
- """Returned storage item"""
-
- # The body bytes of the retrieved storage item
- body: bytes = betterproto.bytes_field(1)
class StorageWriteRequest(betterproto.Message):
- """Request to put (create/update) a storage item"""
-
- # Nitric name of the bucket to store in this will be automatically resolved
- # to the provider specific bucket identifier.
- bucket_name: str = betterproto.string_field(1)
- # Key to store the item under
- key: str = betterproto.string_field(2)
- # bytes array to store
- body: bytes = betterproto.bytes_field(3)
-
-
Ancestors
-
-
betterproto.Message
-
abc.ABC
-
-
Class variables
-
-
var body : bytes
-
-
-
-
var bucket_name : str
-
-
-
-
var key : str
-
-
-
-
-
-
-class StorageWriteResponse
-
-
-
Result of putting a storage item
-
-
-Expand source code
-
-
class StorageWriteResponse(betterproto.Message):
- """Result of putting a storage item"""
-
- pass
-
-
Ancestors
-
-
betterproto.Message
-
abc.ABC
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/nitric/proto/queue/v1/queue_pb2.html b/docs/nitric/proto/queue/v1/queue_pb2.html
deleted file mode 100644
index 85725ae..0000000
--- a/docs/nitric/proto/queue/v1/queue_pb2.html
+++ /dev/null
@@ -1,976 +0,0 @@
-
-
-
-
-
-
-nitric.proto.queue.v1.queue_pb2 API documentation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-