def test_item_test(): '''Test the `item_test` argument.''' def is_int_like(item): '''Is `item` something like an `int`?''' try: 1 + item except Exception: return False else: return True def is_list_like(item): '''Is `item` something like a `list`?''' try: [1, 2] + item except Exception: return False else: return True def is_tuple_like(item): '''Is `item` something like an `tuple`?''' try: (1, 2) + item except Exception: return False else: return True assert to_tuple(7, item_test=is_int_like) == (7,) assert to_tuple((1, 2), item_test=is_int_like) == (1, 2) assert to_tuple([7], item_test=is_list_like) == ([7],) assert to_tuple(([1], [2]), item_test=is_list_like) == ([1], [2]) assert to_tuple((7,), item_test=is_tuple_like) == ((7,),)
def test(): '''Test the basic workings of `sequence_tools.to_tuple`.''' assert to_tuple((1, 2, 3)) == (1, 2, 3) assert to_tuple([1, 2, 3]) == (1, 2, 3) assert to_tuple(7) == (7,) assert to_tuple((7,)) == (7,) assert to_tuple(Ellipsis) == (Ellipsis,)
def test_item_type(): '''Test the `item_type` argument.''' assert to_tuple(7, item_type=int) == (7,) assert to_tuple([7], item_type=list) == ([7],) assert to_tuple([7], item_type=(list, tuple, float)) == ([7],) assert to_tuple((7,), item_type=tuple) == ((7,),) assert to_tuple((7,), item_type=(tuple, range)) == ((7,),)
def __init__(self, case_style_possibilites=(LowerCase, ), n_preceding_underscores_possibilities=(1, )): ''' Construct the `NameParser`. In `case_style_possibilites` you may specify a set of case styles (subclasses of `BaseCaseStyle`) that will be accepted by this parser. In `n_preceding_underscores_possibilities`, you may specify a set of ints signifying the number of underscores prefixing the name. For example, if you specify `(1, 2)`, this parser will accept names starting with either 1 or 2 underscores. ''' self.case_style_possibilites = sequence_tools.to_tuple( case_style_possibilites, item_type=CaseStyleType) '''The set of case styles that this name parser accepts.''' self.n_preceding_underscores_possibilities = sequence_tools.to_tuple( n_preceding_underscores_possibilities) '''Set of number of preceding underscores that this parser accepts.''' assert all( isinstance(case_style, CaseStyleType) for case_style in self.case_style_possibilites) assert all( isinstance(n_preceding_underscores, int) for n_preceding_underscores in self.n_preceding_underscores_possibilities)
def __init__(self, case_style_possibilites=(LowerCase,), n_preceding_underscores_possibilities=(1,)): ''' Construct the `NameParser`. In `case_style_possibilites` you may specify a set of case styles (subclasses of `BaseCaseStyle`) that will be accepted by this parser. In `n_preceding_underscores_possibilities`, you may specify a set of ints signifying the number of underscores prefixing the name. For example, if you specify `(1, 2)`, this parser will accept names starting with either 1 or 2 underscores. ''' self.case_style_possibilites = sequence_tools.to_tuple( case_style_possibilites, item_type=CaseStyleType ) '''The set of case styles that this name parser accepts.''' self.n_preceding_underscores_possibilities = sequence_tools.to_tuple( n_preceding_underscores_possibilities ) '''Set of number of preceding underscores that this parser accepts.''' assert all(isinstance(case_style, CaseStyleType) for case_style in self.case_style_possibilites) assert all(isinstance(n_preceding_underscores, int) for n_preceding_underscores in self.n_preceding_underscores_possibilities)
def test_too_many_arguments(): '''Test helpful error when giving both `item_type` and `item_test`.''' with cute_testing.RaiseAssertor(text='either'): to_tuple( (1, 2, 3), item_type=int, item_test=lambda item: isinstance(item, int) )
def __init__(self, inputs=(), outputs=(), name=None): ''' Construct the emitter. `inputs` is an iterable of inputs, all of which must be emitters. (You can also pass in a single input without using an iterable.) `outputs` is an iterable of outputs, which may be either emitters or callables. (You can also pass in a single output without using an iterable.) `name` is a string name for the emitter. (Optional, helps with debugging.) ''' from python_toolbox import sequence_tools inputs = sequence_tools.to_tuple(inputs, item_type=Emitter) outputs = sequence_tools.to_tuple(outputs, item_type=(collections.abc.Callable, Emitter)) self._inputs = set() '''The emitter's inputs.''' self._outputs = set() '''The emitter's inputs.''' for output in outputs: self.add_output(output) self.__total_callable_outputs_cache = None ''' A cache of total callable outputs. This means the callable outputs of this emitter and any output emitters. ''' self._recalculate_total_callable_outputs() # We made sure to create the callable outputs cache before we add # inputs, so when we update their cache, it could use ours. for input in inputs: self.add_input(input) self.name = name '''The emitter's name.'''
def __init__(self, inputs=(), outputs=(), name=None): ''' Construct the emitter. `inputs` is an iterable of inputs, all of which must be emitters. (You can also pass in a single input without using an iterable.) `outputs` is an iterable of outputs, which may be either emitters or callables. (You can also pass in a single output without using an iterable.) `name` is a string name for the emitter. (Optional, helps with debugging.) ''' from python_toolbox import sequence_tools inputs = sequence_tools.to_tuple(inputs, item_type=Emitter) outputs = sequence_tools.to_tuple(outputs, item_type=(collections.Callable, Emitter)) self._inputs = set() '''The emitter's inputs.''' self._outputs = set() '''The emitter's inputs.''' for output in outputs: self.add_output(output) self.__total_callable_outputs_cache = None ''' A cache of total callable outputs. This means the callable outputs of this emitter and any output emitters. ''' self._recalculate_total_callable_outputs() # We made sure to create the callable outputs cache before we add # inputs, so when we update their cache, it could use ours. for input in inputs: self.add_input(input) self.name = name '''The emitter's name.'''
def get_event_code_from_name(name, evt_handler_type): ''' Get an event code given a `name` and an `evt_handler_type`. For example, given a `name` of `left_down` this function will return the event code `wx.EVT_LEFT_DOWN`. If `evt_handler_type` has an `.event_modules` attribute, these modules will be searched for event codes in precedence to `wx` and the event handler type's own module. ''' processed_name = 'EVT_%s' % string_tools.case_conversions. \ camel_case_to_lower_case(name).upper() raw_event_modules = sequence_tools.to_tuple(evt_handler_type.event_modules) event_modules = raw_event_modules + ( address_tools.resolve(evt_handler_type.__module__), wx ) for event_module in event_modules: try: return getattr(event_module, processed_name) except AttributeError: pass else: raise LookupError(f"Couldn't find event by the name of " f"'{processed_name}'.")
def get_degreed(self, degrees): '''Get a version of this `PermSpace` restricted to certain degrees.''' from . import variations if self.is_sliced: raise TypeError( "Can't be used on sliced perm spaces. Try " "`perm_space.unsliced.get_degreed(...)`. You may then " "re-slice the resulting space." ) if self.is_combination: raise variations.UnallowedVariationSelectionException( {variations.Variation.DEGREED: True, variations.Variation.COMBINATION: True,} ) degrees = sequence_tools.to_tuple(degrees, item_type=int) if not degrees: return self degrees_to_use = \ degrees if not self.is_degreed else set(degrees) & set(self.degrees) return PermSpace( self.sequence, n_elements=self.n_elements, domain=self.domain, fixed_map=self.fixed_map, degrees=degrees_to_use, is_combination=self.is_combination, perm_type=self.perm_type )
def _call_until_exception(function, exception): from python_toolbox import sequence_tools exceptions = sequence_tools.to_tuple(exception, item_type=type) try: while True: yield function() except exceptions: raise StopIteration
def _call_until_exception(function, exception): from python_toolbox import sequence_tools exceptions = sequence_tools.to_tuple(exception, item_type=type) try: while True: yield function() except exceptions: return
def __init__(self, addition): ''' Construct the `TempSysPathAdder`. `addition` may be a path or a sequence of paths. ''' self.addition = map( unicode, sequence_tools.to_tuple(addition, item_type=(basestring, pathlib.PurePath)))
def __init__(self, addition): ''' Construct the `TempSysPathAdder`. `addition` may be a path or a sequence of paths. ''' self.addition = map( unicode, sequence_tools.to_tuple(addition, item_type=(basestring, pathlib.PurePath)) )
def get_event_code_from_name(name, evt_handler_type): """ Get an event code given a `name` and an `evt_handler_type`. For example, given a `name` of `left_down` this function will return the event code `wx.EVT_LEFT_DOWN`. If `evt_handler_type` has an `.event_modules` attribute, these modules will be searched for event codes in precedence to `wx` and the event handler type's own module. """ processed_name = "EVT_%s" % string_tools.case_conversions.camel_case_to_lower_case(name).upper() raw_event_modules = sequence_tools.to_tuple(evt_handler_type.event_modules) event_modules = raw_event_modules + (address_tools.resolve(evt_handler_type.__module__), wx) for event_module in event_modules: try: return getattr(event_module, processed_name) except AttributeError: pass else: raise LookupError("Couldn't find event by the name of '%s'." % processed_name)
def __init__(self, iterable_or_length, n_elements=None, *, domain=None, fixed_map=None, degrees=None, is_combination=False, slice_=None, perm_type=None): ### Making basic argument checks: ##################################### # # assert isinstance( iterable_or_length, (collections.Iterable, numbers.Integral) ) if isinstance(iterable_or_length, numbers.Integral): assert iterable_or_length >= 0 if slice_ is not None: assert isinstance(slice_, (slice, sequence_tools.CanonicalSlice)) if slice_.step not in (1, None): raise NotImplementedError assert isinstance(n_elements, numbers.Integral) or n_elements is None assert isinstance(is_combination, bool) # # ### Finished making basic argument checks. ############################ ### Figuring out sequence and whether space is rapplied: ############## # # if isinstance(iterable_or_length, numbers.Integral): self.is_rapplied = False self.sequence = sequence_tools.CuteRange(iterable_or_length) self.sequence_length = iterable_or_length else: assert isinstance(iterable_or_length, collections.Iterable) self.sequence = sequence_tools. \ ensure_iterable_is_immutable_sequence(iterable_or_length) range_candidate = sequence_tools.CuteRange(len(self.sequence)) self.is_rapplied = not ( cute_iter_tools.are_equal(self.sequence, range_candidate) ) self.sequence_length = len(self.sequence) if not self.is_rapplied: self.sequence = sequence_tools.CuteRange(self.sequence_length) # # ### Finished figuring out sequence and whether space is rapplied. ##### ### Figuring out whether sequence is recurrent: ####################### # # if self.is_rapplied: self.is_recurrent = any(count >= 2 for count in self._frozen_ordered_bag.values()) else: self.is_recurrent = False # # ### Finished figuring out whether sequence is recurrent. ############## ### Figuring out number of elements: ################################## # # self.n_elements = self.sequence_length if (n_elements is None) \ else n_elements if not isinstance(self.n_elements, int): raise TypeError('`n_elements` must be an `int`.') if not self.n_elements >= 0: raise TypeError('`n_elements` must be positive or zero.') self.is_partial = (self.n_elements != self.sequence_length) self.indices = sequence_tools.CuteRange(self.n_elements) # # ### Finished figuring out number of elements. ######################### ### Figuring out whether it's a combination: ########################## # # self.is_combination = is_combination # Well that was quick. # # ### Finished figuring out whether it's a combination. ################# ### Figuring out whether space is dapplied: ########################### # # if domain is None: domain = self.indices domain = \ sequence_tools.ensure_iterable_is_immutable_sequence(domain) if self.is_partial: domain = domain[:self.n_elements] self.is_dapplied = not cute_iter_tools.are_equal( domain, self.indices ) if self.is_dapplied: if self.is_combination: raise UnallowedVariationSelectionException( {variations.Variation.DAPPLIED: True, variations.Variation.COMBINATION: True,} ) self.domain = domain if len(set(self.domain)) < len(self.domain): raise Exception('The domain must not have repeating elements.') else: self.domain = self.indices self.undapplied = self # # ### Finished figuring out whether space is dapplied. ################## ### Figuring out fixed map: ########################################### # # if fixed_map is None: fixed_map = {} if not isinstance(fixed_map, dict): if isinstance(fixed_map, collections.Callable): fixed_map = {item: fixed_map(item) for item in self.sequence} else: fixed_map = dict(fixed_map) if fixed_map: self.fixed_map = {key: value for (key, value) in fixed_map.items() if (key in self.domain) and (value in self.sequence)} else: (self.fixed_map, self.free_indices, self.free_keys, self.free_values) = ( {}, self.indices, self.domain, self.sequence ) self.is_fixed = bool(self.fixed_map) if self.is_fixed: if not (self.is_dapplied or self.is_rapplied or degrees or slice_ or (n_elements is not None) or self.is_combination): self._just_fixed = self else: self._get_just_fixed = lambda: PermSpace( len(self.sequence), fixed_map=self._undapplied_unrapplied_fixed_map, ) else: if not (self.is_dapplied or self.is_rapplied or degrees or slice_ or (n_elements is not None) or self.is_combination): self._just_fixed = self else: self._get_just_fixed = lambda: PermSpace(len(self.sequence)) # # ### Finished figuring out fixed map. ################################## ### Figuring out degrees: ############################################# # # all_degrees = sequence_tools.CuteRange(self.sequence_length) if degrees is None: degrees = () degrees = sequence_tools.to_tuple(degrees, item_type=int) if (not degrees) or cute_iter_tools.are_equal(degrees, all_degrees): self.is_degreed = False self.degrees = all_degrees else: self.is_degreed = True if self.is_combination: raise UnallowedVariationSelectionException( {variations.Variation.DEGREED: True, variations.Variation.COMBINATION: True,} ) if self.is_partial: raise UnallowedVariationSelectionException( {variations.Variation.DEGREED: True, variations.Variation.PARTIAL: True,} ) if self.is_recurrent: raise UnallowedVariationSelectionException( {variations.Variation.DEGREED: True, variations.Variation.RECURRENT: True,} ) # The space is degreed; we canonicalize `degrees` into a sorted # tuple. self.degrees = tuple(sorted( degree for degree in degrees if degree in all_degrees )) # # ### Finished figuring out degrees. #################################### ### Figuring out slice and length: #################################### # # self.slice_ = slice_ self.canonical_slice = sequence_tools.CanonicalSlice( slice_ or slice(float('inf')), self._unsliced_length ) self.length = max( self.canonical_slice.stop - self.canonical_slice.start, 0 ) self.is_sliced = (self.length != self._unsliced_length) # # ### Finished figuring out slice and length. ########################### ### Figuring out perm type: ########################################### # # self.is_typed = perm_type not in (None, self.default_perm_type) self.perm_type = perm_type if self.is_typed else self.default_perm_type assert issubclass(self.perm_type, Perm) # # ### Finished figuring out perm type. ################################## self.is_pure = not (self.is_rapplied or self.is_fixed or self.is_sliced or self.is_degreed or self.is_partial or self.is_combination or self.is_typed) if self.is_pure: self.purified = self if not self.is_rapplied: self.unrapplied = self if not self.is_recurrent: self.unrecurrented = self if not self.is_partial: self.unpartialled = self if not self.is_combination: self.uncombinationed = self # No need do this for `undapplied`, it's already done above. if not self.is_fixed: self.unfixed = self if not self.is_degreed: self.undegreed = self if not self.is_sliced: self.unsliced = self if not self.is_typed: self.untyped = self
def get_event_codes_of_component(component): """Get the event codes that should be bound to `component`.""" return sequence_tools.to_tuple(component._EventHandlerGrokker__event_code)
def test_none(): assert to_tuple(None) == () assert to_tuple(None, item_type=int) == () assert to_tuple(None, item_type=list) == () assert to_tuple(None, item_type=type(None)) == (None, )
def __init__(self, iterable_or_length, n_elements=None, *, domain=None, fixed_map=None, degrees=None, is_combination=False, slice_=None, perm_type=None): ### Making basic argument checks: ##################################### # # assert isinstance(iterable_or_length, (collections.abc.Iterable, numbers.Integral)) if isinstance(iterable_or_length, numbers.Integral): assert iterable_or_length >= 0 if slice_ is not None: assert isinstance(slice_, (slice, sequence_tools.CanonicalSlice)) if slice_.step not in (1, None): raise NotImplementedError assert isinstance(n_elements, numbers.Integral) or n_elements is None assert isinstance(is_combination, bool) # # ### Finished making basic argument checks. ############################ ### Figuring out sequence and whether space is rapplied: ############## # # if isinstance(iterable_or_length, numbers.Integral): self.is_rapplied = False self.sequence = sequence_tools.CuteRange(iterable_or_length) self.sequence_length = iterable_or_length else: assert isinstance(iterable_or_length, collections.abc.Iterable) self.sequence = sequence_tools. \ ensure_iterable_is_immutable_sequence(iterable_or_length) range_candidate = sequence_tools.CuteRange(len(self.sequence)) self.is_rapplied = not (cute_iter_tools.are_equal( self.sequence, range_candidate)) self.sequence_length = len(self.sequence) if not self.is_rapplied: self.sequence = sequence_tools.CuteRange(self.sequence_length) # # ### Finished figuring out sequence and whether space is rapplied. ##### ### Figuring out whether sequence is recurrent: ####################### # # if self.is_rapplied: self.is_recurrent = any( count >= 2 for count in self._frozen_ordered_bag.values()) else: self.is_recurrent = False # # ### Finished figuring out whether sequence is recurrent. ############## ### Figuring out number of elements: ################################## # # self.n_elements = self.sequence_length if (n_elements is None) \ else n_elements if not isinstance(self.n_elements, int): raise TypeError('`n_elements` must be an `int`.') if not self.n_elements >= 0: raise TypeError('`n_elements` must be positive or zero.') self.is_partial = (self.n_elements != self.sequence_length) self.indices = sequence_tools.CuteRange(self.n_elements) # # ### Finished figuring out number of elements. ######################### ### Figuring out whether it's a combination: ########################## # # self.is_combination = is_combination # Well that was quick. # # ### Finished figuring out whether it's a combination. ################# ### Figuring out whether space is dapplied: ########################### # # if domain is None: domain = self.indices domain = \ sequence_tools.ensure_iterable_is_immutable_sequence(domain) if self.is_partial: domain = domain[:self.n_elements] self.is_dapplied = not cute_iter_tools.are_equal(domain, self.indices) if self.is_dapplied: if self.is_combination: raise UnallowedVariationSelectionException({ variations.Variation.DAPPLIED: True, variations.Variation.COMBINATION: True, }) self.domain = domain if len(set(self.domain)) < len(self.domain): raise Exception('The domain must not have repeating elements.') else: self.domain = self.indices self.undapplied = self # # ### Finished figuring out whether space is dapplied. ################## ### Figuring out fixed map: ########################################### # # if fixed_map is None: fixed_map = {} if not isinstance(fixed_map, dict): if isinstance(fixed_map, collections.abc.Callable): fixed_map = {item: fixed_map(item) for item in self.sequence} else: fixed_map = dict(fixed_map) if fixed_map: self.fixed_map = { key: value for (key, value) in fixed_map.items() if (key in self.domain) and (value in self.sequence) } else: (self.fixed_map, self.free_indices, self.free_keys, self.free_values) = ({}, self.indices, self.domain, self.sequence) self.is_fixed = bool(self.fixed_map) if self.is_fixed: if not (self.is_dapplied or self.is_rapplied or degrees or slice_ or (n_elements is not None) or self.is_combination): self._just_fixed = self else: self._get_just_fixed = lambda: PermSpace( len(self.sequence), fixed_map=self._undapplied_unrapplied_fixed_map, ) else: if not (self.is_dapplied or self.is_rapplied or degrees or slice_ or (n_elements is not None) or self.is_combination): self._just_fixed = self else: self._get_just_fixed = lambda: PermSpace(len(self.sequence)) # # ### Finished figuring out fixed map. ################################## ### Figuring out degrees: ############################################# # # all_degrees = sequence_tools.CuteRange(self.sequence_length) if degrees is None: degrees = () degrees = sequence_tools.to_tuple(degrees, item_type=int) if (not degrees) or cute_iter_tools.are_equal(degrees, all_degrees): self.is_degreed = False self.degrees = all_degrees else: self.is_degreed = True if self.is_combination: raise UnallowedVariationSelectionException({ variations.Variation.DEGREED: True, variations.Variation.COMBINATION: True, }) if self.is_partial: raise UnallowedVariationSelectionException({ variations.Variation.DEGREED: True, variations.Variation.PARTIAL: True, }) if self.is_recurrent: raise UnallowedVariationSelectionException({ variations.Variation.DEGREED: True, variations.Variation.RECURRENT: True, }) # The space is degreed; we canonicalize `degrees` into a sorted # tuple. self.degrees = tuple( sorted(degree for degree in degrees if degree in all_degrees)) # # ### Finished figuring out degrees. #################################### ### Figuring out slice and length: #################################### # # self.slice_ = slice_ self.canonical_slice = sequence_tools.CanonicalSlice( slice_ or slice(float('inf')), self._unsliced_length) self.length = max( self.canonical_slice.stop - self.canonical_slice.start, 0) self.is_sliced = (self.length != self._unsliced_length) # # ### Finished figuring out slice and length. ########################### ### Figuring out perm type: ########################################### # # self.is_typed = perm_type not in (None, self.default_perm_type) self.perm_type = perm_type if self.is_typed else self.default_perm_type assert issubclass(self.perm_type, Perm) # # ### Finished figuring out perm type. ################################## self.is_pure = not (self.is_rapplied or self.is_fixed or self.is_sliced or self.is_degreed or self.is_partial or self.is_combination or self.is_typed) if self.is_pure: self.purified = self if not self.is_rapplied: self.unrapplied = self if not self.is_recurrent: self.unrecurrented = self if not self.is_partial: self.unpartialled = self if not self.is_combination: self.uncombinationed = self # No need do this for `undapplied`, it's already done above. if not self.is_fixed: self.unfixed = self if not self.is_degreed: self.undegreed = self if not self.is_sliced: self.unsliced = self if not self.is_typed: self.untyped = self
def test_tuple_in_tuple(): '''Test input of tuple inside a tuple.''' raise nose.SkipTest("Don't know how to solve this case.") assert to_tuple(((1,), (2,)), item_test=is_tuple_like) == ((1,), (2,))
def get_event_codes_of_component(component): '''Get the event codes that should be bound to `component`.''' return sequence_tools.to_tuple(component._EventHandlerGrokker__event_code)
def test_none(): assert to_tuple(None) == () assert to_tuple(None, item_type=int) == () assert to_tuple(None, item_type=list) == () assert to_tuple(None, item_type=type(None)) == (None,)