Пример #1
0
def namedtuple(typename, field_names, verbose=False, rename=False):
    if isinstance(field_names, str):
        field_names = field_names.replace(',', ' ').split()
    field_names = list(map(str, field_names))
    if rename:
        seen = set()
        for (index, name) in enumerate(field_names):
            if not name.isidentifier() or (_iskeyword(name) or name.startswith('_')) or name in seen:
                field_names[index] = '_%d' % index
            seen.add(name)
    for name in [typename] + field_names:
        if not name.isidentifier():
            raise ValueError('Type names and field names must be valid identifiers: %r' % name)
        while _iskeyword(name):
            raise ValueError('Type names and field names cannot be a keyword: %r' % name)
    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: %r' % name)
        if name in seen:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen.add(name)
    class_definition = _class_template.format(typename=typename, field_names=tuple(field_names), num_fields=len(field_names), arg_list=repr(tuple(field_names)).replace("'", '')[1:-1], repr_fmt=', '.join(_repr_template.format(name=name) for name in field_names), field_defs='\n'.join(_field_template.format(index=index, name=name) for (index, name) in enumerate(field_names)))
    namespace = dict(__name__='namedtuple_%s' % typename)
    exec(class_definition, namespace)
    result = namespace[typename]
    result._source = class_definition
    if verbose:
        print(result._source)
    try:
        result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass
    return result
Пример #2
0
def namedtuple(typename, field_names, verbose = False, rename = False):
    if isinstance(field_names, basestring):
        field_names = field_names.replace(',', ' ').split()
    field_names = tuple(map(str, field_names))
    if rename:
        names = list(field_names)
        seen = set()
        for i, name in enumerate(names):
            if not all((c.isalnum() or c == '_' for c in name)) or _iskeyword(name) or not name or name[0].isdigit() or name.startswith('_') or name in seen:
                names[i] = '_%d' % i
            seen.add(name)

        field_names = tuple(names)
    for name in (typename,) + field_names:
        if not all((c.isalnum() or c == '_' for c in name)):
            raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a keyword: %r' % name)
        if name[0].isdigit():
            raise ValueError('Type names and field names cannot start with a number: %r' % name)

    seen_names = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: %r' % name)
        if name in seen_names:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen_names.add(name)

    numfields = len(field_names)
    argtxt = repr(field_names).replace("'", '')[1:-1]
    reprtxt = ', '.join(('%s=%%r' % name for name in field_names))
    template = "class %(typename)s(tuple):\n        '%(typename)s(%(argtxt)s)' \n\n        __slots__ = () \n\n        _fields = %(field_names)r \n\n        def __new__(_cls, %(argtxt)s):\n            'Create new instance of %(typename)s(%(argtxt)s)'\n            return _tuple.__new__(_cls, (%(argtxt)s)) \n\n        @classmethod\n        def _make(cls, iterable, new=tuple.__new__, len=len):\n            'Make a new %(typename)s object from a sequence or iterable'\n            result = new(cls, iterable)\n            if len(result) != %(numfields)d:\n                raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))\n            return result \n\n        def __repr__(self):\n            'Return a nicely formatted representation string'\n            return '%(typename)s(%(reprtxt)s)' %% self \n\n        def _asdict(self):\n            'Return a new OrderedDict which maps field names to their values'\n            return OrderedDict(zip(self._fields, self)) \n\n        def _replace(_self, **kwds):\n            'Return a new %(typename)s object replacing specified fields with new values'\n            result = _self._make(map(kwds.pop, %(field_names)r, _self))\n            if kwds:\n                raise ValueError('Got unexpected field names: %%r' %% kwds.keys())\n            return result \n\n        def __getnewargs__(self):\n            'Return self as a plain tuple.  Used by copy and pickle.'\n            return tuple(self) \n\n" % locals()
    for i, name in enumerate(field_names):
        template += "        %s = _property(_itemgetter(%d), doc='Alias for field number %d')\n" % (name, i, i)

    if verbose:
        print template
    namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename, OrderedDict=OrderedDict, _property=property, _tuple=tuple)
    try:
        exec template in namespace
    except SyntaxError as e:
        raise SyntaxError(e.message + ':\n' + template)

    result = namespace[typename]
    try:
        result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass

    return result
Пример #3
0
def namedtuple(typename, field_names, *, verbose=False, rename=False, module=None):
    """Returns a new subclass of tuple with named fields.

    >>> Point = namedtuple('Point', ['x', 'y'])
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessible by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)

    """

    # Validate the field names.  At the user's option, either generate an error
    # message or automatically replace the field name with a valid name.
    if isinstance(field_names, str):
        field_names = field_names.replace(',', ' ').split()
    field_names = list(map(str, field_names))
    typename = str(typename)
    if rename:
        seen = set()
        for index, name in enumerate(field_names):
            if (not name.isidentifier()
                or _iskeyword(name)
                or name.startswith('_')
                or name in seen):
                field_names[index] = '_%d' % index
            seen.add(name)
    for name in [typename] + field_names:
        if type(name) is not str:
            raise TypeError('Type names and field names must be strings')
        if not name.isidentifier():
            raise ValueError('Type names and field names must be valid '
                             'identifiers: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a '
                             'keyword: %r' % name)
Пример #4
0
    def namedtuple(typename, field_names, verbose=False):
        # Parse and validate the field names.  Validation serves two purposes,
        # generating informative error messages and preventing template injection attacks.
        if isinstance(field_names, basestring):
            field_names = field_names.replace(',', ' ').split() # names separated by whitespace and/or commas
        field_names = tuple(field_names)
        for name in (typename,) + field_names:
            if not all(c.isalnum() or c=='_' for c in name):
                raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name)
            if _iskeyword(name):
                raise ValueError('Type names and field names cannot be a keyword: %r' % name)
            if name[0].isdigit():
                raise ValueError('Type names and field names cannot start with a number: %r' % name)
        seen_names = set()
        for name in field_names:
            if name.startswith('_'):
                raise ValueError('Field names cannot start with an underscore: %r' % name)
            if name in seen_names:
                raise ValueError('Encountered duplicate field name: %r' % name)
            seen_names.add(name)

        # Create and fill-in the class template
        numfields = len(field_names)
        argtxt = repr(field_names).replace("'", "")[1:-1]   # tuple repr without parens or quotes
        reprtxt = ', '.join('%s=%%r' % name for name in field_names)
        dicttxt = ', '.join('%r: t[%d]' % (name, pos) for pos, name in enumerate(field_names))
        template = '''class %(typename)s(tuple):
        '%(typename)s(%(argtxt)s)' \n
        __slots__ = () \n
        _fields = %(field_names)r \n
        def __new__(cls, %(argtxt)s):
            return tuple.__new__(cls, (%(argtxt)s)) \n
        @classmethod
        def _make(cls, iterable, new=tuple.__new__, len=len):
            'Make a new %(typename)s object from a sequence or iterable'
            result = new(cls, iterable)
            if len(result) != %(numfields)d:
                raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
            return result \n
        def __repr__(self):
            return '%(typename)s(%(reprtxt)s)' %% self \n
        def _asdict(t):
            'Return a new dict which maps field names to their values'
            return {%(dicttxt)s} \n
        def _replace(self, **kwds):
            'Return a new %(typename)s object replacing specified fields with new values'
            result = self._make(map(kwds.pop, %(field_names)r, self))
            if kwds:
                raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
            return result \n\n''' % locals()
        for i, name in enumerate(field_names):
            template += '        %s = property(itemgetter(%d))\n' % (name, i)
        if verbose:
            print template
        # Execute the template string in a temporary namespace
        namespace = dict(itemgetter=_itemgetter)
        try:
            exec template in namespace
        except SyntaxError, e:
            raise SyntaxError(e.message + ':\n' + template)
Пример #5
0
    def getPymelEnums(self, enumDict):
        """remove all common prefixes from list of enum values"""
        if len(enumDict) > 1:
            enumList = enumDict.keys()
            splitEnums = [ [ y for y in re.split( '([A-Z0-9][a-z0-9]*)', x ) if y ] for x in enumList ]
            splitEnumsCopy = splitEnums[:]
            for partList in zip( *splitEnumsCopy ):
                if  tuple([partList[0]]*len(partList)) == partList:
                    [ x.pop(0) for x in splitEnums ]
                else: break
            joinedEnums = [ util.uncapitalize(''.join(x), preserveAcronymns=True ) for x in splitEnums]
            for i, enum in enumerate(joinedEnums):
                if _iskeyword(enum):
                    joinedEnums[i] = enum+'_'
                    self.xprint( "bad enum", enum )
                elif enum[0].isdigit():
                    joinedEnums[i] = 'k' + enum
                    self.xprint( "bad enum", enum )

                    #print joinedEnums
                    #print enumList
                    #break

            pymelEnumDict = dict( [ (k2,enumDict[k1]) for k1, k2 in zip( enumList, joinedEnums ) ] )

            #print "enums", joinedEnums
            return pymelEnumDict

        return enumDict
Пример #6
0
def create_struct_class(field_names):
    # type: (Iterable[str]) -> Type

    field_names = tuple(field_names)
    struct_class = _CLASS_CACHE.get(field_names)
    if struct_class:
        return struct_class

    # Variables used in the methods and docstrings

    for name in field_names:
        if not all(c.isalnum() or c == "_" for c in name):
            raise ValueError(
                "Field names can only contain alphanumeric characters and underscores: %r"
                % name
            )
        if _iskeyword(name):
            raise ValueError("Field names cannot be a keyword: %r" % name)
        if name[0].isdigit():
            raise ValueError("Field names cannot start with a number: %r" % name)

    arg_list = repr(field_names).replace("'", "")[1:-1]
    tuple_new = tuple.__new__

    # Create all the named tuple methods to be added to the class namespace

    s = (
        "def __new__(_cls, "
        + arg_list
        + "): return _tuple_new(_cls, ("
        + arg_list
        + "))"
    )
    namespace = {"_tuple_new": tuple_new, "__name__": _TYPENAME}
    # Note: exec() has the side-effect of interning the field names
    exec(s, namespace)
    __new__ = namespace["__new__"]

    # Build-up the class namespace dictionary
    # and use type() to build the result class
    class_namespace = {
        "__slots__": (),
        "_fields": field_names,
        "__new__": __new__,
        "__repr__": _create_struct_repr(field_names),
        "_asdict": _asdict,
        "to_json": _to_json,
    }
    cache = _nt_itemgetters
    for index, name in enumerate(field_names):
        try:
            itemgetter_object = cache[index]
        except KeyError:
            itemgetter_object = _itemgetter(index)
            cache[index] = itemgetter_object
        class_namespace[name] = property(itemgetter_object)

    struct_class = type(_TYPENAME, (tuple,), class_namespace)
    _CLASS_CACHE[field_names] = struct_class
    return struct_class
Пример #7
0
def _validate_fields(field_names: list[str]) -> list[str]:
    """
    Validate the given field names
    
    Args:
        field_names: a list of strings to be used as attributes.
    
    Example
    =======

    .. code::
    
        # Numbers are not valid identifiers
        # an object cannot have non-unique attributes
        >>> _validate_fields(["0", "field", "field"])
        ['_0', 'field', '_2']

    """
    names = list(map(str, list(field_names)))
    seen = set()
    for i, name in enumerate(names):
        if (not all(c.isalnum() or c == "_" for c in name) or _iskeyword(name)
                or not name or name[0].isdigit() or name.startswith("_")
                or name in seen):
            names[i] = "field%d" % i
        seen.add(name)
    return names
Пример #8
0
def namedtuple(typename, field_names, verbose=False):
    """Returns a new subclass of tuple with named fields.

    >>> Point = namedtuple('Point', 'x y')
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessable by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)

    """
    # Parse and validate the field names.  Validation serves two purposes,
    # generating informative error messages and preventing template injection attacks.
    if isinstance(field_names, basestring):
        # names separated by whitespace and/or commas
        field_names = field_names.replace(',', ' ').split() 
    field_names = list(field_names)
    seen_names = set()
    for name in [typename] + field_names:
        if not all(c.isalnum() or c=='_' for c in name):
            raise ValueError('Names can only contain alphanumeric characters and underscores: %r' % name)
        if _iskeyword(name):
            raise ValueError('Encountered duplicate field name: %r' % name)
        if name[0].isdigit():
            raise ValueError('Type names and field names cannot start with a number: %r' % name)
        seen_names.add(name)
    name_to_field = dict((v, idx) for idx, v in (enumerate(field_names)))
    attributes = {'_field_names' : name_to_field,
                  '_fields' : tuple(field_names),
                  # immutable and we need it often
                  '_field_len' : len(field_names),
                  '__slots__' : (),
                  '__doc__': "%s(%s)" % (typename, ', '.join(field_names))}
    # create properties
    for attr, idx in name_to_field.iteritems():
        attributes[attr] = property(_itemgetter(idx))
    if verbose:
        print attributes
    # create the new class, deriving from _NamedTuple
    result = type(typename, (_NamedTuple,), attributes) 
    # For pickling to work, the __module__ variable needs to be set to the frame
    # where the named tuple is created.  Bypass this step in enviroments where
    # sys._getframe is not defined (Jython for example).
    if hasattr(_sys, '_getframe'):
        result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
    return result
Пример #9
0
def _auto_positive_symbol(tokens, local_dict, global_dict):
    """
    Inserts calls to ``Symbol`` for undefined variables.
    Passes in positive=True as a keyword argument.
    Adapted from sympy.sympy.parsing.sympy_parser.auto_symbol
    """
    result = []
    prevTok = (None, None)

    tokens.append((None, None))  # so zip traverses all tokens
    for tok, nextTok in zip(tokens, tokens[1:]):
        tokNum, tokVal = tok
        nextTokNum, nextTokVal = nextTok
        if tokNum == token.NAME:
            name = tokVal
            if (name in ["True", "False", "None"]
                    # special case 'as' for attosecond
                    or (_iskeyword(name) and name != "as") or
                    name in local_dict
                    # Don't convert attribute access
                    or (prevTok[0] == token.OP and prevTok[1] == ".")
                    # Don't convert keyword arguments
                    or (prevTok[0] == token.OP and prevTok[1] in ("(", ",")
                        and nextTokNum == token.OP and nextTokVal == "=")):
                result.append((token.NAME, name))
                continue
            elif name in global_dict:
                obj = global_dict[name]
                if isinstance(obj, (Basic, type)) or callable(obj):
                    result.append((token.NAME, name))
                    continue

            # try to resolve known alternative unit name
            try:
                used_name = inv_name_alternatives[str(name)]
            except KeyError:
                # if we don't know this name it's a user-defined unit name
                # so we should create a new symbol for it
                used_name = str(name)

            result.extend([
                (token.NAME, "Symbol"),
                (token.OP, "("),
                (token.NAME, repr(used_name)),
                (token.OP, ","),
                (token.NAME, "positive"),
                (token.OP, "="),
                (token.NAME, "True"),
                (token.OP, ")"),
            ])
        else:
            result.append((tokNum, tokVal))

        prevTok = (tokNum, tokVal)

    return result
Пример #10
0
def is_qualifiable(symbol):
    """Determines if symbol can be qualified with a module.

    Can't be ``quote``, ``__import__``, any Python reserved word, an
    auto-gensym, already qualified, method syntax, or a module literal;
    and must be a valid identifier or attribute identifier.
    """
    return (symbol not in {"quote", "__import__"} and not _iskeyword(symbol)
            and not re.match(r".*_QzNo\d+_$", symbol)
            and all(map(str.isidentifier, symbol.split("."))))
Пример #11
0
def check_name(name):
    if not isinstance(name, str):
        raise TypeError('Type names and field names must be strings')
    if not _isidentifier(name):
        raise ValueError('Type names and field names must be valid '
                         'identifiers: %r' % name)
    if _iskeyword(name):
        raise ValueError('Type names and field names cannot be a '
                         'keyword: %r' % name)
    return name
Пример #12
0
def namedtuple(typename, field_names, verbose=False, rename=False):
    if isinstance(field_names, basestring):
        field_names = field_names.replace(',', ' ').split()
    field_names = map(str, field_names)
    if rename:
        seen = set()
        for index, name in enumerate(field_names):
            if not all((c.isalnum() or c == '_' for c in name)) or _iskeyword(name) or not name or name[0].isdigit() or name.startswith('_') or name in seen:
                field_names[index] = '_%d' % index
            seen.add(name)

    for name in [typename] + field_names:
        if not all((c.isalnum() or c == '_' for c in name)):
            raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a keyword: %r' % name)
        if name[0].isdigit():
            raise ValueError('Type names and field names cannot start with a number: %r' % name)

    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: %r' % name)
        if name in seen:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen.add(name)

    class_definition = _class_template.format(typename=typename, field_names=tuple(field_names), num_fields=len(field_names), arg_list=repr(tuple(field_names)).replace("'", '')[1:-1], repr_fmt=(', ').join((_repr_template.format(name=name) for name in field_names)), field_defs=('\n').join((_field_template.format(index=index, name=name) for index, name in enumerate(field_names))))
    if verbose:
        print class_definition
    namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename, OrderedDict=OrderedDict, _property=property, _tuple=tuple)
    try:
        exec class_definition in namespace
    except SyntaxError as e:
        raise SyntaxError(e.message + ':\n' + class_definition)

    result = namespace[typename]
    try:
        result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass

    return result
Пример #13
0
def create_struct_class(field_names):
    # type: (Iterable[str]) -> Type

    field_names = tuple(field_names)
    struct_class = _CLASS_CACHE.get(field_names)
    if struct_class:
        return struct_class

    # Variables used in the methods and docstrings

    for name in field_names:
        if not all(c.isalnum() or c == "_" for c in name):
            raise ValueError(
                "Field names can only contain alphanumeric characters and underscores: %r"
                % name)
        if _iskeyword(name):
            raise ValueError("Field names cannot be a keyword: %r" % name)
        if name[0].isdigit():
            raise ValueError("Field names cannot start with a number: %r" %
                             name)

    arg_list = repr(field_names).replace("'", "")[1:-1]
    tuple_new = tuple.__new__

    # Create all the named tuple methods to be added to the class namespace

    s = ("def __new__(_cls, " + arg_list + "): return _tuple_new(_cls, (" +
         arg_list + "))")
    namespace = {"_tuple_new": tuple_new, "__name__": _TYPENAME}
    # Note: exec() has the side-effect of interning the field names
    exec(s, namespace)
    __new__ = namespace["__new__"]

    # Build-up the class namespace dictionary
    # and use type() to build the result class
    class_namespace = {
        "__slots__": (),
        "_fields": field_names,
        "__new__": __new__,
        "__repr__": _create_struct_repr(field_names),
        "_asdict": _asdict,
        "to_json": _to_json,
    }
    cache = _nt_itemgetters
    for index, name in enumerate(field_names):
        try:
            itemgetter_object = cache[index]
        except KeyError:
            itemgetter_object = _itemgetter(index)
            cache[index] = itemgetter_object
        class_namespace[name] = property(itemgetter_object)

    struct_class = type(_TYPENAME, (tuple, ), class_namespace)
    _CLASS_CACHE[field_names] = struct_class
    return struct_class
Пример #14
0
 def _validate_name(n):
   if type(n) != str:
     raise TypeError("struct/field name is not a str: {!r}".format(n))
   if not n.isidentifier():
     raise _ValErrF("struct/field name is not a valid identifier: {!r}", n)
   if _iskeyword(n):
     raise ValErrF("struct/field name cannot be a keyword: {!r}", n)
   if n.startswith('__'):
     raise ValErrF("struct/field name cannot begin with '__': {!r}", n)
   if n in _reserved_names:
     raise ValErrF("struct/field name is reserved: {!r}", n)
Пример #15
0
    def getPymelEnums(self, enumDict):
        """remove all common prefixes from list of enum values"""
        if len(enumDict) > 1:
            enumList = enumDict.keys()
            capitalizedRe = re.compile('([A-Z0-9][a-z0-9]*)')

            # We first aim to remove all similar 'camel-case-group' prefixes, ie:
            # if our enums look like:
            #    kFooBar
            #    kFooSomeThing
            #    kFooBunnies
            # we want to get Bar, SomeThing, Bunnies

            # {'kFooBar':0, 'kFooSomeThing':1}
            #     => [['k', 'Foo', 'Some', 'Thing'], ['k', 'Foo', 'Bar']]
            splitEnums = [[y for y in capitalizedRe.split(x) if y]
                          for x in enumList]

            # [['k', 'Invalid'], ['k', 'Pre', 'Transform']]
            #     => [('k', 'k'), ('Foo', 'Foo'), ('Some', 'Bar')]
            splitZip = zip(*splitEnums)
            for partList in splitZip:
                if tuple([partList[0]] * len(partList)) == partList:
                    [x.pop(0) for x in splitEnums]
                else:
                    break
            # splitEnums == [['Some', 'Thing'], ['Bar']]

            joinedEnums = [
                util.uncapitalize(''.join(x), preserveAcronymns=True)
                for x in splitEnums
            ]
            for i, enum in enumerate(joinedEnums):
                if _iskeyword(enum):
                    joinedEnums[i] = enum + '_'
                    self.xprint("bad enum", enum)
                elif enum[0].isdigit():
                    joinedEnums[i] = 'k' + enum
                    self.xprint("bad enum", enum)

                    #print joinedEnums
                    #print enumList
                    #break

            pymelEnumDict = dict((new, enumDict[orig])
                                 for orig, new in zip(enumList, joinedEnums))

            #print "enums", joinedEnums
            return pymelEnumDict

        return enumDict
Пример #16
0
def _generate(name):
    """
    Generate a new variable in the caller's locals. Test if the variable name is valid.
    """
    _locals = _stack()[2][0].f_locals
    if _iskeyword(name):
        raise ValueError("cannot name variable '{}' because it is a Python keyword".format(name))
    if name in _builtins:
        raise ValueError("cannot name variable '{}' because it is a Python builtin".format(name))
    if name in _locals:
        raise ValueError("cannot name variable '{}' because that name is already in use".format(name))
    if not name.isidentifier():
        raise ValueError("cannot name variable '{}' because it is an invalid Python variable name".format(name))
    _locals[name] = _df[name]
Пример #17
0
def _check_name(name):
  err_id = 'Type names and field names'
  if not isinstance(name, _six.string_types):
    raise ValueError('{} must be a string (type: {!r}): '
                     '{!r}'.format(err_id, type(name), name))
  if not name:
    raise ValueError('{} cannot be empty.'.format(err_id))
  if not all(c.isalnum() or c=='_' for c in name):
    raise ValueError('{} can only contain alphanumerics and underscores: '
                     '{!r}'.format(err_id, name))
  if _iskeyword(name):
    raise ValueError('{} cannot be a keyword: {!r}'.format(err_id, name))
  if name[0].isdigit():
    raise ValueError('{} cannot start with a number: '
                     '{!r}'.format(err_id, name))
Пример #18
0
def _auto_positive_symbol(tokens, local_dict, global_dict):
    """
    Inserts calls to ``Symbol`` for undefined variables.
    Passes in positive=True as a keyword argument.
    Adapted from sympy.sympy.parsing.sympy_parser.auto_symbol
    """
    result = []
    prevTok = (None, None)

    tokens.append((None, None))  # so zip traverses all tokens
    for tok, nextTok in zip(tokens, tokens[1:]):
        tokNum, tokVal = tok
        nextTokNum, nextTokVal = nextTok
        if tokNum == token.NAME:
            name = tokVal

            if (name in ['True', 'False', 'None']
                or _iskeyword(name)
                or name in local_dict
                # Don't convert attribute access
                or (prevTok[0] == token.OP and prevTok[1] == '.')
                # Don't convert keyword arguments
                or (prevTok[0] == token.OP and prevTok[1] in ('(', ',')
                    and nextTokNum == token.OP and nextTokVal == '=')):
                result.append((token.NAME, name))
                continue
            elif name in global_dict:
                obj = global_dict[name]
                if isinstance(obj, (Basic, type)) or callable(obj):
                    result.append((token.NAME, name))
                    continue

            result.extend([
                (token.NAME, 'Symbol'),
                (token.OP, '('),
                (token.NAME, repr(str(name))),
                (token.OP, ','),
                (token.NAME, 'positive'),
                (token.OP, '='),
                (token.NAME, 'True'),
                (token.OP, ')'),
            ])
        else:
            result.append((tokNum, tokVal))

        prevTok = (tokNum, tokVal)

    return result
Пример #19
0
    def getPymelEnums(self, enumDict):
        """remove all common prefixes from list of enum values"""
        if len(enumDict) > 1:
            enumList = enumDict.keys()
            capitalizedRe =  re.compile('([A-Z0-9][a-z0-9]*)')
            
            # We first aim to remove all similar 'camel-case-group' prefixes, ie:
            # if our enums look like:
            #    kFooBar
            #    kFooSomeThing
            #    kFooBunnies
            # we want to get Bar, SomeThing, Bunnies
            
            # {'kFooBar':0, 'kFooSomeThing':1} 
            #     => [['k', 'Foo', 'Some', 'Thing'], ['k', 'Foo', 'Bar']]
            splitEnums = [ [ y for y in capitalizedRe.split( x ) if y ] for x in enumList ]
            
            # [['k', 'Invalid'], ['k', 'Pre', 'Transform']]
            #     => [('k', 'k'), ('Foo', 'Foo'), ('Some', 'Bar')]
            splitZip = zip( *splitEnums )
            for partList in splitZip:
                if  tuple([partList[0]]*len(partList)) == partList:
                    [ x.pop(0) for x in splitEnums ]
                else: break
            # splitEnums == [['Some', 'Thing'], ['Bar']]    
            
            joinedEnums = [ util.uncapitalize(''.join(x), preserveAcronymns=True ) for x in splitEnums]
            for i, enum in enumerate(joinedEnums):
                if _iskeyword(enum):
                    joinedEnums[i] = enum+'_'
                    self.xprint( "bad enum", enum )
                elif enum[0].isdigit():
                    joinedEnums[i] = 'k' + enum
                    self.xprint( "bad enum", enum )

                    #print joinedEnums
                    #print enumList
                    #break

            pymelEnumDict = dict( (new,enumDict[orig]) for orig, new in zip( enumList, joinedEnums ) )

            #print "enums", joinedEnums
            return pymelEnumDict

        return enumDict
Пример #20
0
def nameddict(typename, field_names):
    """ """

    if isinstance(field_names, str):
        field_names = field_names.replace(',', ' ').split()
    field_names = list(map(str, field_names))

    for name in [typename] + field_names:
        if not name.isidentifier():
            raise ValueError('Type names and field names must be valid '
                             'identifiers: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a '
                             'keyword: %r' % name)

    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: '
                             '%r' % name)
        if name in seen:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen.add(name)

    # Fill-in the class template
    class_definition = _nameddict_class_tmpl.format(
        typename=typename,
        field_names=tuple(field_names),
        arg_list=','.join(field_names),
    )

    namespace = dict(__name__='nameddict_%s' % typename,
                     _OrderedDict=_OrderedDict,
                     NamedDict=NamedDict)
    exec(class_definition, namespace)
    result = namespace[typename]

    try:
        result.__module__ = _sys._getframe(1).f_globals.get(
            '__name__', '__main__')
    except (AttributeError, ValueError):
        pass

    return result
Пример #21
0
def nameddict(typename, field_names):
    """ """

    if isinstance(field_names, str):
        field_names = field_names.replace(',', ' ').split()
    field_names = list(map(str, field_names))


    for name in [typename] + field_names:
        if not name.isidentifier():
            raise ValueError('Type names and field names must be valid '
                             'identifiers: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a '
                             'keyword: %r' % name)

    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: '
                             '%r' % name)
        if name in seen:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen.add(name)

    # Fill-in the class template
    class_definition = _nameddict_class_tmpl.format(
        typename    = typename,
        field_names = tuple(field_names),
        arg_list    = ','.join(field_names),
    )

    namespace = dict(__name__='nameddict_%s' % typename,
        _OrderedDict=_OrderedDict,
        NamedDict=NamedDict)
    exec(class_definition, namespace)
    result = namespace[typename]

    try:
        result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass

    return result
Пример #22
0
    def _apiEnumNamesToPymelEnumNames(self, apiEnumNames):
        """remove all common prefixes from list of enum values"""
        if isinstance(apiEnumNames, util.Enum):
            apiEnumNames = apiEnumNames._keys.keys()
        if len(apiEnumNames) > 1:
            # We first aim to remove all similar 'camel-case-group' prefixes, ie:
            # if our enums look like:
            #    kFooBar
            #    kFooSomeThing
            #    kFooBunnies
            # we want to get Bar, SomeThing, Bunnies

            # {'kFooBar':0, 'kFooSomeThing':1}
            #     => [['k', 'Foo', 'Some', 'Thing'], ['k', 'Foo', 'Bar']]
            splitEnums = [ [ y for y in self._capitalizedRe.split( x ) if y ] for x in apiEnumNames ]

            # [['k', 'Invalid'], ['k', 'Pre', 'Transform']]
            #     => [('k', 'k'), ('Foo', 'Foo'), ('Some', 'Bar')]
            splitZip = zip( *splitEnums )
            for partList in splitZip:
                if  tuple([partList[0]]*len(partList)) == partList:
                    [ x.pop(0) for x in splitEnums ]
                else: break
            # splitEnums == [['Some', 'Thing'], ['Bar']]

            joinedEnums = [ util.uncapitalize(''.join(x), preserveAcronymns=True ) for x in splitEnums]
            for i, enum in enumerate(joinedEnums):
                if _iskeyword(enum):
                    joinedEnums[i] = enum+'_'
                    self.xprint( "bad enum", enum )
                elif enum[0].isdigit():
                    joinedEnums[i] = 'k' + enum
                    self.xprint( "bad enum", enum )

                    #print joinedEnums
                    #print enumList
                    #break

            return dict(zip(apiEnumNames, joinedEnums))
        else:
            # if only 1 name or less, name is unaltered
            return dict((name, name) for name in apiEnumNames)
Пример #23
0
def check_fields(typename, fields):
    if isinstance(fields, str):
        fields = fields.split()
    elif isinstance(fields, tuple):
        fields = list(fields)

    if isinstance(fields, list):
        fields = [fn.strip() for fn in fields]
        n_fields = len(fields)

        for name in [typename] + fields:
            if not isinstance(name, str):
                raise TypeError('Type names and field names must be strings')
            if not _isidentifier(name):
                raise ValueError('Type names and field names must be valid '
                                 'identifiers: %r' % name)
            if _iskeyword(name):
                raise ValueError('Type names and field names cannot be a '
                                 'keyword: %r' % name)
    return fields
Пример #24
0
 def _check_common(self, name, type_of_name):
     # tests that are common to both field names and the type name
     if len(name) == 0:
         raise ValueError('{0} names cannot be zero '
                          'length: {1!r}'.format(type_of_name, name))
     if _PY2:
         if not all(c.isalnum() or c=='_' for c in name):
             raise ValueError('{0} names can only contain '
                              'alphanumeric characters and underscores: '
                              '{1!r}'.format(type_of_name, name))
         if name[0].isdigit():
             raise ValueError('{0} names cannot start with a '
                              'number: {1!r}'.format(type_of_name, name))
     else:
         if not name.isidentifier():
             raise ValueError('{0} names names must be valid '
                              'identifiers: {1!r}'.format(type_of_name, name))
     if _iskeyword(name):
         raise ValueError('{0} names cannot be a keyword: '
                          '{1!r}'.format(type_of_name, name))
Пример #25
0
 def _check_common(self, name, type_of_name):
     # tests that are common to both field names and the type name
     if len(name) == 0:
         raise ValueError('{0} names cannot be zero '
                          'length: {1!r}'.format(type_of_name, name))
     if _PY2:
         if not all(c.isalnum() or c=='_' for c in name):
             raise ValueError('{0} names can only contain '
                              'alphanumeric characters and underscores: '
                              '{1!r}'.format(type_of_name, name))
         if name[0].isdigit():
             raise ValueError('{0} names cannot start with a '
                              'number: {1!r}'.format(type_of_name, name))
     else:
         if not name.isidentifier():
             raise ValueError('{0} names names must be valid '
                              'identifiers: {1!r}'.format(type_of_name, name))
     if _iskeyword(name):
         raise ValueError('{0} names cannot be a keyword: '
                          '{1!r}'.format(type_of_name, name))
Пример #26
0
def check_fields(typename, fields):
    if isinstance(fields, str):
        fields = fields.split()
    elif isinstance(fields, tuple):
        fields = list(fields)

    if isinstance(fields, list):
        fields = [fn.strip() for fn in fields]
        n_fields = len(fields)

        for name in [typename] + fields:
            if not isinstance(name, str):
                raise TypeError('Type names and field names must be strings')
            if not _isidentifier(name):
                raise ValueError('Type names and field names must be valid '
                                 'identifiers: %r' % name)
            if _iskeyword(name):
                raise ValueError('Type names and field names cannot be a '
                                 'keyword: %r' % name)
    return fields
Пример #27
0
def _check_name(name):
    """Check type or field name is valid.

    Returns an error message if name is not valid, otherwise the
    empty string.
    """
    if not name:
        err = "names must not be empty"
    elif name[0].isdigit():
        err = "name '%s' cannot start with a digit" % name
    elif name.startswith('_'):
        err = "name '%s' cannot start with an underscore" % name
    elif not all(c.isalnum() or c == '_' for c in name):
        err = ("name '%s' must only contain alphanumeric characters"
               " and underscores" % name)
    elif _iskeyword(name):
        err = "name '%s' is a reserved keyword" % name
    else:
        err = ""
    return err
Пример #28
0
def _check_name(name, is_type_name=False, seen_names=None):
    if len(name) == 0:
        raise ValueError("Type names and field names cannot be zero " "length: {0!r}".format(name))
    if not all(c.isalnum() or c == "_" for c in name):
        raise ValueError(
            "Type names and field names can only contain "
            "alphanumeric characters and underscores: "
            "{0!r}".format(name)
        )
    if _iskeyword(name):
        raise ValueError("Type names and field names cannot be a keyword: " "{0!r}".format(name))
    if name[0].isdigit():
        raise ValueError("Type names and field names cannot start with a " "number: {0!r}".format(name))

    if not is_type_name:
        # these tests don't apply for the typename, just the fieldnames
        if name in seen_names:
            raise ValueError("Encountered duplicate field name: " "{0!r}".format(name))

        if name.startswith("_"):
            raise ValueError("Field names cannot start with an underscore: " "{0!r}".format(name))
Пример #29
0
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)
Пример #30
0
def _check_name(name, is_type_name=False, seen_names=None):
    if len(name) == 0:
        raise ValueError("Type names and field names cannot be zero "
                         "length: {0!r}".format(name))
    if not all(c.isalnum() or c == "_" for c in name):
        raise ValueError("Type names and field names can only contain "
                         "alphanumeric characters and underscores: "
                         "{0!r}".format(name))
    if _iskeyword(name):
        raise ValueError("Type names and field names cannot be a keyword: "
                         "{0!r}".format(name))
    if name[0].isdigit():
        raise ValueError("Type names and field names cannot start with a "
                         "number: {0!r}".format(name))

    if not is_type_name:
        # these tests don't apply for the typename, just the fieldnames
        if name in seen_names:
            raise ValueError("Encountered duplicate field name: "
                             "{0!r}".format(name))

        if name.startswith("_"):
            raise ValueError("Field names cannot start with an underscore: "
                             "{0!r}".format(name))
Пример #31
0
def namedtuple(typename,
               field_names,
               *,
               verbose=False,
               rename=False,
               module=None):
    """Returns a new subclass of tuple with named fields.

    >>> Point = namedtuple('Point', ['x', 'y'])
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessible by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)

    """

    # Validate the field names.  At the user's option, either generate an error
    # message or automatically replace the field name with a valid name.
    if isinstance(field_names, str):
        field_names = field_names.replace(',', ' ').split()
    field_names = list(map(str, field_names))
    typename = str(typename)
    if rename:
        seen = set()
        for index, name in enumerate(field_names):
            if (not name.isidentifier() or _iskeyword(name)
                    or name.startswith('_') or name in seen):
                field_names[index] = '_%d' % index
            seen.add(name)
    for name in [typename] + field_names:
        if type(name) is not str:
            raise TypeError('Type names and field names must be strings')
        if not name.isidentifier():
            raise ValueError('Type names and field names must be valid '
                             'identifiers: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a '
                             'keyword: %r' % name)
    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: '
                             '%r' % name)
        if name in seen:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen.add(name)

    # Fill-in the class template
    class_definition = _class_template.format(
        typename=typename,
        field_names=tuple(field_names),
        num_fields=len(field_names),
        arg_list=repr(tuple(field_names)).replace("'", "")[1:-1],
        repr_fmt=', '.join(
            _repr_template.format(name=name) for name in field_names),
        field_defs='\n'.join(
            _field_template.format(index=index, name=name)
            for index, name in enumerate(field_names)))

    # Execute the template string in a temporary namespace and support
    # tracing utilities by setting a value for frame.f_globals['__name__']
    namespace = dict(__name__='namedtuple_%s' % typename)
    exec(class_definition, namespace)
    result = namespace[typename]
    result._source = class_definition
    if verbose:
        print(result._source)

    # 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

    return result
def namedtuple(typename, field_names, verbose=False, rename=False):
    """Returns a new subclass of tuple with named fields.
    
    >>> Point = namedtuple('Point', ['x', 'y'])
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessible by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)
    
    """
    if isinstance(field_names, basestring):
        field_names = field_names.replace(',', ' ').split()
    field_names = map(str, field_names)
    typename = str(typename)
    if rename:
        seen = set()
        for index, name in enumerate(field_names):
            if not all((c.isalnum() or c == '_' for c in name)) or _iskeyword(name) or not name or name[0].isdigit() or name.startswith('_') or name in seen:
                field_names[index] = '_%d' % index
            seen.add(name)

    for name in [typename] + field_names:
        if type(name) != str:
            raise TypeError('Type names and field names must be strings')
        if not all((c.isalnum() or c == '_' for c in name)):
            raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a keyword: %r' % name)
        if name[0].isdigit():
            raise ValueError('Type names and field names cannot start with a number: %r' % name)

    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: %r' % name)
        if name in seen:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen.add(name)

    class_definition = _class_template.format(typename=typename, field_names=tuple(field_names), num_fields=len(field_names), arg_list=repr(tuple(field_names)).replace("'", '')[1:-1], repr_fmt=(', ').join((_repr_template.format(name=name) for name in field_names)), field_defs=('\n').join((_field_template.format(index=index, name=name) for index, name in enumerate(field_names))))
    if verbose:
        print class_definition
    namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename, OrderedDict=OrderedDict, _property=property, _tuple=tuple)
    try:
        exec class_definition in namespace
    except SyntaxError as e:
        raise SyntaxError(e.message + ':\n' + class_definition)

    result = namespace[typename]
    try:
        result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass

    return result
Пример #33
0
    def namedtuple(typename, field_names, verbose=False, rename=False):
        """A collections.namedtuple implementation written in Python
        to support Python versions < 2.6.

        Taken from: http://code.activestate.com/recipes/500261/
        """
        # Parse and validate the field names.  Validation serves two
        # purposes, generating informative error messages and preventing
        # template injection attacks.
        if isinstance(field_names, basestring):
            # names separated by whitespace and/or commas
            field_names = field_names.replace(',', ' ').split()
        field_names = tuple(map(str, field_names))
        if rename:
            names = list(field_names)
            seen = set()
            for i, name in enumerate(names):
                if (not min(c.isalnum() or c == '_' for c in name)
                        or _iskeyword(name) or not name or name[0].isdigit()
                        or name.startswith('_') or name in seen):
                    names[i] = '_%d' % i
                seen.add(name)
            field_names = tuple(names)
        for name in (typename, ) + field_names:
            if not min(c.isalnum() or c == '_' for c in name):
                raise ValueError('Type names and field names can only contain ' \
                                 'alphanumeric characters and underscores: %r'
                                 % name)
            if _iskeyword(name):
                raise ValueError('Type names and field names cannot be a keyword: %r' \
                                 % name)
            if name[0].isdigit():
                raise ValueError('Type names and field names cannot start with a ' \
                                 'number: %r' % name)
        seen_names = set()
        for name in field_names:
            if name.startswith('_') and not rename:
                raise ValueError(
                    'Field names cannot start with an underscore: %r' % name)
            if name in seen_names:
                raise ValueError('Encountered duplicate field name: %r' % name)
            seen_names.add(name)

        # Create and fill-in the class template
        numfields = len(field_names)
        # tuple repr without parens or quotes
        argtxt = repr(field_names).replace("'", "")[1:-1]
        reprtxt = ', '.join('%s=%%r' % name for name in field_names)
        template = '''class %(typename)s(tuple):
        '%(typename)s(%(argtxt)s)' \n
        __slots__ = () \n
        _fields = %(field_names)r \n
        def __new__(_cls, %(argtxt)s):
            return _tuple.__new__(_cls, (%(argtxt)s)) \n
        @classmethod
        def _make(cls, iterable, new=tuple.__new__, len=len):
            'Make a new %(typename)s object from a sequence or iterable'
            result = new(cls, iterable)
            if len(result) != %(numfields)d:
                raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
            return result \n
        def __repr__(self):
            return '%(typename)s(%(reprtxt)s)' %% self \n
        def _asdict(self):
            'Return a new dict which maps field names to their values'
            return dict(zip(self._fields, self)) \n
        def _replace(_self, **kwds):
            'Return a new %(typename)s object replacing specified fields with new values'
            result = _self._make(map(kwds.pop, %(field_names)r, _self))
            if kwds:
                raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
            return result \n
        def __getnewargs__(self):
            return tuple(self) \n\n''' % locals()
        for i, name in enumerate(field_names):
            template += '        %s = _property(_itemgetter(%d))\n' % (name, i)
        if verbose:
            sys.stdout.write(template + '\n')
            sys.stdout.flush()

        # Execute the template string in a temporary namespace
        namespace = dict(_itemgetter=_itemgetter,
                         __name__='namedtuple_%s' % typename,
                         _property=property,
                         _tuple=tuple)
        try:
            exec_(template, namespace)
        except SyntaxError:
            e = sys.exc_info()[1]
            raise SyntaxError(e.message + ':\n' + template)
        result = namespace[typename]

        # For pickling to work, the __module__ variable needs to be set
        # to the frame where the named tuple is created.  Bypass this
        # step in enviroments where sys._getframe is not defined (Jython
        # for example) or sys._getframe is not defined for arguments
        # greater than 0 (IronPython).
        try:
            result.__module__ = _sys._getframe(1).f_globals.get(
                '__name__', '__main__')
        except (AttributeError, ValueError):
            pass

        return result
Пример #34
0
def namedtuple(typename, field_names, *, rename=False, defaults=None, module=None):
    """Returns a new subclass of tuple with named fields.

    >>> Point = namedtuple('Point', ['x', 'y'])
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessible by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)

    """

    # Validate the field names.  At the user's option, either generate an error
    # message or automatically replace the field name with a valid name.
    if isinstance(field_names, str):
        field_names = field_names.replace(',', ' ').split()
    field_names = list(map(str, field_names))
    typename = _sys.intern(str(typename))

    if rename:
        seen = set()
        for index, name in enumerate(field_names):
            if (not name.isidentifier()
                or _iskeyword(name)
                or name.startswith('_')
                or name in seen):
                field_names[index] = f'_{index}'
            seen.add(name)

    for name in [typename] + field_names:
        if type(name) is not str:
            raise TypeError('Type names and field names must be strings')
        if not name.isidentifier():
            raise ValueError('Type names and field names must be valid '
                             f'identifiers: {name!r}')
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a '
                             f'keyword: {name!r}')

    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: '
                             f'{name!r}')
        if name in seen:
            raise ValueError(f'Encountered duplicate field name: {name!r}')
        seen.add(name)

    field_defaults = {}
    if defaults is not None:
        defaults = tuple(defaults)
        if len(defaults) > len(field_names):
            raise TypeError('Got more default values than field names')
        field_defaults = dict(reversed(list(zip(reversed(field_names),
                                                reversed(defaults)))))

    # Variables used in the methods and docstrings
    field_names = tuple(map(_sys.intern, field_names))
    num_fields = len(field_names)
    arg_list = repr(field_names).replace("'", "")[1:-1]
    repr_fmt = '(' + ', '.join(f'{name}=%r' for name in field_names) + ')'
    tuple_new = tuple.__new__
    _len = len

    # Create all the named tuple methods to be added to the class namespace

    s = f'def __new__(_cls, {arg_list}): return _tuple_new(_cls, ({arg_list}))'
    namespace = {'_tuple_new': tuple_new, '__name__': f'namedtuple_{typename}'}
    # Note: exec() has the side-effect of interning the field names
    exec(s, namespace)
    __new__ = namespace['__new__']
    __new__.__doc__ = f'Create new instance of {typename}({arg_list})'
    if defaults is not None:
        __new__.__defaults__ = defaults

    @classmethod
    def _make(cls, iterable):
        result = tuple_new(cls, iterable)
        if _len(result) != num_fields:
            raise TypeError(f'Expected {num_fields} arguments, got {len(result)}')
        return result

    _make.__func__.__doc__ = (f'Make a new {typename} object from a sequence '
                              'or iterable')

    def _replace(_self, **kwds):
        result = _self._make(map(kwds.pop, field_names, _self))
        if kwds:
            raise ValueError(f'Got unexpected field names: {list(kwds)!r}')
        return result

    _replace.__doc__ = (f'Return a new {typename} object replacing specified '
                        'fields with new values')

    def __repr__(self):
        'Return a nicely formatted representation string'
        return self.__class__.__name__ + repr_fmt % self

    _dict, _zip = dict, zip

    def _asdict(self):
        'Return a new dict which maps field names to their values.'
        return _dict(_zip(self._fields, self))

    def __getnewargs__(self):
        'Return self as a plain tuple.  Used by copy and pickle.'
        return tuple(self)

    # Modify function metadata to help with introspection and debugging

    for method in (__new__, _make.__func__, _replace,
                   __repr__, _asdict, __getnewargs__):
        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}({arg_list})',
        '__slots__': (),
        '_fields': field_names,
        '_fields_defaults': field_defaults,
        '__new__': __new__,
        '_make': _make,
        '_replace': _replace,
        '__repr__': __repr__,
        '_asdict': _asdict,
        '__getnewargs__': __getnewargs__,
    }
    for index, name in enumerate(field_names):
        doc = _sys.intern(f'Alias for field number {index}')
        class_namespace[name] = _tuplegetter(index, doc)

    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

    return result
Пример #35
0
def namedtuple(typename, field_names, *, verbose=False, rename=False, module=None):
    """Returns a new subclass of tuple with named fields.

    >>> Point = namedtuple('Point', ['x', 'y'])
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessible by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)

    """

    # Validate the field names.  At the user's option, either generate an error
    # message or automatically replace the field name with a valid name.
    if isinstance(field_names, str):
        field_names = field_names.replace(',', ' ').split()
    field_names = list(map(str, field_names))
    typename = str(typename)
    if rename:
        seen = set()
        for index, name in enumerate(field_names):
            if (not name.isidentifier()
                or _iskeyword(name)
                or name.startswith('_')
                or name in seen):
                field_names[index] = '_%d' % index
            seen.add(name)
    for name in [typename] + field_names:
        if type(name) is not str:
            raise TypeError('Type names and field names must be strings')
        if not name.isidentifier():
            raise ValueError('Type names and field names must be valid '
                             'identifiers: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a '
                             'keyword: %r' % name)
    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: '
                             '%r' % name)
        if name in seen:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen.add(name)

    # Fill-in the class template
    class_definition = _class_template.format(
        typename = typename,
        field_names = tuple(field_names),
        num_fields = len(field_names),
        arg_list = repr(tuple(field_names)).replace("'", "")[1:-1],
        repr_fmt = ', '.join(_repr_template.format(name=name)
                             for name in field_names),
        field_defs = '\n'.join(_field_template.format(index=index, name=name)
                               for index, name in enumerate(field_names))
    )

    # Execute the template string in a temporary namespace and support
    # tracing utilities by setting a value for frame.f_globals['__name__']
    namespace = dict(__name__='namedtuple_%s' % typename)
    exec(class_definition, namespace)
    result = namespace[typename]
    result._source = class_definition
    if verbose:
        print(result._source)

    # 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

    return result
Пример #36
0
def rectuple(typename, field_names, verbose=False, rename=False):
    """
    Returns a new subclass of tuple that acts like a record.

    Used to represent an immutable record with named fields. Compared
    to namedtuple, it behaves less like a tuple and more like a
    record. rectuples from different classes are never equal, and they
    cannot be added or multiplied like tuples.
    """

    # Validate the field names.  At the user's option, either generate an error
    # message or automatically replace the field name with a valid name.
    if isinstance(field_names, basestring):
        field_names = field_names.replace(',', ' ').split()
    field_names = map(str, field_names)
    if rename:
        seen = set()
        for index, name in enumerate(field_names):
            if (not all(c.isalnum() or c=='_' for c in name)
                or _iskeyword(name)
                or not name
                or name[0].isdigit()
                or name.startswith('_')
                or name in seen):
                field_names[index] = '_%d' % index
            seen.add(name)
    for name in [typename] + field_names:
        if not all(c.isalnum() or c=='_' for c in name):
            raise ValueError('Type names and field names can only contain '
                             'alphanumeric characters and underscores: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a '
                             'keyword: %r' % name)
        if name[0].isdigit():
            raise ValueError('Type names and field names cannot start with '
                             'a number: %r' % name)
    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: '
                             '%r' % name)
        if name in seen:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen.add(name)

    # Fill-in the class template
    class_definition = _class_template.format(
        typename = typename,
        field_names = tuple(field_names),
        num_fields = len(field_names),
        arg_list = repr(tuple(field_names)).replace("'", "")[1:-1],
        repr_fmt = ', '.join(_repr_template.format(name=name)
                             for name in field_names),
        field_defs = '\n'.join(_field_template.format(index=index, name=name)
                               for index, name in enumerate(field_names))
    )
    if verbose:
        print class_definition

    # Execute the template string in a temporary namespace and support
    # tracing utilities by setting a value for frame.f_globals['__name__']
    namespace = dict(_itemgetter=_itemgetter, __name__='rectuple_%s' % typename,
                     OrderedDict=OrderedDict, _property=property, _tuple=tuple)
    try:
        exec class_definition in namespace
    except SyntaxError as e:
        raise SyntaxError(e.message + ':\n' + class_definition)
    result = namespace[typename]

    # 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).
    try:
        result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass

    return result
Пример #37
0
def namedtuple(typename, field_names, verbose=False, rename=False):
    """Returns a new subclass of tuple with named fields.

    >>> Point = namedtuple('Point', 'x y')
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessable by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)

    """

    # Parse and validate the field names.  Validation serves two purposes,
    # generating informative error messages and preventing template injection attacks.
    if isinstance(field_names, str):
        field_names = field_names.replace(',', ' ').split() # names separated by whitespace and/or commas
    field_names = tuple(map(str, field_names))
    if rename:
        names = list(field_names)
        seen = set()
        for i, name in enumerate(names):
            if (not min(c.isalnum() or c=='_' for c in name) or _iskeyword(name)
                or not name or name[0].isdigit() or name.startswith('_')
                or name in seen):
                    names[i] = '_%d' % i
            seen.add(name)
        field_names = tuple(names)
    for name in (typename,) + field_names:
        if not min(c.isalnum() or c=='_' for c in name):
            raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a keyword: %r' % name)
        if name[0].isdigit():
            raise ValueError('Type names and field names cannot start with a number: %r' % name)
    seen_names = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: %r' % name)
        if name in seen_names:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen_names.add(name)

    # Create and fill-in the class template
    numfields = len(field_names)
    argtxt = repr(field_names).replace("'", "")[1:-1]   # tuple repr without parens or quotes
    reprtxt = ', '.join('%s=%%r' % name for name in field_names)

    template = '''class %(typename)s(tuple):
        '%(typename)s(%(argtxt)s)' \n
        __slots__ = () \n
        _fields = %(field_names)r \n
        def __new__(_cls, %(argtxt)s):
            return tuple.__new__(_cls, (%(argtxt)s)) \n
        @classmethod
        def _make(cls, iterable, new=tuple.__new__, len=len):
            'Make a new %(typename)s object from a sequence or iterable'
            result = new(cls, iterable)
            if len(result) != %(numfields)d:
                raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
            return result \n
        def __repr__(self):
            return '%(typename)s(%(reprtxt)s)' %% self \n
        def _asdict(self):
            'Return a new dict which maps field names to their values'
            return dict(zip(self._fields, self)) \n
        def _replace(_self, **kwds):
            'Return a new %(typename)s object replacing specified fields with new values'
            result = _self._make(map(kwds.pop, %(field_names)r, _self))
            if kwds:
                raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
            return result \n
        def __getnewargs__(self):
            return tuple(self) \n\n''' % locals()
    for i, name in enumerate(field_names):
        template += '        %s = _property(_itemgetter(%d))\n' % (name, i)
    
    if verbose:
        print(template)

    # Execute the template string in a temporary namespace
    namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
                     _property=property, _tuple=tuple)
    try:
        exec(template,namespace)
    except SyntaxError as e:
        raise SyntaxError(e.message + ':\n' + template)
    result = namespace[typename]

    # For pickling to work, the __module__ variable needs to be set to the frame
    # where the named tuple is created.  Bypass this step in enviroments where
    # sys._getframe is not defined (Jython for example) or sys._getframe is not
    # defined for arguments greater than 0 (IronPython).
    try:
        result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass

    return result
Пример #38
0
def namedtuple(typename,
               field_names,
               *,
               rename=False,
               defaults=None,
               module=None):
    """Returns a new subclass of tuple with named fields.

    >>> Point = namedtuple('Point', ['x', 'y'])
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessible by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)

    """

    # Validate the field names.  At the user's option, either generate an error
    # message or automatically replace the field name with a valid name.
    if isinstance(field_names, str):
        field_names = field_names.replace(',', ' ').split()
    field_names = list(map(str, field_names))
    typename = _sys.intern(str(typename))

    if rename:
        seen = set()
        for index, name in enumerate(field_names):
            if (not name.isidentifier() or _iskeyword(name)
                    or name.startswith('_') or name in seen):
                field_names[index] = f'_{index}'
            seen.add(name)

    for name in [typename] + field_names:
        if type(name) is not str:
            raise TypeError('Type names and field names must be strings')
        if not name.isidentifier():
            raise ValueError('Type names and field names must be valid '
                             f'identifiers: {name!r}')
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a '
                             f'keyword: {name!r}')

    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: '
                             f'{name!r}')
        if name in seen:
            raise ValueError(f'Encountered duplicate field name: {name!r}')
        seen.add(name)

    field_defaults = {}
    if defaults is not None:
        defaults = tuple(defaults)
        if len(defaults) > len(field_names):
            raise TypeError('Got more default values than field names')
        field_defaults = dict(
            reversed(list(zip(reversed(field_names), reversed(defaults)))))

    # Variables used in the methods and docstrings
    field_names = tuple(map(_sys.intern, field_names))
    num_fields = len(field_names)
    arg_list = repr(field_names).replace("'", "")[1:-1]
    repr_fmt = '(' + ', '.join(f'{name}=%r' for name in field_names) + ')'
    tuple_new = tuple.__new__
    _len = len

    # Create all the named tuple methods to be added to the class namespace

    s = f'def __new__(_cls, {arg_list}): return _tuple_new(_cls, ({arg_list}))'
    namespace = {'_tuple_new': tuple_new, '__name__': f'namedtuple_{typename}'}
    # Note: exec() has the side-effect of interning the field names
    exec(s, namespace)
    __new__ = namespace['__new__']
    __new__.__doc__ = f'Create new instance of {typename}({arg_list})'
    if defaults is not None:
        __new__.__defaults__ = defaults

    @classmethod
    def _make(cls, iterable):
        result = tuple_new(cls, iterable)
        if _len(result) != num_fields:
            raise TypeError(
                f'Expected {num_fields} arguments, got {len(result)}')
        return result

    _make.__func__.__doc__ = (f'Make a new {typename} object from a sequence '
                              'or iterable')

    def _replace(_self, **kwds):
        result = _self._make(map(kwds.pop, field_names, _self))
        if kwds:
            raise ValueError(f'Got unexpected field names: {list(kwds)!r}')
        return result

    _replace.__doc__ = (f'Return a new {typename} object replacing specified '
                        'fields with new values')

    def __repr__(self):
        'Return a nicely formatted representation string'
        return self.__class__.__name__ + repr_fmt % self

    def _asdict(self):
        'Return a new OrderedDict which maps field names to their values.'
        return OrderedDict(zip(self._fields, self))

    def __getnewargs__(self):
        'Return self as a plain tuple.  Used by copy and pickle.'
        return tuple(self)

    # Modify function metadata to help with introspection and debugging

    for method in (__new__, _make.__func__, _replace, __repr__, _asdict,
                   __getnewargs__):
        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}({arg_list})',
        '__slots__': (),
        '_fields': field_names,
        '_fields_defaults': field_defaults,
        '__new__': __new__,
        '_make': _make,
        '_replace': _replace,
        '__repr__': __repr__,
        '_asdict': _asdict,
        '__getnewargs__': __getnewargs__,
    }
    cache = _nt_itemgetters
    for index, name in enumerate(field_names):
        try:
            itemgetter_object, doc = cache[index]
        except KeyError:
            itemgetter_object = _itemgetter(index)
            doc = f'Alias for field number {index}'
            cache[index] = itemgetter_object, doc
        class_namespace[name] = property(itemgetter_object, doc=doc)

    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

    return result
Пример #39
0
def sparsenamedtuple(typename, field_names, verbose=False, rename=False):
    """Returns a new subclass of tuple with named fields.

    # sparsenamedtuples are defined similar to namedtuples
    >>> from collections import namedtuple
    >>> from sparsenamedtuple import sparsenamedtuple
    >>> Customer = namedtuple('Customer', 'username first middle last city state zip bday')
    >>> CustomerS = sparsenamedtuple('Customer', 'username first middle last city state zip bday')

    # __doc__ works the same
    >>> Customer.__doc__
    'Customer(username, first, middle, last, city, state, zip, bday)'
    >>> CustomerS.__doc__
    'Customer(username, first, middle, last, city, state, zip, bday)'

    # unlike namedtuples, sparsenamedtuples are always created by passing kwargs
    # Note that we don't pass the names of any None values
    >>> c1 = Customer('jdoe', None, None, None, None, 'NY', None, None)
    >>> c2 = CustomerS(username='******', state='NY')
    
    # repr looks the same
    >>> c1
    Customer(username='******', first=None, middle=None, last=None, city=None, state='NY', zip=None, bday=None)
    >>> c2
    Customer(username='******', first=None, middle=None, last=None, city=None, state='NY', zip=None, bday=None)
    
    # but the sparsenamedtuple takes up less space in memory
    >>> import sys
    >>> sys.getsizeof(c1)
    56
    >>> sys.getsizeof(c2)
    36
    
    # _asdict works the same
    >>> c1._asdict()
    OrderedDict([('username', 'jdoe'), ('first', None), ('middle', None), ('last', None), ('city', None), ('state', 'NY'), ('zip', None), ('bday', None)])
    >>> c2._asdict()
    OrderedDict([('username', 'jdoe'), ('first', None), ('middle', None), ('last', None), ('city', None), ('state', 'NY'), ('zip', None), ('bday', None)])
    
    # indexing works the same as with namedtuple
    >>> c1[0]
    'jdoe'
    >>> c2[0]
    'jdoe'
    >>> c1[1]
    >>> c2[1]

    # accessing values by field name works the same as with namedtuple
    >>> c1.middle
    >>> c2.middle
    >>> c1.state
    'NY'
    >>> c2.state
    'NY'

    # here we can see how it works; in sparsenamedtuple the indexes of the specified values are stashed
    # in the last element of the tuple. For this reason, unfortunately you can't use tuple unpacking
    # in the same way that you would with a regular namedtuple
    >>> tuple(c1)
    ('jdoe', None, None, None, None, 'NY', None, None)
    >>> tuple(c2)
    ('jdoe', 'NY', (0, 5))
    
    # you can use _asnamedtuple to convert a sparsenamedtuple into its namedtuple equivalent tuple;
    # this allows tuple unpacking similar to namedtuple
    >>> c2._asnamedtuple()
    ('jdoe', None, None, None, None, 'NY', None, None)

    # equality of sparsenamedtuple and namedtuple works...
    >>> c2 == c1
    True
    
    # but is not symmetrical; you have to specify the sparsenamedtuple as the lvalue
    >>> c1 == c2
    False
    """

    # Validate the field names.  At the user's option, either generate an error
    # message or automatically replace the field name with a valid name.
    if isinstance(field_names, basestring):
        field_names = field_names.replace(',', ' ').split()
    field_names = map(str, field_names)
    if rename:
        seen = set()
        for index, name in enumerate(field_names):
            if (not all(c.isalnum() or c=='_' for c in name)
                or _iskeyword(name)
                or not name
                or name[0].isdigit()
                or name.startswith('_')
                or name in seen):
                field_names[index] = '_%d' % index
            seen.add(name)
    for name in [typename] + field_names:
        if not all(c.isalnum() or c=='_' for c in name):
            raise ValueError('Type names and field names can only contain '
                             'alphanumeric characters and underscores: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a '
                             'keyword: %r' % name)
        if name[0].isdigit():
            raise ValueError('Type names and field names cannot start with '
                             'a number: %r' % name)
    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: '
                             '%r' % name)
        if name in seen:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen.add(name)

    # Fill-in the class template
    class_definition = _class_template.format(
        typename = typename,
        field_names = tuple(field_names),
        num_fields = len(field_names),
        arg_list = repr(tuple(field_names)).replace("'", "")[1:-1],
        repr_fmt = ', '.join(_repr_template.format(name=name)
                             for name in field_names),
        field_defs = '\n'.join(_field_template.format(index=index, name=name)
                               for index, name in enumerate(field_names))
    )
    if verbose:
        print class_definition

    # Execute the template string in a temporary namespace and support
    # tracing utilities by setting a value for frame.f_globals['__name__']
    namespace = dict(_itemgetter=_itemgetter, __name__='sparsenamedtuple_%s' % typename,
                     OrderedDict=OrderedDict, _property=property, _tuple=tuple)
    try:
        exec class_definition in namespace
    except SyntaxError as e:
        raise SyntaxError(e.message + ':\n' + class_definition)
    result = namespace[typename]

    # For pickling to work, the __module__ variable needs to be set to the frame
    # where the named tuple is created.  Bypass this step in enviroments where
    # sys._getframe is not defined (Jython for example) or sys._getframe is not
    # defined for arguments greater than 0 (IronPython).
    try:
        result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass

    return result
Пример #40
0
def namedtuple(typename,
               field_names,
               *,
               rename=False,
               defaults=None,
               module=None):
    """Returns a new subclass of tuple with named fields.

    >>> Point = namedtuple('Point', ['x', 'y'])
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessible by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)

    """

    # Validate the field names.  At the user's option, either generate an error
    # message or automatically replace the field name with a valid name.
    if isinstance(field_names, str):
        field_names = field_names.replace(',', ' ').split()
    field_names = list(map(str, field_names))
    typename = _sys.intern(str(typename))

    if rename:
        seen = set()
        for index, name in enumerate(field_names):
            if (not name.isidentifier() or _iskeyword(name)
                    or name.startswith('_') or name in seen):
                field_names[index] = f'_{index}'
            seen.add(name)

    for name in [typename] + field_names:
        if type(name) is not str:
            raise TypeError('Type names and field names must be strings')
        if not name.isidentifier():
            raise ValueError('Type names and field names must be valid '
                             f'identifiers: {name!r}')
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a '
                             f'keyword: {name!r}')

    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: '
                             f'{name!r}')
        if name in seen:
            raise ValueError(f'Encountered duplicate field name: {name!r}')
        seen.add(name)

    field_defaults = {}
    if defaults is not None:
        defaults = tuple(defaults)
        if len(defaults) > len(field_names):
            raise TypeError('Got more default values than field names')
        field_defaults = dict(
            reversed(list(zip(reversed(field_names), reversed(defaults)))))

    # Variables used in the methods and docstrings
    field_names = tuple(map(_sys.intern, field_names))
    num_fields = len(field_names)
    arg_list = repr(field_names).replace("'", "")[1:-1]
    repr_fmt = '(' + ', '.join(f'{name}=%r' for name in field_names) + ')'
    tuple_new = tuple.__new__
    _dict, _tuple, _len, _map, _zip = dict, tuple, len, map, zip

    # Create all the named tuple methods to be added to the class namespace

    s = f'def __new__(_cls, {arg_list}): return _tuple_new(_cls, ({arg_list}))'
    namespace = {'_tuple_new': tuple_new, '__name__': f'namedtuple_{typename}'}
    # Note: exec() has the side-effect of interning the field names
    exec(s, namespace)
    __new__ = namespace['__new__']
    __new__.__doc__ = f'Create new instance of {typename}({arg_list})'
    if defaults is not None:
        __new__.__defaults__ = defaults

    @classmethod
    def _make(cls, iterable):
        result = tuple_new(cls, iterable)
        if _len(result) != num_fields:
            raise TypeError(
                f'Expected {num_fields} arguments, got {len(result)}')
        return result

    _make.__func__.__doc__ = (f'Make a new {typename} object from a sequence '
                              'or iterable')

    def _replace(self, /, **kwds):
        result = self._make(_map(kwds.pop, field_names, self))
        if kwds:
            raise ValueError(f'Got unexpected field names: {list(kwds)!r}')
        return result
Пример #41
0
def namedtuple(typename, field_names, verbose=False):
    """Returns a new subclass of tuple with named fields.

    >>> Point = namedtuple('Point', 'x y')
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessable by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)

    """

    # Parse and validate the field names.  Validation serves two purposes,
    # generating informative error messages and preventing template injection attacks.
    if isinstance(field_names, basestring):
        # names separated by whitespace and/or commas
        field_names = field_names.replace(',', ' ').split()
    field_names = tuple(map(str, field_names))
    for name in (typename,) + field_names:
        if not all(c.isalnum() or c == '_' for c in name):
            raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % (name,))
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a keyword: %r' % name)
        if name[0].isdigit():
            raise ValueError('Type names and field names cannot start with a number: %r' % name)
    seen_names = set()
    for name in field_names:
        if name.startswith('_'):
            raise ValueError('Field names cannot start with an underscore: %r' % name)
        if name in seen_names:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen_names.add(name)

    # Create and fill-in the class template
    numfields = len(field_names)
    argtxt = repr(field_names).replace("'", "")[1:-1]   # tuple repr without parens or quotes
    reprtxt = ', '.join('%s=%%r' % name for name in field_names)
    dicttxt = ', '.join('%r: t[%d]' % (name, pos) for pos, name in enumerate(field_names))
    template = '''class %(typename)s(tuple):
        '%(typename)s(%(argtxt)s)' \n
        __slots__ = () \n
        _fields = %(field_names)r \n
        def __new__(_cls, %(argtxt)s):
            return _tuple.__new__(_cls, (%(argtxt)s)) \n
        def __repr__(self):
            return '%(typename)s(%(reprtxt)s)' %% self \n
        def _asdict(t):
            'Return a new dict which maps field names to their values'
            return {%(dicttxt)s} \n
        def __getnewargs__(self):
            return tuple(self) \n\n''' % locals()
    for i, name in enumerate(field_names):
        template += '        %s = _property(_itemgetter(%d))\n' % (name, i)
    if verbose:
        print template

    # Execute the template string in a temporary namespace and
    # support tracing utilities by setting a value for frame.f_globals['__name__']
    namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
                     _property=property, _tuple=tuple)
    try:
        exec template in namespace
    except SyntaxError, e:
        raise SyntaxError(e.message + ':\n' + template)
Пример #42
0
def recordclass(typename, fields, 
                rename=False, defaults=None, readonly=False, hashable=False, gc=False, module=None):
    """Returns a new subclass of array with named fields.

    >>> Point = recordclass('Point', 'x y')
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessable by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d.x
    11
    >>> d.x = 33                        # assign new value
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)
    """

    if readonly:
        baseclass = memoryslotsreadonly
    else:
        baseclass = memoryslots
    
    # Validate the field names.  At the user's option, either generate an error
    # message or automatically replace the field name with a valid name.
    if isinstance(fields, str):
        field_names = fields.replace(',', ' ').split()
        annotations = None
    else:
        msg = "recordclass('Name', [(f0, t0), (f1, t1), ...]); each t must be a type"
        annotations = {}
        field_names = []
        for fn in fields:
            if type(fn) is tuple:
                n, t = fn
                n = str(n)
                if _type_check:
                    t = _type_check(t, msg)
                annotations[n] = t
                field_names.append(n)
            else:
                field_names.append(str(fn))

    typename = _intern(str(typename))

    if rename:
        seen = set()
        for index, name in enumerate(field_names):
            if (not _isidentifier(name)
                or _iskeyword(name)
                or name.startswith('_')
                or name in seen):
                    field_names[index] = '_%d' % index
            seen.add(name)

    for name in [typename] + field_names:
        if type(name) != str:
            raise TypeError('Type names and field names must be strings')
        if not _isidentifier(name):
            raise ValueError('Type names and field names must be valid '
                             'identifiers: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a '
                             'keyword: %r' % name)
    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: '
                             '%r' % name)
        if name in seen:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen.add(name)

    if defaults is not None:
        defaults = tuple(defaults)
        if len(defaults) > len(field_names):
            raise TypeError('Got more default values than field names')
        field_defaults = dict(reversed(list(zip(reversed(field_names),
                                                reversed(defaults)))))
    else:
        field_defaults = {}

    field_names = tuple(map(_intern, field_names))
    n_fields = len(field_names)
    arg_list = ', '.join(field_names)
    repr_fmt=', '.join(_repr_template.format(name=name) for name in field_names)

    if readonly:
        new_func_template = """\
def __new__(_cls, {1}):
    'Create new instance of {0}({1})'
    return _method_new(_cls, ({1}))
"""
        _method_new = memoryslotsreadonly.__new__
    else:
        new_func_template = """\
def __new__(_cls, {1}):
    'Create new instance: {0}({1})'
    return _method_new(_cls, {1})
"""
        _method_new = memoryslots.__new__

    new_func_def = new_func_template.format(typename, arg_list)
    
    # Execute the template string in a temporary namespace and support
    # tracing utilities by setting a value for frame.f_globals['__name__']
    namespace = dict(_method_new=_method_new)
    
    code = compile(new_func_def, "", "exec")
    eval(code, namespace)
    
    __new__ = namespace['__new__']
    if defaults is not None:
        __new__.__defaults__ = defaults
    if annotations:
        __new__.__annotations__ = annotations
    
    def _make(_cls, iterable):
        ob = _method_new(_cls, *iterable)
        if len(ob) != n_fields:
            raise TypeError('Expected %s arguments, got %s' % (n_fields, len(ob)))
        return ob
    
    _make.__doc__ = 'Make a new %s object from a sequence or iterable' % typename

    if readonly:
        def _replace(_self, **kwds):
            result = _self._make((kwds.pop(name) for name in field_names))
            if kwds:
                raise ValueError('Got unexpected field names: %r' % list(kwds))
            return result
    else:
        def _replace(_self, **kwds):
            for name, val in kwds.items():
                setattr(_self, name, val)
            return _self
    
    _replace.__doc__ = 'Return a new %s object replacing specified fields with new values' % typename

    def __repr__(self):
        'Return a nicely formatted representation string'
        return self.__class__.__name__ + "(" + (repr_fmt % tuple(self)) + ")" 
    
    def _asdict(self):
        'Return a new OrderedDict which maps field names to their values.'
        return OrderedDict(zip(self.__attrs__, self))
        
    def __getnewargs__(self):
        'Return self as a plain tuple.  Used by copy and pickle.'
        return tuple(self)
        
    def __getstate__(self):
        'Exclude the OrderedDict from pickling'
        return None
        
    def __reduce__(self):
        'Reduce'
        return type(self), tuple(self)

    if not readonly and hashable:
        def __hash__(self):
            return hash(tuple(self))
        __hash__.__qualname__ = typename + "." + "__hash__"

    for method in (__new__, _make, _replace,
                   __repr__, _asdict, __getnewargs__,
                   __reduce__, __getstate__):
        method.__qualname__ = typename + "." + method.__name__
        
    _make = classmethod(_make)

    if readonly:
        cache = _itemgeters
    else:
        cache = _itemgetseters
    class_namespace = {}
    for index, name in enumerate(field_names):
        try:
            item_object = cache[index]
        except KeyError:
            if readonly:
                item_object = itemget(index)
            else:
                item_object = itemgetset(index)
            #doc = 'Alias for field number ' + str(index)
            cache[index] = item_object
        class_namespace[name] = item_object

    __options__ = {'hashable':hashable, 'gc':gc}
    if readonly:
        __options__['hashable'] = True
        
    class_namespace.update({
        '__slots__': (),
        '__doc__': typename+'('+arg_list+')',
        '__attrs__': field_names,
        '__new__': __new__,
        '_make': _make,
        '_replace': _replace,
        '__repr__': __repr__,
        '_asdict': _asdict,
        '__getnewargs__': __getnewargs__,
        '__getstate__': __getstate__,
        '__reduce__': __reduce__,
        '__dict__': property(_asdict),
        '__options__': __options__,
    })

    _result = recordclasstype(typename, (baseclass,), class_namespace)
    
    # For pickling to work, the __module__ variable needs to be set to the frame
    # where the class is created.
    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
    if annotations:
        _result.__annotations__ = annotations

    return _result
Пример #43
0
def namedtuple(typename, field_names, verbose=False, rename=False):
    """Returns a new subclass of tuple with named fields.
    This is a patched version of collections.namedtuple from the stdlib.
    Unlike the latter, it accepts non-identifier strings as field names.
    All values are accessible through dict syntax. Fields whose names are
    identifiers are also accessible via attribute syntax as in ordinary namedtuples, alongside traditional
    indexing. This feature is needed as SDMX allows field names
    to contain '-'. 

    >>> Point = namedtuple('Point', ['x', 'y'])
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessable by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)

    """

    if isinstance(field_names, str):
        field_names = field_names.replace(",", " ").split()
    field_names = list(map(str, field_names))
    typename = str(typename)
    for name in [typename] + field_names:
        if type(name) != str:
            raise TypeError("Type names and field names must be strings")
        if _iskeyword(name):
            raise ValueError("Type names and field names cannot be a " "keyword: %r" % name)
    if not _isidentifier(typename):
        raise ValueError("Type names must be valid " "identifiers: %r" % name)
    seen = set()
    for name in field_names:
        if name.startswith("_") and not rename:
            raise ValueError("Field names cannot start with an underscore: " "%r" % name)
        if name in seen:
            raise ValueError("Encountered duplicate field name: %r" % name)
        seen.add(name)
    arg_names = ["_" + str(i) for i in range(len(field_names))]
    # Fill-in the class template
    class_definition = _class_template.format(
        typename=typename,
        field_names=tuple(field_names),
        num_fields=len(field_names),
        arg_list=repr(tuple(arg_names)).replace("'", "")[1:-1],
        repr_fmt=", ".join(_repr_template.format(name=name) for name in field_names),
        field_defs="\n".join(
            _field_template.format(index=index, name=name)
            for index, name in enumerate(field_names)
            if _isidentifier(name)
        ),
    )

    # Execute the template string in a temporary namespace and support
    # tracing utilities by setting a value for frame.f_globals['__name__']
    namespace = dict(__name__="namedtuple_%s" % typename)
    exec(class_definition, namespace)
    result = namespace[typename]
    result._source = class_definition
    if verbose:
        print(result._source)

    # 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).
    try:
        result.__module__ = _sys._getframe(1).f_globals.get("__name__", "__main__")
    except (AttributeError, ValueError):
        pass

    return result
Пример #44
0
    def namedtuple(typename, field_names, verbose=False, rename=False):
        """A collections.namedtuple implementation, see:
        http://docs.python.org/library/collections.html#namedtuple
        """
        if isinstance(field_names, basestring):
            field_names = field_names.replace(',', ' ').split()
        field_names = tuple(map(str, field_names))
        if rename:
            names = list(field_names)
            seen = set()
            for i, name in enumerate(names):
                if ((not min(c.isalnum() or c == '_' for c in name)
                        or _iskeyword(name)
                        or not name or name[0].isdigit()
                        or name.startswith('_')
                        or name in seen)):
                    names[i] = '_%d' % i
                seen.add(name)
            field_names = tuple(names)
        for name in (typename,) + field_names:
            if not min(c.isalnum() or c == '_' for c in name):
                raise ValueError('Type names and field names can only contain '
                                 'alphanumeric characters and underscores: %r'
                                 % name)
            if _iskeyword(name):
                raise ValueError('Type names and field names cannot be a '
                                 'keyword: %r' % name)
            if name[0].isdigit():
                raise ValueError('Type names and field names cannot start '
                                 'with a number: %r' % name)
        seen_names = set()
        for name in field_names:
            if name.startswith('_') and not rename:
                raise ValueError(
                    'Field names cannot start with an underscore: %r' % name)
            if name in seen_names:
                raise ValueError('Encountered duplicate field name: %r' % name)
            seen_names.add(name)

        numfields = len(field_names)
        argtxt = repr(field_names).replace("'", "")[1:-1]
        reprtxt = ', '.join('%s=%%r' % name for name in field_names)
        template = '''class %(typename)s(tuple):
        '%(typename)s(%(argtxt)s)' \n
        __slots__ = () \n
        _fields = %(field_names)r \n
        def __new__(_cls, %(argtxt)s):
            return _tuple.__new__(_cls, (%(argtxt)s)) \n
        @classmethod
        def _make(cls, iterable, new=tuple.__new__, len=len):
            'Make a new %(typename)s object from a sequence or iterable'
            result = new(cls, iterable)
            if len(result) != %(numfields)d:
                raise TypeError(
                    'Expected %(numfields)d arguments, got %%d' %% len(result))
            return result \n
        def __repr__(self):
            return '%(typename)s(%(reprtxt)s)' %% self \n
        def _asdict(self):
            'Return a new dict which maps field names to their values'
            return dict(zip(self._fields, self)) \n
        def _replace(_self, **kwds):
            result = _self._make(map(kwds.pop, %(field_names)r, _self))
            if kwds:
                raise ValueError(
                    'Got unexpected field names: %%r' %% kwds.keys())
            return result \n
        def __getnewargs__(self):
            return tuple(self) \n\n''' % locals()
        for i, name in enumerate(field_names):
            template += '        %s = _property(_itemgetter(%d))\n' % (name, i)
        if verbose:
            sys.stdout.write(template + '\n')
            sys.stdout.flush()

        namespace = dict(
            _itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
            _property=property, _tuple=tuple)
        try:
            exec_(template, namespace)
        except SyntaxError:
            e = sys.exc_info()[1]
            raise SyntaxError(e.message + ':\n' + template)
        result = namespace[typename]
        try:
            result.__module__ = _sys._getframe(
                1).f_globals.get('__name__', '__main__')
        except (AttributeError, ValueError):
            pass

        return result
Пример #45
0
def namedtuple(typename, field_names, verbose=False, rename=False):
    """Returns a new subclass of tuple with named fields.

    >>> Point = namedtuple('Point', ['x', 'y'])
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessable by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)

    """

    # Validate the field names.  At the user's option, either generate an error
    # message or automatically replace the field name with a valid name.
    if isinstance(field_names, basestring):
        field_names = field_names.replace(',', ' ').split()
    field_names = map(str, field_names)
    if rename:
        seen = set()
        for index, name in enumerate(field_names):
            if (not all(c.isalnum() or c=='_' for c in name)
                or _iskeyword(name)
                or not name
                or name[0].isdigit()
                or name.startswith('_')
                or name in seen):
                field_names[index] = '_%d' % index
            seen.add(name)
    for name in [typename] + field_names:
        if not all(c.isalnum() or c=='_' for c in name):
            raise ValueError('Type names and field names can only contain '
                             'alphanumeric characters and underscores: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a '
                             'keyword: %r' % name)
        if name[0].isdigit():
            raise ValueError('Type names and field names cannot start with '
                             'a number: %r' % name)
    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: '
                             '%r' % name)
        if name in seen:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen.add(name)

    # Fill-in the class template
    class_definition = _class_template.format(
        typename = typename,
        field_names = tuple(field_names),
        num_fields = len(field_names),
        arg_list = repr(tuple(field_names)).replace("'", "")[1:-1],
        repr_fmt = ', '.join(_repr_template.format(name=name)
                             for name in field_names),
        field_defs = '\n'.join(_field_template.format(index=index, name=name)
                               for index, name in enumerate(field_names))
    )
    if verbose:
        print class_definition

    # Execute the template string in a temporary namespace and support
    # tracing utilities by setting a value for frame.f_globals['__name__']
    namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
                     OrderedDict=OrderedDict, _property=property, _tuple=tuple)
    try:
        exec class_definition in namespace
    except SyntaxError as e:
        raise SyntaxError(e.message + ':\n' + class_definition)
    result = namespace[typename]

    # 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).
    try:
        result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass

    return result
Пример #46
0
def namedtuple(typename, field_names, namespaceaugment={}, verbose=False):
	"""Returns a new subclass of tuple with named fields.

	>>> Point = namedtuple('Point', 'x y')
	>>> Point.__doc__				   # docstring for the new class
	'Point(x, y)'
	>>> p = Point(11, y=22)			 # instantiate with positional args or keywords
	>>> p[0] + p[1]					 # indexable like a plain tuple
	33
	>>> x, y = p						# unpack like a regular tuple
	>>> x, y
	(11, 22)
	>>> p.x + p.y					   # fields also accessable by name
	33
	>>> d = p._asdict()				 # convert to a dictionary
	>>> d['x']
	11
	>>> Point(**d)					  # convert from a dictionary
	Point(x=11, y=22)
	>>> p._replace(x=100)			   # _replace() is like str.replace() but targets named fields
	Point(x=100, y=22)

	"""

	# Parse and validate the field names.  Validation serves two purposes,
	# generating informative error messages and preventing template injection attacks.
	if isinstance(field_names, basestring):
		field_names = field_names.replace(',', ' ').split() # names separated by whitespace and/or commas
	field_names = tuple(map(str, field_names))
	for name in (typename,) + field_names:
		if not all(c.isalnum() or c=='_' for c in name):
			raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name)
		if _iskeyword(name):
			raise ValueError('Type names and field names cannot be a keyword: %r' % name)
		if name[0].isdigit():
			raise ValueError('Type names and field names cannot start with a number: %r' % name)
	seen_names = set()
	for name in field_names:
		if name.startswith('_'):
			raise ValueError('Field names cannot start with an underscore: %r' % name)
		if name in seen_names:
			raise ValueError('Encountered duplicate field name: %r' % name)
		seen_names.add(name)

	# Create and fill-in the class template
	numfields = len(field_names)
	argtxt = repr(field_names).replace("'", "")[1:-1]   # tuple repr without parens or quotes
	reprtxt = ', '.join('%s=%%r' % name for name in field_names)
	dicttxt = ', '.join('%r: t[%d]' % (name, pos) for pos, name in enumerate(field_names))
	template = '''class %(typename)s(tuple):
		'%(typename)s(%(argtxt)s)' \n
		__slots__ = () \n
		_fields = %(field_names)r \n
		def __new__(cls, %(argtxt)s):
			return tuple.__new__(cls, (%(argtxt)s)) \n
		@classmethod
		def _make(cls, iterable, new=tuple.__new__, len=len):
			'Make a new %(typename)s object from a sequence or iterable'
			result = new(cls, iterable)
			if len(result) != %(numfields)d:
				raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
			return result \n
		def __repr__(self):
			return '%(typename)s(%(reprtxt)s)' %% self \n
		def _asdict(t):
			'Return a new dict which maps field names to their values'
			return {%(dicttxt)s} \n
		def _replace(self, **kwds):
			'Return a new %(typename)s object replacing specified fields with new values'
			result = self._make(map(kwds.pop, %(field_names)r, self))
			if kwds:
				raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
			return result \n
		def __getnewargs__(self):
			return tuple(self) \n\n''' % locals()
	for i, name in enumerate(field_names):
		template += '		%s = property(itemgetter(%d))\n' % (name, i)

	for name in namespaceaugment.iterkeys():
		template += '		%s = %s\n' % (name, name)

	if verbose:
		print template

	# Execute the template string in a temporary namespace and
	# support tracing utilities by setting a value for frame.f_globals['__name__']
	namespace = dict(namespaceaugment)
	namespace.update(itemgetter=_itemgetter, __name__='namedtuple_%s' % typename)
	try:
		exec template in namespace
	except SyntaxError, e:
		raise SyntaxError(e.message + ':\n' + template)
Пример #47
0
def marshalable_object(typename, field_names, verbose=False):
    """Returns a new object with named fields.

    >>> Point = marshalable_object('Point', 'x y')
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    """

    # Parse and validate the field names.  Validation serves two purposes,
    # generating informative error messages and preventing template injection attacks.
    if isinstance(field_names, basestring):
        field_names = field_names.replace(
            ',', ' ').split()  # names separated by whitespace and/or commas
    field_names = tuple(map(str, field_names))
    for name in (typename, ) + field_names:
        if not all(c.isalnum() or c == '_' for c in name):
            raise ValueError(
                'Type names and field names can only contain alphanumeric characters and underscores: %r'
                % name)
        if _iskeyword(name):
            raise ValueError(
                'Type names and field names cannot be a keyword: %r' % name)
        if name[0].isdigit():
            raise ValueError(
                'Type names and field names cannot start with a number: %r' %
                name)
    seen_names = set()
    for name in field_names:
        if name.startswith('_'):
            raise ValueError(
                'Field names cannot start with an underscore: %r' % name)
        if name in seen_names:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen_names.add(name)

    # Create and fill-in the class template
    numfields = len(field_names)
    argtxt = repr(field_names).replace(
        "'", "")[1:-1]  # tuple repr without parens or quotes
    reprtxt = ', '.join('%s=%%r' % name for name in field_names)
    dicttxt = ', '.join('%r: t[%d]' % (name, pos)
                        for pos, name in enumerate(field_names))
    template = '''class %(typename)s(object):
    '%(typename)s(%(argtxt)s)' \n
    __slots__ = %(field_names)r \n
    #_____________________________________________________________________________________
    #
    #   __init__
    #_____________________________________________________________________________________
    def __init__(self, %(argtxt)s):
        """
        Initialise
        """
        self._do_init(%(argtxt)s)

    def _as_tuple (self):
        """
        returns data as a list
        """
        return tuple(getattr(self, self.__slots__[i]) for i in range(%(numfields)d))

    def _as_dict (self):
        """
        returns data as a list
        """
        return dict(zip(%(field_names)s, tuple(getattr(self, self.__slots__[i]) for i in range(%(numfields)d))))

    def _do_init (self, *data):
        """
        delegate from __init__ to handle variable number of arguments
        """
        if len(data) != %(numfields)d:
            raise TypeError('%(typename)s(%(argtxt)s): Expected %(numfields)d arguments, got %%d' %% len(data))
        for i in range(%(numfields)d):
            setattr(self, self.__slots__[i], data[i])

    def __eq__(self, other):
       if type(other) == %(typename)s:
           return cmp(self, other) == 0
       else:
           return False

    def __cmp__(self, other):
        if type(other) != %(typename)s:
           return -1
        for i in range(%(numfields)d):
            c = cmp(getattr(self, self.__slots__[i]) != getattr(other, self.__slots__[i]))
            if c:
                return c
        return 0
    #_____________________________________________________________________________________
    #
    #   dump
    #_____________________________________________________________________________________
    def dump(self, data_file):
        """
        dump
        """
        for i in range(%(numfields)d):
            dump(getattr(self, self.__slots__[i]), data_file)

    #_____________________________________________________________________________________
    #
    #   load
    #_____________________________________________________________________________________
    @staticmethod
    def load(data_file):
        """
        load
        """
        data = []
        for i in range(%(numfields)d):
            data.append(load(data_file))

        return %(typename)s(  *data)

    #_____________________________________________________________________________________
    #
    #   __repr__
    #_____________________________________________________________________________________
    def __repr__ (self):
        return ('%(typename)s(%(reprtxt)s)' %% self._as_tuple())\n
    \n\n''' % locals()
    if verbose:
        print template

    # Execute the template string in a temporary namespace and
    # support tracing utilities by setting a value for frame.f_globals['__name__']
    namespace = dict(dump=_dump,
                     load=_load,
                     __name__='marshalable_object_%s' % typename)
    try:
        exec template in namespace
    except SyntaxError, e:
        raise SyntaxError(str(e) + ':\n' + template)
Пример #48
0
def namedlist(typename, field_names, verbose=False, rename=False):
    """Returns a new subclass of list with named fields.

    >>> Point = namedlist('Point', ['x', 'y'])
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with pos args or keywords
    >>> p[0] + p[1]                     # indexable like a plain list
    33
    >>> x, y = p                        # unpack like a regular list
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessible by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)
    """

    # Validate the field names.  At the user's option, either generate an error
    # message or automatically replace the field name with a valid name.
    if isinstance(field_names, basestring):
        field_names = field_names.replace(',', ' ').split()
    field_names = [str(x) for x in field_names]
    if rename:
        seen = set()
        for index, name in enumerate(field_names):
            if (not all(c.isalnum() or c == '_' for c in name)
                or _iskeyword(name)
                or not name
                or name[0].isdigit()
                or name.startswith('_')
                or name in seen):
                field_names[index] = '_%d' % index
            seen.add(name)
    for name in [typename] + field_names:
        if not all(c.isalnum() or c == '_' for c in name):
            raise ValueError('Type names and field names can only contain '
                             'alphanumeric characters and underscores: %r'
                             % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a '
                             'keyword: %r' % name)
        if name[0].isdigit():
            raise ValueError('Type names and field names cannot start with '
                             'a number: %r' % name)
    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: '
                             '%r' % name)
        if name in seen:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen.add(name)

    # Fill-in the class template
    fmt_kw = {'typename': typename}
    fmt_kw['field_names'] = tuple(field_names)
    fmt_kw['num_fields'] = len(field_names)
    fmt_kw['arg_list'] = repr(tuple(field_names)).replace("'", "")[1:-1]
    fmt_kw['repr_fmt'] = ', '.join(_repr_tmpl.format(name=name)
                                   for name in field_names)
    fmt_kw['field_defs'] = '\n'.join(_m_field_tmpl.format(index=index, name=name)
                                     for index, name in enumerate(field_names))
    class_definition = _namedlist_tmpl.format(**fmt_kw)

    if verbose:
        print(class_definition)

    def _itemsetter(key):
        def _itemsetter(obj, value):
            obj[key] = value
        return _itemsetter

    # Execute the template string in a temporary namespace and support
    # tracing utilities by setting a value for frame.f_globals['__name__']
    namespace = dict(_itemgetter=_itemgetter,
                     _itemsetter=_itemsetter,
                     __name__='namedlist_%s' % typename,
                     OrderedDict=OrderedDict,
                     _property=property,
                     _list=list)
    try:
        exec_(class_definition, namespace)
    except SyntaxError as e:
        raise SyntaxError(e.message + ':\n' + class_definition)
    result = namespace[typename]

    # For pickling to work, the __module__ variable needs to be set to
    # the frame where the named list 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).
    try:
        frame = _sys._getframe(1)
        result.__module__ = frame.f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass

    return result
Пример #49
0
    def namedtuple(typename, field_names, verbose=False, rename=False):
        """A collections.namedtuple implementation written in Python
        to support Python versions < 2.6.

        Taken from: http://code.activestate.com/recipes/500261/
        """
        # Parse and validate the field names.  Validation serves two
        # purposes, generating informative error messages and preventing
        # template injection attacks.
        if isinstance(field_names, basestring):
            # names separated by whitespace and/or commas
            field_names = field_names.replace(",", " ").split()
        field_names = tuple(map(str, field_names))
        if rename:
            names = list(field_names)
            seen = set()
            for i, name in enumerate(names):
                if (
                    not min(c.isalnum() or c == "_" for c in name)
                    or _iskeyword(name)
                    or not name
                    or name[0].isdigit()
                    or name.startswith("_")
                    or name in seen
                ):
                    names[i] = "_%d" % i
                seen.add(name)
            field_names = tuple(names)
        for name in (typename,) + field_names:
            if not min(c.isalnum() or c == "_" for c in name):
                raise ValueError(
                    "Type names and field names can only contain " "alphanumeric characters and underscores: %r" % name
                )
            if _iskeyword(name):
                raise ValueError("Type names and field names cannot be a keyword: %r" % name)
            if name[0].isdigit():
                raise ValueError("Type names and field names cannot start with a " "number: %r" % name)
        seen_names = set()
        for name in field_names:
            if name.startswith("_") and not rename:
                raise ValueError("Field names cannot start with an underscore: %r" % name)
            if name in seen_names:
                raise ValueError("Encountered duplicate field name: %r" % name)
            seen_names.add(name)

        # Create and fill-in the class template
        numfields = len(field_names)
        # tuple repr without parens or quotes
        argtxt = repr(field_names).replace("'", "")[1:-1]
        reprtxt = ", ".join("%s=%%r" % name for name in field_names)
        template = (
            """class %(typename)s(tuple):
        '%(typename)s(%(argtxt)s)' \n
        __slots__ = () \n
        _fields = %(field_names)r \n
        def __new__(_cls, %(argtxt)s):
            return _tuple.__new__(_cls, (%(argtxt)s)) \n
        @classmethod
        def _make(cls, iterable, new=tuple.__new__, len=len):
            'Make a new %(typename)s object from a sequence or iterable'
            result = new(cls, iterable)
            if len(result) != %(numfields)d:
                raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
            return result \n
        def __repr__(self):
            return '%(typename)s(%(reprtxt)s)' %% self \n
        def _asdict(self):
            'Return a new dict which maps field names to their values'
            return dict(zip(self._fields, self)) \n
        def _replace(_self, **kwds):
            'Return a new %(typename)s object replacing specified fields with new values'
            result = _self._make(map(kwds.pop, %(field_names)r, _self))
            if kwds:
                raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
            return result \n
        def __getnewargs__(self):
            return tuple(self) \n\n"""
            % locals()
        )
        for i, name in enumerate(field_names):
            template += "        %s = _property(_itemgetter(%d))\n" % (name, i)
        if verbose:
            sys.stdout.write(template + "\n")
            sys.stdout.flush()

        # Execute the template string in a temporary namespace
        namespace = dict(_itemgetter=_itemgetter, __name__="namedtuple_%s" % typename, _property=property, _tuple=tuple)
        try:
            exec_(template, namespace)
        except SyntaxError:
            e = sys.exc_info()[1]
            raise SyntaxError(e.message + ":\n" + template)
        result = namespace[typename]

        # For pickling to work, the __module__ variable needs to be set
        # to the frame where the named tuple is created.  Bypass this
        # step in enviroments where sys._getframe is not defined (Jython
        # for example) or sys._getframe is not defined for arguments
        # greater than 0 (IronPython).
        try:
            result.__module__ = _sys._getframe(1).f_globals.get("__name__", "__main__")
        except (AttributeError, ValueError):
            pass

        return result
Пример #50
0
def namedtuple(typename, field_names, verbose=False):
    """Returns a new subclass of tuple with named fields.

    >>> Point = namedtuple('Point', 'x y')
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessable by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)

    """

    # Parse and validate the field names.  Validation serves two purposes,
    # generating informative error messages and preventing template injection attacks.
    if isinstance(field_names, basestring):
        field_names = field_names.replace(
            ',', ' ').split()  # names separated by whitespace and/or commas
    field_names = tuple(field_names)
    for name in (typename, ) + field_names:
        if not min(c.isalnum() or c == '_' for c in name):
            raise ValueError(
                'Type names and field names can only contain alphanumeric characters and underscores: %r'
                % name)
        if _iskeyword(name):
            raise ValueError(
                'Type names and field names cannot be a keyword: %r' % name)
        if name[0].isdigit():
            raise ValueError(
                'Type names and field names cannot start with a number: %r' %
                name)
    seen_names = set()
    for name in field_names:
        if name.startswith('_'):
            raise ValueError(
                'Field names cannot start with an underscore: %r' % name)
        if name in seen_names:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen_names.add(name)

    # Create and fill-in the class template
    numfields = len(field_names)
    argtxt = repr(field_names).replace(
        "'", "")[1:-1]  # tuple repr without parens or quotes
    reprtxt = ', '.join('%s=%%r' % name for name in field_names)
    dicttxt = ', '.join('%r: t[%d]' % (name, pos)
                        for pos, name in enumerate(field_names))
    template = '''class %(typename)s(tuple):
        '%(typename)s(%(argtxt)s)' \n
        __slots__ = () \n
        _fields = %(field_names)r \n
        def __new__(cls, %(argtxt)s):
            return tuple.__new__(cls, (%(argtxt)s)) \n
        @classmethod
        def _make(cls, iterable, new=tuple.__new__, len=len):
            'Make a new %(typename)s object from a sequence or iterable'
            result = new(cls, iterable)
            if len(result) != %(numfields)d:
                raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
            return result \n
        def __repr__(self):
            return '%(typename)s(%(reprtxt)s)' %% self \n
        def _asdict(t):
            'Return a new dict which maps field names to their values'
            return {%(dicttxt)s} \n
        def _replace(self, **kwds):
            'Return a new %(typename)s object replacing specified fields with new values'
            result = self._make(map(kwds.pop, %(field_names)r, self))
            if kwds:
                raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
            return result \n\n''' % locals()
    for i, name in enumerate(field_names):
        template += '        %s = property(itemgetter(%d))\n' % (name, i)
    if verbose:
        print template

    # Execute the template string in a temporary namespace
    namespace = dict(itemgetter=_itemgetter)
    try:
        exec template in namespace
    except SyntaxError, e:
        raise SyntaxError(e.message + ':\n' + template)
Пример #51
0
def namedtuple(typename, field_names, verbose = False, rename = False):
    """Returns a new subclass of tuple with named fields.
    
    >>> Point = namedtuple('Point', ['x', 'y'])
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessable by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)
    
    """
    if isinstance(field_names, basestring):
        field_names = field_names.replace(',', ' ').split()
    field_names = map(str, field_names)
    if rename:
        seen = set()
        for index, name in enumerate(field_names):
            if not all((c.isalnum() or c == '_' for c in name)) or _iskeyword(name) or not name or name[0].isdigit() or name.startswith('_') or name in seen:
                field_names[index] = '_%d' % index
            seen.add(name)

    for name in [typename] + field_names:
        if not all((c.isalnum() or c == '_' for c in name)):
            raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a keyword: %r' % name)
        if name[0].isdigit():
            raise ValueError('Type names and field names cannot start with a number: %r' % name)

    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: %r' % name)
        if name in seen:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen.add(name)

    class_definition = _class_template.format(typename=typename, field_names=tuple(field_names), num_fields=len(field_names), arg_list=repr(tuple(field_names)).replace("'", '')[1:-1], repr_fmt=', '.join((_repr_template.format(name=name) for name in field_names)), field_defs='\n'.join((_field_template.format(index=index, name=name) for index, name in enumerate(field_names))))
    if verbose:
        print class_definition
    namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename, OrderedDict=OrderedDict, _property=property, _tuple=tuple)
    try:
        exec class_definition in namespace
    except SyntaxError as e:
        raise SyntaxError(e.message + ':\n' + class_definition)

    result = namespace[typename]
    try:
        result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass

    return result
Пример #52
0
    def _namedtuple(typename, field_names, verbose=False, rename=False):
        if isinstance(field_names, basestring):
            field_names = field_names.replace(",", " ").split()
        field_names = tuple(map(str, field_names))
        if rename:
            names = list(field_names)
            seen = set()
            for i, name in enumerate(names):
                if (
                    not min(c.isalnum() or c == "_" for c in name)
                    or _iskeyword(name)
                    or not name
                    or name[0].isdigit()
                    or name.startswith("_")
                    or name in seen
                ):
                    names[i] = "_%d" % i
                seen.add(name)
            field_names = tuple(names)
        for name in (typename,) + field_names:
            if not min(c.isalnum() or c == "_" for c in name):
                raise ValueError(
                    "Type names and field names can only contain" " alphanumeric characters and underscores: %r" % name
                )
            if _iskeyword(name):
                raise ValueError("Type names and field names cannot be a" " keyword: %r" % name)
            if name[0].isdigit():
                raise ValueError("Type names and field names cannot start" " with a number: %r" % name)
        seen_names = set()
        for name in field_names:
            if name.startswith("_") and not rename:
                raise ValueError("Field names cannot start with an" " underscore: %r" % name)
            if name in seen_names:
                raise ValueError("Encountered duplicate field name: %r" % name)
            seen_names.add(name)

        # Create and fill-in the class template
        numfields = len(field_names)
        argtxt = repr(field_names).replace("'", "")[1:-1]
        reprtxt = ", ".join("%s=%%r" % name for name in field_names)
        template = (
            """class %(typename)s(tuple):
    '%(typename)s(%(argtxt)s)' \n
    __slots__ = () \n
    _fields = %(field_names)r \n
    def __new__(_cls, %(argtxt)s):
        return _tuple.__new__(_cls, (%(argtxt)s)) \n
    @classmethod
    def _make(cls, iterable, new=tuple.__new__, len=len):
        'Make a new %(typename)s object from a sequence or iterable'
        result = new(cls, iterable)
        if len(result) != %(numfields)d:
            raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
        return result \n
    def __repr__(self):
        return '%(typename)s(%(reprtxt)s)' %% self \n
    def _asdict(self):
        'Return a new dict which maps field names to their values'
        return dict(zip(self._fields, self)) \n
    def _replace(_self, **kwds):
        'Return a new %(typename)s object replacing specified fields with new values'
        result = _self._make(map(kwds.pop, %(field_names)r, _self))
        if kwds:
            raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
        return result \n
    def __getnewargs__(self):
        return tuple(self) \n\n"""
            % locals()
        )
        for i, name in enumerate(field_names):
            template += "    %s = _property(_itemgetter(%d))\n" % (name, i)
        if verbose:
            print template

        # Execute the template string in a temporary namespace
        namespace = dict(_itemgetter=_itemgetter, __name__="namedtuple_%s" % typename, _property=property, _tuple=tuple)
        try:
            exec template in namespace
        except SyntaxError, e:
            raise SyntaxError(e.message + ":\n" + template)
Пример #53
0
    def namedtuple(typename, field_names, verbose=False, rename=False):
        """A collections.namedtuple implementation written in Python
        to support Python versions < 2.6.

        Taken from: http://code.activestate.com/recipes/500261/
        """
        # Parse and validate the field names.  Validation serves two
        # purposes, generating informative error messages and preventing
        # template injection attacks.
        if isinstance(field_names, basestring):
             # names separated by whitespace and/or commas
            field_names = field_names.replace(',', ' ').split()
        field_names = tuple(map(str, field_names))
        if rename:
            names = list(field_names)
            seen = set()
            for i, name in enumerate(names):
                if (not min(c.isalnum() or c=='_' for c in name) or _iskeyword(name)
                    or not name or name[0].isdigit() or name.startswith('_')
                    or name in seen):
                        names[i] = '_%d' % i
                seen.add(name)
            field_names = tuple(names)
        for name in (typename,) + field_names:
            if not min(c.isalnum() or c=='_' for c in name):
                raise ValueError('Type names and field names can only contain ' \
                                 'alphanumeric characters and underscores: %r'
                                 % name)
            if _iskeyword(name):
                raise ValueError('Type names and field names cannot be a keyword: %r' \
                                 % name)
            if name[0].isdigit():
                raise ValueError('Type names and field names cannot start with a ' \
                                 'number: %r' % name)
        seen_names = set()
        for name in field_names:
            if name.startswith('_') and not rename:
                raise ValueError('Field names cannot start with an underscore: %r'
                                 % name)
            if name in seen_names:
                raise ValueError('Encountered duplicate field name: %r' % name)
            seen_names.add(name)

        # Create and fill-in the class template
        numfields = len(field_names)
        # tuple repr without parens or quotes
        argtxt = repr(field_names).replace("'", "")[1:-1]
        reprtxt = ', '.join('%s=%%r' % name for name in field_names)
        template = '''class %(typename)s(tuple):
        '%(typename)s(%(argtxt)s)' \n
        __slots__ = () \n
        _fields = %(field_names)r \n
        def __new__(_cls, %(argtxt)s):
            return _tuple.__new__(_cls, (%(argtxt)s)) \n
        @classmethod
        def _make(cls, iterable, new=tuple.__new__, len=len):
            'Make a new %(typename)s object from a sequence or iterable'
            result = new(cls, iterable)
            if len(result) != %(numfields)d:
                raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
            return result \n
        def __repr__(self):
            return '%(typename)s(%(reprtxt)s)' %% self \n
        def _asdict(self):
            'Return a new dict which maps field names to their values'
            return dict(zip(self._fields, self)) \n
        def _replace(_self, **kwds):
            'Return a new %(typename)s object replacing specified fields with new values'
            result = _self._make(map(kwds.pop, %(field_names)r, _self))
            if kwds:
                raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
            return result \n
        def __getnewargs__(self):
            return tuple(self) \n\n''' % locals()
        for i, name in enumerate(field_names):
            template += '        %s = _property(_itemgetter(%d))\n' % (name, i)
        if verbose:
            print template

        # Execute the template string in a temporary namespace
        namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
                         _property=property, _tuple=tuple)
        try:
            exec template in namespace
        except SyntaxError, e:
            raise SyntaxError(e.message + ':\n' + template)
Пример #54
0
def namedtuple(typename, field_names, verbose=False, rename=False):
    """Returns a new subclass of tuple with named fields.

    >>> Point = namedtuple('Point', 'x y')
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessable by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)

    """

    # Parse and validate the field names.  Validation serves two purposes,
    # generating informative error messages and preventing template injection attacks.
    if isinstance(field_names, str):
        field_names = field_names.replace(
            ',', ' ').split()  # names separated by whitespace and/or commas
    field_names = tuple(map(str, field_names))
    if rename:
        names = list(field_names)
        seen = set()
        for i, name in enumerate(names):
            if (not all(c.isalnum() or c == '_' for c in name)
                    or _iskeyword(name) or not name or name[0].isdigit()
                    or name.startswith('_') or name in seen):
                names[i] = '_%d' % i
            seen.add(name)
        field_names = tuple(names)
    for name in (typename, ) + field_names:
        if not all(c.isalnum() or c == '_' for c in name):
            raise ValueError(
                'Type names and field names can only contain alphanumeric characters and underscores: %r'
                % name)
        if _iskeyword(name):
            raise ValueError(
                'Type names and field names cannot be a keyword: %r' % name)
        if name[0].isdigit():
            raise ValueError(
                'Type names and field names cannot start with a number: %r' %
                name)
    seen_names = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError(
                'Field names cannot start with an underscore: %r' % name)
        if name in seen_names:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen_names.add(name)

    # Create and fill-in the class template
    numfields = len(field_names)
    argtxt = repr(field_names).replace(
        "'", "")[1:-1]  # tuple repr without parens or quotes
    reprtxt = ', '.join('%s=%%r' % name for name in field_names)
    template = '''class %(typename)s(tuple):
        '%(typename)s(%(argtxt)s)' \n
        __slots__ = () \n
        _fields = %(field_names)r \n
        def __new__(_cls, %(argtxt)s):
            return _tuple.__new__(_cls, (%(argtxt)s)) \n
        @classmethod
        def _make(cls, iterable, new=tuple.__new__, len=len):
            'Make a new %(typename)s object from a sequence or iterable'
            result = new(cls, iterable)
            if len(result) != %(numfields)d:
                raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
            return result \n
        def __repr__(self):
            return '%(typename)s(%(reprtxt)s)' %% self \n
        def _asdict(self):
            'Return a new OrderedDict which maps field names to their values'
            return OrderedDict(zip(self._fields, self)) \n
        def _replace(_self, **kwds):
            'Return a new %(typename)s object replacing specified fields with new values'
            result = _self._make(map(kwds.pop, %(field_names)r, _self))
            if kwds:
                raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
            return result \n
        def __getnewargs__(self):
            return tuple(self) \n\n''' % locals()
    for i, name in enumerate(field_names):
        template += '        %s = _property(_itemgetter(%d))\n' % (name, i)
    if verbose:
        print(template)

    # Execute the template string in a temporary namespace and
    # support tracing utilities by setting a value for frame.f_globals['__name__']
    namespace = dict(_itemgetter=_itemgetter,
                     __name__='namedtuple_%s' % typename,
                     OrderedDict=OrderedDict,
                     _property=property,
                     _tuple=tuple)
    try:
        exec(template, namespace)
    except SyntaxError as e:
        raise SyntaxError(e.msg + ':\n' + template) from e
    result = namespace[typename]

    # For pickling to work, the __module__ variable needs to be set to the frame
    # where the named tuple is created.  Bypass this step in enviroments where
    # sys._getframe is not defined (Jython for example) or sys._getframe is not
    # defined for arguments greater than 0 (IronPython).
    try:
        result.__module__ = _sys._getframe(1).f_globals.get(
            '__name__', '__main__')
    except (AttributeError, ValueError):
        pass

    return result
Пример #55
0
def struct(**kwargs):
    """Creates an immutable container using the keyword arguments as attributes.

    It can be used to group multiple values and/or functions together. Example:
        def _my_function():
          return 3
        s = struct(x = 2, foo = _my_function)
        return s.x + s.foo()  # returns 5

    The implementation is almost identical to namedtuple, but:
     - it does not forbid fields starting with underscores
     - does not implement methods for pickling
     - does not support copy/deepcopy
    """
    field_names = tuple(kwargs.keys())

    for name in field_names:
        if not all(c.isalnum() or c == "_" for c in name):
            raise ValueError(
                "Field names can only contain alphanumeric characters and underscores: %r"
                % name)
        if _iskeyword(name):
            raise ValueError("Field names cannot be a keyword: %r" % name)
        if name[0].isdigit():
            raise ValueError("Field names cannot start with a number: %r" %
                             name)

    # Variables used in the methods and docstrings
    arg_list = repr(field_names).replace("'", "")[1:-1]
    repr_fmt = "(" + ", ".join(name + "=%r" for name in field_names) + ")"
    tuple_new = tuple.__new__

    # Create all the named tuple methods to be added to the class namespace

    s = ("def __new__(_cls, " + arg_list + "): return _tuple_new(_cls, (" +
         arg_list + "))")
    namespace = {"_tuple_new": tuple_new, "__name__": _TYPENAME}
    # Note: exec() has the side-effect of interning the field names
    exec s in namespace
    __new__ = namespace["__new__"]

    def __repr__(self):
        """Return a nicely formatted representation string"""
        return self.__class__.__name__ + repr_fmt % self

    def _asdict(self):
        """Return a new OrderedDict which maps field names to their values."""
        return OrderedDict(zip(self._fields, self))

    def to_json(self):
        """Creates a JSON string representation of this struct instance."""
        return json.dumps(self,
                          cls=StructEncoder,
                          separators=(",", ":"),
                          sort_keys=True)

    # Build-up the class namespace dictionary
    # and use type() to build the result class
    class_namespace = {
        "__slots__": (),
        "_fields": field_names,
        "__new__": __new__,
        "__repr__": __repr__,
        "_asdict": _asdict,
        "to_json": to_json,
    }
    cache = _nt_itemgetters
    for index, name in enumerate(field_names):
        try:
            itemgetter_object = cache[index]
        except KeyError:
            itemgetter_object = _itemgetter(index)
            cache[index] = itemgetter_object
        class_namespace[name] = property(itemgetter_object)

    result = type(_TYPENAME, (tuple, ), class_namespace)

    return result(**kwargs)
Пример #56
0
def namedtuple(typename, field_names, verbose=False, rename=False):
    """Returns a new subclass of tuple with named fields.

    >>> Point = namedtuple('Point', ['x', 'y'])
    >>> Point.__doc__                   # docstring for the new class
    'Point(x, y)'
    >>> p = Point(11, y=22)             # instantiate with positional args or keywords
    >>> p[0] + p[1]                     # indexable like a plain tuple
    33
    >>> x, y = p                        # unpack like a regular tuple
    >>> x, y
    (11, 22)
    >>> p.x + p.y                       # fields also accessable by name
    33
    >>> d = p._asdict()                 # convert to a dictionary
    >>> d['x']
    11
    >>> Point(**d)                      # convert from a dictionary
    Point(x=11, y=22)
    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
    Point(x=100, y=22)

    """

    # Validate the field names.  At the user's option, either generate an error
    # message or automatically replace the field name with a valid name.
    if isinstance(field_names, basestring):
        field_names = field_names.replace(',', ' ').split()
    field_names = map(str, field_names)
    if rename:
        seen = set()
        for index, name in enumerate(field_names):
            if (not all(c.isalnum() or c=='_' for c in name)
                or _iskeyword(name)
                or not name
                or name[0].isdigit()
                or name.startswith('_')
                or name in seen):
                field_names[index] = '_%d' % index
            seen.add(name)
    for name in [typename] + field_names:
        if not all(c.isalnum() or c=='_' for c in name):
            raise ValueError('Type names and field names can only contain '
                             'alphanumeric characters and underscores: %r' % name)
        if _iskeyword(name):
            raise ValueError('Type names and field names cannot be a '
                             'keyword: %r' % name)
        if name[0].isdigit():
            raise ValueError('Type names and field names cannot start with '
                             'a number: %r' % name)
    seen = set()
    for name in field_names:
        if name.startswith('_') and not rename:
            raise ValueError('Field names cannot start with an underscore: '
                             '%r' % name)
        if name in seen:
            raise ValueError('Encountered duplicate field name: %r' % name)
        seen.add(name)

    # Fill-in the class template
    class_definition = _class_template.format(
        typename = typename,
        field_names = tuple(field_names),
        num_fields = len(field_names),
        arg_list = repr(tuple(field_names)).replace("'", "")[1:-1],
        repr_fmt = ', '.join(_repr_template.format(name=name)
                             for name in field_names),
        field_defs = '\n'.join(_field_template.format(index=index, name=name)
                               for index, name in enumerate(field_names))
    )
    if verbose:
        print class_definition

    # Execute the template string in a temporary namespace and support
    # tracing utilities by setting a value for frame.f_globals['__name__']
    namespace = newdict('module')
    namespace['__name__'] = 'namedtuple_%s' % typename
    namespace['OrderedDict'] = OrderedDict
    namespace['_property'] = property
    namespace['_tuple'] = tuple
    try:
        exec class_definition in namespace
    except SyntaxError as e:
        raise SyntaxError(e.message + ':\n' + class_definition)
    result = namespace[typename]

    # 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).
    try:
        result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass

    return result
Пример #57
0
    def _namedtuple(typename, field_names, verbose=False, rename=False):
        if isinstance(field_names, basestring):
            field_names = field_names.replace(',', ' ').split()
        field_names = tuple(map(str, field_names))
        if rename:
            names = list(field_names)
            seen = set()
            for i, name in enumerate(names):
                if (not min(c.isalnum() or c=='_' for c in name) or _iskeyword(name)
                    or not name or name[0].isdigit() or name.startswith('_')
                    or name in seen):
                        names[i] = '_%d' % i
                seen.add(name)
            field_names = tuple(names)
        for name in (typename,) + field_names:
            if not min(c.isalnum() or c=='_' for c in name):
                raise ValueError('Type names and field names can only contain'
                                 ' alphanumeric characters and underscores: %r' % name)
            if _iskeyword(name):
                raise ValueError('Type names and field names cannot be a'
                                 ' keyword: %r' % name)
            if name[0].isdigit():
                raise ValueError('Type names and field names cannot start'
                                 ' with a number: %r' % name)
        seen_names = set()
        for name in field_names:
            if name.startswith('_') and not rename:
                raise ValueError('Field names cannot start with an'
                                 ' underscore: %r' % name)
            if name in seen_names:
                raise ValueError('Encountered duplicate field name: %r' % name)
            seen_names.add(name)

        # Create and fill-in the class template
        numfields = len(field_names)
        argtxt = repr(field_names).replace("'", "")[1:-1]
        reprtxt = ', '.join('%s=%%r' % name for name in field_names)
        template = '''class %(typename)s(tuple):
    '%(typename)s(%(argtxt)s)' \n
    __slots__ = () \n
    _fields = %(field_names)r \n
    def __new__(_cls, %(argtxt)s):
        return _tuple.__new__(_cls, (%(argtxt)s)) \n
    @classmethod
    def _make(cls, iterable, new=tuple.__new__, len=len):
        'Make a new %(typename)s object from a sequence or iterable'
        result = new(cls, iterable)
        if len(result) != %(numfields)d:
            raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
        return result \n
    def __repr__(self):
        return '%(typename)s(%(reprtxt)s)' %% self \n
    def _asdict(self):
        'Return a new dict which maps field names to their values'
        return dict(zip(self._fields, self)) \n
    def _replace(_self, **kwds):
        'Return a new %(typename)s object replacing specified fields with new values'
        result = _self._make(map(kwds.pop, %(field_names)r, _self))
        if kwds:
            raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
        return result \n
    def __getnewargs__(self):
        return tuple(self) \n\n''' % locals()
        for i, name in enumerate(field_names):
            template += '    %s = _property(_itemgetter(%d))\n' % (name, i)
        if verbose:
            print template

        # Execute the template string in a temporary namespace
        namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
                         _property=property, _tuple=tuple)
        try:
            exec template in namespace
        except SyntaxError, e:
            raise SyntaxError(e.message + ':\n' + template)