spmd-types 0.2.1__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 (36) hide show
  1. spmd_types-0.2.1/LICENSE +28 -0
  2. spmd_types-0.2.1/PKG-INFO +103 -0
  3. spmd_types-0.2.1/README.md +51 -0
  4. spmd_types-0.2.1/pyproject.toml +51 -0
  5. spmd_types-0.2.1/setup.cfg +4 -0
  6. spmd_types-0.2.1/spmd_types/__init__.py +109 -0
  7. spmd_types-0.2.1/spmd_types/_backward_hooks.py +133 -0
  8. spmd_types-0.2.1/spmd_types/_checker/__init__.py +3146 -0
  9. spmd_types-0.2.1/spmd_types/_collectives.py +1418 -0
  10. spmd_types-0.2.1/spmd_types/_dist.py +31 -0
  11. spmd_types-0.2.1/spmd_types/_dtensor.py +262 -0
  12. spmd_types-0.2.1/spmd_types/_dtensor_checker.py +107 -0
  13. spmd_types-0.2.1/spmd_types/_dtype_utils.py +243 -0
  14. spmd_types-0.2.1/spmd_types/_frame.py +68 -0
  15. spmd_types-0.2.1/spmd_types/_local.py +1207 -0
  16. spmd_types-0.2.1/spmd_types/_mesh.py +95 -0
  17. spmd_types-0.2.1/spmd_types/_mesh_axis.py +427 -0
  18. spmd_types-0.2.1/spmd_types/_mesh_region.py +313 -0
  19. spmd_types-0.2.1/spmd_types/_raw_dist.py +227 -0
  20. spmd_types-0.2.1/spmd_types/_reinterpret_mesh.py +255 -0
  21. spmd_types-0.2.1/spmd_types/_scalar.py +279 -0
  22. spmd_types-0.2.1/spmd_types/_scalar_sentinel.py +50 -0
  23. spmd_types-0.2.1/spmd_types/_state.py +145 -0
  24. spmd_types-0.2.1/spmd_types/_test_utils.py +290 -0
  25. spmd_types-0.2.1/spmd_types/_testing.py +30 -0
  26. spmd_types-0.2.1/spmd_types/_traceback.py +211 -0
  27. spmd_types-0.2.1/spmd_types/_type_attr.py +90 -0
  28. spmd_types-0.2.1/spmd_types/_vmap.py +117 -0
  29. spmd_types-0.2.1/spmd_types/checker.py +13 -0
  30. spmd_types-0.2.1/spmd_types/runtime.py +1070 -0
  31. spmd_types-0.2.1/spmd_types/types.py +676 -0
  32. spmd_types-0.2.1/spmd_types.egg-info/PKG-INFO +103 -0
  33. spmd_types-0.2.1/spmd_types.egg-info/SOURCES.txt +34 -0
  34. spmd_types-0.2.1/spmd_types.egg-info/dependency_links.txt +1 -0
  35. spmd_types-0.2.1/spmd_types.egg-info/requires.txt +1 -0
  36. spmd_types-0.2.1/spmd_types.egg-info/top_level.txt +1 -0
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ (c) Meta Platforms, Inc. and affiliates.
4
+
5
+ Redistribution and use in source and binary forms, with or without modification,
6
+ are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this list
9
+ of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice, this
12
+ list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its contributors may
16
+ be used to endorse or promote products derived from this software without specific
17
+ prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
22
+ SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28
+ DAMAGE.
@@ -0,0 +1,103 @@
1
+ Metadata-Version: 2.4
2
+ Name: spmd_types
3
+ Version: 0.2.1
4
+ Summary: A type system for distributed (SPMD) tensor computations in PyTorch
5
+ Author: Meta Platforms, Inc.
6
+ License: BSD 3-Clause License
7
+
8
+ (c) Meta Platforms, Inc. and affiliates.
9
+
10
+ Redistribution and use in source and binary forms, with or without modification,
11
+ are permitted provided that the following conditions are met:
12
+
13
+ 1. Redistributions of source code must retain the above copyright notice, this list
14
+ of conditions and the following disclaimer.
15
+
16
+ 2. Redistributions in binary form must reproduce the above copyright notice, this
17
+ list of conditions and the following disclaimer in the documentation
18
+ and/or other materials provided with the distribution.
19
+
20
+ 3. Neither the name of the copyright holder nor the names of its contributors may
21
+ be used to endorse or promote products derived from this software without specific
22
+ prior written permission.
23
+
24
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
25
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
27
+ SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33
+ DAMAGE.
34
+
35
+ Project-URL: Homepage, https://github.com/meta-pytorch/spmd_types
36
+ Project-URL: Repository, https://github.com/meta-pytorch/spmd_types
37
+ Project-URL: Issues, https://github.com/meta-pytorch/spmd_types/issues
38
+ Classifier: Development Status :: 4 - Beta
39
+ Classifier: Intended Audience :: Developers
40
+ Classifier: Intended Audience :: Science/Research
41
+ Classifier: License :: OSI Approved :: BSD License
42
+ Classifier: Programming Language :: Python :: 3 :: Only
43
+ Classifier: Programming Language :: Python :: 3.10
44
+ Classifier: Programming Language :: Python :: 3.11
45
+ Classifier: Programming Language :: Python :: 3.12
46
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
47
+ Requires-Python: >=3.10
48
+ Description-Content-Type: text/markdown
49
+ License-File: LICENSE
50
+ Requires-Dist: torch>=2.10.0
51
+ Dynamic: license-file
52
+
53
+ # spmd_types
54
+
55
+ A type system for distributed (SPMD) tensor computations in PyTorch.
56
+
57
+ spmd_types tracks per-mesh-axis types on tensors -- Replicate (R), Invariant (I),
58
+ Varying (V), Partial (P), and Shard (S) -- and enforces type-correct transitions
59
+ through collective operations and local rewrites. It catches distributed
60
+ programming errors at development time without requiring a GPU cluster.
61
+
62
+ ## Installation
63
+
64
+ ```bash
65
+ pip install spmd_types
66
+ ```
67
+
68
+ ## Quick start
69
+
70
+ ```python
71
+ import torch
72
+ import torch.distributed as dist
73
+ import spmd_types as spmd
74
+ from torch.distributed.device_mesh import init_device_mesh
75
+
76
+ # Set up a fake process group (no GPUs needed)
77
+ dist.init_process_group(backend="fake", rank=0, world_size=8)
78
+ mesh = init_device_mesh("cpu", (2, 4), mesh_dim_names=("dp", "tp"))
79
+ dp = mesh.get_group("dp")
80
+ tp = mesh.get_group("tp")
81
+
82
+ with spmd.set_current_mesh(mesh), spmd.typecheck():
83
+ x = torch.randn(4)
84
+ spmd.assert_type(x, {dp: spmd.R, tp: spmd.P}) # R on dp, partial on tp
85
+ y = spmd.all_reduce(x, tp, src=spmd.P, dst=spmd.R) # sum across tp ranks
86
+ spmd.assert_type(y, {dp: spmd.R, tp: spmd.R}) # now replicated everywhere
87
+ z = torch.mul(y, y) # type inference: R * R -> R
88
+ spmd.assert_type(z, {dp: spmd.R, tp: spmd.R})
89
+
90
+ dist.destroy_process_group()
91
+ ```
92
+
93
+ ## Documentation
94
+
95
+ See [MEGATRON_QUICKSTART.md](MEGATRON_QUICKSTART.md) for a guide on porting
96
+ Megatron-derived training frameworks to use spmd_types.
97
+
98
+ See [DESIGN.md](DESIGN.md) for the full type system specification, including
99
+ type inference rules, collective signatures, and forward-backward pairs.
100
+
101
+ ## License
102
+
103
+ BSD 3-Clause License. See [LICENSE](LICENSE) for details.
@@ -0,0 +1,51 @@
1
+ # spmd_types
2
+
3
+ A type system for distributed (SPMD) tensor computations in PyTorch.
4
+
5
+ spmd_types tracks per-mesh-axis types on tensors -- Replicate (R), Invariant (I),
6
+ Varying (V), Partial (P), and Shard (S) -- and enforces type-correct transitions
7
+ through collective operations and local rewrites. It catches distributed
8
+ programming errors at development time without requiring a GPU cluster.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ pip install spmd_types
14
+ ```
15
+
16
+ ## Quick start
17
+
18
+ ```python
19
+ import torch
20
+ import torch.distributed as dist
21
+ import spmd_types as spmd
22
+ from torch.distributed.device_mesh import init_device_mesh
23
+
24
+ # Set up a fake process group (no GPUs needed)
25
+ dist.init_process_group(backend="fake", rank=0, world_size=8)
26
+ mesh = init_device_mesh("cpu", (2, 4), mesh_dim_names=("dp", "tp"))
27
+ dp = mesh.get_group("dp")
28
+ tp = mesh.get_group("tp")
29
+
30
+ with spmd.set_current_mesh(mesh), spmd.typecheck():
31
+ x = torch.randn(4)
32
+ spmd.assert_type(x, {dp: spmd.R, tp: spmd.P}) # R on dp, partial on tp
33
+ y = spmd.all_reduce(x, tp, src=spmd.P, dst=spmd.R) # sum across tp ranks
34
+ spmd.assert_type(y, {dp: spmd.R, tp: spmd.R}) # now replicated everywhere
35
+ z = torch.mul(y, y) # type inference: R * R -> R
36
+ spmd.assert_type(z, {dp: spmd.R, tp: spmd.R})
37
+
38
+ dist.destroy_process_group()
39
+ ```
40
+
41
+ ## Documentation
42
+
43
+ See [MEGATRON_QUICKSTART.md](MEGATRON_QUICKSTART.md) for a guide on porting
44
+ Megatron-derived training frameworks to use spmd_types.
45
+
46
+ See [DESIGN.md](DESIGN.md) for the full type system specification, including
47
+ type inference rules, collective signatures, and forward-backward pairs.
48
+
49
+ ## License
50
+
51
+ BSD 3-Clause License. See [LICENSE](LICENSE) for details.
@@ -0,0 +1,51 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "spmd_types"
7
+ version = "0.2.1"
8
+ description = "A type system for distributed (SPMD) tensor computations in PyTorch"
9
+ readme = "README.md"
10
+ license = {file = "LICENSE"}
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ {name = "Meta Platforms, Inc."},
14
+ ]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Developers",
18
+ "Intended Audience :: Science/Research",
19
+ "License :: OSI Approved :: BSD License",
20
+ "Programming Language :: Python :: 3 :: Only",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
25
+ ]
26
+ dependencies = [
27
+ "torch>=2.10.0",
28
+ ]
29
+
30
+ [project.urls]
31
+ Homepage = "https://github.com/meta-pytorch/spmd_types"
32
+ Repository = "https://github.com/meta-pytorch/spmd_types"
33
+ Issues = "https://github.com/meta-pytorch/spmd_types/issues"
34
+
35
+ [tool.setuptools.packages.find]
36
+ include = ["spmd_types*"]
37
+
38
+
39
+ [tool.ruff]
40
+ line-length = 88
41
+ target-version = "py310"
42
+
43
+ [tool.ruff.lint]
44
+ select = ["E4", "E7", "E9", "F"]
45
+
46
+ [tool.ruff.format]
47
+ quote-style = "double"
48
+
49
+ [tool.pytest.ini_options]
50
+ testpaths = ["tests"]
51
+ python_files = ["*_test.py"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,109 @@
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+ #
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ # spmd_types package
8
+ from __future__ import annotations
9
+
10
+ from spmd_types._backward_hooks import ( # noqa: F401
11
+ register_local_backward_hook,
12
+ )
13
+ from spmd_types._collectives import ( # noqa: F401
14
+ all_gather,
15
+ all_reduce,
16
+ all_to_all,
17
+ redistribute,
18
+ reduce_scatter,
19
+ unshard,
20
+ )
21
+ from spmd_types._dist import set_dist # noqa: F401
22
+ from spmd_types._dtensor import ( # noqa: F401
23
+ dtensor_placement_to_spmd_type,
24
+ spmd_redistribute,
25
+ spmd_type_to_dtensor_placement,
26
+ )
27
+ from spmd_types._local import ( # noqa: F401
28
+ convert,
29
+ invariant_to_replicate,
30
+ reinterpret,
31
+ shard,
32
+ )
33
+ from spmd_types._mesh import set_current_mesh # noqa: F401
34
+ from spmd_types._mesh_axis import MeshAxis # noqa: F401
35
+
36
+ # reinterpret_mesh lives in its own module
37
+ from spmd_types._reinterpret_mesh import reinterpret_mesh # noqa: F401
38
+ from spmd_types._scalar import Scalar # noqa: F401
39
+ from spmd_types._state import ( # noqa: F401
40
+ current_mesh,
41
+ current_mesh_all_names,
42
+ current_mesh_names,
43
+ is_type_checking,
44
+ no_typecheck,
45
+ )
46
+ from spmd_types._traceback import traceback_filtering # noqa: F401
47
+ from spmd_types._type_attr import ( # noqa: F401
48
+ get_axis_local_type,
49
+ get_local_type,
50
+ maybe_get_axis_local_type,
51
+ )
52
+
53
+ # Collectives and operations -- runtime API (no _checker dependency)
54
+ from spmd_types.runtime import ( # noqa: F401
55
+ assert_local_type,
56
+ assert_type,
57
+ assert_type_like,
58
+ Infer,
59
+ local,
60
+ local_map,
61
+ mutate_type,
62
+ register_autograd_function,
63
+ register_decomposition,
64
+ register_local_autograd_function,
65
+ trace,
66
+ )
67
+
68
+ # Types
69
+ from spmd_types.types import ( # noqa: F401
70
+ DimSharding,
71
+ I,
72
+ Invariant,
73
+ LocalSpmdType,
74
+ normalize_axis,
75
+ normalize_mesh,
76
+ normalize_partition_spec,
77
+ P,
78
+ Partial,
79
+ PartitionSpec,
80
+ PerMeshAxisLocalSpmdType,
81
+ PerMeshAxisSpmdType,
82
+ PerMeshAxisSpmdTypes,
83
+ R,
84
+ Replicate,
85
+ S,
86
+ Shard,
87
+ SpmdTypeError,
88
+ TensorSharding,
89
+ V,
90
+ Varying,
91
+ )
92
+
93
+
94
+ class _TypeCheckingSentinel:
95
+ """Singleton whose bool value reflects whether type checking is active.
96
+
97
+ ``bool(TYPE_CHECKING)`` returns True when a ``typecheck()`` context is
98
+ active on the current thread, False otherwise. This avoids the
99
+ sys.modules replacement trick which breaks torch.compile / Dynamo.
100
+ """
101
+
102
+ def __bool__(self) -> bool:
103
+ return is_type_checking()
104
+
105
+ def __repr__(self) -> str:
106
+ return f"TYPE_CHECKING({is_type_checking()})"
107
+
108
+
109
+ TYPE_CHECKING = _TypeCheckingSentinel()
@@ -0,0 +1,133 @@
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+ #
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ """Per-hook SPMD type-propagation registry for nn.Module backward hooks.
8
+
9
+ BackwardHookFunction (nn.Module.register_full_backward_hook) has a pure
10
+ pass-through forward. Each user hook callable must be explicitly registered
11
+ via ``register_local_backward_hook`` to declare that it does not alter SPMD
12
+ types; unregistered hooks raise SpmdTypeError when type checking is active.
13
+
14
+ TODO: a per-hook rule API (for hooks that do collectives on grads, e.g.
15
+ all-reduce flipping I -> R) can be added later when a real use case
16
+ motivates the exact shape.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ from collections.abc import Callable
22
+
23
+ import torch
24
+ import torch.utils.hooks as _torch_hooks
25
+ from spmd_types._state import is_type_checking
26
+ from spmd_types.runtime import (
27
+ _set_partition_spec,
28
+ assert_type_like,
29
+ get_partition_spec,
30
+ )
31
+ from spmd_types.types import SpmdTypeError
32
+ from torch.nn.modules._functions import BackwardHookFunction
33
+
34
+ _LOCAL_BACKWARD_HOOKS: set[Callable] = set()
35
+
36
+
37
+ def register_local_backward_hook(fn: Callable) -> Callable:
38
+ """Declare that ``fn`` does not alter SPMD types when it runs in backward.
39
+
40
+ Analogous to :func:`register_local_autograd_function`: the hook's backward
41
+ is treated as local (no collectives, no type-changing effects on grads).
42
+ Side-agnostic: covers both ``register_full_backward_hook`` (post) and
43
+ ``register_full_backward_pre_hook`` (pre) use. Usable as a decorator.
44
+ """
45
+ _LOCAL_BACKWARD_HOOKS.add(fn)
46
+ return fn
47
+
48
+
49
+ def _validate(hooks):
50
+ if not is_type_checking():
51
+ return
52
+ for fn in hooks:
53
+ if fn in _LOCAL_BACKWARD_HOOKS:
54
+ continue
55
+ raise SpmdTypeError(
56
+ f"Backward hook {getattr(fn, '__qualname__', fn)!r} attached to "
57
+ f"nn.Module is not registered for SPMD type propagation. Call "
58
+ f"register_local_backward_hook(fn) if the hook does not alter "
59
+ f"gradient SPMD types."
60
+ )
61
+
62
+
63
+ def _apply_types(hooks, inputs, outputs):
64
+ """Copy SPMD annotations across BackwardHookFunction wrappers.
65
+
66
+ BackwardHookFunction.apply creates fresh tensor objects for module
67
+ backward hooks. Registered local hooks are semantically pass-through, so
68
+ their wrapper tensors should keep the input SPMD metadata.
69
+ """
70
+ if not isinstance(inputs, tuple):
71
+ inputs = (inputs,)
72
+ if not isinstance(outputs, tuple):
73
+ outputs = (outputs,)
74
+
75
+ for fn in hooks:
76
+ if fn in _LOCAL_BACKWARD_HOOKS:
77
+ for inp, out in zip(inputs, outputs):
78
+ if isinstance(inp, torch.Tensor) and isinstance(out, torch.Tensor):
79
+ spec = get_partition_spec(inp)
80
+ assert_type_like(out, inp)
81
+ if spec is not None:
82
+ _set_partition_spec(out, spec)
83
+
84
+
85
+ _orig_setup_input_hook = None
86
+ _orig_setup_output_hook = None
87
+
88
+
89
+ def _patched_setup_input_hook(self, input):
90
+ _validate(self.user_hooks)
91
+ result = _orig_setup_input_hook(self, input)
92
+ _apply_types(self.user_hooks, input, result)
93
+ _apply_types(self.user_pre_hooks, input, result)
94
+ return result
95
+
96
+
97
+ def _patched_setup_output_hook(self, output):
98
+ _validate(self.user_pre_hooks)
99
+ result = _orig_setup_output_hook(self, output)
100
+ _apply_types(self.user_pre_hooks, output, result)
101
+ _apply_types(self.user_hooks, output, result)
102
+ return result
103
+
104
+
105
+ def install() -> None:
106
+ """Install the BackwardHook monkey-patch. Idempotent."""
107
+ global _orig_setup_input_hook, _orig_setup_output_hook
108
+
109
+ if _orig_setup_input_hook is not None:
110
+ return
111
+
112
+ from spmd_types._checker import register_autograd_function
113
+
114
+ BackwardHookFunction.typecheck_forward = staticmethod(BackwardHookFunction.apply)
115
+ register_autograd_function(BackwardHookFunction)
116
+
117
+ _orig_setup_input_hook = _torch_hooks.BackwardHook.setup_input_hook
118
+ _orig_setup_output_hook = _torch_hooks.BackwardHook.setup_output_hook
119
+ _torch_hooks.BackwardHook.setup_input_hook = _patched_setup_input_hook
120
+ _torch_hooks.BackwardHook.setup_output_hook = _patched_setup_output_hook
121
+
122
+
123
+ def uninstall() -> None:
124
+ """Remove the BackwardHook monkey-patch. Idempotent."""
125
+ global _orig_setup_input_hook, _orig_setup_output_hook
126
+
127
+ if _orig_setup_input_hook is None:
128
+ return
129
+
130
+ _torch_hooks.BackwardHook.setup_input_hook = _orig_setup_input_hook
131
+ _torch_hooks.BackwardHook.setup_output_hook = _orig_setup_output_hook
132
+ _orig_setup_input_hook = None
133
+ _orig_setup_output_hook = None