Skip to content

Project module

Methods attached to the Kili client, to run actions on projects.

Source code in kili/presentation/client/project.py
class ProjectClientMethods(BaseClientMethods):
    """Methods attached to the Kili client, to run actions on projects."""

    @typechecked
    # pylint: disable=too-many-arguments
    def create_project(
        self,
        input_type: InputType,
        json_interface: Dict,
        title: str,
        description: str = "",
        project_type: Optional[ProjectType] = None,
        tags: Optional[ListOrTuple[str]] = None,
    ) -> Dict[Literal["id"], str]:
        # pylint: disable=line-too-long
        """Create a project.

        Args:
            input_type: Currently, one of `IMAGE`, `PDF`, `TEXT` or `VIDEO`.
            json_interface: The json parameters of the project, see Edit your interface.
            title: Title of the project.
            description: Description of the project.
            project_type: Currently, one of:

                - `IMAGE_CLASSIFICATION_MULTI`
                - `IMAGE_CLASSIFICATION_SINGLE`
                - `IMAGE_OBJECT_DETECTION_POLYGON`
                - `IMAGE_OBJECT_DETECTION_RECTANGLE`
                - `IMAGE_OBJECT_DETECTION_SEMANTIC`
                - `IMAGE_POSE_ESTIMATION`
                - `OCR`
                - `PDF_CLASSIFICATION_MULTI`
                - `PDF_CLASSIFICATION_SINGLE`
                - `PDF_NAMED_ENTITY_RECOGNITION`
                - `PDF_OBJECT_DETECTION_RECTANGLE`
                - `SPEECH_TO_TEXT`
                - `TEXT_CLASSIFICATION_MULTI`
                - `TEXT_CLASSIFICATION_SINGLE`
                - `TEXT_NER`
                - `TEXT_TRANSCRIPTION`
                - `TIME_SERIES`
                - `VIDEO_CLASSIFICATION_SINGLE`
                - `VIDEO_FRAME_CLASSIFICATION`
                - `VIDEO_FRAME_OBJECT_TRACKING`

            tags: Tags to add to the project. The tags must already exist in the organization.

        Returns:
            A dict with the id of the created project.

        Examples:
            >>> kili.create_project(input_type='IMAGE', json_interface=json_interface, title='Example')

        !!! example "Recipe"
            For more detailed examples on how to create projects,
                see [the recipe](https://docs.kili-technology.com/recipes/creating-a-project).
        """
        project_id = ProjectUseCases(self.kili_api_gateway).create_project(
            input_type=input_type,
            json_interface=json_interface,
            title=title,
            description=description,
            project_type=project_type,
        )

        if tags is not None:
            tag_use_cases = TagUseCases(self.kili_api_gateway)
            tag_ids = tag_use_cases.get_tag_ids_from_labels(labels=tags)
            tag_use_cases.tag_project(
                project_id=project_id, tag_ids=cast(ListOrTuple[TagId], tag_ids), disable_tqdm=True
            )

        return {"id": project_id}

    @overload
    # pylint: disable=too-many-arguments
    def projects(
        self,
        project_id: Optional[str] = None,
        search_query: Optional[str] = None,
        should_relaunch_kpi_computation: Optional[bool] = None,
        updated_at_gte: Optional[str] = None,
        updated_at_lte: Optional[str] = None,
        archived: Optional[bool] = None,
        starred: Optional[bool] = None,
        tags_in: Optional[ListOrTuple[str]] = None,
        fields: ListOrTuple[str] = (
            "consensusTotCoverage",
            "id",
            "inputType",
            "jsonInterface",
            "minConsensusSize",
            "reviewCoverage",
            "roles.id",
            "roles.role",
            "roles.user.email",
            "roles.user.id",
            "title",
        ),
        first: Optional[int] = None,
        skip: int = 0,
        disable_tqdm: Optional[bool] = None,
        *,
        as_generator: Literal[True],
    ) -> Generator[Dict, None, None]: ...

    @overload
    # pylint: disable=too-many-arguments
    def projects(
        self,
        project_id: Optional[str] = None,
        search_query: Optional[str] = None,
        should_relaunch_kpi_computation: Optional[bool] = None,
        updated_at_gte: Optional[str] = None,
        updated_at_lte: Optional[str] = None,
        archived: Optional[bool] = None,
        starred: Optional[bool] = None,
        tags_in: Optional[ListOrTuple[str]] = None,
        fields: ListOrTuple[str] = (
            "consensusTotCoverage",
            "id",
            "inputType",
            "jsonInterface",
            "minConsensusSize",
            "reviewCoverage",
            "roles.id",
            "roles.role",
            "roles.user.email",
            "roles.user.id",
            "title",
        ),
        first: Optional[int] = None,
        skip: int = 0,
        disable_tqdm: Optional[bool] = None,
        *,
        as_generator: Literal[False] = False,
    ) -> List[Dict]: ...

    @typechecked
    # pylint: disable=too-many-arguments,too-many-locals
    def projects(
        self,
        project_id: Optional[str] = None,
        search_query: Optional[str] = None,
        should_relaunch_kpi_computation: Optional[bool] = None,
        updated_at_gte: Optional[str] = None,
        updated_at_lte: Optional[str] = None,
        archived: Optional[bool] = None,
        starred: Optional[bool] = None,
        tags_in: Optional[ListOrTuple[str]] = None,
        fields: ListOrTuple[str] = (
            "consensusTotCoverage",
            "id",
            "inputType",
            "jsonInterface",
            "minConsensusSize",
            "reviewCoverage",
            "roles.id",
            "roles.role",
            "roles.user.email",
            "roles.user.id",
            "title",
        ),
        first: Optional[int] = None,
        skip: int = 0,
        disable_tqdm: Optional[bool] = None,
        *,
        as_generator: bool = False,
    ) -> Iterable[Dict]:
        # pylint: disable=line-too-long
        """Get a generator or a list of projects that match a set of criteria.

        Args:
            project_id: Select a specific project through its project_id.
            search_query: Returned projects with a title or a description matching this [PostgreSQL ILIKE](https://www.postgresql.org/docs/current/functions-matching.html#FUNCTIONS-LIKE) pattern.
            should_relaunch_kpi_computation: Deprecated, do not use.
            updated_at_gte: Returned projects should have a label whose update date is greater or equal
                to this date.
            updated_at_lte: Returned projects should have a label whose update date is lower or equal to this date.
            archived: If `True`, only archived projects are returned, if `False`, only active projects are returned.
                `None` disables this filter.
            starred: If `True`, only starred projects are returned, if `False`, only unstarred projects are returned.
                `None` disables this filter.
            tags_in: Returned projects should have at least one of these tags.
            fields: All the fields to request among the possible fields for the projects.
                See [the documentation](https://docs.kili-technology.com/reference/graphql-api#project) for all possible fields.
            first: Maximum number of projects to return.
            skip: Number of projects to skip (they are ordered by their creation).
            disable_tqdm: If `True`, the progress bar will be disabled.
            as_generator: If `True`, a generator on the projects is returned.

        !!! info "Dates format"
            Date strings should have format: "YYYY-MM-DD"

        Returns:
            A list of projects or a generator of projects if `as_generator` is `True`.

        Examples:
            >>> # List all my projects
            >>> kili.projects()
        """
        tag_ids = (
            TagUseCases(self.kili_api_gateway).get_tag_ids_from_labels(tags_in) if tags_in else None
        )

        projects_gen = ProjectUseCases(self.kili_api_gateway).list_projects(
            ProjectFilters(
                id=ProjectId(project_id) if project_id else None,
                archived=archived,
                search_query=search_query,
                should_relaunch_kpi_computation=should_relaunch_kpi_computation,
                starred=starred,
                updated_at_gte=updated_at_gte,
                updated_at_lte=updated_at_lte,
                created_at_gte=None,
                created_at_lte=None,
                tag_ids=tag_ids,
            ),
            fields,
            first,
            skip,
            disable_tqdm,
        )

        if as_generator:
            return projects_gen
        return list(projects_gen)

create_project(self, input_type, json_interface, title, description='', project_type=None, tags=None)

Create a project.

Parameters:

Name Type Description Default
input_type Literal['IMAGE', 'PDF', 'TEXT', 'VIDEO', 'VIDEO_LEGACY']

Currently, one of IMAGE, PDF, TEXT or VIDEO.

required
json_interface Dict

The json parameters of the project, see Edit your interface.

required
title str

Title of the project.

required
description str

Description of the project.

''
project_type Optional[Literal['IMAGE_CLASSIFICATION_SINGLE', 'IMAGE_CLASSIFICATION_MULTI', 'IMAGE_OBJECT_DETECTION_RECTANGLE', 'IMAGE_OBJECT_DETECTION_POLYGON', 'IMAGE_OBJECT_DETECTION_SEMANTIC', 'IMAGE_POSE_ESTIMATION', 'OCR', 'PDF_CLASSIFICATION_SINGLE', 'PDF_CLASSIFICATION_MULTI', 'PDF_OBJECT_DETECTION_RECTANGLE', 'PDF_NAMED_ENTITY_RECOGNITION', 'SPEECH_TO_TEXT', 'TEXT_CLASSIFICATION_SINGLE', 'TEXT_CLASSIFICATION_MULTI', 'TEXT_TRANSCRIPTION', 'TEXT_NER', 'TIME_SERIES', 'VIDEO_CLASSIFICATION_SINGLE', 'VIDEO_OBJECT_DETECTION', 'VIDEO_FRAME_CLASSIFICATION', 'VIDEO_FRAME_OBJECT_TRACKING']]

Currently, one of:

  • IMAGE_CLASSIFICATION_MULTI
  • IMAGE_CLASSIFICATION_SINGLE
  • IMAGE_OBJECT_DETECTION_POLYGON
  • IMAGE_OBJECT_DETECTION_RECTANGLE
  • IMAGE_OBJECT_DETECTION_SEMANTIC
  • IMAGE_POSE_ESTIMATION
  • OCR
  • PDF_CLASSIFICATION_MULTI
  • PDF_CLASSIFICATION_SINGLE
  • PDF_NAMED_ENTITY_RECOGNITION
  • PDF_OBJECT_DETECTION_RECTANGLE
  • SPEECH_TO_TEXT
  • TEXT_CLASSIFICATION_MULTI
  • TEXT_CLASSIFICATION_SINGLE
  • TEXT_NER
  • TEXT_TRANSCRIPTION
  • TIME_SERIES
  • VIDEO_CLASSIFICATION_SINGLE
  • VIDEO_FRAME_CLASSIFICATION
  • VIDEO_FRAME_OBJECT_TRACKING
None
tags Union[List[str], Tuple[str, ...]]

Tags to add to the project. The tags must already exist in the organization.

None

Returns:

Type Description
Dict[Literal['id'], str]

A dict with the id of the created project.

Examples:

>>> kili.create_project(input_type='IMAGE', json_interface=json_interface, title='Example')

Recipe

For more detailed examples on how to create projects, see the recipe.

Source code in kili/presentation/client/project.py
@typechecked
# pylint: disable=too-many-arguments
def create_project(
    self,
    input_type: InputType,
    json_interface: Dict,
    title: str,
    description: str = "",
    project_type: Optional[ProjectType] = None,
    tags: Optional[ListOrTuple[str]] = None,
) -> Dict[Literal["id"], str]:
    # pylint: disable=line-too-long
    """Create a project.

    Args:
        input_type: Currently, one of `IMAGE`, `PDF`, `TEXT` or `VIDEO`.
        json_interface: The json parameters of the project, see Edit your interface.
        title: Title of the project.
        description: Description of the project.
        project_type: Currently, one of:

            - `IMAGE_CLASSIFICATION_MULTI`
            - `IMAGE_CLASSIFICATION_SINGLE`
            - `IMAGE_OBJECT_DETECTION_POLYGON`
            - `IMAGE_OBJECT_DETECTION_RECTANGLE`
            - `IMAGE_OBJECT_DETECTION_SEMANTIC`
            - `IMAGE_POSE_ESTIMATION`
            - `OCR`
            - `PDF_CLASSIFICATION_MULTI`
            - `PDF_CLASSIFICATION_SINGLE`
            - `PDF_NAMED_ENTITY_RECOGNITION`
            - `PDF_OBJECT_DETECTION_RECTANGLE`
            - `SPEECH_TO_TEXT`
            - `TEXT_CLASSIFICATION_MULTI`
            - `TEXT_CLASSIFICATION_SINGLE`
            - `TEXT_NER`
            - `TEXT_TRANSCRIPTION`
            - `TIME_SERIES`
            - `VIDEO_CLASSIFICATION_SINGLE`
            - `VIDEO_FRAME_CLASSIFICATION`
            - `VIDEO_FRAME_OBJECT_TRACKING`

        tags: Tags to add to the project. The tags must already exist in the organization.

    Returns:
        A dict with the id of the created project.

    Examples:
        >>> kili.create_project(input_type='IMAGE', json_interface=json_interface, title='Example')

    !!! example "Recipe"
        For more detailed examples on how to create projects,
            see [the recipe](https://docs.kili-technology.com/recipes/creating-a-project).
    """
    project_id = ProjectUseCases(self.kili_api_gateway).create_project(
        input_type=input_type,
        json_interface=json_interface,
        title=title,
        description=description,
        project_type=project_type,
    )

    if tags is not None:
        tag_use_cases = TagUseCases(self.kili_api_gateway)
        tag_ids = tag_use_cases.get_tag_ids_from_labels(labels=tags)
        tag_use_cases.tag_project(
            project_id=project_id, tag_ids=cast(ListOrTuple[TagId], tag_ids), disable_tqdm=True
        )

    return {"id": project_id}

projects(self, project_id=None, search_query=None, should_relaunch_kpi_computation=None, updated_at_gte=None, updated_at_lte=None, archived=None, starred=None, tags_in=None, fields=('consensusTotCoverage', 'id', 'inputType', 'jsonInterface', 'minConsensusSize', 'reviewCoverage', 'roles.id', 'roles.role', 'roles.user.email', 'roles.user.id', 'title'), first=None, skip=0, disable_tqdm=None, *, as_generator=False)

Get a generator or a list of projects that match a set of criteria.

Parameters:

Name Type Description Default
project_id Optional[str]

Select a specific project through its project_id.

None
search_query Optional[str]

Returned projects with a title or a description matching this PostgreSQL ILIKE pattern.

None
should_relaunch_kpi_computation Optional[bool]

Deprecated, do not use.

None
updated_at_gte Optional[str]

Returned projects should have a label whose update date is greater or equal to this date.

None
updated_at_lte Optional[str]

Returned projects should have a label whose update date is lower or equal to this date.

None
archived Optional[bool]

If True, only archived projects are returned, if False, only active projects are returned. None disables this filter.

None
starred Optional[bool]

If True, only starred projects are returned, if False, only unstarred projects are returned. None disables this filter.

None
tags_in Union[List[str], Tuple[str, ...]]

Returned projects should have at least one of these tags.

None
fields Union[List[str], Tuple[str, ...]]

All the fields to request among the possible fields for the projects. See the documentation for all possible fields.

('consensusTotCoverage', 'id', 'inputType', 'jsonInterface', 'minConsensusSize', 'reviewCoverage', 'roles.id', 'roles.role', 'roles.user.email', 'roles.user.id', 'title')
first Optional[int]

Maximum number of projects to return.

None
skip int

Number of projects to skip (they are ordered by their creation).

0
disable_tqdm Optional[bool]

If True, the progress bar will be disabled.

None
as_generator bool

If True, a generator on the projects is returned.

False

Dates format

Date strings should have format: "YYYY-MM-DD"

Returns:

Type Description
Iterable[Dict]

A list of projects or a generator of projects if as_generator is True.

Examples:

>>> # List all my projects
>>> kili.projects()
Source code in kili/presentation/client/project.py
@typechecked
# pylint: disable=too-many-arguments,too-many-locals
def projects(
    self,
    project_id: Optional[str] = None,
    search_query: Optional[str] = None,
    should_relaunch_kpi_computation: Optional[bool] = None,
    updated_at_gte: Optional[str] = None,
    updated_at_lte: Optional[str] = None,
    archived: Optional[bool] = None,
    starred: Optional[bool] = None,
    tags_in: Optional[ListOrTuple[str]] = None,
    fields: ListOrTuple[str] = (
        "consensusTotCoverage",
        "id",
        "inputType",
        "jsonInterface",
        "minConsensusSize",
        "reviewCoverage",
        "roles.id",
        "roles.role",
        "roles.user.email",
        "roles.user.id",
        "title",
    ),
    first: Optional[int] = None,
    skip: int = 0,
    disable_tqdm: Optional[bool] = None,
    *,
    as_generator: bool = False,
) -> Iterable[Dict]:
    # pylint: disable=line-too-long
    """Get a generator or a list of projects that match a set of criteria.

    Args:
        project_id: Select a specific project through its project_id.
        search_query: Returned projects with a title or a description matching this [PostgreSQL ILIKE](https://www.postgresql.org/docs/current/functions-matching.html#FUNCTIONS-LIKE) pattern.
        should_relaunch_kpi_computation: Deprecated, do not use.
        updated_at_gte: Returned projects should have a label whose update date is greater or equal
            to this date.
        updated_at_lte: Returned projects should have a label whose update date is lower or equal to this date.
        archived: If `True`, only archived projects are returned, if `False`, only active projects are returned.
            `None` disables this filter.
        starred: If `True`, only starred projects are returned, if `False`, only unstarred projects are returned.
            `None` disables this filter.
        tags_in: Returned projects should have at least one of these tags.
        fields: All the fields to request among the possible fields for the projects.
            See [the documentation](https://docs.kili-technology.com/reference/graphql-api#project) for all possible fields.
        first: Maximum number of projects to return.
        skip: Number of projects to skip (they are ordered by their creation).
        disable_tqdm: If `True`, the progress bar will be disabled.
        as_generator: If `True`, a generator on the projects is returned.

    !!! info "Dates format"
        Date strings should have format: "YYYY-MM-DD"

    Returns:
        A list of projects or a generator of projects if `as_generator` is `True`.

    Examples:
        >>> # List all my projects
        >>> kili.projects()
    """
    tag_ids = (
        TagUseCases(self.kili_api_gateway).get_tag_ids_from_labels(tags_in) if tags_in else None
    )

    projects_gen = ProjectUseCases(self.kili_api_gateway).list_projects(
        ProjectFilters(
            id=ProjectId(project_id) if project_id else None,
            archived=archived,
            search_query=search_query,
            should_relaunch_kpi_computation=should_relaunch_kpi_computation,
            starred=starred,
            updated_at_gte=updated_at_gte,
            updated_at_lte=updated_at_lte,
            created_at_gte=None,
            created_at_lte=None,
            tag_ids=tag_ids,
        ),
        fields,
        first,
        skip,
        disable_tqdm,
    )

    if as_generator:
        return projects_gen
    return list(projects_gen)

Set of Project queries.

Source code in kili/entrypoints/queries/project/__init__.py
class QueriesProject(BaseOperationEntrypointMixin):
    """Set of Project queries."""

    # pylint: disable=too-many-arguments

    @typechecked
    def count_projects(
        self,
        project_id: Optional[str] = None,
        search_query: Optional[str] = None,
        should_relaunch_kpi_computation: Optional[bool] = None,
        updated_at_gte: Optional[str] = None,
        updated_at_lte: Optional[str] = None,
        archived: Optional[bool] = None,
    ) -> int:
        # pylint: disable=line-too-long
        """Count the number of projects with a search_query.

        Args:
            project_id: Select a specific project through its project_id.
            search_query: Returned projects with a title or a description matching this [PostgreSQL ILIKE](https://www.postgresql.org/docs/current/functions-matching.html#FUNCTIONS-LIKE) pattern.
            should_relaunch_kpi_computation: Technical field, added to indicate changes in honeypot
                or consensus settings
            updated_at_gte: Returned projects should have a label
                whose update date is greater
                or equal to this date.
            updated_at_lte: Returned projects should have a label
                whose update date is lower or equal to this date.
            archived: If `True`, only archived projects are returned, if `False`, only active projects are returned.
                None disable this filter.

        !!! info "Dates format"
            Date strings should have format: "YYYY-MM-DD"

        Returns:
            The number of projects with the parameters provided
        """
        where = ProjectWhere(
            project_id=project_id,
            search_query=search_query,
            should_relaunch_kpi_computation=should_relaunch_kpi_computation,
            updated_at_gte=updated_at_gte,
            updated_at_lte=updated_at_lte,
            archived=archived,
        )
        return ProjectQuery(self.graphql_client, self.http_client).count(where)

count_projects(self, project_id=None, search_query=None, should_relaunch_kpi_computation=None, updated_at_gte=None, updated_at_lte=None, archived=None)

Count the number of projects with a search_query.

Parameters:

Name Type Description Default
project_id Optional[str]

Select a specific project through its project_id.

None
search_query Optional[str]

Returned projects with a title or a description matching this PostgreSQL ILIKE pattern.

None
should_relaunch_kpi_computation Optional[bool]

Technical field, added to indicate changes in honeypot or consensus settings

None
updated_at_gte Optional[str]

Returned projects should have a label whose update date is greater or equal to this date.

None
updated_at_lte Optional[str]

Returned projects should have a label whose update date is lower or equal to this date.

None
archived Optional[bool]

If True, only archived projects are returned, if False, only active projects are returned. None disable this filter.

None

Dates format

Date strings should have format: "YYYY-MM-DD"

Returns:

Type Description
int

The number of projects with the parameters provided

Source code in kili/entrypoints/queries/project/__init__.py
@typechecked
def count_projects(
    self,
    project_id: Optional[str] = None,
    search_query: Optional[str] = None,
    should_relaunch_kpi_computation: Optional[bool] = None,
    updated_at_gte: Optional[str] = None,
    updated_at_lte: Optional[str] = None,
    archived: Optional[bool] = None,
) -> int:
    # pylint: disable=line-too-long
    """Count the number of projects with a search_query.

    Args:
        project_id: Select a specific project through its project_id.
        search_query: Returned projects with a title or a description matching this [PostgreSQL ILIKE](https://www.postgresql.org/docs/current/functions-matching.html#FUNCTIONS-LIKE) pattern.
        should_relaunch_kpi_computation: Technical field, added to indicate changes in honeypot
            or consensus settings
        updated_at_gte: Returned projects should have a label
            whose update date is greater
            or equal to this date.
        updated_at_lte: Returned projects should have a label
            whose update date is lower or equal to this date.
        archived: If `True`, only archived projects are returned, if `False`, only active projects are returned.
            None disable this filter.

    !!! info "Dates format"
        Date strings should have format: "YYYY-MM-DD"

    Returns:
        The number of projects with the parameters provided
    """
    where = ProjectWhere(
        project_id=project_id,
        search_query=search_query,
        should_relaunch_kpi_computation=should_relaunch_kpi_computation,
        updated_at_gte=updated_at_gte,
        updated_at_lte=updated_at_lte,
        archived=archived,
    )
    return ProjectQuery(self.graphql_client, self.http_client).count(where)

Set of Project mutations.

Source code in kili/entrypoints/mutations/project/__init__.py
class MutationsProject(BaseOperationEntrypointMixin):
    """Set of Project mutations."""

    # pylint: disable=too-many-arguments,too-many-locals
    @typechecked
    def append_to_roles(
        self,
        project_id: str,
        user_email: str,
        role: Literal["ADMIN", "TEAM_MANAGER", "REVIEWER", "LABELER"] = "LABELER",
    ) -> Dict:
        """Add a user to a project.

        !!! info
            If the user does not exist in your organization, he/she is invited and added
                both to your organization and project. This function can also be used to change
                the role of the user in the project.

        Args:
            project_id: Identifier of the project
            user_email: The email of the user.
                This email is used as the unique identifier of the user.
            role: The role of the user.

        Returns:
            A dictionary with the project user information.


        Examples:
            >>> kili.append_to_roles(project_id=project_id, user_email='john@doe.com')
        """
        variables = {
            "data": {"role": role, "userEmail": user_email},
            "where": {"id": project_id},
        }
        result = self.graphql_client.execute(GQL_APPEND_TO_ROLES, variables)

        project_data = self.format_result("data", result)
        for project_user in project_data["roles"]:
            if project_user["user"]["email"] == user_email.lower() and project_user["role"] == role:
                return project_user

        raise MutationError(
            f"Failed to mutate user {user_email} to role {role} for project {project_id}."
        )

    @typechecked
    def update_properties_in_project(
        self,
        project_id: str,
        can_navigate_between_assets: Optional[bool] = None,
        can_skip_asset: Optional[bool] = None,
        consensus_mark: Optional[float] = None,
        consensus_tot_coverage: Optional[int] = None,
        description: Optional[str] = None,
        honeypot_mark: Optional[float] = None,
        instructions: Optional[str] = None,
        input_type: Optional[str] = None,
        json_interface: Optional[dict] = None,
        min_consensus_size: Optional[int] = None,
        number_of_assets: Optional[int] = None,
        number_of_skipped_assets: Optional[int] = None,
        number_of_remaining_assets: Optional[int] = None,
        number_of_reviewed_assets: Optional[int] = None,
        review_coverage: Optional[int] = None,
        should_relaunch_kpi_computation: Optional[bool] = None,
        title: Optional[str] = None,
        use_honeypot: Optional[bool] = None,
        metadata_types: Optional[dict] = None,
    ) -> Dict[str, Any]:
        """Update properties of a project.

        Args:
            project_id: Identifier of the project.
            can_navigate_between_assets:
                Activate / Deactivate the use of next and previous buttons in labeling interface.
            can_skip_asset: Activate / Deactivate the use of skip button in labeling interface.
            consensus_mark: Should be between 0 and 1.
            consensus_tot_coverage: Should be between 0 and 100.
                It is the percentage of the dataset that will be annotated several times.
            description: Description of the project.
            honeypot_mark: Should be between 0 and 1
            instructions: Instructions of the project.
            input_type: Currently, one of `IMAGE`, `PDF`, `TEXT` or `VIDEO`.
            json_interface: The json parameters of the project, see Edit your interface.
            min_consensus_size: Should be between 1 and 10
                Number of people that will annotate the same asset, for consensus computation.
            number_of_assets: Defaults to 0
            number_of_skipped_assets: Defaults to 0
            number_of_remaining_assets: Defaults to 0
            number_of_reviewed_assets: Defaults to 0
            review_coverage: Allow to set the percentage of assets
                that will be queued in the review interface.
                Should be between 0 and 100
            should_relaunch_kpi_computation: Technical field, added to indicate changes
                in honeypot or consensus settings
            title: Title of the project
            use_honeypot: Activate / Deactivate the use of honeypot in the project
            metadata_types: Types of the project metadata.
                Should be a `dict` of metadata fields name as keys and metadata types as values.
                Currently, possible types are: `string`, `number`

        Returns:
            A dict with the changed properties which indicates if the mutation was successful,
                else an error message.

        !!! example "Change Metadata Types"
            Metadata fields are by default interpreted as `string` types. To change the type
            of a metadata field, you can use the `update_properties_in_project` function with the
            metadata_types argument. `metadata_types` is given as a dict of metadata field names
            as keys and metadata types as values.

            ```python
            kili.update_properties_in_project(
                project_id = project_id,
                metadata_types = {
                    'customConsensus': 'number',
                    'sensitiveData': 'string',
                    'uploadedFromCloud': 'string',
                    'modelLabelErrorScore': 'number'
                }
            )
            ```

            Not providing a type for a metadata field or providing an unsupported one
            will default to the `string` type.
        """
        verify_argument_ranges(consensus_tot_coverage, min_consensus_size, review_coverage)

        variables = {
            "canNavigateBetweenAssets": can_navigate_between_assets,
            "canSkipAsset": can_skip_asset,
            "consensusMark": consensus_mark,
            "consensusTotCoverage": consensus_tot_coverage,
            "description": description,
            "honeypotMark": honeypot_mark,
            "instructions": instructions,
            "inputType": input_type,
            "jsonInterface": dumps(json_interface) if json_interface is not None else None,
            "metadataTypes": metadata_types,
            "minConsensusSize": min_consensus_size,
            "numberOfAssets": number_of_assets,
            "numberOfSkippedAssets": number_of_skipped_assets,
            "numberOfRemainingAssets": number_of_remaining_assets,
            "numberOfReviewedAssets": number_of_reviewed_assets,
            "projectID": project_id,
            "reviewCoverage": review_coverage,
            "shouldRelaunchKpiComputation": should_relaunch_kpi_computation,
            "title": title,
            "useHoneyPot": use_honeypot,
        }
        result = self.graphql_client.execute(GQL_UPDATE_PROPERTIES_IN_PROJECT, variables)
        result = self.format_result("data", result)

        variables.pop("projectID")
        variables = {k: v for k, v in variables.items() if v is not None}

        new_project_settings = get_project(self, project_id, list(variables.keys()))

        return {**result, **new_project_settings}

    @typechecked
    def update_properties_in_role(
        self, role_id: str, project_id: str, user_id: str, role: str
    ) -> Dict:
        """Update properties of a role.

        !!! info
            To be able to change someone's role, you must be either of:

            - an admin of the project
            - a team manager of the project
            - an admin of the organization

        Args:
            role_id: Role identifier of the user. E.g. : 'to-be-deactivated'
            project_id: Identifier of the project
            user_id: The email or identifier of the user with updated role
            role: The new role.
                Possible choices are: `ADMIN`, `TEAM_MANAGER`, `REVIEWER`, `LABELER`

        Returns:
            A dictionary with the project user information.
        """
        variables = {
            "roleID": role_id,
            "projectID": project_id,
            "userID": user_id,
            "role": role,
        }
        result = self.graphql_client.execute(GQL_UPDATE_PROPERTIES_IN_ROLE, variables)
        return self.format_result("data", result)

    @typechecked
    def delete_from_roles(self, role_id: str) -> Dict[Literal["id"], str]:
        """Delete users by their role_id.

        Args:
            role_id: Identifier of the project user (not the ID of the user)

        Returns:
            A dict with the project id.
        """
        variables = {"where": {"id": role_id}}
        result = self.graphql_client.execute(GQL_DELETE_FROM_ROLES, variables)
        return self.format_result("data", result)

    @typechecked
    def delete_project(self, project_id: str) -> str:
        """Delete a project permanently.

        Args:
            project_id: Identifier of the project

        Returns:
            A string with the deleted project id.
        """
        variables = {"where": {"id": project_id}}
        result = self.graphql_client.execute(GQL_PROJECT_DELETE_ASYNCHRONOUSLY, variables)
        return self.format_result("data", result)

    @typechecked
    def archive_project(self, project_id: str) -> Dict[Literal["id"], str]:
        """Archive a project.

        Args:
            project_id: Identifier of the project.

        Returns:
            A dict with the id of the project.
        """
        variables = {
            "projectID": project_id,
            "archived": True,
        }

        result = self.graphql_client.execute(GQL_UPDATE_PROPERTIES_IN_PROJECT, variables)

        return self.format_result("data", result)

    @typechecked
    def unarchive_project(self, project_id: str) -> Dict[Literal["id"], str]:
        """Unarchive a project.

        Args:
            project_id: Identifier of the project

        Returns:
            A dict with the id of the project.
        """
        variables = {
            "projectID": project_id,
            "archived": False,
        }

        result = self.graphql_client.execute(GQL_UPDATE_PROPERTIES_IN_PROJECT, variables)
        return self.format_result("data", result)

    @typechecked
    def copy_project(  # pylint: disable=too-many-arguments
        self,
        from_project_id: str,
        title: Optional[str] = None,
        description: Optional[str] = None,
        copy_json_interface: bool = True,
        copy_quality_settings: bool = True,
        copy_members: bool = True,
        copy_assets: bool = False,
        copy_labels: bool = False,
        disable_tqdm: Optional[bool] = None,
    ) -> str:
        """Create new project from an existing project.

        Args:
            from_project_id: Project ID to copy from.
            title: Title for the new project. Defaults to source project
                title if `None` is provided.
            description: Description for the new project. Defaults to empty string
                if `None` is provided.
            copy_json_interface: Include json interface in the copy.
            copy_quality_settings: Include quality settings in the copy.
            copy_members: Include members in the copy.
            copy_assets: Include assets in the copy.
            copy_labels: Include labels in the copy.
            disable_tqdm: Disable tqdm progress bars.

        Returns:
            The created project ID.

        Examples:
            >>> kili.copy_project(from_project_id="clbqn56b331234567890l41c0")
        """
        return ProjectCopier(self).copy_project(
            from_project_id,
            title,
            description,
            copy_json_interface,
            copy_quality_settings,
            copy_members,
            copy_assets,
            copy_labels,
            disable_tqdm,
        )

    @typechecked
    def update_project_anonymization(
        self, project_id: str, should_anonymize: bool = True
    ) -> Dict[Literal["id"], str]:
        """Anonymize the project for the labelers and reviewers.

        !!! info
            Compatible with versions of the Kili app >= 2.135.0

        Args:
            project_id: Identifier of the project
            should_anonymize: The value to be applied. Defaults to `True`.

        Returns:
            A dict with the id of the project which indicates if the mutation was successful,
                or an error message.

        Examples:
            >>> kili.update_project_anonymization(project_id=project_id)
            >>> kili.update_project_anonymization(project_id=project_id, should_anonymize=False)
        """
        variables = {
            "input": {
                "id": project_id,
                "shouldAnonymize": should_anonymize,
            }
        }

        result = self.graphql_client.execute(GQL_PROJECT_UPDATE_ANONYMIZATION, variables)
        return self.format_result("data", result)

append_to_roles(self, project_id, user_email, role='LABELER')

Add a user to a project.

Info

If the user does not exist in your organization, he/she is invited and added both to your organization and project. This function can also be used to change the role of the user in the project.

Parameters:

Name Type Description Default
project_id str

Identifier of the project

required
user_email str

The email of the user. This email is used as the unique identifier of the user.

required
role Literal['ADMIN', 'TEAM_MANAGER', 'REVIEWER', 'LABELER']

The role of the user.

'LABELER'

Returns:

Type Description
Dict

A dictionary with the project user information.

Examples:

>>> kili.append_to_roles(project_id=project_id, user_email='john@doe.com')
Source code in kili/entrypoints/mutations/project/__init__.py
@typechecked
def append_to_roles(
    self,
    project_id: str,
    user_email: str,
    role: Literal["ADMIN", "TEAM_MANAGER", "REVIEWER", "LABELER"] = "LABELER",
) -> Dict:
    """Add a user to a project.

    !!! info
        If the user does not exist in your organization, he/she is invited and added
            both to your organization and project. This function can also be used to change
            the role of the user in the project.

    Args:
        project_id: Identifier of the project
        user_email: The email of the user.
            This email is used as the unique identifier of the user.
        role: The role of the user.

    Returns:
        A dictionary with the project user information.


    Examples:
        >>> kili.append_to_roles(project_id=project_id, user_email='john@doe.com')
    """
    variables = {
        "data": {"role": role, "userEmail": user_email},
        "where": {"id": project_id},
    }
    result = self.graphql_client.execute(GQL_APPEND_TO_ROLES, variables)

    project_data = self.format_result("data", result)
    for project_user in project_data["roles"]:
        if project_user["user"]["email"] == user_email.lower() and project_user["role"] == role:
            return project_user

    raise MutationError(
        f"Failed to mutate user {user_email} to role {role} for project {project_id}."
    )

archive_project(self, project_id)

Archive a project.

Parameters:

Name Type Description Default
project_id str

Identifier of the project.

required

Returns:

Type Description
Dict[Literal['id'], str]

A dict with the id of the project.

Source code in kili/entrypoints/mutations/project/__init__.py
@typechecked
def archive_project(self, project_id: str) -> Dict[Literal["id"], str]:
    """Archive a project.

    Args:
        project_id: Identifier of the project.

    Returns:
        A dict with the id of the project.
    """
    variables = {
        "projectID": project_id,
        "archived": True,
    }

    result = self.graphql_client.execute(GQL_UPDATE_PROPERTIES_IN_PROJECT, variables)

    return self.format_result("data", result)

copy_project(self, from_project_id, title=None, description=None, copy_json_interface=True, copy_quality_settings=True, copy_members=True, copy_assets=False, copy_labels=False, disable_tqdm=None)

Create new project from an existing project.

Parameters:

Name Type Description Default
from_project_id str

Project ID to copy from.

required
title Optional[str]

Title for the new project. Defaults to source project title if None is provided.

None
description Optional[str]

Description for the new project. Defaults to empty string if None is provided.

None
copy_json_interface bool

Include json interface in the copy.

True
copy_quality_settings bool

Include quality settings in the copy.

True
copy_members bool

Include members in the copy.

True
copy_assets bool

Include assets in the copy.

False
copy_labels bool

Include labels in the copy.

False
disable_tqdm Optional[bool]

Disable tqdm progress bars.

None

Returns:

Type Description
str

The created project ID.

Examples:

>>> kili.copy_project(from_project_id="clbqn56b331234567890l41c0")
Source code in kili/entrypoints/mutations/project/__init__.py
@typechecked
def copy_project(  # pylint: disable=too-many-arguments
    self,
    from_project_id: str,
    title: Optional[str] = None,
    description: Optional[str] = None,
    copy_json_interface: bool = True,
    copy_quality_settings: bool = True,
    copy_members: bool = True,
    copy_assets: bool = False,
    copy_labels: bool = False,
    disable_tqdm: Optional[bool] = None,
) -> str:
    """Create new project from an existing project.

    Args:
        from_project_id: Project ID to copy from.
        title: Title for the new project. Defaults to source project
            title if `None` is provided.
        description: Description for the new project. Defaults to empty string
            if `None` is provided.
        copy_json_interface: Include json interface in the copy.
        copy_quality_settings: Include quality settings in the copy.
        copy_members: Include members in the copy.
        copy_assets: Include assets in the copy.
        copy_labels: Include labels in the copy.
        disable_tqdm: Disable tqdm progress bars.

    Returns:
        The created project ID.

    Examples:
        >>> kili.copy_project(from_project_id="clbqn56b331234567890l41c0")
    """
    return ProjectCopier(self).copy_project(
        from_project_id,
        title,
        description,
        copy_json_interface,
        copy_quality_settings,
        copy_members,
        copy_assets,
        copy_labels,
        disable_tqdm,
    )

delete_from_roles(self, role_id)

Delete users by their role_id.

Parameters:

Name Type Description Default
role_id str

Identifier of the project user (not the ID of the user)

required

Returns:

Type Description
Dict[Literal['id'], str]

A dict with the project id.

Source code in kili/entrypoints/mutations/project/__init__.py
@typechecked
def delete_from_roles(self, role_id: str) -> Dict[Literal["id"], str]:
    """Delete users by their role_id.

    Args:
        role_id: Identifier of the project user (not the ID of the user)

    Returns:
        A dict with the project id.
    """
    variables = {"where": {"id": role_id}}
    result = self.graphql_client.execute(GQL_DELETE_FROM_ROLES, variables)
    return self.format_result("data", result)

delete_project(self, project_id)

Delete a project permanently.

Parameters:

Name Type Description Default
project_id str

Identifier of the project

required

Returns:

Type Description
str

A string with the deleted project id.

Source code in kili/entrypoints/mutations/project/__init__.py
@typechecked
def delete_project(self, project_id: str) -> str:
    """Delete a project permanently.

    Args:
        project_id: Identifier of the project

    Returns:
        A string with the deleted project id.
    """
    variables = {"where": {"id": project_id}}
    result = self.graphql_client.execute(GQL_PROJECT_DELETE_ASYNCHRONOUSLY, variables)
    return self.format_result("data", result)

unarchive_project(self, project_id)

Unarchive a project.

Parameters:

Name Type Description Default
project_id str

Identifier of the project

required

Returns:

Type Description
Dict[Literal['id'], str]

A dict with the id of the project.

Source code in kili/entrypoints/mutations/project/__init__.py
@typechecked
def unarchive_project(self, project_id: str) -> Dict[Literal["id"], str]:
    """Unarchive a project.

    Args:
        project_id: Identifier of the project

    Returns:
        A dict with the id of the project.
    """
    variables = {
        "projectID": project_id,
        "archived": False,
    }

    result = self.graphql_client.execute(GQL_UPDATE_PROPERTIES_IN_PROJECT, variables)
    return self.format_result("data", result)

update_project_anonymization(self, project_id, should_anonymize=True)

Anonymize the project for the labelers and reviewers.

Info

Compatible with versions of the Kili app >= 2.135.0

Parameters:

Name Type Description Default
project_id str

Identifier of the project

required
should_anonymize bool

The value to be applied. Defaults to True.

True

Returns:

Type Description
Dict[Literal['id'], str]

A dict with the id of the project which indicates if the mutation was successful, or an error message.

Examples:

>>> kili.update_project_anonymization(project_id=project_id)
>>> kili.update_project_anonymization(project_id=project_id, should_anonymize=False)
Source code in kili/entrypoints/mutations/project/__init__.py
@typechecked
def update_project_anonymization(
    self, project_id: str, should_anonymize: bool = True
) -> Dict[Literal["id"], str]:
    """Anonymize the project for the labelers and reviewers.

    !!! info
        Compatible with versions of the Kili app >= 2.135.0

    Args:
        project_id: Identifier of the project
        should_anonymize: The value to be applied. Defaults to `True`.

    Returns:
        A dict with the id of the project which indicates if the mutation was successful,
            or an error message.

    Examples:
        >>> kili.update_project_anonymization(project_id=project_id)
        >>> kili.update_project_anonymization(project_id=project_id, should_anonymize=False)
    """
    variables = {
        "input": {
            "id": project_id,
            "shouldAnonymize": should_anonymize,
        }
    }

    result = self.graphql_client.execute(GQL_PROJECT_UPDATE_ANONYMIZATION, variables)
    return self.format_result("data", result)

update_properties_in_project(self, project_id, can_navigate_between_assets=None, can_skip_asset=None, consensus_mark=None, consensus_tot_coverage=None, description=None, honeypot_mark=None, instructions=None, input_type=None, json_interface=None, min_consensus_size=None, number_of_assets=None, number_of_skipped_assets=None, number_of_remaining_assets=None, number_of_reviewed_assets=None, review_coverage=None, should_relaunch_kpi_computation=None, title=None, use_honeypot=None, metadata_types=None)

Update properties of a project.

Parameters:

Name Type Description Default
project_id str

Identifier of the project.

required
can_navigate_between_assets Optional[bool]

Activate / Deactivate the use of next and previous buttons in labeling interface.

None
can_skip_asset Optional[bool]

Activate / Deactivate the use of skip button in labeling interface.

None
consensus_mark Optional[float]

Should be between 0 and 1.

None
consensus_tot_coverage Optional[int]

Should be between 0 and 100. It is the percentage of the dataset that will be annotated several times.

None
description Optional[str]

Description of the project.

None
honeypot_mark Optional[float]

Should be between 0 and 1

None
instructions Optional[str]

Instructions of the project.

None
input_type Optional[str]

Currently, one of IMAGE, PDF, TEXT or VIDEO.

None
json_interface Optional[dict]

The json parameters of the project, see Edit your interface.

None
min_consensus_size Optional[int]

Should be between 1 and 10 Number of people that will annotate the same asset, for consensus computation.

None
number_of_assets Optional[int]

Defaults to 0

None
number_of_skipped_assets Optional[int]

Defaults to 0

None
number_of_remaining_assets Optional[int]

Defaults to 0

None
number_of_reviewed_assets Optional[int]

Defaults to 0

None
review_coverage Optional[int]

Allow to set the percentage of assets that will be queued in the review interface. Should be between 0 and 100

None
should_relaunch_kpi_computation Optional[bool]

Technical field, added to indicate changes in honeypot or consensus settings

None
title Optional[str]

Title of the project

None
use_honeypot Optional[bool]

Activate / Deactivate the use of honeypot in the project

None
metadata_types Optional[dict]

Types of the project metadata. Should be a dict of metadata fields name as keys and metadata types as values. Currently, possible types are: string, number

None

Returns:

Type Description
Dict[str, Any]

A dict with the changed properties which indicates if the mutation was successful, else an error message.

Change Metadata Types

Metadata fields are by default interpreted as string types. To change the type of a metadata field, you can use the update_properties_in_project function with the metadata_types argument. metadata_types is given as a dict of metadata field names as keys and metadata types as values.

kili.update_properties_in_project(
    project_id = project_id,
    metadata_types = {
        'customConsensus': 'number',
        'sensitiveData': 'string',
        'uploadedFromCloud': 'string',
        'modelLabelErrorScore': 'number'
    }
)

Not providing a type for a metadata field or providing an unsupported one will default to the string type.

Source code in kili/entrypoints/mutations/project/__init__.py
@typechecked
def update_properties_in_project(
    self,
    project_id: str,
    can_navigate_between_assets: Optional[bool] = None,
    can_skip_asset: Optional[bool] = None,
    consensus_mark: Optional[float] = None,
    consensus_tot_coverage: Optional[int] = None,
    description: Optional[str] = None,
    honeypot_mark: Optional[float] = None,
    instructions: Optional[str] = None,
    input_type: Optional[str] = None,
    json_interface: Optional[dict] = None,
    min_consensus_size: Optional[int] = None,
    number_of_assets: Optional[int] = None,
    number_of_skipped_assets: Optional[int] = None,
    number_of_remaining_assets: Optional[int] = None,
    number_of_reviewed_assets: Optional[int] = None,
    review_coverage: Optional[int] = None,
    should_relaunch_kpi_computation: Optional[bool] = None,
    title: Optional[str] = None,
    use_honeypot: Optional[bool] = None,
    metadata_types: Optional[dict] = None,
) -> Dict[str, Any]:
    """Update properties of a project.

    Args:
        project_id: Identifier of the project.
        can_navigate_between_assets:
            Activate / Deactivate the use of next and previous buttons in labeling interface.
        can_skip_asset: Activate / Deactivate the use of skip button in labeling interface.
        consensus_mark: Should be between 0 and 1.
        consensus_tot_coverage: Should be between 0 and 100.
            It is the percentage of the dataset that will be annotated several times.
        description: Description of the project.
        honeypot_mark: Should be between 0 and 1
        instructions: Instructions of the project.
        input_type: Currently, one of `IMAGE`, `PDF`, `TEXT` or `VIDEO`.
        json_interface: The json parameters of the project, see Edit your interface.
        min_consensus_size: Should be between 1 and 10
            Number of people that will annotate the same asset, for consensus computation.
        number_of_assets: Defaults to 0
        number_of_skipped_assets: Defaults to 0
        number_of_remaining_assets: Defaults to 0
        number_of_reviewed_assets: Defaults to 0
        review_coverage: Allow to set the percentage of assets
            that will be queued in the review interface.
            Should be between 0 and 100
        should_relaunch_kpi_computation: Technical field, added to indicate changes
            in honeypot or consensus settings
        title: Title of the project
        use_honeypot: Activate / Deactivate the use of honeypot in the project
        metadata_types: Types of the project metadata.
            Should be a `dict` of metadata fields name as keys and metadata types as values.
            Currently, possible types are: `string`, `number`

    Returns:
        A dict with the changed properties which indicates if the mutation was successful,
            else an error message.

    !!! example "Change Metadata Types"
        Metadata fields are by default interpreted as `string` types. To change the type
        of a metadata field, you can use the `update_properties_in_project` function with the
        metadata_types argument. `metadata_types` is given as a dict of metadata field names
        as keys and metadata types as values.

        ```python
        kili.update_properties_in_project(
            project_id = project_id,
            metadata_types = {
                'customConsensus': 'number',
                'sensitiveData': 'string',
                'uploadedFromCloud': 'string',
                'modelLabelErrorScore': 'number'
            }
        )
        ```

        Not providing a type for a metadata field or providing an unsupported one
        will default to the `string` type.
    """
    verify_argument_ranges(consensus_tot_coverage, min_consensus_size, review_coverage)

    variables = {
        "canNavigateBetweenAssets": can_navigate_between_assets,
        "canSkipAsset": can_skip_asset,
        "consensusMark": consensus_mark,
        "consensusTotCoverage": consensus_tot_coverage,
        "description": description,
        "honeypotMark": honeypot_mark,
        "instructions": instructions,
        "inputType": input_type,
        "jsonInterface": dumps(json_interface) if json_interface is not None else None,
        "metadataTypes": metadata_types,
        "minConsensusSize": min_consensus_size,
        "numberOfAssets": number_of_assets,
        "numberOfSkippedAssets": number_of_skipped_assets,
        "numberOfRemainingAssets": number_of_remaining_assets,
        "numberOfReviewedAssets": number_of_reviewed_assets,
        "projectID": project_id,
        "reviewCoverage": review_coverage,
        "shouldRelaunchKpiComputation": should_relaunch_kpi_computation,
        "title": title,
        "useHoneyPot": use_honeypot,
    }
    result = self.graphql_client.execute(GQL_UPDATE_PROPERTIES_IN_PROJECT, variables)
    result = self.format_result("data", result)

    variables.pop("projectID")
    variables = {k: v for k, v in variables.items() if v is not None}

    new_project_settings = get_project(self, project_id, list(variables.keys()))

    return {**result, **new_project_settings}

update_properties_in_role(self, role_id, project_id, user_id, role)

Update properties of a role.

Info

To be able to change someone's role, you must be either of:

  • an admin of the project
  • a team manager of the project
  • an admin of the organization

Parameters:

Name Type Description Default
role_id str

Role identifier of the user. E.g. : 'to-be-deactivated'

required
project_id str

Identifier of the project

required
user_id str

The email or identifier of the user with updated role

required
role str

The new role. Possible choices are: ADMIN, TEAM_MANAGER, REVIEWER, LABELER

required

Returns:

Type Description
Dict

A dictionary with the project user information.

Source code in kili/entrypoints/mutations/project/__init__.py
@typechecked
def update_properties_in_role(
    self, role_id: str, project_id: str, user_id: str, role: str
) -> Dict:
    """Update properties of a role.

    !!! info
        To be able to change someone's role, you must be either of:

        - an admin of the project
        - a team manager of the project
        - an admin of the organization

    Args:
        role_id: Role identifier of the user. E.g. : 'to-be-deactivated'
        project_id: Identifier of the project
        user_id: The email or identifier of the user with updated role
        role: The new role.
            Possible choices are: `ADMIN`, `TEAM_MANAGER`, `REVIEWER`, `LABELER`

    Returns:
        A dictionary with the project user information.
    """
    variables = {
        "roleID": role_id,
        "projectID": project_id,
        "userID": user_id,
        "role": role,
    }
    result = self.graphql_client.execute(GQL_UPDATE_PROPERTIES_IN_ROLE, variables)
    return self.format_result("data", result)