PyOpenGL-accelerate 4.0.0a4__tar.gz → 4.0.0a7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. pyopengl_accelerate-4.0.0a7/MANIFEST.in +25 -0
  2. pyopengl_accelerate-4.0.0a7/OpenGL_accelerate/__init__.py +21 -0
  3. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/PKG-INFO +18 -2
  4. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/PyOpenGL_accelerate.egg-info/PKG-INFO +18 -2
  5. pyopengl_accelerate-4.0.0a7/PyOpenGL_accelerate.egg-info/requires.txt +1 -0
  6. pyopengl_accelerate-4.0.0a7/README.md +31 -0
  7. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/pyproject.toml +6 -0
  8. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/setup.py +98 -7
  9. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/arraydatatype.pyx +35 -1
  10. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/buffers_formathandler.pyx +16 -4
  11. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/c/generated/pygl_GL.c +474 -474
  12. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/c/generated/pygl_GLES1.c +44 -44
  13. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/c/generated/pygl_GLES2.c +119 -119
  14. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/c/generated/pygl_GLES3.c +62 -62
  15. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/c/generated/pygl_GLSC2.c +14 -14
  16. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/c/pygl_runtime.c +140 -29
  17. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/vbo.pyx +6 -2
  18. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/wrapper.pyx +16 -4
  19. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/tests/test_arraydatatypeaccel.py +17 -8
  20. pyopengl_accelerate-4.0.0a4/MANIFEST.in +0 -4
  21. pyopengl_accelerate-4.0.0a4/OpenGL_accelerate/__init__.py +0 -11
  22. pyopengl_accelerate-4.0.0a4/PyOpenGL_accelerate.egg-info/requires.txt +0 -1
  23. pyopengl_accelerate-4.0.0a4/README.md +0 -15
  24. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/OpenGL_accelerate/formathandler.pxd +0 -0
  25. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/OpenGL_accelerate/wrapper.pxd +0 -0
  26. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/PyOpenGL_accelerate.egg-info/SOURCES.txt +0 -0
  27. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/PyOpenGL_accelerate.egg-info/dependency_links.txt +0 -0
  28. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/PyOpenGL_accelerate.egg-info/top_level.txt +0 -0
  29. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/license.txt +0 -0
  30. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/setup.cfg +0 -0
  31. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/c/generated/pygl_EGL.c +0 -0
  32. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/c/generated/pygl_GLX.c +0 -0
  33. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/c/generated/pygl_WGL.c +0 -0
  34. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/c/generated/pygl_generated.c +0 -0
  35. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/c/generated/pygl_modules.c +0 -0
  36. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/c/pygl_handwritten.c +0 -0
  37. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/errorchecker.pyx +0 -0
  38. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/formathandler.pyx +0 -0
  39. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/latebind.pyx +0 -0
  40. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/nones_formathandler.pyx +0 -0
  41. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/src/numpy_formathandler.pyx +0 -0
  42. {pyopengl_accelerate-4.0.0a4 → pyopengl_accelerate-4.0.0a7}/tests/test_numpyaccel.py +0 -0
@@ -0,0 +1,25 @@
1
+ # The sources an install builds from.
2
+ include src/*.pyx
3
+ include OpenGL_accelerate/*.pxd
4
+ include license.txt
5
+
6
+ # `exclude`, not merely "not included": setuptools puts every extension
7
+ # `sources` entry into the archive by itself, and `cythonize` rewrites those
8
+ # entries from the .pyx to the .c it generated. So the C arrives without
9
+ # anything here asking for it, and has to be taken back out.
10
+ exclude src/*.c
11
+
12
+ # NOT `include src/*.c`: that is Cython's output from the .pyx beside it, and
13
+ # Cython is a hard build requirement of this package (see [build-system]), so
14
+ # every install from this archive writes that C itself. `setup.py`'s
15
+ # `drop_c_from_another_toolchain` deletes any that arrived, because the
16
+ # archive carries no toolchain stamp for it to match against -- so shipping it
17
+ # is weight that is deleted on arrival, with a hazard attached: stale
18
+ # generated C is what fails to compile against a numpy it was not written for,
19
+ # reporting an error inside a numpy header that names nothing in this package.
20
+ # See https://github.com/mcfletch/pyopengl/issues/121
21
+ #
22
+ # `src/c/**` is a different thing and is shipped: the dispatch layer generated
23
+ # from the Khronos registry by a tool that does not run at install time and is
24
+ # not distributed. setup.py names those as extension sources, which is what
25
+ # puts them in the archive.
@@ -0,0 +1,21 @@
1
+ """Cython-coded accelerators for the PyOpenGL wrapper
2
+
3
+ This package contains Cython accelerator modules which
4
+ attempt to speed up certain aspects of the PyOpenGL 3.x
5
+ wrapper mechanism. The source code is part of the
6
+ PyOpenGL package and is built via the setupaccel.py
7
+ script in the top level of the PyOpenGL source package.
8
+ """
9
+
10
+ import re as _re
11
+
12
+ #: The version this was built as, which is also the PyOpenGL it pairs with:
13
+ #: the two share generated tables, the dependency is pinned to this number,
14
+ #: and the extension refuses a PyOpenGL stating another. A release bumps
15
+ #: both this and ``OpenGL/version.py``.
16
+ __version__ = "4.0.0a7"
17
+ #: The numeric release ``__version__`` names, without a pre-release marker,
18
+ #: which ``OpenGL.acceleratesupport`` compares with its floor.
19
+ __version_tuple__ = tuple(
20
+ int(part) for part in _re.match(r'(\d+)\.(\d+)\.(\d+)', __version__).groups()
21
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyOpenGL-accelerate
3
- Version: 4.0.0a4
3
+ Version: 4.0.0a7
4
4
  Summary: Cython-coded accelerators for PyOpenGL
5
5
  Home-page: http://pyopengl.sourceforge.net
6
6
  Download-URL: http://sourceforge.net/project/showfiles.php?group_id=5988
@@ -24,7 +24,7 @@ Classifier: Intended Audience :: Developers
24
24
  Requires-Python: >=3.9
25
25
  Description-Content-Type: text/markdown
26
26
  License-File: license.txt
27
- Requires-Dist: PyOpenGL==4.0.0a4
27
+ Requires-Dist: PyOpenGL==4.0.0a7
28
28
  Dynamic: download-url
29
29
  Dynamic: license-file
30
30
  Dynamic: requires-dist
@@ -35,6 +35,22 @@ This set of C (Cython) extensions provides acceleration of common operations
35
35
  for slow points in PyOpenGL 3.x. It is not a requirement for using PyOpenGL
36
36
  but performance without it will be poor.
37
37
 
38
+ ## The PyOpenGL it pairs with
39
+
40
+ `PyOpenGL_accelerate` and `PyOpenGL` are released together, carry the same
41
+ version number, and have to be equal. They share the dispatch extension's
42
+ generated tables, where the slot numbering of one release is meaningless to
43
+ another, so this package requires the exact `PyOpenGL` it was built against:
44
+
45
+ pip install PyOpenGL PyOpenGL_accelerate
46
+
47
+ Installing or upgrading `PyOpenGL_accelerate` brings the matching `PyOpenGL`
48
+ with it. Upgrading `PyOpenGL` on its own does not go the other way — it leaves
49
+ the older accelerate installed — so name both packages when you upgrade either.
50
+ A pair that has come apart is refused when the first entry point is built, in a
51
+ message naming both versions; `PYOPENGL_USE_ACCELERATE=0` in the environment
52
+ runs on ctypes until it is put right.
53
+
38
54
  ## Build Process
39
55
 
40
56
  Cython is updated frequently to support newer versions of Python. As of
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyOpenGL-accelerate
3
- Version: 4.0.0a4
3
+ Version: 4.0.0a7
4
4
  Summary: Cython-coded accelerators for PyOpenGL
5
5
  Home-page: http://pyopengl.sourceforge.net
6
6
  Download-URL: http://sourceforge.net/project/showfiles.php?group_id=5988
@@ -24,7 +24,7 @@ Classifier: Intended Audience :: Developers
24
24
  Requires-Python: >=3.9
25
25
  Description-Content-Type: text/markdown
26
26
  License-File: license.txt
27
- Requires-Dist: PyOpenGL==4.0.0a4
27
+ Requires-Dist: PyOpenGL==4.0.0a7
28
28
  Dynamic: download-url
29
29
  Dynamic: license-file
30
30
  Dynamic: requires-dist
@@ -35,6 +35,22 @@ This set of C (Cython) extensions provides acceleration of common operations
35
35
  for slow points in PyOpenGL 3.x. It is not a requirement for using PyOpenGL
36
36
  but performance without it will be poor.
37
37
 
38
+ ## The PyOpenGL it pairs with
39
+
40
+ `PyOpenGL_accelerate` and `PyOpenGL` are released together, carry the same
41
+ version number, and have to be equal. They share the dispatch extension's
42
+ generated tables, where the slot numbering of one release is meaningless to
43
+ another, so this package requires the exact `PyOpenGL` it was built against:
44
+
45
+ pip install PyOpenGL PyOpenGL_accelerate
46
+
47
+ Installing or upgrading `PyOpenGL_accelerate` brings the matching `PyOpenGL`
48
+ with it. Upgrading `PyOpenGL` on its own does not go the other way — it leaves
49
+ the older accelerate installed — so name both packages when you upgrade either.
50
+ A pair that has come apart is refused when the first entry point is built, in a
51
+ message naming both versions; `PYOPENGL_USE_ACCELERATE=0` in the environment
52
+ runs on ctypes until it is put right.
53
+
38
54
  ## Build Process
39
55
 
40
56
  Cython is updated frequently to support newer versions of Python. As of
@@ -0,0 +1 @@
1
+ PyOpenGL==4.0.0a7
@@ -0,0 +1,31 @@
1
+ # Acceleration code for PyOpenGL
2
+
3
+ This set of C (Cython) extensions provides acceleration of common operations
4
+ for slow points in PyOpenGL 3.x. It is not a requirement for using PyOpenGL
5
+ but performance without it will be poor.
6
+
7
+ ## The PyOpenGL it pairs with
8
+
9
+ `PyOpenGL_accelerate` and `PyOpenGL` are released together, carry the same
10
+ version number, and have to be equal. They share the dispatch extension's
11
+ generated tables, where the slot numbering of one release is meaningless to
12
+ another, so this package requires the exact `PyOpenGL` it was built against:
13
+
14
+ pip install PyOpenGL PyOpenGL_accelerate
15
+
16
+ Installing or upgrading `PyOpenGL_accelerate` brings the matching `PyOpenGL`
17
+ with it. Upgrading `PyOpenGL` on its own does not go the other way — it leaves
18
+ the older accelerate installed — so name both packages when you upgrade either.
19
+ A pair that has come apart is refused when the first entry point is built, in a
20
+ message naming both versions; `PYOPENGL_USE_ACCELERATE=0` in the environment
21
+ runs on ctypes until it is put right.
22
+
23
+ ## Build Process
24
+
25
+ Cython is updated frequently to support newer versions of Python. As of
26
+ release 3.1.9 we no longer check in the Cython generated code for the
27
+ wrapper modules, relying on the build machines to generate the wrappers.
28
+
29
+ The Github CI Pipeline should generate and release binary builds for most
30
+ major platforms (Windows, Linux, Mac), but if you need to build from source,
31
+ a `pip install .` **should** work from the PyOpenGL repository.
@@ -70,3 +70,9 @@ cache-keys = [
70
70
  { file = "setup.py" },
71
71
  { file = "OpenGL_accelerate/__init__.py" },
72
72
  ]
73
+
74
+ [tool.openglcontext-checks]
75
+ # The OGC rules (openglcontext-checks) this project is held to by the
76
+ # workspace preflight: every rule there is, each named, so a rule added
77
+ # later joins when the project is clean of it.
78
+ select = ["OGC121", "OGC131", "OGC141", "OGC161", "OGC201", "OGC221", "OGC222", "OGC223"]
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env python
2
2
  """Builds accelleration functions for PyOpenGL
3
3
  """
4
- import sys
5
4
  from setuptools import setup, Extension
6
5
 
7
6
  try:
@@ -53,6 +52,43 @@ def pyopengl_requirement():
53
52
  return 'PyOpenGL==%s' % (_our_version(),)
54
53
 
55
54
 
55
+ VERSION_HEADER = 'src/c/generated/pygl_version.h'
56
+
57
+
58
+ def write_version_header():
59
+ """State the version in a header, and answer where it was written.
60
+
61
+ The extension reports at import which PyOpenGL its tables came from, so
62
+ that number has to reach the C. A ``-D`` on the command line would too,
63
+ but a compiler driver's flags are not something the build compares against
64
+ an object file it already has: bump the version, and the existing
65
+ ``pygl_runtime.o`` is still newer than every source and header, so it is
66
+ linked as it stands and the new build announces the old version. A header
67
+ is compared, being in ``depends``, so a bump recompiles what includes it.
68
+
69
+ Rewritten only when the contents change, so an unchanged version does not
70
+ invalidate the objects on every build.
71
+ """
72
+ path = os.path.join(HERE, VERSION_HEADER)
73
+ contents = (
74
+ '/* Written by accelerate\'s setup.py from OpenGL_accelerate.__version__.\n'
75
+ ' * The pair is released together and carries one number, so this is\n'
76
+ ' * the PyOpenGL whose generated tables this extension holds. */\n'
77
+ '#define PYOPENGL_VERSION "%s"\n' % (_our_version(),)
78
+ )
79
+ try:
80
+ with open(path, encoding='utf-8') as handle:
81
+ if handle.read() == contents:
82
+ return VERSION_HEADER
83
+ except OSError:
84
+ pass
85
+ os.makedirs(os.path.dirname(path), exist_ok=True)
86
+ with open(path + '.partial', 'w', encoding='utf-8') as handle:
87
+ handle.write(contents)
88
+ os.replace(path + '.partial', path)
89
+ return VERSION_HEADER
90
+
91
+
56
92
  def dispatch_extension():
57
93
  """The registry-generated C implementation of the OpenGL entry points.
58
94
 
@@ -94,18 +130,16 @@ def dispatch_extension():
94
130
  'src/c/pygl.h',
95
131
  'src/c/generated/pygl_elements.h',
96
132
  'src/c/generated/pygl_glgets.h',
133
+ # Says which PyOpenGL these tables were generated from, so that a
134
+ # mismatched pair is refused with a sentence rather than dispatching
135
+ # through the wrong slot indices.
136
+ write_version_header(),
97
137
  ]
98
138
  return [
99
139
  Extension(
100
140
  'OpenGL_accelerate.dispatch',
101
141
  sources=sources,
102
142
  include_dirs=['src/c', 'src/c/generated'],
103
- # The extension states which PyOpenGL its tables were generated
104
- # from, so that a mismatched pair is refused with a sentence rather
105
- # than dispatching through the wrong slot indices. The two are
106
- # released together and carry the same number, so this is the
107
- # accelerate version.
108
- define_macros=[('PYOPENGL_VERSION', '"%s"' % (_our_version(),))],
109
143
  depends=[
110
144
  path for path in headers if os.path.exists(os.path.join(HERE, path))
111
145
  ],
@@ -121,6 +155,59 @@ def dispatch_extension():
121
155
  extensions.extend(dispatch_extension())
122
156
 
123
157
 
158
+ #: Where the toolchain the generated C was written against is recorded.
159
+ TOOLCHAIN_STAMP = os.path.join(HERE, 'src', '.cython-toolchain')
160
+
161
+
162
+ def _toolchain():
163
+ """Cython and numpy as the generated C sees them: version strings.
164
+
165
+ numpy is in here because these modules ``cimport numpy``, and what that
166
+ expands to is numpy's own declarations rather than anything in this
167
+ package.
168
+ """
169
+ from Cython import __version__ as cython_version
170
+
171
+ try:
172
+ from numpy import __version__ as numpy_version
173
+ except ImportError: # the numpy extension is skipped
174
+ numpy_version = 'none'
175
+ return 'cython %s\nnumpy %s\n' % (cython_version, numpy_version)
176
+
177
+
178
+ def drop_c_from_another_toolchain():
179
+ """Delete generated C that a different Cython or numpy wrote.
180
+
181
+ ``cythonize`` decides whether to rewrite a ``.c`` by comparing it against
182
+ the ``.pyx`` and the ``.pxd`` files that ``.pyx`` cimports. A
183
+ wheel-installed numpy carries the timestamps recorded in the wheel, so its
184
+ declarations can be years older than a ``.c`` generated from a *previous*
185
+ numpy last week -- and the stale C is then compiled against headers that no
186
+ longer match it. What that reports is a compile error inside a numpy
187
+ internal, naming nothing in this package.
188
+
189
+ The generated C is not tracked by git and every ``.pyx`` beside it is
190
+ shipped, so it can always be written again. Only with Cython installed:
191
+ an install from an sdist without one has the C and no way to make more.
192
+ """
193
+ import glob
194
+
195
+ if not have_cython:
196
+ return
197
+ wanted = _toolchain()
198
+ try:
199
+ with open(TOOLCHAIN_STAMP, encoding='utf-8') as handle:
200
+ if handle.read() == wanted:
201
+ return
202
+ except OSError:
203
+ pass
204
+ for path in glob.glob(os.path.join(HERE, 'src', '*.c')):
205
+ os.unlink(path)
206
+ with open(TOOLCHAIN_STAMP + '.partial', 'w', encoding='utf-8') as handle:
207
+ handle.write(wanted)
208
+ os.replace(TOOLCHAIN_STAMP + '.partial', TOOLCHAIN_STAMP)
209
+
210
+
124
211
  def cython_extension(
125
212
  name,
126
213
  include_dirs=(),
@@ -190,6 +277,10 @@ else:
190
277
  if ( # Prevents running of setup during code introspection imports
191
278
  __name__ == "__main__"
192
279
  ):
280
+ # Here rather than at module level: importing this file is how the suite
281
+ # and the packaging tools read what it declares, and an import that
282
+ # deleted generated C would make reading the declarations a build step.
283
+ drop_c_from_another_toolchain()
193
284
  # Workaround for Broken apple Python build params echoed in distutils
194
285
  # Approach taken from the PyMongo driver. OS-X Python builds were created with
195
286
  # non-existent flag, and distutils passes those flags to the extension
@@ -28,9 +28,35 @@ cdef class HandlerRegistry:
28
28
  self.all_output_handlers = []
29
29
  def __setitem__( self,key,value ):
30
30
  self.registry[key] = value
31
+ # The pure-Python HandlerRegistry is a dict subclass, so it answers a
32
+ # lookup by type as well as a lookup by value. This one held its mapping
33
+ # privately and offered only __setitem__, so `FormatHandler.typeLookup`
34
+ # -- a public classmethod, and how a third party asks which handler its
35
+ # own array format resolved to -- raised
36
+ # TypeError: 'HandlerRegistry' object is not subscriptable
37
+ # wherever the accelerators are installed, which is most installations.
38
+ # Its `except KeyError` could not catch that, so the caller got an error
39
+ # about the registry's type rather than the answer or the KeyError the
40
+ # method documents.
41
+ def __getitem__( self, key ):
42
+ return self.registry[key]
43
+ def __contains__( self, key ):
44
+ return key in self.registry
45
+ def __len__( self ):
46
+ return len( self.registry )
47
+ def __iter__( self ):
48
+ return iter( self.registry )
49
+ def get( self, key, default=None ):
50
+ return self.registry.get( key, default )
51
+ def keys( self ):
52
+ return self.registry.keys()
53
+ def values( self ):
54
+ return self.registry.values()
55
+ def items( self ):
56
+ return self.registry.items()
31
57
  def __call__( self, value ):
32
58
  return self.c_lookup( value )
33
-
59
+
34
60
  cdef object c_lookup( self, object value ):
35
61
  """C-level lookup of handler for given value"""
36
62
  cdef object typ, handler,base
@@ -491,6 +517,14 @@ cdef class AsArrayOfType(pyArgConverter):
491
517
  self.typeIndex = wrapper.pyArgIndex( self.typeName )
492
518
  cdef object c_call( self, object incoming, object function, tuple arguments ):
493
519
  """Get the arg as an array of the appropriate type"""
520
+ # An integer is a byte offset into the bound buffer rather than one
521
+ # datum to upload: this converter serves glDrawElements and the pixel
522
+ # calls, whose data argument the GL reads as an offset whenever a
523
+ # buffer object is bound. Kept in step with the ctypes converter of
524
+ # the same name in OpenGL/arrays/arrayhelpers.py, and with
525
+ # OpenGL.arrays.arraydatatype.buffer_offset, which decides.
526
+ if type(incoming) is int:
527
+ return ctypes.c_void_p( incoming )
494
528
  return self.arrayType.asArray( incoming, arguments[ self.typeIndex ] )
495
529
 
496
530
  cdef class AsArrayTyped(pyArgConverter):
@@ -91,7 +91,13 @@ cdef class MemoryviewHandler(FormatHandler):
91
91
  cdef c_arraySize( self, object instance, object typeCode ):
92
92
  """Retrieve array size reference"""
93
93
  cdef Py_buffer * buffer
94
- buffer = PyMemoryView_GET_BUFFER( self.c_as_memoryview( instance ) )
94
+ # `view` holds the memoryview for as long as `buffer` points into it.
95
+ # `c_as_memoryview` builds one where the instance is not already a
96
+ # memoryview, and a temporary of it lives only to the end of the
97
+ # statement that made it -- so reading through `buffer` on the next
98
+ # line reads a Py_buffer inside a freed object.
99
+ view = self.c_as_memoryview( instance )
100
+ buffer = PyMemoryView_GET_BUFFER( view )
95
101
  return buffer.len//buffer.itemsize
96
102
  cdef c_arrayByteCount( self, object instance ):
97
103
  """Given a data-value, calculate number of bytes required to represent"""
@@ -100,7 +106,9 @@ cdef class MemoryviewHandler(FormatHandler):
100
106
  cdef c_arrayToGLType( self, object instance ):
101
107
  """Given a value, guess OpenGL type of the corresponding pointer"""
102
108
  cdef Py_buffer * buffer
103
- buffer = PyMemoryView_GET_BUFFER( self.c_as_memoryview( instance ) )
109
+ # `view` keeps the memoryview alive; see `c_arraySize`.
110
+ view = self.c_as_memoryview( instance )
111
+ buffer = PyMemoryView_GET_BUFFER( view )
104
112
  cdef object constant = self.array_to_gl_constant.get( buffer.format )
105
113
  if constant is None:
106
114
  if isinstance(buffer.format,bytes):
@@ -133,10 +141,14 @@ cdef class MemoryviewHandler(FormatHandler):
133
141
  cdef c_dimensions( self, object instance ):
134
142
  """Retrieve full set of dimensions for the array as tuple"""
135
143
  cdef Py_buffer * buffer
136
- buffer = PyMemoryView_GET_BUFFER( self.c_as_memoryview( instance ) )
144
+ # `view` keeps the memoryview alive; see `c_arraySize`.
145
+ view = self.c_as_memoryview( instance )
146
+ buffer = PyMemoryView_GET_BUFFER( view )
137
147
  cdef dim = 0
138
148
  cdef list result
139
149
  result = []
140
150
  for dim in range(buffer.ndim):
141
151
  result.append( buffer.shape[dim] )
142
- return result
152
+ # A tuple, as the shape of an array is everywhere else here and as
153
+ # `OpenGL.arrays.buffers.BufferHandler.dimensions` answers.
154
+ return tuple( result )