PyVRML97 2.3.4b3__tar.gz → 2.4.0a1__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 (90) hide show
  1. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/MANIFEST.in +1 -0
  2. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/PKG-INFO +16 -3
  3. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/PyVRML97.egg-info/PKG-INFO +16 -3
  4. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/PyVRML97.egg-info/SOURCES.txt +26 -3
  5. pyvrml97-2.4.0a1/PyVRML97.egg-info/requires.txt +3 -0
  6. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/README.rst +7 -0
  7. pyvrml97-2.4.0a1/RELEASE-NOTES-2.3.5.md +104 -0
  8. pyvrml97-2.4.0a1/pyproject.toml +112 -0
  9. pyvrml97-2.4.0a1/requirements.txt +8 -0
  10. pyvrml97-2.4.0a1/tests/test_arrays.py +171 -0
  11. pyvrml97-2.4.0a1/tests/test_basefield.py +335 -0
  12. pyvrml97-2.4.0a1/tests/test_cache.py +237 -0
  13. pyvrml97-2.4.0a1/tests/test_copying.py +166 -0
  14. pyvrml97-2.4.0a1/tests/test_csscolors.py +71 -0
  15. pyvrml97-2.4.0a1/tests/test_field_assignment.py +186 -0
  16. pyvrml97-2.4.0a1/tests/test_field_coercion.py +181 -0
  17. pyvrml97-2.4.0a1/tests/test_field_declaration.py +467 -0
  18. pyvrml97-2.4.0a1/tests/test_fieldtype_edges.py +341 -0
  19. pyvrml97-2.4.0a1/tests/test_fieldtypes.py +144 -0
  20. pyvrml97-2.4.0a1/tests/test_linearise.py +596 -0
  21. pyvrml97-2.4.0a1/tests/test_matrix_primitives.py +235 -0
  22. pyvrml97-2.4.0a1/tests/test_node_behaviour.py +268 -0
  23. pyvrml97-2.4.0a1/tests/test_node_definitions.py +173 -0
  24. pyvrml97-2.4.0a1/tests/test_nodepath.py +201 -0
  25. pyvrml97-2.4.0a1/tests/test_olist.py +156 -0
  26. pyvrml97-2.4.0a1/tests/test_parseprocessor.py +276 -0
  27. pyvrml97-2.4.0a1/tests/test_parsing_values.py +365 -0
  28. pyvrml97-2.4.0a1/tests/test_routes_and_protofunctions.py +274 -0
  29. pyvrml97-2.4.0a1/tests/test_scenegraph.py +249 -0
  30. pyvrml97-2.4.0a1/tests/test_smallmodules.py +156 -0
  31. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/tests/test_tostring.py +2 -10
  32. pyvrml97-2.4.0a1/tests/test_transform_composition.py +186 -0
  33. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/tests/test_transformmatrix.py +12 -9
  34. pyvrml97-2.4.0a1/tests/test_vrml200x_parser.py +119 -0
  35. pyvrml97-2.4.0a1/tests/test_vrmlstr.py +187 -0
  36. pyvrml97-2.4.0a1/tests/test_weakcollections.py +280 -0
  37. pyvrml97-2.4.0a1/tox.ini +44 -0
  38. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/__init__.py +1 -1
  39. pyvrml97-2.4.0a1/vrml/arrays.py +133 -0
  40. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/cache.py +47 -42
  41. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/copier.py +14 -6
  42. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/csscolors.py +9 -22
  43. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/event.py +8 -4
  44. pyvrml97-2.4.0a1/vrml/field.py +569 -0
  45. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/fieldtypes.py +216 -226
  46. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/node.py +196 -91
  47. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/nodepath.py +20 -14
  48. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/olist.py +52 -41
  49. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/protofunctions.py +24 -23
  50. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/protonamespace.py +13 -5
  51. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/route.py +53 -22
  52. pyvrml97-2.4.0a1/vrml/vrml200x/__init__.py +0 -0
  53. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml200x/parser.py +20 -8
  54. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml97/_transformmatrix.py +26 -23
  55. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml97/_transformmatrix_accel.py +5 -4
  56. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml97/basenamespaces.py +2 -3
  57. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml97/basenodes.py +35 -35
  58. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml97/linearise.py +144 -101
  59. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml97/nodepath.py +55 -42
  60. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml97/nodetypes.py +9 -8
  61. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml97/nurbs.py +3 -3
  62. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml97/parseprocessor.py +87 -52
  63. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml97/parser.py +14 -6
  64. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml97/scenegraph.py +50 -41
  65. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml97/script.py +3 -2
  66. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml97/shaders.py +14 -14
  67. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml97/transformmatrix.py +60 -51
  68. pyvrml97-2.4.0a1/vrml/vrml97/tree.py +117 -0
  69. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/weaklist.py +73 -56
  70. pyvrml97-2.4.0a1/vrml/weaktuple.py +167 -0
  71. pyvrml97-2.3.4b3/PyVRML97.egg-info/requires.txt +0 -3
  72. pyvrml97-2.3.4b3/pyproject.toml +0 -48
  73. pyvrml97-2.3.4b3/requirements.txt +0 -5
  74. pyvrml97-2.3.4b3/tests/test_fieldtypes.py +0 -20
  75. pyvrml97-2.3.4b3/tests/test_nodepath.py +0 -80
  76. pyvrml97-2.3.4b3/tests/test_olist.py +0 -43
  77. pyvrml97-2.3.4b3/tox.ini +0 -13
  78. pyvrml97-2.3.4b3/vrml/_bytes.py +0 -85
  79. pyvrml97-2.3.4b3/vrml/arrays.py +0 -86
  80. pyvrml97-2.3.4b3/vrml/field.py +0 -476
  81. pyvrml97-2.3.4b3/vrml/weakkeydictfix.py +0 -36
  82. pyvrml97-2.3.4b3/vrml/weaktuple.py +0 -138
  83. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/PyVRML97.egg-info/dependency_links.txt +0 -0
  84. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/PyVRML97.egg-info/not-zip-safe +0 -0
  85. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/PyVRML97.egg-info/top_level.txt +0 -0
  86. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/license.txt +0 -0
  87. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/setup.cfg +0 -0
  88. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/test-requirements.txt +0 -0
  89. /pyvrml97-2.3.4b3/vrml/vrml200x/__init__.py → /pyvrml97-2.4.0a1/vrml/py.typed +0 -0
  90. {pyvrml97-2.3.4b3 → pyvrml97-2.4.0a1}/vrml/vrml97/__init__.py +0 -0
@@ -2,4 +2,5 @@ include *.txt
2
2
  include *.in
3
3
  include *.py
4
4
  include *.rst
5
+ include *.md
5
6
  include *.ini
@@ -1,13 +1,19 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyVRML97
3
- Version: 2.3.4b3
3
+ Version: 2.4.0a1
4
4
  Summary: VRML97 Scenegraph model for Python
5
5
  Author-email: "Mike C. Fletcher" <mcfletch@vrplumber.com>
6
6
  License: BSD-style, see license.txt for details
7
7
  Project-URL: Homepage, http://pyopengl.sourceforge.net/context/
8
8
  Keywords: VRML,VRML97,scenegraph
9
9
  Classifier: License :: OSI Approved :: BSD License
10
- Classifier: Programming Language :: Python
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
11
17
  Classifier: Programming Language :: C
12
18
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
19
  Classifier: Topic :: Multimedia :: Graphics :: 3D Rendering
@@ -16,7 +22,7 @@ Requires-Python: >=3.9
16
22
  Description-Content-Type: text/x-rst
17
23
  Requires-Dist: numpy
18
24
  Requires-Dist: PyDispatcher
19
- Requires-Dist: simpleparse
25
+ Requires-Dist: simpleparse>=3.0.0a3
20
26
 
21
27
  PyVRML97 Scenegraph Model
22
28
  ==========================
@@ -35,6 +41,13 @@ optimize the rendering process.
35
41
  .. _`PyDispatcher`: https://pypi.python.org/pypi/PyDispatcher
36
42
  .. _`Numpy`: https://pypi.python.org/pypi/numpy
37
43
 
44
+ `RELEASE-NOTES-2.3.5.md`_ says what changed for a program using this release,
45
+ including the two behaviour changes a caller may need to act on:
46
+ ``transformmatrix.orthoMatrix`` is transposed, and ``Node.copy()`` copies the
47
+ whole subtree.
48
+
49
+ .. _`RELEASE-NOTES-2.3.5.md`: RELEASE-NOTES-2.3.5.md
50
+
38
51
  Installation
39
52
  -------------
40
53
 
@@ -1,13 +1,19 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyVRML97
3
- Version: 2.3.4b3
3
+ Version: 2.4.0a1
4
4
  Summary: VRML97 Scenegraph model for Python
5
5
  Author-email: "Mike C. Fletcher" <mcfletch@vrplumber.com>
6
6
  License: BSD-style, see license.txt for details
7
7
  Project-URL: Homepage, http://pyopengl.sourceforge.net/context/
8
8
  Keywords: VRML,VRML97,scenegraph
9
9
  Classifier: License :: OSI Approved :: BSD License
10
- Classifier: Programming Language :: Python
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
11
17
  Classifier: Programming Language :: C
12
18
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
19
  Classifier: Topic :: Multimedia :: Graphics :: 3D Rendering
@@ -16,7 +22,7 @@ Requires-Python: >=3.9
16
22
  Description-Content-Type: text/x-rst
17
23
  Requires-Dist: numpy
18
24
  Requires-Dist: PyDispatcher
19
- Requires-Dist: simpleparse
25
+ Requires-Dist: simpleparse>=3.0.0a3
20
26
 
21
27
  PyVRML97 Scenegraph Model
22
28
  ==========================
@@ -35,6 +41,13 @@ optimize the rendering process.
35
41
  .. _`PyDispatcher`: https://pypi.python.org/pypi/PyDispatcher
36
42
  .. _`Numpy`: https://pypi.python.org/pypi/numpy
37
43
 
44
+ `RELEASE-NOTES-2.3.5.md`_ says what changed for a program using this release,
45
+ including the two behaviour changes a caller may need to act on:
46
+ ``transformmatrix.orthoMatrix`` is transposed, and ``Node.copy()`` copies the
47
+ whole subtree.
48
+
49
+ .. _`RELEASE-NOTES-2.3.5.md`: RELEASE-NOTES-2.3.5.md
50
+
38
51
  Installation
39
52
  -------------
40
53
 
@@ -1,5 +1,6 @@
1
1
  MANIFEST.in
2
2
  README.rst
3
+ RELEASE-NOTES-2.3.5.md
3
4
  license.txt
4
5
  pyproject.toml
5
6
  requirements.txt
@@ -11,13 +12,34 @@ PyVRML97.egg-info/dependency_links.txt
11
12
  PyVRML97.egg-info/not-zip-safe
12
13
  PyVRML97.egg-info/requires.txt
13
14
  PyVRML97.egg-info/top_level.txt
15
+ tests/test_arrays.py
16
+ tests/test_basefield.py
17
+ tests/test_cache.py
18
+ tests/test_copying.py
19
+ tests/test_csscolors.py
20
+ tests/test_field_assignment.py
21
+ tests/test_field_coercion.py
22
+ tests/test_field_declaration.py
23
+ tests/test_fieldtype_edges.py
14
24
  tests/test_fieldtypes.py
25
+ tests/test_linearise.py
26
+ tests/test_matrix_primitives.py
27
+ tests/test_node_behaviour.py
28
+ tests/test_node_definitions.py
15
29
  tests/test_nodepath.py
16
30
  tests/test_olist.py
31
+ tests/test_parseprocessor.py
32
+ tests/test_parsing_values.py
33
+ tests/test_routes_and_protofunctions.py
34
+ tests/test_scenegraph.py
35
+ tests/test_smallmodules.py
17
36
  tests/test_tostring.py
37
+ tests/test_transform_composition.py
18
38
  tests/test_transformmatrix.py
39
+ tests/test_vrml200x_parser.py
40
+ tests/test_vrmlstr.py
41
+ tests/test_weakcollections.py
19
42
  vrml/__init__.py
20
- vrml/_bytes.py
21
43
  vrml/arrays.py
22
44
  vrml/cache.py
23
45
  vrml/copier.py
@@ -30,8 +52,8 @@ vrml/nodepath.py
30
52
  vrml/olist.py
31
53
  vrml/protofunctions.py
32
54
  vrml/protonamespace.py
55
+ vrml/py.typed
33
56
  vrml/route.py
34
- vrml/weakkeydictfix.py
35
57
  vrml/weaklist.py
36
58
  vrml/weaktuple.py
37
59
  vrml/vrml200x/__init__.py
@@ -50,4 +72,5 @@ vrml/vrml97/parser.py
50
72
  vrml/vrml97/scenegraph.py
51
73
  vrml/vrml97/script.py
52
74
  vrml/vrml97/shaders.py
53
- vrml/vrml97/transformmatrix.py
75
+ vrml/vrml97/transformmatrix.py
76
+ vrml/vrml97/tree.py
@@ -0,0 +1,3 @@
1
+ numpy
2
+ PyDispatcher
3
+ simpleparse>=3.0.0a3
@@ -15,6 +15,13 @@ optimize the rendering process.
15
15
  .. _`PyDispatcher`: https://pypi.python.org/pypi/PyDispatcher
16
16
  .. _`Numpy`: https://pypi.python.org/pypi/numpy
17
17
 
18
+ `RELEASE-NOTES-2.3.5.md`_ says what changed for a program using this release,
19
+ including the two behaviour changes a caller may need to act on:
20
+ ``transformmatrix.orthoMatrix`` is transposed, and ``Node.copy()`` copies the
21
+ whole subtree.
22
+
23
+ .. _`RELEASE-NOTES-2.3.5.md`: RELEASE-NOTES-2.3.5.md
24
+
18
25
  Installation
19
26
  -------------
20
27
 
@@ -0,0 +1,104 @@
1
+ # PyVRML97 2.3.5
2
+
3
+ ## What changed for a program using this
4
+
5
+ ### `transformmatrix.orthoMatrix` is transposed
6
+
7
+ It answers the row-vector form now, matching `perspectiveMatrix`, the three
8
+ primitives beside it, and the module's own instructions: a point goes through
9
+ a matrix here as `dot( point, matrix )`. The previous form put the offset in
10
+ the last column, so a point through it landed the translation in `w`; a
11
+ centred box came out right and an off-centre one did not.
12
+
13
+ A caller that fed the result straight to `glLoadMatrixf` was relying on GL's
14
+ column-major upload to transpose it back. That caller now wants
15
+ `matrix.T` — or, better, one of the core-profile paths that take a row-vector
16
+ matrix.
17
+
18
+ ### `Node.copy()` copies the whole subtree
19
+
20
+ A node's copy shared the nodes its fields pointed at, so writing to the copy's
21
+ child was writing to the original's. Each instance of a PROTO is a copy of the
22
+ prototype's body, so this was also why two instances of one prototype drew the
23
+ same thing: `Wheel { radius 2 }` beside `Wheel { radius 5 }` gave two wheels of
24
+ radius 5. A node reached twice in the original is still one node in the copy,
25
+ which is what DEF/USE and a prototype's IS wiring need.
26
+
27
+ ### `NULL` compares and hashes as a value
28
+
29
+ `NullNode.__eq__` answered a three-way comparison — 0 for equal, which reads as
30
+ false, and -1 for anything else, which reads as true. `NULL == 42` was true and
31
+ `NULL == NullNode()` was false, and the class was unhashable. It now equals
32
+ another NULL, differs from anything that is not a node, and can be a dictionary
33
+ key.
34
+
35
+ ### A field left at its default is no longer written
36
+
37
+ `arrays.safeCompare` is what the lineariser asks about every field it is about
38
+ to write, and it answered two questions wrongly. Two arrays were "the same"
39
+ when they shared a single element, and a list compared as a different type from
40
+ an array — which is the pair the question is usually about, since a node
41
+ declares its default as a list of numbers and stores its value as an array. So
42
+ no vector field ever looked like its default, and every one was written out.
43
+
44
+ A `Transform` with a translation set was written with all eight of its fields;
45
+ it is written with the one now. Files are shorter and read back the same. NULL
46
+ node fields go the same way, now that `NULL` compares as a value.
47
+
48
+ A program that read the output looking for a field it had not set will not find
49
+ it. That is what the format says, and what a file written by anything else
50
+ looks like.
51
+
52
+ ### `del someNode.children[0]` removes the child
53
+
54
+ It announced the removal and left the child in the list. Only the slice form
55
+ deleted anything.
56
+
57
+ ### A node appended to a scene learns which scene it is in
58
+
59
+ `scene.children.append(node)` left the node without a scene root, so `getProto`
60
+ and the DEF names did not reach it; only assignment to the whole field passed
61
+ the root down. Both do now.
62
+
63
+ ## What a file can say that it could not
64
+
65
+ - **Every registered field type can be read.** `SFVec4f`, `SFVec2d`, `SFVec3d`,
66
+ `SFVec4d`, `SFUInt32`, `SFArray32`, `MFVec4f`, `MFVec2d`, `MFVec3d`,
67
+ `MFVec4d` and the four `MFMatrix` types had no reader; a file naming one
68
+ raised. The four `SFMatrix` types were not registered at all, so a PROTO
69
+ could not declare one.
70
+ - **A file that is a header and nothing else parses**, as does one whose last
71
+ line is a comment.
72
+ - **A PROTO declared without a body can be written out.**
73
+
74
+ ## What the writer gets right
75
+
76
+ - An **MFString** field is written as a list of strings rather than as a list of
77
+ nodes. A node with a non-empty MFString — `Text`, `WorldInfo`, `Anchor`,
78
+ `ImageTexture`, `Script`, `Inline` — was written with an opening bracket that
79
+ was never closed and its next field swallowed inside it.
80
+ - An **EXTERNPROTO** reads back: its interface is written without values, which
81
+ is what VRML97 has room for, and `externalURL` is no longer written as one of
82
+ the fields the prototype declares.
83
+ - A **Script** is written as `DEF x Script` rather than `DEF x Script`, and
84
+ closed with a comment naming `x`.
85
+ - `Lineariser.linear( scene, skipProtos=... )` leaves the named prototypes out.
86
+ The argument was accepted and dropped. Name them by name, by the prototype
87
+ itself, or as the keys of a mapping such as a scene graph's `protoTypes`;
88
+ their instances are still written, which is how a caller writes a fragment
89
+ for a file that already declares them.
90
+
91
+ ## Smaller things
92
+
93
+ - `protofunctions.getField` answers the field for a name that is not an
94
+ attribute — `' DEF'`, or an event stored under a name a program cannot write.
95
+ It answered the name itself.
96
+ - `str(node)` says the node's DEF name.
97
+ - Setting a vector field from one number works: `transform.scale = 2` raised.
98
+ - `MFString` refuses a value it cannot read with a ValueError naming the field,
99
+ as its sibling types do.
100
+ - `field.PyBaseField` names the Python implementation of the field primitives
101
+ whichever build is installed, so the two can be compared. Where the
102
+ accelerator is installed, `field.BaseField` is the compiled class as before.
103
+ - `vrml.arrays` drops what it carried for Numeric. `typeCode` reads
104
+ `dtype.char`; the `typecode()` fallbacks are gone.
@@ -0,0 +1,112 @@
1
+ [build-system]
2
+ # PyVRML97 (the root package) is pure Python - no C extensions - so it needs
3
+ # nothing but setuptools to build. Cython/numpy build-deps live only in
4
+ # accelerate/pyproject.toml, where the extensions actually are. setuptools>=61
5
+ # is required to read the PEP 621 [project] table below.
6
+ requires = ["setuptools>=61.0"]
7
+ build-backend = "setuptools.build_meta"
8
+
9
+ [project]
10
+ name = "PyVRML97"
11
+ dynamic = ["version"]
12
+ description = "VRML97 Scenegraph model for Python"
13
+ requires-python = ">=3.9"
14
+ readme = "README.rst"
15
+ license = { text = "BSD-style, see license.txt for details" }
16
+ authors = [
17
+ { name = "Mike C. Fletcher", email = "mcfletch@vrplumber.com" },
18
+ ]
19
+ dependencies = [
20
+ "numpy",
21
+ "PyDispatcher",
22
+ # 3.0.0a3 or newer: the first release with wheels for a current Python.
23
+ # 2.2.4 has none past 3.11 and its mxTextTools C extension does not compile
24
+ # against a current GCC, so an install that resolves to it fails to build.
25
+ # Named as a pre-release so an installer does not skip it.
26
+ "simpleparse >= 3.0.0a3",
27
+ ]
28
+ keywords = [
29
+ "VRML",
30
+ "VRML97",
31
+ "scenegraph",
32
+ ]
33
+ classifiers = [
34
+ "License :: OSI Approved :: BSD License",
35
+ "Programming Language :: Python :: 3",
36
+ "Programming Language :: Python :: 3 :: Only",
37
+ "Programming Language :: Python :: 3.9",
38
+ "Programming Language :: Python :: 3.10",
39
+ "Programming Language :: Python :: 3.11",
40
+ "Programming Language :: Python :: 3.12",
41
+ "Programming Language :: Python :: 3.13",
42
+ "Programming Language :: C",
43
+ "Topic :: Software Development :: Libraries :: Python Modules",
44
+ "Topic :: Multimedia :: Graphics :: 3D Rendering",
45
+ "Intended Audience :: Developers",
46
+ ]
47
+
48
+ [project.urls]
49
+ Homepage = "http://pyopengl.sourceforge.net/context/"
50
+
51
+ [tool.setuptools]
52
+ zip-safe = false
53
+
54
+ [tool.setuptools.packages.find]
55
+ include = ["vrml*"]
56
+
57
+ [tool.setuptools.package-data]
58
+ # `py.typed` is what tells a checker this package's exports are real. Without
59
+ # it `vrml.arrays` -- the abstraction OpenGLContext and its kin reach numpy
60
+ # through -- resolves to nothing, and every `arrays.dot`, `arrays.zeros` and
61
+ # their fellows becomes an error in code that is correct.
62
+ vrml = ["py.typed"]
63
+
64
+ [tool.setuptools.dynamic]
65
+ version = { attr = "vrml.__version__" }
66
+
67
+ # uv decides whether its cached metadata for a source tree is still current
68
+ # from pyproject.toml, setup.py and setup.cfg alone. This project's version
69
+ # lives in vrml/__init__.py, so name that file too: without it a version bump
70
+ # leaves uv answering with the previous number, and a dependent requiring the
71
+ # new one resolves against PyPI rather than this checkout.
72
+ [tool.uv]
73
+ cache-keys = [{ file = "pyproject.toml" }, { file = "vrml/__init__.py" }]
74
+
75
+ # Named explicitly rather than left to ruff's default, which has widened
76
+ # between releases: a gate whose meaning moves when a tool is upgraded is not a
77
+ # gate. `E,W,F,B` is what the other pre-2010 projects here hold to.
78
+ [tool.ruff.lint]
79
+ select = ["E", "W", "F", "B"]
80
+ # `_name` as well as `_`: an underscore prefix is how Python says a name is
81
+ # bound but deliberately unused.
82
+ dummy-variable-rgx = "^(_[a-zA-Z0-9_]*|err)$"
83
+ ignore = [
84
+ 'E501', # long lines, kept readable by hand
85
+ # The scenegraph's namespaces are assembled with `from x import *`, which
86
+ # is how the VRML97 node types are gathered; the names are there at run
87
+ # time. What holds the modules to importing is the suite, which imports
88
+ # them.
89
+ 'F403',
90
+ 'F405',
91
+ ]
92
+
93
+ [tool.mypy]
94
+ # This package ships `py.typed`, so what it declares is what every consumer's
95
+ # checker believes -- `vrml.arrays` is the abstraction OpenGLContext and its
96
+ # kin reach numpy through. Publishing types that nothing holds the package to
97
+ # is worse than publishing none.
98
+ python_version = "3.12"
99
+ files = ["vrml"]
100
+ ignore_missing_imports = true
101
+ warn_unused_ignores = true
102
+ # Every function body, not only the annotated ones. Nothing here was annotated,
103
+ # so without this the gate read the module-level declarations and skipped all
104
+ # 326 bodies -- which is where `str.replace` was called with one argument, where
105
+ # `WeakList.get` called a method Python 2 had, and where a property assigned to
106
+ # itself. A gate that cannot see inside a function is not checking the package.
107
+ check_untyped_defs = true
108
+ # Every one of the 331 definitions carries its types now, so a new one that does
109
+ # not is a gap the gate reports rather than a body it quietly stops checking.
110
+ # This is what keeps the setting above a floor rather than the whole of it.
111
+ disallow_untyped_defs = true
112
+ disallow_incomplete_defs = true
@@ -0,0 +1,8 @@
1
+ --prefer-binary
2
+ # 3.0.0a3 or newer: it is the first release with wheels for a current
3
+ # Python, and 2.2.4's mxTextTools C extension does not compile against a
4
+ # current GCC. Named as a pre-release so an installer does not skip it.
5
+ simpleparse >= 3.0.0a3
6
+ numpy >= 2.0.1; python_version >= '3.10'
7
+ numpy; python_version < '3.10'
8
+ PyDispatcher
@@ -0,0 +1,171 @@
1
+ """The array abstraction the scenegraph reaches numpy through.
2
+
3
+ `vrml.arrays` is what let the package move from Numeric to numpy without every
4
+ node changing, and OpenGLContext and the projects built on it reach numpy
5
+ through it in turn. So what it exports is what a great deal of code sees under
6
+ those names, and a name that shadows a builtin with something that is not a
7
+ drop-in for it is a trap laid across all of that.
8
+
9
+ The reductions -- `sum`, `min`, `max`, `any`, `abs` -- shadow builtins
10
+ deliberately: taking the numpy one is the point, and each answers what the
11
+ builtin does for a scalar. `bool` is the exception, and the reason this file
12
+ names them one at a time rather than asserting a rule about the whole set.
13
+ """
14
+
15
+ import builtins
16
+ import math
17
+
18
+ import unittest
19
+
20
+ from vrml import arrays
21
+
22
+
23
+ class TestWhatItShadows(unittest.TestCase):
24
+ def test_bool_is_the_builtin(self):
25
+ """`numpy.bool` is a scalar type, not a drop-in for the builtin.
26
+
27
+ `isinstance(True, numpy.bool)` is False and `numpy.bool(1) is not
28
+ True`, so a module reading `bool` out of here got a name that fails
29
+ both of the things `bool` is used for.
30
+ """
31
+ self.assertIs(getattr(arrays, 'bool', builtins.bool), builtins.bool)
32
+ self.assertNotIn('bool', arrays.__all__)
33
+
34
+ def test_it_exports_no_other_type_that_shadows_a_builtin(self):
35
+ """A shadowing *function* is the abstraction; a shadowing *type* is not.
36
+
37
+ `sum` and the rest answer for a scalar what the builtin does. A type
38
+ does not: it is what `isinstance` is asked about and what an
39
+ annotation names.
40
+ """
41
+ shadowing_types = [
42
+ name for name in arrays.__all__
43
+ if isinstance(getattr(arrays, name, None), type)
44
+ and hasattr(builtins, name)
45
+ and getattr(arrays, name) is not getattr(builtins, name)
46
+ ]
47
+ self.assertEqual(shadowing_types, [])
48
+
49
+ def test_the_reductions_are_still_numpy(self):
50
+ """Removing one shadow must not take the abstraction with it."""
51
+ for name in ('sum', 'min', 'max', 'any', 'abs'):
52
+ self.assertIn(name, arrays.__all__)
53
+ self.assertIsNot(getattr(arrays, name), getattr(builtins, name), name)
54
+
55
+ def test_log_is_still_not_exported(self):
56
+ """`math.log` and `numpy.log` differ, so neither is offered here."""
57
+ self.assertNotIn('log', arrays.__all__)
58
+
59
+
60
+ class TestSafeCompare(unittest.TestCase):
61
+ """Comparing two field values, either of which may be an array."""
62
+
63
+ def test_two_equal_arrays_compare_equal(self):
64
+ first = arrays.array([1.0, 2.0, 3.0], 'f')
65
+ second = arrays.array([1.0, 2.0, 3.0], 'f')
66
+ self.assertTrue(arrays.safeCompare(first, second))
67
+
68
+ def test_two_different_arrays_do_not(self):
69
+ first = arrays.array([1.0, 2.0, 3.0], 'f')
70
+ second = arrays.array([9.0, 9.0, 9.0], 'f')
71
+ self.assertFalse(arrays.safeCompare(first, second))
72
+
73
+ def test_arrays_alike_in_one_place_are_not_equal(self):
74
+ """Every element has to match, not merely one of them: the
75
+ lineariser asks this to decide whether a field is still at its
76
+ default, and a translation of (1,0,0) shares two with (0,0,0)."""
77
+ first = arrays.array([0.0, 0.0, 0.0], 'f')
78
+ second = arrays.array([1.0, 0.0, 0.0], 'f')
79
+ self.assertFalse(arrays.safeCompare(first, second))
80
+
81
+ def test_arrays_of_different_lengths_are_not_equal(self):
82
+ self.assertFalse(arrays.safeCompare(arrays.array([1.0, 2.0], 'f'),
83
+ arrays.array([1.0], 'f')))
84
+
85
+ def test_a_sequence_equals_the_array_of_the_same_numbers(self):
86
+ """A node declares its default as a list and stores its value as an
87
+ array, and the two are the same value."""
88
+ self.assertTrue(arrays.safeCompare([0.0, 0.0, 0.0],
89
+ arrays.array([0.0, 0.0, 0.0], 'f')))
90
+
91
+ def test_a_sequence_of_other_numbers_does_not(self):
92
+ self.assertFalse(arrays.safeCompare([0.0, 0.0, 0.0],
93
+ arrays.array([1.0, 0.0, 0.0], 'f')))
94
+
95
+ def test_two_equal_sequences_compare_equal(self):
96
+ self.assertTrue(arrays.safeCompare([1.0, 2.0], (1.0, 2.0)))
97
+
98
+ def test_two_empty_sequences_compare_equal(self):
99
+ self.assertTrue(arrays.safeCompare([], arrays.array([], 'f')))
100
+
101
+ def test_a_list_of_objects_compares_by_identity(self):
102
+ """Which is what an MFNode's value is: the same nodes or not."""
103
+ held = [object(), object()]
104
+ self.assertTrue(arrays.safeCompare(held, list(held)))
105
+ self.assertFalse(arrays.safeCompare(held, [held[0], object()]))
106
+
107
+ def test_a_ragged_sequence_falls_back_to_comparing_it(self):
108
+ """numpy refuses to make an array of rows of different lengths, and
109
+ the two lists still have an answer."""
110
+ ragged = [[1, 2], [3]]
111
+ self.assertTrue(arrays.safeCompare(ragged, [[1, 2], [3]]))
112
+ self.assertFalse(arrays.safeCompare(ragged, [[1, 2], [4]]))
113
+
114
+ def test_something_neither_kind_falls_back_to_comparing_it(self):
115
+ self.assertTrue(arrays.safeCompare({'a': 1}, {'a': 1}))
116
+ self.assertFalse(arrays.safeCompare({'a': 1}, {'a': 2}))
117
+
118
+ def test_it_answers_a_real_bool(self):
119
+ """A caller writing `if x is True` or storing the answer wants one."""
120
+ first = arrays.array([1.0], 'f')
121
+ answer = arrays.safeCompare(first, arrays.array([1.0], 'f'))
122
+ self.assertIs(type(answer), builtins.bool)
123
+
124
+ def test_none_compares_equal_to_none(self):
125
+ self.assertTrue(arrays.safeCompare(None, None))
126
+
127
+ def test_none_and_a_value_do_not_compare_equal(self):
128
+ self.assertFalse(arrays.safeCompare(None, 3))
129
+ self.assertFalse(arrays.safeCompare(3, None))
130
+
131
+ def test_two_equal_scalars_compare_equal(self):
132
+ self.assertTrue(arrays.safeCompare(3, 3))
133
+ self.assertTrue(arrays.safeCompare(3.5, 3.5))
134
+ self.assertTrue(arrays.safeCompare('a', 'a'))
135
+
136
+ def test_values_of_different_types_do_not(self):
137
+ self.assertFalse(arrays.safeCompare(arrays.array([1.0], 'f'), 'a'))
138
+
139
+
140
+ class TestTypeCode(unittest.TestCase):
141
+ def test_it_answers_the_arrays_own_code(self):
142
+ self.assertEqual(arrays.typeCode(arrays.array([1.0], 'f')), 'f')
143
+ self.assertEqual(arrays.typeCode(arrays.array([1.0], 'd')), 'd')
144
+
145
+ def test_it_wants_an_array_rather_than_a_sequence(self):
146
+ """It reads the code off the value; a list carries none."""
147
+ with self.assertRaises(AttributeError):
148
+ arrays.typeCode([1.0, 2.0])
149
+
150
+
151
+ class TestContiguous(unittest.TestCase):
152
+ def test_a_contiguous_array_is_answered_as_it_is(self):
153
+ original = arrays.array([1.0, 2.0, 3.0], 'f')
154
+ self.assertTrue(arrays.contiguous(original).flags['C_CONTIGUOUS'])
155
+
156
+ def test_a_sliced_array_is_made_contiguous(self):
157
+ sliced = arrays.array([[1.0, 2.0], [3.0, 4.0]], 'f')[:, 0]
158
+ self.assertTrue(arrays.contiguous(sliced).flags['C_CONTIGUOUS'])
159
+
160
+
161
+ class TestWhichImplementation(unittest.TestCase):
162
+ def test_it_names_the_one_it_is_using(self):
163
+ self.assertEqual(arrays.implementation_name, 'numpy')
164
+
165
+ def test_the_trig_is_the_array_kind(self):
166
+ """`math.sin` keeps a float32 float32; the array one widens it."""
167
+ self.assertIsNot(arrays.sin, math.sin)
168
+
169
+
170
+ if __name__ == '__main__':
171
+ unittest.main()