Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4be5fa0
edited microarray and added 2 new endpoints and created efp_proxy end…
rmobmina Nov 18, 2025
a1d09c7
dynamic ORMs
rmobmina Dec 4, 2025
4ab2af3
tried to fix to pass
rmobmina Dec 18, 2025
3dcc24c
Add fail-fast: false to see all Python test results
rmobmina Dec 18, 2025
fb84c4b
Add Sphinx/reST docstrings to dynamic ORM functions
rmobmina Dec 18, 2025
339746a
comment style
rmobmina Dec 18, 2025
ca88f95
Add Q&A reference guide for supervisor meetings
rmobmina Dec 18, 2025
722369c
Add guide explaining schema definition vs database creation
rmobmina Dec 18, 2025
b3cdeae
Add BARUtils validation, Sphinx docstrings, and fix SQL injection
rmobmina Jan 8, 2026
849edea
got rid of inaccurate markdown files
rmobmina Jan 8, 2026
9c31b98
Fix flake8 linting errors
rmobmina Jan 8, 2026
ab5bf91
flake8 ran
rmobmina Jan 8, 2026
d9ce002
Fix dynamic eFP query fallback for CI mirrors
rmobmina Jan 8, 2026
080b0bc
fixed syntax error
rmobmina Jan 8, 2026
645b10c
Refactor EFP services and simplify schema definitions
rmobmina Jan 11, 2026
4bb2bd9
Fix missing length fields for string-type QA columns
rmobmina Jan 11, 2026
fc6eafc
Add DB_HOST environment variable for Docker MySQL connection
rmobmina Jan 11, 2026
b5b37e3
Handle external API errors gracefully in ATTED proxy
rmobmina Jan 11, 2026
4b8b380
Revert proxy changes - external API issue unrelated to EFP work
rmobmina Jan 11, 2026
b800d78
fixed?
rmobmina Jan 11, 2026
6493ee8
fixed comments
rmobmina Jan 22, 2026
c2fd4d2
added new schemas
rmobmina Jan 29, 2026
d8bec41
should pass all checks?
rmobmina Jan 29, 2026
c433ec9
Fix TEXT columns in primary keys causing MySQL error
rmobmina Jan 29, 2026
74aca07
checkcheck
rmobmina Jan 29, 2026
e74ef92
cleaned flake
rmobmina Jan 29, 2026
675e771
passed?
rmobmina Jan 29, 2026
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
18 changes: 7 additions & 11 deletions .flake8
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
[flake8]
max-line-length = 120
extend-ignore = E203, W503, E501
ignore = E501, E203, E121, E123, E126, W503, W504
exclude =
.git,
__pycache__,
docs/source/conf.py,
old,
build,
dist,
venv,
env,
.venv,
./venv-docs,
__pycache__,
api/Archive,
data,
docs,
.env
instance,
output,
venv
1 change: 1 addition & 0 deletions .github/workflows/bar-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ jobs:

runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
python-version: [3.10.18, 3.11, 3.12, 3.13]

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,16 @@ jobs:

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v3

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,6 @@ dmypy.json
output/*
!output
!output/placeholder.txt

# Local sqlite mirrors generated from MySQL dumps
config/databases/*.db
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

[![Website Status](https://img.shields.io/website?url=http%3A%2F%2Fbar.utoronto.ca%2Fapi%2F)](http://bar.utoronto.ca/api/) ![GitHub repo size](https://img.shields.io/github/repo-size/BioAnalyticResource/BAR_API) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Documentation Status](https://readthedocs.org/projects/bar-api/badge/?version=latest)](https://bar-api.readthedocs.io/en/latest/?badge=latest)

This is the official repository for the Bio-Analytic Resource API. The API documentation can be found [here](https://bar-api.readthedocs.io/en/latest/).
This is the official repository for the Bio-Analytic Resource API. The API documentation can be found [here](https://bar-api.readthedocs.io/en/latest/).
1,128 changes: 1,128 additions & 0 deletions api/Archive/efp_tables_structure_sample_data_dump_01_28_25.csv

Large diffs are not rendered by default.

1,128 changes: 1,128 additions & 0 deletions api/Archive/efp_tables_structure_sample_data_dump_01_28_25.sql

Large diffs are not rendered by default.

23,169 changes: 23,169 additions & 0 deletions api/Archive/schema.sql

Large diffs are not rendered by default.

114 changes: 114 additions & 0 deletions api/Archive/structural_diffs_sample_data_dump_01_28_25.csv

Large diffs are not rendered by default.

114 changes: 114 additions & 0 deletions api/Archive/structural_diffs_sample_data_dump_01_28_25.sql

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def create_app():
from api.resources.efp_image import efp_image
from api.resources.fastpheno import fastpheno
from api.resources.llama3 import llama3
from api.resources.efp_proxy import efp_proxy_ns

bar_api.add_namespace(gene_information)
bar_api.add_namespace(rnaseq_gene_expression)
Expand All @@ -78,6 +79,7 @@ def create_app():
bar_api.add_namespace(efp_image)
bar_api.add_namespace(fastpheno)
bar_api.add_namespace(llama3)
bar_api.add_namespace(efp_proxy_ns)
bar_api.init_app(bar_app)
return bar_app

Expand Down
15 changes: 0 additions & 15 deletions api/models/arabidopsis_ecotypes.py

This file was deleted.

12 changes: 0 additions & 12 deletions api/models/arachis.py

This file was deleted.

4 changes: 4 additions & 0 deletions api/models/bar_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Bridge file to maintain backward compatibility with imports
from api.utils.bar_utils import BARUtils

__all__ = ['BARUtils']
12 changes: 0 additions & 12 deletions api/models/cannabis.py

This file was deleted.

12 changes: 0 additions & 12 deletions api/models/dna_damage.py

This file was deleted.

88 changes: 88 additions & 0 deletions api/models/efp_dynamic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""
Dynamic SQLAlchemy model generation for simple eFP databases.

This module provides runtime generation of SQLAlchemy ORM models from schema
definitions, enabling dynamic database access without hardcoded model classes.
"""

from __future__ import annotations

from typing import Dict

from sqlalchemy import Float, Integer, String, Text
from sqlalchemy.dialects.mysql import INTEGER

from api import db
from api.models.efp_schemas import SIMPLE_EFP_DATABASE_SCHEMAS


def _to_sqla_type(column_spec):
"""
Map a column specification dictionary to a SQLAlchemy column type.

Converts the simple type descriptors used in schema definitions to the
appropriate SQLAlchemy type objects for ORM model generation.

:param column_spec: Column specification with 'type', 'length', and 'unsigned' keys
:type column_spec: Dict[str, Any]
:return: SQLAlchemy column type (String, Integer, Float, or Text)
:rtype: sqlalchemy.types.TypeEngine
:raises ValueError: If column type is not one of: string, integer, float, text

Example::

col_spec = {"type": "string", "length": 24}
sqla_type = _to_sqla_type(col_spec) # Returns String(24)
"""
col_type = column_spec.get("type")
if col_type == "string":
return String(column_spec["length"])
if col_type == "integer":
if column_spec.get("unsigned"):
return INTEGER(unsigned=True)
return Integer
if col_type == "float":
return Float
if col_type == "text":
return Text
raise ValueError(f"Unsupported column type: {col_type}")


def _generate_model(bind_key: str, spec) -> db.Model:
"""
Build a concrete SQLAlchemy model class for the given schema specification.

Dynamically creates an ORM model with the specified table name, bind key,
and columns based on the schema definition. The generated model class can
be used like any Flask-SQLAlchemy model.

:param bind_key: Database bind key (e.g., 'cannabis', 'embryo')
:type bind_key: str
:param spec: Database schema specification from SIMPLE_EFP_DATABASE_SCHEMAS
:type spec: Dict[str, Any]
:return: Dynamically generated SQLAlchemy model class
:rtype: db.Model

Example::

schema = SIMPLE_EFP_DATABASE_SCHEMAS['cannabis']
CannabisModel = _generate_model('cannabis', schema)
# Returns class: CannabisSampleData(db.Model)
"""
attrs = {"__bind_key__": bind_key, "__tablename__": spec["table_name"]}

for column in spec["columns"]:
kwargs = {"nullable": column.get("nullable", True)}
if column.get("primary_key"):
kwargs["primary_key"] = True
attrs[column["name"]] = db.mapped_column(_to_sqla_type(column), **kwargs)

class_name = "".join([part.capitalize() for part in bind_key.split("_")]) + "SampleData"
return type(class_name, (db.Model,), attrs)


SIMPLE_EFP_SAMPLE_MODELS: Dict[str, db.Model] = {
db_name: _generate_model(db_name, spec) for db_name, spec in SIMPLE_EFP_DATABASE_SCHEMAS.items()
}

__all__ = ["SIMPLE_EFP_SAMPLE_MODELS"]
Loading