<s> import functools <EOL> import threading <EOL> import collections <EOL> import itertools <EOL> from python_toolbox import misc_tools <EOL> from python_toolbox import decorator_tools <EOL> from python_toolbox import comparison_tools <EOL> infinity = float ( '<STR_LIT>' ) <EOL> class _SENTINEL ( misc_tools . NonInstantiable ) : <EOL> '''<STR_LIT>''' <EOL> def _convert_index_to_exhaustion_point ( index ) : <EOL> '''<STR_LIT>''' <EOL> assert isinstance ( index , int ) or index == infinity <EOL> if index >= <NUM_LIT:0> : <EOL> return index <EOL> else : <EOL> return infinity <EOL> @ decorator_tools . decorator <EOL> def _with_lock ( method , * args , ** kwargs ) : <EOL> '''<STR_LIT>''' <EOL> self = args [ <NUM_LIT:0> ] <EOL> with self . lock : <EOL> return method ( * args , ** kwargs ) <EOL> @ functools . total_ordering <EOL> class LazyTuple ( collections . Sequence ) : <EOL> '''<STR_LIT>''' <EOL> def __init__ ( self , iterable , definitely_infinite = False ) : <EOL> was_given_a_sequence = isinstance ( iterable , collections . Sequence ) and not isinstance ( iterable , LazyTuple ) <EOL> self . is_exhausted = True if was_given_a_sequence else False <EOL> '''<STR_LIT>''' <EOL> self . collected_data = iterable if was_given_a_sequence else [ ] <EOL> '''<STR_LIT>''' <EOL> self . _iterator = None if was_given_a_sequence else iter ( iterable ) <EOL> '''<STR_LIT>''' <EOL> self . definitely_infinite = definitely_infinite <EOL> '''<STR_LIT>''' <EOL> self . lock = threading . Lock ( ) <EOL> '''<STR_LIT>''' <EOL> @ classmethod <EOL> @ decorator_tools . helpful_decorator_builder <EOL> def factory ( cls , definitely_infinite = False ) : <EOL> '''<STR_LIT>''' <EOL> def inner ( function , * args , ** kwargs ) : <EOL> return cls ( function ( * args , ** kwargs ) , <EOL> definitely_infinite = definitely_infinite ) <EOL> return decorator_tools . decorator ( inner ) <EOL> @ property <EOL> def known_length ( self ) : <EOL> '''<STR_LIT>''' <EOL> return len ( self . collected_data ) <EOL> def exhaust ( self , i = infinity ) : <EOL> '''<STR_LIT>''' <EOL> from python_toolbox import sequence_tools <EOL> if self . is_exhausted : <EOL> return <EOL> elif isinstance ( i , int ) or i == infinity : <EOL> exhaustion_point = _convert_index_to_exhaustion_point ( i ) <EOL> else : <EOL> assert isinstance ( i , slice ) <EOL> canonical_slice = sequence_tools . CanonicalSlice ( i ) <EOL> exhaustion_point = max ( <EOL> _convert_index_to_exhaustion_point ( canonical_slice . start ) , <EOL> _convert_index_to_exhaustion_point ( canonical_slice . stop ) <EOL> ) <EOL> if canonical_slice . step > <NUM_LIT:0> : <EOL> exhaustion_point -= <NUM_LIT:1> <EOL> while len ( self . collected_data ) <= exhaustion_point : <EOL> try : <EOL> with self . lock : <EOL> self . collected_data . append ( next ( self . _iterator ) ) <EOL> except StopIteration : <EOL> self . is_exhausted = True <EOL> break <EOL> def __getitem__ ( self , i ) : <EOL> '''<STR_LIT>''' <EOL> self . exhaust ( i ) <EOL> result = self . collected_data [ i ] <EOL> if isinstance ( i , slice ) : <EOL> return tuple ( result ) <EOL> else : <EOL> return result <EOL> def __len__ ( self ) : <EOL> if self . definitely_infinite : <EOL> return <NUM_LIT:0> <EOL> else : <EOL> self . exhaust ( ) <EOL> return len ( self . collected_data ) <EOL> def __eq__ ( self , other ) : <EOL> from python_toolbox import sequence_tools <EOL> if not sequence_tools . is_immutable_sequence ( other ) : <EOL> return False <EOL> for i , j in itertools . zip_longest ( self , other , <EOL> fillvalue = _SENTINEL ) : <EOL> if ( i is _SENTINEL ) or ( j is _SENTINEL ) : <EOL> return False <EOL> if i != j : <EOL> return False <EOL> return True <EOL> def __ne__ ( self , other ) : <EOL> return not self . __eq__ ( other ) <EOL> def __bool__ ( self ) : <EOL> try : next ( iter ( self ) ) <EOL> except StopIteration : return False <EOL> else : return True <EOL> def __lt__ ( self , other ) : <EOL> if not self and other : <EOL> return True <EOL> elif self and not other : <EOL> return False <EOL> elif not self and not other : <EOL> return False <EOL> for a , b in itertools . zip_longest ( self , other , <EOL> fillvalue = _SENTINEL ) : <EOL> if a is _SENTINEL : <EOL> return True <EOL> elif b is _SENTINEL : <EOL> assert a is not _SENTINEL <EOL> return False <EOL> elif a == b : <EOL> continue <EOL> elif a < b : <EOL> return True <EOL> else : <EOL> assert a > b <EOL> return False <EOL> def __repr__ ( self ) : <EOL> '''<STR_LIT>''' <EOL> if self . is_exhausted : <EOL> inner = repr ( self . collected_data ) <EOL> else : <EOL> if self . collected_data == [ ] : <EOL> inner = '<STR_LIT>' <EOL> else : <EOL> inner = '<STR_LIT>' % repr ( self . collected_data ) <EOL> return '<STR_LIT>' % ( self . __class__ . __name__ , inner ) <EOL> def __add__ ( self , other ) : <EOL> return tuple ( self ) + tuple ( other ) <EOL> def __radd__ ( self , other ) : <EOL> return tuple ( other ) + tuple ( self ) <EOL> def __mul__ ( self , other ) : <EOL> return tuple ( self ) . __mul__ ( other ) <EOL> def __rmul__ ( self , other ) : <EOL> return tuple ( self ) . __rmul__ ( other ) <EOL> def __hash__ ( self ) : <EOL> '''<STR_LIT>''' <EOL> if self . definitely_infinite : <EOL> raise TypeError ( "<STR_LIT>" ) <EOL> else : <EOL> self . exhaust ( ) <EOL> return hash ( tuple ( self ) ) </s>
