ENPICOM Logo API Docs Python SDK Docs Events

enpi_api.l2.client.api.sequence_annotation_api

  1from typing import cast
  2
  3from loguru import logger
  4from pydantic import StrictStr
  5
  6from enpi_api.l1 import openapi_client
  7from enpi_api.l2.client.api.collection_api import CollectionApi
  8from enpi_api.l2.events.workflow_execution_task_waitable import WorkflowExecutionTaskWaitable
  9from enpi_api.l2.types.api_error import ApiError, ApiErrorContext
 10from enpi_api.l2.types.collection import CollectionId, CollectionMetadata
 11from enpi_api.l2.types.execution import Execution
 12from enpi_api.l2.types.file import FileId
 13from enpi_api.l2.types.log import LogLevel
 14from enpi_api.l2.types.reference_database import ReferenceDatabaseRevision
 15from enpi_api.l2.types.sequence_annotation import (
 16    CloneIdentifierExtractionConfig,
 17    CorrectionSettings,
 18    LiabilityType,
 19    MutationAssaySettings,
 20    QualityControlTemplate,
 21    SequenceTemplate,
 22    SequenceTemplateConfig,
 23)
 24from enpi_api.l2.types.tag import TagId
 25from enpi_api.l2.types.task import TaskState
 26from enpi_api.l2.types.workflow import WorkflowExecutionId, WorkflowExecutionTaskId, WorkflowTaskTemplateName
 27
 28
 29class MultipleSequenceTemplatesWithName(Exception):
 30    """Indicates that multiple sequence templates with the given name can be found."""
 31
 32    def __init__(self, name: str) -> None:
 33        """@private"""
 34        super().__init__(
 35            f"Multiple sequence templates with name '{name}' found, ensure the names are unique, or use the "
 36            f"`get_sequence_templates` method to filter them yourself"
 37        )
 38
 39
 40class NoQualityControlTemplateWithName(Exception):
 41    """Indicates that no quality control template with the given name can be found."""
 42
 43    def __init__(self, name: str) -> None:
 44        """@private"""
 45        super().__init__(f"No quality control template with name '{name}' found")
 46
 47
 48class MultipleQualityControlTemplatesWithName(Exception):
 49    """Indicates that multiple quality control templates with the given name can be found."""
 50
 51    def __init__(self, name: str) -> None:
 52        """@private"""
 53        super().__init__(
 54            f"Multiple quality control templates with name '{name}' found, ensure the names are unique, or use the "
 55            f"`get_quality_control_templates` method to filter them yourself"
 56        )
 57
 58
 59class NoSequenceTemplateWithName(Exception):
 60    """Indicates that no sequence template with the given name can be found."""
 61
 62    def __init__(self, name: str) -> None:
 63        """@private"""
 64        super().__init__(f"No sequence template with name '{name}' found")
 65
 66
 67class SequenceAnnotationApi:
 68    _inner_api_client: openapi_client.ApiClient
 69    _log_level: LogLevel
 70
 71    def __init__(self, inner_api_client: openapi_client.ApiClient, log_level: LogLevel):
 72        """@private"""
 73        self._inner_api_client = inner_api_client
 74        self._log_level = log_level
 75
 76    def get_quality_control_templates(self) -> list[QualityControlTemplate]:
 77        """Get a list of all quality control templates owned by you or shared with you.
 78
 79        Returns:
 80            list[enpi_api.l2.types.sequence_annotation.QualityControlTemplate]: A list of quality control templates.
 81
 82        Raises:
 83            enpi_api.l2.types.api_error.ApiError: If API request fails.
 84
 85        Example:
 86            ```python
 87            quality_control_templates = self.get_quality_control_templates()
 88            ```
 89        """
 90
 91        sequence_annotation_api_instance = openapi_client.SequenceAnnotationApi(self._inner_api_client)
 92
 93        try:
 94            return [QualityControlTemplate.from_raw(i) for i in sequence_annotation_api_instance.quality_control_templates()]
 95        except openapi_client.ApiException as e:
 96            raise ApiError(e)
 97
 98    def get_quality_control_template_by_name(self, name: str) -> QualityControlTemplate:
 99        """Get a quality control template by its name.
100
101        It will raise an error if not exactly one quality control template with the given name is found.
102
103        Args:
104            name (str): The name of the quality control template to get.
105
106        Returns:
107            enpi_api.l2.types.sequence_annotation.QualityControlTemplate: The quality control template.
108
109        Raises:
110            enpi_api.l2.client.api.sequence_annotation_api.NoQualityControlTemplateWithName: If no quality control template with the given name can be found.
111            enpi_api.l2.client.api.sequence_annotation_api.MultipleQualityControlTemplatesWithName: If multiple quality control templates with the given name can be found.
112            enpi_api.l2.types.api_error.ApiError: If API request fails.
113
114        Example:
115            ```python
116            name = "Quality control template 1"
117            quality_control_template = self.get_quality_control_template_by_name(name)
118            ```
119        """
120
121        quality_control_templates = self.get_quality_control_templates()
122
123        matching_templates = [qct for qct in quality_control_templates if qct.name == name]
124
125        if len(matching_templates) == 0:
126            raise NoQualityControlTemplateWithName(name)
127        elif len(matching_templates) > 1:
128            raise MultipleQualityControlTemplatesWithName(name)
129
130        return matching_templates[0]
131
132    def get_sequence_templates(self) -> list[SequenceTemplate]:
133        """Get a list of all sequence templates owned by you or shared with you.
134
135        Returns:
136            list[enpi_api.l2.types.sequence_annotation.SequenceTemplate]: A list of sequence templates
137
138        Raises:
139            enpi_api.l2.types.api_error.ApiError: If API request fails.
140
141        Example:
142            ```python
143            sequence_templates = self.get_sequence_templates()
144            ```
145        """
146
147        sequence_annotation_api_instance = openapi_client.SequenceAnnotationApi(self._inner_api_client)
148
149        try:
150            return [SequenceTemplate.from_raw(i) for i in sequence_annotation_api_instance.sequence_templates()]
151        except openapi_client.ApiException as e:
152            raise ApiError(e)
153
154    def get_sequence_template_by_name(self, name: str) -> SequenceTemplate:
155        """Get a sequence template by its name.
156
157        It will raise an error if not exactly one sequence template with the given name is found.
158
159        Args:
160            name (str): The name of the sequence template to get.
161
162        Raises:
163            enpi_api.l2.client.api.sequence_annotation_api.NoSequenceTemplateWithName: If no sequence template with the given name can be found.
164            enpi_api.l2.client.api.sequence_annotation_api.MultipleSequenceTemplatesWithName: If multiple sequence templates with the given name can be found.
165            enpi_api.l2.types.api_error.ApiError: If API request fails.
166
167        Returns:
168            enpi_api.l2.types.sequence_annotation.SequenceTemplate: The sequence template.
169
170        Example:
171            ```python
172            name = "Sequence template 1"
173            sequence_template = self.get_sequence_template_by_name(name)
174            ```
175        """
176
177        sequence_templates = self.get_sequence_templates()
178
179        matching_templates = [st for st in sequence_templates if st.name == name]
180
181        if len(matching_templates) == 0:
182            raise NoSequenceTemplateWithName(name)
183        elif len(matching_templates) > 1:
184            raise MultipleSequenceTemplatesWithName(name)
185
186        return matching_templates[0]
187
188    def start(
189        self,
190        name: str,
191        file_ids: list[FileId],
192        sequence_templates: list[SequenceTemplateConfig],
193        reference_database_revision: ReferenceDatabaseRevision,
194        quality_control_template: QualityControlTemplate,
195        archive_inputs: bool = False,
196        clone_id_extraction: CloneIdentifierExtractionConfig | None = None,
197        correction_settings: CorrectionSettings | None = None,
198        mutation_assay_settings: MutationAssaySettings | None = None,
199        chain_fraction_tag_id: TagId | None = None,
200        liability_check: list[LiabilityType | str] = [],
201        restrict_deduplication_within_file: bool = False,
202        should_deduplicate_on_amino_acids: bool = False,
203        filename_tag_id: TagId | None = None,
204    ) -> Execution[CollectionMetadata]:
205        """Start Sequence Annotation on raw sequencing data.
206
207        A sequence template (available here: enpi_api.l2.client.api.sequence_annotation_api.SequenceAnnotationApi.get_sequence_template_by_name) and a quality control template
208        (enpi_api.l2.client.api.sequence_annotation_api.SequenceAnnotationApi.get_quality_control_template_by_name) are required in order to run a Sequence Annotation task.
209        **<u>Templates can be created and configured only via the [web interface of ENPICOM-Platform](https://igx.bio/)</u>**, it can not
210        be done through SDK or API. Additionally, getting familiar with Sequence Annotation in the web interface can help
211        in understanding it and setting up a desired task configuration due to it being more informative than the
212        minimal documentation provided for this function.
213
214        Args:
215            name (str): The name of the resulting collection.
216            file_ids (list[enpi_api.l2.types.file.FileId]): List of the IDs of raw sequencing data files.
217            sequence_templates (list[enpi_api.l2.types.sequence_annotation.SequenceTemplateConfig]): A list of configuration objects to specify the sequence
218              templates to be used. For more information, see the `enpi_api.l2.types.sequence_annotation.SequenceTemplateConfig` class.
219            reference_database_revision (enpi_api.l2.types.reference_database.ReferenceDatabaseRevision | None): The reference database revision to use.
220              The reference database specifies which organism it is linked to.
221            archive_inputs (bool): Whether to archive the input files after the Sequence Annotation run is finished.
222            quality_control_template (enpi_api.l2.types.sequence_annotation.QualityControlTemplate): The Quality Control Template to use.
223            clone_id_extraction (enpi_api.l2.types.sequence_annotation.CloneIdentifierExtractionConfig | None): The configuration for extracting clone IDs. This is only
224              needed if your sequence template has the option "Manually Specify Clone Identifier" enabled. In other
225              cases, this parameter can be omitted.
226
227              For more information, see the `enpi_api.l2.types.sequence_annotation.CloneIdentifierExtractionConfig` class.
228            correction_settings (enpi_api.l2.types.sequence_annotation.CorrectionSettings | None): The settings to correct regions to the germline reference,
229            or complete the sequence to full VDJ using germline reference nucleotides.
230            This is useful to reduce artificial diversity in libraries with e.g. fixed framework regions.
231            mutation_assay_settings (enpi_api.l2.types.sequence_annotation.MutationAssaySettings | None): The settings to run Sequence Annotation for a mutation assay.
232            chain_fraction_tag_id (enpi_api.l2.types.tag.TagId | None): The sequence-level tag identifier of the tag that is used to store
233              the fraction of each chain within a clone.
234            liability_check (list[enpi_api.l2.types.sequence_annotation.LiabilityType | str]): A list of liability checks to perform.
235              Summed counts are stored as clone level tags.
236
237        Raises:
238            enpi_api.l2.types.api_error.ApiError: If API request fails.
239
240        Returns:
241            enpi_api.l2.types.execution.Execution[enpi_api.l2.types.collection.CollectionMetadata]: An object that allows you to wait for the
242              execution to finish and get the resulting collection metadata.
243
244        Example:
245
246            Part of `start_sequence_annotation_run.py` example script.
247
248            ```python
249            # Templates need to be present in the ENPICOM-Platform already
250            sequence_template_name = "sequence template 1"
251            quality_control_template_name = "quality control template 1"
252
253            sequence_templates = [st for st in client.sequence_annotation_api.get_sequence_templates() if st.name == sequence_template_name]
254            quality_control_templates = [qct for qct in client.sequence_annotation_api.get_quality_control_templates() if qct.name == quality_control_template_name]
255
256            quality_control_template = QualityControlTemplate(quality_control_templates[0])
257            sequence_template_id = SequenceTemplateId(sequence_templates[0].id)
258
259            # Upload the input file
260            file_path = "data.fq"
261            file: File = client.file_api.upload_file(file_path=file_path, tags=[]).wait()
262            file_ids = [file.id]
263
264            # Get the reference database revision
265            reference_database_revision = client.reference_database_api.get_revision_by_name(name=REFERENCE_NAME, species=ORGANISM)
266
267            collection_name = "New collection from Sequence Annotation"
268
269            # We will now start Sequence Annotation, which will process raw sequencing data into annotated clone collections
270            clone_collection = client.sequence_annotation_api.start(
271                name=collection_name,
272                file_ids=file_ids,
273                # To assign a sequence template to each input file
274                sequence_templates=[
275                    SequenceTemplateConfig(
276                        # We select it using a selector, in this case by matching the file_id, but we could also match on file name or tags
277                        selector=SequenceTemplateSelector(value=f),
278                        # And then assign it using a sequence template id
279                        id=sequence_template_id,
280                    )
281                    for f in file_ids
282                ],
283                reference_database_revision=reference_database_revision,
284                # Archives the raw sequencing data after they have been processed
285                archive_inputs=True,
286                quality_control_template=quality_control_template,
287            ).wait()
288            ```
289        """
290
291        if filename_tag_id is not None:
292            if not restrict_deduplication_within_file:
293                raise ValueError("filename_tag_id can only be set if restrict_deduplication_within_file is set to True")
294
295        sequence_annotation_api_instance = openapi_client.SequenceAnnotationApi(self._inner_api_client)
296
297        try:
298            inner_sequence_templates: list[openapi_client.SequenceAnnotationWorkSequenceTemplatesInner] = []
299            for st in sequence_templates:
300                match st.selector.type:
301                    case "file_id":
302                        inner_sequence_templates.append(
303                            openapi_client.SequenceAnnotationWorkSequenceTemplatesInner(
304                                template_id=st.id,
305                                template_version=st.version,
306                                selector=openapi_client.SequenceTemplateSelector(
307                                    openapi_client.MatchAFileByItsID(type=st.selector.type, value=st.selector.value)
308                                ),
309                            )
310                        )
311                    case _:
312                        assert False, f"Selector type {st.selector.type} should be matched"
313
314            sequence_annotation_work = openapi_client.SequenceAnnotationWork(
315                name=name,
316                file_ids=cast(list[StrictStr], file_ids),
317                sequence_templates=inner_sequence_templates,
318                reference_database=openapi_client.ReferenceDatabaseIdVersion(
319                    id=str(reference_database_revision.reference_database_id),
320                    version=int(reference_database_revision.reference_database_version),
321                ),
322                quality_control_template=openapi_client.QualityControlTemplateIdOptionalVersion(
323                    id=str(quality_control_template.id), version=int(quality_control_template.version)
324                ),
325                archive_inputs=archive_inputs,
326                clone_id_to_tag_spec=clone_id_extraction.to_api_payload() if clone_id_extraction else None,
327                correction_settings=correction_settings.to_api_payload() if correction_settings else None,
328                mutation_assay_settings=mutation_assay_settings.to_api_payload() if mutation_assay_settings else None,
329                chain_fraction_tag_id=chain_fraction_tag_id,
330                liability_check=liability_check,
331                restrict_deduplication_within_file=restrict_deduplication_within_file,
332                should_deduplicate_on_amino_acids=should_deduplicate_on_amino_acids,
333                filename_tag_id=filename_tag_id,
334            )
335
336            with ApiErrorContext():
337                sequence_annotation_job = sequence_annotation_api_instance.start_sequence_annotation(sequence_annotation_work=sequence_annotation_work)
338                assert sequence_annotation_job.workflow_execution_id is not None
339
340                workflow_execution_id = WorkflowExecutionId(int(sequence_annotation_job.workflow_execution_id))
341
342                def on_complete(task_id: WorkflowExecutionTaskId, task_state: TaskState) -> CollectionMetadata:
343                    assert task_state == TaskState.SUCCEEDED, f"Task {task_id} did not reach {TaskState.SUCCEEDED} state, got {task_state} state instead"
344
345                    get_collection_id_response = sequence_annotation_api_instance.get_sequence_annotation_collection_id_by_workflow_execution_task_id(task_id)
346                    collection_id = get_collection_id_response.collection_id
347                    assert collection_id is not None
348
349                    logger.success(f"Collection with ID `{collection_id}` was successfully obtained by running Sequence Annotation")
350
351                    collection_api = CollectionApi(self._inner_api_client, self._log_level)
352                    return collection_api.get_collection_metadata_by_id(CollectionId(collection_id))
353
354                waitable = WorkflowExecutionTaskWaitable[CollectionMetadata](
355                    workflow_execution_id=workflow_execution_id,
356                    task_template_name=WorkflowTaskTemplateName.ENPI_APP_SEQUENCE_ANNOTATION,
357                    on_complete=on_complete,
358                )
359
360                return Execution(wait=waitable.wait_and_return_result, check_execution_state=waitable.check_execution_state)
361
362        except openapi_client.ApiException as e:
363            raise ApiError(e)
class MultipleSequenceTemplatesWithName(builtins.Exception):
30class MultipleSequenceTemplatesWithName(Exception):
31    """Indicates that multiple sequence templates with the given name can be found."""
32
33    def __init__(self, name: str) -> None:
34        """@private"""
35        super().__init__(
36            f"Multiple sequence templates with name '{name}' found, ensure the names are unique, or use the "
37            f"`get_sequence_templates` method to filter them yourself"
38        )

Indicates that multiple sequence templates with the given name can be found.

class NoQualityControlTemplateWithName(builtins.Exception):
41class NoQualityControlTemplateWithName(Exception):
42    """Indicates that no quality control template with the given name can be found."""
43
44    def __init__(self, name: str) -> None:
45        """@private"""
46        super().__init__(f"No quality control template with name '{name}' found")

Indicates that no quality control template with the given name can be found.

class MultipleQualityControlTemplatesWithName(builtins.Exception):
49class MultipleQualityControlTemplatesWithName(Exception):
50    """Indicates that multiple quality control templates with the given name can be found."""
51
52    def __init__(self, name: str) -> None:
53        """@private"""
54        super().__init__(
55            f"Multiple quality control templates with name '{name}' found, ensure the names are unique, or use the "
56            f"`get_quality_control_templates` method to filter them yourself"
57        )

Indicates that multiple quality control templates with the given name can be found.

class NoSequenceTemplateWithName(builtins.Exception):
60class NoSequenceTemplateWithName(Exception):
61    """Indicates that no sequence template with the given name can be found."""
62
63    def __init__(self, name: str) -> None:
64        """@private"""
65        super().__init__(f"No sequence template with name '{name}' found")

Indicates that no sequence template with the given name can be found.

class SequenceAnnotationApi:
 68class SequenceAnnotationApi:
 69    _inner_api_client: openapi_client.ApiClient
 70    _log_level: LogLevel
 71
 72    def __init__(self, inner_api_client: openapi_client.ApiClient, log_level: LogLevel):
 73        """@private"""
 74        self._inner_api_client = inner_api_client
 75        self._log_level = log_level
 76
 77    def get_quality_control_templates(self) -> list[QualityControlTemplate]:
 78        """Get a list of all quality control templates owned by you or shared with you.
 79
 80        Returns:
 81            list[enpi_api.l2.types.sequence_annotation.QualityControlTemplate]: A list of quality control templates.
 82
 83        Raises:
 84            enpi_api.l2.types.api_error.ApiError: If API request fails.
 85
 86        Example:
 87            ```python
 88            quality_control_templates = self.get_quality_control_templates()
 89            ```
 90        """
 91
 92        sequence_annotation_api_instance = openapi_client.SequenceAnnotationApi(self._inner_api_client)
 93
 94        try:
 95            return [QualityControlTemplate.from_raw(i) for i in sequence_annotation_api_instance.quality_control_templates()]
 96        except openapi_client.ApiException as e:
 97            raise ApiError(e)
 98
 99    def get_quality_control_template_by_name(self, name: str) -> QualityControlTemplate:
100        """Get a quality control template by its name.
101
102        It will raise an error if not exactly one quality control template with the given name is found.
103
104        Args:
105            name (str): The name of the quality control template to get.
106
107        Returns:
108            enpi_api.l2.types.sequence_annotation.QualityControlTemplate: The quality control template.
109
110        Raises:
111            enpi_api.l2.client.api.sequence_annotation_api.NoQualityControlTemplateWithName: If no quality control template with the given name can be found.
112            enpi_api.l2.client.api.sequence_annotation_api.MultipleQualityControlTemplatesWithName: If multiple quality control templates with the given name can be found.
113            enpi_api.l2.types.api_error.ApiError: If API request fails.
114
115        Example:
116            ```python
117            name = "Quality control template 1"
118            quality_control_template = self.get_quality_control_template_by_name(name)
119            ```
120        """
121
122        quality_control_templates = self.get_quality_control_templates()
123
124        matching_templates = [qct for qct in quality_control_templates if qct.name == name]
125
126        if len(matching_templates) == 0:
127            raise NoQualityControlTemplateWithName(name)
128        elif len(matching_templates) > 1:
129            raise MultipleQualityControlTemplatesWithName(name)
130
131        return matching_templates[0]
132
133    def get_sequence_templates(self) -> list[SequenceTemplate]:
134        """Get a list of all sequence templates owned by you or shared with you.
135
136        Returns:
137            list[enpi_api.l2.types.sequence_annotation.SequenceTemplate]: A list of sequence templates
138
139        Raises:
140            enpi_api.l2.types.api_error.ApiError: If API request fails.
141
142        Example:
143            ```python
144            sequence_templates = self.get_sequence_templates()
145            ```
146        """
147
148        sequence_annotation_api_instance = openapi_client.SequenceAnnotationApi(self._inner_api_client)
149
150        try:
151            return [SequenceTemplate.from_raw(i) for i in sequence_annotation_api_instance.sequence_templates()]
152        except openapi_client.ApiException as e:
153            raise ApiError(e)
154
155    def get_sequence_template_by_name(self, name: str) -> SequenceTemplate:
156        """Get a sequence template by its name.
157
158        It will raise an error if not exactly one sequence template with the given name is found.
159
160        Args:
161            name (str): The name of the sequence template to get.
162
163        Raises:
164            enpi_api.l2.client.api.sequence_annotation_api.NoSequenceTemplateWithName: If no sequence template with the given name can be found.
165            enpi_api.l2.client.api.sequence_annotation_api.MultipleSequenceTemplatesWithName: If multiple sequence templates with the given name can be found.
166            enpi_api.l2.types.api_error.ApiError: If API request fails.
167
168        Returns:
169            enpi_api.l2.types.sequence_annotation.SequenceTemplate: The sequence template.
170
171        Example:
172            ```python
173            name = "Sequence template 1"
174            sequence_template = self.get_sequence_template_by_name(name)
175            ```
176        """
177
178        sequence_templates = self.get_sequence_templates()
179
180        matching_templates = [st for st in sequence_templates if st.name == name]
181
182        if len(matching_templates) == 0:
183            raise NoSequenceTemplateWithName(name)
184        elif len(matching_templates) > 1:
185            raise MultipleSequenceTemplatesWithName(name)
186
187        return matching_templates[0]
188
189    def start(
190        self,
191        name: str,
192        file_ids: list[FileId],
193        sequence_templates: list[SequenceTemplateConfig],
194        reference_database_revision: ReferenceDatabaseRevision,
195        quality_control_template: QualityControlTemplate,
196        archive_inputs: bool = False,
197        clone_id_extraction: CloneIdentifierExtractionConfig | None = None,
198        correction_settings: CorrectionSettings | None = None,
199        mutation_assay_settings: MutationAssaySettings | None = None,
200        chain_fraction_tag_id: TagId | None = None,
201        liability_check: list[LiabilityType | str] = [],
202        restrict_deduplication_within_file: bool = False,
203        should_deduplicate_on_amino_acids: bool = False,
204        filename_tag_id: TagId | None = None,
205    ) -> Execution[CollectionMetadata]:
206        """Start Sequence Annotation on raw sequencing data.
207
208        A sequence template (available here: enpi_api.l2.client.api.sequence_annotation_api.SequenceAnnotationApi.get_sequence_template_by_name) and a quality control template
209        (enpi_api.l2.client.api.sequence_annotation_api.SequenceAnnotationApi.get_quality_control_template_by_name) are required in order to run a Sequence Annotation task.
210        **<u>Templates can be created and configured only via the [web interface of ENPICOM-Platform](https://igx.bio/)</u>**, it can not
211        be done through SDK or API. Additionally, getting familiar with Sequence Annotation in the web interface can help
212        in understanding it and setting up a desired task configuration due to it being more informative than the
213        minimal documentation provided for this function.
214
215        Args:
216            name (str): The name of the resulting collection.
217            file_ids (list[enpi_api.l2.types.file.FileId]): List of the IDs of raw sequencing data files.
218            sequence_templates (list[enpi_api.l2.types.sequence_annotation.SequenceTemplateConfig]): A list of configuration objects to specify the sequence
219              templates to be used. For more information, see the `enpi_api.l2.types.sequence_annotation.SequenceTemplateConfig` class.
220            reference_database_revision (enpi_api.l2.types.reference_database.ReferenceDatabaseRevision | None): The reference database revision to use.
221              The reference database specifies which organism it is linked to.
222            archive_inputs (bool): Whether to archive the input files after the Sequence Annotation run is finished.
223            quality_control_template (enpi_api.l2.types.sequence_annotation.QualityControlTemplate): The Quality Control Template to use.
224            clone_id_extraction (enpi_api.l2.types.sequence_annotation.CloneIdentifierExtractionConfig | None): The configuration for extracting clone IDs. This is only
225              needed if your sequence template has the option "Manually Specify Clone Identifier" enabled. In other
226              cases, this parameter can be omitted.
227
228              For more information, see the `enpi_api.l2.types.sequence_annotation.CloneIdentifierExtractionConfig` class.
229            correction_settings (enpi_api.l2.types.sequence_annotation.CorrectionSettings | None): The settings to correct regions to the germline reference,
230            or complete the sequence to full VDJ using germline reference nucleotides.
231            This is useful to reduce artificial diversity in libraries with e.g. fixed framework regions.
232            mutation_assay_settings (enpi_api.l2.types.sequence_annotation.MutationAssaySettings | None): The settings to run Sequence Annotation for a mutation assay.
233            chain_fraction_tag_id (enpi_api.l2.types.tag.TagId | None): The sequence-level tag identifier of the tag that is used to store
234              the fraction of each chain within a clone.
235            liability_check (list[enpi_api.l2.types.sequence_annotation.LiabilityType | str]): A list of liability checks to perform.
236              Summed counts are stored as clone level tags.
237
238        Raises:
239            enpi_api.l2.types.api_error.ApiError: If API request fails.
240
241        Returns:
242            enpi_api.l2.types.execution.Execution[enpi_api.l2.types.collection.CollectionMetadata]: An object that allows you to wait for the
243              execution to finish and get the resulting collection metadata.
244
245        Example:
246
247            Part of `start_sequence_annotation_run.py` example script.
248
249            ```python
250            # Templates need to be present in the ENPICOM-Platform already
251            sequence_template_name = "sequence template 1"
252            quality_control_template_name = "quality control template 1"
253
254            sequence_templates = [st for st in client.sequence_annotation_api.get_sequence_templates() if st.name == sequence_template_name]
255            quality_control_templates = [qct for qct in client.sequence_annotation_api.get_quality_control_templates() if qct.name == quality_control_template_name]
256
257            quality_control_template = QualityControlTemplate(quality_control_templates[0])
258            sequence_template_id = SequenceTemplateId(sequence_templates[0].id)
259
260            # Upload the input file
261            file_path = "data.fq"
262            file: File = client.file_api.upload_file(file_path=file_path, tags=[]).wait()
263            file_ids = [file.id]
264
265            # Get the reference database revision
266            reference_database_revision = client.reference_database_api.get_revision_by_name(name=REFERENCE_NAME, species=ORGANISM)
267
268            collection_name = "New collection from Sequence Annotation"
269
270            # We will now start Sequence Annotation, which will process raw sequencing data into annotated clone collections
271            clone_collection = client.sequence_annotation_api.start(
272                name=collection_name,
273                file_ids=file_ids,
274                # To assign a sequence template to each input file
275                sequence_templates=[
276                    SequenceTemplateConfig(
277                        # We select it using a selector, in this case by matching the file_id, but we could also match on file name or tags
278                        selector=SequenceTemplateSelector(value=f),
279                        # And then assign it using a sequence template id
280                        id=sequence_template_id,
281                    )
282                    for f in file_ids
283                ],
284                reference_database_revision=reference_database_revision,
285                # Archives the raw sequencing data after they have been processed
286                archive_inputs=True,
287                quality_control_template=quality_control_template,
288            ).wait()
289            ```
290        """
291
292        if filename_tag_id is not None:
293            if not restrict_deduplication_within_file:
294                raise ValueError("filename_tag_id can only be set if restrict_deduplication_within_file is set to True")
295
296        sequence_annotation_api_instance = openapi_client.SequenceAnnotationApi(self._inner_api_client)
297
298        try:
299            inner_sequence_templates: list[openapi_client.SequenceAnnotationWorkSequenceTemplatesInner] = []
300            for st in sequence_templates:
301                match st.selector.type:
302                    case "file_id":
303                        inner_sequence_templates.append(
304                            openapi_client.SequenceAnnotationWorkSequenceTemplatesInner(
305                                template_id=st.id,
306                                template_version=st.version,
307                                selector=openapi_client.SequenceTemplateSelector(
308                                    openapi_client.MatchAFileByItsID(type=st.selector.type, value=st.selector.value)
309                                ),
310                            )
311                        )
312                    case _:
313                        assert False, f"Selector type {st.selector.type} should be matched"
314
315            sequence_annotation_work = openapi_client.SequenceAnnotationWork(
316                name=name,
317                file_ids=cast(list[StrictStr], file_ids),
318                sequence_templates=inner_sequence_templates,
319                reference_database=openapi_client.ReferenceDatabaseIdVersion(
320                    id=str(reference_database_revision.reference_database_id),
321                    version=int(reference_database_revision.reference_database_version),
322                ),
323                quality_control_template=openapi_client.QualityControlTemplateIdOptionalVersion(
324                    id=str(quality_control_template.id), version=int(quality_control_template.version)
325                ),
326                archive_inputs=archive_inputs,
327                clone_id_to_tag_spec=clone_id_extraction.to_api_payload() if clone_id_extraction else None,
328                correction_settings=correction_settings.to_api_payload() if correction_settings else None,
329                mutation_assay_settings=mutation_assay_settings.to_api_payload() if mutation_assay_settings else None,
330                chain_fraction_tag_id=chain_fraction_tag_id,
331                liability_check=liability_check,
332                restrict_deduplication_within_file=restrict_deduplication_within_file,
333                should_deduplicate_on_amino_acids=should_deduplicate_on_amino_acids,
334                filename_tag_id=filename_tag_id,
335            )
336
337            with ApiErrorContext():
338                sequence_annotation_job = sequence_annotation_api_instance.start_sequence_annotation(sequence_annotation_work=sequence_annotation_work)
339                assert sequence_annotation_job.workflow_execution_id is not None
340
341                workflow_execution_id = WorkflowExecutionId(int(sequence_annotation_job.workflow_execution_id))
342
343                def on_complete(task_id: WorkflowExecutionTaskId, task_state: TaskState) -> CollectionMetadata:
344                    assert task_state == TaskState.SUCCEEDED, f"Task {task_id} did not reach {TaskState.SUCCEEDED} state, got {task_state} state instead"
345
346                    get_collection_id_response = sequence_annotation_api_instance.get_sequence_annotation_collection_id_by_workflow_execution_task_id(task_id)
347                    collection_id = get_collection_id_response.collection_id
348                    assert collection_id is not None
349
350                    logger.success(f"Collection with ID `{collection_id}` was successfully obtained by running Sequence Annotation")
351
352                    collection_api = CollectionApi(self._inner_api_client, self._log_level)
353                    return collection_api.get_collection_metadata_by_id(CollectionId(collection_id))
354
355                waitable = WorkflowExecutionTaskWaitable[CollectionMetadata](
356                    workflow_execution_id=workflow_execution_id,
357                    task_template_name=WorkflowTaskTemplateName.ENPI_APP_SEQUENCE_ANNOTATION,
358                    on_complete=on_complete,
359                )
360
361                return Execution(wait=waitable.wait_and_return_result, check_execution_state=waitable.check_execution_state)
362
363        except openapi_client.ApiException as e:
364            raise ApiError(e)
def get_quality_control_templates( self) -> list[enpi_api.l2.types.sequence_annotation.QualityControlTemplate]:
77    def get_quality_control_templates(self) -> list[QualityControlTemplate]:
78        """Get a list of all quality control templates owned by you or shared with you.
79
80        Returns:
81            list[enpi_api.l2.types.sequence_annotation.QualityControlTemplate]: A list of quality control templates.
82
83        Raises:
84            enpi_api.l2.types.api_error.ApiError: If API request fails.
85
86        Example:
87            ```python
88            quality_control_templates = self.get_quality_control_templates()
89            ```
90        """
91
92        sequence_annotation_api_instance = openapi_client.SequenceAnnotationApi(self._inner_api_client)
93
94        try:
95            return [QualityControlTemplate.from_raw(i) for i in sequence_annotation_api_instance.quality_control_templates()]
96        except openapi_client.ApiException as e:
97            raise ApiError(e)

Get a list of all quality control templates owned by you or shared with you.

Returns:

list[enpi_api.l2.types.sequence_annotation.QualityControlTemplate]: A list of quality control templates.

Raises:
Example:
quality_control_templates = self.get_quality_control_templates()
def get_quality_control_template_by_name( self, name: str) -> enpi_api.l2.types.sequence_annotation.QualityControlTemplate:
 99    def get_quality_control_template_by_name(self, name: str) -> QualityControlTemplate:
100        """Get a quality control template by its name.
101
102        It will raise an error if not exactly one quality control template with the given name is found.
103
104        Args:
105            name (str): The name of the quality control template to get.
106
107        Returns:
108            enpi_api.l2.types.sequence_annotation.QualityControlTemplate: The quality control template.
109
110        Raises:
111            enpi_api.l2.client.api.sequence_annotation_api.NoQualityControlTemplateWithName: If no quality control template with the given name can be found.
112            enpi_api.l2.client.api.sequence_annotation_api.MultipleQualityControlTemplatesWithName: If multiple quality control templates with the given name can be found.
113            enpi_api.l2.types.api_error.ApiError: If API request fails.
114
115        Example:
116            ```python
117            name = "Quality control template 1"
118            quality_control_template = self.get_quality_control_template_by_name(name)
119            ```
120        """
121
122        quality_control_templates = self.get_quality_control_templates()
123
124        matching_templates = [qct for qct in quality_control_templates if qct.name == name]
125
126        if len(matching_templates) == 0:
127            raise NoQualityControlTemplateWithName(name)
128        elif len(matching_templates) > 1:
129            raise MultipleQualityControlTemplatesWithName(name)
130
131        return matching_templates[0]

Get a quality control template by its name.

It will raise an error if not exactly one quality control template with the given name is found.

Arguments:
  • name (str): The name of the quality control template to get.
Returns:

enpi_api.l2.types.sequence_annotation.QualityControlTemplate: The quality control template.

Raises:
Example:
name = "Quality control template 1"
quality_control_template = self.get_quality_control_template_by_name(name)
def get_sequence_templates(self) -> list[enpi_api.l2.types.sequence_annotation.SequenceTemplate]:
133    def get_sequence_templates(self) -> list[SequenceTemplate]:
134        """Get a list of all sequence templates owned by you or shared with you.
135
136        Returns:
137            list[enpi_api.l2.types.sequence_annotation.SequenceTemplate]: A list of sequence templates
138
139        Raises:
140            enpi_api.l2.types.api_error.ApiError: If API request fails.
141
142        Example:
143            ```python
144            sequence_templates = self.get_sequence_templates()
145            ```
146        """
147
148        sequence_annotation_api_instance = openapi_client.SequenceAnnotationApi(self._inner_api_client)
149
150        try:
151            return [SequenceTemplate.from_raw(i) for i in sequence_annotation_api_instance.sequence_templates()]
152        except openapi_client.ApiException as e:
153            raise ApiError(e)

Get a list of all sequence templates owned by you or shared with you.

Returns:

list[enpi_api.l2.types.sequence_annotation.SequenceTemplate]: A list of sequence templates

Raises:
Example:
sequence_templates = self.get_sequence_templates()
def get_sequence_template_by_name( self, name: str) -> enpi_api.l2.types.sequence_annotation.SequenceTemplate:
155    def get_sequence_template_by_name(self, name: str) -> SequenceTemplate:
156        """Get a sequence template by its name.
157
158        It will raise an error if not exactly one sequence template with the given name is found.
159
160        Args:
161            name (str): The name of the sequence template to get.
162
163        Raises:
164            enpi_api.l2.client.api.sequence_annotation_api.NoSequenceTemplateWithName: If no sequence template with the given name can be found.
165            enpi_api.l2.client.api.sequence_annotation_api.MultipleSequenceTemplatesWithName: If multiple sequence templates with the given name can be found.
166            enpi_api.l2.types.api_error.ApiError: If API request fails.
167
168        Returns:
169            enpi_api.l2.types.sequence_annotation.SequenceTemplate: The sequence template.
170
171        Example:
172            ```python
173            name = "Sequence template 1"
174            sequence_template = self.get_sequence_template_by_name(name)
175            ```
176        """
177
178        sequence_templates = self.get_sequence_templates()
179
180        matching_templates = [st for st in sequence_templates if st.name == name]
181
182        if len(matching_templates) == 0:
183            raise NoSequenceTemplateWithName(name)
184        elif len(matching_templates) > 1:
185            raise MultipleSequenceTemplatesWithName(name)
186
187        return matching_templates[0]

Get a sequence template by its name.

It will raise an error if not exactly one sequence template with the given name is found.

Arguments:
  • name (str): The name of the sequence template to get.
Raises:
Returns:

enpi_api.l2.types.sequence_annotation.SequenceTemplate: The sequence template.

Example:
name = "Sequence template 1"
sequence_template = self.get_sequence_template_by_name(name)
def start( self, name: str, file_ids: list[enpi_api.l2.types.file.FileId], sequence_templates: list[enpi_api.l2.types.sequence_annotation.SequenceTemplateConfig], reference_database_revision: enpi_api.l2.types.reference_database.ReferenceDatabaseRevision, quality_control_template: enpi_api.l2.types.sequence_annotation.QualityControlTemplate, archive_inputs: bool = False, clone_id_extraction: enpi_api.l2.types.sequence_annotation.CloneIdentifierExtractionConfig | None = None, correction_settings: enpi_api.l2.types.sequence_annotation.CorrectionSettings | None = None, mutation_assay_settings: enpi_api.l2.types.sequence_annotation.MutationAssaySettings | None = None, chain_fraction_tag_id: Optional[enpi_api.l2.types.tag.TagId] = None, liability_check: list[enpi_api.l2.types.sequence_annotation.LiabilityType | str] = [], restrict_deduplication_within_file: bool = False, should_deduplicate_on_amino_acids: bool = False, filename_tag_id: Optional[enpi_api.l2.types.tag.TagId] = None) -> enpi_api.l2.types.execution.Execution[CollectionMetadata]:
189    def start(
190        self,
191        name: str,
192        file_ids: list[FileId],
193        sequence_templates: list[SequenceTemplateConfig],
194        reference_database_revision: ReferenceDatabaseRevision,
195        quality_control_template: QualityControlTemplate,
196        archive_inputs: bool = False,
197        clone_id_extraction: CloneIdentifierExtractionConfig | None = None,
198        correction_settings: CorrectionSettings | None = None,
199        mutation_assay_settings: MutationAssaySettings | None = None,
200        chain_fraction_tag_id: TagId | None = None,
201        liability_check: list[LiabilityType | str] = [],
202        restrict_deduplication_within_file: bool = False,
203        should_deduplicate_on_amino_acids: bool = False,
204        filename_tag_id: TagId | None = None,
205    ) -> Execution[CollectionMetadata]:
206        """Start Sequence Annotation on raw sequencing data.
207
208        A sequence template (available here: enpi_api.l2.client.api.sequence_annotation_api.SequenceAnnotationApi.get_sequence_template_by_name) and a quality control template
209        (enpi_api.l2.client.api.sequence_annotation_api.SequenceAnnotationApi.get_quality_control_template_by_name) are required in order to run a Sequence Annotation task.
210        **<u>Templates can be created and configured only via the [web interface of ENPICOM-Platform](https://igx.bio/)</u>**, it can not
211        be done through SDK or API. Additionally, getting familiar with Sequence Annotation in the web interface can help
212        in understanding it and setting up a desired task configuration due to it being more informative than the
213        minimal documentation provided for this function.
214
215        Args:
216            name (str): The name of the resulting collection.
217            file_ids (list[enpi_api.l2.types.file.FileId]): List of the IDs of raw sequencing data files.
218            sequence_templates (list[enpi_api.l2.types.sequence_annotation.SequenceTemplateConfig]): A list of configuration objects to specify the sequence
219              templates to be used. For more information, see the `enpi_api.l2.types.sequence_annotation.SequenceTemplateConfig` class.
220            reference_database_revision (enpi_api.l2.types.reference_database.ReferenceDatabaseRevision | None): The reference database revision to use.
221              The reference database specifies which organism it is linked to.
222            archive_inputs (bool): Whether to archive the input files after the Sequence Annotation run is finished.
223            quality_control_template (enpi_api.l2.types.sequence_annotation.QualityControlTemplate): The Quality Control Template to use.
224            clone_id_extraction (enpi_api.l2.types.sequence_annotation.CloneIdentifierExtractionConfig | None): The configuration for extracting clone IDs. This is only
225              needed if your sequence template has the option "Manually Specify Clone Identifier" enabled. In other
226              cases, this parameter can be omitted.
227
228              For more information, see the `enpi_api.l2.types.sequence_annotation.CloneIdentifierExtractionConfig` class.
229            correction_settings (enpi_api.l2.types.sequence_annotation.CorrectionSettings | None): The settings to correct regions to the germline reference,
230            or complete the sequence to full VDJ using germline reference nucleotides.
231            This is useful to reduce artificial diversity in libraries with e.g. fixed framework regions.
232            mutation_assay_settings (enpi_api.l2.types.sequence_annotation.MutationAssaySettings | None): The settings to run Sequence Annotation for a mutation assay.
233            chain_fraction_tag_id (enpi_api.l2.types.tag.TagId | None): The sequence-level tag identifier of the tag that is used to store
234              the fraction of each chain within a clone.
235            liability_check (list[enpi_api.l2.types.sequence_annotation.LiabilityType | str]): A list of liability checks to perform.
236              Summed counts are stored as clone level tags.
237
238        Raises:
239            enpi_api.l2.types.api_error.ApiError: If API request fails.
240
241        Returns:
242            enpi_api.l2.types.execution.Execution[enpi_api.l2.types.collection.CollectionMetadata]: An object that allows you to wait for the
243              execution to finish and get the resulting collection metadata.
244
245        Example:
246
247            Part of `start_sequence_annotation_run.py` example script.
248
249            ```python
250            # Templates need to be present in the ENPICOM-Platform already
251            sequence_template_name = "sequence template 1"
252            quality_control_template_name = "quality control template 1"
253
254            sequence_templates = [st for st in client.sequence_annotation_api.get_sequence_templates() if st.name == sequence_template_name]
255            quality_control_templates = [qct for qct in client.sequence_annotation_api.get_quality_control_templates() if qct.name == quality_control_template_name]
256
257            quality_control_template = QualityControlTemplate(quality_control_templates[0])
258            sequence_template_id = SequenceTemplateId(sequence_templates[0].id)
259
260            # Upload the input file
261            file_path = "data.fq"
262            file: File = client.file_api.upload_file(file_path=file_path, tags=[]).wait()
263            file_ids = [file.id]
264
265            # Get the reference database revision
266            reference_database_revision = client.reference_database_api.get_revision_by_name(name=REFERENCE_NAME, species=ORGANISM)
267
268            collection_name = "New collection from Sequence Annotation"
269
270            # We will now start Sequence Annotation, which will process raw sequencing data into annotated clone collections
271            clone_collection = client.sequence_annotation_api.start(
272                name=collection_name,
273                file_ids=file_ids,
274                # To assign a sequence template to each input file
275                sequence_templates=[
276                    SequenceTemplateConfig(
277                        # We select it using a selector, in this case by matching the file_id, but we could also match on file name or tags
278                        selector=SequenceTemplateSelector(value=f),
279                        # And then assign it using a sequence template id
280                        id=sequence_template_id,
281                    )
282                    for f in file_ids
283                ],
284                reference_database_revision=reference_database_revision,
285                # Archives the raw sequencing data after they have been processed
286                archive_inputs=True,
287                quality_control_template=quality_control_template,
288            ).wait()
289            ```
290        """
291
292        if filename_tag_id is not None:
293            if not restrict_deduplication_within_file:
294                raise ValueError("filename_tag_id can only be set if restrict_deduplication_within_file is set to True")
295
296        sequence_annotation_api_instance = openapi_client.SequenceAnnotationApi(self._inner_api_client)
297
298        try:
299            inner_sequence_templates: list[openapi_client.SequenceAnnotationWorkSequenceTemplatesInner] = []
300            for st in sequence_templates:
301                match st.selector.type:
302                    case "file_id":
303                        inner_sequence_templates.append(
304                            openapi_client.SequenceAnnotationWorkSequenceTemplatesInner(
305                                template_id=st.id,
306                                template_version=st.version,
307                                selector=openapi_client.SequenceTemplateSelector(
308                                    openapi_client.MatchAFileByItsID(type=st.selector.type, value=st.selector.value)
309                                ),
310                            )
311                        )
312                    case _:
313                        assert False, f"Selector type {st.selector.type} should be matched"
314
315            sequence_annotation_work = openapi_client.SequenceAnnotationWork(
316                name=name,
317                file_ids=cast(list[StrictStr], file_ids),
318                sequence_templates=inner_sequence_templates,
319                reference_database=openapi_client.ReferenceDatabaseIdVersion(
320                    id=str(reference_database_revision.reference_database_id),
321                    version=int(reference_database_revision.reference_database_version),
322                ),
323                quality_control_template=openapi_client.QualityControlTemplateIdOptionalVersion(
324                    id=str(quality_control_template.id), version=int(quality_control_template.version)
325                ),
326                archive_inputs=archive_inputs,
327                clone_id_to_tag_spec=clone_id_extraction.to_api_payload() if clone_id_extraction else None,
328                correction_settings=correction_settings.to_api_payload() if correction_settings else None,
329                mutation_assay_settings=mutation_assay_settings.to_api_payload() if mutation_assay_settings else None,
330                chain_fraction_tag_id=chain_fraction_tag_id,
331                liability_check=liability_check,
332                restrict_deduplication_within_file=restrict_deduplication_within_file,
333                should_deduplicate_on_amino_acids=should_deduplicate_on_amino_acids,
334                filename_tag_id=filename_tag_id,
335            )
336
337            with ApiErrorContext():
338                sequence_annotation_job = sequence_annotation_api_instance.start_sequence_annotation(sequence_annotation_work=sequence_annotation_work)
339                assert sequence_annotation_job.workflow_execution_id is not None
340
341                workflow_execution_id = WorkflowExecutionId(int(sequence_annotation_job.workflow_execution_id))
342
343                def on_complete(task_id: WorkflowExecutionTaskId, task_state: TaskState) -> CollectionMetadata:
344                    assert task_state == TaskState.SUCCEEDED, f"Task {task_id} did not reach {TaskState.SUCCEEDED} state, got {task_state} state instead"
345
346                    get_collection_id_response = sequence_annotation_api_instance.get_sequence_annotation_collection_id_by_workflow_execution_task_id(task_id)
347                    collection_id = get_collection_id_response.collection_id
348                    assert collection_id is not None
349
350                    logger.success(f"Collection with ID `{collection_id}` was successfully obtained by running Sequence Annotation")
351
352                    collection_api = CollectionApi(self._inner_api_client, self._log_level)
353                    return collection_api.get_collection_metadata_by_id(CollectionId(collection_id))
354
355                waitable = WorkflowExecutionTaskWaitable[CollectionMetadata](
356                    workflow_execution_id=workflow_execution_id,
357                    task_template_name=WorkflowTaskTemplateName.ENPI_APP_SEQUENCE_ANNOTATION,
358                    on_complete=on_complete,
359                )
360
361                return Execution(wait=waitable.wait_and_return_result, check_execution_state=waitable.check_execution_state)
362
363        except openapi_client.ApiException as e:
364            raise ApiError(e)

Start Sequence Annotation on raw sequencing data.

A sequence template (available here: enpi_api.l2.client.api.sequence_annotation_api.SequenceAnnotationApi.get_sequence_template_by_name) and a quality control template (enpi_api.l2.client.api.sequence_annotation_api.SequenceAnnotationApi.get_quality_control_template_by_name) are required in order to run a Sequence Annotation task. Templates can be created and configured only via the web interface of ENPICOM-Platform, it can not be done through SDK or API. Additionally, getting familiar with Sequence Annotation in the web interface can help in understanding it and setting up a desired task configuration due to it being more informative than the minimal documentation provided for this function.

Arguments:
Raises:
Returns:

enpi_api.l2.types.execution.Execution[enpi_api.l2.types.collection.CollectionMetadata]: An object that allows you to wait for the execution to finish and get the resulting collection metadata.

Example:

Part of start_sequence_annotation_run.py example script.

# Templates need to be present in the ENPICOM-Platform already
sequence_template_name = "sequence template 1"
quality_control_template_name = "quality control template 1"

sequence_templates = [st for st in client.sequence_annotation_api.get_sequence_templates() if st.name == sequence_template_name]
quality_control_templates = [qct for qct in client.sequence_annotation_api.get_quality_control_templates() if qct.name == quality_control_template_name]

quality_control_template = QualityControlTemplate(quality_control_templates[0])
sequence_template_id = SequenceTemplateId(sequence_templates[0].id)

# Upload the input file
file_path = "data.fq"
file: File = client.file_api.upload_file(file_path=file_path, tags=[]).wait()
file_ids = [file.id]

# Get the reference database revision
reference_database_revision = client.reference_database_api.get_revision_by_name(name=REFERENCE_NAME, species=ORGANISM)

collection_name = "New collection from Sequence Annotation"

# We will now start Sequence Annotation, which will process raw sequencing data into annotated clone collections
clone_collection = client.sequence_annotation_api.start(
    name=collection_name,
    file_ids=file_ids,
    # To assign a sequence template to each input file
    sequence_templates=[
        SequenceTemplateConfig(
            # We select it using a selector, in this case by matching the file_id, but we could also match on file name or tags
            selector=SequenceTemplateSelector(value=f),
            # And then assign it using a sequence template id
            id=sequence_template_id,
        )
        for f in file_ids
    ],
    reference_database_revision=reference_database_revision,
    # Archives the raw sequencing data after they have been processed
    archive_inputs=True,
    quality_control_template=quality_control_template,
).wait()