glBufferSubData invalid operation in python

I have ‘Invalid Operation’ upon glBufferSubData in the RenderText function at the first iteration of RenderText from a Python 3.1.1 environment for windows:

	C:\Users\phill\PycharmProjects\rendertext\venv\Scripts\python.exe C:\Users\phill\PycharmProjects\rendertext\main_glfw.py 
	Traceback (most recent call last):
	  File "C:\Users\phill\PycharmProjects\rendertext\venv\Lib\site-packages\OpenGL\latebind.py", line 43, in __call__
		return self._finalCall( *args, **named )
			   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	TypeError: 'NoneType' object is not callable

	During handling of the above exception, another exception occurred:

	Traceback (most recent call last):
	  File "C:\Users\phill\PycharmProjects\rendertext\main_glfw.py", line 146, in <module>
		main()
	  File "C:\Users\phill\PycharmProjects\rendertext\main_glfw.py", line 133, in main
		RenderText(shader, 'This is sample text', 25.0, 25.0, 1.0, glm.vec3(0.5, 0.8, 0.2))
	  File "C:\Users\phill\PycharmProjects\rendertext\main_glfw.py", line 44, in RenderText
		glBufferSubData(GL_ARRAY_BUFFER, 0, len(vertices) * ctypes.sizeof(ctypes.c_float), dataArray)
	  File "C:\Users\phill\PycharmProjects\rendertext\venv\Lib\site-packages\OpenGL\latebind.py", line 63, in __call__
		return self.wrapperFunction( self.baseFunction, *args, **named )
			   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	  File "C:\Users\phill\PycharmProjects\rendertext\venv\Lib\site-packages\OpenGL\GL\VERSION\GL_1_5.py", line 125, in glBufferSubData
		return baseOperation( target, offset, size, data )
			   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	  File "C:\Users\phill\PycharmProjects\rendertext\venv\Lib\site-packages\OpenGL\latebind.py", line 47, in __call__
		return self._finalCall( *args, **named )
			   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	  File "C:\Users\phill\PycharmProjects\rendertext\venv\Lib\site-packages\OpenGL\wrapper.py", line 700, in wrapperCall
		raise err
	  File "C:\Users\phill\PycharmProjects\rendertext\venv\Lib\site-packages\OpenGL\wrapper.py", line 693, in wrapperCall
		result = wrappedOperation( *cArguments )
				 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	  File "C:\Users\phill\PycharmProjects\rendertext\venv\Lib\site-packages\OpenGL\platform\baseplatform.py", line 415, in __call__
		return self( *args, **named )
			   ^^^^^^^^^^^^^^^^^^^^^^
	  File "C:\Users\phill\PycharmProjects\rendertext\venv\Lib\site-packages\OpenGL\error.py", line 230, in glCheckError
		raise self._errorClass(
	OpenGL.error.GLError: GLError(
		err = 1282,
		description = b'invalid operation',
		baseOperation = glBufferSubData,
		pyArgs = (
			GL_ARRAY_BUFFER,
			0,
			96,
			<__main__.c_float_Array_24 object at 0x0000014C334FE2D0>,
		),
		cArgs = (
			GL_ARRAY_BUFFER,
			0,
			96,
			<__main__.c_float_Array_24 object at 0x0000014C334FE2D0>,
		),
		cArguments = (
			GL_ARRAY_BUFFER,
			0,
			96,
			<__main__.c_float_Array_24 object at 0x0000014C334FE2D0>,
		)
	)

	Process finished with exit code 1

For the code:

	import glfw
	from includes.learnopengl.shader import Shader
	from Character import Character
	import glm
	from OpenGL.GL import *
	import freetype


class Character:
    def __init__(self):
        self.TextureID = 0
        self.Size = glm.vec2(0.0, 0.0)
        self.Bearing = glm.vec2(0.0, 0.0)
        self.Advance = 0.0
        # print('Character()')
	    screen_width = 800
	    screen_height = 600
	    character_list = []
	    VAO = 0
	    VBO = 0

	def RenderText(shader, text, x, y, scale, color):
		shader.use();
		glUniform3f(glGetUniformLocation(shader.ID, "textColor"), color.x, color.y, color.z)
		glActiveTexture(GL_TEXTURE0);
		glBindVertexArray(VAO);

		for c in text:
			# print('drawtext....')
			cc = ord(c)
			ch = character_list[int(cc)]
			# ch = character_list.get
			xpos = x + ch.Bearing.x * scale
			ypos = y - (ch.Size.y - ch.Bearing.y) * scale

			w = ch.Size.x * scale
			h = ch.Size.y * scale

			vertices = [
								 xpos, ypos + h, 0.0, 0.0,
								 xpos, ypos, 0.0, 1.0,
								 xpos + w, ypos, 1.0, 1.0,

								 xpos, ypos + h, 0.0, 0.0,
								 xpos + w, ypos, 1.0, 1.0,
								 xpos + w, ypos + h, 1.0, 0.0
								 ]
			glBindTexture(GL_TEXTURE_2D, ch.TextureID)

			glBindBuffer(GL_ARRAY_BUFFER, VBO)
			dataArray = (GLfloat * len(vertices))(*vertices)
			glBufferSubData(GL_ARRAY_BUFFER, 0, len(vertices) * ctypes.sizeof(ctypes.c_float), dataArray)
			glBindBuffer(GL_ARRAY_BUFFER, 0)
			glDrawArrays(GL_TRIANGLES, 0, 6)
			x += (ch.Advance >> 6) * scale

		glBindVertexArray(0);
		glBindTexture(GL_TEXTURE_2D, 0);
		print('Done...')

	def main():
		# Initialize the library
		if not glfw.init():
			return
		# Create a windowed mode window and its OpenGL context
		window = glfw.create_window(screen_width, screen_height, "Hello World", None, None)


		if not window:
			glfw.terminate()
			return

		# Make the window's context current
		glfw.make_context_current(window)
		shader = Shader('text.vs', 'text.fs')
		projection = glm.ortho(0, screen_width, 0, screen_height)
		shader.use()
		glUniformMatrix4fv(glGetUniformLocation(shader.ID, "projection"), 1, GL_FALSE, glm.value_ptr(projection))

		for i in range(128):
			c = Character()
			face = freetype.Face("arial.ttf")
			face.set_char_size((48 * 2) * (64 * 2))
			face.load_char(i, freetype.FT_LOAD_RENDER |
						   freetype.FT_LOAD_TARGET_NORMAL)
			bitmap = face.glyph.bitmap


			texture = glGenTextures(1)
			glBindTexture(GL_TEXTURE_2D, texture);
			glTexImage2D(
				GL_TEXTURE_2D,
				0,
				GL_RED,
				face.glyph.bitmap.width,
				face.glyph.bitmap.rows,
				0,
				GL_RED,
				GL_UNSIGNED_BYTE,
				face.glyph.bitmap.buffer
			)

			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)

			c.TextureID = texture
			c.Size = glm.vec2(bitmap.width, bitmap.rows)
			c.Bearing = glm.vec2(face.glyph.bitmap_left, face.glyph.bitmap_top)
			c.Advance = face.glyph.advance.x
			character_list.append(c)
			# print('ASCII')

		VAO = glGenVertexArrays(1)
		VBO = glGenBuffers(1)
		glBindVertexArray(VAO)
		glBindBuffer(GL_ARRAY_BUFFER, VBO)
		glBufferData(GL_ARRAY_BUFFER, ctypes.sizeof(ctypes.c_float) * 6 * 4, None, GL_DYNAMIC_DRAW)
		glEnableVertexAttribArray(0)
		glVertexAttribPointer(
			0,  # attribute 0.
			3,  # components per vertex attribute
			GL_FLOAT,  # type
			False,  # to be normalized?
			0,  # stride
			None  # array buffer offset
		)
		glBindBuffer(GL_ARRAY_BUFFER, 0)
		glBindVertexArray(0)

		# Loop until the user closes the window
		while not glfw.window_should_close(window):
			# Render here, e.g. using pyOpenGL
			# processInput(window);


			glClearColor(0.2, 0.3, 0.3, 1.0);
			glClear(GL_COLOR_BUFFER_BIT);

			RenderText(shader, 'This is sample text', 25.0, 25.0, 1.0, glm.vec3(0.5, 0.8, 0.2))
			RenderText(shader, '(C) LearnOpenGL.com', 540.0, 570.0, 0.5, glm.vec3(0.3, 0.7, 0.9))

			# Swap front and back buffers
			glfw.swap_buffers(window)

			# Poll for and process events
			glfw.poll_events()

		glfw.terminate()


	if __name__ == "__main__":
		main()

For some reason the glBufferSubData is throwing an invalid operation exception. I checked the glAttributePointer and glBufferSubData looked right to me so far but
I don’t discount maybe some problemt there. Does anyone know how to get the invalid operation exception to go away so I can get the characters drawing?

The shader class is from:

The global variable VAO is equal to zero inside RenderText(). The main() function assigns to a local variable named VAO; you need a global statement if you want to modify a global variable from within a function. But it’s more common to put global state into an object whose members can then be modified.

OK. Thank you for pointing that out. I am coming over from C++ so I have some situations to work out how they play out with Python. I had better luck with numpy syntax.