Skip to content

Commit deb42f4

Browse files
feat: fix subscriptions and add bucket notifications (#106)
2 parents c31870d + e35bd28 commit deb42f4

Some content is hidden

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

56 files changed

+2272
-595
lines changed

docs/nitric/api/documents.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ <h1 class="title">Module <code>nitric.api.documents</code></h1>
5353
from grpclib import GRPCError
5454

5555
from nitric.api.const import MAX_SUB_COLLECTION_DEPTH
56-
from nitric.api.exception import exception_from_grpc_error
56+
from nitric.exception import exception_from_grpc_error
5757
from nitric.proto.nitric.document.v1 import (
5858
DocumentServiceStub,
5959
Collection as CollectionMessage,

docs/nitric/api/events.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ <h1 class="title">Module <code>nitric.api.events</code></h1>
5050

5151
from grpclib import GRPCError
5252

53-
from nitric.api.exception import exception_from_grpc_error
53+
from nitric.exception import exception_from_grpc_error
5454
from nitric.utils import new_default_channel, _struct_from_dict
5555
from nitric.proto.nitric.event.v1 import (
5656
EventServiceStub,

docs/nitric/api/index.html

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,6 @@ <h2 class="section-title" id="header-submodules">Sub-modules</h2>
8080
<dd>
8181
<div class="desc"></div>
8282
</dd>
83-
<dt><code class="name"><a title="nitric.api.exception" href="exception.html">nitric.api.exception</a></code></dt>
84-
<dd>
85-
<div class="desc"></div>
86-
</dd>
8783
<dt><code class="name"><a title="nitric.api.queues" href="queues.html">nitric.api.queues</a></code></dt>
8884
<dd>
8985
<div class="desc"></div>
@@ -421,7 +417,7 @@ <h3>Methods</h3>
421417

422418
def bucket(self, name: str):
423419
&#34;&#34;&#34;Return a reference to a bucket from the connected storage service.&#34;&#34;&#34;
424-
return BucketRef(_storage=self, name=name)</code></pre>
420+
return BucketRef(_storage=self, name=name, _server=None)</code></pre>
425421
</details>
426422
<h3>Methods</h3>
427423
<dl>
@@ -436,7 +432,7 @@ <h3>Methods</h3>
436432
</summary>
437433
<pre><code class="python">def bucket(self, name: str):
438434
&#34;&#34;&#34;Return a reference to a bucket from the connected storage service.&#34;&#34;&#34;
439-
return BucketRef(_storage=self, name=name)</code></pre>
435+
return BucketRef(_storage=self, name=name, _server=None)</code></pre>
440436
</details>
441437
</dd>
442438
</dl>
@@ -586,7 +582,6 @@ <h1>Index</h1>
586582
<li><code><a title="nitric.api.const" href="const.html">nitric.api.const</a></code></li>
587583
<li><code><a title="nitric.api.documents" href="documents.html">nitric.api.documents</a></code></li>
588584
<li><code><a title="nitric.api.events" href="events.html">nitric.api.events</a></code></li>
589-
<li><code><a title="nitric.api.exception" href="exception.html">nitric.api.exception</a></code></li>
590585
<li><code><a title="nitric.api.queues" href="queues.html">nitric.api.queues</a></code></li>
591586
<li><code><a title="nitric.api.secrets" href="secrets.html">nitric.api.secrets</a></code></li>
592587
<li><code><a title="nitric.api.storage" href="storage.html">nitric.api.storage</a></code></li>

docs/nitric/api/queues.html

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ <h1 class="title">Module <code>nitric.api.queues</code></h1>
5050

5151
from grpclib import GRPCError
5252

53-
from nitric.api.exception import FailedPreconditionException, exception_from_grpc_error, InvalidArgumentException
53+
from nitric.exception import FailedPreconditionException, exception_from_grpc_error, InvalidArgumentException
5454
from nitric.utils import new_default_channel, _struct_from_dict, _dict_from_struct
5555
from nitric.proto.nitric.queue.v1 import (
5656
QueueServiceStub,
@@ -183,7 +183,9 @@ <h1 class="title">Module <code>nitric.api.queues</code></h1>
183183
task = Task()
184184

185185
if isinstance(task, dict):
186-
# TODO: handle tasks that are just a payload
186+
# Handle if its just a payload
187+
if task.get(&#34;payload&#34;) is None:
188+
task = {&#34;payload&#34;: task}
187189
task = Task(**task)
188190

189191
try:
@@ -332,7 +334,9 @@ <h3>Class variables</h3>
332334
task = Task()
333335

334336
if isinstance(task, dict):
335-
# TODO: handle tasks that are just a payload
337+
# Handle if its just a payload
338+
if task.get(&#34;payload&#34;) is None:
339+
task = {&#34;payload&#34;: task}
336340
task = Task(**task)
337341

338342
try:
@@ -471,7 +475,9 @@ <h3>Methods</h3>
471475
task = Task()
472476

473477
if isinstance(task, dict):
474-
# TODO: handle tasks that are just a payload
478+
# Handle if its just a payload
479+
if task.get(&#34;payload&#34;) is None:
480+
task = {&#34;payload&#34;: task}
475481
task = Task(**task)
476482

477483
try:

docs/nitric/api/secrets.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ <h1 class="title">Module <code>nitric.api.secrets</code></h1>
5050

5151
from grpclib import GRPCError
5252

53-
from nitric.api.exception import exception_from_grpc_error
53+
from nitric.exception import exception_from_grpc_error
5454
from nitric.utils import new_default_channel
5555
from nitric.proto.nitric.secret.v1 import (
5656
SecretServiceStub,

docs/nitric/api/storage.html

Lines changed: 82 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,12 @@ <h1 class="title">Module <code>nitric.api.storage</code></h1>
4545
# limitations under the License.
4646
#
4747
from dataclasses import dataclass
48+
from typing import Union
4849

4950
from grpclib import GRPCError
50-
from nitric.api.exception import exception_from_grpc_error, InvalidArgumentException
51+
from nitric.exception import exception_from_grpc_error, InvalidArgumentException
52+
from nitric.application import Nitric
53+
from nitric.faas import FunctionServer, FileNotificationWorkerOptions, FileNotificationMiddleware
5154
from nitric.utils import new_default_channel
5255
from nitric.proto.nitric.storage.v1 import (
5356
StorageServiceStub,
@@ -59,6 +62,7 @@ <h1 class="title">Module <code>nitric.api.storage</code></h1>
5962
StorageListFilesRequest,
6063
)
6164
from enum import Enum
65+
from warnings import warn
6266

6367

6468
class Storage(object):
@@ -80,15 +84,16 @@ <h1 class="title">Module <code>nitric.api.storage</code></h1>
8084

8185
def bucket(self, name: str):
8286
&#34;&#34;&#34;Return a reference to a bucket from the connected storage service.&#34;&#34;&#34;
83-
return BucketRef(_storage=self, name=name)
87+
return BucketRef(_storage=self, name=name, _server=None)
8488

8589

86-
@dataclass(frozen=True, order=True)
90+
@dataclass(order=True)
8791
class BucketRef(object):
8892
&#34;&#34;&#34;A reference to a bucket in a storage service, used to the perform operations on that bucket.&#34;&#34;&#34;
8993

9094
_storage: Storage
9195
name: str
96+
_server: Union[FunctionServer, None]
9297

9398
def file(self, key: str):
9499
&#34;&#34;&#34;Return a reference to a file in this bucket.&#34;&#34;&#34;
@@ -101,6 +106,22 @@ <h1 class="title">Module <code>nitric.api.storage</code></h1>
101106
)
102107
return [self.file(f.key) for f in resp.files]
103108

109+
def on(self, notification_type: str, notification_prefix_filter: str):
110+
&#34;&#34;&#34;Create and return a bucket notification decorator for this bucket.&#34;&#34;&#34;
111+
112+
def decorator(func: FileNotificationMiddleware):
113+
self._server = FunctionServer(
114+
FileNotificationWorkerOptions(
115+
bucket=self,
116+
notification_type=notification_type,
117+
notification_prefix_filter=notification_prefix_filter,
118+
)
119+
)
120+
self._server.bucket_notification(func)
121+
Nitric._register_worker(self._server)
122+
123+
return decorator
124+
104125

105126
class FileMode(Enum):
106127
&#34;&#34;&#34;Definition of available operation modes for file signed URLs.&#34;&#34;&#34;
@@ -160,14 +181,15 @@ <h1 class="title">Module <code>nitric.api.storage</code></h1>
160181

161182
async def upload_url(self, expiry: int = 600):
162183
&#34;&#34;&#34;Get a temporary writable URL to this file.&#34;&#34;&#34;
163-
await self.sign_url(mode=FileMode.WRITE, expiry=expiry)
184+
return await self.sign_url(mode=FileMode.WRITE, expiry=expiry)
164185

165186
async def download_url(self, expiry: int = 600):
166187
&#34;&#34;&#34;Get a temporary readable URL to this file.&#34;&#34;&#34;
167-
await self.sign_url(mode=FileMode.READ, expiry=expiry)
188+
return await self.sign_url(mode=FileMode.READ, expiry=expiry)
168189

169190
async def sign_url(self, mode: FileMode = FileMode.READ, expiry: int = 3600):
170191
&#34;&#34;&#34;Generate a signed URL for reading or writing to a file.&#34;&#34;&#34;
192+
warn(&#34;File.sign_url() is deprecated, use upload_url() or download_url() instead&#34;, DeprecationWarning)
171193
try:
172194
response = await self._storage._storage_stub.pre_sign_url(
173195
storage_pre_sign_url_request=StoragePreSignUrlRequest(
@@ -190,20 +212,21 @@ <h2 class="section-title" id="header-classes">Classes</h2>
190212
<dl>
191213
<dt id="nitric.api.storage.BucketRef"><code class="flex name class">
192214
<span>class <span class="ident">BucketRef</span></span>
193-
<span>(</span><span>_storage: <a title="nitric.api.storage.Storage" href="#nitric.api.storage.Storage">Storage</a>, name: str)</span>
215+
<span>(</span><span>_storage: <a title="nitric.api.storage.Storage" href="#nitric.api.storage.Storage">Storage</a>, name: str, _server: Optional[<a title="nitric.faas.FunctionServer" href="../faas.html#nitric.faas.FunctionServer">FunctionServer</a>])</span>
194216
</code></dt>
195217
<dd>
196218
<div class="desc"><p>A reference to a bucket in a storage service, used to the perform operations on that bucket.</p></div>
197219
<details class="source">
198220
<summary>
199221
<span>Expand source code</span>
200222
</summary>
201-
<pre><code class="python">@dataclass(frozen=True, order=True)
223+
<pre><code class="python">@dataclass(order=True)
202224
class BucketRef(object):
203225
&#34;&#34;&#34;A reference to a bucket in a storage service, used to the perform operations on that bucket.&#34;&#34;&#34;
204226

205227
_storage: Storage
206228
name: str
229+
_server: Union[FunctionServer, None]
207230

208231
def file(self, key: str):
209232
&#34;&#34;&#34;Return a reference to a file in this bucket.&#34;&#34;&#34;
@@ -214,7 +237,23 @@ <h2 class="section-title" id="header-classes">Classes</h2>
214237
resp = await self._storage._storage_stub.list_files(
215238
storage_list_files_request=StorageListFilesRequest(bucket_name=self.name)
216239
)
217-
return [self.file(f.key) for f in resp.files]</code></pre>
240+
return [self.file(f.key) for f in resp.files]
241+
242+
def on(self, notification_type: str, notification_prefix_filter: str):
243+
&#34;&#34;&#34;Create and return a bucket notification decorator for this bucket.&#34;&#34;&#34;
244+
245+
def decorator(func: FileNotificationMiddleware):
246+
self._server = FunctionServer(
247+
FileNotificationWorkerOptions(
248+
bucket=self,
249+
notification_type=notification_type,
250+
notification_prefix_filter=notification_prefix_filter,
251+
)
252+
)
253+
self._server.bucket_notification(func)
254+
Nitric._register_worker(self._server)
255+
256+
return decorator</code></pre>
218257
</details>
219258
<h3>Class variables</h3>
220259
<dl>
@@ -256,6 +295,32 @@ <h3>Methods</h3>
256295
return [self.file(f.key) for f in resp.files]</code></pre>
257296
</details>
258297
</dd>
298+
<dt id="nitric.api.storage.BucketRef.on"><code class="name flex">
299+
<span>def <span class="ident">on</span></span>(<span>self, notification_type: str, notification_prefix_filter: str)</span>
300+
</code></dt>
301+
<dd>
302+
<div class="desc"><p>Create and return a bucket notification decorator for this bucket.</p></div>
303+
<details class="source">
304+
<summary>
305+
<span>Expand source code</span>
306+
</summary>
307+
<pre><code class="python">def on(self, notification_type: str, notification_prefix_filter: str):
308+
&#34;&#34;&#34;Create and return a bucket notification decorator for this bucket.&#34;&#34;&#34;
309+
310+
def decorator(func: FileNotificationMiddleware):
311+
self._server = FunctionServer(
312+
FileNotificationWorkerOptions(
313+
bucket=self,
314+
notification_type=notification_type,
315+
notification_prefix_filter=notification_prefix_filter,
316+
)
317+
)
318+
self._server.bucket_notification(func)
319+
Nitric._register_worker(self._server)
320+
321+
return decorator</code></pre>
322+
</details>
323+
</dd>
259324
</dl>
260325
</dd>
261326
<dt id="nitric.api.storage.File"><code class="flex name class">
@@ -310,14 +375,15 @@ <h3>Methods</h3>
310375

311376
async def upload_url(self, expiry: int = 600):
312377
&#34;&#34;&#34;Get a temporary writable URL to this file.&#34;&#34;&#34;
313-
await self.sign_url(mode=FileMode.WRITE, expiry=expiry)
378+
return await self.sign_url(mode=FileMode.WRITE, expiry=expiry)
314379

315380
async def download_url(self, expiry: int = 600):
316381
&#34;&#34;&#34;Get a temporary readable URL to this file.&#34;&#34;&#34;
317-
await self.sign_url(mode=FileMode.READ, expiry=expiry)
382+
return await self.sign_url(mode=FileMode.READ, expiry=expiry)
318383

319384
async def sign_url(self, mode: FileMode = FileMode.READ, expiry: int = 3600):
320385
&#34;&#34;&#34;Generate a signed URL for reading or writing to a file.&#34;&#34;&#34;
386+
warn(&#34;File.sign_url() is deprecated, use upload_url() or download_url() instead&#34;, DeprecationWarning)
321387
try:
322388
response = await self._storage._storage_stub.pre_sign_url(
323389
storage_pre_sign_url_request=StoragePreSignUrlRequest(
@@ -367,7 +433,7 @@ <h3>Methods</h3>
367433
</summary>
368434
<pre><code class="python">async def download_url(self, expiry: int = 600):
369435
&#34;&#34;&#34;Get a temporary readable URL to this file.&#34;&#34;&#34;
370-
await self.sign_url(mode=FileMode.READ, expiry=expiry)</code></pre>
436+
return await self.sign_url(mode=FileMode.READ, expiry=expiry)</code></pre>
371437
</details>
372438
</dd>
373439
<dt id="nitric.api.storage.File.read"><code class="name flex">
@@ -401,6 +467,7 @@ <h3>Methods</h3>
401467
</summary>
402468
<pre><code class="python">async def sign_url(self, mode: FileMode = FileMode.READ, expiry: int = 3600):
403469
&#34;&#34;&#34;Generate a signed URL for reading or writing to a file.&#34;&#34;&#34;
470+
warn(&#34;File.sign_url() is deprecated, use upload_url() or download_url() instead&#34;, DeprecationWarning)
404471
try:
405472
response = await self._storage._storage_stub.pre_sign_url(
406473
storage_pre_sign_url_request=StoragePreSignUrlRequest(
@@ -423,7 +490,7 @@ <h3>Methods</h3>
423490
</summary>
424491
<pre><code class="python">async def upload_url(self, expiry: int = 600):
425492
&#34;&#34;&#34;Get a temporary writable URL to this file.&#34;&#34;&#34;
426-
await self.sign_url(mode=FileMode.WRITE, expiry=expiry)</code></pre>
493+
return await self.sign_url(mode=FileMode.WRITE, expiry=expiry)</code></pre>
427494
</details>
428495
</dd>
429496
<dt id="nitric.api.storage.File.write"><code class="name flex">
@@ -545,7 +612,7 @@ <h3>Methods</h3>
545612

546613
def bucket(self, name: str):
547614
&#34;&#34;&#34;Return a reference to a bucket from the connected storage service.&#34;&#34;&#34;
548-
return BucketRef(_storage=self, name=name)</code></pre>
615+
return BucketRef(_storage=self, name=name, _server=None)</code></pre>
549616
</details>
550617
<h3>Methods</h3>
551618
<dl>
@@ -560,7 +627,7 @@ <h3>Methods</h3>
560627
</summary>
561628
<pre><code class="python">def bucket(self, name: str):
562629
&#34;&#34;&#34;Return a reference to a bucket from the connected storage service.&#34;&#34;&#34;
563-
return BucketRef(_storage=self, name=name)</code></pre>
630+
return BucketRef(_storage=self, name=name, _server=None)</code></pre>
564631
</details>
565632
</dd>
566633
</dl>
@@ -587,6 +654,7 @@ <h4><code><a title="nitric.api.storage.BucketRef" href="#nitric.api.storage.Buck
587654
<li><code><a title="nitric.api.storage.BucketRef.file" href="#nitric.api.storage.BucketRef.file">file</a></code></li>
588655
<li><code><a title="nitric.api.storage.BucketRef.files" href="#nitric.api.storage.BucketRef.files">files</a></code></li>
589656
<li><code><a title="nitric.api.storage.BucketRef.name" href="#nitric.api.storage.BucketRef.name">name</a></code></li>
657+
<li><code><a title="nitric.api.storage.BucketRef.on" href="#nitric.api.storage.BucketRef.on">on</a></code></li>
590658
</ul>
591659
</li>
592660
<li>

docs/nitric/application.html

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ <h1 class="title">Module <code>nitric.application</code></h1>
5454
from opentelemetry.instrumentation.grpc import GrpcInstrumentorClient
5555

5656
from nitric.faas import FunctionServer
57-
from nitric.api.exception import NitricUnavailableException
57+
from nitric.exception import NitricUnavailableException
5858

5959
# from nitric.resources.base import BaseResource
6060
from typing import Dict, List, Type, Any, TypeVar
@@ -95,9 +95,9 @@ <h1 class="title">Module <code>nitric.application</code></h1>
9595
)
9696

9797
@classmethod
98-
def _create_tracer(cls) -&gt; TracerProvider:
99-
local_run = &#34;OTELCOL_BIN&#34; not in environ
100-
samplePercent = int(getenv(&#34;NITRIC_TRACE_SAMPLE_PERCENT&#34;, &#34;100&#34;)) / 100.0
98+
def _create_tracer(cls, local: bool = True, sampler: int = 100) -&gt; TracerProvider:
99+
local_run = local or &#34;OTELCOL_BIN&#34; not in environ
100+
samplePercent = int(getenv(&#34;NITRIC_TRACE_SAMPLE_PERCENT&#34;, sampler)) / 100.0
101101

102102
# If its a local run use a console exporter, otherwise export using OTEL Protocol
103103
exporter = OTLPSpanExporter(endpoint=&#34;http://localhost:4317&#34;, insecure=True)
@@ -123,6 +123,7 @@ <h1 class="title">Module <code>nitric.application</code></h1>
123123
This will execute in an existing event loop if there is one, otherwise it will attempt to create its own.
124124
&#34;&#34;&#34;
125125
provider = cls._create_tracer()
126+
print(cls._workers)
126127
try:
127128
try:
128129
loop = asyncio.get_running_loop()
@@ -191,9 +192,9 @@ <h2 class="section-title" id="header-classes">Classes</h2>
191192
)
192193

193194
@classmethod
194-
def _create_tracer(cls) -&gt; TracerProvider:
195-
local_run = &#34;OTELCOL_BIN&#34; not in environ
196-
samplePercent = int(getenv(&#34;NITRIC_TRACE_SAMPLE_PERCENT&#34;, &#34;100&#34;)) / 100.0
195+
def _create_tracer(cls, local: bool = True, sampler: int = 100) -&gt; TracerProvider:
196+
local_run = local or &#34;OTELCOL_BIN&#34; not in environ
197+
samplePercent = int(getenv(&#34;NITRIC_TRACE_SAMPLE_PERCENT&#34;, sampler)) / 100.0
197198

198199
# If its a local run use a console exporter, otherwise export using OTEL Protocol
199200
exporter = OTLPSpanExporter(endpoint=&#34;http://localhost:4317&#34;, insecure=True)
@@ -219,6 +220,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
219220
This will execute in an existing event loop if there is one, otherwise it will attempt to create its own.
220221
&#34;&#34;&#34;
221222
provider = cls._create_tracer()
223+
print(cls._workers)
222224
try:
223225
try:
224226
loop = asyncio.get_running_loop()
@@ -256,6 +258,7 @@ <h3>Static methods</h3>
256258
This will execute in an existing event loop if there is one, otherwise it will attempt to create its own.
257259
&#34;&#34;&#34;
258260
provider = cls._create_tracer()
261+
print(cls._workers)
259262
try:
260263
try:
261264
loop = asyncio.get_running_loop()

0 commit comments

Comments
 (0)