Skip to content

Commit 80d13f2

Browse files
committed
Merge branch 'dev' into add-graphql-to-navbar
2 parents cf401ae + 78cafc7 commit 80d13f2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+703
-547
lines changed

.github/workflows/lint.yaml

+34-4
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,52 @@ on: push
44
jobs:
55
lint:
66
runs-on: ubuntu-latest
7+
env:
8+
DOCKER_BUILDKIT: 1
9+
BUILDKIT_PROGRESS: plain
10+
CLOUDSDK_CORE_DISABLE_PROMPTS: 1
11+
# used for generating API
12+
SM_DOCKER: samplemetadata:dev
713
defaults:
814
run:
915
shell: bash -eo pipefail -l {0}
10-
1116
steps:
12-
- uses: actions/checkout@v2
17+
- uses: actions/checkout@main
1318

1419
- uses: actions/setup-python@v2
1520
with:
1621
python-version: "3.10"
17-
cache: "pip"
1822

19-
- name: Install packages
23+
- uses: actions/setup-java@v2
24+
with:
25+
distribution: "temurin" # See 'Supported distributions' for available options
26+
java-version: "17"
27+
28+
- name: Setup build env
29+
run: |
30+
set -euxo pipefail
31+
32+
pip install -r requirements-dev.txt
33+
pip install -r requirements.txt
34+
35+
# openapi-generator
36+
wget https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/5.3.0/openapi-generator-cli-5.3.0.jar -O openapi-generator-cli.jar
37+
38+
- name: "build image"
39+
run: |
40+
docker build \
41+
--build-arg SM_ENVIRONMENT=local \
42+
--tag $SM_DOCKER \
43+
-f deploy/api/Dockerfile \
44+
.
45+
46+
- name: Build + install packages
2047
run: |
48+
export OPENAPI_COMMAND="java -jar openapi-generator-cli.jar"
49+
python regenerate_api.py
2150
pip install -r requirements-dev.txt
2251
pip install .
52+
mkdir .mypy_cache
2353
2454
- name: pre-commit
2555
run: pre-commit run --all-files

.pre-commit-config.yaml

+90-84
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,98 @@
11
repos:
2-
- repo: https://github.com/pre-commit/pre-commit-hooks
3-
rev: v4.4.0
4-
hooks:
5-
- id: check-yaml
6-
exclude: '\.*conda/.*'
7-
- id: end-of-file-fixer
8-
- id: trailing-whitespace
9-
exclude: '\.txt$|\.tsv$'
10-
- id: check-case-conflict
11-
- id: check-merge-conflict
12-
- id: detect-private-key
13-
- id: debug-statements
14-
- id: check-added-large-files
2+
- repo: https://github.com/pre-commit/pre-commit-hooks
3+
rev: v4.4.0
4+
hooks:
5+
- id: check-yaml
6+
exclude: '\.*conda/.*'
7+
- id: end-of-file-fixer
8+
- id: trailing-whitespace
9+
exclude: '\.txt$|\.tsv$'
10+
- id: check-case-conflict
11+
- id: check-merge-conflict
12+
- id: detect-private-key
13+
- id: debug-statements
14+
- id: check-added-large-files
1515

16-
- repo: https://github.com/igorshubovych/markdownlint-cli
17-
rev: v0.33.0
18-
hooks:
19-
- id: markdownlint
20-
args: ["--config", ".markdownlint.json"]
16+
- repo: https://github.com/igorshubovych/markdownlint-cli
17+
rev: v0.33.0
18+
hooks:
19+
- id: markdownlint
20+
args: ["--config", ".markdownlint.json"]
2121

22-
- repo: https://github.com/ambv/black
23-
rev: 23.3.0
24-
hooks:
25-
- id: black
26-
args: [.]
27-
pass_filenames: false
28-
always_run: true
29-
exclude: ^metamist/
22+
- repo: https://github.com/ambv/black
23+
rev: 23.3.0
24+
hooks:
25+
- id: black
26+
args: [.]
27+
pass_filenames: false
28+
always_run: true
29+
exclude: ^metamist/
3030

31-
- repo: https://github.com/PyCQA/flake8
32-
rev: "6.0.0"
33-
hooks:
34-
- id: flake8
35-
additional_dependencies: [flake8-bugbear, flake8-quotes]
31+
- repo: https://github.com/PyCQA/flake8
32+
rev: "6.0.0"
33+
hooks:
34+
- id: flake8
35+
additional_dependencies: [flake8-bugbear, flake8-quotes]
3636

37-
# Using system installation of pylint to support checking python module imports
38-
- repo: local
39-
hooks:
40-
- id: pylint
41-
name: pylint
42-
entry: pylint
43-
language: system
44-
types: [python]
37+
# Using system installation of pylint to support checking python module imports
38+
- repo: local
39+
hooks:
40+
- id: pylint
41+
name: pylint
42+
entry: pylint
43+
language: system
44+
types: [python]
4545

46-
# mypy
47-
- repo: https://github.com/pre-commit/mirrors-mypy
48-
rev: v0.961
49-
hooks:
50-
- id: mypy
51-
args:
52-
[
53-
--pretty,
54-
--show-error-codes,
55-
--no-strict-optional,
56-
--ignore-missing-imports,
57-
--install-types,
58-
--non-interactive,
59-
]
60-
additional_dependencies:
61-
- strawberry-graphql[fastapi]==0.138.1
46+
# mypy
47+
- repo: https://github.com/pre-commit/mirrors-mypy
48+
rev: v1.5.1
49+
hooks:
50+
- id: mypy
51+
args:
52+
[
53+
--pretty,
54+
--show-error-codes,
55+
--no-strict-optional,
56+
--ignore-missing-imports,
57+
--install-types,
58+
--non-interactive,
59+
--show-error-context,
60+
--check-untyped-defs,
61+
--explicit-package-bases,
62+
--disable-error-code,
63+
operator,
64+
]
65+
additional_dependencies:
66+
- strawberry-graphql[fastapi]==0.206.0
67+
- types-PyMySQL==1.1.0.1
6268

63-
- repo: https://github.com/pre-commit/mirrors-prettier
64-
rev: "v3.0.0-alpha.4"
65-
hooks:
66-
- id: prettier
67-
# I'm not exactly sure why it changes behaviour, but
68-
# calling `cd web`, then calling `ls src/**/*.tsx`
69-
# returns different results to `cd web && ls src/**/*.tsx`
70-
# so just include both patterns here
71-
entry: bash -c 'cd web && prettier --write --ignore-unknown --check src/*.{ts,tsx,css} src/**/*.{ts,tsx,css}'
69+
- repo: https://github.com/pre-commit/mirrors-prettier
70+
rev: "v3.0.0-alpha.4"
71+
hooks:
72+
- id: prettier
73+
# I'm not exactly sure why it changes behaviour, but
74+
# calling `cd web`, then calling `ls src/**/*.tsx`
75+
# returns different results to `cd web && ls src/**/*.tsx`
76+
# so just include both patterns here
77+
entry: bash -c 'cd web && prettier --write --ignore-unknown --check src/*.{ts,tsx,css} src/**/*.{ts,tsx,css}'
7278

73-
- repo: https://github.com/pre-commit/mirrors-eslint
74-
rev: "v8.33.0"
75-
hooks:
76-
- id: eslint
77-
entry: bash -c 'cd web && eslint'
78-
files: \.[jt]sx?$
79-
types: [file]
80-
additional_dependencies:
81-
- eslint@^7.32.0
82-
- eslint-config-airbnb@^19.0.4
83-
- eslint-config-airbnb-base@^15.0.0
84-
- eslint-config-airbnb-typescript@^17.0.0
85-
- eslint-config-prettier@^8.6.0
86-
- eslint-plugin-import@^2.26.0
87-
- eslint-plugin-jsx-a11y@^6.6.1
88-
- eslint-plugin-prettier@^4.2.1
89-
- eslint-plugin-react@^7.31.11
90-
- eslint-plugin-react-hooks@^4.6.0
91-
- "@typescript-eslint/eslint-plugin@^5.48.0"
92-
- "@typescript-eslint/parser@^5.48.0"
79+
- repo: https://github.com/pre-commit/mirrors-eslint
80+
rev: "v8.33.0"
81+
hooks:
82+
- id: eslint
83+
entry: bash -c 'cd web && eslint'
84+
files: \.[jt]sx?$
85+
types: [file]
86+
additional_dependencies:
87+
- eslint@^7.32.0
88+
- eslint-config-airbnb@^19.0.4
89+
- eslint-config-airbnb-base@^15.0.0
90+
- eslint-config-airbnb-typescript@^17.0.0
91+
- eslint-config-prettier@^8.6.0
92+
- eslint-plugin-import@^2.26.0
93+
- eslint-plugin-jsx-a11y@^6.6.1
94+
- eslint-plugin-prettier@^4.2.1
95+
- eslint-plugin-react@^7.31.11
96+
- eslint-plugin-react-hooks@^4.6.0
97+
- "@typescript-eslint/eslint-plugin@^5.48.0"
98+
- "@typescript-eslint/parser@^5.48.0"

api/graphql/loaders.py

+27-11
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,26 @@
1313
from db.python.connect import NotFoundError
1414
from db.python.layers import (
1515
AnalysisLayer,
16-
SampleLayer,
1716
AssayLayer,
17+
FamilyLayer,
1818
ParticipantLayer,
19+
SampleLayer,
1920
SequencingGroupLayer,
20-
FamilyLayer,
2121
)
2222
from db.python.tables.analysis import AnalysisFilter
2323
from db.python.tables.assay import AssayFilter
2424
from db.python.tables.project import ProjectPermissionsTable
2525
from db.python.tables.sample import SampleFilter
2626
from db.python.tables.sequencing_group import SequencingGroupFilter
27-
from db.python.utils import ProjectId, GenericFilter
27+
from db.python.utils import GenericFilter, ProjectId
2828
from models.models import (
29-
AssayInternal,
30-
SampleInternal,
31-
SequencingGroupInternal,
3229
AnalysisInternal,
33-
ParticipantInternal,
30+
AssayInternal,
3431
FamilyInternal,
32+
ParticipantInternal,
3533
Project,
34+
SampleInternal,
35+
SequencingGroupInternal,
3636
)
3737

3838

@@ -53,6 +53,8 @@ class LoaderKeys(enum.Enum):
5353
SAMPLES_FOR_PARTICIPANTS = 'samples_for_participants'
5454
SAMPLES_FOR_PROJECTS = 'samples_for_projects'
5555

56+
PHENOTYPES_FOR_PARTICIPANTS = 'phenotypes_for_participants'
57+
5658
PARTICIPANTS_FOR_IDS = 'participants_for_ids'
5759
PARTICIPANTS_FOR_FAMILIES = 'participants_for_families'
5860
PARTICIPANTS_FOR_PROJECTS = 'participants_for_projects'
@@ -291,9 +293,7 @@ async def load_participants_for_ids(
291293
p_by_id = {p.id: p for p in persons}
292294
missing_pids = set(participant_ids) - set(p_by_id.keys())
293295
if missing_pids:
294-
raise NotFoundError(
295-
f'Could not find participants with ids {missing_pids}'
296-
)
296+
raise NotFoundError(f'Could not find participants with ids {missing_pids}')
297297
return [p_by_id.get(p) for p in participant_ids]
298298

299299

@@ -400,7 +400,23 @@ async def load_analyses_for_sequencing_groups(
400400
return by_sg_id
401401

402402

403-
async def get_context(request: Request, connection=get_projectless_db_connection): # pylint: disable=unused-argument
403+
@connected_data_loader(LoaderKeys.PHENOTYPES_FOR_PARTICIPANTS)
404+
async def load_phenotypes_for_participants(
405+
participant_ids: list[int], connection
406+
) -> list[dict]:
407+
"""
408+
Data loader for phenotypes for participants
409+
"""
410+
player = ParticipantLayer(connection)
411+
participant_phenotypes = await player.get_phenotypes_for_participants(
412+
participant_ids=participant_ids
413+
)
414+
return [participant_phenotypes.get(pid, {}) for pid in participant_ids]
415+
416+
417+
async def get_context(
418+
request: Request, connection=get_projectless_db_connection
419+
): # pylint: disable=unused-argument
404420
"""Get loaders / cache context for strawberyy GraphQL"""
405421
mapped_loaders = {k: fn(connection) for k, fn in loaders.items()}
406422
return {

api/graphql/schema.py

+16-17
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,10 @@
1414
from strawberry.fastapi import GraphQLRouter
1515
from strawberry.types import Info
1616

17-
from api.graphql.filters import (
18-
GraphQLFilter,
19-
GraphQLMetaFilter,
20-
)
21-
from api.graphql.loaders import (
22-
get_context,
23-
LoaderKeys,
24-
)
17+
from api.graphql.filters import GraphQLFilter, GraphQLMetaFilter
18+
from api.graphql.loaders import LoaderKeys, get_context
2519
from db.python import enum_tables
26-
from db.python.layers import AnalysisLayer, SequencingGroupLayer, SampleLayer
20+
from db.python.layers import AnalysisLayer, SampleLayer, SequencingGroupLayer
2721
from db.python.layers.assay import AssayLayer
2822
from db.python.layers.family import FamilyLayer
2923
from db.python.tables.analysis import AnalysisFilter
@@ -34,21 +28,19 @@
3428
from db.python.utils import GenericFilter
3529
from models.enums import AnalysisStatus
3630
from models.models import (
37-
SampleInternal,
38-
ParticipantInternal,
39-
Project,
4031
AnalysisInternal,
32+
AssayInternal,
4133
FamilyInternal,
34+
ParticipantInternal,
35+
Project,
36+
SampleInternal,
4237
SequencingGroupInternal,
43-
AssayInternal,
4438
)
4539
from models.models.sample import sample_id_transform_to_raw
46-
from models.utils.sample_id_format import (
47-
sample_id_format,
48-
)
40+
from models.utils.sample_id_format import sample_id_format
4941
from models.utils.sequencing_group_id_format import (
50-
sequencing_group_id_transform_to_raw,
5142
sequencing_group_id_format,
43+
sequencing_group_id_transform_to_raw,
5244
)
5345

5446
enum_methods = {}
@@ -336,6 +328,13 @@ async def samples(
336328
samples = await info.context[LoaderKeys.SAMPLES_FOR_PARTICIPANTS].load(q)
337329
return [GraphQLSample.from_internal(s) for s in samples]
338330

331+
@strawberry.field
332+
async def phenotypes(
333+
self, info: Info, root: 'GraphQLParticipant'
334+
) -> strawberry.scalars.JSON:
335+
loader = info.context[LoaderKeys.PHENOTYPES_FOR_PARTICIPANTS]
336+
return await loader.load(root.id)
337+
339338
@strawberry.field
340339
async def families(
341340
self, info: Info, root: 'GraphQLParticipant'

0 commit comments

Comments
 (0)