Beispiel #1
0
 def get_by_id(cls, task_id: str) -> "Task":
     """Returns the task specified by the passed id (if your token authorizes you to see it)"""
     client = _get_generated_client(enforce_auth=True)
     response = task_info.sync(id=task_id, client=client)
     assert (response is not None
             ), f"Requesting task infos from {client.base_url} failed."
     return cls._from_generated_response(response)
    def __init__(
        self,
        organization_id: Optional[str],
        tags: Optional[Union[str, Sequence[str]]],
    ) -> None:
        from webknossos.administration.user import User
        from webknossos.client._generated.api.default import dataset_list
        from webknossos.client.context import _get_generated_client
        from webknossos.dataset.dataset import Dataset

        client = _get_generated_client(enforce_auth=True)

        if organization_id is None:
            organization_id = User.get_current_user().organization_id

        if isinstance(tags, str):
            tags = [tags]

        response = dataset_list.sync(client=client)
        assert response is not None

        ds_names = []

        for ds_info in response:
            tags_match = tags is None or any(tag in tags
                                             for tag in ds_info.tags)
            if ds_info.owning_organization == organization_id and tags_match:
                ds_names.append(ds_info.name)

        super().__init__(
            entries=dict(zip(ds_names, ds_names)),
            func=lambda name: Dataset.open_remote(name, organization_id),
        )
Beispiel #3
0
 def get_annotation_infos(self) -> List[AnnotationInfo]:
     """Returns AnnotationInfo objects describing all task instances that have been started by annotators for this task"""
     client = _get_generated_client(enforce_auth=True)
     response = annotation_infos_by_task_id.sync(id=self.task_id,
                                                 client=client)
     assert (
         response is not None
     ), f"Requesting annotation infos for task from {client.base_url} failed."
     return [AnnotationInfo._from_generated_response(a) for a in response]
Beispiel #4
0
 def get_by_name(cls, name: str) -> "Team":
     """Returns the Team specified by the passed name if your token authorizes you to see it."""
     client = _get_generated_client(enforce_auth=True)
     response = team_list.sync(client=client)
     assert response is not None, "Could not fetch teams."
     for team in response:
         if team.name == name:
             return cls(team.id, team.name, team.organization)
     raise KeyError(f"Could not find team {name}.")
Beispiel #5
0
    def create(
        cls,
        task_type_id: str,
        project_name: str,
        dataset_name: Union[str, RemoteDataset],
        needed_experience_domain: str,
        needed_experience_value: int,
        starting_position: Vec3Int,
        starting_rotation: Optional[Vec3Int] = Vec3Int(0, 0, 0),
        instances: int = 1,
        script_id: Optional[str] = None,
        bounding_box: Optional[BoundingBox] = None,
    ) -> List["Task"]:
        """Submits tasks in webKnossos based on a dataset, starting position + rotation, and returns the Task objects"""

        client = _get_generated_client(enforce_auth=True)
        url = f"{client.base_url}/api/tasks"
        if isinstance(dataset_name, RemoteDataset):
            dataset_name = dataset_name._dataset_name
        task_parameters = {
            "taskTypeId":
            task_type_id,
            "neededExperience": {
                "domain": needed_experience_domain,
                "value": needed_experience_value,
            },
            "openInstances":
            instances,
            "projectName":
            project_name,
            "scriptId":
            script_id,
            "dataSet":
            dataset_name,
            "editPosition":
            starting_position,
            "editRotation":
            starting_rotation,
            "boundingBox":
            bounding_box.to_wkw_dict() if bounding_box is not None else None,
        }

        response = httpx.post(
            url=url,
            headers=client.get_headers(),
            cookies=client.get_cookies(),
            timeout=client.get_timeout(),
            json=[task_parameters],
        )
        assert (
            response.status_code == 200
        ), f"Failed to create tasks: {response.status_code}: {response.text}"

        return cls._handle_task_creation_response(response)
Beispiel #6
0
    def create_from_annotations(
        cls,
        task_type_id: str,
        project_name: str,
        base_annotations: List[Annotation],
        needed_experience_domain: str,
        needed_experience_value: int,
        instances: int = 1,
        script_id: Optional[str] = None,
        bounding_box: Optional[BoundingBox] = None,
    ) -> List["Task"]:
        """Submits tasks in webKnossos based on existing annotations, and returns the Task objects"""

        assert (len(base_annotations) >
                0), "Must supply at least one base annotation to create tasks"

        client = _get_generated_client(enforce_auth=True)
        url = f"{client.base_url}/api/tasks/createFromFiles"
        task_parameters = {
            "taskTypeId":
            task_type_id,
            "neededExperience": {
                "domain": needed_experience_domain,
                "value": needed_experience_value,
            },
            "openInstances":
            instances,
            "projectName":
            project_name,
            "scriptId":
            script_id,
            "boundingBox":
            bounding_box.to_wkw_dict() if bounding_box is not None else None,
        }
        form_data = {"formJSON": json.dumps(task_parameters)}
        files: Mapping[str, Tuple[str, Union[bytes, BinaryIO]]] = {
            f"{a.name}.zip": (f"{a.name}.zip", a._binary_zip())
            for a in base_annotations
        }

        response = httpx.post(
            url=url,
            headers=client.get_headers(),
            cookies=client.get_cookies(),
            timeout=client.get_timeout(),
            data=form_data,
            files=files,
        )
        assert (
            response.status_code == 200
        ), f"Failed to create tasks from files: {response.status_code}: {response.text}"

        return cls._handle_task_creation_response(response)
Beispiel #7
0
 def get_logged_times(self) -> List["LoggedTime"]:
     """Get the logged times of this user.
     Returns a list of `LoggedTime` objects where one represents one month."""
     client = _get_generated_client(enforce_auth=True)
     response = user_logged_time.sync(id=self.user_id, client=client)
     assert response is not None, f"Could not fetch logged time of {self}"
     return [
         LoggedTime(
             duration_in_seconds=i.duration_in_seconds,
             month=i.payment_interval.month,
             year=i.payment_interval.year,
         ) for i in response.logged_time
     ]
Beispiel #8
0
    def get_tasks(self, fetch_all: bool = False) -> List["Task"]:
        """Returns the tasks of this project.
        Note: will fetch only the first 1000 entries by default, warns if that means some are missing.
        set parameter pass fetch_all=True to use pagination to fetch all tasks iteratively with pagination."""

        from webknossos.administration import Task

        PAGINATION_LIMIT = 1000
        pagination_page = 0

        client = _get_generated_client(enforce_auth=True)
        response_raw = task_infos_by_project_id.sync_detailed(
            self.project_id,
            limit=PAGINATION_LIMIT,
            page_number=pagination_page,
            include_total_count=True,
            client=client,
        )
        total_count_raw = response_raw.headers.get("X-Total-Count")
        assert total_count_raw is not None, "X-Total-Count header missing from response"
        total_count = int(total_count_raw)
        response = response_raw.parsed
        assert response is not None, "Could not fetch task infos by project id."
        all_tasks = [Task._from_generated_response(t) for t in response]
        if total_count > PAGINATION_LIMIT:
            if fetch_all:
                while total_count > len(all_tasks):
                    pagination_page += 1
                    response = task_infos_by_project_id.sync(
                        self.project_id,
                        limit=PAGINATION_LIMIT,
                        page_number=pagination_page,
                        include_total_count=False,
                        client=client,
                    )
                    assert (response is not None
                            ), "Could not fetch task infos by project id."
                    new_tasks = [
                        Task._from_generated_response(t) for t in response
                    ]
                    all_tasks.extend(new_tasks)

            else:
                warnings.warn(
                    f"Fetched only {PAGINATION_LIMIT} of {total_count} tasks. Pass fetch_all=True to fetch all tasks iteratively (may be slow!)"
                )

        return all_tasks
def test_dataset_info() -> None:
    with webknossos_context(url=DEFAULT_WEBKNOSSOS_URL):
        client = _get_generated_client()
    response = dataset_info.sync(
        organization_name="scalable_minds",
        data_set_name="l4dense_motta_et_al_demo",
        client=client,
    )
    assert response is not None
    assert response.data_store.url == DATASTORE_URL
    assert response.display_name == "L4 Mouse Cortex Demo"
    assert sorted((layer.name, layer.category, layer.element_class)
                  for layer in response.data_source.data_layers) == [
                      ("color", "color", "uint8"),
                      ("predictions", "color", "uint24"),
                      ("segmentation", "segmentation", "uint32"),
                  ]
Beispiel #10
0
    def upload(self) -> str:
        """Uploads the annotation to your current `webknossos_context`."""
        from webknossos.client.context import _get_generated_client

        client = _get_generated_client(enforce_auth=True)
        url = f"{client.base_url}/api/annotations/upload"

        response = httpx.post(
            url=url,
            headers=client.get_headers(),
            cookies=client.get_cookies(),
            timeout=client.get_timeout(),
            data={"createGroupForEachFile": False},
            files={
                f"{self.name}.zip": (f"{self.name}.zip", self._binary_zip()),
            },
        )
        assert (
            response.status_code == 200
        ), f"Failed to upload annotation {self.name}: {response.status_code}: {response.text}"
        response_annotation_info = response.json()["annotation"]
        return f"{client.base_url}/annotations/{response_annotation_info['typ']}/{response_annotation_info['id']}"
def auth_client() -> Client:
    return _get_generated_client(enforce_auth=True)
def client() -> Client:
    return _get_generated_client()
Beispiel #13
0
 def get_current_user(cls) -> "User":
     """Returns the current user from the authentication context."""
     client = _get_generated_client(enforce_auth=True)
     response = current_user_info.sync(client=client)
     assert response is not None, "Could not fetch current user."
     return cls._from_generated_response(response)
Beispiel #14
0
 def get_by_id(cls, id: str) -> "User":  # pylint: disable=redefined-builtin
     """Returns the user specified by the passed id if your token authorizes you to see them."""
     client = _get_generated_client(enforce_auth=True)
     response = user_info_by_id.sync(id, client=client)
     assert response is not None, "Could not fetch user by id."
     return cls._from_generated_response(response)
Beispiel #15
0
 def get_all_managed_users(cls) -> List["User"]:
     """Returns all users of whom the current user is admin or team-manager."""
     client = _get_generated_client(enforce_auth=True)
     response = user_list.sync(client=client)
     assert response is not None, "Could not fetch managed users."
     return [cls._from_generated_response(i) for i in response]
Beispiel #16
0
 def get_by_name(cls, name: str) -> "Project":
     """Returns the user specified by the passed name if your token authorizes you to see it."""
     client = _get_generated_client(enforce_auth=True)
     response = project_info_by_name.sync(name, client=client)
     assert response is not None, "Could not fetch project by name."
     return cls._from_generated_response(response)
def iterate_request_ids_with_responses() -> Iterable[Tuple[str, bytes]]:
    """Send requests to webKnossos and record the schema of their replies"""
    from webknossos.client._generated.api.default import (
        annotation_info,
        annotation_infos_by_task_id,
        build_info,
        current_user_info,
        dataset_info,
        dataset_list,
        dataset_sharing_token,
        datastore_list,
        generate_token_for_data_store,
        project_info_by_id,
        project_info_by_name,
        task_info,
        task_infos_by_project_id,
        team_list,
        user_info_by_id,
        user_list,
        user_logged_time,
    )
    from webknossos.client.context import _get_generated_client
    from webknossos.utils import snake_to_camel_case

    organization_id = "Organization_X"
    dataset_name = "e2006_knossos"
    task_id = "581367a82faeb37a008a5352"
    user_id = "570b9f4d2a7c0e4d008da6ef"
    project_id = "58135bfd2faeb3190181c057"
    project_name = "Test_Project"
    explorative_annotation_id = "58135c192faeb34c0081c05d"

    extract_200_response(
        httpx.post(
            url=f"{WK_URL}/data/triggers/checkInboxBlocking?token={WK_TOKEN}",
        ))
    response = httpx.get(
        url=f"{WK_URL}/api/datasets/{organization_id}/{dataset_name}",
        headers={"X-Auth-Token": f"{WK_TOKEN}"},
    )
    assert (
        response.status_code == 200 and response.json()["isActive"]
    ), f"You need to copy or link any dataset to binaryData/{organization_id}/{dataset_name}."

    d = datetime.utcnow()
    unixtime = calendar.timegm(d.utctimetuple())
    client = _get_generated_client(enforce_auth=True)

    yield (
        "annotationInfo",
        extract_200_response(
            annotation_info.sync_detailed(
                id=explorative_annotation_id,
                client=client,
                timestamp=unixtime,
            )),
    )

    yield (
        "datasetInfo",
        extract_200_response(
            dataset_info.sync_detailed(
                organization_name=organization_id,
                data_set_name=dataset_name,
                client=client,
            )),
    )

    yield (
        "datasetList",
        extract_200_response(dataset_list.sync_detailed(client=client, )),
    )

    yield (
        "datasetSharingToken",
        extract_200_response(
            dataset_sharing_token.sync_detailed(
                organization_name=organization_id,
                data_set_name=dataset_name,
                client=client,
            )),
    )

    yield (
        "taskInfo",
        extract_200_response(
            task_info.sync_detailed(
                id=task_id,
                client=client,
            ), ),
    )

    yield (
        "userInfoById",
        extract_200_response(
            user_info_by_id.sync_detailed(
                id=user_id,
                client=client,
            ), ),
    )

    yield (
        "teamList",
        extract_200_response(team_list.sync_detailed(client=client, ), ),
    )

    yield (
        "projectInfoById",
        extract_200_response(
            project_info_by_id.sync_detailed(
                id=project_id,
                client=client,
            ), ),
    )

    yield (
        "projectInfoByName",
        extract_200_response(
            project_info_by_name.sync_detailed(name=project_name,
                                               client=client), ),
    )

    yield (
        "taskInfosByProjectId",
        extract_200_response(
            task_infos_by_project_id.sync_detailed(
                id=project_id,
                client=client,
            ), ),
    )

    yield (
        "annotationInfosByTaskId",
        extract_200_response(
            annotation_infos_by_task_id.sync_detailed(id=task_id,
                                                      client=client), ),
    )

    yield (
        "userLoggedTime",
        extract_200_response(
            user_logged_time.sync_detailed(
                id=user_id,
                client=client,
            ), ),
    )

    for api_endpoint in [
            datastore_list,
            build_info,
            current_user_info,
            generate_token_for_data_store,
            user_list,
    ]:
        api_endpoint_name = api_endpoint.__name__.split(".")[-1]
        api_endpoint_name = snake_to_camel_case(api_endpoint_name)

        yield (
            api_endpoint_name,
            extract_200_response(api_endpoint.sync_detailed(client=client)),
        )
Beispiel #18
0
    def download(
        cls,
        annotation_id_or_url: str,
        annotation_type: Union[str, "AnnotationType", None] = None,
        webknossos_url: Optional[str] = None,
    ) -> "Annotation":
        """
        * `annotation_id_or_url` may be an annotation id or a full URL to an annotation, e.g.
          `https://webknossos.org/annotations/6114d9410100009f0096c640`
        * `annotation_type` is no longer required and therefore deprecated and ignored
        * `webknossos_url` may be supplied if an annotation id was used
          and allows to specifiy in which webknossos instance to search for the annotation.
          It defaults to the url from your current `webknossos_context`, using https://webknossos.org as a fallback.
        """
        from webknossos.client._generated.api.default import annotation_download
        from webknossos.client.context import (
            _get_context,
            _get_generated_client,
            webknossos_context,
        )

        match = re.match(_ANNOTATION_URL_REGEX, annotation_id_or_url)
        if match is not None:
            assert webknossos_url is None and annotation_type is None, (
                "When Annotation.download() is be called with an annotation url, "
                + "e.g. Annotation.download('https://webknossos.org/annotations/6114d9410100009f0096c640'), "
                + "annotation_type and webknossos_url must not be set."
            )
            annotation_id = match.group("annotation_id")
            webknossos_url = match.group("webknossos_url")
        else:
            annotation_id = annotation_id_or_url

        if annotation_type is not None:
            warnings.warn(
                "[DEPRECATION] `annotation_type` is deprecated for Annotation.download(), it should be omitted.",
                DeprecationWarning,
            )

        if webknossos_url is not None and webknossos_url != _get_context().url:
            warnings.warn(
                f"The supplied url {webknossos_url} does not match your current context {_get_context().url}. "
                + "Using no token, only public annotations can be downloaded. "
                + "Please see https://docs.webknossos.org/api/webknossos/client/context.html to adapt the URL and token."
            )
            context: ContextManager[None] = webknossos_context(
                webknossos_url, token=None
            )
        else:
            context = nullcontext()

        with context:
            client = _get_generated_client()
            response = annotation_download.sync_detailed(
                id=annotation_id, client=client
            )
        assert response.status_code == 200, response
        content_disposition_header = response.headers.get("content-disposition", "")
        _header_value, header_params = cgi.parse_header(content_disposition_header)
        filename = header_params.get("filename", "")
        if filename.endswith(".nml"):
            annotation, nml = Annotation._load_from_nml(
                filename[:-4], BytesIO(response.content)
            )
            assert (
                len(nml.volumes) == 0
            ), "The downloaded NML contains volume tags, it should have downloaded a zip instead."
            return annotation
        else:
            assert filename.endswith(
                ".zip"
            ), f"Downloaded annoation should have the suffix .zip or .nml, but has filename {filename}"
            return Annotation._load_from_zip(BytesIO(response.content))