├── torchwindow ├── __init__.py ├── exceptions.py ├── example.py ├── shaders.py └── window.py ├── example.png ├── pyproject.toml ├── README.md └── poetry.lock /torchwindow/__init__.py: -------------------------------------------------------------------------------- 1 | from .window import Window 2 | -------------------------------------------------------------------------------- /example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbaron34/torchwindow/HEAD/example.png -------------------------------------------------------------------------------- /torchwindow/exceptions.py: -------------------------------------------------------------------------------- 1 | class SDLException(Exception): 2 | pass 3 | 4 | 5 | class CudaException(Exception): 6 | pass 7 | 8 | 9 | class OpenGLException(Exception): 10 | pass 11 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "torchwindow" 3 | version = "1.1.0" 4 | description = "Display tensors directly from GPU" 5 | authors = ["Jeremy "] 6 | readme = "README.md" 7 | license = "MIT" 8 | homepage = "https://github.com/jbaron34/torchwindow" 9 | repository = "https://github.com/jbaron34/torchwindow" 10 | 11 | [tool.poetry.dependencies] 12 | python = "^3.8" 13 | pysdl2 = "^0.9.14" 14 | pysdl2-dll = "^2.24.1" 15 | numpy = "^1.23.4" 16 | pyopengl = "^3.1.6" 17 | cuda-python = "^11.8.0" 18 | 19 | 20 | [tool.poetry.group.dev.dependencies] 21 | black = {version = "^22.10.0", allow-prereleases = true} 22 | 23 | [build-system] 24 | requires = ["poetry-core"] 25 | build-backend = "poetry.core.masonry.api" 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TorchWindow 2 | 3 | TorchWindow is a Python library that enables viewing of PyTorch Cuda Tensors on screen directly from GPU memory (No copying back and forth between GPU and CPU) via OpenGL-Cuda interop. 4 | 5 | ## Install 6 | 7 | ``` 8 | pip install torchwindow 9 | ``` 10 | 11 | ## Use 12 | To create a window 13 | ``` 14 | from torchwindow import Window 15 | window = Window(640, 480, name="Torch Window") 16 | ``` 17 | To display an image tensor in the window 18 | ``` 19 | window.draw(image) 20 | ``` 21 | `image` must be a tensor with the following properties: 22 | - 3 dimensions, specifically `(rows, columns, channels)` in that order. 23 | - `channels` dimension must be of size 4 (r, g, b, a) 24 | 25 | ## Example 26 | To check if torchwindow is properly installed try running 27 | ``` 28 | python3 -m torchwindow.example 29 | ``` 30 | You should see this window appear for 5 seconds before closing 31 | ![Example](example.png) -------------------------------------------------------------------------------- /torchwindow/example.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torchwindow import Window 3 | 4 | import time 5 | 6 | 7 | if __name__ == "__main__": 8 | ones_v_half = torch.ones((300, 800, 1), dtype=torch.float32, device="cuda") 9 | zeros_v_half = torch.zeros((300, 800, 1), dtype=torch.float32, device="cuda") 10 | 11 | ones_h_half = torch.ones((600, 400, 1), dtype=torch.float32, device="cuda") 12 | zeros_h_half = torch.zeros((600, 400, 1), dtype=torch.float32, device="cuda") 13 | 14 | ones_whole = torch.ones((600, 800, 1), dtype=torch.float32, device="cuda") 15 | zeros_whole = torch.zeros((600, 800, 1), dtype=torch.float32, device="cuda") 16 | 17 | whole_v_half = torch.cat([ones_v_half, zeros_v_half], dim=0) 18 | whole_h_half = torch.cat([ones_h_half, zeros_h_half], dim=1) 19 | 20 | image = torch.cat([whole_v_half, zeros_whole, whole_h_half, ones_whole], dim=-1) 21 | 22 | window = Window(800, 600, "Example") 23 | window.draw(image) 24 | 25 | time.sleep(5) 26 | 27 | window.close() 28 | -------------------------------------------------------------------------------- /torchwindow/shaders.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import GL_VERTEX_SHADER, GL_FRAGMENT_SHADER 2 | from OpenGL.GL.shaders import compileProgram, compileShader 3 | 4 | 5 | VERTEX_SHADER_SOURCE = """ 6 | #version 450 7 | 8 | smooth out vec4 fragColor; 9 | smooth out vec2 texcoords; 10 | 11 | vec4 positions[3] = vec4[3]( 12 | vec4(-1.0, 1.0, 0.0, 1.0), 13 | vec4(3.0, 1.0, 0.0, 1.0), 14 | vec4(-1.0, -3.0, 0.0, 1.0) 15 | ); 16 | 17 | vec2 texpos[3] = vec2[3]( 18 | vec2(0, 0), 19 | vec2(2, 0), 20 | vec2(0, 2) 21 | ); 22 | 23 | vec4 colors[3] = vec4[3]( 24 | vec4(1.0, 0.0, 0.0, 1.0), 25 | vec4(0.0, 1.0, 0.0, 1.0), 26 | vec4(0.0, 0.0, 1.0, 1.0) 27 | ); 28 | 29 | void main() { 30 | gl_Position = positions[gl_VertexID]; 31 | fragColor = colors[gl_VertexID]; 32 | texcoords = texpos[gl_VertexID]; 33 | } 34 | """ 35 | 36 | FRAGMENT_SHADER_SOURCE = """ 37 | #version 330 38 | 39 | smooth in vec4 fragColor; 40 | smooth in vec2 texcoords; 41 | 42 | out vec4 outputColour; 43 | 44 | uniform sampler2D texSampler; 45 | 46 | void main() 47 | { 48 | outputColour = texture(texSampler, texcoords); 49 | } 50 | """ 51 | 52 | 53 | def create_shader_program(): 54 | vertex_shader = compileShader(VERTEX_SHADER_SOURCE, GL_VERTEX_SHADER) 55 | fragment_shader = compileShader(FRAGMENT_SHADER_SOURCE, GL_FRAGMENT_SHADER) 56 | return compileProgram(vertex_shader, fragment_shader) 57 | -------------------------------------------------------------------------------- /torchwindow/window.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import warnings 3 | 4 | with warnings.catch_warnings(): 5 | warnings.filterwarnings(action="ignore", category=UserWarning) 6 | import sdl2 7 | 8 | from sdl2 import video 9 | from OpenGL import GL as gl 10 | from cuda import cudart as cu 11 | 12 | from .shaders import create_shader_program 13 | from .exceptions import SDLException, CudaException, OpenGLException 14 | 15 | import logging 16 | 17 | logger = logging.getLogger(__name__) 18 | 19 | 20 | class Window: 21 | def __init__(self, width: int = 800, height: int = 600, name: str = "torchwindow"): 22 | self.name = name 23 | self.width = width 24 | self.height = height 25 | 26 | self.cuda_is_setup = False 27 | self.running = True 28 | 29 | self.setup() 30 | 31 | def setup_sdl(self): 32 | if sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO): 33 | raise SDLException(sdl2.SDL_GetError()) 34 | 35 | self.sdl_window = sdl2.SDL_CreateWindow( 36 | self.name.encode(), 37 | sdl2.SDL_WINDOWPOS_UNDEFINED, 38 | sdl2.SDL_WINDOWPOS_UNDEFINED, 39 | self.width, 40 | self.height, 41 | sdl2.SDL_WINDOW_OPENGL, 42 | ) 43 | if not self.sdl_window: 44 | raise SDLException(sdl2.SDL_GetError()) 45 | 46 | # Force OpenGL 3.3 'core' context. 47 | # Must set *before* creating GL context! 48 | video.SDL_GL_SetAttribute(video.SDL_GL_CONTEXT_MAJOR_VERSION, 3) 49 | video.SDL_GL_SetAttribute(video.SDL_GL_CONTEXT_MINOR_VERSION, 3) 50 | video.SDL_GL_SetAttribute( 51 | video.SDL_GL_CONTEXT_PROFILE_MASK, video.SDL_GL_CONTEXT_PROFILE_CORE 52 | ) 53 | self.gl_context = sdl2.SDL_GL_CreateContext(self.sdl_window) 54 | 55 | def setup_opengl(self): 56 | self.shader_program = create_shader_program() 57 | self.vao = gl.glGenVertexArrays(1) 58 | 59 | self.tex = gl.glGenTextures(1) 60 | gl.glBindTexture(gl.GL_TEXTURE_2D, self.tex) 61 | gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_REPEAT) 62 | gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_REPEAT) 63 | gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR) 64 | gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR) 65 | gl.glTexImage2D( 66 | gl.GL_TEXTURE_2D, 67 | 0, 68 | gl.GL_RGBA32F, 69 | self.width, 70 | self.height, 71 | 0, 72 | gl.GL_RGBA, 73 | gl.GL_FLOAT, 74 | None, 75 | ) 76 | gl.glBindTexture(gl.GL_TEXTURE_2D, 0) 77 | gl.glEnable(gl.GL_BLEND) 78 | gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) 79 | 80 | def setup_cuda(self): 81 | if self.cuda_is_setup: 82 | return 83 | 84 | if sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO) != 0: 85 | raise SDLException(sdl2.SDL_GetError()) 86 | 87 | err, *_ = cu.cudaGLGetDevices(1, cu.cudaGLDeviceList.cudaGLDeviceListAll) 88 | if err == cu.cudaError_t.cudaErrorUnknown: 89 | raise OpenGLException( 90 | "OpenGL context may be running on integrated graphics" 91 | ) 92 | 93 | err, self.cuda_image = cu.cudaGraphicsGLRegisterImage( 94 | self.tex, 95 | gl.GL_TEXTURE_2D, 96 | cu.cudaGraphicsRegisterFlags.cudaGraphicsRegisterFlagsWriteDiscard, 97 | ) 98 | if err != cu.cudaError_t.cudaSuccess: 99 | raise CudaException("Unable to register opengl texture") 100 | 101 | self.cuda_is_setup = True 102 | 103 | def render(self): 104 | gl.glUseProgram(self.shader_program) 105 | try: 106 | gl.glClearColor(0, 0, 0, 1) 107 | gl.glClear(gl.GL_COLOR_BUFFER_BIT) 108 | gl.glBindTexture(gl.GL_TEXTURE_2D, self.tex) 109 | gl.glBindVertexArray(self.vao) 110 | gl.glDrawArrays(gl.GL_TRIANGLES, 0, 3) 111 | finally: 112 | gl.glBindTexture(gl.GL_TEXTURE_2D, 0) 113 | gl.glBindVertexArray(0) 114 | gl.glUseProgram(0) 115 | sdl2.SDL_GL_SwapWindow(self.sdl_window) 116 | 117 | def step(self): 118 | event = sdl2.SDL_Event() 119 | if self.running: 120 | while sdl2.SDL_PollEvent(ctypes.byref(event)): 121 | if ( 122 | event.type == sdl2.SDL_WINDOWEVENT 123 | and event.window.event == sdl2.SDL_WINDOWEVENT_CLOSE 124 | ): 125 | self.running = False 126 | self.render() 127 | 128 | def setup(self): 129 | self.setup_sdl() 130 | self.setup_opengl() 131 | self.setup_cuda() 132 | 133 | def draw(self, tensor): 134 | if not self.running: 135 | return 136 | if not self.cuda_is_setup: 137 | self.setup_cuda() 138 | (err,) = cu.cudaGraphicsMapResources(1, self.cuda_image, cu.cudaStreamLegacy) 139 | if err != cu.cudaError_t.cudaSuccess: 140 | raise CudaException("Unable to map graphics resource") 141 | err, array = cu.cudaGraphicsSubResourceGetMappedArray(self.cuda_image, 0, 0) 142 | if err != cu.cudaError_t.cudaSuccess: 143 | raise CudaException("Unable to get mapped array") 144 | (err,) = cu.cudaMemcpy2DToArrayAsync( 145 | array, 146 | 0, 147 | 0, 148 | tensor.data_ptr(), 149 | 4 * 4 * self.width, 150 | 4 * 4 * self.width, 151 | self.height, 152 | cu.cudaMemcpyKind.cudaMemcpyDeviceToDevice, 153 | cu.cudaStreamLegacy, 154 | ) 155 | if err != cu.cudaError_t.cudaSuccess: 156 | raise CudaException("Unable to copy from tensor to texture") 157 | 158 | (err,) = cu.cudaGraphicsUnmapResources(1, self.cuda_image, cu.cudaStreamLegacy) 159 | if err != cu.cudaError_t.cudaSuccess: 160 | raise CudaException("Unable to unmap graphics resource") 161 | self.step() 162 | 163 | def close(self): 164 | self.running = False 165 | sdl2.SDL_GL_DeleteContext(self.gl_context) 166 | sdl2.SDL_DestroyWindow(self.sdl_window) 167 | sdl2.SDL_Quit() 168 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "black" 3 | version = "22.10.0" 4 | description = "The uncompromising code formatter." 5 | category = "dev" 6 | optional = false 7 | python-versions = ">=3.7" 8 | 9 | [package.dependencies] 10 | click = ">=8.0.0" 11 | mypy-extensions = ">=0.4.3" 12 | pathspec = ">=0.9.0" 13 | platformdirs = ">=2" 14 | tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} 15 | typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} 16 | 17 | [package.extras] 18 | colorama = ["colorama (>=0.4.3)"] 19 | d = ["aiohttp (>=3.7.4)"] 20 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 21 | uvloop = ["uvloop (>=0.15.2)"] 22 | 23 | [[package]] 24 | name = "click" 25 | version = "8.1.3" 26 | description = "Composable command line interface toolkit" 27 | category = "dev" 28 | optional = false 29 | python-versions = ">=3.7" 30 | 31 | [package.dependencies] 32 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 33 | 34 | [[package]] 35 | name = "colorama" 36 | version = "0.4.6" 37 | description = "Cross-platform colored terminal text." 38 | category = "dev" 39 | optional = false 40 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 41 | 42 | [[package]] 43 | name = "cuda-python" 44 | version = "11.8.0" 45 | description = "Python bindings for CUDA" 46 | category = "main" 47 | optional = false 48 | python-versions = "*" 49 | 50 | [package.dependencies] 51 | cython = "*" 52 | 53 | [[package]] 54 | name = "cython" 55 | version = "0.29.32" 56 | description = "The Cython compiler for writing C extensions for the Python language." 57 | category = "main" 58 | optional = false 59 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 60 | 61 | [[package]] 62 | name = "mypy-extensions" 63 | version = "0.4.3" 64 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 65 | category = "dev" 66 | optional = false 67 | python-versions = "*" 68 | 69 | [[package]] 70 | name = "numpy" 71 | version = "1.23.4" 72 | description = "NumPy is the fundamental package for array computing with Python." 73 | category = "main" 74 | optional = false 75 | python-versions = ">=3.8" 76 | 77 | [[package]] 78 | name = "pathspec" 79 | version = "0.10.1" 80 | description = "Utility library for gitignore style pattern matching of file paths." 81 | category = "dev" 82 | optional = false 83 | python-versions = ">=3.7" 84 | 85 | [[package]] 86 | name = "platformdirs" 87 | version = "2.5.2" 88 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 89 | category = "dev" 90 | optional = false 91 | python-versions = ">=3.7" 92 | 93 | [package.extras] 94 | docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] 95 | test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] 96 | 97 | [[package]] 98 | name = "pyopengl" 99 | version = "3.1.6" 100 | description = "Standard OpenGL bindings for Python" 101 | category = "main" 102 | optional = false 103 | python-versions = "*" 104 | 105 | [[package]] 106 | name = "pysdl2" 107 | version = "0.9.14" 108 | description = "Python SDL2 bindings" 109 | category = "main" 110 | optional = false 111 | python-versions = "*" 112 | 113 | [[package]] 114 | name = "pysdl2-dll" 115 | version = "2.24.1" 116 | description = "Pre-built SDL2 binaries for PySDL2" 117 | category = "main" 118 | optional = false 119 | python-versions = "*" 120 | 121 | [[package]] 122 | name = "tomli" 123 | version = "2.0.1" 124 | description = "A lil' TOML parser" 125 | category = "dev" 126 | optional = false 127 | python-versions = ">=3.7" 128 | 129 | [[package]] 130 | name = "typing-extensions" 131 | version = "4.4.0" 132 | description = "Backported and Experimental Type Hints for Python 3.7+" 133 | category = "dev" 134 | optional = false 135 | python-versions = ">=3.7" 136 | 137 | [metadata] 138 | lock-version = "1.1" 139 | python-versions = "^3.8" 140 | content-hash = "43561555c9484ee394dd5bcb564f4b7613da7af2276101ac701f7fdc892103f6" 141 | 142 | [metadata.files] 143 | black = [ 144 | {file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"}, 145 | {file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"}, 146 | {file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"}, 147 | {file = "black-22.10.0-1fixedarch-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d"}, 148 | {file = "black-22.10.0-1fixedarch-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4"}, 149 | {file = "black-22.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb"}, 150 | {file = "black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"}, 151 | {file = "black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"}, 152 | {file = "black-22.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae"}, 153 | {file = "black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"}, 154 | {file = "black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"}, 155 | {file = "black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"}, 156 | {file = "black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"}, 157 | {file = "black-22.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff"}, 158 | {file = "black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"}, 159 | {file = "black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"}, 160 | {file = "black-22.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0"}, 161 | {file = "black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"}, 162 | {file = "black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"}, 163 | {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"}, 164 | {file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"}, 165 | ] 166 | click = [ 167 | {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, 168 | {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, 169 | ] 170 | colorama = [ 171 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 172 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 173 | ] 174 | cuda-python = [ 175 | {file = "cuda_python-11.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:096cc16e75e2920ff0116bbf8281d9f9d1ad3b13305d85fc26affc353a077546"}, 176 | {file = "cuda_python-11.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:df092a8efd00c6122b45bafc7099afcff86f8f308dac08c21176b7c37ed6999e"}, 177 | {file = "cuda_python-11.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fff5a4bc499a079a78d5e54b644677b06843e79c185bcef4f008e56d56b503d0"}, 178 | {file = "cuda_python-11.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:f8580bc42780d1d9c039d4e4ae6154b4045df43445827646e577ea4c1629ab44"}, 179 | {file = "cuda_python-11.8.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c7a5eaa4e8fb1a7c8a94ece1cdc780dffac32249c04ad388ca29c5a669df1f5"}, 180 | {file = "cuda_python-11.8.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04bf84045f35199aae35bcb4ea4f70308889b90ae0b816daa07d4e128bdad53c"}, 181 | {file = "cuda_python-11.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afa457dc5e6a28a4e2b992fb01c60e0efbb7b4a71da5a3cc7f1b6e9c56f402d9"}, 182 | {file = "cuda_python-11.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4fd13e3bd879f59649dd44b90ae623b56ff221f0074e4096e95eddbc96432cbc"}, 183 | {file = "cuda_python-11.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88b1ff2e83901f6f9c93ce4cd1493b5de6d0f796c92cbf281a82cb0c8e57f71e"}, 184 | {file = "cuda_python-11.8.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60ae149d592fe6c956744ef58da43dbbdcf413e5db67710800251062a37d7a21"}, 185 | {file = "cuda_python-11.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cd01b344b87a9c7b2dff9132f4fbc8d990131872fab58bd24a673007908c3d0"}, 186 | {file = "cuda_python-11.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:b7c05cfc18ff7e1a4de0bcf15fce587980d73884ecd4bb6c4aeea75a9280437e"}, 187 | {file = "cuda_python-11.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36a3cb9141239daf31ee53c71ae791c5a3ef381ed2ed6798ca7e065fe1e8638a"}, 188 | {file = "cuda_python-11.8.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a7693d54e369a3b3f280e5191805a9e69c24b1e26989d9b10b63e1de44ac2e2"}, 189 | {file = "cuda_python-11.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:474b275b795d74df89c1f3be397bcb8ca7c13f30854043c3c1cda8d1b4caa159"}, 190 | {file = "cuda_python-11.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:37b6cc0798f5e37606fa218f105a5bb286e75190523179f5df7854006d18d03b"}, 191 | ] 192 | cython = [ 193 | {file = "Cython-0.29.32-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:39afb4679b8c6bf7ccb15b24025568f4f9b4d7f9bf3cbd981021f542acecd75b"}, 194 | {file = "Cython-0.29.32-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dbee03b8d42dca924e6aa057b836a064c769ddfd2a4c2919e65da2c8a362d528"}, 195 | {file = "Cython-0.29.32-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ba622326f2862f9c1f99ca8d47ade49871241920a352c917e16861e25b0e5c3"}, 196 | {file = "Cython-0.29.32-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e6ffa08aa1c111a1ebcbd1cf4afaaec120bc0bbdec3f2545f8bb7d3e8e77a1cd"}, 197 | {file = "Cython-0.29.32-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:97335b2cd4acebf30d14e2855d882de83ad838491a09be2011745579ac975833"}, 198 | {file = "Cython-0.29.32-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:06be83490c906b6429b4389e13487a26254ccaad2eef6f3d4ee21d8d3a4aaa2b"}, 199 | {file = "Cython-0.29.32-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:eefd2b9a5f38ded8d859fe96cc28d7d06e098dc3f677e7adbafda4dcdd4a461c"}, 200 | {file = "Cython-0.29.32-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5514f3b4122cb22317122a48e175a7194e18e1803ca555c4c959d7dfe68eaf98"}, 201 | {file = "Cython-0.29.32-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:656dc5ff1d269de4d11ee8542f2ffd15ab466c447c1f10e5b8aba6f561967276"}, 202 | {file = "Cython-0.29.32-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:cdf10af3e2e3279dc09fdc5f95deaa624850a53913f30350ceee824dc14fc1a6"}, 203 | {file = "Cython-0.29.32-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:3875c2b2ea752816a4d7ae59d45bb546e7c4c79093c83e3ba7f4d9051dd02928"}, 204 | {file = "Cython-0.29.32-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:79e3bab19cf1b021b613567c22eb18b76c0c547b9bc3903881a07bfd9e7e64cf"}, 205 | {file = "Cython-0.29.32-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0595aee62809ba353cebc5c7978e0e443760c3e882e2c7672c73ffe46383673"}, 206 | {file = "Cython-0.29.32-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0ea8267fc373a2c5064ad77d8ff7bf0ea8b88f7407098ff51829381f8ec1d5d9"}, 207 | {file = "Cython-0.29.32-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:c8e8025f496b5acb6ba95da2fb3e9dacffc97d9a92711aacfdd42f9c5927e094"}, 208 | {file = "Cython-0.29.32-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:afbce249133a830f121b917f8c9404a44f2950e0e4f5d1e68f043da4c2e9f457"}, 209 | {file = "Cython-0.29.32-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:513e9707407608ac0d306c8b09d55a28be23ea4152cbd356ceaec0f32ef08d65"}, 210 | {file = "Cython-0.29.32-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e83228e0994497900af954adcac27f64c9a57cd70a9ec768ab0cb2c01fd15cf1"}, 211 | {file = "Cython-0.29.32-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ea1dcc07bfb37367b639415333cfbfe4a93c3be340edf1db10964bc27d42ed64"}, 212 | {file = "Cython-0.29.32-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8669cadeb26d9a58a5e6b8ce34d2c8986cc3b5c0bfa77eda6ceb471596cb2ec3"}, 213 | {file = "Cython-0.29.32-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:ed087eeb88a8cf96c60fb76c5c3b5fb87188adee5e179f89ec9ad9a43c0c54b3"}, 214 | {file = "Cython-0.29.32-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:3f85eb2343d20d91a4ea9cf14e5748092b376a64b7e07fc224e85b2753e9070b"}, 215 | {file = "Cython-0.29.32-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:63b79d9e1f7c4d1f498ab1322156a0d7dc1b6004bf981a8abda3f66800e140cd"}, 216 | {file = "Cython-0.29.32-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e1958e0227a4a6a2c06fd6e35b7469de50adf174102454db397cec6e1403cce3"}, 217 | {file = "Cython-0.29.32-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:856d2fec682b3f31583719cb6925c6cdbb9aa30f03122bcc45c65c8b6f515754"}, 218 | {file = "Cython-0.29.32-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:479690d2892ca56d34812fe6ab8f58e4b2e0129140f3d94518f15993c40553da"}, 219 | {file = "Cython-0.29.32-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:67fdd2f652f8d4840042e2d2d91e15636ba2bcdcd92e7e5ffbc68e6ef633a754"}, 220 | {file = "Cython-0.29.32-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:4a4b03ab483271f69221c3210f7cde0dcc456749ecf8243b95bc7a701e5677e0"}, 221 | {file = "Cython-0.29.32-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:40eff7aa26e91cf108fd740ffd4daf49f39b2fdffadabc7292b4b7dc5df879f0"}, 222 | {file = "Cython-0.29.32-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0bbc27abdf6aebfa1bce34cd92bd403070356f28b0ecb3198ff8a182791d58b9"}, 223 | {file = "Cython-0.29.32-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cddc47ec746a08603037731f5d10aebf770ced08666100bd2cdcaf06a85d4d1b"}, 224 | {file = "Cython-0.29.32-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca3065a1279456e81c615211d025ea11bfe4e19f0c5650b859868ca04b3fcbd"}, 225 | {file = "Cython-0.29.32-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:d968ffc403d92addf20b68924d95428d523436adfd25cf505d427ed7ba3bee8b"}, 226 | {file = "Cython-0.29.32-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f3fd44cc362eee8ae569025f070d56208908916794b6ab21e139cea56470a2b3"}, 227 | {file = "Cython-0.29.32-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:b6da3063c5c476f5311fd76854abae6c315f1513ef7d7904deed2e774623bbb9"}, 228 | {file = "Cython-0.29.32-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:061e25151c38f2361bc790d3bcf7f9d9828a0b6a4d5afa56fbed3bd33fb2373a"}, 229 | {file = "Cython-0.29.32-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f9944013588a3543fca795fffb0a070a31a243aa4f2d212f118aa95e69485831"}, 230 | {file = "Cython-0.29.32-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:07d173d3289415bb496e72cb0ddd609961be08fe2968c39094d5712ffb78672b"}, 231 | {file = "Cython-0.29.32-py2.py3-none-any.whl", hash = "sha256:eeb475eb6f0ccf6c039035eb4f0f928eb53ead88777e0a760eccb140ad90930b"}, 232 | {file = "Cython-0.29.32.tar.gz", hash = "sha256:8733cf4758b79304f2a4e39ebfac5e92341bce47bcceb26c1254398b2f8c1af7"}, 233 | ] 234 | mypy-extensions = [ 235 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 236 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 237 | ] 238 | numpy = [ 239 | {file = "numpy-1.23.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:95d79ada05005f6f4f337d3bb9de8a7774f259341c70bc88047a1f7b96a4bcb2"}, 240 | {file = "numpy-1.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:926db372bc4ac1edf81cfb6c59e2a881606b409ddc0d0920b988174b2e2a767f"}, 241 | {file = "numpy-1.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c237129f0e732885c9a6076a537e974160482eab8f10db6292e92154d4c67d71"}, 242 | {file = "numpy-1.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8365b942f9c1a7d0f0dc974747d99dd0a0cdfc5949a33119caf05cb314682d3"}, 243 | {file = "numpy-1.23.4-cp310-cp310-win32.whl", hash = "sha256:2341f4ab6dba0834b685cce16dad5f9b6606ea8a00e6da154f5dbded70fdc4dd"}, 244 | {file = "numpy-1.23.4-cp310-cp310-win_amd64.whl", hash = "sha256:d331afac87c92373826af83d2b2b435f57b17a5c74e6268b79355b970626e329"}, 245 | {file = "numpy-1.23.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:488a66cb667359534bc70028d653ba1cf307bae88eab5929cd707c761ff037db"}, 246 | {file = "numpy-1.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce03305dd694c4873b9429274fd41fc7eb4e0e4dea07e0af97a933b079a5814f"}, 247 | {file = "numpy-1.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8981d9b5619569899666170c7c9748920f4a5005bf79c72c07d08c8a035757b0"}, 248 | {file = "numpy-1.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a70a7d3ce4c0e9284e92285cba91a4a3f5214d87ee0e95928f3614a256a1488"}, 249 | {file = "numpy-1.23.4-cp311-cp311-win32.whl", hash = "sha256:5e13030f8793e9ee42f9c7d5777465a560eb78fa7e11b1c053427f2ccab90c79"}, 250 | {file = "numpy-1.23.4-cp311-cp311-win_amd64.whl", hash = "sha256:7607b598217745cc40f751da38ffd03512d33ec06f3523fb0b5f82e09f6f676d"}, 251 | {file = "numpy-1.23.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7ab46e4e7ec63c8a5e6dbf5c1b9e1c92ba23a7ebecc86c336cb7bf3bd2fb10e5"}, 252 | {file = "numpy-1.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8aae2fb3180940011b4862b2dd3756616841c53db9734b27bb93813cd79fce6"}, 253 | {file = "numpy-1.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c053d7557a8f022ec823196d242464b6955a7e7e5015b719e76003f63f82d0f"}, 254 | {file = "numpy-1.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0882323e0ca4245eb0a3d0a74f88ce581cc33aedcfa396e415e5bba7bf05f68"}, 255 | {file = "numpy-1.23.4-cp38-cp38-win32.whl", hash = "sha256:dada341ebb79619fe00a291185bba370c9803b1e1d7051610e01ed809ef3a4ba"}, 256 | {file = "numpy-1.23.4-cp38-cp38-win_amd64.whl", hash = "sha256:0fe563fc8ed9dc4474cbf70742673fc4391d70f4363f917599a7fa99f042d5a8"}, 257 | {file = "numpy-1.23.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c67b833dbccefe97cdd3f52798d430b9d3430396af7cdb2a0c32954c3ef73894"}, 258 | {file = "numpy-1.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f76025acc8e2114bb664294a07ede0727aa75d63a06d2fae96bf29a81747e4a7"}, 259 | {file = "numpy-1.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12ac457b63ec8ded85d85c1e17d85efd3c2b0967ca39560b307a35a6703a4735"}, 260 | {file = "numpy-1.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95de7dc7dc47a312f6feddd3da2500826defdccbc41608d0031276a24181a2c0"}, 261 | {file = "numpy-1.23.4-cp39-cp39-win32.whl", hash = "sha256:f2f390aa4da44454db40a1f0201401f9036e8d578a25f01a6e237cea238337ef"}, 262 | {file = "numpy-1.23.4-cp39-cp39-win_amd64.whl", hash = "sha256:f260da502d7441a45695199b4e7fd8ca87db659ba1c78f2bbf31f934fe76ae0e"}, 263 | {file = "numpy-1.23.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:61be02e3bf810b60ab74e81d6d0d36246dbfb644a462458bb53b595791251911"}, 264 | {file = "numpy-1.23.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:296d17aed51161dbad3c67ed6d164e51fcd18dbcd5dd4f9d0a9c6055dce30810"}, 265 | {file = "numpy-1.23.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4d52914c88b4930dafb6c48ba5115a96cbab40f45740239d9f4159c4ba779962"}, 266 | {file = "numpy-1.23.4.tar.gz", hash = "sha256:ed2cc92af0efad20198638c69bb0fc2870a58dabfba6eb722c933b48556c686c"}, 267 | ] 268 | pathspec = [ 269 | {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, 270 | {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, 271 | ] 272 | platformdirs = [ 273 | {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, 274 | {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, 275 | ] 276 | pyopengl = [ 277 | {file = "PyOpenGL-3.1.6-py2-none-any.whl", hash = "sha256:57c597d989178e1413002df6b923619f6d29807501dece1c60cc6f12c0c8e8a7"}, 278 | {file = "PyOpenGL-3.1.6-py3-none-any.whl", hash = "sha256:a7139bc3e15d656feae1f7e3ef68c799941ed43fadc78177a23db7e946c20738"}, 279 | {file = "PyOpenGL-3.1.6.tar.gz", hash = "sha256:8ea6c8773927eda7405bffc6f5bb93be81569a7b05c8cac50cd94e969dce5e27"}, 280 | ] 281 | pysdl2 = [ 282 | {file = "PySDL2-0.9.14.tar.gz", hash = "sha256:24091f8d9e437646591c7f76d5baeee3d3aa6cd8ae492a51c7026e53389f187a"}, 283 | ] 284 | pysdl2-dll = [ 285 | {file = "pysdl2-dll-2.24.1.tar.gz", hash = "sha256:9ca39bcabc64f550c86b64bf7fb705d28b0a24c99b539ad48a2abeaa61f2e27f"}, 286 | {file = "pysdl2_dll-2.24.1-py2.py3-none-macosx_10_7_universal2.whl", hash = "sha256:edfb2702f39b10ae323a207e0d6793489d92774889f549237a0bac749e011778"}, 287 | {file = "pysdl2_dll-2.24.1-py2.py3-none-macosx_10_7_x86_64.whl", hash = "sha256:879759374999c49fe7b9acc56003545e9e18b66fe6c97d94df31ed06f55c2109"}, 288 | {file = "pysdl2_dll-2.24.1-py2.py3-none-manylinux2014_i686.whl", hash = "sha256:0c5d5a52f6fe4c6902cc019bc37ea75e2ea40d9843ed0d0341d006604d1db30a"}, 289 | {file = "pysdl2_dll-2.24.1-py2.py3-none-manylinux2014_x86_64.whl", hash = "sha256:8183615f661c0a28ed99c59781e8775f8d691ab05070663c4c935a46519a0a3d"}, 290 | {file = "pysdl2_dll-2.24.1-py2.py3-none-manylinux_2_24_aarch64.whl", hash = "sha256:e587fc3ca14b4d50e77a7d0a42528e4e010964751925ab91724eeb601ac0e8e5"}, 291 | {file = "pysdl2_dll-2.24.1-py2.py3-none-manylinux_2_24_x86_64.whl", hash = "sha256:31de25ed1390e1f082ba7bd2928055e2164f662a95baa6d2e58714e0a777c18b"}, 292 | {file = "pysdl2_dll-2.24.1-py2.py3-none-win32.whl", hash = "sha256:a7c76e28a2a816a5c42c0249c5e416c501bd65e73e47067c0c21534d8fd4ea69"}, 293 | {file = "pysdl2_dll-2.24.1-py2.py3-none-win_amd64.whl", hash = "sha256:30bd1e7d618f1e6d0b5fff344125cdbf7e111ecddb4f5232ceb8a502ccee5ee1"}, 294 | ] 295 | tomli = [ 296 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 297 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 298 | ] 299 | typing-extensions = [ 300 | {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, 301 | {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, 302 | ] 303 | --------------------------------------------------------------------------------