| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 | 
							
- import sys as _sys
 
- from keyword import iskeyword as _iskeyword
 
- def _validate_names(typename, field_names, extra_field_names):
 
-     """
 
-     Ensure that all the given names are valid Python identifiers that
 
-     do not start with '_'.  Also check that there are no duplicates
 
-     among field_names + extra_field_names.
 
-     """
 
-     for name in [typename] + field_names + extra_field_names:
 
-         if type(name) is not str:
 
-             raise TypeError('typename and all field names must be strings')
 
-         if not name.isidentifier():
 
-             raise ValueError('typename and all field names must be valid '
 
-                              f'identifiers: {name!r}')
 
-         if _iskeyword(name):
 
-             raise ValueError('typename and all field names cannot be a '
 
-                              f'keyword: {name!r}')
 
-     seen = set()
 
-     for name in field_names + extra_field_names:
 
-         if name.startswith('_'):
 
-             raise ValueError('Field names cannot start with an underscore: '
 
-                              f'{name!r}')
 
-         if name in seen:
 
-             raise ValueError(f'Duplicate field name: {name!r}')
 
-         seen.add(name)
 
- # Note: This code is adapted from CPython:Lib/collections/__init__.py
 
- def _make_tuple_bunch(typename, field_names, extra_field_names=None,
 
-                       module=None):
 
-     """
 
-     Create a namedtuple-like class with additional attributes.
 
-     This function creates a subclass of tuple that acts like a namedtuple
 
-     and that has additional attributes.
 
-     The additional attributes are listed in `extra_field_names`.  The
 
-     values assigned to these attributes are not part of the tuple.
 
-     The reason this function exists is to allow functions in SciPy
 
-     that currently return a tuple or a namedtuple to returned objects
 
-     that have additional attributes, while maintaining backwards
 
-     compatibility.
 
-     This should only be used to enhance *existing* functions in SciPy.
 
-     New functions are free to create objects as return values without
 
-     having to maintain backwards compatibility with an old tuple or
 
-     namedtuple return value.
 
-     Parameters
 
-     ----------
 
-     typename : str
 
-         The name of the type.
 
-     field_names : list of str
 
-         List of names of the values to be stored in the tuple. These names
 
-         will also be attributes of instances, so the values in the tuple
 
-         can be accessed by indexing or as attributes.  At least one name
 
-         is required.  See the Notes for additional restrictions.
 
-     extra_field_names : list of str, optional
 
-         List of names of values that will be stored as attributes of the
 
-         object.  See the notes for additional restrictions.
 
-     Returns
 
-     -------
 
-     cls : type
 
-         The new class.
 
-     Notes
 
-     -----
 
-     There are restrictions on the names that may be used in `field_names`
 
-     and `extra_field_names`:
 
-     * The names must be unique--no duplicates allowed.
 
-     * The names must be valid Python identifiers, and must not begin with
 
-       an underscore.
 
-     * The names must not be Python keywords (e.g. 'def', 'and', etc., are
 
-       not allowed).
 
-     Examples
 
-     --------
 
-     >>> from scipy._lib._bunch import _make_tuple_bunch
 
-     Create a class that acts like a namedtuple with length 2 (with field
 
-     names `x` and `y`) that will also have the attributes `w` and `beta`:
 
-     >>> Result = _make_tuple_bunch('Result', ['x', 'y'], ['w', 'beta'])
 
-     `Result` is the new class.  We call it with keyword arguments to create
 
-     a new instance with given values.
 
-     >>> result1 = Result(x=1, y=2, w=99, beta=0.5)
 
-     >>> result1
 
-     Result(x=1, y=2, w=99, beta=0.5)
 
-     `result1` acts like a tuple of length 2:
 
-     >>> len(result1)
 
-     2
 
-     >>> result1[:]
 
-     (1, 2)
 
-     The values assigned when the instance was created are available as
 
-     attributes:
 
-     >>> result1.y
 
-     2
 
-     >>> result1.beta
 
-     0.5
 
-     """
 
-     if len(field_names) == 0:
 
-         raise ValueError('field_names must contain at least one name')
 
-     if extra_field_names is None:
 
-         extra_field_names = []
 
-     _validate_names(typename, field_names, extra_field_names)
 
-     typename = _sys.intern(str(typename))
 
-     field_names = tuple(map(_sys.intern, field_names))
 
-     extra_field_names = tuple(map(_sys.intern, extra_field_names))
 
-     all_names = field_names + extra_field_names
 
-     arg_list = ', '.join(field_names)
 
-     full_list = ', '.join(all_names)
 
-     repr_fmt = ''.join(('(',
 
-                         ', '.join(f'{name}=%({name})r' for name in all_names),
 
-                         ')'))
 
-     tuple_new = tuple.__new__
 
-     _dict, _tuple, _zip = dict, tuple, zip
 
-     # Create all the named tuple methods to be added to the class namespace
 
-     s = f"""\
 
- def __new__(_cls, {arg_list}, **extra_fields):
 
-     return _tuple_new(_cls, ({arg_list},))
 
- def __init__(self, {arg_list}, **extra_fields):
 
-     for key in self._extra_fields:
 
-         if key not in extra_fields:
 
-             raise TypeError("missing keyword argument '%s'" % (key,))
 
-     for key, val in extra_fields.items():
 
-         if key not in self._extra_fields:
 
-             raise TypeError("unexpected keyword argument '%s'" % (key,))
 
-         self.__dict__[key] = val
 
- def __setattr__(self, key, val):
 
-     if key in {repr(field_names)}:
 
-         raise AttributeError("can't set attribute %r of class %r"
 
-                              % (key, self.__class__.__name__))
 
-     else:
 
-         self.__dict__[key] = val
 
- """
 
-     del arg_list
 
-     namespace = {'_tuple_new': tuple_new,
 
-                  '__builtins__': dict(TypeError=TypeError,
 
-                                       AttributeError=AttributeError),
 
-                  '__name__': f'namedtuple_{typename}'}
 
-     exec(s, namespace)
 
-     __new__ = namespace['__new__']
 
-     __new__.__doc__ = f'Create new instance of {typename}({full_list})'
 
-     __init__ = namespace['__init__']
 
-     __init__.__doc__ = f'Instantiate instance of {typename}({full_list})'
 
-     __setattr__ = namespace['__setattr__']
 
-     def __repr__(self):
 
-         'Return a nicely formatted representation string'
 
-         return self.__class__.__name__ + repr_fmt % self._asdict()
 
-     def _asdict(self):
 
-         'Return a new dict which maps field names to their values.'
 
-         out = _dict(_zip(self._fields, self))
 
-         out.update(self.__dict__)
 
-         return out
 
-     def __getnewargs_ex__(self):
 
-         'Return self as a plain tuple.  Used by copy and pickle.'
 
-         return _tuple(self), self.__dict__
 
-     # Modify function metadata to help with introspection and debugging
 
-     for method in (__new__, __repr__, _asdict, __getnewargs_ex__):
 
-         method.__qualname__ = f'{typename}.{method.__name__}'
 
-     # Build-up the class namespace dictionary
 
-     # and use type() to build the result class
 
-     class_namespace = {
 
-         '__doc__': f'{typename}({full_list})',
 
-         '_fields': field_names,
 
-         '__new__': __new__,
 
-         '__init__': __init__,
 
-         '__repr__': __repr__,
 
-         '__setattr__': __setattr__,
 
-         '_asdict': _asdict,
 
-         '_extra_fields': extra_field_names,
 
-         '__getnewargs_ex__': __getnewargs_ex__,
 
-     }
 
-     for index, name in enumerate(field_names):
 
-         def _get(self, index=index):
 
-             return self[index]
 
-         class_namespace[name] = property(_get)
 
-     for name in extra_field_names:
 
-         def _get(self, name=name):
 
-             return self.__dict__[name]
 
-         class_namespace[name] = property(_get)
 
-     result = type(typename, (tuple,), class_namespace)
 
-     # For pickling to work, the __module__ variable needs to be set to the
 
-     # frame where the named tuple is created.  Bypass this step in environments
 
-     # where sys._getframe is not defined (Jython for example) or sys._getframe
 
-     # is not defined for arguments greater than 0 (IronPython), or where the
 
-     # user has specified a particular module.
 
-     if module is None:
 
-         try:
 
-             module = _sys._getframe(1).f_globals.get('__name__', '__main__')
 
-         except (AttributeError, ValueError):
 
-             pass
 
-     if module is not None:
 
-         result.__module__ = module
 
-         __new__.__module__ = module
 
-     return result
 
 
  |