a stack is an abstract data type that serves as a collection of elements with two principal operations push and pop push adds an element to the top of the stack and pop removes an element from the top of a stack the order in which elements come off of a stack are last in first out lifo https en wikipedia orgwikistackabstractdatatype push an element to the top of the stack s stack2 stack size 2 s push10 s push20 prints 10 20 s stack1 stack size 1 s push10 s push20 traceback most recent call last datastructures stacks stack stackoverflowerror pop an element off of the top of the stack s stack s push5 s push10 s pop 10 stack pop traceback most recent call last datastructures stacks stack stackunderflowerror peek at the topmost element of the stack s stack s push5 s push10 s peek 10 stack peek traceback most recent call last datastructures stacks stack stackunderflowerror check if a stack is empty s stack s isempty true s stack s push10 s isempty false s stack s isfull false s stack1 s push10 s isfull true return the size of the stack s stack3 s size 0 s stack3 s push10 s size 1 s stack3 s push10 s push20 s size 2 check if item is in stack s stack3 s push10 10 in s true s stack3 s push10 20 in s false teststack a stack is an abstract data type that serves as a collection of elements with two principal operations push and pop push adds an element to the top of the stack and pop removes an element from the top of a stack the order in which elements come off of a stack are last in first out lifo https en wikipedia org wiki stack_ abstract_data_type push an element to the top of the stack s stack 2 stack size 2 s push 10 s push 20 print s 10 20 s stack 1 stack size 1 s push 10 s push 20 traceback most recent call last data_structures stacks stack stackoverflowerror pop an element off of the top of the stack s stack s push 5 s push 10 s pop 10 stack pop traceback most recent call last data_structures stacks stack stackunderflowerror peek at the top most element of the stack s stack s push 5 s push 10 s peek 10 stack peek traceback most recent call last data_structures stacks stack stackunderflowerror check if a stack is empty s stack s is_empty true s stack s push 10 s is_empty false s stack s is_full false s stack 1 s push 10 s is_full true return the size of the stack s stack 3 s size 0 s stack 3 s push 10 s size 1 s stack 3 s push 10 s push 20 s size 2 check if item is in stack s stack 3 s push 10 10 in s true s stack 3 s push 10 20 in s false test_stack this should not happen this should happen this should not happen this should happen this should not happen this should happen
from __future__ import annotations

from typing import Generic, TypeVar

T = TypeVar("T")


class StackOverflowError(BaseException):
    pass


class StackUnderflowError(BaseException):
    pass


class Stack(Generic[T]):
    

    def __init__(self, limit: int = 10):
        self.stack: list[T] = []
        self.limit = limit

    def __bool__(self) -> bool:
        return bool(self.stack)

    def __str__(self) -> str:
        return str(self.stack)

    def push(self, data: T) -> None:
        
        if len(self.stack) >= self.limit:
            raise StackOverflowError
        self.stack.append(data)

    def pop(self) -> T:
        
        if not self.stack:
            raise StackUnderflowError
        return self.stack.pop()

    def peek(self) -> T:
        
        if not self.stack:
            raise StackUnderflowError
        return self.stack[-1]

    def is_empty(self) -> bool:
        
        return not bool(self.stack)

    def is_full(self) -> bool:
        
        return self.size() == self.limit

    def size(self) -> int:
        
        return len(self.stack)

    def __contains__(self, item: T) -> bool:
        
        return item in self.stack


def test_stack() -> None:
    
    stack: Stack[int] = Stack(10)
    assert bool(stack) is False
    assert stack.is_empty() is True
    assert stack.is_full() is False
    assert str(stack) == "[]"

    try:
        _ = stack.pop()
        raise AssertionError  
    except StackUnderflowError:
        assert True  

    try:
        _ = stack.peek()
        raise AssertionError  
    except StackUnderflowError:
        assert True  

    for i in range(10):
        assert stack.size() == i
        stack.push(i)

    assert bool(stack)
    assert not stack.is_empty()
    assert stack.is_full()
    assert str(stack) == str(list(range(10)))
    assert stack.pop() == 9
    assert stack.peek() == 8

    stack.push(100)
    assert str(stack) == str([0, 1, 2, 3, 4, 5, 6, 7, 8, 100])

    try:
        stack.push(200)
        raise AssertionError  
    except StackOverflowError:
        assert True  

    assert not stack.is_empty()
    assert stack.size() == 10

    assert 5 in stack
    assert 55 not in stack


if __name__ == "__main__":
    test_stack()

    import doctest

    doctest.testmod()