def lstrip(iterable, strip_value):
    """ Return iterable with strip_value removed from the beginnning"""
    stripped = []
    iterator = iter(iterable)
    for item in iterator:
        if not item == strip_value:
            stripped.append(item)
            break
            
    for item in iterator:
        stripped.append(item)
        
    return stripped

import unittest

class LStripTests(unittest.TestCase):

    """Tests for lstrip."""

    def assertIterableEqual(self, iterable1, iterable2):
        self.assertEqual(list(iterable1), list(iterable2))

    def test_list(self):
        self.assertIterableEqual(lstrip([1, 1, 2, 3], 1), [2, 3])

    def test_nothing_to_strip(self):
        self.assertIterableEqual(lstrip([1, 2, 3], 0), [1, 2, 3])

    def test_string(self):
        self.assertIterableEqual(lstrip('  hello', ' '), 'hello')

    def test_empty_iterable(self):
        self.assertIterableEqual(lstrip([], 1), [])

    def test_strip_all(self):
        self.assertIterableEqual(lstrip([1, 1, 1], 1), [])

    def test_none_values(self):
        self.assertIterableEqual(lstrip([None, 1, 2, 3], 0), [None, 1, 2, 3])

    def test_iterator(self):
        squares = (n**2 for n in [0, 0, 1, 2, 3])
        self.assertIterableEqual(lstrip(squares, 0), [1, 4, 9])

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_returns_iterator(self):
        stripped = lstrip((1, 2, 3), 1)
        self.assertEqual(iter(stripped), iter(stripped))

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_function_given(self):
        numbers = [0, 2, 4, 1, 3, 5, 6]
        def is_even(n): return n % 2 == 0
        self.assertIterableEqual(lstrip(numbers, is_even), [1, 3, 5, 6])


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)

"""
Explanation: Using the iterator protocol
======================
Loop through the iterator, skip the items in iterator until an item that does not match the skip_value is found.
End of explanation
"""


def lstrip(iterable, strip_value):
    """ Return iterable with strip_value removed from the beginnning"""
    iterator = iter(iterable)
    for item in iterator:
        if not item == strip_value:
            yield item
            break
            
    for item in iterator:
        yield item


import unittest

class LStripTests(unittest.TestCase):

    """Tests for lstrip."""

    def assertIterableEqual(self, iterable1, iterable2):
        self.assertEqual(list(iterable1), list(iterable2))

    def test_list(self):
        self.assertIterableEqual(lstrip([1, 1, 2, 3], 1), [2, 3])

    def test_nothing_to_strip(self):
        self.assertIterableEqual(lstrip([1, 2, 3], 0), [1, 2, 3])

    def test_string(self):
        self.assertIterableEqual(lstrip('  hello', ' '), 'hello')

    def test_empty_iterable(self):
        self.assertIterableEqual(lstrip([], 1), [])

    def test_strip_all(self):
        self.assertIterableEqual(lstrip([1, 1, 1], 1), [])

    def test_none_values(self):
        self.assertIterableEqual(lstrip([None, 1, 2, 3], 0), [None, 1, 2, 3])

    def test_iterator(self):
        squares = (n**2 for n in [0, 0, 1, 2, 3])
        self.assertIterableEqual(lstrip(squares, 0), [1, 4, 9])

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_returns_iterator(self):
        stripped = lstrip((1, 2, 3), 1)
        self.assertEqual(iter(stripped), iter(stripped))

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_function_given(self):
        numbers = [0, 2, 4, 1, 3, 5, 6]
        def is_even(n): return n % 2 == 0
        self.assertIterableEqual(lstrip(numbers, is_even), [1, 3, 5, 6])


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)

"""
Explanation: Bonus1: The lstrip function should return an iterator
End of explanation
"""


my_list = [1, 2, 3, 4]
iterator1 = iter(my_list)
iterator2 = iter(my_list)
iterator1 == iterator2

my_list = [1, 2, 3, 4]
iterator = iter(my_list)
iterator1 = iter(iterator)
iterator2 = iter(iterator)
iterator1 == iterator2

"""
Explanation: Experiments : Testing iterator
End of explanation
"""


def lstrip(iterable, strip_value):
    """Return iterable with strip_value items removed from beginning."""
    iterator = iter(iterable)
    for item in iterator:
        if (callable(strip_value) and not strip_value(item)
                or item != strip_value):
            yield item
            break
    for item in iterator:
        yield item

import unittest

class LStripTests(unittest.TestCase):

    """Tests for lstrip."""

    def assertIterableEqual(self, iterable1, iterable2):
        self.assertEqual(list(iterable1), list(iterable2))

    def test_list(self):
        self.assertIterableEqual(lstrip([1, 1, 2, 3], 1), [2, 3])

    def test_nothing_to_strip(self):
        self.assertIterableEqual(lstrip([1, 2, 3], 0), [1, 2, 3])

    def test_string(self):
        self.assertIterableEqual(lstrip('  hello', ' '), 'hello')

    def test_empty_iterable(self):
        self.assertIterableEqual(lstrip([], 1), [])

    def test_strip_all(self):
        self.assertIterableEqual(lstrip([1, 1, 1], 1), [])

    def test_none_values(self):
        self.assertIterableEqual(lstrip([None, 1, 2, 3], 0), [None, 1, 2, 3])

    def test_iterator(self):
        squares = (n**2 for n in [0, 0, 1, 2, 3])
        self.assertIterableEqual(lstrip(squares, 0), [1, 4, 9])

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_returns_iterator(self):
        stripped = lstrip((1, 2, 3), 1)
        self.assertEqual(iter(stripped), iter(stripped))

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_function_given(self):
        numbers = [0, 2, 4, 1, 3, 5, 6]
        def is_even(n): return n % 2 == 0
        self.assertIterableEqual(lstrip(numbers, is_even), [1, 3, 5, 6])


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)

def lstrip(iterable, strip_value):
    """Return iterable with strip_value items removed from beginning."""
    iterator = iter(iterable)
    if callable(strip_value):
        predicate = strip_value
    else:
        def predicate(value): return value == strip_value
        
    for item in iterator:
        if not predicate(item):
            yield item
            break
    for item in iterator:
        yield item

import unittest

class LStripTests(unittest.TestCase):

    """Tests for lstrip."""

    def assertIterableEqual(self, iterable1, iterable2):
        self.assertEqual(list(iterable1), list(iterable2))

    def test_list(self):
        self.assertIterableEqual(lstrip([1, 1, 2, 3], 1), [2, 3])

    def test_nothing_to_strip(self):
        self.assertIterableEqual(lstrip([1, 2, 3], 0), [1, 2, 3])

    def test_string(self):
        self.assertIterableEqual(lstrip('  hello', ' '), 'hello')

    def test_empty_iterable(self):
        self.assertIterableEqual(lstrip([], 1), [])

    def test_strip_all(self):
        self.assertIterableEqual(lstrip([1, 1, 1], 1), [])

    def test_none_values(self):
        self.assertIterableEqual(lstrip([None, 1, 2, 3], 0), [None, 1, 2, 3])

    def test_iterator(self):
        squares = (n**2 for n in [0, 0, 1, 2, 3])
        self.assertIterableEqual(lstrip(squares, 0), [1, 4, 9])

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_returns_iterator(self):
        stripped = lstrip((1, 2, 3), 1)
        self.assertEqual(iter(stripped), iter(stripped))

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_function_given(self):
        numbers = [0, 2, 4, 1, 3, 5, 6]
        def is_even(n): return n % 2 == 0
        self.assertIterableEqual(lstrip(numbers, is_even), [1, 3, 5, 6])


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)

"""
Explanation: Bonus2: We're supposed to optionally accept a function as our strip value and call that function to determine whether values should be removed
End of explanation
"""


from itertools import dropwhile
def lstrip(iterable, strip_value):
    """Return iterable with strip_value items removed from beginning."""
    def is_strip_value(item): return item == strip_value
    
    return dropwhile(is_strip_value, iterable)

import unittest

class LStripTests(unittest.TestCase):

    """Tests for lstrip."""

    def assertIterableEqual(self, iterable1, iterable2):
        self.assertEqual(list(iterable1), list(iterable2))

    def test_list(self):
        self.assertIterableEqual(lstrip([1, 1, 2, 3], 1), [2, 3])

    def test_nothing_to_strip(self):
        self.assertIterableEqual(lstrip([1, 2, 3], 0), [1, 2, 3])

    def test_string(self):
        self.assertIterableEqual(lstrip('  hello', ' '), 'hello')

    def test_empty_iterable(self):
        self.assertIterableEqual(lstrip([], 1), [])

    def test_strip_all(self):
        self.assertIterableEqual(lstrip([1, 1, 1], 1), [])

    def test_none_values(self):
        self.assertIterableEqual(lstrip([None, 1, 2, 3], 0), [None, 1, 2, 3])

    def test_iterator(self):
        squares = (n**2 for n in [0, 0, 1, 2, 3])
        self.assertIterableEqual(lstrip(squares, 0), [1, 4, 9])

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_returns_iterator(self):
        stripped = lstrip((1, 2, 3), 1)
        self.assertEqual(iter(stripped), iter(stripped))

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_function_given(self):
        numbers = [0, 2, 4, 1, 3, 5, 6]
        def is_even(n): return n % 2 == 0
        self.assertIterableEqual(lstrip(numbers, is_even), [1, 3, 5, 6])


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)

"""
Explanation: Using dropwhile helper function in itertools module
========================================
The dropwhile function in the itertools module will give us an iterable that has our original iterable's values except it drops any at the beginning that pass a certain test.
Bonus1: The lstrip function should return an iterator
End of explanation
"""


from itertools import dropwhile
def lstrip(iterable, strip_value):
    """Return iterable with strip_value items removed from beginning."""
    if callable(strip_value):
        predicate = strip_value
    else:
        def predicate(item): return item == strip_value
        
    return dropwhile(predicate, iterable)

import unittest

class LStripTests(unittest.TestCase):

    """Tests for lstrip."""

    def assertIterableEqual(self, iterable1, iterable2):
        self.assertEqual(list(iterable1), list(iterable2))

    def test_list(self):
        self.assertIterableEqual(lstrip([1, 1, 2, 3], 1), [2, 3])

    def test_nothing_to_strip(self):
        self.assertIterableEqual(lstrip([1, 2, 3], 0), [1, 2, 3])

    def test_string(self):
        self.assertIterableEqual(lstrip('  hello', ' '), 'hello')

    def test_empty_iterable(self):
        self.assertIterableEqual(lstrip([], 1), [])

    def test_strip_all(self):
        self.assertIterableEqual(lstrip([1, 1, 1], 1), [])

    def test_none_values(self):
        self.assertIterableEqual(lstrip([None, 1, 2, 3], 0), [None, 1, 2, 3])

    def test_iterator(self):
        squares = (n**2 for n in [0, 0, 1, 2, 3])
        self.assertIterableEqual(lstrip(squares, 0), [1, 4, 9])

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_returns_iterator(self):
        stripped = lstrip((1, 2, 3), 1)
        self.assertEqual(iter(stripped), iter(stripped))

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_function_given(self):
        numbers = [0, 2, 4, 1, 3, 5, 6]
        def is_even(n): return n % 2 == 0
        self.assertIterableEqual(lstrip(numbers, is_even), [1, 3, 5, 6])


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)

"""
Explanation: Bonus2: We're supposed to optionally accept a function as our strip value and call that function to determine whether values should be removed
End of explanation
"""


