This is an automated email from the ASF dual-hosted git repository.
sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git
The following commit(s) were added to refs/heads/main by this push:
new b049d77 Move the outcome types to the storage types module
b049d77 is described below
commit b049d771cfea8b09461699474f97c0f5b5707499
Author: Sean B. Palmer <[email protected]>
AuthorDate: Mon Jul 21 10:51:12 2025 +0100
Move the outcome types to the storage types module
---
atr/blueprints/admin/admin.py | 2 +-
atr/blueprints/api/api.py | 12 +--
atr/routes/keys.py | 10 +--
atr/storage/__init__.py | 179 +-------------------------------------
atr/storage/types.py | 196 ++++++++++++++++++++++++++++++++++++++----
atr/storage/writers/keys.py | 47 +++++-----
6 files changed, 216 insertions(+), 230 deletions(-)
diff --git a/atr/blueprints/admin/admin.py b/atr/blueprints/admin/admin.py
index e017000..1e9b57b 100644
--- a/atr/blueprints/admin/admin.py
+++ b/atr/blueprints/admin/admin.py
@@ -661,7 +661,7 @@ async def admin_test() -> quart.wrappers.response.Response:
async with storage.write(asf_uid) as write:
wacm = write.as_committee_member("tooling").writer_or_raise()
start = time.perf_counter_ns()
- outcomes: types.KeyOutcomes = await
wacm.keys.ensure_stored(keys_file_text)
+ outcomes: types.Outcomes[types.Key] = await
wacm.keys.ensure_stored(keys_file_text)
end = time.perf_counter_ns()
logging.info(f"Upload of {outcomes.result_count} keys took {end -
start} ns")
for ocr in outcomes.results():
diff --git a/atr/blueprints/api/api.py b/atr/blueprints/api/api.py
index 4a6e743..43712ba 100644
--- a/atr/blueprints/api/api.py
+++ b/atr/blueprints/api/api.py
@@ -305,12 +305,14 @@ async def keys_add(data: models.api.KeysAddArgs) ->
DictResponse:
async with storage.write(asf_uid) as write:
wafm = write.as_foundation_member().writer_or_raise()
- ocr: types.KeyOutcome = await wafm.keys.ensure_stored_one(data.key)
+ ocr: types.Outcome[types.Key] = await
wafm.keys.ensure_stored_one(data.key)
key = ocr.result_or_raise()
for selected_committee_name in selected_committee_names:
wacm =
write.as_committee_member(selected_committee_name).writer_or_raise()
- outcome: types.LinkedCommitteeOutcome = await
wacm.keys.associate_fingerprint(key.key_model.fingerprint)
+ outcome: types.Outcome[types.LinkedCommittee] = await
wacm.keys.associate_fingerprint(
+ key.key_model.fingerprint
+ )
outcome.result_or_raise()
return models.api.KeysAddResults(
@@ -382,20 +384,20 @@ async def keys_upload(data: models.api.KeysUploadArgs) ->
DictResponse:
selected_committee_name = data.committee
async with storage.write(asf_uid) as write:
wacm =
write.as_committee_member(selected_committee_name).writer_or_raise()
- outcomes: types.KeyOutcomes = await
wacm.keys.ensure_associated(filetext)
+ outcomes: types.Outcomes[types.Key] = await
wacm.keys.ensure_associated(filetext)
# TODO: It would be nice to serialise the actual outcomes
api_outcomes = []
for outcome in outcomes.outcomes():
api_outcome: models.api.KeysUploadOutcome | None = None
match outcome:
- case storage.OutcomeResult() as ocr:
+ case types.OutcomeResult() as ocr:
result: types.Key = ocr.result_or_raise()
api_outcome = models.api.KeysUploadResult(
status="success",
key=result.key_model,
)
- case storage.OutcomeException() as oce:
+ case types.OutcomeException() as oce:
# TODO: This branch means we must improve the return type
match oce.exception_or_none():
case types.PublicKeyError() as pke:
diff --git a/atr/routes/keys.py b/atr/routes/keys.py
index 6d52b70..93ad707 100644
--- a/atr/routes/keys.py
+++ b/atr/routes/keys.py
@@ -170,12 +170,12 @@ async def add(session: routes.CommitterSession) -> str:
async with storage.write(asf_uid) as write:
wafm = write.as_foundation_member().writer_or_raise()
- ocr: types.KeyOutcome = await
wafm.keys.ensure_stored_one(key_text)
+ ocr: types.Outcome[types.Key] = await
wafm.keys.ensure_stored_one(key_text)
key = ocr.result_or_raise()
for selected_committee_name in selected_committee_names:
wacm =
write.as_committee_member(selected_committee_name).writer_or_raise()
- outcome: types.LinkedCommitteeOutcome = await
wacm.keys.associate_fingerprint(
+ outcome: types.Outcome[types.LinkedCommittee] = await
wacm.keys.associate_fingerprint(
key.key_model.fingerprint
)
outcome.result_or_raise()
@@ -535,7 +535,7 @@ async def upload(session: routes.CommitterSession) -> str:
)
form = await UploadKeyForm.create_form()
- results: types.KeyOutcomes | None = None
+ results: types.Outcomes[types.Key] | None = None
async def render(
error: str | None = None,
@@ -743,10 +743,10 @@ async def _upload_keys(
asf_uid: str,
filetext: str,
selected_committee: str,
-) -> types.KeyOutcomes:
+) -> types.Outcomes[types.Key]:
async with storage.write(asf_uid) as write:
wacm = write.as_committee_member(selected_committee).writer_or_raise()
- outcomes: types.KeyOutcomes = await
wacm.keys.ensure_associated(filetext)
+ outcomes: types.Outcomes[types.Key] = await
wacm.keys.ensure_associated(filetext)
return outcomes
diff --git a/atr/storage/__init__.py b/atr/storage/__init__.py
index 4c7c704..ab2da74 100644
--- a/atr/storage/__init__.py
+++ b/atr/storage/__init__.py
@@ -18,10 +18,10 @@
from __future__ import annotations
import contextlib
-from typing import TYPE_CHECKING, Final, NoReturn, TypeVar
+from typing import TYPE_CHECKING, Final, TypeVar
if TYPE_CHECKING:
- from collections.abc import AsyncGenerator, Callable, Sequence
+ from collections.abc import AsyncGenerator
import atr.db as db
import atr.storage.writers as writers
@@ -222,181 +222,6 @@ class Write:
return AccessOutcomeWrite(wafm)
-# Outcome
-
-E = TypeVar("E", bound=Exception)
-T = TypeVar("T", bound=object)
-
-
-class OutcomeCore[T]:
- @property
- def ok(self) -> bool:
- raise NotImplementedError("ok is not implemented")
-
- @property
- def name(self) -> str | None:
- raise NotImplementedError("name is not implemented")
-
- def result_or_none(self) -> T | None:
- raise NotImplementedError("result_or_none is not implemented")
-
- def result_or_raise(self, exception_class: type[E] | None = None) -> T:
- raise NotImplementedError("result_or_raise is not implemented")
-
- def exception_or_none(self) -> Exception | None:
- raise NotImplementedError("exception_or_none is not implemented")
-
- def exception_type_or_none(self) -> type[Exception] | None:
- raise NotImplementedError("exception_type_or_none is not implemented")
-
-
-class OutcomeResult[T](OutcomeCore[T]):
- __result: T
-
- def __init__(self, result: T, name: str | None = None):
- self.__result = result
- self.__name = name
-
- @property
- def ok(self) -> bool:
- return True
-
- @property
- def name(self) -> str | None:
- return self.__name
-
- def result_or_none(self) -> T | None:
- return self.__result
-
- def result_or_raise(self, exception_class: type[Exception] | None = None)
-> T:
- return self.__result
-
- def exception_or_none(self) -> Exception | None:
- return None
-
- def exception_type_or_none(self) -> type[Exception] | None:
- return None
-
-
-class OutcomeException[T, E: Exception](OutcomeCore[T]):
- __exception: E
-
- def __init__(self, exception: E, name: str | None = None):
- self.__exception = exception
- self.__name = name
-
- @property
- def ok(self) -> bool:
- return False
-
- @property
- def name(self) -> str | None:
- return self.__name
-
- def result_or_none(self) -> T | None:
- return None
-
- def result_or_raise(self, exception_class: type[Exception] | None = None)
-> NoReturn:
- if exception_class is not None:
- raise exception_class(str(self.__exception)) from self.__exception
- raise self.__exception
-
- def exception_or_none(self) -> Exception | None:
- return self.__exception
-
- def exception_type_or_none(self) -> type[Exception] | None:
- return type(self.__exception)
-
-
-class Outcomes[T]:
- __outcomes: list[OutcomeResult[T] | OutcomeException[T, Exception]]
-
- def __init__(self, *outcomes: OutcomeResult[T] | OutcomeException[T,
Exception]):
- self.__outcomes = list(outcomes)
-
- @property
- def any_ok(self) -> bool:
- return any(outcome.ok for outcome in self.__outcomes)
-
- @property
- def all_ok(self) -> bool:
- return all(outcome.ok for outcome in self.__outcomes)
-
- def append(self, result_or_error: T | Exception, name: str | None = None)
-> None:
- if isinstance(result_or_error, Exception):
- self.__outcomes.append(OutcomeException(result_or_error, name))
- else:
- self.__outcomes.append(OutcomeResult(result_or_error, name))
-
- @property
- def exception_count(self) -> int:
- return sum(1 for outcome in self.__outcomes if isinstance(outcome,
OutcomeException))
-
- def exceptions(self) -> list[Exception]:
- exceptions_list = []
- for outcome in self.__outcomes:
- if isinstance(outcome, OutcomeException):
- exception_or_none = outcome.exception_or_none()
- if exception_or_none is not None:
- exceptions_list.append(exception_or_none)
- return exceptions_list
-
- def extend(self, result_or_error_list: Sequence[T | Exception]) -> None:
- for result_or_error in result_or_error_list:
- self.append(result_or_error)
-
- def named_results(self) -> dict[str, T]:
- named = {}
- for outcome in self.__outcomes:
- if (outcome.name is not None) and outcome.ok:
- named[outcome.name] = outcome.result_or_raise()
- return named
-
- def names(self) -> list[str | None]:
- return [outcome.name for outcome in self.__outcomes if (outcome.name
is not None)]
-
- # def replace(self, a: T, b: T) -> None:
- # for i, outcome in enumerate(self.__outcomes):
- # if isinstance(outcome, OutcomeResult):
- # if outcome.result_or_raise() == a:
- # self.__outcomes[i] = OutcomeResult(b, outcome.name)
-
- def results_or_raise(self, exception_class: type[Exception] | None = None)
-> list[T]:
- return [outcome.result_or_raise(exception_class) for outcome in
self.__outcomes]
-
- def results(self) -> list[T]:
- return [outcome.result_or_raise() for outcome in self.__outcomes if
outcome.ok]
-
- @property
- def result_count(self) -> int:
- return sum(1 for outcome in self.__outcomes if outcome.ok)
-
- def outcomes(self) -> list[OutcomeResult[T] | OutcomeException[T,
Exception]]:
- return self.__outcomes
-
- def result_predicate_count(self, predicate: Callable[[T], bool]) -> int:
- return sum(
- 1
- for outcome in self.__outcomes
- if isinstance(outcome, OutcomeResult) and
predicate(outcome.result_or_raise())
- )
-
- def update_results(self, f: Callable[[T], T]) -> None:
- for i, outcome in enumerate(self.__outcomes):
- if isinstance(outcome, OutcomeResult):
- try:
- result = f(outcome.result_or_raise())
- except Exception as e:
- self.__outcomes[i] = OutcomeException(e, outcome.name)
- else:
- self.__outcomes[i] = OutcomeResult(result, outcome.name)
-
-
-# TODO: Could use + and += instead, or in addition
-def outcomes_merge[T](*outcomes: Outcomes[T]) -> Outcomes[T]:
- return Outcomes(*[outcome for outcome in outcomes for outcome in
outcome.outcomes()])
-
-
# Context managers
diff --git a/atr/storage/types.py b/atr/storage/types.py
index 3237e74..b639474 100644
--- a/atr/storage/types.py
+++ b/atr/storage/types.py
@@ -17,11 +17,183 @@
import dataclasses
import enum
-from typing import Any
+from collections.abc import Callable, Sequence
+from typing import NoReturn, TypeVar
import atr.models.schema as schema
import atr.models.sql as sql
-import atr.storage as storage
+
+# Outcome
+
+E = TypeVar("E", bound=Exception)
+T = TypeVar("T", bound=object)
+
+
+class OutcomeCore[T]:
+ @property
+ def ok(self) -> bool:
+ raise NotImplementedError("ok is not implemented")
+
+ @property
+ def name(self) -> str | None:
+ raise NotImplementedError("name is not implemented")
+
+ def result_or_none(self) -> T | None:
+ raise NotImplementedError("result_or_none is not implemented")
+
+ def result_or_raise(self, exception_class: type[E] | None = None) -> T:
+ raise NotImplementedError("result_or_raise is not implemented")
+
+ def exception_or_none(self) -> Exception | None:
+ raise NotImplementedError("exception_or_none is not implemented")
+
+ def exception_type_or_none(self) -> type[Exception] | None:
+ raise NotImplementedError("exception_type_or_none is not implemented")
+
+
+class OutcomeResult[T](OutcomeCore[T]):
+ __result: T
+
+ def __init__(self, result: T, name: str | None = None):
+ self.__result = result
+ self.__name = name
+
+ @property
+ def ok(self) -> bool:
+ return True
+
+ @property
+ def name(self) -> str | None:
+ return self.__name
+
+ def result_or_none(self) -> T | None:
+ return self.__result
+
+ def result_or_raise(self, exception_class: type[Exception] | None = None)
-> T:
+ return self.__result
+
+ def exception_or_none(self) -> Exception | None:
+ return None
+
+ def exception_type_or_none(self) -> type[Exception] | None:
+ return None
+
+
+class OutcomeException[T, E: Exception](OutcomeCore[T]):
+ __exception: E
+
+ def __init__(self, exception: E, name: str | None = None):
+ self.__exception = exception
+ self.__name = name
+
+ @property
+ def ok(self) -> bool:
+ return False
+
+ @property
+ def name(self) -> str | None:
+ return self.__name
+
+ def result_or_none(self) -> T | None:
+ return None
+
+ def result_or_raise(self, exception_class: type[Exception] | None = None)
-> NoReturn:
+ if exception_class is not None:
+ raise exception_class(str(self.__exception)) from self.__exception
+ raise self.__exception
+
+ def exception_or_none(self) -> Exception | None:
+ return self.__exception
+
+ def exception_type_or_none(self) -> type[Exception] | None:
+ return type(self.__exception)
+
+
+class Outcomes[T]:
+ __outcomes: list[OutcomeResult[T] | OutcomeException[T, Exception]]
+
+ def __init__(self, *outcomes: OutcomeResult[T] | OutcomeException[T,
Exception]):
+ self.__outcomes = list(outcomes)
+
+ @property
+ def any_ok(self) -> bool:
+ return any(outcome.ok for outcome in self.__outcomes)
+
+ @property
+ def all_ok(self) -> bool:
+ return all(outcome.ok for outcome in self.__outcomes)
+
+ def append(self, result_or_error: T | Exception, name: str | None = None)
-> None:
+ if isinstance(result_or_error, Exception):
+ self.__outcomes.append(OutcomeException(result_or_error, name))
+ else:
+ self.__outcomes.append(OutcomeResult(result_or_error, name))
+
+ @property
+ def exception_count(self) -> int:
+ return sum(1 for outcome in self.__outcomes if isinstance(outcome,
OutcomeException))
+
+ def exceptions(self) -> list[Exception]:
+ exceptions_list = []
+ for outcome in self.__outcomes:
+ if isinstance(outcome, OutcomeException):
+ exception_or_none = outcome.exception_or_none()
+ if exception_or_none is not None:
+ exceptions_list.append(exception_or_none)
+ return exceptions_list
+
+ def extend(self, result_or_error_list: Sequence[T | Exception]) -> None:
+ for result_or_error in result_or_error_list:
+ self.append(result_or_error)
+
+ def named_results(self) -> dict[str, T]:
+ named = {}
+ for outcome in self.__outcomes:
+ if (outcome.name is not None) and outcome.ok:
+ named[outcome.name] = outcome.result_or_raise()
+ return named
+
+ def names(self) -> list[str | None]:
+ return [outcome.name for outcome in self.__outcomes if (outcome.name
is not None)]
+
+ # def replace(self, a: T, b: T) -> None:
+ # for i, outcome in enumerate(self.__outcomes):
+ # if isinstance(outcome, OutcomeResult):
+ # if outcome.result_or_raise() == a:
+ # self.__outcomes[i] = OutcomeResult(b, outcome.name)
+
+ def results_or_raise(self, exception_class: type[Exception] | None = None)
-> list[T]:
+ return [outcome.result_or_raise(exception_class) for outcome in
self.__outcomes]
+
+ def results(self) -> list[T]:
+ return [outcome.result_or_raise() for outcome in self.__outcomes if
outcome.ok]
+
+ @property
+ def result_count(self) -> int:
+ return sum(1 for outcome in self.__outcomes if outcome.ok)
+
+ def outcomes(self) -> list[OutcomeResult[T] | OutcomeException[T,
Exception]]:
+ return self.__outcomes
+
+ def result_predicate_count(self, predicate: Callable[[T], bool]) -> int:
+ return sum(
+ 1
+ for outcome in self.__outcomes
+ if isinstance(outcome, OutcomeResult) and
predicate(outcome.result_or_raise())
+ )
+
+ def update_results(self, f: Callable[[T], T]) -> None:
+ for i, outcome in enumerate(self.__outcomes):
+ if isinstance(outcome, OutcomeResult):
+ try:
+ result = f(outcome.result_or_raise())
+ except Exception as e:
+ self.__outcomes[i] = OutcomeException(e, outcome.name)
+ else:
+ self.__outcomes[i] = OutcomeResult(result, outcome.name)
+
+
+type Outcome[T] = OutcomeResult[T] | OutcomeException[T, Exception]
class KeyStatus(enum.Flag):
@@ -36,14 +208,10 @@ class Key(schema.Strict):
key_model: sql.PublicSigningKey
-# OutcomeStr = storage.OutcomeResult[str] | storage.OutcomeException[str,
Exception]
-
-
@dataclasses.dataclass
class LinkedCommittee:
name: str
- # TODO: Move Outcome here
- autogenerated_keys_file: Any
+ autogenerated_keys_file: Outcome[str]
class PublicKeyError(Exception):
@@ -63,14 +231,6 @@ class PublicKeyError(Exception):
return self.__original_error
-type KeyOutcomeResult = storage.OutcomeResult[Key]
-type KeyOutcomeException = storage.OutcomeException[Key, Exception]
-type KeyOutcome = KeyOutcomeResult | KeyOutcomeException
-
-type KeyOutcomes = storage.Outcomes[Key]
-
-type LinkedCommitteeOutcomeResult = storage.OutcomeResult[LinkedCommittee]
-type LinkedCommitteeOutcomeException =
storage.OutcomeException[LinkedCommittee, Exception]
-type LinkedCommitteeOutcome = LinkedCommitteeOutcomeResult |
LinkedCommitteeOutcomeException
-
-type LinkedCommitteeOutcomes = storage.Outcomes[LinkedCommittee]
+# TODO: Could use + and += instead, or in addition
+def outcomes_merge[T](*outcomes: Outcomes[T]) -> Outcomes[T]:
+ return Outcomes(*[outcome for outcome in outcomes for outcome in
outcome.outcomes()])
diff --git a/atr/storage/writers/keys.py b/atr/storage/writers/keys.py
index c9acbf5..2794c94 100644
--- a/atr/storage/writers/keys.py
+++ b/atr/storage/writers/keys.py
@@ -85,7 +85,7 @@ class FoundationMember:
self.__key_block_models_cache = {}
@performance_async
- async def ensure_stored_one(self, key_file_text: str) -> types.KeyOutcome:
+ async def ensure_stored_one(self, key_file_text: str) ->
types.Outcome[types.Key]:
return await self.__ensure_one(key_file_text, associate=False)
@performance
@@ -124,7 +124,7 @@ class FoundationMember:
async def __database_add_model(
self,
key: types.Key,
- ) -> storage.OutcomeResult[types.Key]:
+ ) -> types.Outcome[types.Key]:
via = sql.validate_instrumented_attribute
await self.__data.begin_immediate()
@@ -143,22 +143,22 @@ class FoundationMember:
await self.__data.commit()
# TODO: PARSED now acts as "ALREADY_ADDED"
- return
storage.OutcomeResult(types.Key(status=types.KeyStatus.INSERTED,
key_model=key.key_model))
+ return types.OutcomeResult(types.Key(status=types.KeyStatus.INSERTED,
key_model=key.key_model))
@performance_async
- async def __ensure_one(self, key_file_text: str, associate: bool = True)
-> types.KeyOutcome:
+ async def __ensure_one(self, key_file_text: str, associate: bool = True)
-> types.Outcome[types.Key]:
try:
key_blocks = util.parse_key_blocks(key_file_text)
except Exception as e:
- return storage.OutcomeException(e)
+ return types.OutcomeException(e)
if len(key_blocks) != 1:
- return storage.OutcomeException(ValueError("Expected one key
block, got none or multiple"))
+ return types.OutcomeException(ValueError("Expected one key block,
got none or multiple"))
key_block = key_blocks[0]
try:
ldap_data = await util.email_to_uid_map()
key = await asyncio.to_thread(self.__block_model, key_block,
ldap_data)
except Exception as e:
- return storage.OutcomeException(e)
+ return types.OutcomeException(e)
outcome = await self.__database_add_model(key)
return outcome
@@ -245,7 +245,7 @@ class CommitteeMember(CommitteeParticipant):
self.__committee_name = committee_name
@performance_async
- async def associate_fingerprint(self, fingerprint: str) ->
types.LinkedCommitteeOutcome:
+ async def associate_fingerprint(self, fingerprint: str) ->
types.Outcome[types.LinkedCommittee]:
via = sql.validate_instrumented_attribute
link_values = [{"committee_name": self.__committee_name,
"key_fingerprint": fingerprint}]
try:
@@ -261,12 +261,12 @@ class CommitteeMember(CommitteeParticipant):
pass
await self.__data.commit()
except Exception as e:
- return storage.OutcomeException(e)
+ return types.OutcomeException(e)
try:
autogenerated_outcome = await self.__autogenerate_keys_file()
except Exception as e:
- return storage.OutcomeException(e)
- return storage.OutcomeResult(
+ return types.OutcomeException(e)
+ return types.OutcomeResult(
types.LinkedCommittee(
name=self.__committee_name,
autogenerated_keys_file=autogenerated_outcome,
@@ -280,18 +280,17 @@ class CommitteeMember(CommitteeParticipant):
)
@performance_async
- async def ensure_associated(self, keys_file_text: str) ->
storage.Outcomes[types.Key]:
+ async def ensure_associated(self, keys_file_text: str) ->
types.Outcomes[types.Key]:
# TODO: Autogenerate KEYS file
return await self.__ensure(keys_file_text, associate=True)
@performance_async
- async def ensure_stored(self, keys_file_text: str) ->
storage.Outcomes[types.Key]:
+ async def ensure_stored(self, keys_file_text: str) ->
types.Outcomes[types.Key]:
return await self.__ensure(keys_file_text, associate=False)
- # TODO: Outcome[str]
async def __autogenerate_keys_file(
self,
- ) -> storage.OutcomeResult[str] | storage.OutcomeException[str, Exception]:
+ ) -> types.Outcome[str]:
base_downloads_dir = util.get_downloads_dir()
committee = await self.committee()
@@ -309,12 +308,12 @@ class CommitteeMember(CommitteeParticipant):
await asyncio.to_thread(committee_keys_path.write_text,
full_keys_file_content, encoding="utf-8")
except OSError as e:
error_msg = f"Failed to write KEYS file for committee
{self.__committee_name}: {e}"
- return storage.OutcomeException(storage.AccessError(error_msg))
+ return types.OutcomeException(storage.AccessError(error_msg))
except Exception as e:
error_msg = f"An unexpected error occurred writing KEYS for
committee {self.__committee_name}: {e}"
logging.exception(e)
- return storage.OutcomeException(storage.AccessError(error_msg))
- return storage.OutcomeResult(str(committee_keys_path))
+ return types.OutcomeException(storage.AccessError(error_msg))
+ return types.OutcomeResult(str(committee_keys_path))
@performance
def __block_models(self, key_block: str, ldap_data: dict[str, str]) ->
list[types.Key | Exception]:
@@ -343,8 +342,8 @@ class CommitteeMember(CommitteeParticipant):
@performance_async
async def __database_add_models(
- self, outcomes: storage.Outcomes[types.Key], associate: bool = True
- ) -> storage.Outcomes[types.Key]:
+ self, outcomes: types.Outcomes[types.Key], associate: bool = True
+ ) -> types.Outcomes[types.Key]:
# Try to upsert all models and link to the committee in one transaction
try:
outcomes = await self.__database_add_models_core(outcomes,
associate=associate)
@@ -364,9 +363,9 @@ class CommitteeMember(CommitteeParticipant):
@performance_async
async def __database_add_models_core(
self,
- outcomes: storage.Outcomes[types.Key],
+ outcomes: types.Outcomes[types.Key],
associate: bool = True,
- ) -> storage.Outcomes[types.Key]:
+ ) -> types.Outcomes[types.Key]:
via = sql.validate_instrumented_attribute
key_list = outcomes.results()
@@ -425,8 +424,8 @@ class CommitteeMember(CommitteeParticipant):
return outcomes
@performance_async
- async def __ensure(self, keys_file_text: str, associate: bool = True) ->
storage.Outcomes[types.Key]:
- outcomes = storage.Outcomes[types.Key]()
+ async def __ensure(self, keys_file_text: str, associate: bool = True) ->
types.Outcomes[types.Key]:
+ outcomes = types.Outcomes[types.Key]()
try:
ldap_data = await util.email_to_uid_map()
key_blocks = util.parse_key_blocks(keys_file_text)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]