prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  `func_persist` fails with Python 3.11
  ```sage
  @func_persist
  def test(n):
      return n*n
  ```
  
  fails with
  
  ```python
  AttributeError                            Traceback (most recent call last)
  Cell In[1], line 1
  ----> 1 @func_persist
        2 def test(n):
        3     return n*n
  
  File /usr/lib/python3.11/site-packages/sage/misc/func_persist.py:60, in func_persist.__init__(self, f, dir)
       56 self.__dir = dir
       57 os.makedirs(dir, exist_ok=True)
       58 self.__doc__ = '%s%s%s' % (
       59     f.__name__,
  ---> 60     inspect.formatargspec(*inspect.getargs(f.__code__)),
       61     f.__doc__)
  
  AttributeError: module 'inspect' has no attribute 'formatargspec'
  ```
  
  This is because `inspect.formatargspec` has been [deprecated in Python 3.5 and removed in 3.11](https://docs.python.org/3/whatsnew/3.11.html#removed). Probably related to #33842.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `src/sage/misc/func_persist.py`
  Content:
  ```
  1 r"""
  2 Support for persistent functions in .sage files
  3 
  4 Persistent functions are functions whose values are stored on disk
  5 so they do not have to be recomputed.
  6 
  7 The inputs to the function must be hashable (so lists are not
  8 allowed). Though a hash is used, in the incredibly unlikely event
  9 that a hash collision occurs, your function will not return an
  10 incorrect result because of this (though the cache might not be
  11 used either).
  12 
  13 This is meant to be used from ``.sage`` files, not from
  14 library ``.py`` files.
  15 
  16 To use this disk caching mechanism, just put
  17 ``@func_persist`` right before your function
  18 definition. For example,
  19 
  20 ::
  21 
  22     @func_persist
  23     def bern(n):
  24         "Return the n-th Bernoulli number, caching the result to disk."
  25         return bernoulli(n)
  26 
  27 You can then use the function ``bern`` as usual, except
  28 it will almost instantly return values that have already been
  29 computed, even if you quit and restart.
  30 
  31 The disk cache files are stored by default in the subdirectory
  32 ``func_persist`` of the current working directory,
  33 with one file for each evaluation of the function.
  34 """
  35 ########################################################################
  36 #       Copyright (C) 2006 William Stein <wstein@gmail.com>
  37 #
  38 #  Distributed under the terms of the GNU General Public License (GPL)
  39 #
  40 #                  https://www.gnu.org/licenses/
  41 ########################################################################
  42 
  43 import inspect
  44 import os
  45 
  46 from . import persist
  47 
  48 
  49 class func_persist:
  50     r"""
  51     Put ``@func_persist`` right before your function
  52     definition to cache values it computes to disk.
  53     """
  54     def __init__(self, f, dir='func_persist'):
  55         self.__func = f
  56         self.__dir = dir
  57         os.makedirs(dir, exist_ok=True)
  58         self.__doc__ = '%s%s%s' % (
  59             f.__name__,
  60             inspect.formatargspec(*inspect.getargs(f.__code__)),
  61             f.__doc__)
  62 
  63     def __call__(self, *args, **kwds):
  64         key = (tuple(args), tuple(kwds.items()))
  65         h = hash(key)
  66         name = '%s/%s_%s.sobj' % (self.__dir, self.__func.__name__, h)
  67 
  68         if os.path.exists(name):
  69             key2, val = persist.load(name)
  70             if key == key2:
  71                 # We save and test equality of keys to avoid
  72                 # the (extremely remote) possibility of a hash
  73                 # collision.  Correctness is crucial in mathematics.
  74                 return val
  75 
  76         val = self.__func(*args, **kwds)
  77         persist.save((key, val), name)
  78         return val
  79
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/src/sage/misc/func_persist.py b/src/sage/misc/func_persist.py
  --- a/src/sage/misc/func_persist.py
  +++ b/src/sage/misc/func_persist.py
  @@ -45,7 +45,6 @@
   
   from . import persist
   
  -
   class func_persist:
       r"""
       Put ``@func_persist`` right before your function
  @@ -57,7 +56,7 @@
           os.makedirs(dir, exist_ok=True)
           self.__doc__ = '%s%s%s' % (
               f.__name__,
  -            inspect.formatargspec(*inspect.getargs(f.__code__)),
  +            inspect.signature(f),
               f.__doc__)
   
       def __call__(self, *args, **kwds):
  
verification_info: {"golden_diff": "diff --git a/src/sage/misc/func_persist.py b/src/sage/misc/func_persist.py\n--- a/src/sage/misc/func_persist.py\n+++ b/src/sage/misc/func_persist.py\n@@ -45,7 +45,6 @@\n \n from . import persist\n \n-\n class func_persist:\n     r\"\"\"\n     Put ``@func_persist`` right before your function\n@@ -57,7 +56,7 @@\n         os.makedirs(dir, exist_ok=True)\n         self.__doc__ = '%s%s%s' % (\n             f.__name__,\n-            inspect.formatargspec(*inspect.getargs(f.__code__)),\n+            inspect.signature(f),\n             f.__doc__)\n \n     def __call__(self, *args, **kwds):\n", "issue": "`func_persist` fails with Python 3.11\n```sage\n@func_persist\ndef test(n):\n    return n*n\n```\n\nfails with\n\n```python\nAttributeError                            Traceback (most recent call last)\nCell In[1], line 1\n----> 1 @func_persist\n      2 def test(n):\n      3     return n*n\n\nFile /usr/lib/python3.11/site-packages/sage/misc/func_persist.py:60, in func_persist.__init__(self, f, dir)\n     56 self.__dir = dir\n     57 os.makedirs(dir, exist_ok=True)\n     58 self.__doc__ = '%s%s%s' % (\n     59     f.__name__,\n---> 60     inspect.formatargspec(*inspect.getargs(f.__code__)),\n     61     f.__doc__)\n\nAttributeError: module 'inspect' has no attribute 'formatargspec'\n```\n\nThis is because `inspect.formatargspec` has been [deprecated in Python 3.5 and removed in 3.11](https://docs.python.org/3/whatsnew/3.11.html#removed). Probably related to #33842.\n\n", "before_files": [{"content": "r\"\"\"\nSupport for persistent functions in .sage files\n\nPersistent functions are functions whose values are stored on disk\nso they do not have to be recomputed.\n\nThe inputs to the function must be hashable (so lists are not\nallowed). Though a hash is used, in the incredibly unlikely event\nthat a hash collision occurs, your function will not return an\nincorrect result because of this (though the cache might not be\nused either).\n\nThis is meant to be used from ``.sage`` files, not from\nlibrary ``.py`` files.\n\nTo use this disk caching mechanism, just put\n``@func_persist`` right before your function\ndefinition. For example,\n\n::\n\n    @func_persist\n    def bern(n):\n        \"Return the n-th Bernoulli number, caching the result to disk.\"\n        return bernoulli(n)\n\nYou can then use the function ``bern`` as usual, except\nit will almost instantly return values that have already been\ncomputed, even if you quit and restart.\n\nThe disk cache files are stored by default in the subdirectory\n``func_persist`` of the current working directory,\nwith one file for each evaluation of the function.\n\"\"\"\n########################################################################\n#       Copyright (C) 2006 William Stein <wstein@gmail.com>\n#\n#  Distributed under the terms of the GNU General Public License (GPL)\n#\n#                  https://www.gnu.org/licenses/\n########################################################################\n\nimport inspect\nimport os\n\nfrom . import persist\n\n\nclass func_persist:\n    r\"\"\"\n    Put ``@func_persist`` right before your function\n    definition to cache values it computes to disk.\n    \"\"\"\n    def __init__(self, f, dir='func_persist'):\n        self.__func = f\n        self.__dir = dir\n        os.makedirs(dir, exist_ok=True)\n        self.__doc__ = '%s%s%s' % (\n            f.__name__,\n            inspect.formatargspec(*inspect.getargs(f.__code__)),\n            f.__doc__)\n\n    def __call__(self, *args, **kwds):\n        key = (tuple(args), tuple(kwds.items()))\n        h = hash(key)\n        name = '%s/%s_%s.sobj' % (self.__dir, self.__func.__name__, h)\n\n        if os.path.exists(name):\n            key2, val = persist.load(name)\n            if key == key2:\n                # We save and test equality of keys to avoid\n                # the (extremely remote) possibility of a hash\n                # collision.  Correctness is crucial in mathematics.\n                return val\n\n        val = self.__func(*args, **kwds)\n        persist.save((key, val), name)\n        return val\n", "path": "src/sage/misc/func_persist.py"}], "after_files": [{"content": "r\"\"\"\nSupport for persistent functions in .sage files\n\nPersistent functions are functions whose values are stored on disk\nso they do not have to be recomputed.\n\nThe inputs to the function must be hashable (so lists are not\nallowed). Though a hash is used, in the incredibly unlikely event\nthat a hash collision occurs, your function will not return an\nincorrect result because of this (though the cache might not be\nused either).\n\nThis is meant to be used from ``.sage`` files, not from\nlibrary ``.py`` files.\n\nTo use this disk caching mechanism, just put\n``@func_persist`` right before your function\ndefinition. For example,\n\n::\n\n    @func_persist\n    def bern(n):\n        \"Return the n-th Bernoulli number, caching the result to disk.\"\n        return bernoulli(n)\n\nYou can then use the function ``bern`` as usual, except\nit will almost instantly return values that have already been\ncomputed, even if you quit and restart.\n\nThe disk cache files are stored by default in the subdirectory\n``func_persist`` of the current working directory,\nwith one file for each evaluation of the function.\n\"\"\"\n########################################################################\n#       Copyright (C) 2006 William Stein <wstein@gmail.com>\n#\n#  Distributed under the terms of the GNU General Public License (GPL)\n#\n#                  https://www.gnu.org/licenses/\n########################################################################\n\nimport inspect\nimport os\n\nfrom . import persist\n\nclass func_persist:\n    r\"\"\"\n    Put ``@func_persist`` right before your function\n    definition to cache values it computes to disk.\n    \"\"\"\n    def __init__(self, f, dir='func_persist'):\n        self.__func = f\n        self.__dir = dir\n        os.makedirs(dir, exist_ok=True)\n        self.__doc__ = '%s%s%s' % (\n            f.__name__,\n            inspect.signature(f),\n            f.__doc__)\n\n    def __call__(self, *args, **kwds):\n        key = (tuple(args), tuple(kwds.items()))\n        h = hash(key)\n        name = '%s/%s_%s.sobj' % (self.__dir, self.__func.__name__, h)\n\n        if os.path.exists(name):\n            key2, val = persist.load(name)\n            if key == key2:\n                # We save and test equality of keys to avoid\n                # the (extremely remote) possibility of a hash\n                # collision.  Correctness is crucial in mathematics.\n                return val\n\n        val = self.__func(*args, **kwds)\n        persist.save((key, val), name)\n        return val\n", "path": "src/sage/misc/func_persist.py"}]}