class_docstr: Shader program object
  
  A Program is an object to which shaders can be attached and linked to
  create the final program.
  
  Uniforms and attributes can be set using indexing: e.g.
  ``program['a_pos'] = pos_data`` and ``program['u_color'] = (1, 0, 0)``.
  
  Parameters
  ----------
  vert : str
      The vertex shader to be used by this program
  frag : str
      The fragment shader to be used by this program
  count : int (optional)
      The program will prepare a structured vertex buffer of count
      vertices. All attributes set using ``prog['attr'] = X`` will
      be combined into a structured vbo with interleaved elements, which
      is more efficient than having one vbo per attribute.
  
  Notes
  -----
  If several shaders are specified, only one can contain the main
  function. OpenGL ES 2.0 does not support a list of shaders.
class_docstr_tok: ["Shader","program","object","A","Program","is","an","object","to","which","shaders","can","be","attached","and","linked","to","create","the","final","program",".","Uniforms","and","attributes","can","be","set","using","indexing",":","e.g",".","``","program","[","'a_pos","'","]","=","pos_data","``","and","``","program","[","'u_color","'","]","=","(","1",",","0",",","0",")","``",".","Parameters","--","--","--","--","--","vert",":","str","The","vertex","shader","to","be","used","by","this","program","frag",":","str","The","fragment","shader","to","be","used","by","this","program","count",":","int","(","optional",")","The","program","will","prepare","a","structured","vertex","buffer","of","count","vertices",".","All","attributes","set","using","``","prog","[","'attr","'","]","=","X","``","will","be","combined","into","a","structured","vbo","with","interleaved","elements",",","which","is","more","efficient","than","having","one","vbo","per","attribute",".","Notes","--","--","-","If","several","shaders","are","specified",",","only","one","can","contain","the","main","function",".","OpenGL","ES","2.0","does","not","support","a","list","of","shaders","."]
docstr: Setting uniform or attribute data
  
  This method requires the information about the variable that we
  know from parsing the source code. If this information is not
  yet available, the data is stored in a list of pending data,
  and we attempt to set it once new shading code has been set.
  
  For uniforms, the data can represent a plain uniform or a
  sampler. In the latter case, this method accepts a Texture
  object or a numpy array which is used to update the existing
  texture. A new texture is created if necessary.
  
  For attributes, the data can be a tuple/float which GLSL will
  use for the value of all vertices. This method also acceps VBO
  data as a VertexBuffer object or a numpy array which is used
  to update the existing VertexBuffer. A new VertexBuffer is
  created if necessary.
  
  By passing None as data, the uniform or attribute can be
  "unregistered". This can be useful to get rid of variables that
  are no longer present or active in the new source code that is
  about to be set.
docstr_tok: ["Setting","uniform","or","attribute","data","This","method","requires","the","information","about","the","variable","that","we","know","from","parsing","the","source","code",".","If","this","information","is","not","yet","available",",","the","data","is","stored","in","a","list","of","pending","data",",","and","we","attempt","to","set","it","once","new","shading","code","has","been","set",".","For","uniforms",",","the","data","can","represent","a","plain","uniform","or","a","sampler",".","In","the","latter","case",",","this","method","accepts","a","Texture","object","or","a","numpy","array","which","is","used","to","update","the","existing","texture",".","A","new","texture","is","created","if","necessary",".","For","attributes",",","the","data","can","be","a","tuple\/float","which","GLSL","will","use","for","the","value","of","all","vertices",".","This","method","also","acceps","VBO","data","as","a","VertexBuffer","object","or","a","numpy","array","which","is","used","to","update","the","existing","VertexBuffer",".","A","new","VertexBuffer","is","created","if","necessary",".","By","passing","None","as","data",",","the","uniform","or","attribute","can","be","''","unregistered","''",".","This","can","be","useful","to","get","rid","of","variables","that","are","no","longer","present","or","active","in","the","new","source","code","that","is","about","to","be","set","."]
code: def __setitem__(self, name, data):
      """Setting uniform or attribute data
  
      This method requires the information about the variable that we
      know from parsing the source code. If this information is not
      yet available, the data is stored in a list of pending data,
      and we attempt to set it once new shading code has been set.
  
      For uniforms, the data can represent a plain uniform or a
      sampler. In the latter case, this method accepts a Texture
      object or a numpy array which is used to update the existing
      texture. A new texture is created if necessary.
  
      For attributes, the data can be a tuple/float which GLSL will
      use for the value of all vertices. This method also acceps VBO
      data as a VertexBuffer object or a numpy array which is used
      to update the existing VertexBuffer. A new VertexBuffer is
      created if necessary.
  
      By passing None as data, the uniform or attribute can be
      "unregistered". This can be useful to get rid of variables that
      are no longer present or active in the new source code that is
      about to be set.
      """
      # Deal with local buffer storage (see count argument in __init__)
      if (self._buffer is not None) and not isinstance(
          data, DataBuffer
      ):
          if name in self._buffer.dtype.names:
              self._buffer[name] = data
              return
  
      # Forget any pending values for this variable
      self._pending_variables.pop(name, None)
  
      # Delete?
      if data is None:
          self._user_variables.pop(name, None)
          return
  
      if name in self._code_variables:
          kind, type_, name, size = self._code_variables[name]
  
          if kind == "uniform":
              if type_.startswith("sampler"):
                  # Texture data; overwrite or update
                  tex = self._user_variables.get(name, None)
                  if isinstance(data, BaseTexture):
                      pass
                  elif tex and hasattr(tex, "set_data"):
                      tex.set_data(data)
                      return
                  elif type_ == "sampler1D":
                      data = Texture1D(data)
                  elif type_ == "sampler2D":
                      data = Texture2D(data)
                  elif type_ == "sampler3D":
                      data = Texture3D(data)
                  elif type_ == "samplerCube":
                      data = TextureCube(data)
                  else:
                      # This should not happen
                      raise RuntimeError("Unknown type %s" % type_)
                  # Store and send GLIR command
                  self._user_variables[name] = data
                  self.glir.associate(data.glir)
                  self._glir.command("TEXTURE", self._id, name, data.id)
              else:
                  # Normal uniform; convert to np array and check size
                  dtype, numel = self._gtypes[type_]
                  data = np.array(data, dtype=dtype).ravel()
                  if data.size != numel:
                      raise ValueError(
                          "Uniform %r needs %i elements, "
                          "not %i." % (name, numel, data.size)
                      )
                  # Store and send GLIR command
                  self._user_variables[name] = data
                  self._glir.command(
                      "UNIFORM", self._id, name, type_, data
                  )
  
          elif kind == "uniform_array":
              # Normal uniform; convert to np array and check size
              dtype, numel = self._gtypes[type_]
              data = np.atleast_2d(data).astype(dtype)
              need_shape = (size, numel)
              if data.shape != need_shape:
                  raise ValueError(
                      "Uniform array %r needs shape %s not %s"
                      % (name, need_shape, data.shape)
                  )
              data = data.ravel()
              # Store and send GLIR command
              self._user_variables[name] = data
              self._glir.command("UNIFORM", self._id, name, type_, data)
  
          elif kind == "attribute":
              # Is this a constant value per vertex
              is_constant = False
  
              def isscalar(x):
                  return isinstance(x, (float, int))
  
              if isscalar(data):
                  is_constant = True
              elif isinstance(data, (tuple, list)):
                  is_constant = all([isscalar(e) for e in data])
  
              if not is_constant:
                  # VBO data; overwrite or update
                  vbo = self._user_variables.get(name, None)
                  if isinstance(data, DataBuffer):
                      pass
                  elif vbo is not None and hasattr(vbo, "set_data"):
                      vbo.set_data(data)
                      return
                  else:
                      data = VertexBuffer(data)
                  # Store and send GLIR command
                  if data.dtype is not None:
                      numel = self._gtypes[type_][1]
                      if data._last_dim and data._last_dim != numel:
                          raise ValueError(
                              "data.shape[-1] must be %s "
                              "not %s for %s"
                              % (numel, data._last_dim, name)
                          )
                  divisor = getattr(data, "divisor", None)
                  self._user_variables[name] = data
                  value = (data.id, data.stride, data.offset)
                  self.glir.associate(data.glir)
                  self._glir.command(
                      "ATTRIBUTE", self._id, name, type_, value, divisor
                  )
              else:
                  # Single-value attribute; convert to array and check size
                  dtype, numel = self._gtypes[type_]
                  data = np.array(data, dtype=dtype)
                  if data.ndim == 0:
                      data.shape = data.size
                  if data.size != numel:
                      raise ValueError(
                          "Attribute %r needs %i elements, "
                          "not %i." % (name, numel, data.size)
                      )
                  divisor = getattr(data, "divisor", None)
                  # Store and send GLIR command
                  self._user_variables[name] = data
                  value = tuple([0] + [i for i in data])
                  self._glir.command(
                      "ATTRIBUTE", self._id, name, type_, value, divisor
                  )
          else:
              raise KeyError("Cannot set data for a %s." % kind)
      else:
          # This variable is not defined in the current source code,
          # so we cannot establish whether this is a uniform or
          # attribute, nor check its type. Try again later.
          self._pending_variables[name] = data
  
imports: import re
  import numpy
  from .globject import GLObject
  from .buffer import VertexBuffer, IndexBuffer, DataBuffer
  from .texture import BaseTexture, Texture2D, Texture3D, Texture1D, TextureCube
  from ..util import logger
  from .util import check_enum
  from .context import get_current_canvas
  from .preprocessor import preprocess
label_desc: Use image node_id 8 for calling the Program obj's underlying member method code with example usage: obj.__setitem__(name, data) and returns: isinstance