We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Snippets requires deprecated fields 
## Description of the problem, including code/CLI snippet

in `project.snippets.create()` the required attributes were deprecated
```shell
AttributeError: Missing attributes: file_name, content
```
filename and content were deprecated in `files:file_path` and `files:content`

https://docs.gitlab.com/ee/api/snippets.html#create-new-snippet


## Specifications

  - python-gitlab version: 3.15.0 
  - API version you are using (v3/v4): v4
  - Gitlab server version (or gitlab.com): 15.11


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `gitlab/v4/objects/snippets.py`
Content:
```
1 from typing import Any, Callable, cast, Iterator, List, Optional, TYPE_CHECKING, Union
2 
3 import requests
4 
5 from gitlab import cli
6 from gitlab import exceptions as exc
7 from gitlab import utils
8 from gitlab.base import RESTManager, RESTObject, RESTObjectList
9 from gitlab.mixins import CRUDMixin, ObjectDeleteMixin, SaveMixin, UserAgentDetailMixin
10 from gitlab.types import RequiredOptional
11 
12 from .award_emojis import ProjectSnippetAwardEmojiManager  # noqa: F401
13 from .discussions import ProjectSnippetDiscussionManager  # noqa: F401
14 from .notes import ProjectSnippetNoteManager  # noqa: F401
15 
16 __all__ = [
17     "Snippet",
18     "SnippetManager",
19     "ProjectSnippet",
20     "ProjectSnippetManager",
21 ]
22 
23 
24 class Snippet(UserAgentDetailMixin, SaveMixin, ObjectDeleteMixin, RESTObject):
25     _repr_attr = "title"
26 
27     @cli.register_custom_action("Snippet")
28     @exc.on_http_error(exc.GitlabGetError)
29     def content(
30         self,
31         streamed: bool = False,
32         action: Optional[Callable[..., Any]] = None,
33         chunk_size: int = 1024,
34         *,
35         iterator: bool = False,
36         **kwargs: Any,
37     ) -> Optional[Union[bytes, Iterator[Any]]]:
38         """Return the content of a snippet.
39 
40         Args:
41             streamed: If True the data will be processed by chunks of
42                 `chunk_size` and each chunk is passed to `action` for
43                 treatment.
44             iterator: If True directly return the underlying response
45                 iterator
46             action: Callable responsible of dealing with chunk of
47                 data
48             chunk_size: Size of each chunk
49             **kwargs: Extra options to send to the server (e.g. sudo)
50 
51         Raises:
52             GitlabAuthenticationError: If authentication is not correct
53             GitlabGetError: If the content could not be retrieved
54 
55         Returns:
56             The snippet content
57         """
58         path = f"/snippets/{self.encoded_id}/raw"
59         result = self.manager.gitlab.http_get(
60             path, streamed=streamed, raw=True, **kwargs
61         )
62         if TYPE_CHECKING:
63             assert isinstance(result, requests.Response)
64         return utils.response_content(
65             result, streamed, action, chunk_size, iterator=iterator
66         )
67 
68 
69 class SnippetManager(CRUDMixin, RESTManager):
70     _path = "/snippets"
71     _obj_cls = Snippet
72     _create_attrs = RequiredOptional(
73         required=("title", "file_name", "content"), optional=("lifetime", "visibility")
74     )
75     _update_attrs = RequiredOptional(
76         optional=("title", "file_name", "content", "visibility")
77     )
78 
79     @cli.register_custom_action("SnippetManager")
80     def public(self, **kwargs: Any) -> Union[RESTObjectList, List[RESTObject]]:
81         """List all the public snippets.
82 
83         Args:
84             all: If True the returned object will be a list
85             **kwargs: Extra options to send to the server (e.g. sudo)
86 
87         Raises:
88             GitlabListError: If the list could not be retrieved
89 
90         Returns:
91             A generator for the snippets list
92         """
93         return self.list(path="/snippets/public", **kwargs)
94 
95     def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> Snippet:
96         return cast(Snippet, super().get(id=id, lazy=lazy, **kwargs))
97 
98 
99 class ProjectSnippet(UserAgentDetailMixin, SaveMixin, ObjectDeleteMixin, RESTObject):
100     _url = "/projects/{project_id}/snippets"
101     _repr_attr = "title"
102 
103     awardemojis: ProjectSnippetAwardEmojiManager
104     discussions: ProjectSnippetDiscussionManager
105     notes: ProjectSnippetNoteManager
106 
107     @cli.register_custom_action("ProjectSnippet")
108     @exc.on_http_error(exc.GitlabGetError)
109     def content(
110         self,
111         streamed: bool = False,
112         action: Optional[Callable[..., Any]] = None,
113         chunk_size: int = 1024,
114         *,
115         iterator: bool = False,
116         **kwargs: Any,
117     ) -> Optional[Union[bytes, Iterator[Any]]]:
118         """Return the content of a snippet.
119 
120         Args:
121             streamed: If True the data will be processed by chunks of
122                 `chunk_size` and each chunk is passed to `action` for
123                 treatment.
124             iterator: If True directly return the underlying response
125                 iterator
126             action: Callable responsible of dealing with chunk of
127                 data
128             chunk_size: Size of each chunk
129             **kwargs: Extra options to send to the server (e.g. sudo)
130 
131         Raises:
132             GitlabAuthenticationError: If authentication is not correct
133             GitlabGetError: If the content could not be retrieved
134 
135         Returns:
136             The snippet content
137         """
138         path = f"{self.manager.path}/{self.encoded_id}/raw"
139         result = self.manager.gitlab.http_get(
140             path, streamed=streamed, raw=True, **kwargs
141         )
142         if TYPE_CHECKING:
143             assert isinstance(result, requests.Response)
144         return utils.response_content(
145             result, streamed, action, chunk_size, iterator=iterator
146         )
147 
148 
149 class ProjectSnippetManager(CRUDMixin, RESTManager):
150     _path = "/projects/{project_id}/snippets"
151     _obj_cls = ProjectSnippet
152     _from_parent_attrs = {"project_id": "id"}
153     _create_attrs = RequiredOptional(
154         required=("title", "file_name", "content", "visibility"),
155         optional=("description",),
156     )
157     _update_attrs = RequiredOptional(
158         optional=("title", "file_name", "content", "visibility", "description"),
159     )
160 
161     def get(
162         self, id: Union[str, int], lazy: bool = False, **kwargs: Any
163     ) -> ProjectSnippet:
164         return cast(ProjectSnippet, super().get(id=id, lazy=lazy, **kwargs))
165
```
--- 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/gitlab/v4/objects/snippets.py b/gitlab/v4/objects/snippets.py
--- a/gitlab/v4/objects/snippets.py
+++ b/gitlab/v4/objects/snippets.py
@@ -70,10 +70,23 @@
     _path = "/snippets"
     _obj_cls = Snippet
     _create_attrs = RequiredOptional(
-        required=("title", "file_name", "content"), optional=("lifetime", "visibility")
+        required=("title",),
+        exclusive=("files", "file_name"),
+        optional=(
+            "description",
+            "content",
+            "visibility",
+        ),
     )
     _update_attrs = RequiredOptional(
-        optional=("title", "file_name", "content", "visibility")
+        optional=(
+            "title",
+            "files",
+            "file_name",
+            "content",
+            "visibility",
+            "description",
+        ),
     )
 
     @cli.register_custom_action("SnippetManager")
@@ -151,11 +164,22 @@
     _obj_cls = ProjectSnippet
     _from_parent_attrs = {"project_id": "id"}
     _create_attrs = RequiredOptional(
-        required=("title", "file_name", "content", "visibility"),
-        optional=("description",),
+        required=("title", "visibility"),
+        exclusive=("files", "file_name"),
+        optional=(
+            "description",
+            "content",
+        ),
     )
     _update_attrs = RequiredOptional(
-        optional=("title", "file_name", "content", "visibility", "description"),
+        optional=(
+            "title",
+            "files",
+            "file_name",
+            "content",
+            "visibility",
+            "description",
+        ),
     )
 
     def get(

{"golden_diff": "diff --git a/gitlab/v4/objects/snippets.py b/gitlab/v4/objects/snippets.py\n--- a/gitlab/v4/objects/snippets.py\n+++ b/gitlab/v4/objects/snippets.py\n@@ -70,10 +70,23 @@\n     _path = \"/snippets\"\n     _obj_cls = Snippet\n     _create_attrs = RequiredOptional(\n-        required=(\"title\", \"file_name\", \"content\"), optional=(\"lifetime\", \"visibility\")\n+        required=(\"title\",),\n+        exclusive=(\"files\", \"file_name\"),\n+        optional=(\n+            \"description\",\n+            \"content\",\n+            \"visibility\",\n+        ),\n     )\n     _update_attrs = RequiredOptional(\n-        optional=(\"title\", \"file_name\", \"content\", \"visibility\")\n+        optional=(\n+            \"title\",\n+            \"files\",\n+            \"file_name\",\n+            \"content\",\n+            \"visibility\",\n+            \"description\",\n+        ),\n     )\n \n     @cli.register_custom_action(\"SnippetManager\")\n@@ -151,11 +164,22 @@\n     _obj_cls = ProjectSnippet\n     _from_parent_attrs = {\"project_id\": \"id\"}\n     _create_attrs = RequiredOptional(\n-        required=(\"title\", \"file_name\", \"content\", \"visibility\"),\n-        optional=(\"description\",),\n+        required=(\"title\", \"visibility\"),\n+        exclusive=(\"files\", \"file_name\"),\n+        optional=(\n+            \"description\",\n+            \"content\",\n+        ),\n     )\n     _update_attrs = RequiredOptional(\n-        optional=(\"title\", \"file_name\", \"content\", \"visibility\", \"description\"),\n+        optional=(\n+            \"title\",\n+            \"files\",\n+            \"file_name\",\n+            \"content\",\n+            \"visibility\",\n+            \"description\",\n+        ),\n     )\n \n     def get(\n", "issue": "Snippets requires deprecated fields \n## Description of the problem, including code/CLI snippet\r\n\r\nin `project.snippets.create()` the required attributes were deprecated\r\n```shell\r\nAttributeError: Missing attributes: file_name, content\r\n```\r\nfilename and content were deprecated in `files:file_path` and `files:content`\r\n\r\nhttps://docs.gitlab.com/ee/api/snippets.html#create-new-snippet\r\n\r\n\r\n## Specifications\r\n\r\n  - python-gitlab version: 3.15.0 \r\n  - API version you are using (v3/v4): v4\r\n  - Gitlab server version (or gitlab.com): 15.11\r\n\n", "before_files": [{"content": "from typing import Any, Callable, cast, Iterator, List, Optional, TYPE_CHECKING, Union\n\nimport requests\n\nfrom gitlab import cli\nfrom gitlab import exceptions as exc\nfrom gitlab import utils\nfrom gitlab.base import RESTManager, RESTObject, RESTObjectList\nfrom gitlab.mixins import CRUDMixin, ObjectDeleteMixin, SaveMixin, UserAgentDetailMixin\nfrom gitlab.types import RequiredOptional\n\nfrom .award_emojis import ProjectSnippetAwardEmojiManager  # noqa: F401\nfrom .discussions import ProjectSnippetDiscussionManager  # noqa: F401\nfrom .notes import ProjectSnippetNoteManager  # noqa: F401\n\n__all__ = [\n    \"Snippet\",\n    \"SnippetManager\",\n    \"ProjectSnippet\",\n    \"ProjectSnippetManager\",\n]\n\n\nclass Snippet(UserAgentDetailMixin, SaveMixin, ObjectDeleteMixin, RESTObject):\n    _repr_attr = \"title\"\n\n    @cli.register_custom_action(\"Snippet\")\n    @exc.on_http_error(exc.GitlabGetError)\n    def content(\n        self,\n        streamed: bool = False,\n        action: Optional[Callable[..., Any]] = None,\n        chunk_size: int = 1024,\n        *,\n        iterator: bool = False,\n        **kwargs: Any,\n    ) -> Optional[Union[bytes, Iterator[Any]]]:\n        \"\"\"Return the content of a snippet.\n\n        Args:\n            streamed: If True the data will be processed by chunks of\n                `chunk_size` and each chunk is passed to `action` for\n                treatment.\n            iterator: If True directly return the underlying response\n                iterator\n            action: Callable responsible of dealing with chunk of\n                data\n            chunk_size: Size of each chunk\n            **kwargs: Extra options to send to the server (e.g. sudo)\n\n        Raises:\n            GitlabAuthenticationError: If authentication is not correct\n            GitlabGetError: If the content could not be retrieved\n\n        Returns:\n            The snippet content\n        \"\"\"\n        path = f\"/snippets/{self.encoded_id}/raw\"\n        result = self.manager.gitlab.http_get(\n            path, streamed=streamed, raw=True, **kwargs\n        )\n        if TYPE_CHECKING:\n            assert isinstance(result, requests.Response)\n        return utils.response_content(\n            result, streamed, action, chunk_size, iterator=iterator\n        )\n\n\nclass SnippetManager(CRUDMixin, RESTManager):\n    _path = \"/snippets\"\n    _obj_cls = Snippet\n    _create_attrs = RequiredOptional(\n        required=(\"title\", \"file_name\", \"content\"), optional=(\"lifetime\", \"visibility\")\n    )\n    _update_attrs = RequiredOptional(\n        optional=(\"title\", \"file_name\", \"content\", \"visibility\")\n    )\n\n    @cli.register_custom_action(\"SnippetManager\")\n    def public(self, **kwargs: Any) -> Union[RESTObjectList, List[RESTObject]]:\n        \"\"\"List all the public snippets.\n\n        Args:\n            all: If True the returned object will be a list\n            **kwargs: Extra options to send to the server (e.g. sudo)\n\n        Raises:\n            GitlabListError: If the list could not be retrieved\n\n        Returns:\n            A generator for the snippets list\n        \"\"\"\n        return self.list(path=\"/snippets/public\", **kwargs)\n\n    def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> Snippet:\n        return cast(Snippet, super().get(id=id, lazy=lazy, **kwargs))\n\n\nclass ProjectSnippet(UserAgentDetailMixin, SaveMixin, ObjectDeleteMixin, RESTObject):\n    _url = \"/projects/{project_id}/snippets\"\n    _repr_attr = \"title\"\n\n    awardemojis: ProjectSnippetAwardEmojiManager\n    discussions: ProjectSnippetDiscussionManager\n    notes: ProjectSnippetNoteManager\n\n    @cli.register_custom_action(\"ProjectSnippet\")\n    @exc.on_http_error(exc.GitlabGetError)\n    def content(\n        self,\n        streamed: bool = False,\n        action: Optional[Callable[..., Any]] = None,\n        chunk_size: int = 1024,\n        *,\n        iterator: bool = False,\n        **kwargs: Any,\n    ) -> Optional[Union[bytes, Iterator[Any]]]:\n        \"\"\"Return the content of a snippet.\n\n        Args:\n            streamed: If True the data will be processed by chunks of\n                `chunk_size` and each chunk is passed to `action` for\n                treatment.\n            iterator: If True directly return the underlying response\n                iterator\n            action: Callable responsible of dealing with chunk of\n                data\n            chunk_size: Size of each chunk\n            **kwargs: Extra options to send to the server (e.g. sudo)\n\n        Raises:\n            GitlabAuthenticationError: If authentication is not correct\n            GitlabGetError: If the content could not be retrieved\n\n        Returns:\n            The snippet content\n        \"\"\"\n        path = f\"{self.manager.path}/{self.encoded_id}/raw\"\n        result = self.manager.gitlab.http_get(\n            path, streamed=streamed, raw=True, **kwargs\n        )\n        if TYPE_CHECKING:\n            assert isinstance(result, requests.Response)\n        return utils.response_content(\n            result, streamed, action, chunk_size, iterator=iterator\n        )\n\n\nclass ProjectSnippetManager(CRUDMixin, RESTManager):\n    _path = \"/projects/{project_id}/snippets\"\n    _obj_cls = ProjectSnippet\n    _from_parent_attrs = {\"project_id\": \"id\"}\n    _create_attrs = RequiredOptional(\n        required=(\"title\", \"file_name\", \"content\", \"visibility\"),\n        optional=(\"description\",),\n    )\n    _update_attrs = RequiredOptional(\n        optional=(\"title\", \"file_name\", \"content\", \"visibility\", \"description\"),\n    )\n\n    def get(\n        self, id: Union[str, int], lazy: bool = False, **kwargs: Any\n    ) -> ProjectSnippet:\n        return cast(ProjectSnippet, super().get(id=id, lazy=lazy, **kwargs))\n", "path": "gitlab/v4/objects/snippets.py"}], "after_files": [{"content": "from typing import Any, Callable, cast, Iterator, List, Optional, TYPE_CHECKING, Union\n\nimport requests\n\nfrom gitlab import cli\nfrom gitlab import exceptions as exc\nfrom gitlab import utils\nfrom gitlab.base import RESTManager, RESTObject, RESTObjectList\nfrom gitlab.mixins import CRUDMixin, ObjectDeleteMixin, SaveMixin, UserAgentDetailMixin\nfrom gitlab.types import RequiredOptional\n\nfrom .award_emojis import ProjectSnippetAwardEmojiManager  # noqa: F401\nfrom .discussions import ProjectSnippetDiscussionManager  # noqa: F401\nfrom .notes import ProjectSnippetNoteManager  # noqa: F401\n\n__all__ = [\n    \"Snippet\",\n    \"SnippetManager\",\n    \"ProjectSnippet\",\n    \"ProjectSnippetManager\",\n]\n\n\nclass Snippet(UserAgentDetailMixin, SaveMixin, ObjectDeleteMixin, RESTObject):\n    _repr_attr = \"title\"\n\n    @cli.register_custom_action(\"Snippet\")\n    @exc.on_http_error(exc.GitlabGetError)\n    def content(\n        self,\n        streamed: bool = False,\n        action: Optional[Callable[..., Any]] = None,\n        chunk_size: int = 1024,\n        *,\n        iterator: bool = False,\n        **kwargs: Any,\n    ) -> Optional[Union[bytes, Iterator[Any]]]:\n        \"\"\"Return the content of a snippet.\n\n        Args:\n            streamed: If True the data will be processed by chunks of\n                `chunk_size` and each chunk is passed to `action` for\n                treatment.\n            iterator: If True directly return the underlying response\n                iterator\n            action: Callable responsible of dealing with chunk of\n                data\n            chunk_size: Size of each chunk\n            **kwargs: Extra options to send to the server (e.g. sudo)\n\n        Raises:\n            GitlabAuthenticationError: If authentication is not correct\n            GitlabGetError: If the content could not be retrieved\n\n        Returns:\n            The snippet content\n        \"\"\"\n        path = f\"/snippets/{self.encoded_id}/raw\"\n        result = self.manager.gitlab.http_get(\n            path, streamed=streamed, raw=True, **kwargs\n        )\n        if TYPE_CHECKING:\n            assert isinstance(result, requests.Response)\n        return utils.response_content(\n            result, streamed, action, chunk_size, iterator=iterator\n        )\n\n\nclass SnippetManager(CRUDMixin, RESTManager):\n    _path = \"/snippets\"\n    _obj_cls = Snippet\n    _create_attrs = RequiredOptional(\n        required=(\"title\",),\n        exclusive=(\"files\", \"file_name\"),\n        optional=(\n            \"description\",\n            \"content\",\n            \"visibility\",\n        ),\n    )\n    _update_attrs = RequiredOptional(\n        optional=(\n            \"title\",\n            \"files\",\n            \"file_name\",\n            \"content\",\n            \"visibility\",\n            \"description\",\n        ),\n    )\n\n    @cli.register_custom_action(\"SnippetManager\")\n    def public(self, **kwargs: Any) -> Union[RESTObjectList, List[RESTObject]]:\n        \"\"\"List all the public snippets.\n\n        Args:\n            all: If True the returned object will be a list\n            **kwargs: Extra options to send to the server (e.g. sudo)\n\n        Raises:\n            GitlabListError: If the list could not be retrieved\n\n        Returns:\n            A generator for the snippets list\n        \"\"\"\n        return self.list(path=\"/snippets/public\", **kwargs)\n\n    def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> Snippet:\n        return cast(Snippet, super().get(id=id, lazy=lazy, **kwargs))\n\n\nclass ProjectSnippet(UserAgentDetailMixin, SaveMixin, ObjectDeleteMixin, RESTObject):\n    _url = \"/projects/{project_id}/snippets\"\n    _repr_attr = \"title\"\n\n    awardemojis: ProjectSnippetAwardEmojiManager\n    discussions: ProjectSnippetDiscussionManager\n    notes: ProjectSnippetNoteManager\n\n    @cli.register_custom_action(\"ProjectSnippet\")\n    @exc.on_http_error(exc.GitlabGetError)\n    def content(\n        self,\n        streamed: bool = False,\n        action: Optional[Callable[..., Any]] = None,\n        chunk_size: int = 1024,\n        *,\n        iterator: bool = False,\n        **kwargs: Any,\n    ) -> Optional[Union[bytes, Iterator[Any]]]:\n        \"\"\"Return the content of a snippet.\n\n        Args:\n            streamed: If True the data will be processed by chunks of\n                `chunk_size` and each chunk is passed to `action` for\n                treatment.\n            iterator: If True directly return the underlying response\n                iterator\n            action: Callable responsible of dealing with chunk of\n                data\n            chunk_size: Size of each chunk\n            **kwargs: Extra options to send to the server (e.g. sudo)\n\n        Raises:\n            GitlabAuthenticationError: If authentication is not correct\n            GitlabGetError: If the content could not be retrieved\n\n        Returns:\n            The snippet content\n        \"\"\"\n        path = f\"{self.manager.path}/{self.encoded_id}/raw\"\n        result = self.manager.gitlab.http_get(\n            path, streamed=streamed, raw=True, **kwargs\n        )\n        if TYPE_CHECKING:\n            assert isinstance(result, requests.Response)\n        return utils.response_content(\n            result, streamed, action, chunk_size, iterator=iterator\n        )\n\n\nclass ProjectSnippetManager(CRUDMixin, RESTManager):\n    _path = \"/projects/{project_id}/snippets\"\n    _obj_cls = ProjectSnippet\n    _from_parent_attrs = {\"project_id\": \"id\"}\n    _create_attrs = RequiredOptional(\n        required=(\"title\", \"visibility\"),\n        exclusive=(\"files\", \"file_name\"),\n        optional=(\n            \"description\",\n            \"content\",\n        ),\n    )\n    _update_attrs = RequiredOptional(\n        optional=(\n            \"title\",\n            \"files\",\n            \"file_name\",\n            \"content\",\n            \"visibility\",\n            \"description\",\n        ),\n    )\n\n    def get(\n        self, id: Union[str, int], lazy: bool = False, **kwargs: Any\n    ) -> ProjectSnippet:\n        return cast(ProjectSnippet, super().get(id=id, lazy=lazy, **kwargs))\n", "path": "gitlab/v4/objects/snippets.py"}]}