Skip to content
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

Update fastapi & pydantic #429

Merged
merged 2 commits into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ verify_ssl = true
name = "pypi"

[packages]
fastapi = "==0.99.1"
fastapi = "==0.101.1"
uvicorn = {version = "==0.23.2", extras = ["standard"]}
jsonlines = "==3.1.0"
cacheout = "==0.14.1"
Expand Down
570 changes: 388 additions & 182 deletions Pipfile.lock

Large diffs are not rendered by default.

8 changes: 1 addition & 7 deletions src/common/product_models/heatmap_common_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,6 @@ class Cell(BaseModel):
description="The value of the heatmap at this cell."
)

class Config:
smart_union = True


class HeatMapRow(BaseModel):
"""
Expand All @@ -133,7 +130,7 @@ class HeatMapRow(BaseModel):
description="The cells in the row of the heatmap in render order."
)
meta: dict[str, str] | None = Field(
examples=[{"growth_media": "Spizizen minimal media + 0.5mM biotin"}],
example={"growth_media": "Spizizen minimal media + 0.5mM biotin"},
description="Arbitrary metadata about the data in the row"
)

Expand Down Expand Up @@ -178,9 +175,6 @@ class CellDetailEntry(BaseModel):
description="The value of the cell entry."
)

class Config:
smart_union = True


class CellDetail(BaseModel):
"""
Expand Down
4 changes: 2 additions & 2 deletions src/common/storage/init_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

def _get_config() -> CollectionsServiceConfig:
parser = argparse.ArgumentParser(
description="Set up ArangoDB collection sharding for the KBase collectins service."
description="Set up ArangoDB collection sharding for the KBase collections service."
)
parser.add_argument(
'-c', '--config', required=True, type=str,
Expand All @@ -33,7 +33,7 @@ def _get_config() -> CollectionsServiceConfig:
"-s", "--skip-database-creation", action="store_true",
help="Don't create the database. This is necessary if the credentials in the config "
+ "file don't have permissions for the _system database; however the target database "
+ "must alreaady exist."
+ "must already exist."
)
args = parser.parse_args()
with open(args.config, 'rb') as cfgfile:
Expand Down
19 changes: 9 additions & 10 deletions src/service/data_products/common_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""

from fastapi import APIRouter, Query
from pydantic import BaseModel, validator, Field
from pydantic import field_validator, ConfigDict, BaseModel, Field
from src.common.product_models.common_models import SubsetProcessStates
from src.common.storage import collection_and_field_names as names
from src.service import models
Expand Down Expand Up @@ -58,14 +58,13 @@ class DataProductSpec(BaseModel):
in the `tags` argument.
"""

@validator("router")
@field_validator("router")
@classmethod
def _check_router_tags(cls, v): # @NoSelf
if not v.tags:
raise ValueError("router must have at least one tag")
return v

class Config:
arbitrary_types_allowed = True
model_config = ConfigDict(arbitrary_types_allowed=True)


class DataProductMissingIDs(SubsetProcessStates):
Expand All @@ -82,10 +81,10 @@ class DataProductMissingIDs(SubsetProcessStates):
)


QUERY_VALIDATOR_LOAD_VERSION_OVERRIDE = Annotated[str | None, Query(
QUERY_VALIDATOR_LOAD_VERSION_OVERRIDE = Annotated[str, Query(
Comment on lines -85 to +84
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For Path and Query components, adding None to the type annotation causes the input restrictions not to be shown in the OpenAPI documentation. Not sure why

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it happen with a Optional[Str] Or Union[] ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't try because the current way works well enough for now and I don't want to go back to the Bad Old Ways of type hints

min_length=models.LENGTH_MIN_LOAD_VERSION,
max_length=models.LENGTH_MAX_LOAD_VERSION,
regex=models.REGEX_LOAD_VERSION,
pattern=models.REGEX_LOAD_VERSION,
example=models.FIELD_LOAD_VERSION_EXAMPLE,
description=models.FIELD_LOAD_VERSION_DESCRIPTION + ". This will override the collection's "
+ "load version. Service administrator privileges are required."
Expand Down Expand Up @@ -114,7 +113,7 @@ class DataProductMissingIDs(SubsetProcessStates):
)]


QUERY_VALIDATOR_MATCH_ID = Annotated[str | None, Query(
QUERY_VALIDATOR_MATCH_ID = Annotated[str, Query(
description="A match ID to set the view to the match rather than "
+ "the entire collection. Authentication is required. If a match ID is "
# matches are against a specific load version, so...
Expand All @@ -136,7 +135,7 @@ class DataProductMissingIDs(SubsetProcessStates):
)]


QUERY_VALIDATOR_SELECTION_ID = Annotated[str | None, Query(
QUERY_VALIDATOR_SELECTION_ID = Annotated[str, Query(
description="A selection ID to set the view to the selection rather than the entire "
+ "collection. If a selection ID is set, any load version override is ignored. "
+ "If a selection filter and a match filter are provided, they are ANDed together. "
Expand All @@ -161,7 +160,7 @@ class DataProductMissingIDs(SubsetProcessStates):
)]


QUERY_VALIDATOR_SORT_ON = Annotated[str | None, Query(
QUERY_VALIDATOR_SORT_ON = Annotated[str, Query(
example=names.FLD_KBASE_ID,
description="The field to sort on."
)]
Expand Down
6 changes: 3 additions & 3 deletions src/service/data_products/heatmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ async def get_heatmap(
self,
r: Request,
collection_id: Annotated[str, PATH_VALIDATOR_COLLECTION_ID],
start_after: str | None = Query(
start_after: str = Query(
default=None,
example="GB_GCA_000006155.2",
description=f"The `{names.FLD_KBASE_ID}` to start after when listing data. This "
Expand Down Expand Up @@ -290,8 +290,8 @@ async def get_missing_ids(
self,
r: Request,
collection_id: Annotated[str, PATH_VALIDATOR_COLLECTION_ID],
match_id: Annotated[str | None, Query(description="A match ID.")] = None,
selection_id: Annotated[str | None, Query(description="A selection ID.")] = None,
match_id: Annotated[str, Query(description="A match ID.")] = None,
selection_id: Annotated[str, Query(description="A selection ID.")] = None,
user: kb_auth.KBaseUser = Depends(_OPT_AUTH),
) -> DataProductMissingIDs:
return await get_missing_ids(
Expand Down
8 changes: 4 additions & 4 deletions src/service/data_products/samples.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,15 +298,15 @@ async def get_sample_locations(
+ "time and a lot of memory. In the future it may be disallowed for collections with "
+ "large numbers of samples."
)] = False,
match_id: Annotated[str | None, Query(
match_id: Annotated[str, Query(
description="A match ID to set the view to the match rather than "
+ "the entire collection. Authentication is required. If a match ID is "
# matches are against a specific load version, so...
+ "set, any load version override is ignored. "
+ "If a selection filter and a match filter are provided, they are ANDed together. "
)] = None,
# TODO FEATURE support a choice of AND or OR for matches & selections
selection_id: Annotated[str | None, Query(
selection_id: Annotated[str, Query(
description="A selection ID to set the view to the selection rather than the entire "
+ "collection. If a selection ID is set, any load version override is ignored. "
+ "If a selection filter and a match filter are provided, they are ANDed together. "
Expand Down Expand Up @@ -492,8 +492,8 @@ async def get_samples_by_id(
async def get_missing_ids(
r: Request,
collection_id: Annotated[str, PATH_VALIDATOR_COLLECTION_ID],
match_id: Annotated[str | None, Query(description="A match ID.")] = None,
selection_id: Annotated[str | None, Query(description="A selection ID.")] = None,
match_id: Annotated[str, Query(description="A match ID.")] = None,
selection_id: Annotated[str, Query(description="A selection ID.")] = None,
user: kb_auth.KBaseUser = Depends(_OPT_AUTH),
) -> common_models.DataProductMissingIDs:
return await _get_missing_ids(
Expand Down
6 changes: 3 additions & 3 deletions src/service/data_products/taxa_count.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class TaxaCounts(SubsetProcessStates):
"""
The taxa counts data set.
"""
data: list[TaxaCount] | None
data: list[TaxaCount] | None = None


_FLD_COL_ID = "colid"
Expand Down Expand Up @@ -193,13 +193,13 @@ async def get_taxa_counts(
example="phylum",
description="The taxonomic rank at which to return results"
),
match_id: str | None = Query(
match_id: str = Query(
default = None,
description="A match ID to include the match count in the taxa count data. "
+ "Authentication is required. "
# matches are against a specific load version, so...
+ "Note that if a match ID is set, any load version override is ignored."),
selection_id: str | None = Query(
selection_id: str = Query(
default = None,
description="A selection ID to include the selection count in the taxa count data. "
+ "Note that if a selection ID is set, any load version override is ignored."),
Expand Down
14 changes: 6 additions & 8 deletions src/service/matchers/lineage_matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import logging

from pydantic import BaseModel, Field, Extra
from pydantic import ConfigDict, BaseModel, Field
from typing import Any

from src.common.constants import GTDB_UNCLASSIFIED_PREFIX
Expand Down Expand Up @@ -32,10 +32,9 @@ class GTDBLineageMatcherCollectionParameters(BaseModel):
description="The GTDB version of the collection in which the matcher is installed. " +
"Input data to the matcher must match this version of GTDB or the match will " +
"abort.",
regex=r"^\d{2,4}\.\d{1,2}$" # giving a little room for expansion
pattern=r"^\d{2,4}\.\d{1,2}$" # giving a little room for expansion
)
class Config:
extra = Extra.forbid
model_config = ConfigDict(extra="forbid")


class GTDBLineageMatcherUserParameters(BaseModel):
Expand All @@ -44,8 +43,7 @@ class GTDBLineageMatcherUserParameters(BaseModel):
example=GTDBRank.SPECIES,
description="A rank in the the GTDB lineage."
)
class Config:
extra = Extra.forbid
model_config = ConfigDict(extra="forbid")


async def _process_match(
Expand Down Expand Up @@ -153,6 +151,6 @@ def generate_match_process(
"KBaseSets.AssemblySet",
],
required_data_products=[genome_attributes.ID],
user_parameters=GTDBLineageMatcherUserParameters.schema(),
collection_parameters=GTDBLineageMatcherCollectionParameters.schema()
user_parameters=GTDBLineageMatcherUserParameters.model_json_schema(),
collection_parameters=GTDBLineageMatcherCollectionParameters.model_json_schema()
)
12 changes: 5 additions & 7 deletions src/service/matchers/minhash_homology_matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import asyncio
import logging

from pydantic import BaseModel, Field, Extra, HttpUrl
from pydantic import ConfigDict, BaseModel, Field, HttpUrl

from src.service import data_product_specs
from src.service import models
Expand Down Expand Up @@ -48,8 +48,7 @@ class MinHashHomologyMatcherCollectionParameters(BaseModel):
description="The name of the sketch database in the Assembly Homology Service to match "
+ "against. This parameter is sent to the sketch service."
)
class Config:
extra = Extra.forbid
model_config = ConfigDict(extra="forbid")


class MinHashHomologyMatcherUserParameters(BaseModel):
Expand All @@ -63,8 +62,7 @@ class MinHashHomologyMatcherUserParameters(BaseModel):
)
# TODO HOMOLOGY_MATCHER may want to support more parameters if we switch to a different
# implementation like sourmash
class Config:
extra = Extra.forbid
model_config = ConfigDict(extra="forbid")


async def _get_sketch_service_client(collection_parameters: dict[str, Any]):
Expand Down Expand Up @@ -225,6 +223,6 @@ def generate_match_process(
"KBaseSets.AssemblySet",
],
required_data_products=[genome_attributes.ID],
user_parameters=MinHashHomologyMatcherUserParameters.schema(),
collection_parameters=MinHashHomologyMatcherCollectionParameters.schema()
user_parameters=MinHashHomologyMatcherUserParameters.model_json_schema(),
collection_parameters=MinHashHomologyMatcherCollectionParameters.model_json_schema()
)
Loading