Issue module
Methods attached to the Kili client, to run actions on issues.
Source code in kili/presentation/client/issue.py
class IssueClientMethods:
"""Methods attached to the Kili client, to run actions on issues."""
kili_api_gateway: KiliAPIGateway
http_client: requests.Session
@typechecked
def create_issues(
self,
project_id: str,
label_id_array: List[str],
object_mid_array: Optional[List[Optional[str]]] = None,
text_array: Optional[List[Optional[str]]] = None,
) -> List[Dict[Literal["id"], str]]:
"""Create an issue.
Args:
project_id: Id of the project.
label_id_array: List of Ids of the labels to add an issue to.
object_mid_array: List of mids of the objects in the labels to associate the issues to.
text_array: List of texts to associate to the issues.
Returns:
A list of dictionary with the `id` key of the created issues.
"""
assert_all_arrays_have_same_size([label_id_array, object_mid_array, text_array])
issues = [
IssueToCreateUseCaseInput(label_id=label_id, object_mid=object_mid, text=text)
for (label_id, object_mid, text) in zip(
label_id_array,
object_mid_array or repeat(None),
text_array or repeat(None),
)
]
issue_service = IssueUseCases(self.kili_api_gateway)
issues_entities = issue_service.create_issues(project_id=project_id, issues=issues)
return [{"id": issue.id_} for issue in issues_entities]
create_issues(self, project_id, label_id_array, object_mid_array=None, text_array=None)
Create an issue.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
project_id |
str |
Id of the project. |
required |
label_id_array |
List[str] |
List of Ids of the labels to add an issue to. |
required |
object_mid_array |
Optional[List[Union[str, NoneType]]] |
List of mids of the objects in the labels to associate the issues to. |
None |
text_array |
Optional[List[Union[str, NoneType]]] |
List of texts to associate to the issues. |
None |
Returns:
Type | Description |
---|---|
List[Dict[Literal['id'], str]] |
A list of dictionary with the |
Source code in kili/presentation/client/issue.py
@typechecked
def create_issues(
self,
project_id: str,
label_id_array: List[str],
object_mid_array: Optional[List[Optional[str]]] = None,
text_array: Optional[List[Optional[str]]] = None,
) -> List[Dict[Literal["id"], str]]:
"""Create an issue.
Args:
project_id: Id of the project.
label_id_array: List of Ids of the labels to add an issue to.
object_mid_array: List of mids of the objects in the labels to associate the issues to.
text_array: List of texts to associate to the issues.
Returns:
A list of dictionary with the `id` key of the created issues.
"""
assert_all_arrays_have_same_size([label_id_array, object_mid_array, text_array])
issues = [
IssueToCreateUseCaseInput(label_id=label_id, object_mid=object_mid, text=text)
for (label_id, object_mid, text) in zip(
label_id_array,
object_mid_array or repeat(None),
text_array or repeat(None),
)
]
issue_service = IssueUseCases(self.kili_api_gateway)
issues_entities = issue_service.create_issues(project_id=project_id, issues=issues)
return [{"id": issue.id_} for issue in issues_entities]
Set of Issue queries.
Source code in kili/entrypoints/queries/issue/__init__.py
class QueriesIssue(BaseOperationEntrypointMixin):
"""Set of Issue queries."""
# pylint: disable=too-many-arguments,dangerous-default-value
@overload
def issues(
self,
project_id: str,
fields: List[str] = [
"id",
"createdAt",
"status",
"type",
],
first: Optional[int] = None,
skip: int = 0,
disable_tqdm: bool = False,
asset_id: Optional[str] = None,
asset_id_in: Optional[List[str]] = None,
issue_type: Optional[Literal["QUESTION", "ISSUE"]] = None,
status: Optional[Literal["OPEN", "SOLVED"]] = None,
*,
as_generator: Literal[True],
) -> Generator[Dict, None, None]:
...
@overload
def issues(
self,
project_id: str,
fields: List[str] = [
"id",
"createdAt",
"status",
"type",
],
first: Optional[int] = None,
skip: int = 0,
disable_tqdm: bool = False,
asset_id: Optional[str] = None,
asset_id_in: Optional[List[str]] = None,
issue_type: Optional[Literal["QUESTION", "ISSUE"]] = None,
status: Optional[Literal["OPEN", "SOLVED"]] = None,
*,
as_generator: Literal[False] = False,
) -> List[Dict]:
...
@typechecked
def issues(
self,
project_id: str,
fields: List[str] = [
"id",
"createdAt",
"status",
"type",
"assetId",
],
first: Optional[int] = None,
skip: int = 0,
disable_tqdm: bool = False,
asset_id: Optional[str] = None,
asset_id_in: Optional[List[str]] = None,
issue_type: Optional[Literal["QUESTION", "ISSUE"]] = None,
status: Optional[Literal["OPEN", "SOLVED"]] = None,
*,
as_generator: bool = False,
) -> Iterable[Dict]:
# pylint: disable=line-too-long
"""Get a generator or a list of issues that match a set of criteria.
!!! Info "Issues or Questions"
An `Issue` object both represent an issue and a question in the app.
To create them, two different methods are provided: `create_issues` and `create_questions`.
However to query issues and questions, we currently provide this unique method that retrieves both of them.
Args:
project_id: Project ID the issue belongs to.
asset_id: Id of the asset whose returned issues are associated to.
asset_id_in: List of Ids of assets whose returned issues are associated to.
issue_type: Type of the issue to return. An issue object both represents issues and questions in the app.
status: Status of the issues to return.
fields: All the fields to request among the possible fields for the assets.
See [the documentation](https://docs.kili-technology.com/reference/graphql-api#issue) for all possible fields.
first: Maximum number of issues to return.
skip: Number of issues to skip (they are ordered by their date of creation, first to last).
disable_tqdm: If `True`, the progress bar will be disabled
as_generator: If `True`, a generator on the issues is returned.
Returns:
An iterable of issues objects represented as `dict`.
Examples:
>>> kili.issues(project_id=project_id, fields=['author.email']) # List all issues of a project and their authors
"""
if asset_id and asset_id_in:
raise ValueError(
"You cannot provide both `asset_id` and `asset_id_in` at the same time"
)
where = IssueWhere(
project_id=project_id,
asset_id=asset_id,
asset_id_in=asset_id_in,
issue_type=issue_type,
status=status,
)
disable_tqdm = disable_tqdm_if_as_generator(as_generator, disable_tqdm)
options = QueryOptions(disable_tqdm, first, skip)
issues_gen = IssueQuery(self.graphql_client, self.http_client)(where, fields, options)
if as_generator:
return issues_gen
return list(issues_gen)
@typechecked
def count_issues(
self,
project_id: str,
asset_id: Optional[str] = None,
asset_id_in: Optional[List[str]] = None,
issue_type: Optional[Literal["QUESTION", "ISSUE"]] = None,
status: Optional[Literal["OPEN", "SOLVED"]] = None,
) -> int:
"""Count and return the number of issues with the given constraints.
Args:
project_id: Project ID the issue belongs to.
asset_id: Asset id whose returned issues are associated to.
asset_id_in: List of asset ids whose returned issues are associated to.
issue_type: Type of the issue to return. An issue object both
represents issues and questions in the app
status: Status of the issues to return.
Returns:
The number of issues with the parameters provided
"""
if asset_id and asset_id_in:
raise ValueError(
"You cannot provide both `asset_id` and `asset_id_in` at the same time"
)
where = IssueWhere(
project_id=project_id,
asset_id=asset_id,
asset_id_in=asset_id_in,
issue_type=issue_type,
status=status,
)
return IssueQuery(self.graphql_client, self.http_client).count(where)
count_issues(self, project_id, asset_id=None, asset_id_in=None, issue_type=None, status=None)
Count and return the number of issues with the given constraints.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
project_id |
str |
Project ID the issue belongs to. |
required |
asset_id |
Optional[str] |
Asset id whose returned issues are associated to. |
None |
asset_id_in |
Optional[List[str]] |
List of asset ids whose returned issues are associated to. |
None |
issue_type |
Optional[Literal['QUESTION', 'ISSUE']] |
Type of the issue to return. An issue object both represents issues and questions in the app |
None |
status |
Optional[Literal['OPEN', 'SOLVED']] |
Status of the issues to return. |
None |
Returns:
Type | Description |
---|---|
int |
The number of issues with the parameters provided |
Source code in kili/entrypoints/queries/issue/__init__.py
@typechecked
def count_issues(
self,
project_id: str,
asset_id: Optional[str] = None,
asset_id_in: Optional[List[str]] = None,
issue_type: Optional[Literal["QUESTION", "ISSUE"]] = None,
status: Optional[Literal["OPEN", "SOLVED"]] = None,
) -> int:
"""Count and return the number of issues with the given constraints.
Args:
project_id: Project ID the issue belongs to.
asset_id: Asset id whose returned issues are associated to.
asset_id_in: List of asset ids whose returned issues are associated to.
issue_type: Type of the issue to return. An issue object both
represents issues and questions in the app
status: Status of the issues to return.
Returns:
The number of issues with the parameters provided
"""
if asset_id and asset_id_in:
raise ValueError(
"You cannot provide both `asset_id` and `asset_id_in` at the same time"
)
where = IssueWhere(
project_id=project_id,
asset_id=asset_id,
asset_id_in=asset_id_in,
issue_type=issue_type,
status=status,
)
return IssueQuery(self.graphql_client, self.http_client).count(where)
issues(self, project_id, fields=['id', 'createdAt', 'status', 'type', 'assetId'], first=None, skip=0, disable_tqdm=False, asset_id=None, asset_id_in=None, issue_type=None, status=None, *, as_generator=False)
Get a generator or a list of issues that match a set of criteria.
Issues or Questions
An Issue
object both represent an issue and a question in the app.
To create them, two different methods are provided: create_issues
and create_questions
.
However to query issues and questions, we currently provide this unique method that retrieves both of them.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
project_id |
str |
Project ID the issue belongs to. |
required |
asset_id |
Optional[str] |
Id of the asset whose returned issues are associated to. |
None |
asset_id_in |
Optional[List[str]] |
List of Ids of assets whose returned issues are associated to. |
None |
issue_type |
Optional[Literal['QUESTION', 'ISSUE']] |
Type of the issue to return. An issue object both represents issues and questions in the app. |
None |
status |
Optional[Literal['OPEN', 'SOLVED']] |
Status of the issues to return. |
None |
fields |
List[str] |
All the fields to request among the possible fields for the assets. See the documentation for all possible fields. |
['id', 'createdAt', 'status', 'type', 'assetId'] |
first |
Optional[int] |
Maximum number of issues to return. |
None |
skip |
int |
Number of issues to skip (they are ordered by their date of creation, first to last). |
0 |
disable_tqdm |
bool |
If |
False |
as_generator |
bool |
If |
False |
Returns:
Type | Description |
---|---|
Iterable[Dict] |
An iterable of issues objects represented as |
Examples:
>>> kili.issues(project_id=project_id, fields=['author.email']) # List all issues of a project and their authors
Source code in kili/entrypoints/queries/issue/__init__.py
@typechecked
def issues(
self,
project_id: str,
fields: List[str] = [
"id",
"createdAt",
"status",
"type",
"assetId",
],
first: Optional[int] = None,
skip: int = 0,
disable_tqdm: bool = False,
asset_id: Optional[str] = None,
asset_id_in: Optional[List[str]] = None,
issue_type: Optional[Literal["QUESTION", "ISSUE"]] = None,
status: Optional[Literal["OPEN", "SOLVED"]] = None,
*,
as_generator: bool = False,
) -> Iterable[Dict]:
# pylint: disable=line-too-long
"""Get a generator or a list of issues that match a set of criteria.
!!! Info "Issues or Questions"
An `Issue` object both represent an issue and a question in the app.
To create them, two different methods are provided: `create_issues` and `create_questions`.
However to query issues and questions, we currently provide this unique method that retrieves both of them.
Args:
project_id: Project ID the issue belongs to.
asset_id: Id of the asset whose returned issues are associated to.
asset_id_in: List of Ids of assets whose returned issues are associated to.
issue_type: Type of the issue to return. An issue object both represents issues and questions in the app.
status: Status of the issues to return.
fields: All the fields to request among the possible fields for the assets.
See [the documentation](https://docs.kili-technology.com/reference/graphql-api#issue) for all possible fields.
first: Maximum number of issues to return.
skip: Number of issues to skip (they are ordered by their date of creation, first to last).
disable_tqdm: If `True`, the progress bar will be disabled
as_generator: If `True`, a generator on the issues is returned.
Returns:
An iterable of issues objects represented as `dict`.
Examples:
>>> kili.issues(project_id=project_id, fields=['author.email']) # List all issues of a project and their authors
"""
if asset_id and asset_id_in:
raise ValueError(
"You cannot provide both `asset_id` and `asset_id_in` at the same time"
)
where = IssueWhere(
project_id=project_id,
asset_id=asset_id,
asset_id_in=asset_id_in,
issue_type=issue_type,
status=status,
)
disable_tqdm = disable_tqdm_if_as_generator(as_generator, disable_tqdm)
options = QueryOptions(disable_tqdm, first, skip)
issues_gen = IssueQuery(self.graphql_client, self.http_client)(where, fields, options)
if as_generator:
return issues_gen
return list(issues_gen)
Set of Issue mutations.
Source code in kili/entrypoints/mutations/issue/__init__.py
class MutationsIssue(BaseOperationEntrypointMixin):
"""Set of Issue mutations."""
# pylint: disable=too-many-arguments
@deprecate(
msg=(
"append_to_issues is deprecated. Please use `create_issues` or `create_questions`"
" instead. These new methods allow to import several issues or questions at the same"
" time and provide better performances."
)
)
@typechecked
def append_to_issues(
self,
label_id: str,
project_id: str,
object_mid: Optional[str] = None,
text: Optional[str] = None,
type_: Literal["ISSUE", "QUESTION"] = "ISSUE",
) -> Dict:
"""Create an issue.
!!! danger "Deprecated"
append_to_issues is deprecated.
Please use `create_issues` or `create_questions` instead.
These new methods allow to import several issues or questions at the same time
and provide better performances.
Args:
label_id: Id of the label to add an issue to
object_mid: Mid of the object in the label to associate the issue to
type_: type of the issue to add. Can be either "ISSUE" or "QUESTION"
text: If given, write a comment related to the issue
project_id: Id of the project
Returns:
A result object which indicates if the mutation was successful,
or an error message.
"""
try:
options = QueryOptions(disable_tqdm=True)
where = LabelWhere(
project_id=project_id,
label_id=label_id,
)
asset_id: str = list(
LabelQuery(self.graphql_client, self.http_client)(
where=where, fields=["labelOf.id"], options=options
)
)[0]["labelOf"]["id"]
except:
# pylint: disable=raise-missing-from
raise ValueError(
f"Label ID {label_id} does not exist in the project of ID {project_id}"
)
variables = {
"issues": [
{
"issueNumber": 0,
"labelID": label_id,
"objectMid": object_mid,
"type": type_,
"assetId": asset_id,
"text": text,
}
],
"where": {"id": asset_id},
}
result = self.graphql_client.execute(GQL_CREATE_ISSUES, variables)
return self.format_result("data", result)[0]
@typechecked
def create_questions(
self,
project_id: str,
text_array: List[Optional[str]],
asset_id_array: Optional[List[str]] = None,
asset_external_id_array: Optional[List[str]] = None,
) -> List[Dict]:
# pylint:disable=line-too-long
"""Create questions.
Args:
project_id: Id of the project.
text_array: List of question strings.
asset_id_array: List of the assets to add the questions to.
asset_external_id_array: List of the assets to add the questions to. Used if `asset_id_array` is not given.
Returns:
A list of dictionary with the `id` key of the created questions.
"""
assert_all_arrays_have_same_size([text_array, asset_id_array])
asset_id_array = get_asset_ids_or_throw_error(
self, asset_id_array, asset_external_id_array, project_id
)
created_questions: List[Dict[str, str]] = []
with tqdm.tqdm(total=len(text_array), desc="Creating questions") as pbar:
for batch_questions in BatchIteratorBuilder(list(zip(asset_id_array, text_array))):
variables = {
"issues": [
{"issueNumber": 0, "type": "QUESTION", "assetId": asset_id, "text": text}
for (asset_id, text) in batch_questions
],
"where": {"idIn": asset_id_array},
}
result = self.graphql_client.execute(GQL_CREATE_ISSUES, variables)
created_questions.extend(self.format_result("data", result))
pbar.update(len(batch_questions))
return created_questions
append_to_issues(self, label_id, project_id, object_mid=None, text=None, type_='ISSUE')
Create an issue.
Deprecated
append_to_issues is deprecated.
Please use create_issues
or create_questions
instead.
These new methods allow to import several issues or questions at the same time
and provide better performances.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
label_id |
str |
Id of the label to add an issue to |
required |
object_mid |
Optional[str] |
Mid of the object in the label to associate the issue to |
None |
type_ |
Literal['ISSUE', 'QUESTION'] |
type of the issue to add. Can be either "ISSUE" or "QUESTION" |
'ISSUE' |
text |
Optional[str] |
If given, write a comment related to the issue |
None |
project_id |
str |
Id of the project |
required |
Returns:
Type | Description |
---|---|
Dict |
A result object which indicates if the mutation was successful, or an error message. |
Source code in kili/entrypoints/mutations/issue/__init__.py
@deprecate(
msg=(
"append_to_issues is deprecated. Please use `create_issues` or `create_questions`"
" instead. These new methods allow to import several issues or questions at the same"
" time and provide better performances."
)
)
@typechecked
def append_to_issues(
self,
label_id: str,
project_id: str,
object_mid: Optional[str] = None,
text: Optional[str] = None,
type_: Literal["ISSUE", "QUESTION"] = "ISSUE",
) -> Dict:
"""Create an issue.
!!! danger "Deprecated"
append_to_issues is deprecated.
Please use `create_issues` or `create_questions` instead.
These new methods allow to import several issues or questions at the same time
and provide better performances.
Args:
label_id: Id of the label to add an issue to
object_mid: Mid of the object in the label to associate the issue to
type_: type of the issue to add. Can be either "ISSUE" or "QUESTION"
text: If given, write a comment related to the issue
project_id: Id of the project
Returns:
A result object which indicates if the mutation was successful,
or an error message.
"""
try:
options = QueryOptions(disable_tqdm=True)
where = LabelWhere(
project_id=project_id,
label_id=label_id,
)
asset_id: str = list(
LabelQuery(self.graphql_client, self.http_client)(
where=where, fields=["labelOf.id"], options=options
)
)[0]["labelOf"]["id"]
except:
# pylint: disable=raise-missing-from
raise ValueError(
f"Label ID {label_id} does not exist in the project of ID {project_id}"
)
variables = {
"issues": [
{
"issueNumber": 0,
"labelID": label_id,
"objectMid": object_mid,
"type": type_,
"assetId": asset_id,
"text": text,
}
],
"where": {"id": asset_id},
}
result = self.graphql_client.execute(GQL_CREATE_ISSUES, variables)
return self.format_result("data", result)[0]
create_questions(self, project_id, text_array, asset_id_array=None, asset_external_id_array=None)
Create questions.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
project_id |
str |
Id of the project. |
required |
text_array |
List[Optional[str]] |
List of question strings. |
required |
asset_id_array |
Optional[List[str]] |
List of the assets to add the questions to. |
None |
asset_external_id_array |
Optional[List[str]] |
List of the assets to add the questions to. Used if |
None |
Returns:
Type | Description |
---|---|
List[Dict] |
A list of dictionary with the |
Source code in kili/entrypoints/mutations/issue/__init__.py
@typechecked
def create_questions(
self,
project_id: str,
text_array: List[Optional[str]],
asset_id_array: Optional[List[str]] = None,
asset_external_id_array: Optional[List[str]] = None,
) -> List[Dict]:
# pylint:disable=line-too-long
"""Create questions.
Args:
project_id: Id of the project.
text_array: List of question strings.
asset_id_array: List of the assets to add the questions to.
asset_external_id_array: List of the assets to add the questions to. Used if `asset_id_array` is not given.
Returns:
A list of dictionary with the `id` key of the created questions.
"""
assert_all_arrays_have_same_size([text_array, asset_id_array])
asset_id_array = get_asset_ids_or_throw_error(
self, asset_id_array, asset_external_id_array, project_id
)
created_questions: List[Dict[str, str]] = []
with tqdm.tqdm(total=len(text_array), desc="Creating questions") as pbar:
for batch_questions in BatchIteratorBuilder(list(zip(asset_id_array, text_array))):
variables = {
"issues": [
{"issueNumber": 0, "type": "QUESTION", "assetId": asset_id, "text": text}
for (asset_id, text) in batch_questions
],
"where": {"idIn": asset_id_array},
}
result = self.graphql_client.execute(GQL_CREATE_ISSUES, variables)
created_questions.extend(self.format_result("data", result))
pbar.update(len(batch_questions))
return created_questions