We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
meshio for i/o
Main author of [meshio](https://github.com/nschloe/meshio) here.

meshio can read a large number of formats which are applicable for vispy, I think it would be a good match for meshio.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `vispy/io/mesh.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # Copyright (c) Vispy Development Team. All Rights Reserved.
3 # Distributed under the (new) BSD License. See LICENSE.txt for more info.
4 
5 """ Reading and writing of data like images and meshes.
6 """
7 
8 from os import path as op
9 
10 from .wavefront import WavefrontReader, WavefrontWriter
11 from .stl import load_stl
12 
13 
14 def read_mesh(fname):
15     """Read mesh data from file.
16 
17     Parameters
18     ----------
19     fname : str
20         File name to read. Format will be inferred from the filename.
21         Currently only '.obj' and '.obj.gz' are supported.
22 
23     Returns
24     -------
25     vertices : array
26         Vertices.
27     faces : array | None
28         Triangle face definitions.
29     normals : array
30         Normals for the mesh.
31     texcoords : array | None
32         Texture coordinates.
33     """
34     # Check format
35     fmt = op.splitext(fname)[1].lower()
36     if fmt == '.gz':
37         fmt = op.splitext(op.splitext(fname)[0])[1].lower()
38 
39     if fmt in ('.obj'):
40         return WavefrontReader.read(fname)
41     elif fmt in ('.stl'):
42         file_obj = open(fname, mode='rb')
43         mesh = load_stl(file_obj)
44         vertices = mesh['vertices']
45         faces = mesh['faces']
46         normals = mesh['face_normals']
47         texcoords = None
48         return vertices, faces, normals, texcoords
49     elif not format:
50         raise ValueError('read_mesh needs could not determine format.')
51     else:
52         raise ValueError('read_mesh does not understand format %s.' % fmt)
53 
54 
55 def write_mesh(fname, vertices, faces, normals, texcoords, name='',
56                format='obj', overwrite=False, reshape_faces=True):
57     """ Write mesh data to file.
58 
59     Parameters
60     ----------
61     fname : str
62         Filename to write. Must end with ".obj" or ".gz".
63     vertices : array
64         Vertices.
65     faces : array | None
66         Triangle face definitions.
67     normals : array
68         Normals for the mesh.
69     texcoords : array | None
70         Texture coordinates.
71     name : str
72         Name of the object.
73     format : str
74         Currently only "obj" is supported.
75     overwrite : bool
76         If the file exists, overwrite it.
77     reshape_faces : bool
78         Reshape the `faces` array to (Nf, 3). Set to `False`
79         if you need to write a mesh with non triangular faces.
80     """
81     # Check file
82     if op.isfile(fname) and not overwrite:
83         raise IOError('file "%s" exists, use overwrite=True' % fname)
84 
85     # Check format
86     if format not in ('obj'):
87         raise ValueError('Only "obj" format writing currently supported')
88     WavefrontWriter.write(fname, vertices, faces,
89                           normals, texcoords, name, reshape_faces)
90
```

Path: `setup.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # Copyright (c) Vispy Development Team. All Rights Reserved.
3 # Distributed under the (new) BSD License. See LICENSE.txt for more info.
4 """Vispy setup script.
5 
6 Steps to do a new release:
7 
8 Preparations:
9   * Test on Windows, Linux, Mac
10   * Make release notes
11   * Update API documentation and other docs that need updating.
12 
13 Define the version and release:
14   * tag the tip changeset as version x.x.x; `git tag -a 'vX.Y.Z' -m "Version X.Y.Z"`
15   * push tag to github
16   * verify that azure pipelines complete
17   * verify that `.tar.gz` sdist and binary wheels are available on PyPI
18 
19 Announcing:
20   * It can be worth waiting a day for eager users to report critical bugs
21   * Announce in scipy-user, vispy mailing list, twitter (@vispyproject)
22 
23 """
24 
25 import os
26 import sys
27 import platform
28 from os import path as op
29 from distutils import log
30 from setuptools import setup, find_packages, Command, Extension
31 from setuptools.command.sdist import sdist
32 from setuptools.command.build_py import build_py
33 from setuptools.command.egg_info import egg_info
34 from subprocess import check_call
35 
36 import numpy as np
37 from Cython.Build import cythonize
38 
39 log.set_verbosity(log.DEBUG)
40 log.info('setup.py entered')
41 log.info('$PATH=%s' % os.environ['PATH'])
42 
43 name = 'vispy'
44 description = 'Interactive visualization in Python'
45 
46 # Special commands for building jupyter notebook extension
47 here = os.path.dirname(os.path.abspath(__file__))
48 node_root = os.path.join(here, 'js')
49 is_repo = os.path.exists(os.path.join(here, '.git'))
50 
51 npm_path = os.pathsep.join([
52     os.path.join(node_root, 'node_modules', '.bin'),
53     os.environ.get('PATH', os.defpath),
54 ])
55 
56 
57 def set_builtin(name, value):
58     if isinstance(__builtins__, dict):
59         __builtins__[name] = value
60     else:
61         setattr(__builtins__, name, value)
62 
63 
64 def js_prerelease(command, strict=False):
65     """decorator for building minified js/css prior to another command"""
66     class DecoratedCommand(command):
67         def run(self):
68             jsdeps = self.distribution.get_command_obj('jsdeps')
69             if not is_repo and all(os.path.exists(t) for t in jsdeps.targets):
70                 # sdist, nothing to do
71                 command.run(self)
72                 return
73 
74             try:
75                 self.distribution.run_command('jsdeps')
76             except Exception as e:
77                 missing = [t for t in jsdeps.targets if not os.path.exists(t)]
78                 if strict or missing:
79                     log.warn('rebuilding js and css failed')
80                     if missing:
81                         log.error('missing files: %s' % missing)
82                     # HACK: Allow users who can't build the JS to still install vispy
83                     if not is_repo:
84                         raise e
85                     log.warn('WARNING: continuing installation WITHOUT nbextension javascript')
86                     # remove JS files from data_files so setuptools doesn't try to copy
87                     # non-existent files
88                     self.distribution.data_files = [x for x in self.distribution.data_files
89                                                     if 'jupyter' not in x[0]]
90                 else:
91                     log.warn('rebuilding js and css failed (not a problem)')
92                     log.warn(str(e))
93             command.run(self)
94             update_package_data(self.distribution)
95     return DecoratedCommand
96 
97 
98 def update_package_data(distribution):
99     """update package_data to catch changes during setup"""
100     build_py = distribution.get_command_obj('build_py')
101     # distribution.package_data = find_package_data()
102     # re-init build_py options which load package_data
103     build_py.finalize_options()
104 
105 
106 class NPM(Command):
107     description = 'install package.json dependencies using npm'
108 
109     user_options = []
110 
111     node_modules = os.path.join(node_root, 'node_modules')
112 
113     targets = [
114         os.path.join(here, 'vispy', 'static', 'extension.js'),
115         os.path.join(here, 'vispy', 'static', 'index.js')
116     ]
117 
118     def initialize_options(self):
119         pass
120 
121     def finalize_options(self):
122         pass
123 
124     def get_npm_name(self):
125         npmName = 'npm';
126         if platform.system() == 'Windows':
127             npmName = 'npm.cmd';
128 
129         return npmName;
130 
131     def has_npm(self):
132         npmName = self.get_npm_name();
133         try:
134             check_call([npmName, '--version'])
135             return True
136         except:
137             return False
138 
139     def should_run_npm_install(self):
140         package_json = os.path.join(node_root, 'package.json')
141         node_modules_exists = os.path.exists(self.node_modules)
142         return self.has_npm()
143 
144     def run(self):
145         has_npm = self.has_npm()
146         if not has_npm:
147             log.error("`npm` unavailable.  If you're running this command "
148                       "using sudo, make sure `npm` is available to sudo")
149 
150         env = os.environ.copy()
151         env['PATH'] = npm_path
152 
153         if self.should_run_npm_install():
154             log.info("Installing build dependencies with npm.  This may take "
155                      "a while...")
156             npmName = self.get_npm_name();
157             check_call([npmName, 'install', '--verbose'], cwd=node_root,
158                        stdout=sys.stdout, stderr=sys.stderr)
159             os.utime(self.node_modules, None)
160 
161         for t in self.targets:
162             if not os.path.exists(t):
163                 msg = 'Missing file: %s' % t
164                 if not has_npm:
165                     msg += '\nnpm is required to build a development ' \
166                            'version of a widget extension'
167                 raise ValueError(msg)
168 
169         # update package data in case this created new files
170         update_package_data(self.distribution)
171 
172 
173 extensions = [Extension('vispy.visuals.text._sdf_cpu',
174                         [op.join('vispy', 'visuals', 'text', '_sdf_cpu.pyx')],
175                         include_dirs=[np.get_include()]),
176               ]
177 
178 readme = open('README.rst', 'r').read()
179 setup(
180     name=name,
181     use_scm_version={'write_to': 'vispy/version.py'},
182     author='Vispy contributors',
183     author_email='vispy@googlegroups.com',
184     license='(new) BSD',
185     url='http://vispy.org',
186     download_url='https://pypi.python.org/pypi/vispy',
187     keywords=[
188         'visualization',
189         'OpenGl',
190         'ES',
191         'medical',
192         'imaging',
193         '3D',
194         'plotting',
195         'numpy',
196         'bigdata',
197         'ipython',
198         'jupyter',
199         'widgets',
200     ],
201     description=description,
202     long_description=readme,
203     platforms='any',
204     provides=['vispy'],
205     cmdclass={
206         'build_py': js_prerelease(build_py),
207         'egg_info': js_prerelease(egg_info),
208         'sdist': js_prerelease(sdist, strict=True),
209         'jsdeps': NPM,
210     },
211     python_requires='>=3.6',
212     install_requires=['numpy', 'freetype-py'],
213     setup_requires=['numpy', 'cython', 'setuptools_scm', 'setuptools_scm_git_archive'],
214     extras_require={
215         'ipython-static': ['ipython'],
216         'ipython-vnc': ['ipython>=7'],
217         'ipython-webgl': ['ipywidgets>=7.0', 'ipython>=7', 'tornado'],
218         'pyglet': ['pyglet>=1.2'],
219         'pyqt5': ['pyqt5'],
220         'pyside': ['PySide'],
221         'pyside2': ['PySide2'],
222         'sdl2': ['PySDL2'],
223         'wx': ['wxPython'],
224         'doc': ['sphinx_bootstrap_theme', 'numpydoc'],
225     },
226     packages=find_packages(exclude=['make']),
227     ext_modules=cythonize(extensions),
228     package_dir={'vispy': 'vispy'},
229     data_files=[
230         ('share/jupyter/nbextensions/vispy', [
231             'vispy/static/extension.js',
232             'vispy/static/index.js',
233             'vispy/static/index.js.map',
234         ]),
235         ('etc/jupyter/nbconfig/notebook.d', ['vispy.json']),
236     ],
237     include_package_data=True,
238     package_data={
239         'vispy': [op.join('io', '_data', '*'),
240                   op.join('html', 'static', 'js', '*'),
241                   op.join('app', 'tests', 'qt-designer.ui'),
242                   op.join('util', 'fonts', 'data', '*.ttf'),
243                   ],
244 
245         'vispy.glsl': ['*.vert','*.frag', "*.glsl"],
246         'vispy.glsl.antialias': ['*.vert','*.frag', "*.glsl"],
247         'vispy.glsl.arrowheads': ['*.vert','*.frag', "*.glsl"],
248         'vispy.glsl.arrows': ['*.vert','*.frag', "*.glsl"],
249         'vispy.glsl.collections': ['*.vert','*.frag', "*.glsl"],
250         'vispy.glsl.colormaps': ['*.vert','*.frag', "*.glsl"],
251         'vispy.glsl.lines': ['*.vert','*.frag', "*.glsl"],
252         'vispy.glsl.markers': ['*.vert','*.frag', "*.glsl"],
253         'vispy.glsl.math': ['*.vert','*.frag', "*.glsl"],
254         'vispy.glsl.misc': ['*.vert','*.frag', "*.glsl"],
255         'vispy.glsl.transforms': ['*.vert','*.frag', "*.glsl"],
256 
257                   },
258     zip_safe=False,
259     classifiers=[
260         'Development Status :: 3 - Alpha',
261         'Intended Audience :: Science/Research',
262         'Intended Audience :: Education',
263         'Intended Audience :: Developers',
264         'Topic :: Scientific/Engineering :: Visualization',
265         'License :: OSI Approved :: BSD License',
266         'Operating System :: MacOS :: MacOS X',
267         'Operating System :: Microsoft :: Windows',
268         'Operating System :: POSIX',
269         'Programming Language :: Python',
270         'Programming Language :: Python :: 3.6',
271         'Programming Language :: Python :: 3.7',
272         'Programming Language :: Python :: 3.8',
273         'Framework :: IPython'
274     ],
275 )
276
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -222,6 +222,7 @@
         'sdl2': ['PySDL2'],
         'wx': ['wxPython'],
         'doc': ['sphinx_bootstrap_theme', 'numpydoc'],
+        'io': ['meshio'],
     },
     packages=find_packages(exclude=['make']),
     ext_modules=cythonize(extensions),
diff --git a/vispy/io/mesh.py b/vispy/io/mesh.py
--- a/vispy/io/mesh.py
+++ b/vispy/io/mesh.py
@@ -5,6 +5,7 @@
 """ Reading and writing of data like images and meshes.
 """
 
+import os
 from os import path as op
 
 from .wavefront import WavefrontReader, WavefrontWriter
@@ -46,14 +47,26 @@
         normals = mesh['face_normals']
         texcoords = None
         return vertices, faces, normals, texcoords
-    elif not format:
-        raise ValueError('read_mesh needs could not determine format.')
     else:
-        raise ValueError('read_mesh does not understand format %s.' % fmt)
+        try:
+            import meshio
+        except ImportError:
+            raise ValueError('read_mesh does not understand format %s.' % fmt)
+
+        try:
+            mesh = meshio.read(fname)
+        except meshio.ReadError:
+            raise ValueError('read_mesh does not understand format %s.' % fmt)
+
+        triangles = mesh.get_cells_type("triangle")
+        if len(triangles) == 0:
+            raise ValueError('mesh file does not contain triangles.')
+
+        return mesh.points, triangles, None, None
 
 
 def write_mesh(fname, vertices, faces, normals, texcoords, name='',
-               format='obj', overwrite=False, reshape_faces=True):
+               format=None, overwrite=False, reshape_faces=True):
     """ Write mesh data to file.
 
     Parameters
@@ -82,8 +95,29 @@
     if op.isfile(fname) and not overwrite:
         raise IOError('file "%s" exists, use overwrite=True' % fname)
 
+    if format is None:
+        format = os.path.splitext(fname)[1][1:]
+
     # Check format
-    if format not in ('obj'):
-        raise ValueError('Only "obj" format writing currently supported')
-    WavefrontWriter.write(fname, vertices, faces,
-                          normals, texcoords, name, reshape_faces)
+    if format == 'obj':
+        WavefrontWriter.write(fname, vertices, faces,
+                              normals, texcoords, name, reshape_faces)
+        return
+
+    try:
+        import meshio
+    except ImportError:
+        raise ValueError('write_mesh does not understand format %s.' % format)
+
+    cell_data = {}
+    if normals is not None:
+        cell_data["normals"] = [normals]
+    if texcoords is not None:
+        cell_data["texcoords"] = [texcoords]
+
+    mesh = meshio.Mesh(vertices, [("triangle", faces)], cell_data=cell_data)
+
+    try:
+        mesh.write(fname, file_format=format)
+    except meshio.WriteError:
+        raise ValueError('write_mesh does not understand format %s.' % format)

{"golden_diff": "diff --git a/setup.py b/setup.py\n--- a/setup.py\n+++ b/setup.py\n@@ -222,6 +222,7 @@\n         'sdl2': ['PySDL2'],\n         'wx': ['wxPython'],\n         'doc': ['sphinx_bootstrap_theme', 'numpydoc'],\n+        'io': ['meshio'],\n     },\n     packages=find_packages(exclude=['make']),\n     ext_modules=cythonize(extensions),\ndiff --git a/vispy/io/mesh.py b/vispy/io/mesh.py\n--- a/vispy/io/mesh.py\n+++ b/vispy/io/mesh.py\n@@ -5,6 +5,7 @@\n \"\"\" Reading and writing of data like images and meshes.\n \"\"\"\n \n+import os\n from os import path as op\n \n from .wavefront import WavefrontReader, WavefrontWriter\n@@ -46,14 +47,26 @@\n         normals = mesh['face_normals']\n         texcoords = None\n         return vertices, faces, normals, texcoords\n-    elif not format:\n-        raise ValueError('read_mesh needs could not determine format.')\n     else:\n-        raise ValueError('read_mesh does not understand format %s.' % fmt)\n+        try:\n+            import meshio\n+        except ImportError:\n+            raise ValueError('read_mesh does not understand format %s.' % fmt)\n+\n+        try:\n+            mesh = meshio.read(fname)\n+        except meshio.ReadError:\n+            raise ValueError('read_mesh does not understand format %s.' % fmt)\n+\n+        triangles = mesh.get_cells_type(\"triangle\")\n+        if len(triangles) == 0:\n+            raise ValueError('mesh file does not contain triangles.')\n+\n+        return mesh.points, triangles, None, None\n \n \n def write_mesh(fname, vertices, faces, normals, texcoords, name='',\n-               format='obj', overwrite=False, reshape_faces=True):\n+               format=None, overwrite=False, reshape_faces=True):\n     \"\"\" Write mesh data to file.\n \n     Parameters\n@@ -82,8 +95,29 @@\n     if op.isfile(fname) and not overwrite:\n         raise IOError('file \"%s\" exists, use overwrite=True' % fname)\n \n+    if format is None:\n+        format = os.path.splitext(fname)[1][1:]\n+\n     # Check format\n-    if format not in ('obj'):\n-        raise ValueError('Only \"obj\" format writing currently supported')\n-    WavefrontWriter.write(fname, vertices, faces,\n-                          normals, texcoords, name, reshape_faces)\n+    if format == 'obj':\n+        WavefrontWriter.write(fname, vertices, faces,\n+                              normals, texcoords, name, reshape_faces)\n+        return\n+\n+    try:\n+        import meshio\n+    except ImportError:\n+        raise ValueError('write_mesh does not understand format %s.' % format)\n+\n+    cell_data = {}\n+    if normals is not None:\n+        cell_data[\"normals\"] = [normals]\n+    if texcoords is not None:\n+        cell_data[\"texcoords\"] = [texcoords]\n+\n+    mesh = meshio.Mesh(vertices, [(\"triangle\", faces)], cell_data=cell_data)\n+\n+    try:\n+        mesh.write(fname, file_format=format)\n+    except meshio.WriteError:\n+        raise ValueError('write_mesh does not understand format %s.' % format)\n", "issue": "meshio for i/o\nMain author of [meshio](https://github.com/nschloe/meshio) here.\r\n\r\nmeshio can read a large number of formats which are applicable for vispy, I think it would be a good match for meshio.\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright (c) Vispy Development Team. All Rights Reserved.\n# Distributed under the (new) BSD License. See LICENSE.txt for more info.\n\n\"\"\" Reading and writing of data like images and meshes.\n\"\"\"\n\nfrom os import path as op\n\nfrom .wavefront import WavefrontReader, WavefrontWriter\nfrom .stl import load_stl\n\n\ndef read_mesh(fname):\n    \"\"\"Read mesh data from file.\n\n    Parameters\n    ----------\n    fname : str\n        File name to read. Format will be inferred from the filename.\n        Currently only '.obj' and '.obj.gz' are supported.\n\n    Returns\n    -------\n    vertices : array\n        Vertices.\n    faces : array | None\n        Triangle face definitions.\n    normals : array\n        Normals for the mesh.\n    texcoords : array | None\n        Texture coordinates.\n    \"\"\"\n    # Check format\n    fmt = op.splitext(fname)[1].lower()\n    if fmt == '.gz':\n        fmt = op.splitext(op.splitext(fname)[0])[1].lower()\n\n    if fmt in ('.obj'):\n        return WavefrontReader.read(fname)\n    elif fmt in ('.stl'):\n        file_obj = open(fname, mode='rb')\n        mesh = load_stl(file_obj)\n        vertices = mesh['vertices']\n        faces = mesh['faces']\n        normals = mesh['face_normals']\n        texcoords = None\n        return vertices, faces, normals, texcoords\n    elif not format:\n        raise ValueError('read_mesh needs could not determine format.')\n    else:\n        raise ValueError('read_mesh does not understand format %s.' % fmt)\n\n\ndef write_mesh(fname, vertices, faces, normals, texcoords, name='',\n               format='obj', overwrite=False, reshape_faces=True):\n    \"\"\" Write mesh data to file.\n\n    Parameters\n    ----------\n    fname : str\n        Filename to write. Must end with \".obj\" or \".gz\".\n    vertices : array\n        Vertices.\n    faces : array | None\n        Triangle face definitions.\n    normals : array\n        Normals for the mesh.\n    texcoords : array | None\n        Texture coordinates.\n    name : str\n        Name of the object.\n    format : str\n        Currently only \"obj\" is supported.\n    overwrite : bool\n        If the file exists, overwrite it.\n    reshape_faces : bool\n        Reshape the `faces` array to (Nf, 3). Set to `False`\n        if you need to write a mesh with non triangular faces.\n    \"\"\"\n    # Check file\n    if op.isfile(fname) and not overwrite:\n        raise IOError('file \"%s\" exists, use overwrite=True' % fname)\n\n    # Check format\n    if format not in ('obj'):\n        raise ValueError('Only \"obj\" format writing currently supported')\n    WavefrontWriter.write(fname, vertices, faces,\n                          normals, texcoords, name, reshape_faces)\n", "path": "vispy/io/mesh.py"}, {"content": "# -*- coding: utf-8 -*-\n# Copyright (c) Vispy Development Team. All Rights Reserved.\n# Distributed under the (new) BSD License. See LICENSE.txt for more info.\n\"\"\"Vispy setup script.\n\nSteps to do a new release:\n\nPreparations:\n  * Test on Windows, Linux, Mac\n  * Make release notes\n  * Update API documentation and other docs that need updating.\n\nDefine the version and release:\n  * tag the tip changeset as version x.x.x; `git tag -a 'vX.Y.Z' -m \"Version X.Y.Z\"`\n  * push tag to github\n  * verify that azure pipelines complete\n  * verify that `.tar.gz` sdist and binary wheels are available on PyPI\n\nAnnouncing:\n  * It can be worth waiting a day for eager users to report critical bugs\n  * Announce in scipy-user, vispy mailing list, twitter (@vispyproject)\n\n\"\"\"\n\nimport os\nimport sys\nimport platform\nfrom os import path as op\nfrom distutils import log\nfrom setuptools import setup, find_packages, Command, Extension\nfrom setuptools.command.sdist import sdist\nfrom setuptools.command.build_py import build_py\nfrom setuptools.command.egg_info import egg_info\nfrom subprocess import check_call\n\nimport numpy as np\nfrom Cython.Build import cythonize\n\nlog.set_verbosity(log.DEBUG)\nlog.info('setup.py entered')\nlog.info('$PATH=%s' % os.environ['PATH'])\n\nname = 'vispy'\ndescription = 'Interactive visualization in Python'\n\n# Special commands for building jupyter notebook extension\nhere = os.path.dirname(os.path.abspath(__file__))\nnode_root = os.path.join(here, 'js')\nis_repo = os.path.exists(os.path.join(here, '.git'))\n\nnpm_path = os.pathsep.join([\n    os.path.join(node_root, 'node_modules', '.bin'),\n    os.environ.get('PATH', os.defpath),\n])\n\n\ndef set_builtin(name, value):\n    if isinstance(__builtins__, dict):\n        __builtins__[name] = value\n    else:\n        setattr(__builtins__, name, value)\n\n\ndef js_prerelease(command, strict=False):\n    \"\"\"decorator for building minified js/css prior to another command\"\"\"\n    class DecoratedCommand(command):\n        def run(self):\n            jsdeps = self.distribution.get_command_obj('jsdeps')\n            if not is_repo and all(os.path.exists(t) for t in jsdeps.targets):\n                # sdist, nothing to do\n                command.run(self)\n                return\n\n            try:\n                self.distribution.run_command('jsdeps')\n            except Exception as e:\n                missing = [t for t in jsdeps.targets if not os.path.exists(t)]\n                if strict or missing:\n                    log.warn('rebuilding js and css failed')\n                    if missing:\n                        log.error('missing files: %s' % missing)\n                    # HACK: Allow users who can't build the JS to still install vispy\n                    if not is_repo:\n                        raise e\n                    log.warn('WARNING: continuing installation WITHOUT nbextension javascript')\n                    # remove JS files from data_files so setuptools doesn't try to copy\n                    # non-existent files\n                    self.distribution.data_files = [x for x in self.distribution.data_files\n                                                    if 'jupyter' not in x[0]]\n                else:\n                    log.warn('rebuilding js and css failed (not a problem)')\n                    log.warn(str(e))\n            command.run(self)\n            update_package_data(self.distribution)\n    return DecoratedCommand\n\n\ndef update_package_data(distribution):\n    \"\"\"update package_data to catch changes during setup\"\"\"\n    build_py = distribution.get_command_obj('build_py')\n    # distribution.package_data = find_package_data()\n    # re-init build_py options which load package_data\n    build_py.finalize_options()\n\n\nclass NPM(Command):\n    description = 'install package.json dependencies using npm'\n\n    user_options = []\n\n    node_modules = os.path.join(node_root, 'node_modules')\n\n    targets = [\n        os.path.join(here, 'vispy', 'static', 'extension.js'),\n        os.path.join(here, 'vispy', 'static', 'index.js')\n    ]\n\n    def initialize_options(self):\n        pass\n\n    def finalize_options(self):\n        pass\n\n    def get_npm_name(self):\n        npmName = 'npm';\n        if platform.system() == 'Windows':\n            npmName = 'npm.cmd';\n\n        return npmName;\n\n    def has_npm(self):\n        npmName = self.get_npm_name();\n        try:\n            check_call([npmName, '--version'])\n            return True\n        except:\n            return False\n\n    def should_run_npm_install(self):\n        package_json = os.path.join(node_root, 'package.json')\n        node_modules_exists = os.path.exists(self.node_modules)\n        return self.has_npm()\n\n    def run(self):\n        has_npm = self.has_npm()\n        if not has_npm:\n            log.error(\"`npm` unavailable.  If you're running this command \"\n                      \"using sudo, make sure `npm` is available to sudo\")\n\n        env = os.environ.copy()\n        env['PATH'] = npm_path\n\n        if self.should_run_npm_install():\n            log.info(\"Installing build dependencies with npm.  This may take \"\n                     \"a while...\")\n            npmName = self.get_npm_name();\n            check_call([npmName, 'install', '--verbose'], cwd=node_root,\n                       stdout=sys.stdout, stderr=sys.stderr)\n            os.utime(self.node_modules, None)\n\n        for t in self.targets:\n            if not os.path.exists(t):\n                msg = 'Missing file: %s' % t\n                if not has_npm:\n                    msg += '\\nnpm is required to build a development ' \\\n                           'version of a widget extension'\n                raise ValueError(msg)\n\n        # update package data in case this created new files\n        update_package_data(self.distribution)\n\n\nextensions = [Extension('vispy.visuals.text._sdf_cpu',\n                        [op.join('vispy', 'visuals', 'text', '_sdf_cpu.pyx')],\n                        include_dirs=[np.get_include()]),\n              ]\n\nreadme = open('README.rst', 'r').read()\nsetup(\n    name=name,\n    use_scm_version={'write_to': 'vispy/version.py'},\n    author='Vispy contributors',\n    author_email='vispy@googlegroups.com',\n    license='(new) BSD',\n    url='http://vispy.org',\n    download_url='https://pypi.python.org/pypi/vispy',\n    keywords=[\n        'visualization',\n        'OpenGl',\n        'ES',\n        'medical',\n        'imaging',\n        '3D',\n        'plotting',\n        'numpy',\n        'bigdata',\n        'ipython',\n        'jupyter',\n        'widgets',\n    ],\n    description=description,\n    long_description=readme,\n    platforms='any',\n    provides=['vispy'],\n    cmdclass={\n        'build_py': js_prerelease(build_py),\n        'egg_info': js_prerelease(egg_info),\n        'sdist': js_prerelease(sdist, strict=True),\n        'jsdeps': NPM,\n    },\n    python_requires='>=3.6',\n    install_requires=['numpy', 'freetype-py'],\n    setup_requires=['numpy', 'cython', 'setuptools_scm', 'setuptools_scm_git_archive'],\n    extras_require={\n        'ipython-static': ['ipython'],\n        'ipython-vnc': ['ipython>=7'],\n        'ipython-webgl': ['ipywidgets>=7.0', 'ipython>=7', 'tornado'],\n        'pyglet': ['pyglet>=1.2'],\n        'pyqt5': ['pyqt5'],\n        'pyside': ['PySide'],\n        'pyside2': ['PySide2'],\n        'sdl2': ['PySDL2'],\n        'wx': ['wxPython'],\n        'doc': ['sphinx_bootstrap_theme', 'numpydoc'],\n    },\n    packages=find_packages(exclude=['make']),\n    ext_modules=cythonize(extensions),\n    package_dir={'vispy': 'vispy'},\n    data_files=[\n        ('share/jupyter/nbextensions/vispy', [\n            'vispy/static/extension.js',\n            'vispy/static/index.js',\n            'vispy/static/index.js.map',\n        ]),\n        ('etc/jupyter/nbconfig/notebook.d', ['vispy.json']),\n    ],\n    include_package_data=True,\n    package_data={\n        'vispy': [op.join('io', '_data', '*'),\n                  op.join('html', 'static', 'js', '*'),\n                  op.join('app', 'tests', 'qt-designer.ui'),\n                  op.join('util', 'fonts', 'data', '*.ttf'),\n                  ],\n\n        'vispy.glsl': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.antialias': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.arrowheads': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.arrows': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.collections': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.colormaps': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.lines': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.markers': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.math': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.misc': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.transforms': ['*.vert','*.frag', \"*.glsl\"],\n\n                  },\n    zip_safe=False,\n    classifiers=[\n        'Development Status :: 3 - Alpha',\n        'Intended Audience :: Science/Research',\n        'Intended Audience :: Education',\n        'Intended Audience :: Developers',\n        'Topic :: Scientific/Engineering :: Visualization',\n        'License :: OSI Approved :: BSD License',\n        'Operating System :: MacOS :: MacOS X',\n        'Operating System :: Microsoft :: Windows',\n        'Operating System :: POSIX',\n        'Programming Language :: Python',\n        'Programming Language :: Python :: 3.6',\n        'Programming Language :: Python :: 3.7',\n        'Programming Language :: Python :: 3.8',\n        'Framework :: IPython'\n    ],\n)\n", "path": "setup.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright (c) Vispy Development Team. All Rights Reserved.\n# Distributed under the (new) BSD License. See LICENSE.txt for more info.\n\n\"\"\" Reading and writing of data like images and meshes.\n\"\"\"\n\nimport os\nfrom os import path as op\n\nfrom .wavefront import WavefrontReader, WavefrontWriter\nfrom .stl import load_stl\n\n\ndef read_mesh(fname):\n    \"\"\"Read mesh data from file.\n\n    Parameters\n    ----------\n    fname : str\n        File name to read. Format will be inferred from the filename.\n        Currently only '.obj' and '.obj.gz' are supported.\n\n    Returns\n    -------\n    vertices : array\n        Vertices.\n    faces : array | None\n        Triangle face definitions.\n    normals : array\n        Normals for the mesh.\n    texcoords : array | None\n        Texture coordinates.\n    \"\"\"\n    # Check format\n    fmt = op.splitext(fname)[1].lower()\n    if fmt == '.gz':\n        fmt = op.splitext(op.splitext(fname)[0])[1].lower()\n\n    if fmt in ('.obj'):\n        return WavefrontReader.read(fname)\n    elif fmt in ('.stl'):\n        file_obj = open(fname, mode='rb')\n        mesh = load_stl(file_obj)\n        vertices = mesh['vertices']\n        faces = mesh['faces']\n        normals = mesh['face_normals']\n        texcoords = None\n        return vertices, faces, normals, texcoords\n    else:\n        try:\n            import meshio\n        except ImportError:\n            raise ValueError('read_mesh does not understand format %s.' % fmt)\n\n        try:\n            mesh = meshio.read(fname)\n        except meshio.ReadError:\n            raise ValueError('read_mesh does not understand format %s.' % fmt)\n\n        triangles = mesh.get_cells_type(\"triangle\")\n        if len(triangles) == 0:\n            raise ValueError('mesh file does not contain triangles.')\n\n        return mesh.points, triangles, None, None\n\n\ndef write_mesh(fname, vertices, faces, normals, texcoords, name='',\n               format=None, overwrite=False, reshape_faces=True):\n    \"\"\" Write mesh data to file.\n\n    Parameters\n    ----------\n    fname : str\n        Filename to write. Must end with \".obj\" or \".gz\".\n    vertices : array\n        Vertices.\n    faces : array | None\n        Triangle face definitions.\n    normals : array\n        Normals for the mesh.\n    texcoords : array | None\n        Texture coordinates.\n    name : str\n        Name of the object.\n    format : str\n        Currently only \"obj\" is supported.\n    overwrite : bool\n        If the file exists, overwrite it.\n    reshape_faces : bool\n        Reshape the `faces` array to (Nf, 3). Set to `False`\n        if you need to write a mesh with non triangular faces.\n    \"\"\"\n    # Check file\n    if op.isfile(fname) and not overwrite:\n        raise IOError('file \"%s\" exists, use overwrite=True' % fname)\n\n    if format is None:\n        format = os.path.splitext(fname)[1][1:]\n\n    # Check format\n    if format == 'obj':\n        WavefrontWriter.write(fname, vertices, faces,\n                              normals, texcoords, name, reshape_faces)\n        return\n\n    try:\n        import meshio\n    except ImportError:\n        raise ValueError('write_mesh does not understand format %s.' % format)\n\n    cell_data = {}\n    if normals is not None:\n        cell_data[\"normals\"] = [normals]\n    if texcoords is not None:\n        cell_data[\"texcoords\"] = [texcoords]\n\n    mesh = meshio.Mesh(vertices, [(\"triangle\", faces)], cell_data=cell_data)\n\n    try:\n        mesh.write(fname, file_format=format)\n    except meshio.WriteError:\n        raise ValueError('write_mesh does not understand format %s.' % format)\n", "path": "vispy/io/mesh.py"}, {"content": "# -*- coding: utf-8 -*-\n# Copyright (c) Vispy Development Team. All Rights Reserved.\n# Distributed under the (new) BSD License. See LICENSE.txt for more info.\n\"\"\"Vispy setup script.\n\nSteps to do a new release:\n\nPreparations:\n  * Test on Windows, Linux, Mac\n  * Make release notes\n  * Update API documentation and other docs that need updating.\n\nDefine the version and release:\n  * tag the tip changeset as version x.x.x; `git tag -a 'vX.Y.Z' -m \"Version X.Y.Z\"`\n  * push tag to github\n  * verify that azure pipelines complete\n  * verify that `.tar.gz` sdist and binary wheels are available on PyPI\n\nAnnouncing:\n  * It can be worth waiting a day for eager users to report critical bugs\n  * Announce in scipy-user, vispy mailing list, twitter (@vispyproject)\n\n\"\"\"\n\nimport os\nimport sys\nimport platform\nfrom os import path as op\nfrom distutils import log\nfrom setuptools import setup, find_packages, Command, Extension\nfrom setuptools.command.sdist import sdist\nfrom setuptools.command.build_py import build_py\nfrom setuptools.command.egg_info import egg_info\nfrom subprocess import check_call\n\nimport numpy as np\nfrom Cython.Build import cythonize\n\nlog.set_verbosity(log.DEBUG)\nlog.info('setup.py entered')\nlog.info('$PATH=%s' % os.environ['PATH'])\n\nname = 'vispy'\ndescription = 'Interactive visualization in Python'\n\n# Special commands for building jupyter notebook extension\nhere = os.path.dirname(os.path.abspath(__file__))\nnode_root = os.path.join(here, 'js')\nis_repo = os.path.exists(os.path.join(here, '.git'))\n\nnpm_path = os.pathsep.join([\n    os.path.join(node_root, 'node_modules', '.bin'),\n    os.environ.get('PATH', os.defpath),\n])\n\n\ndef set_builtin(name, value):\n    if isinstance(__builtins__, dict):\n        __builtins__[name] = value\n    else:\n        setattr(__builtins__, name, value)\n\n\ndef js_prerelease(command, strict=False):\n    \"\"\"decorator for building minified js/css prior to another command\"\"\"\n    class DecoratedCommand(command):\n        def run(self):\n            jsdeps = self.distribution.get_command_obj('jsdeps')\n            if not is_repo and all(os.path.exists(t) for t in jsdeps.targets):\n                # sdist, nothing to do\n                command.run(self)\n                return\n\n            try:\n                self.distribution.run_command('jsdeps')\n            except Exception as e:\n                missing = [t for t in jsdeps.targets if not os.path.exists(t)]\n                if strict or missing:\n                    log.warn('rebuilding js and css failed')\n                    if missing:\n                        log.error('missing files: %s' % missing)\n                    # HACK: Allow users who can't build the JS to still install vispy\n                    if not is_repo:\n                        raise e\n                    log.warn('WARNING: continuing installation WITHOUT nbextension javascript')\n                    # remove JS files from data_files so setuptools doesn't try to copy\n                    # non-existent files\n                    self.distribution.data_files = [x for x in self.distribution.data_files\n                                                    if 'jupyter' not in x[0]]\n                else:\n                    log.warn('rebuilding js and css failed (not a problem)')\n                    log.warn(str(e))\n            command.run(self)\n            update_package_data(self.distribution)\n    return DecoratedCommand\n\n\ndef update_package_data(distribution):\n    \"\"\"update package_data to catch changes during setup\"\"\"\n    build_py = distribution.get_command_obj('build_py')\n    # distribution.package_data = find_package_data()\n    # re-init build_py options which load package_data\n    build_py.finalize_options()\n\n\nclass NPM(Command):\n    description = 'install package.json dependencies using npm'\n\n    user_options = []\n\n    node_modules = os.path.join(node_root, 'node_modules')\n\n    targets = [\n        os.path.join(here, 'vispy', 'static', 'extension.js'),\n        os.path.join(here, 'vispy', 'static', 'index.js')\n    ]\n\n    def initialize_options(self):\n        pass\n\n    def finalize_options(self):\n        pass\n\n    def get_npm_name(self):\n        npmName = 'npm';\n        if platform.system() == 'Windows':\n            npmName = 'npm.cmd';\n\n        return npmName;\n\n    def has_npm(self):\n        npmName = self.get_npm_name();\n        try:\n            check_call([npmName, '--version'])\n            return True\n        except:\n            return False\n\n    def should_run_npm_install(self):\n        package_json = os.path.join(node_root, 'package.json')\n        node_modules_exists = os.path.exists(self.node_modules)\n        return self.has_npm()\n\n    def run(self):\n        has_npm = self.has_npm()\n        if not has_npm:\n            log.error(\"`npm` unavailable.  If you're running this command \"\n                      \"using sudo, make sure `npm` is available to sudo\")\n\n        env = os.environ.copy()\n        env['PATH'] = npm_path\n\n        if self.should_run_npm_install():\n            log.info(\"Installing build dependencies with npm.  This may take \"\n                     \"a while...\")\n            npmName = self.get_npm_name();\n            check_call([npmName, 'install', '--verbose'], cwd=node_root,\n                       stdout=sys.stdout, stderr=sys.stderr)\n            os.utime(self.node_modules, None)\n\n        for t in self.targets:\n            if not os.path.exists(t):\n                msg = 'Missing file: %s' % t\n                if not has_npm:\n                    msg += '\\nnpm is required to build a development ' \\\n                           'version of a widget extension'\n                raise ValueError(msg)\n\n        # update package data in case this created new files\n        update_package_data(self.distribution)\n\n\nextensions = [Extension('vispy.visuals.text._sdf_cpu',\n                        [op.join('vispy', 'visuals', 'text', '_sdf_cpu.pyx')],\n                        include_dirs=[np.get_include()]),\n              ]\n\nreadme = open('README.rst', 'r').read()\nsetup(\n    name=name,\n    use_scm_version={'write_to': 'vispy/version.py'},\n    author='Vispy contributors',\n    author_email='vispy@googlegroups.com',\n    license='(new) BSD',\n    url='http://vispy.org',\n    download_url='https://pypi.python.org/pypi/vispy',\n    keywords=[\n        'visualization',\n        'OpenGl',\n        'ES',\n        'medical',\n        'imaging',\n        '3D',\n        'plotting',\n        'numpy',\n        'bigdata',\n        'ipython',\n        'jupyter',\n        'widgets',\n    ],\n    description=description,\n    long_description=readme,\n    platforms='any',\n    provides=['vispy'],\n    cmdclass={\n        'build_py': js_prerelease(build_py),\n        'egg_info': js_prerelease(egg_info),\n        'sdist': js_prerelease(sdist, strict=True),\n        'jsdeps': NPM,\n    },\n    python_requires='>=3.6',\n    install_requires=['numpy', 'freetype-py'],\n    setup_requires=['numpy', 'cython', 'setuptools_scm', 'setuptools_scm_git_archive'],\n    extras_require={\n        'ipython-static': ['ipython'],\n        'ipython-vnc': ['ipython>=7'],\n        'ipython-webgl': ['ipywidgets>=7.0', 'ipython>=7', 'tornado'],\n        'pyglet': ['pyglet>=1.2'],\n        'pyqt5': ['pyqt5'],\n        'pyside': ['PySide'],\n        'pyside2': ['PySide2'],\n        'sdl2': ['PySDL2'],\n        'wx': ['wxPython'],\n        'doc': ['sphinx_bootstrap_theme', 'numpydoc'],\n        'io': ['meshio'],\n    },\n    packages=find_packages(exclude=['make']),\n    ext_modules=cythonize(extensions),\n    package_dir={'vispy': 'vispy'},\n    data_files=[\n        ('share/jupyter/nbextensions/vispy', [\n            'vispy/static/extension.js',\n            'vispy/static/index.js',\n            'vispy/static/index.js.map',\n        ]),\n        ('etc/jupyter/nbconfig/notebook.d', ['vispy.json']),\n    ],\n    include_package_data=True,\n    package_data={\n        'vispy': [op.join('io', '_data', '*'),\n                  op.join('html', 'static', 'js', '*'),\n                  op.join('app', 'tests', 'qt-designer.ui'),\n                  op.join('util', 'fonts', 'data', '*.ttf'),\n                  ],\n\n        'vispy.glsl': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.antialias': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.arrowheads': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.arrows': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.collections': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.colormaps': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.lines': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.markers': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.math': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.misc': ['*.vert','*.frag', \"*.glsl\"],\n        'vispy.glsl.transforms': ['*.vert','*.frag', \"*.glsl\"],\n\n                  },\n    zip_safe=False,\n    classifiers=[\n        'Development Status :: 3 - Alpha',\n        'Intended Audience :: Science/Research',\n        'Intended Audience :: Education',\n        'Intended Audience :: Developers',\n        'Topic :: Scientific/Engineering :: Visualization',\n        'License :: OSI Approved :: BSD License',\n        'Operating System :: MacOS :: MacOS X',\n        'Operating System :: Microsoft :: Windows',\n        'Operating System :: POSIX',\n        'Programming Language :: Python',\n        'Programming Language :: Python :: 3.6',\n        'Programming Language :: Python :: 3.7',\n        'Programming Language :: Python :: 3.8',\n        'Framework :: IPython'\n    ],\n)\n", "path": "setup.py"}]}