Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 18 additions & 0 deletions .github/workflows/codespell.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Codespell

on:
pull_request:
push:
branches: [main]

jobs:
codespell:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install codespell
run: |
python -m pip install --upgrade pip
pip install codespell
- name: Run codespell
run: codespell --check-hidden -q 3
22 changes: 22 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Docker Build

on:
pull_request:
push:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build Docker image
uses: docker/build-push-action@v5
with:
context: .
push: false
tags: qkay:test
21 changes: 21 additions & 0 deletions .github/workflows/package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Build Package

on:
pull_request:
push:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install build tool
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: python -m build
23 changes: 23 additions & 0 deletions .github/workflows/ruff.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Ruff Checks

on:
pull_request:
push:
branches: [main]

jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install ruff
run: |
python -m pip install --upgrade pip
pip install ruff
- name: Ruff check
run: ruff check .
- name: Ruff format
run: ruff format --diff .
27 changes: 27 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Run Tests

on:
pull_request:
push:
branches: [main]

jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pytest
- name: Run tests
env:
PYTHONPATH: ${{ github.workspace }}
run: pytest -v
17 changes: 8 additions & 9 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,23 @@

# -- Project information -----------------------------------------------------

project = 'qkay'
copyright = 'The NiPreps Developers'
author = 'The NiPreps Developers'
project = "qkay"
copyright = "The NiPreps Developers"
author = "The NiPreps Developers"

# The full version, including alpha/beta/rc tags
release = 'v.0.0.0'
release = "v.0.0.0"


# -- General configuration ---------------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
]
extensions = []

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
Expand All @@ -47,9 +46,9 @@
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
html_theme = "alabaster"

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_static_path = ["_static"]
30 changes: 30 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "qkay"
version = "0.1.0"
description = "Flask web application"
authors = [{name = "The NiPreps Developers", email = "[email protected]"}]
license = {file = "LICENSE"}
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"beautifulsoup4==4.11.2",
"Flask==2.2.2",
"Flask_Login==0.6.2",
"flask_mongoengine==1.0.0",
"Flask_WTF==1.1.1",
"Jinja2==3.1.2",
"mongoengine==0.26.0",
"numpy",
"Werkzeug==2.2.2",
"WTForms==3.0.1",
]

[tool.setuptools.packages.find]
where = ["."]

[project.scripts]
qkay = "qkay.wsgi:app"
2 changes: 2 additions & 0 deletions qkay/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""qkay package."""

from .qkay import app

__all__ = ["app"]
9 changes: 3 additions & 6 deletions qkay/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
# https://www.nipreps.org/community/licensing/
#
"""Utilities: Jinja2 templates."""

from io import open # pylint: disable=W0622


Expand Down Expand Up @@ -65,15 +66,11 @@ class IndividualTemplate(Template):
"""Specific template for the individual report. From MRIQC"""

def __init__(self):
super(IndividualTemplate, self).__init__(
"./templates/reports.html"
)
super(IndividualTemplate, self).__init__("./templates/reports.html")


class IndexTemplate(Template):
"""Specific template for the index file of the reports."""

def __init__(self):
super(IndexTemplate, self).__init__(
"./templates/index.html"
)
super(IndexTemplate, self).__init__("./templates/index.html")
121 changes: 76 additions & 45 deletions qkay/qkay.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,35 +178,35 @@ def validate_dataset(self):

class Inspection(db.Document):
"""
Class to define an inspection
...

Attributes
----------
meta : dict
mongodb collection
dataset : str
name of the dataset to be inspected
username : str
name of the user assigned to the inspection
randomize : bool
If files must be shuffled
rate_all : bool
If all files must be rated
blind : bool
If reports must be anonymized
names_files : string list
list of filenames to grade
names_shuffled : string list
shuffled list of filenames
names_anonymized : string list
list of filenames anonymized and shuffled if randomize==True
names_subsample: string list
subsample of file to inspect if rate_all==False
random_seed: int
random seed used to shuffle the filename
index_rated_reports: list
index of reports already rated
Class to define an inspection
...

Attributes
----------
meta : dict
mongodb collection
dataset : str
name of the dataset to be inspected
username : str
name of the user assigned to the inspection
randomize : bool
If files must be shuffled
rate_all : bool
If all files must be rated
blind : bool
If reports must be anonymized
names_files : string list
list of filenames to grade
names_shuffled : string list
shuffled list of filenames
names_anonymized : string list
list of filenames anonymized and shuffled if randomize==True
names_subsample: string list
subsample of file to inspect if rate_all==False
random_seed: int
random seed used to shuffle the filename
index_rated_reports: list
index of reports already rated
"""

meta = {"collection": "inspections"}
Expand Down Expand Up @@ -687,15 +687,25 @@ def display_report_non_anonymized(username, report_name):
dataset = user.current_dataset
dataset_path = str(Dataset.objects(name=dataset).values_list("path_dataset")[0])

app.logger.debug("Searching recursively for a report named %s under %s.", report_name, dataset_path)
app.logger.debug(
"Searching recursively for a report named %s under %s.",
report_name,
dataset_path,
)

mriqc_report = ""
path_mriqc_report = glob.glob(os.path.join(dataset_path, "**", "sub-" + report_name), recursive=True)
path_mriqc_report = glob.glob(
os.path.join(dataset_path, "**", "sub-" + report_name), recursive=True
)
if len(path_mriqc_report) == 0:
app.logger.error("No report named %s was found in the children of %s.","sub-" + report_name, dataset_path)
app.logger.error(
"No report named %s was found in the children of %s.",
"sub-" + report_name,
dataset_path,
)
else:
path_mriqc_report = path_mriqc_report[0]
# Modify the html to adapt it to Q'kay
# Modify the html to adapt it to Q'kay
mriqc_report = modify_mriqc_report(path_mriqc_report)

return render_template(
Expand Down Expand Up @@ -757,7 +767,11 @@ def display_index_inspection(username, dataset):
user.save()
path_index = "./templates/index.html"

app.logger.debug("Searching for inspection matching dataset %s and username %s.", dataset, username)
app.logger.debug(
"Searching for inspection matching dataset %s and username %s.",
dataset,
username,
)

# Find in the inspection which reports have been rated
current_inspection = Inspection.objects(Q(dataset=dataset) & Q(username=username))
Expand Down Expand Up @@ -816,28 +830,47 @@ def create_dataset():
selected_datasets = request.form.getlist("datasets[]")
for d in selected_datasets:
dataset_path = op.join("/datasets", d)
app.logger.debug("Searching recursively for dataset_description.json under %s.", dataset_path)
app.logger.debug(
"Searching recursively for dataset_description.json under %s.",
dataset_path,
)

# Get dataset name from the data_description.json file if it exists
# otherwise, use the folder name
desc_file = ""
desc_files = glob.glob(os.path.join(dataset_path, "**", "dataset_description.json"), recursive=True)
desc_files = glob.glob(
os.path.join(dataset_path, "**", "dataset_description.json"),
recursive=True,
)
if len(desc_files) > 1:
app.logger.warning("More than one dataset_description.json was found!: %s .", desc_files)

app.logger.warning(
"More than one dataset_description.json was found!: %s .",
desc_files,
)

desc_file = desc_files[0]
app.logger.debug("dataset_description.json found at %s.", desc_file)
app.logger.debug("dataset_description.json found at %s.", desc_file)
if desc_file:
with open(desc_file, "r") as file:
data_description = json.load(file)
dataset_name = data_description["Name"]
app.logger.info("The dataset name %s was assigned based on the name in %s", dataset_name, desc_file)
app.logger.info(
"The dataset name %s was assigned based on the name in %s",
dataset_name,
desc_file,
)
# If the name of the dataset is the default MRIQC value, use the folder name instead
if dataset_name == "MRIQC - MRI Quality Control":
app.logger.info("The dataset name is the default of MRIQC which is not informative, using folder name instead: %s.", d)
app.logger.info(
"The dataset name is the default of MRIQC which is not informative, using folder name instead: %s.",
d,
)
dataset_name = d
else:
app.logger.info("No dataset_description.json found, assigning dataset name to folder name: %s.", d)
app.logger.info(
"No dataset_description.json found, assigning dataset name to folder name: %s.",
d,
)
dataset_name = d

dataset = Dataset(name=dataset_name, path_dataset=dataset_path)
Expand Down Expand Up @@ -908,9 +941,7 @@ def assign_dataset():
)

names_files = list_individual_reports(dataset_path)
app.logger.debug(
"%s reports found at %s", len(names_files), dataset_path
)
app.logger.debug("%s reports found at %s", len(names_files), dataset_path)
new_names = names_files
if repeat:
names_repeated = repeat_reports(new_names, number_rep)
Expand Down
Loading
Loading