Skip to content

Commit e8fec18

Browse files
authored
fix: forbid extra attributes when additionalProperties is set to False (#17)
close #16
1 parent e299e01 commit e8fec18

File tree

3 files changed

+34
-29
lines changed

3 files changed

+34
-29
lines changed

src/ga4gh/va_spec/base/core.py

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@
1010
from typing import Annotated, Literal, TypeVar
1111

1212
from ga4gh.cat_vrs.models import CategoricalVariant
13-
from ga4gh.core.models import Entity, MappableConcept, iriReference
13+
from ga4gh.core.models import (
14+
BaseModelForbidExtra,
15+
Entity,
16+
MappableConcept,
17+
iriReference,
18+
)
1419
from ga4gh.va_spec.base.domain_entities import Condition, Therapeutic
1520
from ga4gh.vrs.models import Allele, MolecularVariation
1621
from pydantic import (
@@ -112,7 +117,9 @@ class ClinicalVariantProposition(_SubjectVariantPropositionBase):
112117
)
113118

114119

115-
class ExperimentalVariantFunctionalImpactProposition(_SubjectVariantPropositionBase):
120+
class ExperimentalVariantFunctionalImpactProposition(
121+
_SubjectVariantPropositionBase, BaseModelForbidExtra
122+
):
116123
"""A Proposition describing the impact of a variant on the function sequence feature
117124
(typically a gene or gene product).
118125
"""
@@ -142,7 +149,7 @@ class DiagnosticPredicate(str, Enum):
142149
EXCLUSIVE = "isDiagnosticExclusionCriterionFor"
143150

144151

145-
class VariantDiagnosticProposition(ClinicalVariantProposition):
152+
class VariantDiagnosticProposition(ClinicalVariantProposition, BaseModelForbidExtra):
146153
"""A Proposition about whether a variant is associated with a disease (a diagnostic
147154
inclusion criterion), or absence of a disease (diagnostic exclusion criterion).
148155
"""
@@ -159,7 +166,7 @@ class VariantDiagnosticProposition(ClinicalVariantProposition):
159166
)
160167

161168

162-
class VariantOncogenicityProposition(ClinicalVariantProposition):
169+
class VariantOncogenicityProposition(ClinicalVariantProposition, BaseModelForbidExtra):
163170
"""A proposition describing the role of a variant in causing a tumor type."""
164171

165172
type: Literal["VariantOncogenicityProposition"] = Field(
@@ -172,7 +179,7 @@ class VariantOncogenicityProposition(ClinicalVariantProposition):
172179
)
173180

174181

175-
class VariantPathogenicityProposition(ClinicalVariantProposition):
182+
class VariantPathogenicityProposition(ClinicalVariantProposition, BaseModelForbidExtra):
176183
"""A proposition describing the role of a variant in causing a heritable condition."""
177184

178185
type: Literal["VariantPathogenicityProposition"] = Field(
@@ -200,7 +207,7 @@ class PrognosticPredicate(str, Enum):
200207
WORSE_OUTCOME = "associatedWithWorseOutcomeFor"
201208

202209

203-
class VariantPrognosticProposition(ClinicalVariantProposition):
210+
class VariantPrognosticProposition(ClinicalVariantProposition, BaseModelForbidExtra):
204211
"""A Proposition about whether a variant is associated with an improved or worse outcome for a disease."""
205212

206213
model_config = ConfigDict(use_enum_values=True)
@@ -222,7 +229,9 @@ class TherapeuticResponsePredicate(str, Enum):
222229
RESISTANCE = "predictsResistanceTo"
223230

224231

225-
class VariantTherapeuticResponseProposition(ClinicalVariantProposition):
232+
class VariantTherapeuticResponseProposition(
233+
ClinicalVariantProposition, BaseModelForbidExtra
234+
):
226235
"""A Proposition about the role of a variant in modulating the response of a neoplasm to drug
227236
administration or other therapeutic procedures.
228237
"""
@@ -262,7 +271,7 @@ class CoreType(str, Enum):
262271
STUDY_GROUP = "StudyGroup"
263272

264273

265-
class Method(Entity):
274+
class Method(Entity, BaseModelForbidExtra):
266275
"""A set of instructions that specify how to achieve some objective."""
267276

268277
type: Literal["Method"] = Field(
@@ -277,7 +286,7 @@ class Method(Entity):
277286
)
278287

279288

280-
class Contribution(Entity):
289+
class Contribution(Entity, BaseModelForbidExtra):
281290
"""An action taken by an agent in contributing to the creation, modification,
282291
assessment, or deprecation of a particular entity (e.g. a Statement, EvidenceLine,
283292
DataSet, Publication, etc.)
@@ -297,7 +306,7 @@ class Contribution(Entity):
297306
date: date | None
298307

299308

300-
class Document(Entity):
309+
class Document(Entity, BaseModelForbidExtra):
301310
"""A collection of information, usually in a text-based or graphic human-readable
302311
form, intended to be read and understood together as a whole.
303312
"""
@@ -331,7 +340,7 @@ class Document(Entity):
331340
)
332341

333342

334-
class Agent(Entity):
343+
class Agent(Entity, BaseModelForbidExtra):
335344
"""An autonomous actor (person, organization, or software agent) that bears some
336345
form of responsibility for an activity taking place, for the existence of an entity,
337346
or for another agent's activity.
@@ -357,7 +366,7 @@ class Direction(str, Enum):
357366
DISPUTES = "disputes"
358367

359368

360-
class DataSet(Entity):
369+
class DataSet(Entity, BaseModelForbidExtra):
361370
"""A collection of related data items or records that are organized together in a
362371
common format or structure, to enable their computational manipulation as a unit.
363372
"""
@@ -385,7 +394,7 @@ class DataSet(Entity):
385394
)
386395

387396

388-
class EvidenceLine(InformationEntity):
397+
class EvidenceLine(InformationEntity, BaseModelForbidExtra):
389398
"""An independent, evidence-based argument that may support or refute the validity
390399
of a specific Proposition. The strength and direction of this argument is based on
391400
an interpretation of one or more pieces of information as evidence for or against
@@ -478,7 +487,7 @@ def validate_has_evidence_items(
478487
return evidence_items
479488

480489

481-
class Statement(InformationEntity):
490+
class Statement(InformationEntity, BaseModelForbidExtra):
482491
"""A claim of purported truth as made by a particular agent, on a particular
483492
occasion. Statements may be used to put forth a possible fact (i.e. a 'Proposition')
484493
as true or false, or to provide a more nuanced assessment of the level of confidence
@@ -516,7 +525,7 @@ class Statement(InformationEntity):
516525
)
517526

518527

519-
class StudyGroup(Entity):
528+
class StudyGroup(Entity, BaseModelForbidExtra):
520529
"""A collection of individuals or specimens from the same taxonomic class, selected
521530
for analysis in a scientific study based on their exhibiting one or more common
522531
characteristics (e.g. species, race, age, gender, disease state, income). May be
@@ -536,7 +545,7 @@ class StudyGroup(Entity):
536545
)
537546

538547

539-
class CohortAlleleFrequencyStudyResult(_StudyResult):
548+
class CohortAlleleFrequencyStudyResult(_StudyResult, BaseModelForbidExtra):
540549
"""A StudyResult that reports measures related to the frequency of an Allele in a cohort"""
541550

542551
type: Literal["CohortAlleleFrequencyStudyResult"] = Field(
@@ -571,7 +580,9 @@ class CohortAlleleFrequencyStudyResult(_StudyResult):
571580
qualityMeasures: dict | None = None
572581

573582

574-
class ExperimentalVariantFunctionalImpactStudyResult(_StudyResult):
583+
class ExperimentalVariantFunctionalImpactStudyResult(
584+
_StudyResult, BaseModelForbidExtra
585+
):
575586
"""A StudyResult that reports a functional impact score from a variant functional assay or study."""
576587

577588
type: Literal["ExperimentalVariantFunctionalImpactStudyResult"] = Field(

src/ga4gh/va_spec/base/domain_entities.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
"""VA Spec Shared Domain Entity Data Structures"""
22

3-
from ga4gh.core.models import Element, MappableConcept
3+
from ga4gh.core.models import BaseModelForbidExtra, Element, MappableConcept
44
from pydantic import Field, RootModel
55

66

7-
class TraitSet(Element):
7+
class TraitSet(Element, BaseModelForbidExtra):
88
"""A set of conditions (diseases, phenotypes, traits) that are co-occurring."""
99

1010
traits: list[MappableConcept] | None = Field(
@@ -27,7 +27,7 @@ class Condition(RootModel):
2727
)
2828

2929

30-
class TherapyGroup(Element):
30+
class TherapyGroup(Element, BaseModelForbidExtra):
3131
"""A group of therapies that are applied together to treat a condition."""
3232

3333
therapies: list[MappableConcept] | None = Field(

tests/validation/test_va_spec_models.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
ExperimentalVariantFunctionalImpactStudyResult,
1212
)
1313
from ga4gh.va_spec.base.core import EvidenceLine, StudyGroup, StudyResult
14+
from pydantic import ValidationError
1415

1516

1617
@pytest.fixture(scope="module")
@@ -37,15 +38,8 @@ def test_agent():
3738
with pytest.raises(ValueError, match='"Agent" object has no field "label"'):
3839
agent.label = "This is an agent"
3940

40-
agent = Agent(
41-
**{ # noqa: PIE804
42-
"name": "Joe",
43-
"label": "Jane",
44-
}
45-
)
46-
47-
with pytest.raises(AttributeError, match="'Agent' object has no attribute 'label'"):
48-
agent.label # noqa: B018
41+
with pytest.raises(ValidationError, match="Extra inputs are not permitted"):
42+
Agent(name="Joe", label="Jane")
4943

5044

5145
def test_caf_study_result(caf):

0 commit comments

Comments
 (0)