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: Set the vertex and fragment shaders.
  
  Parameters
  ----------
  vert : str
      Source code for vertex shader.
  frag : str
      Source code for fragment shaders.
  geom : str (optional)
      Source code for geometry shader.
  update_variables : bool
      If True, then process any pending variables immediately after
      setting shader code. Default is True.
docstr_tok: ["Set","the","vertex","and","fragment","shaders",".","Parameters","--","--","--","--","--","vert",":","str","Source","code","for","vertex","shader",".","frag",":","str","Source","code","for","fragment","shaders",".","geom",":","str","(","optional",")","Source","code","for","geometry","shader",".","update_variables",":","bool","If","True",",","then","process","any","pending","variables","immediately","after","setting","shader","code",".","Default","is","True","."]
code: def set_shaders(self, vert, frag, geom=None, update_variables=True):
      """Set the vertex and fragment shaders.
  
      Parameters
      ----------
      vert : str
          Source code for vertex shader.
      frag : str
          Source code for fragment shaders.
      geom : str (optional)
          Source code for geometry shader.
      update_variables : bool
          If True, then process any pending variables immediately after
          setting shader code. Default is True.
      """
      if not vert or not frag:
          raise ValueError(
              "Vertex and fragment code must both be non-empty"
          )
  
      # pre-process shader code for #include directives
      shaders = [VertexShader(vert), FragmentShader(frag)]
      if geom is not None:
          shaders.append(GeometryShader(geom))
  
      for shader in shaders:
          self.glir.associate(shader.glir)
          self._glir.command("ATTACH", self._id, shader.id)
  
      # Store source code, send it to glir, parse the code for variables
      self._shaders = shaders
  
      # Link all shaders into one program. All shaders are detached after
      # linking is complete.
      self._glir.command("LINK", self._id)
  
      # Delete shaders. We no longer need them and it frees up precious GPU
      # memory: http://gamedev.stackexchange.com/questions/47910
      for shader in shaders:
          shader.delete()
  
      # All current variables become pending variables again
      for key, val in self._user_variables.items():
          self._pending_variables[key] = val
      self._user_variables = {}
      # Parse code (and process pending variables)
      self._parse_variables_from_code(update_variables=update_variables)
  
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 2 for calling the Program obj's underlying member method code with example usage: obj.set_shaders(vert, frag, geom, update_variables) without return types