Skip to content

Commit f89c530

Browse files
Merge pull request #85 from MatBarba/mbarba/test_vs_core
Script to test ORM vs core + fixes
2 parents 6abdfa7 + 19db50c commit f89c530

File tree

2 files changed

+104
-17
lines changed

2 files changed

+104
-17
lines changed

src/python/ensembl/core/models.py

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,15 @@ class DNAAlignFeatureAttrib(Base):
196196
Index("ditag_value_idx", "value", mysql_length=10),
197197
)
198198

199-
dna_align_feature_attrib_id: Column = Column(INTEGER(10), primary_key=True)
200199
dna_align_feature_id: Column = Column(
201-
INTEGER(10), ForeignKey("dna_align_feature.dna_align_feature_id"), nullable=False, index=True
200+
INTEGER(10),
201+
ForeignKey("dna_align_feature.dna_align_feature_id"),
202+
nullable=False,
203+
index=True,
204+
primary_key=True,
202205
)
203-
attrib_type_id: Column = Column(SMALLINT(5), nullable=False)
204-
value: Column = Column(Text, nullable=False)
206+
attrib_type_id: Column = Column(SMALLINT(5), nullable=False, primary_key=True)
207+
value: Column = Column(String(500), nullable=False, primary_key=True)
205208

206209

207210
class ExternalDb(Base):
@@ -415,10 +418,11 @@ class RNAproductAttrib(Base):
415418
Index("rnaproduct_type_val_idx", "attrib_type_id", "value", mysql_length={"value": 10}),
416419
Index("rnaproduct_value_idx", "value", mysql_length=10),
417420
)
418-
rnaproduct_attrib_id: Column = Column(INTEGER(10), primary_key=True)
419-
rnaproduct_id: Column = Column(ForeignKey("rnaproduct.rnaproduct_id"), nullable=False, index=True)
420-
attrib_type_id: Column = Column(SMALLINT(5), nullable=False)
421-
value: Column = Column(Text, nullable=False)
421+
rnaproduct_id: Column = Column(
422+
ForeignKey("rnaproduct.rnaproduct_id"), nullable=False, index=True, primary_key=True
423+
)
424+
attrib_type_id: Column = Column(SMALLINT(5), nullable=False, primary_key=True)
425+
value: Column = Column(String(500), nullable=False, primary_key=True)
422426

423427

424428
class RnaproductType(Base):
@@ -652,21 +656,22 @@ class GeneAttrib(Base):
652656
Index("gene_attrib_value_idx", "value", mysql_length=10),
653657
)
654658

655-
gene_attrib_id: Column = Column(INTEGER(10), primary_key=True)
656659
gene_id: Column = Column(
657660
INTEGER(10),
658661
ForeignKey("gene.gene_id"),
659662
nullable=False,
660663
index=True,
661664
server_default=text("'0'"),
665+
primary_key=True,
662666
)
663667
attrib_type_id: Column = Column(
664668
SMALLINT(5),
665669
ForeignKey("attrib_type.attrib_type_id"),
666670
nullable=False,
667671
server_default=text("'0'"),
672+
primary_key=True,
668673
)
669-
value: Column = Column(Text, nullable=False)
674+
value: Column = Column(String(500), nullable=False, primary_key=True)
670675

671676

672677
class MarkerMapLocation(Base):
@@ -862,21 +867,22 @@ class TranscriptAttrib(Base):
862867
Index("transcript_attrib_value_idx", "value", mysql_length=10),
863868
)
864869

865-
transcript_attrib_id: Column = Column(INTEGER(10), primary_key=True)
866870
transcript_id: Column = Column(
867871
INTEGER(10),
868872
ForeignKey("transcript.transcript_id"),
869873
nullable=False,
870874
index=True,
871875
server_default=text("'0'"),
876+
primary_key=True,
872877
)
873878
attrib_type_id: Column = Column(
874879
SMALLINT(5),
875880
ForeignKey("attrib_type.attrib_type_id"),
876881
nullable=False,
877882
server_default=text("'0'"),
883+
primary_key=True,
878884
)
879-
value: Column = Column(Text, nullable=False)
885+
value: Column = Column(String(500), nullable=False, primary_key=True)
880886

881887

882888
class TranscriptSupportingFeature(Base):
@@ -904,7 +910,7 @@ class TranscriptSupportingFeature(Base):
904910

905911

906912
class TranslationAttrib(Base):
907-
__tablename__ = ("translation_attrib",)
913+
__tablename__ = "translation_attrib"
908914
__table_args__ = (
909915
Index("translation_attrib_type_val_idx", "attrib_type_id", "value", mysql_length={"value": 10}),
910916
Index(
@@ -918,19 +924,20 @@ class TranslationAttrib(Base):
918924
Index("translation_attrib_value_idx", "value", mysql_length=10),
919925
)
920926

921-
translation_attrib_id: Column = Column(INTEGER(10), primary_key=True)
922927
translation_id: Column = Column(
923928
ForeignKey("translation.translation_id"),
924929
nullable=False,
925930
index=True,
926931
server_default=text("'0'"),
932+
primary_key=True,
927933
)
928934
attrib_type_id: Column = Column(
929935
ForeignKey("attrib_type.attrib_type_id"),
930936
nullable=False,
931937
server_default=text("'0'"),
938+
primary_key=True,
932939
)
933-
value: Column = Column(Text, nullable=False)
940+
value: Column = Column(String(500), nullable=False, primary_key=True)
934941

935942

936943
class UnmappedObject(Base):
@@ -1850,21 +1857,22 @@ class MiscAttrib(Base):
18501857
Index("misc_attrib_value_idx", "value", mysql_length=10),
18511858
)
18521859

1853-
misc_attrib_id: Column = Column(INTEGER(10), primary_key=True)
18541860
misc_feature_id: Column = Column(
18551861
INTEGER(10),
18561862
ForeignKey("misc_feature.misc_feature_id"),
18571863
nullable=False,
18581864
index=True,
18591865
server_default=text("'0'"),
1866+
primary_key=True,
18601867
)
18611868
attrib_type_id: Column = Column(
18621869
SMALLINT(5),
18631870
ForeignKey("attrib_type.attrib_type_id"),
18641871
nullable=False,
18651872
server_default=text("'0'"),
1873+
primary_key=True,
18661874
)
1867-
value: Column = Column(Text, nullable=False)
1875+
value: Column = Column(String(500), nullable=False, primary_key=True)
18681876

18691877

18701878
class OntologyXref(Base):
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# See the NOTICE file distributed with this work for additional information
2+
# regarding copyright ownership.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
"""Check the current ensembl-py core model against a core created from Ensembl SQL.
15+
This script gets one row for each table in the ORM to check that SQLAlchemy can correctly query the table.
16+
If not, it will show the `OperationalError` exception to explain what is wrong in the ORM.
17+
18+
Use this script to check the ORM (and fix it if needed).
19+
"""
20+
21+
import logging
22+
23+
from ensembl.core.models import Base
24+
from ensembl.utils.database import DBConnection
25+
from ensembl.utils.argparse import ArgumentParser
26+
from ensembl.utils.logging import init_logging_with_args
27+
from sqlalchemy import select
28+
from sqlalchemy.exc import NoResultFound, MultipleResultsFound, OperationalError, ProgrammingError
29+
from sqlalchemy.orm import Session
30+
31+
32+
def check_tables(session: Session, only_table: str = "") -> None:
33+
"""Load data from a core using the ORM to check for any discrepancies in the definitions.
34+
35+
Args:
36+
session: SQLAlchemy session.
37+
only_table: Only check this one table instead of all of the tables defined in the ORM.
38+
"""
39+
success = []
40+
errors = []
41+
for table_name, table in Base.metadata.tables.items():
42+
if isinstance(table_name, tuple):
43+
table_name = table_name[0]
44+
if only_table and table_name != only_table:
45+
continue
46+
logging.debug(f"Check table {table_name}")
47+
stmt = select(table)
48+
try:
49+
session.execute(stmt).one()
50+
success.append(table_name)
51+
except (NoResultFound, MultipleResultsFound):
52+
success.append(table_name)
53+
except (OperationalError, ProgrammingError) as err:
54+
# Show the problematic query and continue
55+
logging.warning(f"{table_name}: {err}")
56+
errors.append(table_name)
57+
58+
logging.info(f"{len(success)} tables successfully queried with the ORM")
59+
if errors:
60+
logging.warning(f"{len(errors)} tables failed to be queried with the ORM: {', '.join(errors)}")
61+
else:
62+
logging.info("No errors found")
63+
64+
65+
def main() -> None:
66+
"""Main script entry-point."""
67+
parser = ArgumentParser(description=__doc__)
68+
parser.add_server_arguments(include_database=True, help="Ensembl MySQL core database")
69+
parser.add_argument("--table", type=str, help="Test this one table only")
70+
parser.add_log_arguments(add_log_file=True)
71+
args = parser.parse_args()
72+
init_logging_with_args(args)
73+
dbc = DBConnection(args.url, reflect=False)
74+
with dbc.session_scope() as session:
75+
check_tables(session, only_table=args.table)
76+
77+
78+
if __name__ == "__main__":
79+
main()

0 commit comments

Comments
 (0)