nucliadb-utils 4.0.3.post586__py3-none-any.whl → 4.0.3.post589__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. nucliadb_utils/asyncio_utils.py +1 -3
  2. nucliadb_utils/audit/audit.py +1 -0
  3. nucliadb_utils/audit/basic.py +2 -4
  4. nucliadb_utils/audit/stream.py +5 -11
  5. nucliadb_utils/authentication.py +7 -21
  6. nucliadb_utils/cache/nats.py +2 -6
  7. nucliadb_utils/debug.py +1 -4
  8. nucliadb_utils/fastapi/versioning.py +5 -4
  9. nucliadb_utils/featureflagging.py +1 -3
  10. nucliadb_utils/grpc.py +1 -3
  11. nucliadb_utils/helpers.py +1 -1
  12. nucliadb_utils/indexing.py +1 -1
  13. nucliadb_utils/nats.py +1 -3
  14. nucliadb_utils/run.py +1 -3
  15. nucliadb_utils/settings.py +3 -9
  16. nucliadb_utils/signals.py +1 -3
  17. nucliadb_utils/storages/exceptions.py +1 -3
  18. nucliadb_utils/storages/gcs.py +15 -40
  19. nucliadb_utils/storages/local.py +5 -14
  20. nucliadb_utils/storages/nuclia.py +1 -1
  21. nucliadb_utils/storages/s3.py +11 -29
  22. nucliadb_utils/storages/storage.py +16 -45
  23. nucliadb_utils/tests/asyncbenchmark.py +4 -11
  24. nucliadb_utils/tests/gcs.py +1 -3
  25. nucliadb_utils/tests/nats.py +4 -15
  26. nucliadb_utils/transaction.py +5 -13
  27. nucliadb_utils/utilities.py +4 -13
  28. {nucliadb_utils-4.0.3.post586.dist-info → nucliadb_utils-4.0.3.post589.dist-info}/METADATA +3 -3
  29. {nucliadb_utils-4.0.3.post586.dist-info → nucliadb_utils-4.0.3.post589.dist-info}/RECORD +32 -32
  30. {nucliadb_utils-4.0.3.post586.dist-info → nucliadb_utils-4.0.3.post589.dist-info}/WHEEL +0 -0
  31. {nucliadb_utils-4.0.3.post586.dist-info → nucliadb_utils-4.0.3.post589.dist-info}/top_level.txt +0 -0
  32. {nucliadb_utils-4.0.3.post586.dist-info → nucliadb_utils-4.0.3.post589.dist-info}/zip-safe +0 -0
@@ -62,9 +62,7 @@ class ConcurrentRunner:
62
62
  return results
63
63
 
64
64
 
65
- async def run_concurrently(
66
- tasks: list[Coroutine], max_concurrent: Optional[int] = None
67
- ) -> list[Any]:
65
+ async def run_concurrently(tasks: list[Coroutine], max_concurrent: Optional[int] = None) -> list[Any]:
68
66
  """
69
67
  Runs a list of coroutines concurrently, with a maximum number of tasks running.
70
68
  Returns the results of the coroutines in the order they were scheduled.
@@ -20,6 +20,7 @@
20
20
  from typing import List, Optional
21
21
 
22
22
  from google.protobuf.timestamp_pb2 import Timestamp
23
+
23
24
  from nucliadb_protos.audit_pb2 import (
24
25
  AuditField,
25
26
  AuditKBCounter,
@@ -20,6 +20,7 @@
20
20
  from typing import List, Optional
21
21
 
22
22
  from google.protobuf.timestamp_pb2 import Timestamp
23
+
23
24
  from nucliadb_protos.audit_pb2 import (
24
25
  AuditField,
25
26
  AuditKBCounter,
@@ -29,7 +30,6 @@ from nucliadb_protos.audit_pb2 import (
29
30
  from nucliadb_protos.nodereader_pb2 import SearchRequest
30
31
  from nucliadb_protos.resources_pb2 import FieldID
31
32
  from nucliadb_protos.writer_pb2 import BrokerMessage
32
-
33
33
  from nucliadb_utils import logger
34
34
  from nucliadb_utils.audit.audit import AuditStorage
35
35
 
@@ -51,9 +51,7 @@ class BasicAuditStorage(AuditStorage):
51
51
  audit_fields: Optional[List[AuditField]] = None,
52
52
  kb_counter: Optional[AuditKBCounter] = None,
53
53
  ):
54
- logger.debug(
55
- f"AUDIT {audit_type} {kbid} {user} {origin} {rid} {audit_fields} {kb_counter}"
56
- )
54
+ logger.debug(f"AUDIT {audit_type} {kbid} {user} {origin} {rid} {audit_fields} {kb_counter}")
57
55
 
58
56
  def report_resources(
59
57
  self,
@@ -25,6 +25,8 @@ import backoff
25
25
  import mmh3
26
26
  import nats
27
27
  from google.protobuf.timestamp_pb2 import Timestamp
28
+ from opentelemetry.trace import format_trace_id, get_current_span
29
+
28
30
  from nucliadb_protos.audit_pb2 import (
29
31
  AuditField,
30
32
  AuditKBCounter,
@@ -34,8 +36,6 @@ from nucliadb_protos.audit_pb2 import (
34
36
  )
35
37
  from nucliadb_protos.nodereader_pb2 import SearchRequest
36
38
  from nucliadb_protos.resources_pb2 import FieldID
37
- from opentelemetry.trace import format_trace_id, get_current_span
38
-
39
39
  from nucliadb_utils import logger
40
40
  from nucliadb_utils.audit.audit import AuditStorage
41
41
  from nucliadb_utils.nats import get_traced_jetstream
@@ -89,9 +89,7 @@ class StreamAuditStorage(AuditStorage):
89
89
  logger.info("Got reconnected to NATS {url}".format(url=self.nc.connected_url))
90
90
 
91
91
  async def error_cb(self, e):
92
- logger.error(
93
- "There was an error connecting to NATS audit: {}".format(e), exc_info=True
94
- )
92
+ logger.error("There was an error connecting to NATS audit: {}".format(e), exc_info=True)
95
93
 
96
94
  async def closed_cb(self):
97
95
  logger.info("Connection is closed on NATS")
@@ -149,9 +147,7 @@ class StreamAuditStorage(AuditStorage):
149
147
  async def send(self, message: AuditRequest):
150
148
  self.queue.put_nowait(message)
151
149
 
152
- @backoff.on_exception(
153
- backoff.expo, (Exception,), jitter=backoff.random_jitter, max_tries=4
154
- )
150
+ @backoff.on_exception(backoff.expo, (Exception,), jitter=backoff.random_jitter, max_tries=4)
155
151
  async def _send(self, message: AuditRequest):
156
152
  if self.js is None: # pragma: no cover
157
153
  raise AttributeError()
@@ -205,9 +201,7 @@ class StreamAuditStorage(AuditStorage):
205
201
  account_id=None,
206
202
  kb_id=kbid,
207
203
  kb_source=KBSource.HOSTED,
208
- storage=Storage(
209
- paragraphs=kb_counter.paragraphs, fields=kb_counter.fields
210
- ),
204
+ storage=Storage(paragraphs=kb_counter.paragraphs, fields=kb_counter.fields),
211
205
  )
212
206
 
213
207
  auditrequest.trace_id = get_trace_id()
@@ -56,9 +56,7 @@ class NucliaCloudAuthenticationBackend(AuthenticationBackend):
56
56
  self.roles_header = roles_header
57
57
  self.user_header = user_header
58
58
 
59
- async def authenticate(
60
- self, request: HTTPConnection
61
- ) -> Optional[Tuple[AuthCredentials, BaseUser]]:
59
+ async def authenticate(self, request: HTTPConnection) -> Optional[Tuple[AuthCredentials, BaseUser]]:
62
60
  if self.roles_header not in request.headers:
63
61
  return None
64
62
  else:
@@ -97,9 +95,7 @@ def requires(
97
95
  elif isinstance(scopes, str):
98
96
  scopes_list = [scopes]
99
97
  elif isinstance(scopes, list):
100
- scopes_list = [
101
- scope.value if isinstance(scope, Enum) else scope for scope in scopes
102
- ]
98
+ scopes_list = [scope.value if isinstance(scope, Enum) else scope for scope in scopes]
103
99
 
104
100
  def decorator(func: typing.Callable) -> typing.Callable:
105
101
  func.__required_scopes__ = scopes_list # type: ignore
@@ -110,16 +106,12 @@ def requires(
110
106
  type = parameter.name
111
107
  break
112
108
  else:
113
- raise Exception(
114
- f'No "request" or "websocket" argument on function "{func}"'
115
- )
109
+ raise Exception(f'No "request" or "websocket" argument on function "{func}"')
116
110
 
117
111
  if type == "websocket":
118
112
  # Handle websocket functions. (Always async)
119
113
  @functools.wraps(func)
120
- async def websocket_wrapper(
121
- *args: typing.Any, **kwargs: typing.Any
122
- ) -> None:
114
+ async def websocket_wrapper(*args: typing.Any, **kwargs: typing.Any) -> None:
123
115
  websocket = kwargs.get("websocket", args[idx])
124
116
  assert isinstance(websocket, WebSocket)
125
117
 
@@ -133,17 +125,13 @@ def requires(
133
125
  elif asyncio.iscoroutinefunction(func):
134
126
  # Handle async request/response functions.
135
127
  @functools.wraps(func)
136
- async def async_wrapper(
137
- *args: typing.Any, **kwargs: typing.Any
138
- ) -> Response:
128
+ async def async_wrapper(*args: typing.Any, **kwargs: typing.Any) -> Response:
139
129
  request = kwargs.get("request", None)
140
130
  assert isinstance(request, Request)
141
131
 
142
132
  if not has_required_scope(request, scopes_list):
143
133
  if redirect is not None:
144
- return RedirectResponse(
145
- url=request.url_for(redirect), status_code=303
146
- )
134
+ return RedirectResponse(url=request.url_for(redirect), status_code=303)
147
135
  raise HTTPException(status_code=status_code)
148
136
  return await func(*args, **kwargs)
149
137
 
@@ -161,9 +149,7 @@ def requires(
161
149
 
162
150
  if not has_required_scope(request, scopes_list):
163
151
  if redirect is not None:
164
- return RedirectResponse(
165
- url=request.url_for(redirect), status_code=303
166
- )
152
+ return RedirectResponse(url=request.url_for(redirect), status_code=303)
167
153
  raise HTTPException(status_code=status_code)
168
154
  return func(*args, **kwargs)
169
155
 
@@ -148,9 +148,7 @@ class NatsPubsub(PubSubDriver):
148
148
 
149
149
  async def reconnected_cb(self):
150
150
  # See who we are connected to on reconnect.
151
- logger.info(
152
- "Got reconnected NATS to {url}".format(url=self.nc.connected_url.netloc)
153
- )
151
+ logger.info("Got reconnected NATS to {url}".format(url=self.nc.connected_url.netloc))
154
152
 
155
153
  async def error_cb(self, e):
156
154
  logger.info("There was an error connecting to NATS {}".format(e), exc_info=True)
@@ -169,9 +167,7 @@ class NatsPubsub(PubSubDriver):
169
167
  else:
170
168
  raise ErrConnectionClosed("Could not subscribe")
171
169
 
172
- async def subscribe(
173
- self, handler: Callback, key, group="", subscription_id: Optional[str] = None
174
- ):
170
+ async def subscribe(self, handler: Callback, key, group="", subscription_id: Optional[str] = None):
175
171
  if subscription_id is None:
176
172
  subscription_id = key
177
173
 
nucliadb_utils/debug.py CHANGED
@@ -54,10 +54,7 @@ def display_top(snapshot, key_type="lineno", limit=10): # pragma: no cover
54
54
  print(f"Top {limit} lines")
55
55
  for index, stat in enumerate(top_stats[:limit], 1):
56
56
  frame = stat.traceback[0]
57
- print(
58
- "#%s: %s:%s: %.1f KiB"
59
- % (index, frame.filename, frame.lineno, stat.size / 1024)
60
- )
57
+ print("#%s: %s:%s: %.1f KiB" % (index, frame.filename, frame.lineno, stat.size / 1024))
61
58
  line = linecache.getline(frame.filename, frame.lineno).strip()
62
59
  if line:
63
60
  print(" %s" % line)
@@ -29,9 +29,7 @@ from starlette.routing import BaseRoute
29
29
  CallableT = TypeVar("CallableT", bound=Callable[..., Any])
30
30
 
31
31
 
32
- def version(
33
- major: int, minor: int = 0
34
- ) -> Callable[[CallableT], CallableT]: # pragma: no cover
32
+ def version(major: int, minor: int = 0) -> Callable[[CallableT], CallableT]: # pragma: no cover
35
33
  def decorator(func: CallableT) -> CallableT:
36
34
  func._api_version = (major, minor) # type: ignore
37
35
  return func
@@ -75,7 +73,10 @@ def VersionedFastAPI(
75
73
  prefix = prefix_format.format(major=major, minor=minor)
76
74
  semver = version_format.format(major=major, minor=minor)
77
75
  versioned_app = FastAPI(
78
- title=app.title, description=app.description, version=semver, **kwargs # type: ignore
76
+ title=app.title,
77
+ description=app.description,
78
+ version=semver,
79
+ **kwargs, # type: ignore
79
80
  )
80
81
  for route in version_route_mapping[version]:
81
82
  for method in route.methods:
@@ -72,9 +72,7 @@ class FlagService:
72
72
  else:
73
73
  self.flag_service = mrflagly.FlagService(url=settings.flag_settings_url)
74
74
 
75
- def enabled(
76
- self, flag_key: str, default: bool = False, context: Optional[dict] = None
77
- ) -> bool:
75
+ def enabled(self, flag_key: str, default: bool = False, context: Optional[dict] = None) -> bool:
78
76
  if context is None:
79
77
  context = {}
80
78
  context["environment"] = running_settings.running_environment
nucliadb_utils/grpc.py CHANGED
@@ -90,8 +90,6 @@ def get_traced_grpc_server(service_name: str, max_receive_message: int = 100):
90
90
  interceptors=[SentryInterceptor()],
91
91
  )
92
92
  else:
93
- options = [
94
- ("grpc.max_receive_message_length", max_receive_message * 1024 * 1024)
95
- ]
93
+ options = [("grpc.max_receive_message_length", max_receive_message * 1024 * 1024)]
96
94
  server = aio.server(options=options)
97
95
  return server
nucliadb_utils/helpers.py CHANGED
@@ -21,7 +21,7 @@ from typing import AsyncGenerator
21
21
 
22
22
 
23
23
  async def async_gen_lookahead(
24
- gen: AsyncGenerator[bytes, None]
24
+ gen: AsyncGenerator[bytes, None],
25
25
  ) -> AsyncGenerator[tuple[bytes, bool], None]:
26
26
  """Async generator that yields the next chunk and whether it's the last one.
27
27
  Empty chunks are ignored.
@@ -22,8 +22,8 @@ from typing import Any, Dict, List, Optional, Tuple, Union
22
22
  import nats
23
23
  from nats.aio.client import Client
24
24
  from nats.js.client import JetStreamContext
25
- from nucliadb_protos.nodewriter_pb2 import IndexMessage
26
25
 
26
+ from nucliadb_protos.nodewriter_pb2 import IndexMessage
27
27
  from nucliadb_telemetry.jetstream import JetStreamContextTelemetry
28
28
  from nucliadb_utils import const, logger
29
29
  from nucliadb_utils.nats import get_traced_jetstream
nucliadb_utils/nats.py CHANGED
@@ -100,9 +100,7 @@ class MessageProgressUpdater:
100
100
  class NatsConnectionManager:
101
101
  _nc: NATSClient
102
102
  _subscriptions: list[tuple[Subscription, Callable[[], Awaitable[None]]]]
103
- _unhealthy_timeout = (
104
- 10 # needs to be unhealth for 10 seconds to be unhealthy and force exit
105
- )
103
+ _unhealthy_timeout = 10 # needs to be unhealth for 10 seconds to be unhealthy and force exit
106
104
 
107
105
  def __init__(
108
106
  self,
nucliadb_utils/run.py CHANGED
@@ -25,9 +25,7 @@ from typing import Awaitable, Callable
25
25
  logger = logging.getLogger(__name__)
26
26
 
27
27
 
28
- async def run_until_exit(
29
- finalizers: list[Callable[[], Awaitable[None]]], sleep: float = 1.0
30
- ):
28
+ async def run_until_exit(finalizers: list[Callable[[], Awaitable[None]]], sleep: float = 1.0):
31
29
  exit_event = asyncio.Event()
32
30
 
33
31
  def handle_exit(*args):
@@ -98,9 +98,7 @@ class StorageSettings(BaseSettings):
98
98
  s3_max_pool_connections: int = 30
99
99
  s3_endpoint: Optional[str] = None
100
100
  s3_region_name: Optional[str] = None
101
- s3_bucket: Optional[str] = Field(
102
- default=None, description="KnowledgeBox S3 bucket name template"
103
- )
101
+ s3_bucket: Optional[str] = Field(default=None, description="KnowledgeBox S3 bucket name template")
104
102
  s3_bucket_tags: Dict[str, str] = Field(
105
103
  default={},
106
104
  description="Map of tags with which S3 buckets will be tagged with: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketTagging.html", # noqa
@@ -125,13 +123,9 @@ storage_settings = StorageSettings()
125
123
  class NucliaSettings(BaseSettings):
126
124
  nuclia_service_account: Optional[str] = None
127
125
  nuclia_public_url: str = "https://{zone}.nuclia.cloud"
128
- nuclia_processing_cluster_url: str = (
129
- "http://processing-api.processing.svc.cluster.local:8080"
130
- )
126
+ nuclia_processing_cluster_url: str = "http://processing-api.processing.svc.cluster.local:8080"
131
127
  nuclia_inner_predict_url: str = "http://predict.learning.svc.cluster.local:8080"
132
- learning_internal_svc_base_url: str = (
133
- "http://{service}.learning.svc.cluster.local:8080"
134
- )
128
+ learning_internal_svc_base_url: str = "http://{service}.learning.svc.cluster.local:8080"
135
129
 
136
130
  nuclia_zone: str = "europe-1"
137
131
  onprem: bool = True
nucliadb_utils/signals.py CHANGED
@@ -62,9 +62,7 @@ class Signal:
62
62
 
63
63
  awaitables = [
64
64
  cb(payload=payload)
65
- for cb, _ in sorted(
66
- self.callbacks.values(), key=lambda t: t[1], reverse=True
67
- )
65
+ for cb, _ in sorted(self.callbacks.values(), key=lambda t: t[1], reverse=True)
68
66
  ]
69
67
 
70
68
  results = await asyncio.gather(*awaitables, return_exceptions=True)
@@ -39,9 +39,7 @@ class InvalidOffset(Exception):
39
39
  class ResumableUploadGone(Exception):
40
40
  def __init__(self, text: str):
41
41
  self.text = text
42
- super().__init__(
43
- "Resumable upload is no longer available " "Google: \n " f"{text}"
44
- )
42
+ super().__init__("Resumable upload is no longer available " "Google: \n " f"{text}")
45
43
 
46
44
 
47
45
  class CouldNotCopyNotFound(Exception):
@@ -35,8 +35,8 @@ import backoff
35
35
  import google.auth.transport.requests # type: ignore
36
36
  import yarl
37
37
  from google.oauth2 import service_account # type: ignore
38
- from nucliadb_protos.resources_pb2 import CloudFile
39
38
 
39
+ from nucliadb_protos.resources_pb2 import CloudFile
40
40
  from nucliadb_telemetry import errors, metrics
41
41
  from nucliadb_telemetry.utils import setup_telemetry
42
42
  from nucliadb_utils import logger
@@ -117,9 +117,7 @@ class GCSStorageField(StorageField):
117
117
  origin_bucket_name: str,
118
118
  destination_bucket_name: str,
119
119
  ):
120
- await self.copy(
121
- origin_uri, destination_uri, origin_bucket_name, destination_bucket_name
122
- )
120
+ await self.copy(origin_uri, destination_uri, origin_bucket_name, destination_bucket_name)
123
121
  await self.storage.delete_upload(origin_uri, origin_bucket_name)
124
122
 
125
123
  @backoff.on_exception(
@@ -163,9 +161,7 @@ class GCSStorageField(StorageField):
163
161
  assert data["resource"]["name"] == destination_uri
164
162
 
165
163
  @storage_ops_observer.wrap({"type": "iter_data"})
166
- async def iter_data(
167
- self, range: Optional[Range] = None
168
- ) -> AsyncGenerator[bytes, None]:
164
+ async def iter_data(self, range: Optional[Range] = None) -> AsyncGenerator[bytes, None]:
169
165
  attempt = 1
170
166
  while True:
171
167
  try:
@@ -243,9 +239,7 @@ class GCSStorageField(StorageField):
243
239
 
244
240
  if self.field is not None and self.field.upload_uri != "":
245
241
  # If there is a temporal url
246
- await self.storage.delete_upload(
247
- self.field.upload_uri, self.field.bucket_name
248
- )
242
+ await self.storage.delete_upload(self.field.upload_uri, self.field.bucket_name)
249
243
 
250
244
  if self.field is not None and self.field.uri != "":
251
245
  field: CloudFile = CloudFile(
@@ -381,18 +375,13 @@ class GCSStorageField(StorageField):
381
375
  if self.field.old_uri not in ("", None):
382
376
  # Already has a file
383
377
  try:
384
- await self.storage.delete_upload(
385
- self.field.old_uri, self.field.bucket_name
386
- )
378
+ await self.storage.delete_upload(self.field.old_uri, self.field.bucket_name)
387
379
  except GoogleCloudException as e:
388
380
  logger.warning(
389
- f"Could not delete existing google cloud file "
390
- f"with uri: {self.field.uri}: {e}"
381
+ f"Could not delete existing google cloud file " f"with uri: {self.field.uri}: {e}"
391
382
  )
392
383
  if self.field.upload_uri != self.key:
393
- await self.move(
394
- self.field.upload_uri, self.key, self.field.bucket_name, self.bucket
395
- )
384
+ await self.move(self.field.upload_uri, self.key, self.field.bucket_name, self.bucket)
396
385
 
397
386
  self.field.uri = self.key
398
387
  self.field.ClearField("resumable_uri")
@@ -490,9 +479,7 @@ class GCSStorage(Storage):
490
479
  self._bucket_labels = labels or {}
491
480
  self._executor = executor
492
481
  self._creation_access_token = datetime.now()
493
- self._upload_url = (
494
- url + "/upload/storage/v1/b/{bucket}/o?uploadType=resumable"
495
- ) # noqa
482
+ self._upload_url = url + "/upload/storage/v1/b/{bucket}/o?uploadType=resumable" # noqa
496
483
  self.object_base_url = url + "/storage/v1/b"
497
484
  self._client = None
498
485
 
@@ -516,17 +503,13 @@ class GCSStorage(Storage):
516
503
  if self.deadletter_bucket is not None and self.deadletter_bucket != "":
517
504
  await self.create_bucket(self.deadletter_bucket)
518
505
  except Exception: # pragma: no cover
519
- logger.exception(
520
- f"Could not create bucket {self.deadletter_bucket}", exc_info=True
521
- )
506
+ logger.exception(f"Could not create bucket {self.deadletter_bucket}", exc_info=True)
522
507
 
523
508
  try:
524
509
  if self.indexing_bucket is not None and self.indexing_bucket != "":
525
510
  await self.create_bucket(self.indexing_bucket)
526
511
  except Exception: # pragma: no cover
527
- logger.exception(
528
- f"Could not create bucket {self.indexing_bucket}", exc_info=True
529
- )
512
+ logger.exception(f"Could not create bucket {self.indexing_bucket}", exc_info=True)
530
513
 
531
514
  async def finalize(self):
532
515
  await self.session.close()
@@ -549,9 +532,7 @@ class GCSStorage(Storage):
549
532
  if self.session is None:
550
533
  raise AttributeError()
551
534
  if uri:
552
- url = "{}/{}/o/{}".format(
553
- self.object_base_url, bucket_name, quote_plus(uri)
554
- )
535
+ url = "{}/{}/o/{}".format(self.object_base_url, bucket_name, quote_plus(uri))
555
536
  headers = await self.get_access_headers()
556
537
  async with self.session.delete(url, headers=headers) as resp:
557
538
  try:
@@ -562,8 +543,7 @@ class GCSStorage(Storage):
562
543
  if resp.status not in (200, 204, 404):
563
544
  if resp.status == 404:
564
545
  logger.error(
565
- f"Attempt to delete not found gcloud: {data}, "
566
- f"status: {resp.status}",
546
+ f"Attempt to delete not found gcloud: {data}, " f"status: {resp.status}",
567
547
  exc_info=True,
568
548
  )
569
549
  else:
@@ -668,8 +648,7 @@ class GCSStorage(Storage):
668
648
  logger.error("Not implemented")
669
649
  elif resp.status == 404:
670
650
  logger.error(
671
- f"Attempt to delete not found gcloud: {data}, "
672
- f"status: {resp.status}",
651
+ f"Attempt to delete not found gcloud: {data}, " f"status: {resp.status}",
673
652
  exc_info=True,
674
653
  )
675
654
  else:
@@ -706,9 +685,7 @@ class GCSStorage(Storage):
706
685
  errors.capture_message(msg, "error", scope)
707
686
  return deleted, conflict
708
687
 
709
- async def iterate_objects(
710
- self, bucket: str, prefix: str
711
- ) -> AsyncGenerator[ObjectInfo, None]:
688
+ async def iterate_objects(self, bucket: str, prefix: str) -> AsyncGenerator[ObjectInfo, None]:
712
689
  if self.session is None:
713
690
  raise AttributeError()
714
691
  url = "{}/{}/o".format(self.object_base_url, bucket)
@@ -755,9 +732,7 @@ def parse_object_metadata(object_data: dict[str, Any], key: str) -> ObjectMetada
755
732
  size = int(custom_size)
756
733
 
757
734
  # Parse content-type
758
- content_type = (
759
- custom_metadata.get("content_type") or object_data.get("contentType") or ""
760
- )
735
+ content_type = custom_metadata.get("content_type") or object_data.get("contentType") or ""
761
736
 
762
737
  # Parse filename
763
738
  filename = custom_metadata.get("filename") or key.split("/")[-1]
@@ -27,8 +27,8 @@ from datetime import datetime
27
27
  from typing import AsyncGenerator, AsyncIterator, Optional
28
28
 
29
29
  import aiofiles
30
- from nucliadb_protos.resources_pb2 import CloudFile
31
30
 
31
+ from nucliadb_protos.resources_pb2 import CloudFile
32
32
  from nucliadb_utils.storages import CHUNK_SIZE
33
33
  from nucliadb_utils.storages.storage import (
34
34
  ObjectInfo,
@@ -78,9 +78,7 @@ class LocalStorageField(StorageField):
78
78
  destination_path = f"{destination_bucket_path}/{destination_uri}"
79
79
  shutil.copy(origin_path, destination_path)
80
80
 
81
- async def iter_data(
82
- self, range: Optional[Range] = None
83
- ) -> AsyncGenerator[bytes, None]:
81
+ async def iter_data(self, range: Optional[Range] = None) -> AsyncGenerator[bytes, None]:
84
82
  key = self.field.uri if self.field else self.key
85
83
  if self.field is None:
86
84
  bucket = self.bucket
@@ -89,7 +87,6 @@ class LocalStorageField(StorageField):
89
87
 
90
88
  path = self.storage.get_file_path(bucket, key)
91
89
  async with aiofiles.open(path, mode="rb") as resp:
92
-
93
90
  if range and range.start is not None:
94
91
  # Seek to the start of the range
95
92
  await resp.seek(range.start)
@@ -123,9 +120,7 @@ class LocalStorageField(StorageField):
123
120
  async def start(self, cf: CloudFile) -> CloudFile:
124
121
  if self.field is not None and self.field.upload_uri != "":
125
122
  # If there is a temporal url
126
- await self.storage.delete_upload(
127
- self.field.upload_uri, self.field.bucket_name
128
- )
123
+ await self.storage.delete_upload(self.field.upload_uri, self.field.bucket_name)
129
124
 
130
125
  if self.field is not None and self.field.uri != "":
131
126
  field: CloudFile = CloudFile(
@@ -193,9 +188,7 @@ class LocalStorageField(StorageField):
193
188
  # Already has a file
194
189
  await self.storage.delete_upload(self.field.uri, self.field.bucket_name)
195
190
  if self.field.upload_uri != self.key:
196
- await self.move(
197
- self.field.upload_uri, self.key, self.field.bucket_name, self.bucket
198
- )
191
+ await self.move(self.field.upload_uri, self.key, self.field.bucket_name, self.bucket)
199
192
 
200
193
  await self._handler.close()
201
194
  self.field.uri = self.key
@@ -284,9 +277,7 @@ class LocalStorage(Storage):
284
277
  deleted = False
285
278
  return deleted
286
279
 
287
- async def iterate_objects(
288
- self, bucket: str, prefix: str
289
- ) -> AsyncGenerator[ObjectInfo, None]:
280
+ async def iterate_objects(self, bucket: str, prefix: str) -> AsyncGenerator[ObjectInfo, None]:
290
281
  for key in glob.glob(f"{bucket}/{prefix}*"):
291
282
  yield ObjectInfo(name=key)
292
283
 
@@ -20,8 +20,8 @@
20
20
  from typing import Optional
21
21
 
22
22
  import aiohttp
23
- from nucliadb_protos.resources_pb2 import CloudFile
24
23
 
24
+ from nucliadb_protos.resources_pb2 import CloudFile
25
25
  from nucliadb_utils.storages import CHUNK_SIZE
26
26
 
27
27
 
@@ -29,8 +29,8 @@ import backoff
29
29
  import botocore # type: ignore
30
30
  from aiobotocore.client import AioBaseClient # type: ignore
31
31
  from aiobotocore.session import AioSession, get_session # type: ignore
32
- from nucliadb_protos.resources_pb2 import CloudFile
33
32
 
33
+ from nucliadb_protos.resources_pb2 import CloudFile
34
34
  from nucliadb_telemetry import errors
35
35
  from nucliadb_utils import logger
36
36
  from nucliadb_utils.storages.exceptions import UnparsableResponse
@@ -90,9 +90,7 @@ class S3StorageField(StorageField):
90
90
  ):
91
91
  range = range or Range()
92
92
  if range.any():
93
- coro = self.storage._s3aioclient.get_object(
94
- Bucket=bucket, Key=uri, Range=range.to_header()
95
- )
93
+ coro = self.storage._s3aioclient.get_object(Bucket=bucket, Key=uri, Range=range.to_header())
96
94
  else:
97
95
  coro = self.storage._s3aioclient.get_object(Bucket=bucket, Key=uri)
98
96
  try:
@@ -104,9 +102,7 @@ class S3StorageField(StorageField):
104
102
  else:
105
103
  raise
106
104
 
107
- async def iter_data(
108
- self, range: Optional[Range] = None
109
- ) -> AsyncGenerator[bytes, None]:
105
+ async def iter_data(self, range: Optional[Range] = None) -> AsyncGenerator[bytes, None]:
110
106
  # Suports field and key based iter
111
107
  uri = self.field.uri if self.field else self.key
112
108
  if self.field is None:
@@ -235,9 +231,7 @@ class S3StorageField(StorageField):
235
231
  self.field.ClearField("old_uri")
236
232
  self.field.ClearField("old_bucket")
237
233
  except botocore.exceptions.ClientError:
238
- logger.error(
239
- f"Referenced key {self.field.uri} could not be found", exc_info=True
240
- )
234
+ logger.error(f"Referenced key {self.field.uri} could not be found", exc_info=True)
241
235
  logger.warning("Error deleting object", exc_info=True)
242
236
 
243
237
  if self.field.resumable_uri != "":
@@ -264,8 +258,7 @@ class S3StorageField(StorageField):
264
258
  self.field.offset += 1
265
259
  part_info = {
266
260
  "Parts": [
267
- {"PartNumber": part + 1, "ETag": etag}
268
- for part, etag in enumerate(self.field.parts)
261
+ {"PartNumber": part + 1, "ETag": etag} for part, etag in enumerate(self.field.parts)
269
262
  ]
270
263
  }
271
264
  await self.storage._s3aioclient.complete_multipart_upload(
@@ -323,9 +316,7 @@ class S3StorageField(StorageField):
323
316
  origin_bucket_name: str,
324
317
  destination_bucket_name: str,
325
318
  ):
326
- await self.copy(
327
- origin_uri, destination_uri, origin_bucket_name, destination_bucket_name
328
- )
319
+ await self.copy(origin_uri, destination_uri, origin_bucket_name, destination_bucket_name)
329
320
  await self.storage.delete_upload(origin_uri, origin_bucket_name)
330
321
 
331
322
  async def upload(self, iterator: AsyncIterator, origin: CloudFile) -> CloudFile:
@@ -373,9 +364,7 @@ class S3Storage(Storage):
373
364
  verify=verify_ssl,
374
365
  use_ssl=use_ssl,
375
366
  region_name=region_name,
376
- config=aiobotocore.config.AioConfig(
377
- None, max_pool_connections=max_pool_connections
378
- ),
367
+ config=aiobotocore.config.AioConfig(None, max_pool_connections=max_pool_connections),
379
368
  )
380
369
  self._exit_stack = AsyncExitStack()
381
370
  self.bucket = bucket
@@ -420,9 +409,7 @@ class S3Storage(Storage):
420
409
  else:
421
410
  raise AttributeError("No valid uri")
422
411
 
423
- async def iterate_objects(
424
- self, bucket: str, prefix: str = "/"
425
- ) -> AsyncGenerator[ObjectInfo, None]:
412
+ async def iterate_objects(self, bucket: str, prefix: str = "/") -> AsyncGenerator[ObjectInfo, None]:
426
413
  paginator = self._s3aioclient.get_paginator("list_objects")
427
414
  async for result in paginator.paginate(Bucket=bucket, Prefix=prefix):
428
415
  for item in result.get("Contents", []):
@@ -436,9 +423,7 @@ class S3Storage(Storage):
436
423
  return await bucket_exists(self._s3aioclient, bucket_name)
437
424
 
438
425
  async def create_bucket(self, bucket_name: str):
439
- await create_bucket(
440
- self._s3aioclient, bucket_name, self._bucket_tags, self._region_name
441
- )
426
+ await create_bucket(self._s3aioclient, bucket_name, self._bucket_tags, self._region_name)
442
427
 
443
428
  async def schedule_delete_kb(self, kbid: str):
444
429
  bucket_name = self.get_bucket_name(kbid)
@@ -509,9 +494,7 @@ async def create_bucket(
509
494
  ):
510
495
  bucket_creation_options = {}
511
496
  if region_name is not None:
512
- bucket_creation_options = {
513
- "CreateBucketConfiguration": {"LocationConstraint": region_name}
514
- }
497
+ bucket_creation_options = {"CreateBucketConfiguration": {"LocationConstraint": region_name}}
515
498
  # Create the bucket
516
499
  await client.create_bucket(Bucket=bucket_name, **bucket_creation_options)
517
500
 
@@ -521,8 +504,7 @@ async def create_bucket(
521
504
  Bucket=bucket_name,
522
505
  Tagging={
523
506
  "TagSet": [
524
- {"Key": tag_key, "Value": tag_value}
525
- for tag_key, tag_value in bucket_tags.items()
507
+ {"Key": tag_key, "Value": tag_value} for tag_key, tag_value in bucket_tags.items()
526
508
  ]
527
509
  },
528
510
  )
@@ -36,12 +36,12 @@ from typing import (
36
36
  cast,
37
37
  )
38
38
 
39
+ from pydantic import BaseModel
40
+
39
41
  from nucliadb_protos.noderesources_pb2 import Resource as BrainResource
40
42
  from nucliadb_protos.nodewriter_pb2 import IndexMessage
41
43
  from nucliadb_protos.resources_pb2 import CloudFile
42
44
  from nucliadb_protos.writer_pb2 import BrokerMessage
43
- from pydantic import BaseModel
44
-
45
45
  from nucliadb_utils import logger
46
46
  from nucliadb_utils.helpers import async_gen_lookahead
47
47
  from nucliadb_utils.storages import CHUNK_SIZE
@@ -110,9 +110,7 @@ class StorageField(abc.ABC, metaclass=abc.ABCMeta):
110
110
  async def upload(self, iterator: AsyncIterator, origin: CloudFile) -> CloudFile: ...
111
111
 
112
112
  @abc.abstractmethod
113
- async def iter_data(
114
- self, range: Optional[Range] = None
115
- ) -> AsyncGenerator[bytes, None]:
113
+ async def iter_data(self, range: Optional[Range] = None) -> AsyncGenerator[bytes, None]:
116
114
  raise NotImplementedError()
117
115
  yield b""
118
116
 
@@ -166,14 +164,10 @@ class Storage(abc.ABC, metaclass=abc.ABCMeta):
166
164
  # Delete all keys inside a resource
167
165
  bucket = self.get_bucket_name(kbid)
168
166
  resource_storage_base_path = STORAGE_RESOURCE.format(kbid=kbid, uuid=uuid)
169
- async for object_info in self.iterate_objects(
170
- bucket, resource_storage_base_path
171
- ):
167
+ async for object_info in self.iterate_objects(bucket, resource_storage_base_path):
172
168
  await self.delete_upload(object_info.name, bucket)
173
169
 
174
- async def deadletter(
175
- self, message: BrokerMessage, seq: int, seqid: int, partition: str
176
- ):
170
+ async def deadletter(self, message: BrokerMessage, seq: int, seqid: int, partition: str):
177
171
  if self.deadletter_bucket is None:
178
172
  logger.error("No Deadletter Bucket defined will not store the error")
179
173
  return
@@ -183,9 +177,7 @@ class Storage(abc.ABC, metaclass=abc.ABCMeta):
183
177
  def get_indexing_storage_key(
184
178
  self, *, kb: str, logical_shard: str, resource_uid: str, txid: Union[int, str]
185
179
  ):
186
- return INDEXING_KEY.format(
187
- kb=kb, shard=logical_shard, resource=resource_uid, txid=txid
188
- )
180
+ return INDEXING_KEY.format(kb=kb, shard=logical_shard, resource=resource_uid, txid=txid)
189
181
 
190
182
  async def indexing(
191
183
  self,
@@ -246,9 +238,7 @@ class Storage(abc.ABC, metaclass=abc.ABCMeta):
246
238
  txid=payload.reindex_id,
247
239
  )
248
240
  else:
249
- key = OLD_INDEXING_KEY.format(
250
- node=payload.node, shard=payload.shard, txid=payload.txid
251
- )
241
+ key = OLD_INDEXING_KEY.format(node=payload.node, shard=payload.shard, txid=payload.txid)
252
242
 
253
243
  bytes_buffer = await self.downloadbytes(self.indexing_bucket, key)
254
244
  if bytes_buffer.getbuffer().nbytes == 0:
@@ -286,17 +276,12 @@ class Storage(abc.ABC, metaclass=abc.ABCMeta):
286
276
  # The cloudfile is valid for our environment
287
277
  if file.uri == "":
288
278
  return False
289
- elif (
290
- file.source == self.source
291
- and self.get_bucket_name(kbid) == file.bucket_name
292
- ):
279
+ elif file.source == self.source and self.get_bucket_name(kbid) == file.bucket_name:
293
280
  return False
294
281
  else:
295
282
  return True
296
283
 
297
- async def normalize_binary(
298
- self, file: CloudFile, destination: StorageField
299
- ): # pragma: no cover
284
+ async def normalize_binary(self, file: CloudFile, destination: StorageField): # pragma: no cover
300
285
  if file.source == self.source and file.uri != destination.key:
301
286
  # This MAY BE the case for NucliaDB hosted deployment (Nuclia's cloud deployment):
302
287
  # The data has been pushed to the bucket but with a different key.
@@ -346,14 +331,10 @@ class Storage(abc.ABC, metaclass=abc.ABCMeta):
346
331
  self, kbid: str, uuid: str, field: str, ident: str, count: int
347
332
  ) -> StorageField:
348
333
  bucket = self.get_bucket_name(kbid)
349
- key = KB_CONVERSATION_FIELD.format(
350
- kbid=kbid, uuid=uuid, field=field, ident=ident, count=count
351
- )
334
+ key = KB_CONVERSATION_FIELD.format(kbid=kbid, uuid=uuid, field=field, ident=ident, count=count)
352
335
  return self.field_klass(storage=self, bucket=bucket, fullkey=key)
353
336
 
354
- def layout_field(
355
- self, kbid: str, uuid: str, field: str, ident: str
356
- ) -> StorageField:
337
+ def layout_field(self, kbid: str, uuid: str, field: str, ident: str) -> StorageField:
357
338
  bucket = self.get_bucket_name(kbid)
358
339
  key = KB_LAYOUT_FIELD.format(kbid=kbid, uuid=uuid, field=field, ident=ident)
359
340
  return self.field_klass(storage=self, bucket=bucket, fullkey=key)
@@ -368,9 +349,7 @@ class Storage(abc.ABC, metaclass=abc.ABCMeta):
368
349
  # Its a file field value
369
350
  bucket = self.get_bucket_name(kbid)
370
351
  key = KB_RESOURCE_FIELD.format(kbid=kbid, uuid=uuid, field=field)
371
- return self.field_klass(
372
- storage=self, bucket=bucket, fullkey=key, field=old_field
373
- )
352
+ return self.field_klass(storage=self, bucket=bucket, fullkey=key, field=old_field)
374
353
 
375
354
  def file_extracted(
376
355
  self, kbid: str, uuid: str, field_type: str, field: str, key: str
@@ -452,9 +431,7 @@ class Storage(abc.ABC, metaclass=abc.ABCMeta):
452
431
  key: str,
453
432
  range: Optional[Range] = None,
454
433
  ):
455
- destination: StorageField = self.field_klass(
456
- storage=self, bucket=bucket, fullkey=key
457
- )
434
+ destination: StorageField = self.field_klass(storage=self, bucket=bucket, fullkey=key)
458
435
  try:
459
436
  async for data in destination.iter_data(range=range):
460
437
  yield data
@@ -536,21 +513,15 @@ class Storage(abc.ABC, metaclass=abc.ABCMeta):
536
513
  async def finalize(self) -> None: ...
537
514
 
538
515
  @abc.abstractmethod
539
- async def iterate_objects(
540
- self, bucket: str, prefix: str
541
- ) -> AsyncGenerator[ObjectInfo, None]:
516
+ async def iterate_objects(self, bucket: str, prefix: str) -> AsyncGenerator[ObjectInfo, None]:
542
517
  raise NotImplementedError()
543
518
  yield ObjectInfo(name="")
544
519
 
545
520
  async def copy(self, file: CloudFile, destination: StorageField) -> None:
546
- await destination.copy(
547
- file.uri, destination.key, file.bucket_name, destination.bucket
548
- )
521
+ await destination.copy(file.uri, destination.key, file.bucket_name, destination.bucket)
549
522
 
550
523
  async def move(self, file: CloudFile, destination: StorageField) -> None:
551
- await destination.move(
552
- file.uri, destination.key, file.bucket_name, destination.bucket
553
- )
524
+ await destination.move(file.uri, destination.key, file.bucket_name, destination.bucket)
554
525
 
555
526
  @abc.abstractmethod
556
527
  async def create_kb(self, kbid: str) -> bool: ...
@@ -108,9 +108,7 @@ class AsyncBenchmarkFixture(object): # pragma: no cover
108
108
  )
109
109
  return timer_precision
110
110
 
111
- async def _make_runner(
112
- self, function_to_benchmark: Callable[..., Awaitable[T]], args, kwargs
113
- ):
111
+ async def _make_runner(self, function_to_benchmark: Callable[..., Awaitable[T]], args, kwargs):
114
112
  async def runner(loops_range, timer=self._timer):
115
113
  gc_enabled = gc.isenabled()
116
114
  if self._disable_gc:
@@ -162,8 +160,7 @@ class AsyncBenchmarkFixture(object): # pragma: no cover
162
160
  if self._mode:
163
161
  self.has_error = True
164
162
  raise FixtureAlreadyUsed(
165
- "Fixture can only be used once. Previously it was used in %s mode."
166
- % self._mode
163
+ "Fixture can only be used once. Previously it was used in %s mode." % self._mode
167
164
  )
168
165
  try:
169
166
  self._mode = "benchmark(...)"
@@ -199,8 +196,7 @@ class AsyncBenchmarkFixture(object): # pragma: no cover
199
196
  if self._warmup:
200
197
  warmup_rounds = min(rounds, max(1, int(self._warmup / iterations)))
201
198
  self._logger.debug(
202
- " Warmup %s rounds x %s iterations ..."
203
- % (warmup_rounds, iterations)
199
+ " Warmup %s rounds x %s iterations ..." % (warmup_rounds, iterations)
204
200
  )
205
201
  for _ in range(warmup_rounds):
206
202
  await runner(loops_range)
@@ -251,10 +247,7 @@ class AsyncBenchmarkFixture(object): # pragma: no cover
251
247
  warmup_start = time.time()
252
248
  warmup_iterations = 0
253
249
  warmup_rounds = 0
254
- while (
255
- time.time() - warmup_start < self._max_time
256
- and warmup_iterations < self._warmup
257
- ):
250
+ while time.time() - warmup_start < self._max_time and warmup_iterations < self._warmup:
258
251
  duration = min(duration, await runner(loops_range))
259
252
  warmup_rounds += 1
260
253
  warmup_iterations += loops
@@ -61,9 +61,7 @@ class GCS(BaseImage):
61
61
 
62
62
  def check(self):
63
63
  try:
64
- response = requests.get(
65
- f"http://{self.host}:{self.get_port()}/storage/v1/b"
66
- )
64
+ response = requests.get(f"http://{self.host}:{self.get_port()}/storage/v1/b")
67
65
  return response.status_code == 200
68
66
  except Exception: # pragma: no cover
69
67
  return False
@@ -124,9 +124,7 @@ class Gnatsd(object):
124
124
  if self.debug:
125
125
  self.proc = subprocess.Popen(cmd)
126
126
  else:
127
- self.proc = subprocess.Popen(
128
- cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
129
- )
127
+ self.proc = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
130
128
 
131
129
  if self.debug:
132
130
  if self.proc is None:
@@ -135,20 +133,14 @@ class Gnatsd(object):
135
133
  % self.port
136
134
  )
137
135
  else:
138
- print(
139
- "[\033[0;33mDEBUG\033[0;0m] Server listening on port %d started."
140
- % self.port
141
- )
136
+ print("[\033[0;33mDEBUG\033[0;0m] Server listening on port %d started." % self.port)
142
137
  return self.proc
143
138
 
144
139
  def stop(self):
145
140
  if self.folder is not None:
146
141
  self.folder.cleanup()
147
142
  if self.debug:
148
- print(
149
- "[\033[0;33mDEBUG\033[0;0m] Server listening on %d will stop."
150
- % self.port
151
- )
143
+ print("[\033[0;33mDEBUG\033[0;0m] Server listening on %d will stop." % self.port)
152
144
 
153
145
  if self.debug:
154
146
  if self.proc is None:
@@ -168,10 +160,7 @@ class Gnatsd(object):
168
160
  os.kill(self.proc.pid, signal.SIGKILL)
169
161
  self.proc.wait()
170
162
  if self.debug:
171
- print(
172
- "[\033[0;33mDEBUG\033[0;0m] Server listening on %d was stopped."
173
- % self.port
174
- )
163
+ print("[\033[0;33mDEBUG\033[0;0m] Server listening on %d was stopped." % self.port)
175
164
 
176
165
 
177
166
  class NatsServer(Gnatsd): # pragma: no cover
@@ -26,13 +26,13 @@ from typing import Any, Optional, Union
26
26
  import nats
27
27
  from nats.aio.client import Client
28
28
  from nats.js.client import JetStreamContext
29
+
29
30
  from nucliadb_protos.writer_pb2 import (
30
31
  BrokerMessage,
31
32
  BrokerMessageBlobReference,
32
33
  Notification,
33
34
  OpStatusWriter,
34
35
  )
35
-
36
36
  from nucliadb_telemetry.jetstream import JetStreamContextTelemetry
37
37
  from nucliadb_utils import const, logger
38
38
  from nucliadb_utils.cache.pubsub import PubSubDriver
@@ -180,9 +180,7 @@ class TransactionUtility:
180
180
  writer: Union[BrokerMessage, BrokerMessageBlobReference],
181
181
  partition: int,
182
182
  wait: bool = False,
183
- target_subject: Optional[
184
- str
185
- ] = None, # allow customizing where to send the message
183
+ target_subject: Optional[str] = None, # allow customizing where to send the message
186
184
  headers: Optional[dict[str, str]] = None,
187
185
  ) -> int:
188
186
  headers = headers or {}
@@ -192,24 +190,18 @@ class TransactionUtility:
192
190
  request_id = uuid.uuid4().hex
193
191
 
194
192
  if wait:
195
- waiting_event = await self.wait_for_commited(
196
- writer.kbid, waiting_for, request_id=request_id
197
- )
193
+ waiting_event = await self.wait_for_commited(writer.kbid, waiting_for, request_id=request_id)
198
194
 
199
195
  if target_subject is None:
200
196
  target_subject = const.Streams.INGEST.subject.format(partition=partition)
201
197
 
202
- res = await self.js.publish(
203
- target_subject, writer.SerializeToString(), headers=headers
204
- )
198
+ res = await self.js.publish(target_subject, writer.SerializeToString(), headers=headers)
205
199
 
206
200
  waiting_for.seq = res.seq
207
201
 
208
202
  if wait and waiting_event is not None:
209
203
  try:
210
- await asyncio.wait_for(
211
- waiting_event.wait(), timeout=self.commit_timeout
212
- )
204
+ await asyncio.wait_for(waiting_event.wait(), timeout=self.commit_timeout)
213
205
  except asyncio.TimeoutError:
214
206
  logger.warning("Took too much to commit")
215
207
  raise TransactionCommitTimeoutError()
@@ -27,7 +27,6 @@ from enum import Enum
27
27
  from typing import TYPE_CHECKING, Any, List, Optional, Union, cast
28
28
 
29
29
  from nucliadb_protos.writer_pb2_grpc import WriterStub
30
-
31
30
  from nucliadb_utils import featureflagging
32
31
  from nucliadb_utils.audit.audit import AuditStorage
33
32
  from nucliadb_utils.audit.basic import BasicAuditStorage
@@ -150,9 +149,7 @@ async def get_storage(
150
149
  await localutil.initialize()
151
150
  logger.info("Configuring Local Storage")
152
151
  else:
153
- raise ConfigurationError(
154
- "Invalid storage settings, please configure FILE_BACKEND"
155
- )
152
+ raise ConfigurationError("Invalid storage settings, please configure FILE_BACKEND")
156
153
 
157
154
  return MAIN[Utility.STORAGE]
158
155
 
@@ -322,9 +319,7 @@ async def start_audit_utility(service: str):
322
319
  seed=audit_settings.audit_hash_seed,
323
320
  service=service,
324
321
  )
325
- logger.info(
326
- f"Configuring stream audit log {audit_settings.audit_jetstream_target}"
327
- )
322
+ logger.info(f"Configuring stream audit log {audit_settings.audit_jetstream_target}")
328
323
  else:
329
324
  raise ConfigurationError("Invalid audit driver")
330
325
  await audit_utility.initialize()
@@ -390,13 +385,9 @@ def has_feature(
390
385
  context = {}
391
386
  if headers is not None:
392
387
  if X_USER_HEADER in headers:
393
- context["user_id_md5"] = hashlib.md5(
394
- headers[X_USER_HEADER].encode("utf-8")
395
- ).hexdigest()
388
+ context["user_id_md5"] = hashlib.md5(headers[X_USER_HEADER].encode("utf-8")).hexdigest()
396
389
  if X_ACCOUNT_HEADER in headers:
397
- context["account_id_md5"] = hashlib.md5(
398
- headers[X_ACCOUNT_HEADER].encode()
399
- ).hexdigest()
390
+ context["account_id_md5"] = hashlib.md5(headers[X_ACCOUNT_HEADER].encode()).hexdigest()
400
391
  if X_ACCOUNT_TYPE_HEADER in headers:
401
392
  context["account_type"] = headers[X_ACCOUNT_TYPE_HEADER]
402
393
  return get_feature_flags().enabled(name, default=default, context=context)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nucliadb_utils
3
- Version: 4.0.3.post586
3
+ Version: 4.0.3.post589
4
4
  Home-page: https://nuclia.com
5
5
  License: BSD
6
6
  Classifier: Development Status :: 4 - Beta
@@ -23,8 +23,8 @@ Requires-Dist: PyNaCl
23
23
  Requires-Dist: pyjwt >=2.4.0
24
24
  Requires-Dist: memorylru >=1.1.2
25
25
  Requires-Dist: mrflagly
26
- Requires-Dist: nucliadb-protos >=4.0.3.post586
27
- Requires-Dist: nucliadb-telemetry >=4.0.3.post586
26
+ Requires-Dist: nucliadb-protos >=4.0.3.post589
27
+ Requires-Dist: nucliadb-telemetry >=4.0.3.post589
28
28
  Provides-Extra: cache
29
29
  Requires-Dist: redis >=4.3.4 ; extra == 'cache'
30
30
  Requires-Dist: orjson >=3.6.7 ; extra == 'cache'
@@ -1,35 +1,35 @@
1
1
  nucliadb_utils/__init__.py,sha256=EvBCH1iTODe-AgXm48aj4kVUt_Std3PeL8QnwimR5wI,895
2
- nucliadb_utils/asyncio_utils.py,sha256=9A0xwlw9E4HYAxiPtLlOzurqiTlCWNqvXrpDl1q7szE,2894
3
- nucliadb_utils/authentication.py,sha256=HTj6kFFrfdN4-DW_MNqldAPqNPdPwGHnSWl-SigiMvk,6071
2
+ nucliadb_utils/asyncio_utils.py,sha256=h8Y-xpcFFRgNzaiIW0eidz7griAQa7ggbNk34-tAt2c,2888
3
+ nucliadb_utils/authentication.py,sha256=N__d2Ez3JHJv5asYK5TgUcIkKqcAC8ZTLlnfLhfSneM,5837
4
4
  nucliadb_utils/const.py,sha256=V9SWXB_Nfy0qqgPkQcEYN_zj90WkOpLubeixRKUprfM,2391
5
- nucliadb_utils/debug.py,sha256=saSfh_CDQoQl-35KCyqef5hdB_OVdrIEnlmWnZU18vg,2470
5
+ nucliadb_utils/debug.py,sha256=Q56Nx9Dp7V2ae3CU2H0ztaZcHTJXdlflPLKLeOPZ170,2436
6
6
  nucliadb_utils/exceptions.py,sha256=y_3wk77WLVUtdo-5FtbBsdSkCtK_DsJkdWb5BoPn3qo,1094
7
- nucliadb_utils/featureflagging.py,sha256=M94p2qQROCmeMX_N3PPvzAR3iaNBGvjwdE1-aAAWp1k,2740
8
- nucliadb_utils/grpc.py,sha256=USXwPRuCJiSyLf0JW4isIKZne6od8gM_GGLWaHHjknk,3336
9
- nucliadb_utils/helpers.py,sha256=fOL6eImdvKO3NV39ymmo2UOCT-GAK1dfXKoMKdzdmFo,1599
10
- nucliadb_utils/indexing.py,sha256=06acsB4zHl7rhnzWr70QqXTX-tTRIZGFZn9HRTS_Ozg,3446
11
- nucliadb_utils/nats.py,sha256=7hRKMflwxK-p_L0KFO5jibOGhzSw2F24mKvPG-A_iN8,8224
7
+ nucliadb_utils/featureflagging.py,sha256=pgqqO4Kbqj4aCuTRbfDK4nXWvWgRUM4GPZu0da-8DG8,2726
8
+ nucliadb_utils/grpc.py,sha256=apu0uePnkGHCAT7GRQ9YZfRYyFj26kJ440i8jitbM3U,3314
9
+ nucliadb_utils/helpers.py,sha256=nPw8yod3hP-pxq80VF8QC36s7ygSg0dBUdfI-LatvCs,1600
10
+ nucliadb_utils/indexing.py,sha256=QGR0d-Oy_rIgMKOqL01ZPZ_ZFTlL8Ed1UXE2U9nqvpo,3446
11
+ nucliadb_utils/nats.py,sha256=zTAXECDXeCPtydk3F_6EMFDZ059kK0UYUU_tnWoxgXs,8208
12
12
  nucliadb_utils/partition.py,sha256=jBgy4Hu5Iwn4gjbPPcthSykwf-qNx-GcLAIwbzPd1d0,1157
13
13
  nucliadb_utils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- nucliadb_utils/run.py,sha256=bKMfsPEK6WdWfiPyWPUxCqcLo4tq6eOwyaf910TOwBk,1713
15
- nucliadb_utils/settings.py,sha256=WVL2u_jCkm7Uf6a2njOZetHM_nU0hwDVhLqfH0k5Yi4,7238
16
- nucliadb_utils/signals.py,sha256=5r53hZvZmwgKdri5jHEjuHmiaq5TyusUUvjoq2uliIc,2704
14
+ nucliadb_utils/run.py,sha256=HpAIM8xbR7UpVC2_7xOjB4fYbUVykyPP6yHrv2RD3DI,1707
15
+ nucliadb_utils/settings.py,sha256=fI3AOn30tNvYS_PqoKilVhJN4OppPAGCM6-OUUitO2s,7192
16
+ nucliadb_utils/signals.py,sha256=JRNv2y9zLtBjOANBf7krGfDGfOc9qcoXZ6N1nKWS2FE,2674
17
17
  nucliadb_utils/store.py,sha256=kQ35HemE0v4_Qg6xVqNIJi8vSFAYQtwI3rDtMsNy62Y,890
18
- nucliadb_utils/transaction.py,sha256=CQpsuF-E2omh4gGMxXCn0dv7vL9ctxooWpSgWGbGfBA,7212
19
- nucliadb_utils/utilities.py,sha256=yaZGGsaRLKuHbSM-dI_9LDKM-2N02804TWGeo13zOLg,13708
18
+ nucliadb_utils/transaction.py,sha256=ym9hmPAoIt8xgxjd8JHG14_PelYTqhUOVfUAq_ghJDM,7100
19
+ nucliadb_utils/utilities.py,sha256=E7W9TzvbyJ7_Yenho9CT059E_g4JQOCS02HrGurwNqs,13603
20
20
  nucliadb_utils/audit/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
21
- nucliadb_utils/audit/audit.py,sha256=ruSdsw5TpOHLzgCDhOjzF_nVwY-2fODuiiUVwgJprLc,2818
22
- nucliadb_utils/audit/basic.py,sha256=8_QCqF5PGnIYTc5voJsXpPGZaRaLPshShmrTBipmS-s,3414
23
- nucliadb_utils/audit/stream.py,sha256=W207A1MkLc9RYTj-tSoZHRfxVUephEFqvX0StUzd_FI,12026
21
+ nucliadb_utils/audit/audit.py,sha256=dn5ZnCVQUlCcvdjzaORghbrjk9QgVGrtkfIftq30Bp8,2819
22
+ nucliadb_utils/audit/basic.py,sha256=NViey6mKbCXqRTLDBX2xNTcCg9I-2e4oB2xkekuhDvM,3392
23
+ nucliadb_utils/audit/stream.py,sha256=CSNFrwCT_IeHFStx4q4ImgOQ7v0WzJr4YG6QRzE7YlQ,11952
24
24
  nucliadb_utils/cache/__init__.py,sha256=itSI7dtTwFP55YMX4iK7JzdMHS5CQVUiB1XzQu4UBh8,833
25
25
  nucliadb_utils/cache/exceptions.py,sha256=Zu-O_-0-yctOEgoDGI92gPzWfBMRrpiAyESA62ld6MA,975
26
- nucliadb_utils/cache/nats.py,sha256=4EnzvYK39ViH4Tp90NT0MltJ12E3ryWefAe6xra7Lmc,7073
26
+ nucliadb_utils/cache/nats.py,sha256=-AjCfkFgKVdJUlGR0hT9JDSNkPVFg4S6w9eW-ZIcXPM,7037
27
27
  nucliadb_utils/cache/pubsub.py,sha256=l8i_RwRf7OPzfmPy-gyn66xgYFs5aHidCIjEaU9VOHE,1654
28
28
  nucliadb_utils/cache/settings.py,sha256=WVeHOE6Re5i4k2hUHdFKfkoL4n83v_Z6UPBK6GHYb8g,1059
29
29
  nucliadb_utils/fastapi/__init__.py,sha256=itSI7dtTwFP55YMX4iK7JzdMHS5CQVUiB1XzQu4UBh8,833
30
30
  nucliadb_utils/fastapi/openapi.py,sha256=b0pLuri0QuzQd0elDyOVXM42YYmES_cmT-jEfsQ1G6Y,1737
31
31
  nucliadb_utils/fastapi/run.py,sha256=n6vOX64QqF1I5n4UlKnpm_ZJ24rmwfRGi-J9YMGpZzA,3631
32
- nucliadb_utils/fastapi/versioning.py,sha256=uOVdKl8GzBt8L1YnU5GjBsNeDdFV2yrjjYFEGqUXRgQ,3774
32
+ nucliadb_utils/fastapi/versioning.py,sha256=pwiwuesJW1jElUUI3pI5kcxkigfGBvI64IL6QCBEWS8,3805
33
33
  nucliadb_utils/nuclia_usage/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
34
34
  nucliadb_utils/nuclia_usage/protos/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
35
35
  nucliadb_utils/nuclia_usage/protos/kb_usage_pb2.py,sha256=7jBWh5aFkNOU6rF_rdp-twZONgrJe3ztJdqKvRWcMM4,5934
@@ -39,23 +39,23 @@ nucliadb_utils/nuclia_usage/protos/kb_usage_pb2_grpc.pyi,sha256=6RIsZ2934iodEckf
39
39
  nucliadb_utils/nuclia_usage/utils/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
40
40
  nucliadb_utils/nuclia_usage/utils/kb_usage_report.py,sha256=E1eUSFXBVNzQP9Q2rWj9y3koCO5S7iKwckny_AoLKuk,3870
41
41
  nucliadb_utils/storages/__init__.py,sha256=5Qc8AUWiJv9_JbGCBpAn88AIJhwDlm0OPQpg2ZdRL4U,872
42
- nucliadb_utils/storages/exceptions.py,sha256=n6aBOyurWMo8mXd1XY6Psgno4VfXJ9TRbxCy67c08-g,2417
43
- nucliadb_utils/storages/gcs.py,sha256=HZpyyHrEA4ZsoDMVyK5PRc99FGAmvnvsJpWEq7my1ug,27356
44
- nucliadb_utils/storages/local.py,sha256=nDrmWy1na96AS__hO3TQqsYMHnu0buwnfUGWfxCpWYU,10348
45
- nucliadb_utils/storages/nuclia.py,sha256=UfvRu92eqG1v-PE-UWH2x8KEJFqDqATMmUGFmEuqSSs,2097
46
- nucliadb_utils/storages/s3.py,sha256=_nw9ztAQyri1W2gbT06NHacrxbC0MjA7jYu0U06KfiM,19484
42
+ nucliadb_utils/storages/exceptions.py,sha256=BfJcn0-60Ts2gLHRTxQKD0QuR7L4WDJtIdsUp7zhQ0k,2395
43
+ nucliadb_utils/storages/gcs.py,sha256=KQ9puMOE89CPIA8q8DeCs7qOp0YoB5ZctXPws1h7lbA,27006
44
+ nucliadb_utils/storages/local.py,sha256=GAEzvbmLzEeEJhhIWKa-vX2i9B0qdq6mbHMolpa2Q20,10259
45
+ nucliadb_utils/storages/nuclia.py,sha256=vEv94xAT7QM2g80S25QyrOw2pzvP2BAX-ADgZLtuCVc,2097
46
+ nucliadb_utils/storages/s3.py,sha256=ABzS9X3fj7SUq-3cLvnKEClngb8hcPyKNSfxubMpyCo,19256
47
47
  nucliadb_utils/storages/settings.py,sha256=ugCPy1zxBOmA2KosT-4tsjpvP002kg5iQyi42yCGCJA,1285
48
- nucliadb_utils/storages/storage.py,sha256=KJ5VDYoZuRmiCFwfLj__tDOHIJWyQAMi-sOXCMoJv9w,20831
48
+ nucliadb_utils/storages/storage.py,sha256=SWeQv6136ruj7TvCPQR6WkG458IDEz2fzQQjkDRRReQ,20533
49
49
  nucliadb_utils/tests/__init__.py,sha256=Oo9CAE7B0eW5VHn8sHd6o30SQzOWUhktLPRXdlDOleA,1456
50
- nucliadb_utils/tests/asyncbenchmark.py,sha256=6VP_G0BGNpmFGa4pwmsnGxYhj-h_fABBbX_RVZTEfJo,10697
50
+ nucliadb_utils/tests/asyncbenchmark.py,sha256=x4be2IwCawle9zWgMOJkmwoUwk5p1tv7cLQGmybkEOg,10587
51
51
  nucliadb_utils/tests/fixtures.py,sha256=j58fTvoWZClC52LX7QOvLXX9DS5QbytSnRp0F4nGzN8,1671
52
- nucliadb_utils/tests/gcs.py,sha256=DR6K7s5cH3TAokHbyaUFVNnylKZf3GfiefdEv9s2rpo,3066
52
+ nucliadb_utils/tests/gcs.py,sha256=Ii8BCHUAAxFIzX67pKTRFRgbqv3FJ6DrPAdAx2Xod1Y,3036
53
53
  nucliadb_utils/tests/indexing.py,sha256=YW2QhkhO9Q_8A4kKWJaWSvXvyQ_AiAwY1VylcfVQFxk,1513
54
54
  nucliadb_utils/tests/local.py,sha256=c3gZJJWmvOftruJkIQIwB3q_hh3uxEhqGIAVWim1Bbk,1343
55
- nucliadb_utils/tests/nats.py,sha256=0Ow8jRUHIcOJfh-h1lWxA4h52OFgGVoWqRClR4Y1YHo,7735
55
+ nucliadb_utils/tests/nats.py,sha256=Tosonm9A9cusImyji80G4pgdXEHNVPaCLT5TbFK_ra0,7543
56
56
  nucliadb_utils/tests/s3.py,sha256=YB8QqDaBXxyhHonEHmeBbRRDmvB7sTOaKBSi8KBGokg,2330
57
- nucliadb_utils-4.0.3.post586.dist-info/METADATA,sha256=WMmjIxM66s_3YEq4RcknbxUh7nydTrxjhyPAfgzjLFY,2030
58
- nucliadb_utils-4.0.3.post586.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
59
- nucliadb_utils-4.0.3.post586.dist-info/top_level.txt,sha256=fE3vJtALTfgh7bcAWcNhcfXkNPp_eVVpbKK-2IYua3E,15
60
- nucliadb_utils-4.0.3.post586.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
61
- nucliadb_utils-4.0.3.post586.dist-info/RECORD,,
57
+ nucliadb_utils-4.0.3.post589.dist-info/METADATA,sha256=YHbtxvU4f1pk0u4KI5CoM1J2bJxAFD9nPOZ9jI5wc8c,2030
58
+ nucliadb_utils-4.0.3.post589.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
59
+ nucliadb_utils-4.0.3.post589.dist-info/top_level.txt,sha256=fE3vJtALTfgh7bcAWcNhcfXkNPp_eVVpbKK-2IYua3E,15
60
+ nucliadb_utils-4.0.3.post589.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
61
+ nucliadb_utils-4.0.3.post589.dist-info/RECORD,,