-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create teams, datasets, and account aliases when ingesting manifests #41
Changes from all commits
4bacad3
14ec332
5331dd0
4f4bb1b
7908ac2
101882d
6c1a706
1412ddc
e1f21fe
b258e6e
380aafe
1ef6939
8a0c773
c7008bf
5e8d43e
1e602c0
4e89d9c
d77e60f
1879e9a
bb67589
4569770
bef16dc
fcbf587
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
"""make datasets table name column nullable | ||
|
||
Revision ID: 8bf414e0ddfb | ||
Revises: dd50d8e7777e | ||
Create Date: 2024-09-04 11:25:43.062068 | ||
|
||
""" | ||
|
||
from typing import Sequence, Union | ||
|
||
from alembic import op | ||
|
||
# revision identifiers, used by Alembic. | ||
revision: str = "8bf414e0ddfb" | ||
down_revision: Union[str, None] = "dd50d8e7777e" | ||
branch_labels: Union[str, Sequence[str], None] = None | ||
depends_on: Union[str, Sequence[str], None] = None | ||
|
||
|
||
def upgrade() -> None: | ||
op.alter_column("datasets", "dataset_name", nullable=True) | ||
|
||
|
||
def downgrade() -> None: | ||
op.alter_column("datasets", "dataset_name", nullable=False) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# pyright: strict | ||
from __future__ import annotations | ||
|
||
import logging | ||
from pathlib import Path | ||
from typing import overload | ||
|
||
logger = logging.getLogger(__name__) | ||
_cached_root: Path | None = None | ||
|
||
|
||
@overload | ||
def project_root() -> Path: ... | ||
@overload | ||
def project_root(*, require: bool) -> Path | None: ... | ||
def project_root(*, require: bool = True) -> Path | None: | ||
""" | ||
Find the project root directory (when we are running in the project). | ||
|
||
This searches upwards from the **current working directory** to find the | ||
root of the project, which it identifies by the ``pyproject.toml`` file. If | ||
this function is called from a directory that is not within a checkout of | ||
the ``poprox-storage`` repository, it will raise an error. | ||
|
||
Args: | ||
require: | ||
Whether to fail when the project root is not found, or return | ||
``None``. If ``require=False`` this function will stil fail on a | ||
*defective* project root (contains an invalid ``pyproject.toml``). | ||
|
||
Returns: | ||
The full path to the project root directory. If the project root is | ||
not found and ``require=False``, returns ``None``. | ||
""" | ||
global _cached_root | ||
if _cached_root is None: | ||
cwd = Path(".").resolve() | ||
candidate = cwd | ||
logger.debug("searching for project root upwards from %s", candidate) | ||
while not _is_project_root(candidate): | ||
candidate = candidate.parent | ||
if not candidate or str(candidate) == "/": | ||
if require: | ||
msg = f"cannot find project root for {cwd}" | ||
raise RuntimeError(msg) | ||
else: | ||
# don't cache None | ||
return None | ||
|
||
logger.debug("found project root at %s", candidate) | ||
_cached_root = candidate | ||
|
||
return _cached_root | ||
|
||
|
||
def _is_project_root(path: Path) -> bool: | ||
tomlf = path / "pyproject.toml" | ||
if tomlf.exists(): | ||
return True | ||
else: | ||
return False |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,6 +55,21 @@ def fetch_account_by_email(self, email: str) -> Account | None: | |
return accounts[0] | ||
return None | ||
|
||
def store_account(self, account: Account) -> UUID | None: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it worth revising the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not totally sure, but maybe? I left the other method there so this wouldn't break anything, but I do kinda like having methods that accept domain objects instead of accepting the relevant info and creating domain objects internally
karlhigley marked this conversation as resolved.
Show resolved
Hide resolved
|
||
account_tbl = self.tables["accounts"] | ||
query = ( | ||
sqlalchemy.insert(account_tbl) | ||
.values( | ||
account_id=account.account_id, | ||
email=account.email, | ||
source=account.source, | ||
status="new_account", | ||
) | ||
.returning(account_tbl.c.account_id) | ||
) | ||
row = self.conn.execute(query).one_or_none() | ||
return row.account_id | ||
|
||
def store_new_account(self, email: str, source: str) -> Account: | ||
account_tbl = self.tables["accounts"] | ||
query = ( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the implication here that the manifest will contain a list of member UUIDs? Do we like this, or should we have the manifest list emails and then look up the UUIDs as part of ingress here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also -- from a type-safety standpoint (which might be uninteresting FWIW) would this be
list[str]
orlist[UUID]
at this point? I feel like it would belist[str]
but theTeam
class haslist[UUID]
?Not sure we care about that, but it occurred to me that it's worth checking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes!
No! I do not like this but it allowed me to punt on integrating account lookups, which complicate the picture as far as testing goes.
It should be
list[UUID]
but it's actuallylist[str]
. I'll fix this!There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I sit corrected—after checking with a breakpoint it actually is
list[UUID]
here, so the types are correct. The conversion from string to UUID happens when Pydantic turns the manifest JSON into model objects.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat!