PyOpenGL-accelerate 4.0.0a1__tar.gz → 4.0.0a5__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 (40) hide show
  1. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/OpenGL_accelerate/__init__.py +1 -1
  2. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/PKG-INFO +19 -1
  3. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/PyOpenGL_accelerate.egg-info/PKG-INFO +19 -1
  4. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/PyOpenGL_accelerate.egg-info/SOURCES.txt +13 -0
  5. pyopengl_accelerate-4.0.0a5/PyOpenGL_accelerate.egg-info/requires.txt +1 -0
  6. pyopengl_accelerate-4.0.0a5/README.md +31 -0
  7. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/pyproject.toml +18 -1
  8. pyopengl_accelerate-4.0.0a5/setup.py +314 -0
  9. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/src/arraydatatype.pyx +83 -1
  10. pyopengl_accelerate-4.0.0a5/src/c/generated/pygl_EGL.c +6283 -0
  11. pyopengl_accelerate-4.0.0a5/src/c/generated/pygl_GL.c +120234 -0
  12. pyopengl_accelerate-4.0.0a5/src/c/generated/pygl_GLES1.c +15983 -0
  13. pyopengl_accelerate-4.0.0a5/src/c/generated/pygl_GLES2.c +29952 -0
  14. pyopengl_accelerate-4.0.0a5/src/c/generated/pygl_GLES3.c +7004 -0
  15. pyopengl_accelerate-4.0.0a5/src/c/generated/pygl_GLSC2.c +4350 -0
  16. pyopengl_accelerate-4.0.0a5/src/c/generated/pygl_GLX.c +5068 -0
  17. pyopengl_accelerate-4.0.0a5/src/c/generated/pygl_WGL.c +5736 -0
  18. pyopengl_accelerate-4.0.0a5/src/c/generated/pygl_generated.c +44 -0
  19. pyopengl_accelerate-4.0.0a5/src/c/generated/pygl_modules.c +23632 -0
  20. pyopengl_accelerate-4.0.0a5/src/c/pygl_handwritten.c +119 -0
  21. pyopengl_accelerate-4.0.0a5/src/c/pygl_runtime.c +2971 -0
  22. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/src/errorchecker.pyx +52 -9
  23. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/src/vbo.pyx +6 -2
  24. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/src/wrapper.pyx +11 -0
  25. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/tests/test_arraydatatypeaccel.py +36 -12
  26. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/tests/test_numpyaccel.py +21 -2
  27. pyopengl_accelerate-4.0.0a1/README.md +0 -15
  28. pyopengl_accelerate-4.0.0a1/setup.py +0 -121
  29. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/MANIFEST.in +0 -0
  30. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/OpenGL_accelerate/formathandler.pxd +0 -0
  31. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/OpenGL_accelerate/wrapper.pxd +0 -0
  32. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/PyOpenGL_accelerate.egg-info/dependency_links.txt +0 -0
  33. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/PyOpenGL_accelerate.egg-info/top_level.txt +0 -0
  34. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/license.txt +0 -0
  35. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/setup.cfg +0 -0
  36. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/src/buffers_formathandler.pyx +0 -0
  37. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/src/formathandler.pyx +0 -0
  38. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/src/latebind.pyx +0 -0
  39. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/src/nones_formathandler.pyx +0 -0
  40. {pyopengl_accelerate-4.0.0a1 → pyopengl_accelerate-4.0.0a5}/src/numpy_formathandler.pyx +0 -0
@@ -7,5 +7,5 @@ PyOpenGL package and is built via the setupaccel.py
7
7
  script in the top level of the PyOpenGL source package.
8
8
  """
9
9
 
10
- __version__ = "4.0.0a1"
10
+ __version__ = "4.0.0a5"
11
11
  __version_tuple__ = (4, 0, 0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyOpenGL-accelerate
3
- Version: 4.0.0a1
3
+ Version: 4.0.0a5
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,8 +24,10 @@ 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.0a5
27
28
  Dynamic: download-url
28
29
  Dynamic: license-file
30
+ Dynamic: requires-dist
29
31
 
30
32
  # Acceleration code for PyOpenGL
31
33
 
@@ -33,6 +35,22 @@ This set of C (Cython) extensions provides acceleration of common operations
33
35
  for slow points in PyOpenGL 3.x. It is not a requirement for using PyOpenGL
34
36
  but performance without it will be poor.
35
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
+
36
54
  ## Build Process
37
55
 
38
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.0a1
3
+ Version: 4.0.0a5
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,8 +24,10 @@ 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.0a5
27
28
  Dynamic: download-url
28
29
  Dynamic: license-file
30
+ Dynamic: requires-dist
29
31
 
30
32
  # Acceleration code for PyOpenGL
31
33
 
@@ -33,6 +35,22 @@ This set of C (Cython) extensions provides acceleration of common operations
33
35
  for slow points in PyOpenGL 3.x. It is not a requirement for using PyOpenGL
34
36
  but performance without it will be poor.
35
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
+
36
54
  ## Build Process
37
55
 
38
56
  Cython is updated frequently to support newer versions of Python. As of
@@ -10,6 +10,7 @@ OpenGL_accelerate/wrapper.pxd
10
10
  PyOpenGL_accelerate.egg-info/PKG-INFO
11
11
  PyOpenGL_accelerate.egg-info/SOURCES.txt
12
12
  PyOpenGL_accelerate.egg-info/dependency_links.txt
13
+ PyOpenGL_accelerate.egg-info/requires.txt
13
14
  PyOpenGL_accelerate.egg-info/top_level.txt
14
15
  src/arraydatatype.pyx
15
16
  src/buffers_formathandler.pyx
@@ -20,5 +21,17 @@ src/nones_formathandler.pyx
20
21
  src/numpy_formathandler.pyx
21
22
  src/vbo.pyx
22
23
  src/wrapper.pyx
24
+ src/c/pygl_handwritten.c
25
+ src/c/pygl_runtime.c
26
+ src/c/generated/pygl_EGL.c
27
+ src/c/generated/pygl_GL.c
28
+ src/c/generated/pygl_GLES1.c
29
+ src/c/generated/pygl_GLES2.c
30
+ src/c/generated/pygl_GLES3.c
31
+ src/c/generated/pygl_GLSC2.c
32
+ src/c/generated/pygl_GLX.c
33
+ src/c/generated/pygl_WGL.c
34
+ src/c/generated/pygl_generated.c
35
+ src/c/generated/pygl_modules.c
23
36
  tests/test_arraydatatypeaccel.py
24
37
  tests/test_numpyaccel.py
@@ -0,0 +1 @@
1
+ PyOpenGL==4.0.0a5
@@ -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.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name="PyOpenGL-accelerate"
3
- dynamic=["version"]
3
+ dynamic=["version", "dependencies"]
4
4
  description = "Cython-coded accelerators for PyOpenGL"
5
5
  authors = [
6
6
  {name="Mike C. Fletcher",email="mcfletch@vrplumber.com"},
@@ -47,9 +47,26 @@ build-backend = "setuptools.build_meta"
47
47
 
48
48
  [tool.setuptools.dynamic]
49
49
  version = {attr = "OpenGL_accelerate.__version__"}
50
+ # The dependency on PyOpenGL is an exact pin on this package's own version, so
51
+ # setup.py builds it from the one number rather than a second copy living here
52
+ # to drift -- see pyopengl_requirement().
50
53
 
51
54
  [tool.setuptools.packages.find]
52
55
  namespaces=false
53
56
  include=["OpenGL_accelerate"]
54
57
  exclude=["tests","src"]
55
58
 
59
+ # uv decides whether its cached metadata for a source tree is still current
60
+ # from pyproject.toml, setup.py and setup.cfg alone. This project's version
61
+ # lives in OpenGL_accelerate/__init__.py, so name that file too: without it a
62
+ # version bump leaves uv answering with the previous number, and a dependent
63
+ # requiring the new one resolves against PyPI rather than this checkout.
64
+ [tool.uv]
65
+ # setup.py too: the dependency on PyOpenGL is built there, from the version
66
+ # in OpenGL_accelerate/__init__.py, so both files decide this package's
67
+ # metadata and a change to either has to invalidate the cached answer.
68
+ cache-keys = [
69
+ { file = "pyproject.toml" },
70
+ { file = "setup.py" },
71
+ { file = "OpenGL_accelerate/__init__.py" },
72
+ ]
@@ -0,0 +1,314 @@
1
+ #!/usr/bin/env python
2
+ """Builds accelleration functions for PyOpenGL
3
+ """
4
+ import sys
5
+ from setuptools import setup, Extension
6
+
7
+ try:
8
+ from Cython.Distutils import build_ext
9
+ except ImportError:
10
+ have_cython = False
11
+ build_ext = False
12
+ else:
13
+ have_cython = True
14
+
15
+ import sys, os
16
+
17
+ HERE = os.path.normpath(os.path.abspath(os.path.dirname(__file__)))
18
+
19
+ extensions = []
20
+
21
+
22
+ def _our_version():
23
+ """This package's version, read without importing it.
24
+
25
+ Importing ``OpenGL_accelerate`` during its own build would need the
26
+ extensions that are not built yet, so the assignment is read out of the
27
+ source the way the build backend reads it.
28
+ """
29
+ import re
30
+
31
+ with open(
32
+ os.path.join(HERE, 'OpenGL_accelerate', '__init__.py'), encoding='utf-8'
33
+ ) as handle:
34
+ source = handle.read()
35
+ found = re.search(r'^__version__\s*=\s*["\']([^"\']+)["\']', source, re.M)
36
+ if not found:
37
+ raise RuntimeError('OpenGL_accelerate/__init__.py states no __version__')
38
+ return found.group(1)
39
+
40
+
41
+ def pyopengl_requirement():
42
+ """The PyOpenGL this accelerate pairs with, as a requirement string.
43
+
44
+ Exact, because the two are released together from one repository and the
45
+ dispatch extension's tables are generated from that PyOpenGL: a mismatched
46
+ pair does not degrade, it dispatches through the wrong slot indices.
47
+ ``OpenGL._dispatch`` refuses one at import; this stops pip assembling one
48
+ in the first place, which is a better place to learn it than the first
49
+ entry point a program calls.
50
+
51
+ Read from this package's own version so there is one number to bump.
52
+ """
53
+ return 'PyOpenGL==%s' % (_our_version(),)
54
+
55
+
56
+ VERSION_HEADER = 'src/c/generated/pygl_version.h'
57
+
58
+
59
+ def write_version_header():
60
+ """State the version in a header, and answer where it was written.
61
+
62
+ The extension reports at import which PyOpenGL its tables came from, so
63
+ that number has to reach the C. A ``-D`` on the command line would too,
64
+ but a compiler driver's flags are not something the build compares against
65
+ an object file it already has: bump the version, and the existing
66
+ ``pygl_runtime.o`` is still newer than every source and header, so it is
67
+ linked as it stands and the new build announces the old version. A header
68
+ is compared, being in ``depends``, so a bump recompiles what includes it.
69
+
70
+ Rewritten only when the contents change, so an unchanged version does not
71
+ invalidate the objects on every build.
72
+ """
73
+ path = os.path.join(HERE, VERSION_HEADER)
74
+ contents = (
75
+ '/* Written by accelerate\'s setup.py from OpenGL_accelerate.__version__.\n'
76
+ ' * The pair is released together and carries one number, so this is\n'
77
+ ' * the PyOpenGL whose generated tables this extension holds. */\n'
78
+ '#define PYOPENGL_VERSION "%s"\n' % (_our_version(),)
79
+ )
80
+ try:
81
+ with open(path, encoding='utf-8') as handle:
82
+ if handle.read() == contents:
83
+ return VERSION_HEADER
84
+ except OSError:
85
+ pass
86
+ os.makedirs(os.path.dirname(path), exist_ok=True)
87
+ with open(path, 'w', encoding='utf-8') as handle:
88
+ handle.write(contents)
89
+ return VERSION_HEADER
90
+
91
+
92
+ def dispatch_extension():
93
+ """The registry-generated C implementation of the OpenGL entry points.
94
+
95
+ It lives here rather than in ``pyopengl`` so that ``pyopengl`` stays a
96
+ single universal wheel: the C is what needs a compiler and a wheel per
97
+ platform, and this package is already the optional compiled companion.
98
+ "Is the fast path available?" is then the question it has always been --
99
+ is accelerate installed?
100
+
101
+ Both packages are released together from one repository, and the two
102
+ share generated tables, so the versions must match exactly; the module
103
+ checks that at import.
104
+ """
105
+ import glob
106
+
107
+ if os.environ.get('PYOPENGL_NO_C_DISPATCH'):
108
+ return []
109
+ if sys.implementation.name != 'cpython':
110
+ # The extension reaches CPython's vectorcall protocol directly. On
111
+ # PyPy it would compile, import, and route every call through an
112
+ # emulated vectorcall across the cpyext boundary -- the slowest path
113
+ # available, chosen by default, on the interpreter the ctypes
114
+ # implementation exists to serve.
115
+ return []
116
+ generated = os.path.join(HERE, 'src', 'c', 'generated')
117
+ sources = sorted(
118
+ os.path.relpath(path, HERE).replace(os.sep, '/')
119
+ for path in glob.glob(os.path.join(generated, '*.c'))
120
+ )
121
+ if not sources:
122
+ return []
123
+ sources.insert(0, 'src/c/pygl_handwritten.c')
124
+ sources.insert(0, 'src/c/pygl_runtime.c')
125
+ # setuptools does not work out header dependencies, so a change to pygl.h
126
+ # would otherwise leave the generated objects stale and the build mixed:
127
+ # objects compiled against one version of a macro linked with a runtime
128
+ # compiled against another.
129
+ headers = [
130
+ 'src/c/pygl.h',
131
+ 'src/c/generated/pygl_elements.h',
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(),
137
+ ]
138
+ return [
139
+ Extension(
140
+ 'OpenGL_accelerate.dispatch',
141
+ sources=sources,
142
+ include_dirs=['src/c', 'src/c/generated'],
143
+ depends=[
144
+ path for path in headers if os.path.exists(os.path.join(HERE, path))
145
+ ],
146
+ # Optional so a source install without a compiler still yields a
147
+ # working accelerate; PyOpenGL falls back to ctypes on its own.
148
+ # Set PYOPENGL_REQUIRE_C_DISPATCH=1 while working on it, or a
149
+ # compile error is a warning and the stale object is kept.
150
+ optional=not os.environ.get('PYOPENGL_REQUIRE_C_DISPATCH'),
151
+ )
152
+ ]
153
+
154
+
155
+ extensions.extend(dispatch_extension())
156
+
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, 'w', encoding='utf-8') as handle:
207
+ handle.write(wanted)
208
+
209
+
210
+ def cython_extension(
211
+ name,
212
+ include_dirs=(),
213
+ ):
214
+ """Create a cython extension object"""
215
+ filenames = "%(name)s.c" % locals(), "%(name)s.pyx" % locals()
216
+ filename = filenames[bool(have_cython)]
217
+ return Extension(
218
+ "OpenGL_accelerate.%(name)s" % locals(),
219
+ [
220
+ os.path.join("src", filename),
221
+ ],
222
+ include_dirs=[
223
+ os.path.join(HERE, "src"),
224
+ HERE,
225
+ ]
226
+ + list(include_dirs),
227
+ define_macros=[
228
+ ('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION'),
229
+ ],
230
+ compiler_directives={'language_level': "3"} if have_cython else {},
231
+ )
232
+
233
+
234
+ extensions.extend(
235
+ [
236
+ cython_extension("wrapper"),
237
+ cython_extension("formathandler"),
238
+ cython_extension("arraydatatype"),
239
+ cython_extension("errorchecker"),
240
+ cython_extension("vbo"),
241
+ cython_extension("nones_formathandler"),
242
+ cython_extension("latebind"),
243
+ ]
244
+ )
245
+ if sys.version_info[:2] >= (2, 7):
246
+ extensions.extend(
247
+ [
248
+ cython_extension("buffers_formathandler"),
249
+ ]
250
+ )
251
+
252
+ try:
253
+ import numpy
254
+ except ImportError:
255
+ sys.stderr.write("""Unable to import numpy, skipping numpy extension building\n""")
256
+ else:
257
+ if hasattr(numpy, "get_include"):
258
+ includeDirectories = [
259
+ numpy.get_include(),
260
+ ]
261
+ else:
262
+ includeDirectories = [
263
+ os.path.join(
264
+ os.path.dirname(numpy.__file__),
265
+ "core",
266
+ "include",
267
+ ),
268
+ ]
269
+ extensions.append(
270
+ cython_extension(
271
+ "numpy_formathandler",
272
+ includeDirectories,
273
+ )
274
+ )
275
+
276
+ if ( # Prevents running of setup during code introspection imports
277
+ __name__ == "__main__"
278
+ ):
279
+ # Here rather than at module level: importing this file is how the suite
280
+ # and the packaging tools read what it declares, and an import that
281
+ # deleted generated C would make reading the declarations a build step.
282
+ drop_c_from_another_toolchain()
283
+ # Workaround for Broken apple Python build params echoed in distutils
284
+ # Approach taken from the PyMongo driver. OS-X Python builds were created with
285
+ # non-existent flag, and distutils passes those flags to the extension
286
+ # build, newer clangs now treat those flags as errors rather than warnings.
287
+ import platform, sys
288
+
289
+ if sys.platform == "darwin" and "clang" in platform.python_compiler().lower():
290
+ from distutils.sysconfig import get_config_vars
291
+
292
+ res = get_config_vars()
293
+ for key in ("CFLAGS", "PY_CFLAGS"):
294
+ if key in res:
295
+ res[key] = res[key].replace("-mno-fused-madd", "")
296
+
297
+ extraArguments = {}
298
+ ### Now the actual set up call
299
+ if have_cython:
300
+ extraArguments["cmdclass"] = {
301
+ "build_ext": build_ext,
302
+ }
303
+ setup(
304
+ build_requires=['cython'],
305
+ install_requires=[pyopengl_requirement()],
306
+ options={
307
+ "sdist": {
308
+ "formats": ["gztar"],
309
+ "force_manifest": True,
310
+ },
311
+ },
312
+ ext_modules=extensions,
313
+ **extraArguments
314
+ )
@@ -303,6 +303,13 @@ cdef class Output(cArgConverter):
303
303
  never reaches the caller's array -- the silent "returns zeroes" bug.
304
304
  Detect the shrinking copy and raise. Correctly-typed arrays are not
305
305
  copied, so they never trip this.
306
+
307
+ Then the other question, which the count answers: an array shorter than
308
+ the call will write into is a heap overrun rather than an exception, so
309
+ it is refused. See ``Output.checkOutputSize`` in OpenGL/converters.py,
310
+ which is the same check for the pure-Python converter -- this one is
311
+ what runs where accelerate is installed, whichever dispatch layer the
312
+ entry points come from.
306
313
  """
307
314
  value = pyArgs[index]
308
315
  result = self.arrayType.asArray( value )
@@ -311,7 +318,10 @@ cdef class Output(cArgConverter):
311
318
  rbytes = self.arrayType.arrayByteCount( result )
312
319
  vbytes = self.arrayType.arrayByteCount( value )
313
320
  except Exception:
314
- return result
321
+ # Not measurable -- a list has no byte count of its own -- so
322
+ # there is no shrinking coercion to detect. The size the call
323
+ # will write is still checked below.
324
+ rbytes = vbytes = 0
315
325
  if rbytes < vbytes:
316
326
  raise TypeError(
317
327
  '%s: pass-in output array was coerced to a smaller buffer '
@@ -319,8 +329,62 @@ cdef class Output(cArgConverter):
319
329
  'into your array. Pass a correctly-typed array, or None to '
320
330
  'have one allocated.' % ( self.name, rbytes, vbytes )
321
331
  )
332
+ self.c_checkOutputSize( result, pyArgs )
322
333
  return result
323
334
 
335
+ cdef int c_checkOutputSize( self, object array, tuple pyArgs ) except -1:
336
+ """Nothing to check: a fixed declared size is a maximum.
337
+
338
+ Which of it a call fills depends on the pname -- glGetVertexAttribiv
339
+ declares four and writes one for most of them -- so a shorter array is
340
+ legitimate here. :class:`SizedOutput` overrides this, because its size
341
+ is a count the caller passed and so says what will be written.
342
+ """
343
+ return 0
344
+
345
+ cdef int c_checkPromisedSize( self, object array, tuple pyArgs ) except -1:
346
+ """Refuse an output array smaller than the call will write into it.
347
+
348
+ Only a shortfall: a larger array is a caller deliberately reusing one
349
+ buffer for several calls, which is ordinary and safe.
350
+ """
351
+ cdef long wanted = 1
352
+ try:
353
+ shape = self.c_getSize( pyArgs )
354
+ except Exception:
355
+ return 0
356
+ if shape is None:
357
+ return 0
358
+ for dimension in shape:
359
+ try:
360
+ wanted = wanted * int(dimension)
361
+ except (TypeError, ValueError):
362
+ return 0
363
+ if wanted <= 0:
364
+ return 0
365
+ # Compared in bytes, not elements. The count is in units of the type
366
+ # the *declaration* names -- glGetBufferSubData's `size` is a byte
367
+ # count, glGenTextures' `n` is a count of GLuint -- and the caller may
368
+ # pass an array of some other type holding the same bytes.
369
+ # Only what carries its own length. A bare ctypes pointer does not --
370
+ # the hand-written wrappers in OpenGL/GL/exceptional.py pass
371
+ # `typedPointer` results straight down -- and arrayByteCount answers
372
+ # for one anyway, with the size of a single element.
373
+ if not hasattr( array, '__len__' ):
374
+ return 0
375
+ try:
376
+ wanted_bytes = wanted * ctypes.sizeof( self.arrayType.baseType )
377
+ held_bytes = self.arrayType.arrayByteCount( array )
378
+ except Exception:
379
+ return 0
380
+ if held_bytes < wanted_bytes:
381
+ raise ValueError(
382
+ '%s: output array holds %d byte(s), but the call will '
383
+ 'write %d. Pass a larger array, or None to have one '
384
+ 'allocated.' % ( self.name, held_bytes, wanted_bytes )
385
+ )
386
+ return 0
387
+
324
388
  def oldStyleReturn( self, object result, object baseOperation, tuple pyArgs, tuple cArgs ):
325
389
  """Retrieve cArgs[ self.index ]"""
326
390
  #TODO: make this a c_api-bearing value, not a Python function call
@@ -362,6 +426,24 @@ cdef class SizedOutput( Output ):
362
426
  def finalise( self, wrapper ):
363
427
  super( SizedOutput,self).finalise( wrapper )
364
428
  self.index = wrapper.pyArgIndex( self.specifier )
429
+ cdef int c_checkOutputSize( self, object array, tuple pyArgs ) except -1:
430
+ """Check the size only where it says what this call will write.
431
+
432
+ It does when it comes from a *count* the caller passed --
433
+ glGenTextures(n, names) writes n, glGetBufferSubData writes `size`
434
+ bytes -- which the declaration spells `size=lambda x: (x,)`.
435
+
436
+ It does not when it comes from a table keyed on a *pname*, which says
437
+ how large that piece of state is in total; how much of it a call fills
438
+ is the call's business, and glGetIntegeri_v writes one element of a
439
+ three-element pname at a time. The declaration spells that
440
+ `size=<a dict>`, handed on as its `__getitem__` -- so the dict it is
441
+ bound to is what tells the two apart.
442
+ """
443
+ if isinstance( getattr( self.lookup, '__self__', None ), dict ):
444
+ return 0
445
+ return self.c_checkPromisedSize( array, pyArgs )
446
+
365
447
  cdef tuple c_getSize( self, tuple pyArgs ):
366
448
  """Retrieve the array size for this argument"""
367
449
  try: