def upload_samples(self, samples, anno_key, backend):
        """Uploads the given samples to CVAT according to the given backend's
        annotation and server configuration.

        Args:
            samples: a :class:`fiftyone.core.collections.SampleCollection`
            anno_key: the annotation key
            backend: a :class:`CVATBackend` to use to perform the upload

        Returns:
            a :class:`CVATAnnotationResults`
        """
        config = backend.config
        label_schema = config.label_schema
        occluded_attr = config.occluded_attr
        group_id_attr = config.group_id_attr
        task_size = config.task_size
        config.job_reviewers = self._parse_reviewers(config.job_reviewers)
        project_name, project_id = self._parse_project_details(
            config.project_name, config.project_id
        )
        has_ignored_attributes = False
        save_config = False

        if (
            samples.media_type == fom.THREE_D
            and config.media_field == "filepath"
        ):
            raise ValueError(
                "The `media_field` argument is required when annotating 3D "
                "datasets. See the documentation for more details: "
                "https://docs.voxel51.com/integrations/cvat.html#annotating-3d-data"
            )

        # When using an existing project, we cannot support multiple label
        # fields of the same type, since it would not be clear which field
        # labels should be downloaded into
        if project_id is not None:
            self._ensure_one_field_per_type(label_schema)
            has_ignored_attributes = self._has_ignored_attributes(label_schema)

        id_map = {}
        project_ids = []
        task_ids = []
        job_ids = {}
        frame_id_map = {}
        labels_task_map = {}

        (
            cvat_schema,
            assign_scalar_attrs,
            occluded_attrs,
            group_id_attrs,
            _,
        ) = self._get_cvat_schema(
            label_schema,
            project_id=project_id,
            occluded_attr=occluded_attr,
            group_id_attr=group_id_attr,
        )

        # When adding to an existing project, its label schema is inherited, so
        # we need to store the updated one
        if (
            project_id is not None
            or occluded_attr is not None
            or group_id_attr is not None
        ):
            if project_id is not None and has_ignored_attributes:
                raise ValueError(
                    "A project was specified so the 'label_schema', "
                    "'classes', and 'attributes' arguments are ignored, but "
                    "they contained either occluded or group id "
                    "attributes. To use occluded or group id attributes "
                    "with existing projects, provide the 'occluded_attr' "
                    "and 'group_id_attr' arguments."
                )

            config.label_schema = label_schema
            save_config = True

        samples.compute_metadata()

        num_samples = len(samples)
        batch_size = self._get_batch_size(samples, task_size)
        num_batches = math.ceil(num_samples / batch_size)
        is_video = samples.media_type == fom.VIDEO
        is_clips = samples._is_clips

        if is_video:
            # The current implementation requires frame IDs for all frames that
            # might get labels
            samples.ensure_frames()

        logger.info("Uploading samples to CVAT...")

        pb_kwargs = {"total": num_samples, "iters_str": "samples"}
        if num_samples <= batch_size:
            pb_kwargs["quiet"] = True

        with fou.ProgressBar(**pb_kwargs) as pb:
            for idx, offset in enumerate(range(0, num_samples, batch_size)):
                samples_batch = samples[offset : (offset + batch_size)]
                anno_tags = []
                anno_shapes = []
                anno_tracks = []

                if is_video:
                    _frame_start = _render_frame_arg(
                        config.frame_start, idx, samples_batch
                    )
                    _frame_stop = _render_frame_arg(
                        config.frame_stop, idx, samples_batch
                    )
                    _frame_step = _render_frame_arg(
                        config.frame_step, idx, samples_batch
                    )
                else:
                    _frame_start = None
                    _frame_stop = None
                    _frame_step = None

                for label_field, label_info in label_schema.items():
                    _tags = []
                    _shapes = []
                    _tracks = []

                    if label_field not in id_map:
                        id_map[label_field] = {}

                    if label_field not in labels_task_map:
                        labels_task_map[label_field] = []

                    if label_info.get("existing_field", False):
                        label_type = label_info["type"]
                        only_keyframes = label_info.get(
                            "only_keyframes", False
                        )

                        self._update_shapes_tags_tracks(
                            _tags,
                            _shapes,
                            _tracks,
                            id_map,
                            label_type,
                            samples_batch,
                            label_field,
                            label_info,
                            cvat_schema,
                            _frame_start,
                            _frame_stop,
                            _frame_step,
                            assign_scalar_attrs,
                            only_keyframes,
                            occluded_attrs,
                            group_id_attrs,
                        )

                        if _tracks and _frame_step is not None:
                            #
                            # @todo fully support working with existing
                            # annotation tracks. This will require additional
                            # logic to handle mutations of objects outside of
                            # the uploaded frames.
                            #
                            # Example: A detection track is deleted with
                            # frame_step 5, then the detections for that track
                            # between frames 1-5 need to be deleted when the
                            # annotations are loaded again.
                            #
                            raise ValueError(
                                "Cannot upload existing annotation tracks for "
                                "field '%s' when a 'frame_step' is provided"
                                % label_field
                            )

                    anno_tags.extend(_tags)
                    anno_shapes.extend(_shapes)
                    anno_tracks.extend(_tracks)

                # We must do this here because `cvat_schema` may be altered the
                # first time shapes are created
                if project_id is None and project_name is not None:
                    project_id = self.create_project(project_name, cvat_schema)
                    project_ids.append(project_id)

                if config.task_name is None:
                    _dataset_name = samples_batch._dataset.name.replace(
                        " ", "_"
                    )
                    task_name = f"FiftyOne_{_dataset_name}"
                else:
                    task_name = config.task_name

                # Append task number when multiple tasks are created
                if num_batches > 1:
                    task_name += f"_{idx + 1}"

                (
                    task_id,
                    class_id_map,
                    attr_id_map,
                ) = self._create_task_upload_data(
                    config,
                    idx,
                    task_name,
                    cvat_schema,
                    project_id,
                    samples_batch,
                    task_ids,
                    job_ids,
                    frame_id_map,
                    _frame_start,
                    _frame_stop,
                    _frame_step,
                )

                for label_field in label_schema.keys():
                    labels_task_map[label_field].append(task_id)

                server_id_map = self._upload_annotations(
                    anno_shapes,
                    anno_tags,
                    anno_tracks,
                    class_id_map,
                    attr_id_map,
                    task_id,
                )

                pb.update(batch_size)

        results = CVATAnnotationResults(
            samples,
            config,
            anno_key,
            id_map,
            server_id_map,
            project_ids,
            task_ids,
            job_ids,
            frame_id_map,
            labels_task_map,
            backend=backend,
        )

        if is_clips:
            # We must store clip start frame numbers because this information
            # is required when downloading annotations to map the CVAT frame
            # IDs back to the correct frame numbers
            frame_starts = [s[0] for s in samples.values("support")]
            results.id_map["_clips_frame_start"] = dict(
                zip(task_ids, frame_starts)
            )

        if save_config:
            results.save_config()

        return results
Uploads the given samples to CVAT according to the given backend's
        annotation and server configuration.

        Args:
            samples: a :class:`fiftyone.core.collections.SampleCollection`
            anno_key: the annotation key
            backend: a :class:`CVATBackend` to use to perform the upload

        Returns:
            a :class:`CVATAnnotationResults`
        
fiftyone/utils/cvat.py