Beispiel #1
0
def _validate_label_elements(label: Dict, task_key: str, files: Dict[str, bytes]) -> None:
    """Validate Label Elements and make sure that all Brush Elements have images."""
    task = TasksRepository.get_task_by_key(task_key)
    available_tags_keys = {tag.key for tag in task.available_tags}
    elements = label['elements']
    for label_element in elements:
        # Check if Label Element Tag is part of this Task
        if label_element['tag'] not in available_tags_keys:
            raise InvalidArgumentsException('Tag {} is not part of Task {}.'.format(label_element['tag'], task_key))

        # Each Brush Label Element should have its own image attached
        if label_element['tool'] == LabelTool.BRUSH.value and not files.get(label_element['image_key']):
            message = 'Request does not have field named {} that could contain the image!'
            raise InvalidArgumentsException(message.format(label_element['image_key']))
Beispiel #2
0
    def _raise_on_invalid_request_slices(self, count: int,
                                         orientation: str) -> None:
        """Validate incoming request and raise an exception if there are issues with given arguments.

        :param count: number of slices that should be returned
        :param orientation: Slice's orientation as a string
        """
        # Make sure that passed orientation is proper one
        if orientation not in SliceOrientation.__members__:
            raise InvalidArgumentsException('Invalid Slice orientation.')

        # Make sure that nobody will fetch whole scan at once. It could freeze our backend application.
        if count > self.MAX_NUMBER_OF_SLICES_PER_REQUEST:
            message = 'Cannot return more than {} slices per request.'.format(
                self.MAX_NUMBER_OF_SLICES_PER_REQUEST)
            raise InvalidArgumentsException(message)
Beispiel #3
0
 def get() -> Any:
     """Return random Scan."""
     args = serializers.args__random_scan.parse_args(request)
     category_key = args.category
     if not business.scan_category_is_valid(category_key):
         raise InvalidArgumentsException(
             'Category "{}" is not available.'.format(category_key))
     return business.get_random_scan(category_key)
Beispiel #4
0
def _validate_tool(label: Dict) -> None:
    """Validate if the tool for given Label Element is available for given tag."""
    elements = label['elements']
    for label_element in elements:
        tag = _get_label_tag(label_element['tag'])
        if label_element['tool'] not in {tool.name for tool in tag.tools}:
            raise InvalidArgumentsException('{} tool is not available for {} tag'.format(
                label_element['tool'], tag.name))
Beispiel #5
0
def add_action_response(action_id: ActionID, response: Dict) -> ActionResponse:
    """Add new Response for given Action.

    :param action_id: ID of an Action for which this Response should be added
    :param response: dictionary Response for given Action
    :return: ActionResponse database object
    """
    try:
        return ActionsRepository.add_action_response(action_id, response)
    except NoResultFound:
        raise NotFoundException('Action "{}" not found.'.format(action_id))
    except UnsupportedActionException:
        raise InvalidArgumentsException(
            'Action does not support returning Respose.')
    except InvalidResponseException:
        raise InvalidArgumentsException(
            'Your answers does not match keys in Survey.')
Beispiel #6
0
def _validate_files(files: Dict[str, bytes]) -> None:
    """Validate files and make sure that images are PNGs."""
    for file_name, file_data in files.items():
        try:
            image = Image.open(io.BytesIO(file_data))
            image.verify()
            assert image.format == 'PNG'
        except Exception:
            raise InvalidArgumentsException('Type of file "{}" is not supported!'.format(file_name))
Beispiel #7
0
    def post() -> Any:
        """Create empty scan."""
        payload = request.json
        dataset_key = payload['dataset']
        number_of_slices = payload['number_of_slices']
        if not business.dataset_is_valid(dataset_key):
            raise InvalidArgumentsException('Dataset "{}" is not available.'.format(dataset_key))

        scan = business.create_empty_scan(dataset_key, number_of_slices)
        return scan, 201
Beispiel #8
0
    def get() -> Any:
        """Get list of all Scans."""
        args = serializers.args__scans.parse_args(request)
        dataset_key = args.dataset_key
        page = args.page
        if page < 1:
            raise InvalidArgumentsException('Page cannot be smaller than 1.')
        per_page = args.per_page
        if per_page > 100:
            raise InvalidArgumentsException('Cannot fetch more than 100 entries at once.')

        scans, total = business.get_paginated_scans(dataset_key=dataset_key, page=page, per_page=per_page)
        return {
            'scans': scans,
            'pagination': {
                'total': total,
                'page': page,
                'per_page': per_page,
            },
        }
Beispiel #9
0
    def post() -> Any:
        """Create empty scan."""
        payload = request.json
        category_key = payload['category']
        number_of_slices = payload['number_of_slices']
        if not business.scan_category_is_valid(category_key):
            raise InvalidArgumentsException(
                'Category "{}" is not available.'.format(category_key))

        scan = business.create_empty_scan(category_key, number_of_slices)
        return scan, 201
Beispiel #10
0
def _validate_label_elements(elements: List[Dict], files: Dict[str,
                                                               bytes]) -> None:
    """Validate Label Elements and make sure that all Brush Elements have images."""
    for label_element in elements:
        # Each Brush Label Element should have its own image attatched
        if label_element['tool'] == LabelTool.BRUSH.value:
            try:
                files[label_element['image_key']]
            except KeyError:
                message = 'Request does not have field named {} that could contain the image!'
                raise InvalidArgumentsException(
                    message.format(label_element['image_key']))
Beispiel #11
0
    def post(scan_id: ScanID, task_key: str) -> Any:
        """Add new Label for given scan.

        This endpoint needs a multipart/form-data content where there is one mandatory section called "label".
        Such section will contain a JSON payload with representation of a Label. If such Label needs additional
        information like images (binary mask), please attach them as a separate part.

        Here is an example CURL command that sends Label with Brush Element:

            $> curl -v
                    -H "Content-Type:multipart/form-data"
                    -H "Authorization: Bearer MEDTAGGER_API_TOKEN"
                    -F "SLICE_1=@"/Users/jakubpowierza/Desktop/test.png""
                    -F "label={"elements": [{"width": 1, "height": 1, "image_key": "SLICE_1",
                               "slice_index": 1, "tag": "LEFT_KIDNEY", "tool": "BRUSH"}],
                               "labeling_time": 0.1};type=application/json"
                     http://localhost:51000/api/v1/scans/c5102707-cb36-4869-8041-f00421c03fa1/MARK_KIDNEYS/label
        """
        is_predefined = (request.args.get('is_predefined', 'false') == 'true')
        if is_predefined:
            require_one_of_roles({'doctor', 'admin'})

        files = {
            name: file_data.read()
            for name, file_data in request.files.items()
        }
        label = json.loads(request.form['label'])
        elements = label['elements']
        try:
            validate(elements, elements_schema)
        except ValidationError:
            validator = Draft4Validator(elements_schema)
            errors = validator.iter_errors(elements)
            best_error = best_match(errors)
            raise InvalidArgumentsException(best_error.message)

        business.validate_label_payload(label, task_key, files)

        labeling_time = label['labeling_time']
        comment = label.get('comment')
        label = business.add_label(scan_id, task_key, elements, files,
                                   labeling_time, comment, is_predefined)
        return label, 201
Beispiel #12
0
def get_random_scan(task_key: str) -> Scan:
    """Fetch random scan from specified Task for labeling.

    :param task_key: unique key identifying task
    :return: Scan Metadata object
    """
    task = TasksRepository.get_task_by_key(task_key)
    if not task:
        raise InvalidArgumentsException('Task key {} is invalid!'.format(task_key))

    user = get_current_user()
    scan = ScansRepository.get_random_scan(task, user)
    if not scan:
        raise NotFoundException('Could not find any Scan for this task!')

    predefined_label = LabelsRepository.get_predefined_label_for_scan_in_task(scan, task)
    if predefined_label:
        scan.predefined_label_id = predefined_label.id

    return scan