1
- """ PGS Catalog pydantic models for data validation
1
+ """PGS Catalog pydantic models for data validation
2
2
3
3
Best way to reuse:
4
4
7
7
* `import pgscatalog.core` and use fully qualified name: `pgscatalog.core.models.CatalogScoreVariant`)
8
8
9
9
"""
10
+
10
11
from functools import cached_property
11
12
from typing import ClassVar , Optional
12
- from typing_extensions import Self
13
+ from typing_extensions import Self , Literal
13
14
14
15
from pydantic import (
15
16
BaseModel ,
@@ -46,7 +47,7 @@ class Allele(BaseModel):
46
47
allele : str
47
48
_valid_snp_bases : ClassVar [frozenset [str ]] = frozenset ({"A" , "C" , "T" , "G" })
48
49
49
- @computed_field
50
+ @computed_field # type: ignore
50
51
@cached_property
51
52
def is_snp (self ) -> bool :
52
53
"""SNPs are the most common type of effect allele in PGS Catalog scoring
@@ -242,23 +243,35 @@ class CatalogScoreVariant(BaseModel):
242
243
)
243
244
244
245
# helpful class attributes (not used by pydantic to instantiate a class)
245
- harmonised_columns : ClassVar [tuple [str ]] = (
246
+ harmonised_columns : ClassVar [
247
+ tuple [Literal ["hm_rsID" ], Literal ["hm_chr" ], Literal ["hm_pos" ]]
248
+ ] = (
246
249
"hm_rsID" ,
247
250
"hm_chr" ,
248
251
"hm_pos" ,
249
252
) # it's OK if (""hm_source", "hm_inferOtherAllele", "hm_match_chr", "hm_match_pos") are missing
250
- complex_columns : ClassVar [tuple [str ]] = (
253
+ complex_columns : ClassVar [
254
+ tuple [
255
+ Literal ["is_haplotype" ], Literal ["is_diplotype" ], Literal ["is_interaction" ]
256
+ ]
257
+ ] = (
251
258
"is_haplotype" ,
252
259
"is_diplotype" ,
253
260
"is_interaction" ,
254
261
)
255
- non_additive_columns : ClassVar [tuple [str ]] = (
262
+ non_additive_columns : ClassVar [
263
+ tuple [
264
+ Literal ["dosage_0_weight" ],
265
+ Literal ["dosage_1_weight" ],
266
+ Literal ["dosage_2_weight" ],
267
+ ]
268
+ ] = (
256
269
"dosage_0_weight" ,
257
270
"dosage_1_weight" ,
258
271
"dosage_2_weight" ,
259
272
)
260
273
261
- @computed_field
274
+ @computed_field # type: ignore
262
275
@cached_property
263
276
def variant_id (self ) -> str :
264
277
"""ID = chr:pos:effect_allele:other_allele"""
@@ -269,7 +282,7 @@ def variant_id(self) -> str:
269
282
]
270
283
)
271
284
272
- @computed_field
285
+ @computed_field # type: ignore
273
286
@cached_property
274
287
def is_harmonised (self ) -> bool :
275
288
# simple check: do any of the harmonised columns have data?
@@ -278,7 +291,7 @@ def is_harmonised(self) -> bool:
278
291
return True
279
292
return False
280
293
281
- @computed_field
294
+ @computed_field # type: ignore
282
295
@cached_property
283
296
def is_complex (self ) -> bool :
284
297
# checking flag fields here, which are defaulted to False
@@ -287,7 +300,7 @@ def is_complex(self) -> bool:
287
300
return True
288
301
return False
289
302
290
- @computed_field
303
+ @computed_field # type: ignore
291
304
@cached_property
292
305
def is_non_additive (self ) -> bool :
293
306
# simple check: do any of the weight dosage columns have data?
@@ -296,7 +309,7 @@ def is_non_additive(self) -> bool:
296
309
return True
297
310
return False
298
311
299
- @computed_field
312
+ @computed_field # type: ignore
300
313
@cached_property
301
314
def effect_type (self ) -> EffectType :
302
315
match (self .is_recessive , self .is_dominant , self .is_non_additive ):
0 commit comments