Skip to content

Commit 41f10db

Browse files
authored
Merge pull request #10 from haddocking/codecov
Codecov
2 parents 99d407f + f097e04 commit 41f10db

File tree

18 files changed

+776
-36
lines changed

18 files changed

+776
-36
lines changed

.github/workflows/ci.yml

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,16 @@ on:
66
- main
77
pull_request:
88

9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
913
jobs:
1014
test:
1115
name: test
1216
runs-on: ubuntu-latest
17+
permissions:
18+
id-token: write
1319
steps:
1420
- uses: actions/checkout@v4
1521
- name: Install uv
@@ -19,7 +25,26 @@ jobs:
1925
- name: Install pocl
2026
run: uv pip install pocl-binary-distribution==3.0
2127
- name: Run tests
22-
run: uv run pytest
28+
run: |
29+
uv run pytest --cov --cov-branch --cov-report=xml --junitxml=junit.xml -o junit_family=legacy
30+
echo $? > pytest-exitcode
31+
continue-on-error: true
32+
# Always upload coverage and test results, even if tests fail
33+
- name: Upload coverage reports to Codecov
34+
uses: codecov/codecov-action@v5
35+
with:
36+
use_oidc: true
37+
files: coverage.xml
38+
- uses: codecov/test-results-action@v1
39+
with:
40+
use_oidc: true
41+
files: junit.xml
42+
- name: Fail job if pytest failed
43+
run: |
44+
if [ -f pytest-exitcode ] && [ "$(cat pytest-exitcode)" -ne 0 ]; then
45+
echo "Pytest failed, failing job."
46+
exit 1
47+
fi
2348
build:
2449
name: build
2550
runs-on: ubuntu-latest

.github/workflows/pages.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ permissions:
1414
# Only have one deployment in progress at a time
1515
concurrency:
1616
group: "pages"
17-
cancel-in-progress: false
17+
cancel-in-progress: true
1818

1919
jobs:
2020
build:

CONTRIBUTING.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,12 @@ uv run mkdocs build
8181
# You can preview it with
8282
python3 -m http.server -d site
8383
```
84+
85+
## Contributing to tests
86+
87+
The code coverage and tests results are stored at https://app.codecov.io/gh/haddocking/protein-quest/ .
88+
89+
The search functions of the protein-quest package talk to web services on the Internet.
90+
To have fast tests we use [pytest-recording](https://github.com/kiwicom/pytest-recording) to record and replay HTTP interactions.
91+
See [pytest-recording documentation](https://github.com/kiwicom/pytest-recording) for more details on how to use it.
92+
Like overwrite previous recordings in test/cassettes/**.yaml files with `--record-mode=rewrite`.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
[![Research Software Directory Badge](https://img.shields.io/badge/rsd-00a3e3.svg)](https://www.research-software.nl/software/protein-quest)
66
[![PyPI](https://img.shields.io/pypi/v/protein-quest)](https://pypi.org/project/protein-quest/)
77
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15632658.svg)](https://doi.org/10.5281/zenodo.15632658)
8+
[![codecov](https://codecov.io/gh/haddocking/protein-quest/graph/badge.svg?token=V2MW3WMIR1)](https://codecov.io/gh/haddocking/protein-quest)
89

910
Python package to search/retrieve/filter proteins and protein structures
1011

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ mcp = [
4545
dev = [
4646
"pyrefly>=0.23.1",
4747
"pytest>=8.3.5",
48+
"pytest-asyncio>=1.1.0",
49+
"pytest-cov>=6.2.1",
50+
"pytest-recording>=0.13.4",
4851
"types-aiofiles>=24.1.0.20250326",
4952
"types-tqdm>=4.67.0.20250513",
5053
]

src/protein_quest/pdbe/io.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ def write_structure(structure: gemmi.Structure, path: Path):
4949
path: The file path to write the structure to.
5050
The format depends on the file extension.
5151
Supported extensions are .pdb, .pdb.gz, .cif, .cif.gz.
52+
53+
Raises:
54+
ValueError: If the file extension is not supported.
5255
"""
5356
if path.name.endswith(".pdb"):
5457
body: str = structure.make_pdb_string()
@@ -65,6 +68,9 @@ def write_structure(structure: gemmi.Structure, path: Path):
6568
cif_str = doc.as_string()
6669
with gzip.open(path, "wt") as f:
6770
f.write(cif_str)
71+
else:
72+
msg = f"Unsupported file extension in {path.name}. Supported extensions are .pdb, .pdb.gz, .cif, .cif.gz"
73+
raise ValueError(msg)
6874

6975

7076
def _split_name_and_extension(name: str) -> tuple[str, str]:

tests/alphafold/test_confidence.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from pathlib import Path
2+
3+
import gemmi
4+
import pytest
5+
6+
from protein_quest.alphafold.confidence import (
7+
ConfidenceFilterQuery,
8+
ConfidenceFilterResult,
9+
filter_files_on_confidence,
10+
filter_out_low_confidence_residues,
11+
find_high_confidence_residues,
12+
)
13+
from protein_quest.pdbe.io import nr_residues_in_chain
14+
15+
16+
@pytest.fixture
17+
def sample_pdb_file() -> Path:
18+
return Path(__file__).parent / "AF-A1YPR0-F1-model_v4.pdb"
19+
20+
21+
@pytest.fixture
22+
def sample_pdb(sample_pdb_file: Path) -> gemmi.Structure:
23+
return gemmi.read_structure(str(sample_pdb_file))
24+
25+
26+
def test_find_high_confidence_residues(sample_pdb: gemmi.Structure):
27+
residues = list(find_high_confidence_residues(sample_pdb, 90))
28+
29+
assert len(residues) == 22
30+
31+
32+
def test_filter_out_low_confidence_residues(sample_pdb: gemmi.Structure):
33+
# Make sure we start with >22 residues
34+
assert len(sample_pdb[0][0]) == 619
35+
36+
residues = set(find_high_confidence_residues(sample_pdb, 90))
37+
new_structure = filter_out_low_confidence_residues(sample_pdb, residues)
38+
39+
assert len(new_structure[0][0]) == 22
40+
41+
42+
def test_filter_files_on_confidence(sample_pdb_file: Path, tmp_path: Path):
43+
input_files = [sample_pdb_file]
44+
query = ConfidenceFilterQuery(
45+
confidence=90,
46+
max_threshold=40,
47+
min_threshold=10,
48+
)
49+
50+
results = list(filter_files_on_confidence(input_files, query, tmp_path))
51+
52+
expected = [
53+
ConfidenceFilterResult(
54+
input_file=sample_pdb_file.name,
55+
count=22,
56+
filtered_file=tmp_path / sample_pdb_file.name,
57+
)
58+
]
59+
60+
assert results == expected
61+
assert results[0].filtered_file is not None
62+
assert results[0].filtered_file.exists()
63+
assert nr_residues_in_chain(results[0].filtered_file) == 22

tests/alphafold/test_density.py

Lines changed: 0 additions & 32 deletions
This file was deleted.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
interactions:
2+
- request:
3+
body: null
4+
headers: {}
5+
method: GET
6+
uri: https://www.ebi.ac.uk/QuickGO/services/ontology/go/search?query=GO:0043293&limit=100&page=1
7+
response:
8+
body:
9+
string: '{"numberOfHits":4,"results":[{"id":"GO:0043293","isObsolete":false,"name":"apoptosome","definition":{"text":"A
10+
multisubunit protein complex involved in the signaling phase of the apoptotic
11+
process. In mammals it is typically composed of seven Apaf-1 subunits bound
12+
to cytochrome c and caspase-9. A similar complex to promote apoptosis is formed
13+
from homologous gene products in other eukaryotic organisms."},"aspect":"cellular_component"},{"id":"GO:0000811","isObsolete":false,"name":"GINS
14+
complex","definition":{"text":"A heterotetrameric protein complex that associates
15+
with replication origins, where it is required for the initiation of DNA replication,
16+
and with replication forks."},"aspect":"cellular_component"},{"id":"GO:0070966","isObsolete":false,"name":"nuclear-transcribed
17+
mRNA catabolic process, no-go decay","definition":{"text":"The chemical reactions
18+
and pathways resulting in the breakdown of the transcript body of a nuclear-transcribed
19+
mRNA with stalls in translation elongation."},"aspect":"biological_process"},{"id":"GO:0001591","isObsolete":false,"name":"dopamine
20+
neurotransmitter receptor activity, coupled via Gi/Go","definition":{"text":"Combining
21+
with the neurotransmitter dopamine and activating adenylate cyclase via coupling
22+
to Gi/Go to initiate a change in cell activity."},"aspect":"molecular_function"}],"pageInfo":{"resultsPerPage":100,"current":1,"total":1}}'
23+
headers:
24+
Access-Control-Allow-Headers:
25+
- Content-Type
26+
Access-Control-Allow-Origin:
27+
- '*'
28+
Content-Type:
29+
- application/json
30+
Date:
31+
- Mon, 18 Aug 2025 13:57:47 GMT
32+
Strict-Transport-Security:
33+
- max-age=0
34+
Transfer-Encoding:
35+
- chunked
36+
status:
37+
code: 200
38+
message: ''
39+
version: 1
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
interactions:
2+
- request:
3+
body: null
4+
headers:
5+
Accept:
6+
- application/sparql-results+json,application/json,text/javascript,application/javascript
7+
Connection:
8+
- close
9+
Host:
10+
- sparql.uniprot.org
11+
User-Agent:
12+
- sparqlwrapper 2.0.0 (rdflib.github.io/sparqlwrapper)
13+
method: GET
14+
uri: https://sparql.uniprot.org/sparql?query=%0A++++++++PREFIX+up%3A+%3Chttp%3A//purl.uniprot.org/core/%3E%0A++++++++PREFIX+taxon%3A+%3Chttp%3A//purl.uniprot.org/taxonomy/%3E%0A++++++++PREFIX+rdf%3A+%3Chttp%3A//www.w3.org/1999/02/22-rdf-syntax-ns%23%3E%0A++++++++PREFIX+rdfs%3A+%3Chttp%3A//www.w3.org/2000/01/rdf-schema%23%3E%0A++++++++PREFIX+skos%3A+%3Chttp%3A//www.w3.org/2004/02/skos/core%23%3E%0A++++++++PREFIX+GO%3A%3Chttp%3A//purl.obolibrary.org/obo/GO_%3E%0A%0A++++++++SELECT+%3Fprotein+%3Faf_db%0A++++++++WHERE+%7B%0A%0A++++++++%23+---+Protein+Selection+---%0A++++++++VALUES+%28%3Fac%29+%7B+%28%22P05067%22%29%7D%0A++++++++BIND+%28IRI%28CONCAT%28%22http%3A//purl.uniprot.org/uniprot/%22%2C%3Fac%29%29+AS+%3Fprotein%29%0A++++++++%3Fprotein+a+up%3AProtein+.%0A%0A%0A%23+---+Protein+Selection+---%0A%3Fprotein+a+up%3AProtein+.%0A%0A%23+---+AlphaFoldDB+Info+---%0A%3Fprotein+rdfs%3AseeAlso+%3Faf_db+.%0A%3Faf_db+up%3Adatabase+%3Chttp%3A//purl.uniprot.org/database/AlphaFoldDB%3E+.%0A%0A%0A++++++++%7D%0A%0A++++++++LIMIT+1%0A&format=json&output=json&results=json
15+
response:
16+
body:
17+
string: "{\n \"head\" : {\n \"vars\" : [\n \"protein\",\n \"af_db\"\n
18+
\ ]\n },\n \"results\" : {\n \"bindings\" : [\n {\n \"protein\"
19+
: {\n \"type\" : \"uri\",\n \"value\" : \"http://purl.uniprot.org/uniprot/P05067\"\n
20+
\ },\n \"af_db\" : {\n \"type\" : \"uri\",\n \"value\"
21+
: \"http://purl.uniprot.org/alphafolddb/P05067\"\n }\n }\n ]\n
22+
\ }\n}"
23+
headers:
24+
Access-Control-Allow-Headers:
25+
- origin, x-requested-with, content-type, X-Release, queryid
26+
Access-Control-Allow-Origin:
27+
- '*'
28+
Access-Control-Expose-Headers:
29+
- X-Total-Results, X-Release, queryid, content-type, user-agent, cache-control,
30+
etag, range
31+
Cache-Control:
32+
- public
33+
Connection:
34+
- close
35+
Content-Disposition:
36+
- attachment; filename="sparql-A8EBFEAA11A5F303CCDAC4F54F9AE459.srj"
37+
Content-Length:
38+
- '375'
39+
Content-Type:
40+
- application/sparql-results+json
41+
Date:
42+
- Mon, 18 Aug 2025 13:40:18 GMT
43+
ETag:
44+
- W/"2025_03"
45+
Expires:
46+
- Tue, 19 Aug 2025 13:40:18 GMT
47+
Server:
48+
- Apache
49+
Strict-Transport-Security:
50+
- max-age=31536001; includeSubDomains
51+
Vary:
52+
- Negotiate,Accept,Accept-Encoding,Content-Type
53+
X-Content-Type-Options:
54+
- nosniff
55+
X-Frame-Options:
56+
- SAMEORIGIN
57+
X-Powered-By:
58+
- sib.swiss
59+
X-Release:
60+
- '2025_03'
61+
queryid:
62+
- '10827012252'
63+
status:
64+
code: 200
65+
message: ''
66+
version: 1

0 commit comments

Comments
 (0)