We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Sending Label with Brush Selection doesn't work 
## Current Behavior

Sending Label with Brush Selection doesn't work.

## Expected Behavior

Label with Brush Selection should be sent correctly.

## Steps to Reproduce the Problem

  1. Go to labeling page and use Brush Tool
  2. Send label
  3. "Can't send scan" appeared



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `backend/medtagger/api/scans/business.py`
Content:
```
1 """Module responsible for business logic in all Scans endpoints."""
2 import io
3 import logging
4 from typing import Callable, Iterable, Dict, List, Tuple, Any
5 
6 from cassandra import WriteTimeout
7 from sqlalchemy.exc import IntegrityError
8 from sqlalchemy.orm.exc import NoResultFound
9 from PIL import Image
10 
11 from medtagger.exceptions import InternalErrorException
12 from medtagger.api.exceptions import NotFoundException, InvalidArgumentsException
13 from medtagger.types import ScanID, LabelPosition, LabelShape, LabelingTime, LabelID, Point
14 from medtagger.database.models import Dataset, Scan, Slice, Label, LabelTag, SliceOrientation
15 from medtagger.definitions import LabelTool
16 from medtagger.repositories import (
17     labels as LabelsRepository,
18     label_tags as LabelTagsRepository,
19     slices as SlicesRepository,
20     scans as ScansRepository,
21     datasets as DatasetsRepository,
22     tasks as TasksRepository,
23 )
24 from medtagger.workers.storage import parse_dicom_and_update_slice
25 from medtagger.api.utils import get_current_user
26 
27 logger = logging.getLogger(__name__)
28 
29 LabelElementHandler = Callable[[Dict[str, Any], LabelID, Dict[str, bytes]], None]
30 
31 
32 def get_available_datasets() -> List[Dataset]:
33     """Fetch list of all available Datasets.
34 
35     :return: list of Datasets
36     """
37     return DatasetsRepository.get_all_datasets()
38 
39 
40 def dataset_is_valid(dataset_key: str) -> bool:
41     """Check if Dataset for such key exists.
42 
43     :param dataset_key: key representing Dataset
44     :return: boolean information if Dataset key is valid
45     """
46     try:
47         DatasetsRepository.get_dataset_by_key(dataset_key)
48         return True
49     except NoResultFound:
50         return False
51 
52 
53 def create_dataset(key: str, name: str) -> Dataset:
54     """Create new Dataset.
55 
56     :param key: unique key representing Dataset
57     :param name: name which describes this Dataset
58     :return: Dataset object
59     """
60     return DatasetsRepository.add_new_dataset(key, name)
61 
62 
63 def create_empty_scan(dataset_key: str, declared_number_of_slices: int) -> Scan:
64     """Create new empty scan.
65 
66     :param dataset_key: string with dataset key
67     :param declared_number_of_slices: number of Slices that will be uploaded
68     :return: Newly created Scan object
69     """
70     user = get_current_user()
71     dataset = DatasetsRepository.get_dataset_by_key(dataset_key)
72     return ScansRepository.add_new_scan(dataset, declared_number_of_slices, user)
73 
74 
75 def get_random_scan(task_key: str) -> Scan:
76     """Fetch random scan from specified Task for labeling.
77 
78     :param task_key: unique key identifying task
79     :return: Scan Metadata object
80     """
81     user = get_current_user()
82     task = TasksRepository.get_task_by_key(task_key)
83     if not task:
84         raise InvalidArgumentsException('Task key {} is invalid!'.format(task_key))
85     scan = ScansRepository.get_random_scan(task, user)
86     if not scan:
87         raise NotFoundException('Could not find any Scan for this task!')
88     return scan
89 
90 
91 def get_slices_for_scan(scan_id: ScanID, begin: int, count: int,
92                         orientation: SliceOrientation = SliceOrientation.Z) -> Iterable[Tuple[Slice, bytes]]:
93     """Fetch multiple slices for given scan.
94 
95     :param scan_id: ID of a given scan
96     :param begin: first slice index (included)
97     :param count: number of slices that will be returned
98     :param orientation: orientation for Slices (by default set to Z axis)
99     :return: generator for Slices
100     """
101     slices = SlicesRepository.get_slices_by_scan_id(scan_id, orientation=orientation)
102     for _slice in slices[begin:begin + count]:
103         image = SlicesRepository.get_slice_converted_image(_slice.id)
104         yield _slice, image
105 
106 
107 def validate_label_payload(elements: List[Dict], files: Dict[str, bytes]) -> None:
108     """Validate and raise an Exception for sent payload.
109 
110     :param elements: List of JSONs describing elements for a single label
111     :param files: mapping of uploaded files (name and content)
112     """
113     _validate_files(files)
114     _validate_label_elements(elements, files)
115     _validate_tool(elements)
116 
117 
118 def _validate_tool(elements: List[Dict]) -> None:
119     """Validate if the tool for given Label Element is available for given tag."""
120     for label_element in elements:
121         tag = _get_label_tag(label_element['tag'])
122         if label_element['tool'] not in {tool.name for tool in tag.tools}:
123             raise InvalidArgumentsException('{} tool is not available for {} tag'.format(
124                 label_element['tool'], tag.name))
125 
126 
127 def _validate_files(files: Dict[str, bytes]) -> None:
128     """Validate files and make sure that images are PNGs."""
129     for file_name, file_data in files.items():
130         try:
131             image = Image.open(io.BytesIO(file_data))
132             image.verify()
133             assert image.format == 'PNG'
134         except Exception:
135             raise InvalidArgumentsException('Type of file "{}" is not supported!'.format(file_name))
136 
137 
138 def _validate_label_elements(elements: List[Dict], files: Dict[str, bytes]) -> None:
139     """Validate Label Elements and make sure that all Brush Elements have images."""
140     for label_element in elements:
141         # Each Brush Label Element should have its own image attached
142         if label_element['tool'] == LabelTool.BRUSH.value:
143             try:
144                 files[label_element['image_key']]
145             except KeyError:
146                 message = 'Request does not have field named {} that could contain the image!'
147                 raise InvalidArgumentsException(message.format(label_element['image_key']))
148 
149 
150 def add_label(scan_id: ScanID, task_key: str, elements: List[Dict],   # pylint: disable-msg=too-many-arguments
151               files: Dict[str, bytes], labeling_time: LabelingTime, comment: str = None) -> Label:
152     """Add label to given scan.
153 
154     :param scan_id: ID of a given scan
155     :param task_key: Key of Task
156     :param elements: List of JSONs describing elements for a single label
157     :param files: mapping of uploaded files (name and content)
158     :param labeling_time: time in seconds that user spent on labeling
159     :param comment: (optional) comment describing a label
160     :return: Label object
161     """
162     user = get_current_user()
163     try:
164         label = LabelsRepository.add_new_label(scan_id, task_key, user, labeling_time, comment)
165     except IntegrityError:
166         raise NotFoundException('Could not find Scan for that id!')
167     for element in elements:
168         add_label_element(element, label.id, files)
169     return label
170 
171 
172 def add_label_element(element: Dict[str, Any], label_id: LabelID, files: Dict[str, bytes]) -> None:
173     """Add new Label Element for given Label.
174 
175     :param element: JSON describing single element
176     :param label_id: ID of a given Label that the element should be added to
177     :param files: mapping of uploaded files (name and content)
178     """
179     tool = element['tool']
180     handlers: Dict[str, LabelElementHandler] = {
181         LabelTool.RECTANGLE.value: _add_rectangle_element,
182         LabelTool.BRUSH.value: _add_brush_element,
183         LabelTool.POINT.value: _add_point_element,
184         LabelTool.CHAIN.value: _add_chain_element,
185     }
186     handler = handlers[tool]
187     handler(element, label_id, files)
188 
189 
190 def _add_rectangle_element(element: Dict[str, Any], label_id: LabelID, *_: Any) -> None:
191     """Add new Rectangular Label Element for given Label.
192 
193     :param element: JSON describing single element
194     :param label_id: ID of a given Label that the element should be added to
195     """
196     position = LabelPosition(x=element['x'], y=element['y'], slice_index=element['slice_index'])
197     shape = LabelShape(width=element['width'], height=element['height'])
198     label_tag = _get_label_tag(element['tag'])
199     LabelsRepository.add_new_rectangular_label_element(label_id, position, shape, label_tag)
200 
201 
202 def _add_brush_element(element: Dict[str, Any], label_id: LabelID, files: Dict[str, bytes]) -> None:
203     """Add new Brush Label Element for given Label.
204 
205     :param element: JSON describing single element
206     :param label_id: ID of a given Label that the element should be added to
207     :param files: mapping of uploaded files (name and content)
208     """
209     width = element['width']
210     height = element['height']
211     label_tag = _get_label_tag(element['tag'])
212     slice_index = element['slice_index']
213     image = files[element['image_key']]
214     LabelsRepository.add_new_brush_label_element(label_id, slice_index, width, height, image, label_tag)
215 
216 
217 def _add_point_element(element: Dict[str, Any], label_id: LabelID, *_: Any) -> None:
218     """Add new Point Label Element for given Label.
219 
220     :param element: JSON describing single element
221     :param label_id: ID of a given Label that the element should be added to
222     """
223     position = LabelPosition(x=element['x'], y=element['y'], slice_index=element['slice_index'])
224     label_tag = _get_label_tag(element['tag'])
225     LabelsRepository.add_new_point_label_element(label_id, position, label_tag)
226 
227 
228 def _add_chain_element(element: Dict[str, Any], label_id: LabelID, *_: Any) -> None:
229     """Add new Chain Label Element for given Label.
230 
231     :param element: JSON describing single element
232     :param label_id: ID of a given Label that the element should be added to
233     """
234     label_tag = _get_label_tag(element['tag'])
235     points = [Point(p['x'], p['y']) for p in element['points']]
236     slice_index = element['slice_index']
237     loop = element['loop']
238     LabelsRepository.add_new_chain_label_element(label_id, slice_index, label_tag, points, loop)
239 
240 
241 def _get_label_tag(tag_key: str) -> LabelTag:
242     """Return Label Tag based on Tag's key or raise an exception in case if not found."""
243     try:
244         return LabelTagsRepository.get_label_tag_by_key(tag_key)
245     except NoResultFound:
246         raise NotFoundException('Could not find any Label Tag for that key!')
247 
248 
249 def add_new_slice(scan_id: ScanID, image: bytes) -> Slice:
250     """Add new Slice for given Scan.
251 
252     :param scan_id: ID of a Scan for which it should add new slice
253     :param image: bytes representing DICOM image
254     :return: Slice object
255     """
256     scan = ScansRepository.get_scan_by_id(scan_id)
257     _slice = scan.add_slice()
258     try:
259         SlicesRepository.store_original_image(_slice.id, image)
260     except WriteTimeout:
261         SlicesRepository.delete_slice(_slice)
262         raise InternalErrorException('Timeout during saving original image to the Storage.')
263     parse_dicom_and_update_slice.delay(_slice.id)
264     return _slice
265 
266 
267 def get_scan(scan_id: ScanID) -> Scan:
268     """Return Scan for given scan_id.
269 
270     :param scan_id: ID of a Scan which should be returned
271     :return: Scan object
272     """
273     try:
274         return ScansRepository.get_scan_by_id(scan_id)
275     except NoResultFound:
276         raise NotFoundException('Scan "{}" not found.'.format(scan_id))
277 
278 
279 def skip_scan(scan_id: ScanID) -> bool:
280     """Increases skip count of Scan with given scan_id.
281 
282     :param scan_id: ID of a Scan which should be returned
283     :return: boolean information whether the Scan was skipped or not
284     """
285     if not ScansRepository.increase_skip_count_of_a_scan(scan_id):
286         raise NotFoundException('Scan "{}" not found.'.format(scan_id))
287     return True
288
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/backend/medtagger/api/scans/business.py b/backend/medtagger/api/scans/business.py
--- a/backend/medtagger/api/scans/business.py
+++ b/backend/medtagger/api/scans/business.py
@@ -110,8 +110,8 @@
     :param elements: List of JSONs describing elements for a single label
     :param files: mapping of uploaded files (name and content)
     """
-    _validate_files(files)
     _validate_label_elements(elements, files)
+    _validate_files(files)
     _validate_tool(elements)

{"golden_diff": "diff --git a/backend/medtagger/api/scans/business.py b/backend/medtagger/api/scans/business.py\n--- a/backend/medtagger/api/scans/business.py\n+++ b/backend/medtagger/api/scans/business.py\n@@ -110,8 +110,8 @@\n     :param elements: List of JSONs describing elements for a single label\n     :param files: mapping of uploaded files (name and content)\n     \"\"\"\n-    _validate_files(files)\n     _validate_label_elements(elements, files)\n+    _validate_files(files)\n     _validate_tool(elements)\n", "issue": "Sending Label with Brush Selection doesn't work \n## Current Behavior\r\n\r\nSending Label with Brush Selection doesn't work.\r\n\r\n## Expected Behavior\r\n\r\nLabel with Brush Selection should be sent correctly.\r\n\r\n## Steps to Reproduce the Problem\r\n\r\n  1. Go to labeling page and use Brush Tool\r\n  2. Send label\r\n  3. \"Can't send scan\" appeared\r\n\r\n\n", "before_files": [{"content": "\"\"\"Module responsible for business logic in all Scans endpoints.\"\"\"\nimport io\nimport logging\nfrom typing import Callable, Iterable, Dict, List, Tuple, Any\n\nfrom cassandra import WriteTimeout\nfrom sqlalchemy.exc import IntegrityError\nfrom sqlalchemy.orm.exc import NoResultFound\nfrom PIL import Image\n\nfrom medtagger.exceptions import InternalErrorException\nfrom medtagger.api.exceptions import NotFoundException, InvalidArgumentsException\nfrom medtagger.types import ScanID, LabelPosition, LabelShape, LabelingTime, LabelID, Point\nfrom medtagger.database.models import Dataset, Scan, Slice, Label, LabelTag, SliceOrientation\nfrom medtagger.definitions import LabelTool\nfrom medtagger.repositories import (\n    labels as LabelsRepository,\n    label_tags as LabelTagsRepository,\n    slices as SlicesRepository,\n    scans as ScansRepository,\n    datasets as DatasetsRepository,\n    tasks as TasksRepository,\n)\nfrom medtagger.workers.storage import parse_dicom_and_update_slice\nfrom medtagger.api.utils import get_current_user\n\nlogger = logging.getLogger(__name__)\n\nLabelElementHandler = Callable[[Dict[str, Any], LabelID, Dict[str, bytes]], None]\n\n\ndef get_available_datasets() -> List[Dataset]:\n    \"\"\"Fetch list of all available Datasets.\n\n    :return: list of Datasets\n    \"\"\"\n    return DatasetsRepository.get_all_datasets()\n\n\ndef dataset_is_valid(dataset_key: str) -> bool:\n    \"\"\"Check if Dataset for such key exists.\n\n    :param dataset_key: key representing Dataset\n    :return: boolean information if Dataset key is valid\n    \"\"\"\n    try:\n        DatasetsRepository.get_dataset_by_key(dataset_key)\n        return True\n    except NoResultFound:\n        return False\n\n\ndef create_dataset(key: str, name: str) -> Dataset:\n    \"\"\"Create new Dataset.\n\n    :param key: unique key representing Dataset\n    :param name: name which describes this Dataset\n    :return: Dataset object\n    \"\"\"\n    return DatasetsRepository.add_new_dataset(key, name)\n\n\ndef create_empty_scan(dataset_key: str, declared_number_of_slices: int) -> Scan:\n    \"\"\"Create new empty scan.\n\n    :param dataset_key: string with dataset key\n    :param declared_number_of_slices: number of Slices that will be uploaded\n    :return: Newly created Scan object\n    \"\"\"\n    user = get_current_user()\n    dataset = DatasetsRepository.get_dataset_by_key(dataset_key)\n    return ScansRepository.add_new_scan(dataset, declared_number_of_slices, user)\n\n\ndef get_random_scan(task_key: str) -> Scan:\n    \"\"\"Fetch random scan from specified Task for labeling.\n\n    :param task_key: unique key identifying task\n    :return: Scan Metadata object\n    \"\"\"\n    user = get_current_user()\n    task = TasksRepository.get_task_by_key(task_key)\n    if not task:\n        raise InvalidArgumentsException('Task key {} is invalid!'.format(task_key))\n    scan = ScansRepository.get_random_scan(task, user)\n    if not scan:\n        raise NotFoundException('Could not find any Scan for this task!')\n    return scan\n\n\ndef get_slices_for_scan(scan_id: ScanID, begin: int, count: int,\n                        orientation: SliceOrientation = SliceOrientation.Z) -> Iterable[Tuple[Slice, bytes]]:\n    \"\"\"Fetch multiple slices for given scan.\n\n    :param scan_id: ID of a given scan\n    :param begin: first slice index (included)\n    :param count: number of slices that will be returned\n    :param orientation: orientation for Slices (by default set to Z axis)\n    :return: generator for Slices\n    \"\"\"\n    slices = SlicesRepository.get_slices_by_scan_id(scan_id, orientation=orientation)\n    for _slice in slices[begin:begin + count]:\n        image = SlicesRepository.get_slice_converted_image(_slice.id)\n        yield _slice, image\n\n\ndef validate_label_payload(elements: List[Dict], files: Dict[str, bytes]) -> None:\n    \"\"\"Validate and raise an Exception for sent payload.\n\n    :param elements: List of JSONs describing elements for a single label\n    :param files: mapping of uploaded files (name and content)\n    \"\"\"\n    _validate_files(files)\n    _validate_label_elements(elements, files)\n    _validate_tool(elements)\n\n\ndef _validate_tool(elements: List[Dict]) -> None:\n    \"\"\"Validate if the tool for given Label Element is available for given tag.\"\"\"\n    for label_element in elements:\n        tag = _get_label_tag(label_element['tag'])\n        if label_element['tool'] not in {tool.name for tool in tag.tools}:\n            raise InvalidArgumentsException('{} tool is not available for {} tag'.format(\n                label_element['tool'], tag.name))\n\n\ndef _validate_files(files: Dict[str, bytes]) -> None:\n    \"\"\"Validate files and make sure that images are PNGs.\"\"\"\n    for file_name, file_data in files.items():\n        try:\n            image = Image.open(io.BytesIO(file_data))\n            image.verify()\n            assert image.format == 'PNG'\n        except Exception:\n            raise InvalidArgumentsException('Type of file \"{}\" is not supported!'.format(file_name))\n\n\ndef _validate_label_elements(elements: List[Dict], files: Dict[str, bytes]) -> None:\n    \"\"\"Validate Label Elements and make sure that all Brush Elements have images.\"\"\"\n    for label_element in elements:\n        # Each Brush Label Element should have its own image attached\n        if label_element['tool'] == LabelTool.BRUSH.value:\n            try:\n                files[label_element['image_key']]\n            except KeyError:\n                message = 'Request does not have field named {} that could contain the image!'\n                raise InvalidArgumentsException(message.format(label_element['image_key']))\n\n\ndef add_label(scan_id: ScanID, task_key: str, elements: List[Dict],   # pylint: disable-msg=too-many-arguments\n              files: Dict[str, bytes], labeling_time: LabelingTime, comment: str = None) -> Label:\n    \"\"\"Add label to given scan.\n\n    :param scan_id: ID of a given scan\n    :param task_key: Key of Task\n    :param elements: List of JSONs describing elements for a single label\n    :param files: mapping of uploaded files (name and content)\n    :param labeling_time: time in seconds that user spent on labeling\n    :param comment: (optional) comment describing a label\n    :return: Label object\n    \"\"\"\n    user = get_current_user()\n    try:\n        label = LabelsRepository.add_new_label(scan_id, task_key, user, labeling_time, comment)\n    except IntegrityError:\n        raise NotFoundException('Could not find Scan for that id!')\n    for element in elements:\n        add_label_element(element, label.id, files)\n    return label\n\n\ndef add_label_element(element: Dict[str, Any], label_id: LabelID, files: Dict[str, bytes]) -> None:\n    \"\"\"Add new Label Element for given Label.\n\n    :param element: JSON describing single element\n    :param label_id: ID of a given Label that the element should be added to\n    :param files: mapping of uploaded files (name and content)\n    \"\"\"\n    tool = element['tool']\n    handlers: Dict[str, LabelElementHandler] = {\n        LabelTool.RECTANGLE.value: _add_rectangle_element,\n        LabelTool.BRUSH.value: _add_brush_element,\n        LabelTool.POINT.value: _add_point_element,\n        LabelTool.CHAIN.value: _add_chain_element,\n    }\n    handler = handlers[tool]\n    handler(element, label_id, files)\n\n\ndef _add_rectangle_element(element: Dict[str, Any], label_id: LabelID, *_: Any) -> None:\n    \"\"\"Add new Rectangular Label Element for given Label.\n\n    :param element: JSON describing single element\n    :param label_id: ID of a given Label that the element should be added to\n    \"\"\"\n    position = LabelPosition(x=element['x'], y=element['y'], slice_index=element['slice_index'])\n    shape = LabelShape(width=element['width'], height=element['height'])\n    label_tag = _get_label_tag(element['tag'])\n    LabelsRepository.add_new_rectangular_label_element(label_id, position, shape, label_tag)\n\n\ndef _add_brush_element(element: Dict[str, Any], label_id: LabelID, files: Dict[str, bytes]) -> None:\n    \"\"\"Add new Brush Label Element for given Label.\n\n    :param element: JSON describing single element\n    :param label_id: ID of a given Label that the element should be added to\n    :param files: mapping of uploaded files (name and content)\n    \"\"\"\n    width = element['width']\n    height = element['height']\n    label_tag = _get_label_tag(element['tag'])\n    slice_index = element['slice_index']\n    image = files[element['image_key']]\n    LabelsRepository.add_new_brush_label_element(label_id, slice_index, width, height, image, label_tag)\n\n\ndef _add_point_element(element: Dict[str, Any], label_id: LabelID, *_: Any) -> None:\n    \"\"\"Add new Point Label Element for given Label.\n\n    :param element: JSON describing single element\n    :param label_id: ID of a given Label that the element should be added to\n    \"\"\"\n    position = LabelPosition(x=element['x'], y=element['y'], slice_index=element['slice_index'])\n    label_tag = _get_label_tag(element['tag'])\n    LabelsRepository.add_new_point_label_element(label_id, position, label_tag)\n\n\ndef _add_chain_element(element: Dict[str, Any], label_id: LabelID, *_: Any) -> None:\n    \"\"\"Add new Chain Label Element for given Label.\n\n    :param element: JSON describing single element\n    :param label_id: ID of a given Label that the element should be added to\n    \"\"\"\n    label_tag = _get_label_tag(element['tag'])\n    points = [Point(p['x'], p['y']) for p in element['points']]\n    slice_index = element['slice_index']\n    loop = element['loop']\n    LabelsRepository.add_new_chain_label_element(label_id, slice_index, label_tag, points, loop)\n\n\ndef _get_label_tag(tag_key: str) -> LabelTag:\n    \"\"\"Return Label Tag based on Tag's key or raise an exception in case if not found.\"\"\"\n    try:\n        return LabelTagsRepository.get_label_tag_by_key(tag_key)\n    except NoResultFound:\n        raise NotFoundException('Could not find any Label Tag for that key!')\n\n\ndef add_new_slice(scan_id: ScanID, image: bytes) -> Slice:\n    \"\"\"Add new Slice for given Scan.\n\n    :param scan_id: ID of a Scan for which it should add new slice\n    :param image: bytes representing DICOM image\n    :return: Slice object\n    \"\"\"\n    scan = ScansRepository.get_scan_by_id(scan_id)\n    _slice = scan.add_slice()\n    try:\n        SlicesRepository.store_original_image(_slice.id, image)\n    except WriteTimeout:\n        SlicesRepository.delete_slice(_slice)\n        raise InternalErrorException('Timeout during saving original image to the Storage.')\n    parse_dicom_and_update_slice.delay(_slice.id)\n    return _slice\n\n\ndef get_scan(scan_id: ScanID) -> Scan:\n    \"\"\"Return Scan for given scan_id.\n\n    :param scan_id: ID of a Scan which should be returned\n    :return: Scan object\n    \"\"\"\n    try:\n        return ScansRepository.get_scan_by_id(scan_id)\n    except NoResultFound:\n        raise NotFoundException('Scan \"{}\" not found.'.format(scan_id))\n\n\ndef skip_scan(scan_id: ScanID) -> bool:\n    \"\"\"Increases skip count of Scan with given scan_id.\n\n    :param scan_id: ID of a Scan which should be returned\n    :return: boolean information whether the Scan was skipped or not\n    \"\"\"\n    if not ScansRepository.increase_skip_count_of_a_scan(scan_id):\n        raise NotFoundException('Scan \"{}\" not found.'.format(scan_id))\n    return True\n", "path": "backend/medtagger/api/scans/business.py"}], "after_files": [{"content": "\"\"\"Module responsible for business logic in all Scans endpoints.\"\"\"\nimport io\nimport logging\nfrom typing import Callable, Iterable, Dict, List, Tuple, Any\n\nfrom cassandra import WriteTimeout\nfrom sqlalchemy.exc import IntegrityError\nfrom sqlalchemy.orm.exc import NoResultFound\nfrom PIL import Image\n\nfrom medtagger.exceptions import InternalErrorException\nfrom medtagger.api.exceptions import NotFoundException, InvalidArgumentsException\nfrom medtagger.types import ScanID, LabelPosition, LabelShape, LabelingTime, LabelID, Point\nfrom medtagger.database.models import Dataset, Scan, Slice, Label, LabelTag, SliceOrientation\nfrom medtagger.definitions import LabelTool\nfrom medtagger.repositories import (\n    labels as LabelsRepository,\n    label_tags as LabelTagsRepository,\n    slices as SlicesRepository,\n    scans as ScansRepository,\n    datasets as DatasetsRepository,\n    tasks as TasksRepository,\n)\nfrom medtagger.workers.storage import parse_dicom_and_update_slice\nfrom medtagger.api.utils import get_current_user\n\nlogger = logging.getLogger(__name__)\n\nLabelElementHandler = Callable[[Dict[str, Any], LabelID, Dict[str, bytes]], None]\n\n\ndef get_available_datasets() -> List[Dataset]:\n    \"\"\"Fetch list of all available Datasets.\n\n    :return: list of Datasets\n    \"\"\"\n    return DatasetsRepository.get_all_datasets()\n\n\ndef dataset_is_valid(dataset_key: str) -> bool:\n    \"\"\"Check if Dataset for such key exists.\n\n    :param dataset_key: key representing Dataset\n    :return: boolean information if Dataset key is valid\n    \"\"\"\n    try:\n        DatasetsRepository.get_dataset_by_key(dataset_key)\n        return True\n    except NoResultFound:\n        return False\n\n\ndef create_dataset(key: str, name: str) -> Dataset:\n    \"\"\"Create new Dataset.\n\n    :param key: unique key representing Dataset\n    :param name: name which describes this Dataset\n    :return: Dataset object\n    \"\"\"\n    return DatasetsRepository.add_new_dataset(key, name)\n\n\ndef create_empty_scan(dataset_key: str, declared_number_of_slices: int) -> Scan:\n    \"\"\"Create new empty scan.\n\n    :param dataset_key: string with dataset key\n    :param declared_number_of_slices: number of Slices that will be uploaded\n    :return: Newly created Scan object\n    \"\"\"\n    user = get_current_user()\n    dataset = DatasetsRepository.get_dataset_by_key(dataset_key)\n    return ScansRepository.add_new_scan(dataset, declared_number_of_slices, user)\n\n\ndef get_random_scan(task_key: str) -> Scan:\n    \"\"\"Fetch random scan from specified Task for labeling.\n\n    :param task_key: unique key identifying task\n    :return: Scan Metadata object\n    \"\"\"\n    user = get_current_user()\n    task = TasksRepository.get_task_by_key(task_key)\n    if not task:\n        raise InvalidArgumentsException('Task key {} is invalid!'.format(task_key))\n    scan = ScansRepository.get_random_scan(task, user)\n    if not scan:\n        raise NotFoundException('Could not find any Scan for this task!')\n    return scan\n\n\ndef get_slices_for_scan(scan_id: ScanID, begin: int, count: int,\n                        orientation: SliceOrientation = SliceOrientation.Z) -> Iterable[Tuple[Slice, bytes]]:\n    \"\"\"Fetch multiple slices for given scan.\n\n    :param scan_id: ID of a given scan\n    :param begin: first slice index (included)\n    :param count: number of slices that will be returned\n    :param orientation: orientation for Slices (by default set to Z axis)\n    :return: generator for Slices\n    \"\"\"\n    slices = SlicesRepository.get_slices_by_scan_id(scan_id, orientation=orientation)\n    for _slice in slices[begin:begin + count]:\n        image = SlicesRepository.get_slice_converted_image(_slice.id)\n        yield _slice, image\n\n\ndef validate_label_payload(elements: List[Dict], files: Dict[str, bytes]) -> None:\n    \"\"\"Validate and raise an Exception for sent payload.\n\n    :param elements: List of JSONs describing elements for a single label\n    :param files: mapping of uploaded files (name and content)\n    \"\"\"\n    _validate_label_elements(elements, files)\n    _validate_files(files)\n    _validate_tool(elements)\n\n\ndef _validate_tool(elements: List[Dict]) -> None:\n    \"\"\"Validate if the tool for given Label Element is available for given tag.\"\"\"\n    for label_element in elements:\n        tag = _get_label_tag(label_element['tag'])\n        if label_element['tool'] not in {tool.name for tool in tag.tools}:\n            raise InvalidArgumentsException('{} tool is not available for {} tag'.format(\n                label_element['tool'], tag.name))\n\n\ndef _validate_files(files: Dict[str, bytes]) -> None:\n    \"\"\"Validate files and make sure that images are PNGs.\"\"\"\n    for file_name, file_data in files.items():\n        try:\n            image = Image.open(io.BytesIO(file_data))\n            image.verify()\n            assert image.format == 'PNG'\n        except Exception:\n            raise InvalidArgumentsException('Type of file \"{}\" is not supported!'.format(file_name))\n\n\ndef _validate_label_elements(elements: List[Dict], files: Dict[str, bytes]) -> None:\n    \"\"\"Validate Label Elements and make sure that all Brush Elements have images.\"\"\"\n    for label_element in elements:\n        # Each Brush Label Element should have its own image attached\n        if label_element['tool'] == LabelTool.BRUSH.value:\n            try:\n                files[label_element['image_key']]\n            except KeyError:\n                message = 'Request does not have field named {} that could contain the image!'\n                raise InvalidArgumentsException(message.format(label_element['image_key']))\n\n\ndef add_label(scan_id: ScanID, task_key: str, elements: List[Dict],   # pylint: disable-msg=too-many-arguments\n              files: Dict[str, bytes], labeling_time: LabelingTime, comment: str = None) -> Label:\n    \"\"\"Add label to given scan.\n\n    :param scan_id: ID of a given scan\n    :param task_key: Key of Task\n    :param elements: List of JSONs describing elements for a single label\n    :param files: mapping of uploaded files (name and content)\n    :param labeling_time: time in seconds that user spent on labeling\n    :param comment: (optional) comment describing a label\n    :return: Label object\n    \"\"\"\n    user = get_current_user()\n    try:\n        label = LabelsRepository.add_new_label(scan_id, task_key, user, labeling_time, comment)\n    except IntegrityError:\n        raise NotFoundException('Could not find Scan for that id!')\n    for element in elements:\n        add_label_element(element, label.id, files)\n    return label\n\n\ndef add_label_element(element: Dict[str, Any], label_id: LabelID, files: Dict[str, bytes]) -> None:\n    \"\"\"Add new Label Element for given Label.\n\n    :param element: JSON describing single element\n    :param label_id: ID of a given Label that the element should be added to\n    :param files: mapping of uploaded files (name and content)\n    \"\"\"\n    tool = element['tool']\n    handlers: Dict[str, LabelElementHandler] = {\n        LabelTool.RECTANGLE.value: _add_rectangle_element,\n        LabelTool.BRUSH.value: _add_brush_element,\n        LabelTool.POINT.value: _add_point_element,\n        LabelTool.CHAIN.value: _add_chain_element,\n    }\n    handler = handlers[tool]\n    handler(element, label_id, files)\n\n\ndef _add_rectangle_element(element: Dict[str, Any], label_id: LabelID, *_: Any) -> None:\n    \"\"\"Add new Rectangular Label Element for given Label.\n\n    :param element: JSON describing single element\n    :param label_id: ID of a given Label that the element should be added to\n    \"\"\"\n    position = LabelPosition(x=element['x'], y=element['y'], slice_index=element['slice_index'])\n    shape = LabelShape(width=element['width'], height=element['height'])\n    label_tag = _get_label_tag(element['tag'])\n    LabelsRepository.add_new_rectangular_label_element(label_id, position, shape, label_tag)\n\n\ndef _add_brush_element(element: Dict[str, Any], label_id: LabelID, files: Dict[str, bytes]) -> None:\n    \"\"\"Add new Brush Label Element for given Label.\n\n    :param element: JSON describing single element\n    :param label_id: ID of a given Label that the element should be added to\n    :param files: mapping of uploaded files (name and content)\n    \"\"\"\n    width = element['width']\n    height = element['height']\n    label_tag = _get_label_tag(element['tag'])\n    slice_index = element['slice_index']\n    image = files[element['image_key']]\n    LabelsRepository.add_new_brush_label_element(label_id, slice_index, width, height, image, label_tag)\n\n\ndef _add_point_element(element: Dict[str, Any], label_id: LabelID, *_: Any) -> None:\n    \"\"\"Add new Point Label Element for given Label.\n\n    :param element: JSON describing single element\n    :param label_id: ID of a given Label that the element should be added to\n    \"\"\"\n    position = LabelPosition(x=element['x'], y=element['y'], slice_index=element['slice_index'])\n    label_tag = _get_label_tag(element['tag'])\n    LabelsRepository.add_new_point_label_element(label_id, position, label_tag)\n\n\ndef _add_chain_element(element: Dict[str, Any], label_id: LabelID, *_: Any) -> None:\n    \"\"\"Add new Chain Label Element for given Label.\n\n    :param element: JSON describing single element\n    :param label_id: ID of a given Label that the element should be added to\n    \"\"\"\n    label_tag = _get_label_tag(element['tag'])\n    points = [Point(p['x'], p['y']) for p in element['points']]\n    slice_index = element['slice_index']\n    loop = element['loop']\n    LabelsRepository.add_new_chain_label_element(label_id, slice_index, label_tag, points, loop)\n\n\ndef _get_label_tag(tag_key: str) -> LabelTag:\n    \"\"\"Return Label Tag based on Tag's key or raise an exception in case if not found.\"\"\"\n    try:\n        return LabelTagsRepository.get_label_tag_by_key(tag_key)\n    except NoResultFound:\n        raise NotFoundException('Could not find any Label Tag for that key!')\n\n\ndef add_new_slice(scan_id: ScanID, image: bytes) -> Slice:\n    \"\"\"Add new Slice for given Scan.\n\n    :param scan_id: ID of a Scan for which it should add new slice\n    :param image: bytes representing DICOM image\n    :return: Slice object\n    \"\"\"\n    scan = ScansRepository.get_scan_by_id(scan_id)\n    _slice = scan.add_slice()\n    try:\n        SlicesRepository.store_original_image(_slice.id, image)\n    except WriteTimeout:\n        SlicesRepository.delete_slice(_slice)\n        raise InternalErrorException('Timeout during saving original image to the Storage.')\n    parse_dicom_and_update_slice.delay(_slice.id)\n    return _slice\n\n\ndef get_scan(scan_id: ScanID) -> Scan:\n    \"\"\"Return Scan for given scan_id.\n\n    :param scan_id: ID of a Scan which should be returned\n    :return: Scan object\n    \"\"\"\n    try:\n        return ScansRepository.get_scan_by_id(scan_id)\n    except NoResultFound:\n        raise NotFoundException('Scan \"{}\" not found.'.format(scan_id))\n\n\ndef skip_scan(scan_id: ScanID) -> bool:\n    \"\"\"Increases skip count of Scan with given scan_id.\n\n    :param scan_id: ID of a Scan which should be returned\n    :return: boolean information whether the Scan was skipped or not\n    \"\"\"\n    if not ScansRepository.increase_skip_count_of_a_scan(scan_id):\n        raise NotFoundException('Scan \"{}\" not found.'.format(scan_id))\n    return True\n", "path": "backend/medtagger/api/scans/business.py"}]}