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()

```

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):

{"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"}]}