-
Notifications
You must be signed in to change notification settings - Fork 29
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
feat!: update gks-common / vrs models #453
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
96211e7
feat!: update gks-common / vrs models
korikuzma ec8fd40
pull in latest changes
korikuzma b5f4505
create base classes for stmt + study result
korikuzma 5ebca83
rm unnecessary abc + dont make class private
korikuzma 7d79121
add schema tests + fix extension required props
korikuzma 0c3d349
more tests for descriptions
korikuzma 9cab291
Revert "rm unnecessary abc + dont make class private"
korikuzma 8632858
Merge branch 'main' into issue-452
korikuzma 9123010
remove duplicate test module
korikuzma 9e78fca
ruff cleanup
korikuzma f870cce
Merge branch 'main' into issue-452
korikuzma File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule vrs
updated
96 files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
"""Test that VRS-Python Pydantic models match VRS and GKS-Common schemas""" | ||
|
||
from enum import Enum | ||
import json | ||
from pathlib import Path | ||
|
||
import pytest | ||
from pydantic import BaseModel | ||
|
||
from ga4gh.core import entity_models, domain_models | ||
from ga4gh.vrs import models as vrs_models | ||
|
||
|
||
class GKSSchema(str, Enum): | ||
"""Enum for GKS schema""" | ||
|
||
VRS = "vrs" | ||
CORE_IM = "core-im" | ||
DOMAIN = "domain-entities" | ||
|
||
|
||
class GKSSchemaMapping(BaseModel): | ||
"""Model for representing GKS Schema concrete classes, primitives, and schema""" | ||
|
||
base_classes: set = set() | ||
concrete_classes: set = set() | ||
primitives: set = set() | ||
schema: dict = {} | ||
|
||
|
||
def _update_gks_schema_mapping( | ||
f_path: Path, gks_schema_mapping: GKSSchemaMapping | ||
) -> None: | ||
"""Update ``gks_schema_mapping`` properties | ||
|
||
:param f_path: Path to JSON Schema file | ||
:param gks_schema_mapping: GKS schema mapping to update | ||
""" | ||
with f_path.open() as rf: | ||
cls_def = json.load(rf) | ||
|
||
spec_class = cls_def["title"] | ||
gks_schema_mapping.schema[spec_class] = cls_def | ||
|
||
if "properties" in cls_def: | ||
gks_schema_mapping.concrete_classes.add(spec_class) | ||
elif cls_def.get("type") in {"array", "integer", "string"}: | ||
gks_schema_mapping.primitives.add(spec_class) | ||
else: | ||
gks_schema_mapping.base_classes.add(spec_class) | ||
|
||
|
||
GKS_SCHEMA_MAPPING = {gks: GKSSchemaMapping() for gks in GKSSchema} | ||
SUBMODULES_DIR = Path(__file__).parents[2] / "submodules" / "vrs" | ||
|
||
|
||
# Get vrs classes | ||
vrs_mapping = GKS_SCHEMA_MAPPING[GKSSchema.VRS] | ||
for f in (SUBMODULES_DIR / "schema" / "vrs" / "json").glob("*"): | ||
_update_gks_schema_mapping(f, vrs_mapping) | ||
|
||
|
||
# Get core-im + domain classes | ||
for child in (SUBMODULES_DIR / "submodules" / "gks-common" / "schema").iterdir(): | ||
mapping_key = ( | ||
GKSSchema.DOMAIN if str(child).endswith(GKSSchema.DOMAIN) else GKSSchema.CORE_IM | ||
) | ||
mapping = GKS_SCHEMA_MAPPING[mapping_key] | ||
for f in (child / "json").glob("*"): | ||
_update_gks_schema_mapping(f, mapping) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
("gks_schema", "pydantic_models"), | ||
[ | ||
(GKSSchema.VRS, vrs_models), | ||
(GKSSchema.CORE_IM, entity_models), | ||
(GKSSchema.DOMAIN, domain_models), | ||
], | ||
) | ||
def test_schema_models_in_pydantic(gks_schema, pydantic_models): | ||
"""Ensure that each schema model has corresponding Pydantic model""" | ||
mapping = GKS_SCHEMA_MAPPING[gks_schema] | ||
for schema_model in ( | ||
mapping.base_classes | mapping.concrete_classes | mapping.primitives | ||
): | ||
assert getattr(pydantic_models, schema_model, False), schema_model | ||
|
||
|
||
@pytest.mark.parametrize( | ||
("gks_schema", "pydantic_models"), | ||
[ | ||
(GKSSchema.VRS, vrs_models), | ||
(GKSSchema.CORE_IM, entity_models), | ||
(GKSSchema.DOMAIN, domain_models), | ||
], | ||
) | ||
def test_schema_class_fields(gks_schema, pydantic_models): | ||
"""Check that each schema model properties exist and are required in corresponding | ||
Pydantic model, and validate required properties | ||
""" | ||
mapping = GKS_SCHEMA_MAPPING[gks_schema] | ||
for schema_model in mapping.concrete_classes: | ||
schema_properties = mapping.schema[schema_model]["properties"] | ||
pydantic_model = getattr(pydantic_models, schema_model) | ||
assert set(pydantic_model.model_fields) == set(schema_properties), schema_model | ||
|
||
required_schema_fields = set(mapping.schema[schema_model]["required"]) | ||
|
||
for prop, property_def in schema_properties.items(): | ||
pydantic_model_field_info = pydantic_model.model_fields[prop] | ||
pydantic_field_required = pydantic_model_field_info.is_required() | ||
|
||
if prop in required_schema_fields: | ||
if prop != "type": | ||
assert pydantic_field_required, f"{pydantic_model}.{prop}" | ||
else: | ||
assert not pydantic_field_required, f"{pydantic_model}.{prop}" | ||
|
||
if "description" in property_def: | ||
assert property_def["description"].replace("'", "\"") == pydantic_model_field_info.description.replace("'", "\""), f"{pydantic_model}.{prop}" | ||
else: | ||
assert pydantic_model_field_info.description is None, f"{pydantic_model}.{prop}" | ||
|
||
|
||
def test_ga4gh_keys(): | ||
"""Ensure ga4ghDigest keys defined in schema model exist in corresponding Pydantic model""" | ||
vrs_mapping = GKS_SCHEMA_MAPPING[GKSSchema.VRS] | ||
for vrs_class in vrs_mapping.concrete_classes: | ||
if ( | ||
vrs_mapping.schema[vrs_class].get("ga4ghDigest", {}).get("keys", None) | ||
is None | ||
): | ||
continue | ||
|
||
pydantic_model = getattr(vrs_models, vrs_class) | ||
|
||
try: | ||
pydantic_model_digest_keys = pydantic_model.ga4gh.keys | ||
except AttributeError as e: | ||
raise AttributeError(vrs_class) from e | ||
|
||
assert set(pydantic_model_digest_keys) == set( | ||
vrs_mapping.schema[vrs_class]["ga4ghDigest"]["keys"] | ||
), vrs_class | ||
assert pydantic_model_digest_keys == sorted( | ||
pydantic_model.ga4gh.keys | ||
), vrs_class |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
as a side note, I tried to properly add ruff to vrs-python a few months ago, but the import sort ended up introducing a circular dependency. If it's not doing that anymore, then we could probably get it added in.
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.
@jsstevenson ah, I don't have ruff added to VRS-Python. I noticed this when working in Cat-VRS-Python, which does have ruff installed.