Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Major refactor of helper functions #167

Open
wants to merge 36 commits into
base: main
Choose a base branch
from
Open

Major refactor of helper functions #167

wants to merge 36 commits into from

Conversation

chrisvanrun
Copy link
Contributor

@chrisvanrun chrisvanrun commented Aug 27, 2024

This PR refactors existing helper functions (i.e. Client.update_archive_item) and adds some new ones that make sense.

These are the helper functions now:

  • update_archive_item
  • add_cases_to_archive (new)
  • update_display_set (new)
  • add_cases_to_reader_study
  • run_external_job
  • upload_cases (untouched)

Proto models

The core of this PR is the 'gcapi/models_proto.py'.

This PR introduces proto-models. These are models of things that are yet to be. Their main function is to separate the creation/saving logic from the validation logic. This allows for quick unit tests to cover corner cases in validation, while simultaneously allowing to validate all values before anything hits the platform.

These 'preflight' validations were, partially, already in place for add_cases_to_reader_study but are now ubiquitous for all helper functions.

While refactoring I ran into several issues concerning the adaptation of models, which I fixed as I went. With deadline pressure and random fixes, flaky tests, et cetera this is now a messy and large change set. Sorry!

Below are some descriptions of additional fixes that are included in the PR.


Both str, and [str] are allowed

Sourcing a CIV from one file no longer requires a one-lengthed list, the helper functions automagically handle both. This also applies to pathlib.Path.


.details API now accepts an api_url keyword argument

Since we are casting to models it made more sense to be able to call the .details with api_url than to manually figure out which gcapi.models one is to use.

This replaces:

 gcapi.models.HyperLinkedImage(**client(url=api_url))

With:

client.images.details(api_url=api_url)

.create()/.update()/.partial_update() -> models

API calls that support .create(..), .update(..), and .partial_update(..) now return gcapi.models instead of dicts.


Using existing images

Related to the actual pitch:

One can add an existing image as follows (pulled from a test):

 # First create an image component interface
added_display_sets = client.add_cases_to_reader_study(
    reader_study="reader-study",
    display_sets=[
        {
            "ct-image": [TESTDATA / "image10x10x101.mha"],
        }
    ],
)

display_set_pk = added_display_sets[0]

# ... wait for import to finish

display_set = c.reader_studies.display_sets.detail(pk=display_set_pk)

# Re-use both as a direct image and a CIV
display = display_set.values[0]
image = client.images.detail(api_url=display.image)

added_display_sets = await client.add_cases_to_reader_study(
    reader_study="reader-study",
    display_sets=[
        {
            "ct-image": image,
        },
        {
            "ct-image": civ,
        },
    ],
)

Some typing stuff

Closes: #163


Usage of JSON for "File" super_kind interfaces.

Closes: #153

It is now possible to provide:

  • a file path to a super-kind:"Value" interface
  • a dict (or other JSON-like python object) to a super-kind:"File" interface

Note that for the "File" one, this cannot be done for an interface with kind "String". It would be far too easy to have a non-existing file path as content for a String interface. All other interfaces should error out on the platform and run into schemas there.

)

# retrieve existing archive item pk
items = get_archive_items(c, archive.pk, len(old_items_list))

old_civ_count = len(items[-1].values)

with pytest.raises(ValueError) as e:
Copy link
Contributor Author

@chrisvanrun chrisvanrun Aug 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Covered by unittests

},
"predictions-csv-file": [
Path(__file__).parent / "testdata" / "test.csv"
CIV_SET_PARAMS = (
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defining this 4x seemed a bit verbose.



def test_add_cases_to_reader_study_multiple_files(local_grand_challenge):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Covered by unittests

@chrisvanrun
Copy link
Contributor Author

Ugh. I was afraid of this. There are some race conditions between a RawImageUpload being processed, a CIV being created and the image being assigned. Resulting in flaky tests. Fixing!

@chrisvanrun
Copy link
Contributor Author

Fingers crossed... locally everything ran butter smooth. It's the CI restraints that show the race conditions.

@chrisvanrun
Copy link
Contributor Author

chrisvanrun commented Aug 27, 2024

DeprecationWarnings, fixing...

/home/runner/work/rse-gcapi/rse-gcapi/gcapi/client.py:510: DeprecationWarning: Using ["api_url"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["api_url"] with .api_url
      uploads=[u["api_url"] for u in uploads], **kwargs
  tests/integration_tests.py::test_upload_cases_to_archive[files1-None]
  tests/integration_tests.py::test_upload_cases_to_archive[files0-generic-overlay]
  tests/integration_tests.py::test_upload_cases_to_archive[files2-generic-overlay]
  tests/integration_tests.py::test_upload_cases_to_archive[files3-None]
    /home/runner/work/rse-gcapi/rse-gcapi/tests/integration_tests.py:150: DeprecationWarning: Using ["pk"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["pk"] with .pk
      us = get_upload_session(c, us["pk"])
  tests/integration_tests.py::test_upload_cases_to_archive[files1-None]
  tests/integration_tests.py::test_upload_cases_to_archive[files0-generic-overlay]
  tests/integration_tests.py::test_upload_cases_to_archive[files2-generic-overlay]
  tests/integration_tests.py::test_upload_cases_to_archive[files3-None]
    /home/runner/work/rse-gcapi/rse-gcapi/tests/integration_tests.py:178: DeprecationWarning: Using ["files"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["files"] with .files
      response = c(url=image["files"][0]["file"], follow_redirects=True)
  tests/integration_tests.py::test_upload_cases_to_archive[files1-None]
  tests/integration_tests.py::test_upload_cases_to_archive[files0-generic-overlay]
  tests/integration_tests.py::test_upload_cases_to_archive[files2-generic-overlay]
  tests/integration_tests.py::test_upload_cases_to_archive[files3-None]
    /home/runner/work/rse-gcapi/rse-gcapi/tests/integration_tests.py:178: DeprecationWarning: Using ["file"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["file"] with .file
      response = c(url=image["files"][0]["file"], follow_redirects=True)
  tests/integration_tests.py::test_download_cases[files0]
    /home/runner/work/rse-gcapi/rse-gcapi/tests/integration_tests.py:283: DeprecationWarning: Using ["pk"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["pk"] with .pk
      us = get_upload_session(c, us["pk"])
  tests/integration_tests.py::test_create_job_with_upload[test-algorithm-evaluation-image-1-generic-medical-image-files0]
    /home/runner/work/rse-gcapi/rse-gcapi/tests/integration_tests.py:339: DeprecationWarning: Using ["status"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["status"] with .status
      assert job["status"] == "Queued"
  tests/integration_tests.py::test_create_job_with_upload[test-algorithm-evaluation-image-1-generic-medical-image-files0]
    /home/runner/work/rse-gcapi/rse-gcapi/tests/integration_tests.py:340: DeprecationWarning: Using ["inputs"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["inputs"] with .inputs
      assert len(job["inputs"]) == 1
  tests/integration_tests.py::test_create_job_with_upload[test-algorithm-evaluation-image-1-generic-medical-image-files0]
    /home/runner/work/rse-gcapi/rse-gcapi/tests/integration_tests.py:341: DeprecationWarning: Using ["pk"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["pk"] with .pk
      job = c.algorithm_jobs.detail(job["pk"])
  tests/integration_tests.py::test_upload_cases_to_archive_item_with_new_interface
    /home/runner/work/rse-gcapi/rse-gcapi/tests/integration_tests.py:258: DeprecationWarning: Using ["pk"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["pk"] with .pk
      us = get_upload_session(c, us["pk"])
  tests/integration_tests.py::test_upload_cases_to_archive_item_with_existing_interface
    /home/runner/work/rse-gcapi/rse-gcapi/tests/integration_tests.py:227: DeprecationWarning: Using ["pk"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["pk"] with .pk
      us = get_upload_session(c, us["pk"])
  tests/async_integration_tests.py::test_download_cases[files0]
    /home/runner/work/rse-gcapi/rse-gcapi/tests/async_integration_tests.py:328: DeprecationWarning: Using ["pk"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["pk"] with .pk
      us = await get_upload_session(c, us["pk"])
  tests/async_integration_tests.py::test_upload_cases_to_archive[files1-None]
  tests/async_integration_tests.py::test_upload_cases_to_archive[files2-generic-overlay]
  tests/async_integration_tests.py::test_upload_cases_to_archive[files3-None]
  tests/async_integration_tests.py::test_upload_cases_to_archive[files0-generic-overlay]
    /home/runner/work/rse-gcapi/rse-gcapi/tests/async_integration_tests.py:170: DeprecationWarning: Using ["pk"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["pk"] with .pk
      us = await get_upload_session(c, us["pk"])
  tests/async_integration_tests.py::test_upload_cases_to_archive_item_with_existing_interface
    /home/runner/work/rse-gcapi/rse-gcapi/tests/async_integration_tests.py:258: DeprecationWarning: Using ["pk"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["pk"] with .pk
      us = await get_upload_session(c, us["pk"])
  tests/async_integration_tests.py::test_create_job_with_upload[test-algorithm-evaluation-image-1-generic-medical-image-files0]
    /home/runner/work/rse-gcapi/rse-gcapi/tests/async_integration_tests.py:381: DeprecationWarning: Using ["status"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["status"] with .status
      assert job["status"] == "Queued"
  tests/async_integration_tests.py::test_create_job_with_upload[test-algorithm-evaluation-image-1-generic-medical-image-files0]
    /home/runner/work/rse-gcapi/rse-gcapi/tests/async_integration_tests.py:382: DeprecationWarning: Using ["inputs"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["inputs"] with .inputs
      assert len(job["inputs"]) == 1
  tests/async_integration_tests.py::test_create_job_with_upload[test-algorithm-evaluation-image-1-generic-medical-image-files0]
    /home/runner/work/rse-gcapi/rse-gcapi/tests/async_integration_tests.py:384: DeprecationWarning: Using ["pk"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["pk"] with .pk
      job = await c.algorithm_jobs.detail(job["pk"])
  tests/async_integration_tests.py::test_upload_cases_to_archive_item_with_new_interface
    /home/runner/work/rse-gcapi/rse-gcapi/tests/async_integration_tests.py:301: DeprecationWarning: Using ["pk"] for getting attributes is deprecated and will be removed in the next release. Suggestion: Replace ["pk"] with .pk

.. Done!

@chrisvanrun
Copy link
Contributor Author

chrisvanrun commented Aug 27, 2024

How can it be that something that is referenced via a hyperlink from the API (e.g. via https://gc.localhost/api/v1/cases/images/8e3e90d5-7622-4574-84fe-82bbfadcd2b7/) SOMETIMES, but then consistently, gives a 404?

"Sometimes" :- because it is flaky.
"Consistently" :- because it is wrapped in a recurse_call which retries it every 500ms for 30 seconds.

@chrisvanrun
Copy link
Contributor Author

Ok, possible fix: not recursing in tests when ObjectNotFound is thrown (instead of a HTTPStatusError)

@chrisvanrun chrisvanrun marked this pull request as ready for review August 28, 2024 07:21
@chrisvanrun chrisvanrun changed the title [WIP] Major refactor of helper functions Major refactor of helper functions Aug 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Some methods do not seem to return models Uploads to archive items fail when CIV is file type and JSON sent
1 participant