prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Add contextlib support to the pyhf.schema API
  > instead of having users overwriting the value by assignment, do you think there is value in offering a `pyhf.utils.update_schema_path` or something that performs this operation through the API?
  >
  > Thanks @kratsg for taking up my suggestion!
  > 
  > I second @matthewfeickert's suggestion to change schemas via function call rather than assignment. It is much simpler to add functionality to a function if it ever becomes necessary, than to replace an entire existing module with a class instance with a property.
  > 
  > I'd even go so far to say that a context manager doubling as an update function would be ideal IMO:
  > ```python
  > # in pyhf.utils
  > _SCHEMAS = Path(...)
  > class use_schema_path: # snake_case to remind of function-like usage
  >     def  __init__(self, path):
  >         global _SCHEMAS
  >         self._old_schemas = _SCHEMAS
  >         _SCHEMAS = pathlib.Path(path)
  >     def __enter__(self):
  >         pass
  >     def __exit__(self, *args, **kwargs):
  >         global _SCHEMAS
  >         _SCHEMAS = self._old_schemas
  > ```
  > which can still be called as a function (only executing `__init__`), so short scripts etc. are not forced to use `with` blocks.
  > But it can also be used like so:
  > ```python
  > def make_my_workspace(spec):
  >     with pyhf.utils.use_schema_path('/my/very/special/schemas'):
  >         return pyhf.Workspace(spec)
  > ```
  > So as a user writing code on top of pyhf, I don't have to worry about resesetting the global variable, the CM does it for me, and there are fewer mistakes to make.
  > 
  _Originally posted by @lhenkelm in https://github.com/scikit-hep/pyhf/issues/1753#issuecomment-1026678066_
  
  </issue>
  <code>
  [start of src/pyhf/schema/__init__.py]
  1 """
  2 See :class:`~pyhf.schema.Schema` for documentation.
  3 """
  4 import pathlib
  5 import sys
  6 from pyhf.schema.loader import load_schema
  7 from pyhf.schema.validator import validate
  8 from pyhf.schema import variables
  9 
  10 __all__ = [
  11     "load_schema",
  12     "validate",
  13     "path",
  14     "version",
  15 ]
  16 
  17 
  18 def __dir__():
  19     return __all__
  20 
  21 
  22 class Schema(sys.modules[__name__].__class__):
  23     """
  24     A module-level wrapper around :mod:`pyhf.schema` which will provide additional functionality for interacting with schemas.
  25 
  26     Example:
  27         >>> import pyhf.schema
  28         >>> import pathlib
  29         >>> curr_path = pyhf.schema.path
  30         >>> curr_path # doctest: +ELLIPSIS
  31         PosixPath('.../pyhf/schemas')
  32         >>> pyhf.schema(pathlib.Path('/home/root/my/new/path'))
  33         >>> pyhf.schema.path
  34         PosixPath('/home/root/my/new/path')
  35         >>> pyhf.schema(curr_path)
  36         >>> pyhf.schema.path # doctest: +ELLIPSIS
  37         PosixPath('.../pyhf/schemas')
  38 
  39     """
  40 
  41     def __call__(self, new_path: pathlib.Path):
  42         """
  43         Change the local search path for finding schemas locally.
  44 
  45         Args:
  46             new_path (pathlib.Path): Path to folder containing the schemas
  47 
  48         Returns:
  49             None
  50         """
  51         variables.schemas = new_path
  52 
  53     @property
  54     def path(self):
  55         """
  56         The local path for schemas.
  57         """
  58         return variables.schemas
  59 
  60     @property
  61     def version(self):
  62         """
  63         The default version used for finding schemas.
  64         """
  65         return variables.SCHEMA_VERSION
  66 
  67 
  68 sys.modules[__name__].__class__ = Schema
  69
  [end of src/pyhf/schema/__init__.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/src/pyhf/schema/__init__.py b/src/pyhf/schema/__init__.py
  --- a/src/pyhf/schema/__init__.py
  +++ b/src/pyhf/schema/__init__.py
  @@ -23,17 +23,40 @@
       """
       A module-level wrapper around :mod:`pyhf.schema` which will provide additional functionality for interacting with schemas.
   
  -    Example:
  +    .. rubric:: Example (callable)
  +
  +    .. code-block:: pycon
  +
           >>> import pyhf.schema
           >>> import pathlib
           >>> curr_path = pyhf.schema.path
  -        >>> curr_path # doctest: +ELLIPSIS
  +        >>> curr_path  # doctest: +ELLIPSIS
           PosixPath('.../pyhf/schemas')
  -        >>> pyhf.schema(pathlib.Path('/home/root/my/new/path'))
  +        >>> new_path = pathlib.Path("/home/root/my/new/path")
  +        >>> pyhf.schema(new_path)  # doctest: +ELLIPSIS
  +        <module 'pyhf.schema' from ...>
           >>> pyhf.schema.path
           PosixPath('/home/root/my/new/path')
  -        >>> pyhf.schema(curr_path)
  -        >>> pyhf.schema.path # doctest: +ELLIPSIS
  +        >>> pyhf.schema(curr_path)  # doctest: +ELLIPSIS
  +        <module 'pyhf.schema' from ...>
  +        >>> pyhf.schema.path  # doctest: +ELLIPSIS
  +        PosixPath('.../pyhf/schemas')
  +
  +    .. rubric:: Example (context-manager)
  +
  +    .. code-block:: pycon
  +
  +        >>> import pyhf.schema
  +        >>> import pathlib
  +        >>> curr_path = pyhf.schema.path
  +        >>> curr_path  # doctest: +ELLIPSIS
  +        PosixPath('.../pyhf/schemas')
  +        >>> new_path = pathlib.Path("/home/root/my/new/path")
  +        >>> with pyhf.schema(new_path):
  +        ...     print(repr(pyhf.schema.path))
  +        ...
  +        PosixPath('/home/root/my/new/path')
  +        >>> pyhf.schema.path  # doctest: +ELLIPSIS
           PosixPath('.../pyhf/schemas')
   
       """
  @@ -45,10 +68,23 @@
           Args:
               new_path (pathlib.Path): Path to folder containing the schemas
   
  +        Returns:
  +            self (pyhf.schema.Schema): Returns itself (for contextlib management)
  +        """
  +        self.orig_path, variables.schemas = variables.schemas, new_path
  +        return self
  +
  +    def __enter__(self):
  +        pass
  +
  +    def __exit__(self, *args, **kwargs):
  +        """
  +        Reset the local search path for finding schemas locally.
  +
           Returns:
               None
           """
  -        variables.schemas = new_path
  +        variables.schemas = self.orig_path
   
       @property
       def path(self):
  
verification_info: {"golden_diff": "diff --git a/src/pyhf/schema/__init__.py b/src/pyhf/schema/__init__.py\n--- a/src/pyhf/schema/__init__.py\n+++ b/src/pyhf/schema/__init__.py\n@@ -23,17 +23,40 @@\n     \"\"\"\n     A module-level wrapper around :mod:`pyhf.schema` which will provide additional functionality for interacting with schemas.\n \n-    Example:\n+    .. rubric:: Example (callable)\n+\n+    .. code-block:: pycon\n+\n         >>> import pyhf.schema\n         >>> import pathlib\n         >>> curr_path = pyhf.schema.path\n-        >>> curr_path # doctest: +ELLIPSIS\n+        >>> curr_path  # doctest: +ELLIPSIS\n         PosixPath('.../pyhf/schemas')\n-        >>> pyhf.schema(pathlib.Path('/home/root/my/new/path'))\n+        >>> new_path = pathlib.Path(\"/home/root/my/new/path\")\n+        >>> pyhf.schema(new_path)  # doctest: +ELLIPSIS\n+        <module 'pyhf.schema' from ...>\n         >>> pyhf.schema.path\n         PosixPath('/home/root/my/new/path')\n-        >>> pyhf.schema(curr_path)\n-        >>> pyhf.schema.path # doctest: +ELLIPSIS\n+        >>> pyhf.schema(curr_path)  # doctest: +ELLIPSIS\n+        <module 'pyhf.schema' from ...>\n+        >>> pyhf.schema.path  # doctest: +ELLIPSIS\n+        PosixPath('.../pyhf/schemas')\n+\n+    .. rubric:: Example (context-manager)\n+\n+    .. code-block:: pycon\n+\n+        >>> import pyhf.schema\n+        >>> import pathlib\n+        >>> curr_path = pyhf.schema.path\n+        >>> curr_path  # doctest: +ELLIPSIS\n+        PosixPath('.../pyhf/schemas')\n+        >>> new_path = pathlib.Path(\"/home/root/my/new/path\")\n+        >>> with pyhf.schema(new_path):\n+        ...     print(repr(pyhf.schema.path))\n+        ...\n+        PosixPath('/home/root/my/new/path')\n+        >>> pyhf.schema.path  # doctest: +ELLIPSIS\n         PosixPath('.../pyhf/schemas')\n \n     \"\"\"\n@@ -45,10 +68,23 @@\n         Args:\n             new_path (pathlib.Path): Path to folder containing the schemas\n \n+        Returns:\n+            self (pyhf.schema.Schema): Returns itself (for contextlib management)\n+        \"\"\"\n+        self.orig_path, variables.schemas = variables.schemas, new_path\n+        return self\n+\n+    def __enter__(self):\n+        pass\n+\n+    def __exit__(self, *args, **kwargs):\n+        \"\"\"\n+        Reset the local search path for finding schemas locally.\n+\n         Returns:\n             None\n         \"\"\"\n-        variables.schemas = new_path\n+        variables.schemas = self.orig_path\n \n     @property\n     def path(self):\n", "issue": "Add contextlib support to the pyhf.schema API\n> instead of having users overwriting the value by assignment, do you think there is value in offering a `pyhf.utils.update_schema_path` or something that performs this operation through the API?\r\n>\r\n> Thanks @kratsg for taking up my suggestion!\r\n> \r\n> I second @matthewfeickert's suggestion to change schemas via function call rather than assignment. It is much simpler to add functionality to a function if it ever becomes necessary, than to replace an entire existing module with a class instance with a property.\r\n> \r\n> I'd even go so far to say that a context manager doubling as an update function would be ideal IMO:\r\n> ```python\r\n> # in pyhf.utils\r\n> _SCHEMAS = Path(...)\r\n> class use_schema_path: # snake_case to remind of function-like usage\r\n>     def  __init__(self, path):\r\n>         global _SCHEMAS\r\n>         self._old_schemas = _SCHEMAS\r\n>         _SCHEMAS = pathlib.Path(path)\r\n>     def __enter__(self):\r\n>         pass\r\n>     def __exit__(self, *args, **kwargs):\r\n>         global _SCHEMAS\r\n>         _SCHEMAS = self._old_schemas\r\n> ```\r\n> which can still be called as a function (only executing `__init__`), so short scripts etc. are not forced to use `with` blocks.\r\n> But it can also be used like so:\r\n> ```python\r\n> def make_my_workspace(spec):\r\n>     with pyhf.utils.use_schema_path('/my/very/special/schemas'):\r\n>         return pyhf.Workspace(spec)\r\n> ```\r\n> So as a user writing code on top of pyhf, I don't have to worry about resesetting the global variable, the CM does it for me, and there are fewer mistakes to make.\r\n> \r\n_Originally posted by @lhenkelm in https://github.com/scikit-hep/pyhf/issues/1753#issuecomment-1026678066_\n", "before_files": [{"content": "\"\"\"\nSee :class:`~pyhf.schema.Schema` for documentation.\n\"\"\"\nimport pathlib\nimport sys\nfrom pyhf.schema.loader import load_schema\nfrom pyhf.schema.validator import validate\nfrom pyhf.schema import variables\n\n__all__ = [\n    \"load_schema\",\n    \"validate\",\n    \"path\",\n    \"version\",\n]\n\n\ndef __dir__():\n    return __all__\n\n\nclass Schema(sys.modules[__name__].__class__):\n    \"\"\"\n    A module-level wrapper around :mod:`pyhf.schema` which will provide additional functionality for interacting with schemas.\n\n    Example:\n        >>> import pyhf.schema\n        >>> import pathlib\n        >>> curr_path = pyhf.schema.path\n        >>> curr_path # doctest: +ELLIPSIS\n        PosixPath('.../pyhf/schemas')\n        >>> pyhf.schema(pathlib.Path('/home/root/my/new/path'))\n        >>> pyhf.schema.path\n        PosixPath('/home/root/my/new/path')\n        >>> pyhf.schema(curr_path)\n        >>> pyhf.schema.path # doctest: +ELLIPSIS\n        PosixPath('.../pyhf/schemas')\n\n    \"\"\"\n\n    def __call__(self, new_path: pathlib.Path):\n        \"\"\"\n        Change the local search path for finding schemas locally.\n\n        Args:\n            new_path (pathlib.Path): Path to folder containing the schemas\n\n        Returns:\n            None\n        \"\"\"\n        variables.schemas = new_path\n\n    @property\n    def path(self):\n        \"\"\"\n        The local path for schemas.\n        \"\"\"\n        return variables.schemas\n\n    @property\n    def version(self):\n        \"\"\"\n        The default version used for finding schemas.\n        \"\"\"\n        return variables.SCHEMA_VERSION\n\n\nsys.modules[__name__].__class__ = Schema\n", "path": "src/pyhf/schema/__init__.py"}]}