Skip to content

Commit

Permalink
Remove retina endpoints (#154)
Browse files Browse the repository at this point in the history
See DIAGNijmegen/rse-grand-challenge-admin#236

---------

Co-authored-by: Harm van Zeeland <[email protected]>
  • Loading branch information
2 people authored and chrisvanrun committed Nov 5, 2024
1 parent 0bb0354 commit 828049e
Show file tree
Hide file tree
Showing 22 changed files with 774 additions and 604 deletions.
20 changes: 9 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
- published

env:
MINIMUM_PYTHON_VERSION: '3.8'
MINIMUM_PYTHON_VERSION: '3.9'

concurrency:
group: ${{ github.head_ref || github.run_id }}
Expand All @@ -19,10 +19,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Install Python ${{ env.MINIMUM_PYTHON_VERSION }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ env.MINIMUM_PYTHON_VERSION }}
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install pre-commit
run: |
python -m pip install --upgrade pip
Expand All @@ -40,19 +40,19 @@ jobs:
strategy:
fail-fast: false # Try to work around ECS errors
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install tox-gh-actions poetry
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: us-east-1
Expand All @@ -66,8 +66,6 @@ jobs:
retry -t 5 -- docker pull public.ecr.aws/diag-nijmegen/grand-challenge/http:latest
- name: Add gc.localhost to /etc/hosts
run: sudo echo "127.0.0.1 gc.localhost\n127.0.0.1 minio.localhost" | sudo tee -a /etc/hosts
- name: Find the docker compose version (should be at least 2.1.1 for --wait, everything works locally with 2.5.1, 2.4.1+azure-1 does not work)
run: docker compose version
- name: Run tox
run: tox

Expand All @@ -77,10 +75,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Install Python ${{ env.MINIMUM_PYTHON_VERSION }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ env.MINIMUM_PYTHON_VERSION }}
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand Down
12 changes: 6 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.6.0
hooks:
- id: check-docstring-first
- id: debug-statements
- id: end-of-file-fixer
- id: mixed-line-ending
- id: trailing-whitespace
- repo: https://github.com/asottile/pyupgrade
rev: v3.3.1
rev: v3.17.0
hooks:
- id: pyupgrade
language: python
args: [--py38-plus, --keep-runtime-typing]
args: [--py39-plus, --keep-runtime-typing]
- repo: https://github.com/pycqa/isort
rev: 5.12.0
rev: 5.13.2
hooks:
- id: isort
- repo: https://github.com/ambv/black
rev: 23.1.0
rev: 24.4.2
hooks:
- id: black
language: python
Expand All @@ -35,7 +35,7 @@ repos:
- mccabe
- yesqa
- repo: https://github.com/pre-commit/mirrors-mypy
rev: 'v1.0.0'
rev: 'v1.11.1'
hooks:
- id: mypy
additional_dependencies:
Expand Down
6 changes: 4 additions & 2 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

## 0.12.0 (UNRELEASED)

- Removed support for Python 3.6 and 3.7
- Added support for Python 3.11
- Removed support for Python 3.6, 3.7 and 3.8
- Added support for Python 3.11 and 3.12
- Removed the retina endpoints
- Migrated to use Pydantic models for request and response validation

## 0.11.0 (2022-12-14)

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ Challenge](https://grand-challenge.org/documentation/grand-challenge-api/).
This client is tested using the `tox` framework. This enables testing
the client in various python-version environments.

For example, running a specific `your_test` for only the python 3.8
For example, running a specific `your_test` for only the python 3.9
environment can be done as follows:
```bash
tox -e py38 -- -k your_test
tox -e py39 -- -k your_test
```
39 changes: 12 additions & 27 deletions gcapi/apibase.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
import collections
from typing import (
Any,
Dict,
Generator,
Generic,
Iterator,
List,
Sequence,
Type,
TypeVar,
overload,
)
from collections.abc import Generator, Iterator, Sequence
from typing import Any, Generic, TypeVar, overload
from urllib.parse import urljoin

from httpx import URL, HTTPStatusError
Expand All @@ -28,15 +18,12 @@

class ClientInterface:
@property
def base_url(self) -> URL:
...
def base_url(self) -> URL: ...

@base_url.setter
def base_url(self, v: URLTypes):
...
def base_url(self, v: URLTypes): ...

def validate_url(self, url):
...
def validate_url(self, url): ...

def __call__(
self,
Expand All @@ -59,7 +46,7 @@ def __init__(
offset: int,
limit: int,
total_count: int,
results: List[T],
results: list[T],
**kwargs,
) -> None:
super().__init__(**kwargs)
Expand All @@ -69,12 +56,10 @@ def __init__(
self._results = results

@overload
def __getitem__(self, key: int) -> T:
...
def __getitem__(self, key: int) -> T: ...

@overload
def __getitem__(self, key: slice) -> Sequence[T]:
...
def __getitem__(self, key: slice) -> Sequence[T]: ...

def __getitem__(self, key):
return self._results[key]
Expand All @@ -96,15 +81,15 @@ def total_count(self) -> int:


class Common(Generic[T]):
model: Type[T]
model: type[T]
_client: ClientInterface
base_path: str

yield_request = CallCapture()


class APIBase(Generic[T], Common[T]):
sub_apis: Dict[str, Type["APIBase"]] = {}
sub_apis: dict[str, type["APIBase"]] = {}

def __init__(self, client) -> None:
if isinstance(self, ModifiableMixin):
Expand All @@ -123,7 +108,7 @@ def list(self, params=None):

def page(
self, offset=0, limit=100, params=None
) -> Generator[T, Dict[Any, Any], PageResult[T]]:
) -> Generator[T, dict[Any, Any], PageResult[T]]:
if params is None:
params = {}

Expand Down Expand Up @@ -158,7 +143,7 @@ def iterate_all(self, params=None) -> Iterator[T]:
yield from current_list
offset += req_count

def detail(self, pk=None, **params) -> Generator[T, Dict[Any, Any], T]:
def detail(self, pk=None, **params) -> Generator[T, dict[Any, Any], T]:
if all((pk, params)):
raise ValueError("Only one of pk or params must be specified")

Expand Down
75 changes: 9 additions & 66 deletions gcapi/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,12 @@
import os
import re
import uuid
from collections.abc import Generator
from io import BytesIO
from pathlib import Path
from random import randint
from time import sleep
from typing import (
TYPE_CHECKING,
Any,
Callable,
Dict,
Generator,
List,
Optional,
Union,
)
from typing import TYPE_CHECKING, Any, Callable, Optional, Union
from urllib.parse import urljoin

import httpx
Expand Down Expand Up @@ -206,40 +198,6 @@ class ComponentInterfacesAPI(APIBase[gcapi.models.ComponentInterface]):
model = gcapi.models.ComponentInterface


class RetinaLandmarkAnnotationSetsAPI(
ModifiableMixin, APIBase[gcapi.models.LandmarkAnnotationSet]
):
base_path = "retina/landmark-annotation/"
model = gcapi.models.LandmarkAnnotationSet

def for_image(self, pk):
result = yield self.yield_request(
method="GET", path=self.base_path, params={"image_id": pk}
)
return result


class RetinaPolygonAnnotationSetsAPI(
ModifiableMixin, APIBase[gcapi.models.NestedPolygonAnnotationSet]
):
base_path = "retina/polygon-annotation-set/"
model = gcapi.models.NestedPolygonAnnotationSet


class RetinaSinglePolygonAnnotationsAPI(
ModifiableMixin, APIBase[gcapi.models.SinglePolygonAnnotation]
):
base_path = "retina/single-polygon-annotation/"
model = gcapi.models.SinglePolygonAnnotation


class RetinaETDRSGridAnnotationsAPI(
ModifiableMixin, APIBase[gcapi.models.ETDRSGridAnnotation]
):
base_path = "retina/etdrs-grid-annotation/"
model = gcapi.models.ETDRSGridAnnotation


class UploadsAPI(APIBase[gcapi.models.UserUpload]):
base_path = "uploads/"
model = gcapi.models.UserUpload
Expand Down Expand Up @@ -385,7 +343,7 @@ class WorkstationConfigsAPI(APIBase[gcapi.models.WorkstationConfig]):
model = gcapi.models.WorkstationConfig


def _generate_auth_header(token: str = "") -> Dict:
def _generate_auth_header(token: str = "") -> dict:
if not token:
try:
token = str(os.environ["GRAND_CHALLENGE_AUTHORIZATION"])
Expand All @@ -410,10 +368,6 @@ class ApiDefinitions:
algorithm_jobs: AlgorithmJobsAPI
archives: ArchivesAPI
workstation_configs: WorkstationConfigsAPI
retina_landmark_annotations: RetinaLandmarkAnnotationSetsAPI
retina_polygon_annotation_sets: RetinaPolygonAnnotationSetsAPI
retina_single_polygon_annotations: RetinaSinglePolygonAnnotationsAPI
retina_etdrs_grid_annotations: RetinaETDRSGridAnnotationsAPI
raw_image_upload_sessions: UploadSessionsAPI
archive_items: ArchiveItemsAPI
interfaces: ComponentInterfacesAPI
Expand Down Expand Up @@ -562,7 +516,7 @@ def _upload_file(self, value):
def upload_cases( # noqa: C901
self,
*,
files: List[str],
files: list[str],
archive: Optional[str] = None,
answer: Optional[str] = None,
archive_item: Optional[str] = None,
Expand Down Expand Up @@ -660,7 +614,7 @@ def upload_cases( # noqa: C901

return raw_image_upload_session

def run_external_job(self, *, algorithm: str, inputs: Dict[str, Any]):
def run_external_job(self, *, algorithm: str, inputs: dict[str, Any]):
"""
Starts an algorithm job with the provided inputs.
You will need to provide the slug of the algorithm. You can find this in the
Expand Down Expand Up @@ -740,7 +694,7 @@ def run_external_job(self, *, algorithm: str, inputs: Dict[str, Any]):
return (yield from self.__org_api_meta.algorithm_jobs.create(**job))

def update_archive_item(
self, *, archive_item_pk: str, values: Dict[str, Any]
self, *, archive_item_pk: str, values: dict[str, Any]
):
"""
This function updates an existing archive item with the provided values
Expand All @@ -764,17 +718,6 @@ def update_archive_item(
If you provide a value or file for an existing interface of the archive
item, the old value will be overwritten by the new one, hence allowing you
to update existing archive item values.
For images that are already associated with an archive item, you can
also change the interface type (e.g. from generic medical image to
generic overlay) by providing the link to the existing image together
with the new interface slug you would like to use:
client.update_archive_item(
archive_item_pk=items[0]['id'],
values={
"generic-overlay":
"https://grand-challenge.org/api/v1/cases/images/.../",
}
)
Parameters
----------
Expand All @@ -788,7 +731,7 @@ def update_archive_item(
item = yield from self.__org_api_meta.archive_items.detail(
pk=archive_item_pk
)
civs: Dict[str, list] = {"values": []}
civs: dict[str, list] = {"values": []}

for civ_slug, value in values.items():
try:
Expand Down Expand Up @@ -880,7 +823,7 @@ def _validate_display_set_values(self, values, interfaces):
return interfaces

def add_cases_to_reader_study(
self, *, reader_study: str, display_sets: List[Dict[str, Any]]
self, *, reader_study: str, display_sets: list[dict[str, Any]]
):
"""
This function takes a reader study slug and a list of diplay sets
Expand Down Expand Up @@ -911,7 +854,7 @@ def add_cases_to_reader_study(
The pks of the newly created display sets.
"""
res = []
interfaces: Dict[str, Dict] = {}
interfaces: dict[str, dict] = {}
for display_set in display_sets:
new_interfaces = yield from self._validate_display_set_values(
display_set.items(), interfaces
Expand Down
Loading

0 comments on commit 828049e

Please sign in to comment.