docs: 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