def get(self):
        """Creates a generator to extract data from the queue.

        Skip the data if it is `None`.

        This method is called from the main thread.

        Yields:
            The next element in the queue, i.e. a tuple
            `(inputs, targets)` or
            `(inputs, targets, sample_weights)`.
        """
        while self.is_running():
            try:
                inputs = self.ready_queue.get(block=False)
                yield inputs
                continue  # Retry the ready_queue
            except queue.Empty:
                pass

            try:
                value = self.future_queue.get(block=True, timeout=5)
                self.future_queue.task_done()
                if isinstance(value, Exception):
                    raise value  # Propagate exception from other thread
                inputs = value.get()
                if inputs is not None:
                    yield inputs
            except queue.Empty:
                pass
            except Exception as e:
                self.stop(drain_queue_and_join=True)
                raise e

        # Note that it is ok to poll the iterator after the initial `start`,
        # which may happen before the first `on_epoch_begin`. But it's not ok to
        # poll after `on_epoch_end`.
        raise ValueError(
            "Iterator called after `on_epoch_end` or before `on_epoch_begin`."
        )
Creates a generator to extract data from the queue.

        Skip the data if it is `None`.

        This method is called from the main thread.

        Yields:
            The next element in the queue, i.e. a tuple
            `(inputs, targets)` or
            `(inputs, targets, sample_weights)`.
        
keras/src/trainers/data_adapters/py_dataset_adapter.py