diff --git a/pyproject.toml b/pyproject.toml index c8744f5af..f8f8df1de 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,7 +72,7 @@ dev = [ # linting "pre-commit >= 3.3.0, < 4.0.0", "pylint == 4.0.3", - "pyright ==1.1.347", + "pyright ==1.1.407", # notebooks tests "nbformat", "nbconvert", @@ -80,8 +80,8 @@ dev = [ # profiling "pyinstrument", # dead code detection - "vulture==2.11", - "dead==1.5.2", + "vulture==2.14", + "dead==2.1.0", # optional dependencies "kili-formats[all] == 0.2.10", "opencv-python >= 4.0.0, < 5.0.0", @@ -132,7 +132,7 @@ yolo = [ ] [tool.pyright] -exclude = ["**/__pycache__", ".github/scripts/upload_test_stats_datadog.py"] +exclude = ["**/__pycache__", ".github/scripts/upload_test_stats_datadog.py", "tests/**"] pythonVersion = "3.10" typeCheckingMode = "basic" diff --git a/recipes/counterfactual_data_augmentation.ipynb b/recipes/counterfactual_data_augmentation.ipynb index 6b264457d..cd7b260a6 100644 --- a/recipes/counterfactual_data_augmentation.ipynb +++ b/recipes/counterfactual_data_augmentation.ipynb @@ -344,7 +344,7 @@ " input_type=project_snli[\"input_type\"],\n", " json_interface=project_snli[\"json_interface\"],\n", ")[\"id\"]\n", - "print(f'Created project {project_snli[\"id\"]}')" + "print(f\"Created project {project_snli['id']}\")" ] }, { diff --git a/recipes/frame_dicom_data.ipynb b/recipes/frame_dicom_data.ipynb index 6ce7f1bfd..a77095c97 100644 --- a/recipes/frame_dicom_data.ipynb +++ b/recipes/frame_dicom_data.ipynb @@ -126,7 +126,7 @@ "for root, dirs, files in os.walk(ASSET_ROOT):\n", " if len(files) > 0:\n", " file_paths = list(map(lambda path: os.path.join(root, path), files))\n", - " sorted_files[f\"asset-{asset_number+1}\"] = sorted(\n", + " sorted_files[f\"asset-{asset_number + 1}\"] = sorted(\n", " [fp for fp in file_paths if fp.endswith(\".dcm\")],\n", " key=lambda path: int(os.path.split(path)[-1].split(\"-\")[1].split(\".\")[0]),\n", " )\n", diff --git a/recipes/misc/Kili_LLAMA2_Fine_tuning.ipynb b/recipes/misc/Kili_LLAMA2_Fine_tuning.ipynb index 21af8354d..1a2669b41 100644 --- a/recipes/misc/Kili_LLAMA2_Fine_tuning.ipynb +++ b/recipes/misc/Kili_LLAMA2_Fine_tuning.ipynb @@ -538,7 +538,7 @@ "source": [ "val_item = val_dataset[0]\n", "\n", - "prompt = f\"\"\"### Question: {val_item['input']}\n", + "prompt = f\"\"\"### Question: {val_item[\"input\"]}\n", "\"\"\"\n", "\n", "print(val_item[\"label\"])" diff --git a/recipes/set_up_workflows.ipynb b/recipes/set_up_workflows.ipynb index 87615cbab..2bfbc58c7 100644 --- a/recipes/set_up_workflows.ipynb +++ b/recipes/set_up_workflows.ipynb @@ -143,7 +143,7 @@ "project_user_ids = []\n", "for i in range(3):\n", " roles = kili.append_to_roles(\n", - " project_id=project_id, user_email=f\"example{i+1}@example.com\", role=\"LABELER\"\n", + " project_id=project_id, user_email=f\"example{i + 1}@example.com\", role=\"LABELER\"\n", " )\n", " project_user_ids.append(roles[\"user\"][\"id\"])" ] diff --git a/src/kili/adapters/kili_api_gateway/cloud_storage/mappers.py b/src/kili/adapters/kili_api_gateway/cloud_storage/mappers.py index c8279df81..a918d6f3a 100644 --- a/src/kili/adapters/kili_api_gateway/cloud_storage/mappers.py +++ b/src/kili/adapters/kili_api_gateway/cloud_storage/mappers.py @@ -1,6 +1,5 @@ """GraphQL payload data mappers for cloud storage operations.""" - from kili.adapters.kili_api_gateway.cloud_storage.types import DataIntegrationData from kili.domain.cloud_storage import DataConnectionFilters, DataIntegrationFilters diff --git a/src/kili/adapters/kili_api_gateway/event/mappers.py b/src/kili/adapters/kili_api_gateway/event/mappers.py index 2ae1a12d1..3acb9f258 100644 --- a/src/kili/adapters/kili_api_gateway/event/mappers.py +++ b/src/kili/adapters/kili_api_gateway/event/mappers.py @@ -1,6 +1,5 @@ """GraphQL payload data mappers for api keys operations.""" - from kili.domain.event import EventFilters, QueryOptions diff --git a/src/kili/adapters/kili_api_gateway/notification/mappers.py b/src/kili/adapters/kili_api_gateway/notification/mappers.py index f019ab764..62b137665 100644 --- a/src/kili/adapters/kili_api_gateway/notification/mappers.py +++ b/src/kili/adapters/kili_api_gateway/notification/mappers.py @@ -1,6 +1,5 @@ """Mappers for notification API calls.""" - from kili.adapters.kili_api_gateway.user.mappers import user_where_mapper from kili.domain.notification import NotificationFilter diff --git a/src/kili/adapters/kili_api_gateway/project/common.py b/src/kili/adapters/kili_api_gateway/project/common.py index 42ce6e572..8917598ea 100644 --- a/src/kili/adapters/kili_api_gateway/project/common.py +++ b/src/kili/adapters/kili_api_gateway/project/common.py @@ -26,7 +26,6 @@ def get_project( if len(projects) == 0: raise NotFound( - f"project ID: {project_id}. The project does not exist or you do not have access" - " to it." + f"project ID: {project_id}. The project does not exist or you do not have access to it." ) return load_project_json_fields(projects[0], fields) diff --git a/src/kili/adapters/kili_api_gateway/project/mappers.py b/src/kili/adapters/kili_api_gateway/project/mappers.py index 29c6ac8cd..940995f88 100644 --- a/src/kili/adapters/kili_api_gateway/project/mappers.py +++ b/src/kili/adapters/kili_api_gateway/project/mappers.py @@ -1,6 +1,5 @@ """GraphQL payload data mappers for project operations.""" - from kili.domain.project import ProjectFilters from .types import ProjectDataKiliAPIGatewayInput diff --git a/src/kili/adapters/kili_api_gateway/project_workflow/operations_mixin.py b/src/kili/adapters/kili_api_gateway/project_workflow/operations_mixin.py index 209129dc3..16b296263 100644 --- a/src/kili/adapters/kili_api_gateway/project_workflow/operations_mixin.py +++ b/src/kili/adapters/kili_api_gateway/project_workflow/operations_mixin.py @@ -1,6 +1,5 @@ """Mixin extending Kili API Gateway class with Projects related operations.""" - from kili.adapters.kili_api_gateway.base import BaseOperationMixin from kili.adapters.kili_api_gateway.helpers.queries import ( fragment_builder, diff --git a/src/kili/adapters/kili_api_gateway/user/mappers.py b/src/kili/adapters/kili_api_gateway/user/mappers.py index b209bcbaa..b49eb65d6 100644 --- a/src/kili/adapters/kili_api_gateway/user/mappers.py +++ b/src/kili/adapters/kili_api_gateway/user/mappers.py @@ -1,6 +1,5 @@ """GraphQL payload data mappers for user operations.""" - from kili.domain.user import UserFilter from .types import CreateUserDataKiliGatewayInput, UserDataKiliGatewayInput diff --git a/src/kili/client.py b/src/kili/client.py index 279e64186..b858fd922 100644 --- a/src/kili/client.py +++ b/src/kili/client.py @@ -166,7 +166,7 @@ def __init__( client_name=client_name, verify=self.verify, http_client=self.http_client, - **(graphql_client_params or {}), # pyright: ignore[reportGeneralTypeIssues] + **(graphql_client_params or {}), # type: ignore[arg-type] ) self.kili_api_gateway = KiliAPIGateway(self.graphql_client, self.http_client) self.internal = InternalClientMethods(self.kili_api_gateway) diff --git a/src/kili/core/constants.py b/src/kili/core/constants.py index bfd0325e5..ecd91cdcd 100644 --- a/src/kili/core/constants.py +++ b/src/kili/core/constants.py @@ -1,6 +1,5 @@ """This script lists package constants.""" - mime_extensions = { "Audio": "audio/x-flac,audio/mpeg,video/mp4", "Csv": "text/csv", diff --git a/src/kili/core/graphql/exceptions.py b/src/kili/core/graphql/exceptions.py index 3a7ee223d..a63f99b0c 100644 --- a/src/kili/core/graphql/exceptions.py +++ b/src/kili/core/graphql/exceptions.py @@ -1,4 +1,5 @@ """Helper functions to extract context from GraphQL error messages.""" + import ast from typing import Optional diff --git a/src/kili/core/graphql/graphql_client.py b/src/kili/core/graphql/graphql_client.py index 2712acc30..a6a374ebb 100644 --- a/src/kili/core/graphql/graphql_client.py +++ b/src/kili/core/graphql/graphql_client.py @@ -192,7 +192,11 @@ def _get_graphql_schema_from_endpoint(self) -> str: fetch_schema_from_transport=True, introspection_args=self._get_introspection_args(), ) as session: - return print_schema(session.client.schema) # pyright: ignore[reportGeneralTypeIssues] + schema = session.client.schema + if schema is None: + msg = "Failed to fetch GraphQL schema" + raise RuntimeError(msg) + return print_schema(schema) def _cache_graphql_schema(self, graphql_schema_path: Path, schema_str: str) -> None: """Cache the graphql schema on disk.""" @@ -332,7 +336,7 @@ def _raw_execute( ) transport = self._gql_client.transport if transport: - headers = transport.response_headers # pyright: ignore[reportGeneralTypeIssues] + headers = transport.response_headers # type: ignore[attr-defined] returned_complexity = int(headers.get("x-complexity", 0)) if headers else 0 self.complexity_consumed += returned_complexity return res diff --git a/src/kili/core/helpers.py b/src/kili/core/helpers.py index e9f459062..bde201257 100644 --- a/src/kili/core/helpers.py +++ b/src/kili/core/helpers.py @@ -35,15 +35,15 @@ def format_result( """ formatted_json = format_json(result[name], http_client) if object_ is None: - return formatted_json # pyright: ignore[reportGeneralTypeIssues] + return formatted_json # type: ignore[return-value] if isinstance(formatted_json, list): if get_origin(object_) is list: obj = get_args(object_)[0] - return [obj(element) for element in formatted_json] # pyright: ignore[reportGeneralTypeIssues] + return [obj(element) for element in formatted_json] # type: ignore[return-value,misc] # the legacy "orm" objects fall into this category. - return [object_(element) for element in formatted_json] # pyright: ignore[reportGeneralTypeIssues] + return [object_(element) for element in formatted_json] # type: ignore[return-value,misc] - return object_(formatted_json) + return object_(formatted_json) # type: ignore[misc] def get_mime_type(path: str): diff --git a/src/kili/entrypoints/cli/common_args.py b/src/kili/entrypoints/cli/common_args.py index 5eb87805c..99da3e2f0 100644 --- a/src/kili/entrypoints/cli/common_args.py +++ b/src/kili/entrypoints/cli/common_args.py @@ -1,6 +1,5 @@ """Common arguments and options for the CLI.""" - import click CONTEXT_SETTINGS = {"help_option_names": ["-h", "--help"]} diff --git a/src/kili/entrypoints/mutations/asset/__init__.py b/src/kili/entrypoints/mutations/asset/__init__.py index a718b6b60..3b332e56f 100644 --- a/src/kili/entrypoints/mutations/asset/__init__.py +++ b/src/kili/entrypoints/mutations/asset/__init__.py @@ -1,6 +1,7 @@ """Asset mutations.""" + import warnings -from typing import Any, Literal, Optional, Union, cast +from typing import TYPE_CHECKING, Any, Literal, Optional, Union, cast from tenacity import retry from tenacity.retry import retry_if_exception_type @@ -30,6 +31,9 @@ from kili.utils.assets import PageResolution from kili.utils.logcontext import for_all_methods, log_call +if TYPE_CHECKING: + from kili.client import Kili + @for_all_methods(log_call, exclude=["__init__"]) class MutationsAsset(BaseOperationEntrypointMixin): @@ -195,7 +199,7 @@ def append_many_to_dataset( if value is not None: assets = [{**assets[i], key: value[i]} for i in range(nb_data)] created_asset_ids = import_assets( - self, # pyright: ignore[reportGeneralTypeIssues] + cast("Kili", self), project_id=ProjectId(project_id), assets=assets, disable_tqdm=disable_tqdm, diff --git a/src/kili/entrypoints/mutations/issue/helpers.py b/src/kili/entrypoints/mutations/issue/helpers.py index 407fc9c7b..8939bc903 100644 --- a/src/kili/entrypoints/mutations/issue/helpers.py +++ b/src/kili/entrypoints/mutations/issue/helpers.py @@ -1,6 +1,5 @@ """Helpers for the issue mutations.""" - from kili.adapters.kili_api_gateway.helpers.queries import QueryOptions from kili.adapters.kili_api_gateway.kili_api_gateway import KiliAPIGateway from kili.domain.label import LabelFilters, LabelId diff --git a/src/kili/entrypoints/mutations/notification/__init__.py b/src/kili/entrypoints/mutations/notification/__init__.py index 87765758a..654051146 100644 --- a/src/kili/entrypoints/mutations/notification/__init__.py +++ b/src/kili/entrypoints/mutations/notification/__init__.py @@ -1,4 +1,5 @@ """Notification mutations.""" + from typing import Optional, Union from typeguard import typechecked diff --git a/src/kili/entrypoints/mutations/plugins/__init__.py b/src/kili/entrypoints/mutations/plugins/__init__.py index 1e2c992d2..78d9b891d 100644 --- a/src/kili/entrypoints/mutations/plugins/__init__.py +++ b/src/kili/entrypoints/mutations/plugins/__init__.py @@ -1,6 +1,6 @@ """Project mutations.""" -from typing import Optional +from typing import TYPE_CHECKING, Optional, cast from typeguard import typechecked from typing_extensions import LiteralString @@ -15,6 +15,9 @@ ) from kili.utils.logcontext import for_all_methods, log_call +if TYPE_CHECKING: + from kili.client import Kili + @for_all_methods(log_call, exclude=["__init__"]) class MutationsPlugins(BaseOperationEntrypointMixin): @@ -57,7 +60,7 @@ def upload_plugin( raise TypeError('"plugin_path is nullish, please provide a value') return PluginUploader( - self, # pyright: ignore[reportGeneralTypeIssues] + cast("Kili", self), plugin_path, plugin_name, verbose, @@ -106,7 +109,7 @@ def create_webhook( >>> kili.create_webhook(webhook_url='https://my-custom-url-publicly-accessible/', plugin_name='my webhook', header='...') """ return WebhookUploader( - self, # pyright: ignore[reportGeneralTypeIssues] + cast("Kili", self), webhook_url, plugin_name, header, @@ -148,7 +151,7 @@ def update_webhook( >>> kili.update_webhook(webhook_url='https://my-custom-url-publicly-accessible/', plugin_name='my webhook', header='...') """ return WebhookUploader( - self, # pyright: ignore[reportGeneralTypeIssues] + cast("Kili", self), new_webhook_url, plugin_name, new_header, @@ -246,7 +249,7 @@ def update_plugin( raise TypeError('"plugin_name is nullish, please provide a value') return PluginUploader( - self, # pyright: ignore[reportGeneralTypeIssues] + cast("Kili", self), plugin_path, plugin_name, verbose, diff --git a/src/kili/entrypoints/mutations/project/__init__.py b/src/kili/entrypoints/mutations/project/__init__.py index e6ab2125a..b4ce40e4e 100644 --- a/src/kili/entrypoints/mutations/project/__init__.py +++ b/src/kili/entrypoints/mutations/project/__init__.py @@ -1,6 +1,6 @@ """Project mutations.""" -from typing import Literal, Optional +from typing import TYPE_CHECKING, Literal, Optional, cast from typeguard import typechecked from typing_extensions import deprecated @@ -20,6 +20,9 @@ GQL_UPDATE_PROPERTIES_IN_ROLE, ) +if TYPE_CHECKING: + from kili.client import Kili + @for_all_methods(log_call, exclude=["__init__"]) class MutationsProject(BaseOperationEntrypointMixin): @@ -253,7 +256,7 @@ def copy_project( # pylint: disable=too-many-arguments "The 'copy_json_interface' and 'copy_quality_settings' arguments are deprecated." ) - return ProjectCopier(self).copy_project( # pyright: ignore[reportGeneralTypeIssues] + return ProjectCopier(cast("Kili", self)).copy_project( from_project_id, title, description, diff --git a/src/kili/entrypoints/queries/plugins/__init__.py b/src/kili/entrypoints/queries/plugins/__init__.py index c992bc4cd..f70305e32 100644 --- a/src/kili/entrypoints/queries/plugins/__init__.py +++ b/src/kili/entrypoints/queries/plugins/__init__.py @@ -2,7 +2,7 @@ import json from datetime import datetime -from typing import Optional +from typing import TYPE_CHECKING, Optional, cast from typeguard import typechecked @@ -17,6 +17,9 @@ from kili.services.plugins import PluginUploader from kili.utils.logcontext import for_all_methods, log_call +if TYPE_CHECKING: + from kili.client import Kili + @for_all_methods(log_call, exclude=["__init__"]) class QueriesPlugins(BaseOperationEntrypointMixin): @@ -108,7 +111,7 @@ def get_plugin_status( >>> kili.get_plugin_status(plugin_name="my_plugin_name") """ return PluginUploader( - self, # pyright: ignore[reportGeneralTypeIssues] + cast("Kili", self), "", plugin_name, verbose, diff --git a/src/kili/exceptions.py b/src/kili/exceptions.py index 7a5f6b1ab..e52899d22 100644 --- a/src/kili/exceptions.py +++ b/src/kili/exceptions.py @@ -20,7 +20,7 @@ def __init__(self, error, batch_number=None, context=None) -> None: if batch_number is None: super().__init__(f'GraphQL error: "{error_msg}"') else: - super().__init__(f'GraphQL error at index {100*batch_number}: {error_msg}"') + super().__init__(f'GraphQL error at index {100 * batch_number}: {error_msg}"') class NotFound(Exception): diff --git a/src/kili/presentation/client/helpers/filter_conversion.py b/src/kili/presentation/client/helpers/filter_conversion.py index 56e43f6c5..94d815574 100644 --- a/src/kili/presentation/client/helpers/filter_conversion.py +++ b/src/kili/presentation/client/helpers/filter_conversion.py @@ -1,6 +1,5 @@ """Module for common argument validators across client methods.""" - from kili.domain.project import ProjectStep diff --git a/src/kili/presentation/client/label.py b/src/kili/presentation/client/label.py index f996dfcbe..ecf28fdf4 100644 --- a/src/kili/presentation/client/label.py +++ b/src/kili/presentation/client/label.py @@ -61,6 +61,8 @@ if TYPE_CHECKING: import pandas as pd + from kili.client import Kili + @for_all_methods(log_call, exclude=["__init__"]) class LabelClientMethods(BaseClientMethods): @@ -674,6 +676,31 @@ def predictions( Examples: >>> kili.predictions(project_id=project_id) # returns a list of prediction labels of a project """ + if as_generator: + return self.labels( + project_id=project_id, + asset_id=asset_id, + asset_status_in=asset_status_in, + asset_external_id_in=asset_external_id_in, + asset_step_name_in=asset_step_name_in, + asset_step_status_in=asset_step_status_in, + author_in=author_in, + created_at=created_at, + created_at_gte=created_at_gte, + created_at_lte=created_at_lte, + fields=fields, + first=first, + honeypot_mark_gte=honeypot_mark_gte, + honeypot_mark_lte=honeypot_mark_lte, + id_contains=id_contains, + label_id=label_id, + skip=skip, + type_in=["PREDICTION"], + user_id=user_id, + disable_tqdm=disable_tqdm, + category_search=category_search, + as_generator=True, + ) return self.labels( project_id=project_id, asset_id=asset_id, @@ -696,7 +723,7 @@ def predictions( user_id=user_id, disable_tqdm=disable_tqdm, category_search=category_search, - as_generator=as_generator, # pyright: ignore[reportGeneralTypeIssues] + as_generator=False, ) @overload @@ -842,6 +869,31 @@ def inferences( Examples: >>> kili.inferences(project_id=project_id) # returns a list of inference labels of a project """ + if as_generator: + return self.labels( + project_id=project_id, + asset_id=asset_id, + asset_status_in=asset_status_in, + asset_external_id_in=asset_external_id_in, + asset_step_name_in=asset_step_name_in, + asset_step_status_in=asset_step_status_in, + author_in=author_in, + created_at=created_at, + created_at_gte=created_at_gte, + created_at_lte=created_at_lte, + fields=fields, + first=first, + honeypot_mark_gte=honeypot_mark_gte, + honeypot_mark_lte=honeypot_mark_lte, + id_contains=id_contains, + label_id=label_id, + skip=skip, + type_in=["INFERENCE"], + user_id=user_id, + disable_tqdm=disable_tqdm, + category_search=category_search, + as_generator=True, + ) return self.labels( project_id=project_id, asset_id=asset_id, @@ -864,7 +916,7 @@ def inferences( user_id=user_id, disable_tqdm=disable_tqdm, category_search=category_search, - as_generator=as_generator, # pyright: ignore[reportGeneralTypeIssues] + as_generator=False, ) @typechecked @@ -1197,11 +1249,15 @@ def append_to_labels( cast(list[AssetExternalId], [label_asset_external_id]), ProjectId(project_id) )[AssetExternalId(label_asset_external_id)] + if label_asset_id is None: + msg = "Either label_asset_id or label_asset_external_id must be provided" + raise ValueError(msg) + return LabelUseCases(self.kili_api_gateway).append_to_labels( author_id=UserId(author_id) if author_id else None, json_response=json_response, label_type=label_type, - asset_id=AssetId(label_asset_id), # pyright: ignore[reportGeneralTypeIssues] + asset_id=AssetId(label_asset_id), seconds_to_label=seconds_to_label, fields=("id",), ) @@ -1380,7 +1436,7 @@ def is_rectangle(coco_annotation, coco_image, kili_annotation): try: return export_labels( - self, # pyright: ignore[reportGeneralTypeIssues] + cast("Kili", self), asset_ids=resolved_asset_ids, project_id=ProjectId(project_id), export_type="latest", diff --git a/src/kili/presentation/client/project.py b/src/kili/presentation/client/project.py index 30c9c7596..4867c8d9a 100644 --- a/src/kili/presentation/client/project.py +++ b/src/kili/presentation/client/project.py @@ -1,4 +1,5 @@ """Client presentation methods for projects.""" + import warnings from collections.abc import Generator, Iterable from typing import ( diff --git a/src/kili/presentation/client/tag.py b/src/kili/presentation/client/tag.py index 34471f8fc..63d466a16 100644 --- a/src/kili/presentation/client/tag.py +++ b/src/kili/presentation/client/tag.py @@ -64,18 +64,20 @@ def tag_project( """ tag_use_cases = TagUseCases(self.kili_api_gateway) + resolved_tag_ids: ListOrTuple[TagId] if tag_ids is None: if tags is None: raise ValueError("Either `tags` or `tag_ids` must be provided.") - tag_ids = tag_use_cases.get_tag_ids_from_labels( - labels=tags # pyright: ignore[reportGeneralTypeIssues] - ) + resolved_tag_ids = tag_use_cases.get_tag_ids_from_labels(labels=tags) + else: + # Cast str to TagId (TagId is NewType("TagId", str), so runtime compatible) + resolved_tag_ids = [TagId(tag_id) for tag_id in tag_ids] return [ {"id": str(tag_id)} for tag_id in tag_use_cases.tag_project( project_id=ProjectId(project_id), - tag_ids=tag_ids, # pyright: ignore[reportGeneralTypeIssues] + tag_ids=resolved_tag_ids, disable_tqdm=disable_tqdm, ) ] @@ -110,26 +112,28 @@ def untag_project( tag_use_cases = TagUseCases(self.kili_api_gateway) + resolved_tag_ids: ListOrTuple[TagId] if tag_ids is None: if tags is not None: - tag_ids = tag_use_cases.get_tag_ids_from_labels( - labels=tags # pyright: ignore[reportGeneralTypeIssues] - ) + resolved_tag_ids = tag_use_cases.get_tag_ids_from_labels(labels=tags) elif all is not None: - tag_ids = [ - tag["id"] + resolved_tag_ids = [ + TagId(tag["id"]) for tag in tag_use_cases.get_tags_of_project( project_id=ProjectId(project_id), fields=("id",) ) ] else: raise ValueError("Either `tags` or `tag_ids` or `all` must be provided.") + else: + # Cast str to TagId (TagId is NewType("TagId", str), so runtime compatible) + resolved_tag_ids = [TagId(tag_id) for tag_id in tag_ids] return [ {"id": str(tag_id)} for tag_id in tag_use_cases.untag_project( project_id=ProjectId(project_id), - tag_ids=tag_ids, # pyright: ignore[reportGeneralTypeIssues] + tag_ids=resolved_tag_ids, disable_tqdm=disable_tqdm, ) ] diff --git a/src/kili/services/asset_import/pdf.py b/src/kili/services/asset_import/pdf.py index d6b62c412..2bb91c969 100644 --- a/src/kili/services/asset_import/pdf.py +++ b/src/kili/services/asset_import/pdf.py @@ -1,6 +1,5 @@ """Functions to import assets into a PDF project.""" - from kili.domain.project import InputType from .base import BaseAbstractAssetImporter, BatchParams, ContentBatchImporter diff --git a/src/kili/services/asset_import/video.py b/src/kili/services/asset_import/video.py index ca0cfa83e..20cfd8bce 100644 --- a/src/kili/services/asset_import/video.py +++ b/src/kili/services/asset_import/video.py @@ -40,9 +40,9 @@ class VideoMixin: def get_video_processing_parameters(asset: AssetLike): """Base method for adding video processing parameters.""" json_metadata = asset.get("json_metadata", {}) - return json_metadata.get( # pyright: ignore[reportGeneralTypeIssues] - "processingParameters", {} - ) + if isinstance(json_metadata, dict): + return json_metadata.get("processingParameters", {}) + return {} @staticmethod def map_frame_urls_to_index(asset: AssetLike): diff --git a/src/kili/services/export/format/base.py b/src/kili/services/export/format/base.py index cccb02647..8df6937d9 100644 --- a/src/kili/services/export/format/base.py +++ b/src/kili/services/export/format/base.py @@ -152,7 +152,7 @@ def create_readme_kili_file(self, root_folder: Path) -> None: fout.write(f"- Project name: {self.project['title']}\n".encode()) fout.write(f"- Project identifier: {self.project['id']}\n".encode()) fout.write(f"- Project description: {self.project.get('description', '')}\n".encode()) - fout.write(f'- Export date: {datetime.now().strftime(r"%Y%m%d-%H%M%S")}\n'.encode()) + fout.write(f"- Export date: {datetime.now().strftime(r'%Y%m%d-%H%M%S')}\n".encode()) fout.write(f"- Exported format: {self.label_format}\n".encode()) fout.write(f"- Exported labels: {self.export_type}\n".encode()) diff --git a/src/kili/services/export/format/coco/types.py b/src/kili/services/export/format/coco/types.py index 39bedab68..effadb927 100644 --- a/src/kili/services/export/format/coco/types.py +++ b/src/kili/services/export/format/coco/types.py @@ -1,6 +1,5 @@ """Types for the Coco export.""" - from typing_extensions import TypedDict diff --git a/src/kili/services/export/format/geojson/__init__.py b/src/kili/services/export/format/geojson/__init__.py index 7c9a53d31..7ee01ed71 100644 --- a/src/kili/services/export/format/geojson/__init__.py +++ b/src/kili/services/export/format/geojson/__init__.py @@ -94,7 +94,7 @@ def _process_asset(asset: dict, labels_folder: Path) -> None: geojson_feature_collection = convert_from_kili_to_geojson_format( asset["latestLabel"]["jsonResponse"] ) - filepath = labels_folder / f'{asset["externalId"]}.geojson' + filepath = labels_folder / f"{asset['externalId']}.geojson" filepath.parent.mkdir(parents=True, exist_ok=True) with open(filepath, "w", encoding="utf-8") as file: json.dump(geojson_feature_collection, file) diff --git a/src/kili/services/export/format/voc/__init__.py b/src/kili/services/export/format/voc/__init__.py index 7bb9d868d..dad5bef57 100644 --- a/src/kili/services/export/format/voc/__init__.py +++ b/src/kili/services/export/format/voc/__init__.py @@ -106,7 +106,7 @@ def _process_asset( raise FileNotFoundError(f"Could not find frames or video for asset {asset}") for frame_id, json_response in asset["latestLabel"]["jsonResponse"].items(): - frame_name = f'{asset["externalId"]}_{str(int(frame_id)+1).zfill(leading_zeros)}' + frame_name = f"{asset['externalId']}_{str(int(frame_id) + 1).zfill(leading_zeros)}" parameters = {"filename": f"{frame_name}{frame_ext}"} annotations = convert_from_kili_to_voc_format( json_response, width, height, parameters, valid_jobs @@ -126,7 +126,7 @@ def _process_asset( annotations = convert_from_kili_to_voc_format( json_response, width, height, parameters, valid_jobs ) - xml_filename = f'{asset["externalId"]}.xml' + xml_filename = f"{asset['externalId']}.xml" filepath = labels_folder / xml_filename filepath.parent.mkdir(parents=True, exist_ok=True) with open(filepath, "wb") as fout: diff --git a/src/kili/services/label_data_parsing/annotation.py b/src/kili/services/label_data_parsing/annotation.py index 51fd4e859..93b4fdc93 100644 --- a/src/kili/services/label_data_parsing/annotation.py +++ b/src/kili/services/label_data_parsing/annotation.py @@ -3,7 +3,7 @@ import functools from collections import defaultdict from collections.abc import Iterator, Sequence -from typing import Literal, Optional, Union +from typing import Any, Literal, Optional, Union, cast from typeguard import typechecked @@ -154,8 +154,8 @@ def children(self) -> "json_response_module.ParsedJobs": def children(self, children: dict) -> None: """Set the children jobs of the annotation job.""" job_names_to_parse = get_children_job_names( - json_interface=self._project_info["jsonInterface"], - job_interface=self._job_interface, # type: ignore + json_interface=cast(dict[Any, Any], self._project_info["jsonInterface"]), + job_interface=cast(dict[Any, Any], self._job_interface), ) parsed_children_job = json_response_module.ParsedJobs( project_info=self._project_info, diff --git a/src/kili/services/label_data_parsing/category.py b/src/kili/services/label_data_parsing/category.py index e7d9b3e8a..d3a990fb3 100644 --- a/src/kili/services/label_data_parsing/category.py +++ b/src/kili/services/label_data_parsing/category.py @@ -1,7 +1,7 @@ """Module for the "categories" key parsing of a job response.""" from collections.abc import Iterator -from typing import Any, Optional +from typing import Any, Optional, cast from typeguard import typechecked @@ -166,8 +166,8 @@ def children(self) -> "json_response_module.ParsedJobs": def children(self, children: dict) -> None: """Set the children jobs of the classification job.""" job_names_to_parse = get_children_job_names( - json_interface=self._project_info["jsonInterface"], - job_interface=self._job_interface, # pyright: ignore [reportGeneralTypeIssues] + json_interface=cast(dict[Any, Any], self._project_info["jsonInterface"]), + job_interface=cast(dict[Any, Any], self._job_interface), ) parsed_children_job = json_response_module.ParsedJobs( project_info=self._project_info, diff --git a/src/kili/services/label_data_parsing/job_response.py b/src/kili/services/label_data_parsing/job_response.py index a95b4c833..8c95f0bf8 100644 --- a/src/kili/services/label_data_parsing/job_response.py +++ b/src/kili/services/label_data_parsing/job_response.py @@ -1,7 +1,7 @@ """Classes for job response parsing.""" from datetime import datetime -from typing import Optional, cast +from typing import Any, Optional, cast from kili_formats.types import Job from typeguard import typechecked @@ -132,8 +132,8 @@ def children(self) -> "json_response_module.ParsedJobs": def children(self, children: dict) -> None: """Sets the children jobs of the job.""" job_names_to_parse = get_children_job_names( - json_interface=self._project_info["jsonInterface"], - job_interface=self._job_interface, # type: ignore + json_interface=cast(dict[Any, Any], self._project_info["jsonInterface"]), + job_interface=cast(dict[Any, Any], self._job_interface), ) parsed_children_job = json_response_module.ParsedJobs( project_info=self._project_info, diff --git a/src/kili/services/label_data_parsing/utils.py b/src/kili/services/label_data_parsing/utils.py index c3acb0654..31ac32548 100644 --- a/src/kili/services/label_data_parsing/utils.py +++ b/src/kili/services/label_data_parsing/utils.py @@ -1,7 +1,11 @@ """Set of utils for label data parsing service module.""" +from typing import Any -def get_children_job_names(json_interface: dict, job_interface: dict) -> list[str]: + +def get_children_job_names( + json_interface: dict[Any, Any], job_interface: dict[Any, Any] +) -> list[str]: """Returns the list of children job names of a parent job interface.""" children_job_names = [] diff --git a/src/kili/use_cases/asset/asset_label_parsing.py b/src/kili/use_cases/asset/asset_label_parsing.py index a7426433a..7b01da6ab 100644 --- a/src/kili/use_cases/asset/asset_label_parsing.py +++ b/src/kili/use_cases/asset/asset_label_parsing.py @@ -1,6 +1,5 @@ """Parsing of the labels of an asset.""" - from kili.services.label_data_parsing.types import Project as LabelParsingProject from kili.utils.labels.parsing import ParsedLabel, parse_labels diff --git a/src/kili/use_cases/asset/media_downloader.py b/src/kili/use_cases/asset/media_downloader.py index 052e2f76d..9ad9c73d7 100644 --- a/src/kili/use_cases/asset/media_downloader.py +++ b/src/kili/use_cases/asset/media_downloader.py @@ -147,7 +147,7 @@ def download_single_asset(self, asset: dict) -> dict[str, Any]: urls = tuple(json_content.values()) nbr_char_zfill = len(str(len(urls))) img_names = ( - f'{asset["externalId"]}_{f"{i+1}".zfill(nbr_char_zfill)}.jpg' + f"{asset['externalId']}_{f'{i + 1}'.zfill(nbr_char_zfill)}.jpg" for i, _ in enumerate(urls) ) with ThreadPoolExecutor() as threads: diff --git a/src/kili/use_cases/cloud_storage/azure.py b/src/kili/use_cases/cloud_storage/azure.py index d1fe1faf0..a3e49bbc5 100644 --- a/src/kili/use_cases/cloud_storage/azure.py +++ b/src/kili/use_cases/cloud_storage/azure.py @@ -17,7 +17,7 @@ def get_blob_paths_azure_data_connection_with_service_credentials( if not (data_integration["azureSASToken"] and data_integration["azureConnectionURL"]): raise ValueError( f"Cannot retrieve blob paths for data connection {data_connection['id']} with data" - f" integration {data_integration['id']}. Need to provide \"azureSASToken\" and" + f' integration {data_integration["id"]}. Need to provide "azureSASToken" and' f' "azureConnectionURL" in data integration: {data_integration}' ) @@ -128,16 +128,18 @@ def get_blob_paths_azure_data_connection_with_service_credentials( if len(exclude) > 0 and any(re.match(pattern, blob.name) for pattern in exclude): continue - has_content_type_field = ( - hasattr(blob, "content_settings") + content_type = ( + blob.content_settings.content_type + if hasattr(blob, "content_settings") and hasattr(blob.content_settings, "content_type") - and isinstance(blob.content_settings.content_type, str) + else None ) - if not has_content_type_field: + + if not isinstance(content_type, str): warnings.add("Objects with missing content-type were ignored") elif not self._is_content_type_compatible_with_input_type( - blob.content_settings.content_type, # pyright: ignore[reportGeneralTypeIssues] + content_type, input_type, ): warnings.add( @@ -146,7 +148,7 @@ def get_blob_paths_azure_data_connection_with_service_credentials( else: blob_paths.append(blob.name) - content_types.append(blob.content_settings.content_type) + content_types.append(content_type) return blob_paths, list(warnings), content_types diff --git a/src/kili/use_cases/label/__init__.py b/src/kili/use_cases/label/__init__.py index 052a19122..f519b4dff 100644 --- a/src/kili/use_cases/label/__init__.py +++ b/src/kili/use_cases/label/__init__.py @@ -108,19 +108,25 @@ def append_labels( asset_id_array = [label.asset_id for label in labels] if any(asset_id is None for asset_id in asset_id_array): - external_id_array = [label.asset_external_id for label in labels] + external_id_array = [ + label.asset_external_id for label in labels if label.asset_external_id is not None + ] + if len(external_id_array) != len(labels): + msg = "Either asset_id or asset_external_id must be provided for all labels" + raise ValueError(msg) asset_id_array = AssetUseCasesUtils( self._kili_api_gateway ).get_asset_ids_or_throw_error( asset_ids=None, - external_ids=external_id_array, # pyright: ignore[reportGeneralTypeIssues] + external_ids=external_id_array, project_id=project_id, ) + # At this point asset_id_array should have all non-None values labels_to_add = [ AppendLabelData( author_id=label.author_id, - asset_id=asset_id, # pyright: ignore[reportGeneralTypeIssues] + asset_id=asset_id, # All asset_ids are now guaranteed to be non-None seconds_to_label=label.seconds_to_label, json_response=label.json_response, model_name=label.model_name, @@ -128,6 +134,7 @@ def append_labels( referenced_label_id=label.referenced_label_id, ) for label, asset_id in zip(labels, asset_id_array, strict=False) + if asset_id is not None ] data = AppendManyLabelsData( diff --git a/src/kili/use_cases/label/process_shapefiles.py b/src/kili/use_cases/label/process_shapefiles.py index 4a19f533d..a2ba1d652 100644 --- a/src/kili/use_cases/label/process_shapefiles.py +++ b/src/kili/use_cases/label/process_shapefiles.py @@ -286,9 +286,18 @@ def _remove_duplicate_points(coords): def _process_marker_records(point_records, category_name, from_epsg, json_response, job_name): """Process point records for marker job type.""" + try: + from shapely.geometry import Point # pylint: disable=import-outside-toplevel + except ImportError as e: + raise ImportError("Install with `pip install kili[gis]` to use GIS features.") from e + for point_record in point_records: point = _transform_geometry(point_record, from_epsg) + if not isinstance(point, Point): + msg = f"Expected Point geometry, got {type(point)}" + raise TypeError(msg) + annotation = { "point": {"x": point.x, "y": point.y}, "categories": [{"name": category_name}], diff --git a/src/kili/use_cases/label/validator.py b/src/kili/use_cases/label/validator.py index d312edc3c..82f2cddae 100644 --- a/src/kili/use_cases/label/validator.py +++ b/src/kili/use_cases/label/validator.py @@ -1,6 +1,5 @@ """Validator for import of labels.""" - from typeguard import typechecked from .types import LabelToCreateUseCaseInput diff --git a/tests/e2e/create_project.ipynb b/tests/e2e/create_project.ipynb index 4f9e16ce1..2adf075d1 100644 --- a/tests/e2e/create_project.ipynb +++ b/tests/e2e/create_project.ipynb @@ -148,7 +148,7 @@ "project = kili.create_project(\n", " title=title, description=description, input_type=input_type, json_interface=json_interface\n", ")\n", - "print(f'Created project {project[\"id\"]}')" + "print(f\"Created project {project['id']}\")" ] }, { diff --git a/tests/integration/entrypoints/cli/project/test_label_import.py b/tests/integration/entrypoints/cli/project/test_label_import.py index 3a0b712bf..7ffeca8fe 100644 --- a/tests/integration/entrypoints/cli/project/test_label_import.py +++ b/tests/integration/entrypoints/cli/project/test_label_import.py @@ -180,9 +180,12 @@ def test_import_labels_yolo(name: str, test_case: dict, mocker: pytest_mock.Mock _ = name runner = CliRunner() - with runner.isolated_filesystem(), patch( - "kili.services.label_import.import_labels_from_files" - ) as mocked_import_labels_service: + with ( + runner.isolated_filesystem(), + patch( + "kili.services.label_import.import_labels_from_files" + ) as mocked_import_labels_service, + ): arguments = test_case["files"] for k, v in test_case["options"].items(): arguments.append("--" + k) diff --git a/tests/unit/domain_api/test_assets_integration.py b/tests/unit/domain_api/test_assets_integration.py index 2a4ade977..039d3ba16 100644 --- a/tests/unit/domain_api/test_assets_integration.py +++ b/tests/unit/domain_api/test_assets_integration.py @@ -24,11 +24,14 @@ def mock_http_client(self): @pytest.fixture() def mock_kili_client(self, mock_graphql_client, mock_http_client): """Create a mock Kili client with proper structure.""" - with patch("kili.client.GraphQLClient"), patch("kili.client.HttpClient"), patch( - "kili.client.KiliAPIGateway" - ) as mock_gateway_class, patch("kili.client.ApiKeyUseCases"), patch( - "kili.client.is_api_key_valid" - ), patch.dict("os.environ", {"KILI_SDK_SKIP_CHECKS": "1"}): + with ( + patch("kili.client.GraphQLClient"), + patch("kili.client.HttpClient"), + patch("kili.client.KiliAPIGateway") as mock_gateway_class, + patch("kili.client.ApiKeyUseCases"), + patch("kili.client.is_api_key_valid"), + patch.dict("os.environ", {"KILI_SDK_SKIP_CHECKS": "1"}), + ): mock_gateway = MagicMock(spec=KiliAPIGateway) mock_gateway_class.return_value = mock_gateway mock_gateway.get_project.return_value = { diff --git a/tests/unit/llm/services/export/test_llm_dynamic_export.py b/tests/unit/llm/services/export/test_llm_dynamic_export.py index 78813d6f3..7c96784b9 100644 --- a/tests/unit/llm/services/export/test_llm_dynamic_export.py +++ b/tests/unit/llm/services/export/test_llm_dynamic_export.py @@ -649,15 +649,13 @@ "role": "USER", }, { - "content": " I'm doing well, thank you! How about you? How " - "can I assist you today?", + "content": " I'm doing well, thank you! How about you? How can I assist you today?", "externalId": "cm5wnv6ax01gvp30w2q9ba29v", "modelName": "AI21-Jamba-1-5-Large-ykxca", "role": "ASSISTANT", }, { - "content": " I'm doing well, thank you! How about you? How " - "can I assist you today?", + "content": " I'm doing well, thank you! How about you? How can I assist you today?", "externalId": "cm5wnv6b501gwp30w764fegsi", "modelName": "AI21-Jamba-1-5-Large-ykxca", "role": "ASSISTANT", diff --git a/tests/unit/services/export/test_export.py b/tests/unit/services/export/test_export.py index 6dc1793f5..024f6b09a 100644 --- a/tests/unit/services/export/test_export.py +++ b/tests/unit/services/export/test_export.py @@ -350,13 +350,13 @@ def get_file_tree(folder: str): }, "file_tree_expected": { "images": { - **{f"video2_{str(i+1).zfill(3)}.jpg": {} for i in range(130)}, - **{f"short_video_{str(i+1).zfill(2)}.jpg": {} for i in range(28)}, + **{f"video2_{str(i + 1).zfill(3)}.jpg": {} for i in range(130)}, + **{f"short_video_{str(i + 1).zfill(2)}.jpg": {} for i in range(28)}, "short_video.mp4": {}, }, "labels": { - **{f"video2_{str(i+1).zfill(3)}.xml": {} for i in range(130)}, - **{f"short_video_{str(i+1).zfill(2)}.xml": {} for i in range(28)}, + **{f"video2_{str(i + 1).zfill(3)}.xml": {} for i in range(130)}, + **{f"short_video_{str(i + 1).zfill(2)}.xml": {} for i in range(28)}, }, "README.kili.txt": {}, }, @@ -372,8 +372,8 @@ def get_file_tree(folder: str): }, "file_tree_expected": { "data": { - **{f"video2_{str(i+1).zfill(3)}.jpg": {} for i in range(130)}, - **{f"short_video_{str(i+1).zfill(2)}.jpg": {} for i in range(28)}, + **{f"video2_{str(i + 1).zfill(3)}.jpg": {} for i in range(130)}, + **{f"short_video_{str(i + 1).zfill(2)}.jpg": {} for i in range(28)}, "short_video.mp4": {}, }, "JOB_0": { @@ -393,8 +393,8 @@ def get_file_tree(folder: str): }, "file_tree_expected": { "data": { - **{f"video2_{str(i+1).zfill(3)}.jpg": {} for i in range(130)}, - **{f"short_video_{str(i+1).zfill(2)}.jpg": {} for i in range(28)}, + **{f"video2_{str(i + 1).zfill(3)}.jpg": {} for i in range(130)}, + **{f"short_video_{str(i + 1).zfill(2)}.jpg": {} for i in range(28)}, "short_video.mp4": {}, }, "labels.json": {}, @@ -436,8 +436,8 @@ def get_file_tree(folder: str): }, "file_tree_expected": { "images": { - **{f"video2_{str(i+1).zfill(3)}.jpg": {} for i in range(130)}, - **{f"short_video_{str(i+1).zfill(2)}.jpg": {} for i in range(28)}, + **{f"video2_{str(i + 1).zfill(3)}.jpg": {} for i in range(130)}, + **{f"short_video_{str(i + 1).zfill(2)}.jpg": {} for i in range(28)}, "short_video.mp4": {}, }, "labels": { @@ -463,8 +463,8 @@ def get_file_tree(folder: str): }, "file_tree_expected": { "images": { - **{f"video2_{str(i+1).zfill(3)}.jpg": {} for i in range(130)}, - **{f"short_video_{str(i+1).zfill(2)}.jpg": {} for i in range(28)}, + **{f"video2_{str(i + 1).zfill(3)}.jpg": {} for i in range(130)}, + **{f"short_video_{str(i + 1).zfill(2)}.jpg": {} for i in range(28)}, "short_video.mp4": {}, }, "labels": { @@ -512,8 +512,8 @@ def get_file_tree(folder: str): }, "file_tree_expected": { "assets": { - **{f"video2_{str(i+1).zfill(3)}.jpg": {} for i in range(130)}, - **{f"short_video_{str(i+1).zfill(2)}.jpg": {} for i in range(28)}, + **{f"video2_{str(i + 1).zfill(3)}.jpg": {} for i in range(130)}, + **{f"short_video_{str(i + 1).zfill(2)}.jpg": {} for i in range(28)}, "short_video.mp4": {}, }, "labels": {"video2.json": {}, "short_video.json": {}}, diff --git a/tests/unit/services/export/test_voc.py b/tests/unit/services/export/test_voc.py index df955eba5..486820dd0 100644 --- a/tests/unit/services/export/test_voc.py +++ b/tests/unit/services/export/test_voc.py @@ -18,7 +18,7 @@ def test__convert_from_kili_to_voc_format(): - parameters = {"filename": f'{asset_image_1_with_0_rotation["externalId"]}.xml'} + parameters = {"filename": f"{asset_image_1_with_0_rotation['externalId']}.xml"} annotations = convert_from_kili_to_voc_format( response=asset_image_1_with_0_rotation["latestLabel"]["jsonResponse"], width=1920, @@ -31,7 +31,7 @@ def test__convert_from_kili_to_voc_format(): ).read_text(encoding="utf-8") assert annotations == expected_annotations - parameters = {"filename": f'{asset_image_1_with_90_rotation["externalId"]}.xml'} + parameters = {"filename": f"{asset_image_1_with_90_rotation['externalId']}.xml"} annotations = convert_from_kili_to_voc_format( response=asset_image_1_with_90_rotation["latestLabel"]["jsonResponse"], width=1920, @@ -44,7 +44,7 @@ def test__convert_from_kili_to_voc_format(): ).read_text(encoding="utf-8") assert annotations == expected_annotations - parameters = {"filename": f'{asset_image_1_with_180_rotation["externalId"]}.xml'} + parameters = {"filename": f"{asset_image_1_with_180_rotation['externalId']}.xml"} annotations = convert_from_kili_to_voc_format( response=asset_image_1_with_180_rotation["latestLabel"]["jsonResponse"], width=1920, @@ -57,7 +57,7 @@ def test__convert_from_kili_to_voc_format(): ).read_text(encoding="utf-8") assert annotations == expected_annotations - parameters = {"filename": f'{asset_image_1_with_270_rotation["externalId"]}.xml'} + parameters = {"filename": f"{asset_image_1_with_270_rotation['externalId']}.xml"} annotations = convert_from_kili_to_voc_format( response=asset_image_1_with_270_rotation["latestLabel"]["jsonResponse"], width=1920, @@ -72,7 +72,7 @@ def test__convert_from_kili_to_voc_format(): def test__convert_from_kili_to_voc_format_no_annotation(): - parameters = {"filename": f'{asset_image_1["externalId"]}.xml'} + parameters = {"filename": f"{asset_image_1['externalId']}.xml"} annotations = convert_from_kili_to_voc_format( response=asset_image_1_without_annotation, width=1920, diff --git a/tests/unit/services/export/test_yolo.py b/tests/unit/services/export/test_yolo.py index bfcf3d416..3312e3471 100644 --- a/tests/unit/services/export/test_yolo.py +++ b/tests/unit/services/export/test_yolo.py @@ -126,19 +126,19 @@ def test_process_asset_for_job_frame_not_served_by_kili(): assert nb_files == 4 for i in range(nb_files): - assert (labels_folder / f"video_1_{i+1}.txt").is_file() + assert (labels_folder / f"video_1_{i + 1}.txt").is_file() expected_content = [ [ "video_1", "https://storage.googleapis.com/label-public-staging/video1/video1.mp4", - f"video_1_{i+1}.txt", + f"video_1_{i + 1}.txt", ] for i in range(4) ] assert asset_remote_content == expected_content - expected_video_filenames = [f"video_1_{i+1}" for i in range(4)] + expected_video_filenames = [f"video_1_{i + 1}" for i in range(4)] assert len(video_filenames) == 4 assert video_filenames == expected_video_filenames diff --git a/tests/unit/test_media_downloader.py b/tests/unit/test_media_downloader.py index c37b70925..20c96e4b8 100644 --- a/tests/unit/test_media_downloader.py +++ b/tests/unit/test_media_downloader.py @@ -128,10 +128,10 @@ def test_download_single_asset_jsoncontent(input_asset): frames = [ filename for filename in os.listdir(tmp_dir) - if filename.startswith(f'{input_asset["externalId"]}_') + if filename.startswith(f"{input_asset['externalId']}_") ] assert len(frames) == 130 - assert sorted(frames)[0] == f'{input_asset["externalId"]}_001.jpg' + assert sorted(frames)[0] == f"{input_asset['externalId']}_001.jpg" assert output_asset["externalId"] == input_asset["externalId"]