def test_length(self):
     ll = Doubly_LinkedList()
     assert ll.length() == 0
     # append and prepend operations increase length
     ll.append('B')
     assert ll.length() == 1
     ll.prepend('A')
     assert ll.length() == 2
     ll.append('C')
     assert ll.length() == 3
     # delete operations decrease length
     ll.delete('B')
     assert ll.length() == 2
     ll.delete('C')
     assert ll.length() == 1
     ll.delete('A')
     assert ll.length() == 0
class Doubly_LinkedQueue(object):
    def __init__(self, iterable=None):
        """Initialize this queue and enqueue the given items, if any."""
        # Initialize a new linked list to store the items
        self.head = None
        self.tail = None
        # self.size = 0
        self.list = Doubly_LinkedList()
        if iterable is not None:
            for item in iterable:
                self.enqueue(item)

    def __repr__(self):
        """Return a string representation of this queue."""
        return 'Queue({} items, front={})'.format(self.length(), self.front())

    def is_empty(self):
        """Return True if this queue is empty, or False otherwise."""
        # TODO: Check if empty
        return self.list.head is None

    def length(self):
        """Return the number of items in this queue."""
        # TODO: Count number of items
        return self.list.length()
        print(self.length)

    def enqueue_back(self, item):
        """Insert the given item at the back of this queue.
        Running time: O(???) – Why? [TODO]"""
        # TODO: Insert given item
        #Append to the end of the list
        self.list.append(item)

    def enqueue_front(self, item):
        # TODO: Insert given item
        # Move the item to the start of the list
        self.list.prepend(item)

    def front(self):
        """Return the item at the front of this queue without removing it,
        or None if this queue is empty."""
        # TODO: Return front item, if any
        if self.is_empty():
            #raise ValueError
            return None
        #return self.list.head.data
        self.list.pop(-1)

    def back(self):
        if self.is_empty():
            return None
        return self.list.tail.data

    def dequeue_front(self):
        """Remove and return the item at the front of this queue,
        or raise ValueError if this queue is empty.
        Running time: O(???) – Why? [TODO]"""
        # TODO: Remove and return front item, if any
        #Check if head is empty
        if self.is_empty():
            raise ValueError

        #Set the data to the tail
        data = self.list.tail.data
        self.list.delete(self.list.tail.data)
        return data

    def dequeue_back(self):

        #Check if head is empty
        if self.is_empty():
            raise ValueError

        #Set the data to the head
        data = self.list.head.data
        self.list.delete(self.list.head.data)
        return data